diff --git a/include/common_structs.h b/include/common_structs.h index fdaa262ce8..90c72c7e9a 100644 --- a/include/common_structs.h +++ b/include/common_structs.h @@ -994,14 +994,13 @@ typedef struct BattleStatus { /* 0x45C */ char unk_45C[4]; } BattleStatus; // size = 0x460 -// alternative name: TileDescriptor typedef struct TextureHeader { /* 0x00 */ s8 name[32]; /* 0x20 */ u16 auxW; /* 0x22 */ u16 mainW; /* 0x24 */ u16 auxH; /* 0x26 */ u16 mainH; - /* 0x28 */ u8 unk_28; + /* 0x28 */ u8 isVariant; /* 0x29 */ u8 extraTiles; // 0 - none, 1 - mipmap, 2 - ?, 3 - use aux tile /* 0x2A */ u8 colorCombineType : 6; /* 0x2A */ u8 colorCombineSubType : 2; diff --git a/include/filemenu.h b/include/filemenu.h index a00b39dc13..fcb085e030 100644 --- a/include/filemenu.h +++ b/include/filemenu.h @@ -113,7 +113,7 @@ void filemenu_choose_name_update(MenuPanel*); void filemenu_choose_name_cleanup(MenuPanel*); void filemenu_draw_message(u8*, s32, s32, s32, s32, u32); -void filemenu_draw_rect(s32 ulx, s32 uly, s32 lrx, s32 lry, s32 tileDescriptor, s32 uls, s32 ult, s32 dsdx, s32 dtdy); +void filemenu_draw_rect(s32 ulx, s32 uly, s32 lrx, s32 lry, s32 tileIdx, s32 uls, s32 ult, s32 dsdx, s32 dtdy); extern WindowStyleCustom filemenu_windowStyles[]; extern u8 filemenu_createfile_gridData[]; diff --git a/include/functions.h b/include/functions.h index f77133bfc5..c93ee6c9da 100644 --- a/include/functions.h +++ b/include/functions.h @@ -1097,7 +1097,7 @@ void btl_update(void); void update_item_entities(void); void iterate_models(void); void restore_map_collision_data(void); -void load_model_textures(struct ModelNode* model, s32 romOffset, s32 size); +void mdl_load_all_textures(struct ModelNode* model, s32 romOffset, s32 size); void calculate_model_sizes(void); #endif diff --git a/include/model.h b/include/model.h index f09f2f18ed..cddc812121 100644 --- a/include/model.h +++ b/include/model.h @@ -179,7 +179,7 @@ void update_model_animator(s32); void update_model_animator_with_transform(s32 animatorID, Mtx* mtx); void set_mdl_custom_gfx_set(Model*, s32, u32); ModelNodeProperty* get_model_property(ModelNode* node, ModelPropertyKeys key); -void func_80115498(u32 romOffset, s32 textureID, s32 baseOffset, s32 size); +void load_texture_variants(u32 romOffset, s32 textureID, s32 baseOffset, s32 size); s32 step_model_animator(ModelAnimator* animator); AnimatorNode* get_animator_node_for_tree_index(ModelAnimator* animator, s32 treeIndex); AnimatorNode* get_animator_node_with_id(ModelAnimator* animator, s32 id); diff --git a/include/variables.h b/include/variables.h index be6bde4f6d..0e3779ede4 100644 --- a/include/variables.h +++ b/include/variables.h @@ -146,7 +146,7 @@ extern u16 gCurrentDoorSounds; extern UNK_TYPE D_800E92D8; extern UNK_TYPE D_80147574; -extern s8 D_8014C248[]; +extern b8 D_8014C248; extern UNK_FUN_PTR(TalkNotificationCallback); extern UNK_FUN_PTR(InteractNotificationCallback); diff --git a/src/16F740.c b/src/16F740.c index 74dda02f46..0a3d71a5d1 100644 --- a/src/16F740.c +++ b/src/16F740.c @@ -193,8 +193,8 @@ void btl_state_update_normal_start(void) { s32 size; UiStatus* uiStatus; void* compressedAsset; - ModelNode* model; - s32 textureRom; + ModelNode* rootModel; + s32 texturesOffset; Actor* actor; Evt* script; s32 enemyNotDone; @@ -226,10 +226,10 @@ void btl_state_update_normal_start(void) { ASSERT(size <= 0x8000); - model = gMapShapeData.header.root; - textureRom = get_asset_offset(stage->texture, &size); - if (model != NULL) { - load_data_for_models(model, textureRom, size); + rootModel = gMapShapeData.header.root; + texturesOffset = get_asset_offset(stage->texture, &size); + if (rootModel != NULL) { + load_data_for_models(rootModel, texturesOffset, size); } load_battle_hit_asset(stage->hit); diff --git a/src/entity.c b/src/entity.c new file mode 100644 index 0000000000..1cbf005d7d --- /dev/null +++ b/src/entity.c @@ -0,0 +1,1759 @@ +#include "common.h" +#include "ld_addrs.h" +#include "entity.h" +#include "model.h" + +#if VERSION_IQUE +// TODO: remove if sections are split in iQue release +extern Addr entity_jan_iwa_ROM_START; +extern Addr entity_jan_iwa_ROM_END; +extern Addr entity_default_ROM_START; +extern Addr entity_default_ROM_END; +extern Addr entity_sbk_omo_ROM_START; +extern Addr entity_sbk_omo_ROM_END; +#endif + +#ifdef SHIFT +extern Addr WorldEntityHeapBottom; +extern Addr WorldEntityHeapBase; +#define WORLD_ENTITY_HEAP_BOTTOM (s32) WorldEntityHeapBottom +#define WORLD_ENTITY_HEAP_BASE (s32) WorldEntityHeapBase +// TODO this only refers to one of 3 overlays which happen to share the same address space +// but don't necessarily have to +#define AREA_SPECIFIC_ENTITY_VRAM (s32) entity_default_VRAM +#else +#define WORLD_ENTITY_HEAP_BOTTOM 0x80250000 +#define WORLD_ENTITY_HEAP_BASE 0x80267FF0 +#define AREA_SPECIFIC_ENTITY_VRAM 0x802BAE00 +#endif + +s32 D_8014AFB0 = 255; + +// BSS +extern s32 D_801516FC; +extern s32 D_801512BC; +extern s32 D_80151304; +extern s32 D_80151344; +extern s32 entity_numEntities; +extern s32 gEntityHeapBase; +extern s32 gLastCreatedEntityIndex; + +extern s32 gEntityHeapBottom; +extern s32 entity_numShadows; +extern s32 isAreaSpecificEntityDataLoaded; +extern s32 entity_updateCounter; + +extern s32 wEntityDataLoadedSize; +extern s32 bEntityDataLoadedSize; + +extern EntityBlueprint* wEntityBlueprint[30]; +extern EntityBlueprint* bEntityBlueprint[4]; + +extern Addr BattleEntityHeapBottom; // todo ??? + +void update_shadows(void); +s32 step_entity_commandlist(Entity* entity); +void entity_swizzle_anim_pointers(EntityBlueprint* entityData, void* baseAnim, void* baseGfx); +void render_shadows(void); +void update_entity_transform_matrix(Entity* entity); +void update_shadow_transform_matrix(Shadow* shadow); +void update_entity_inverse_rotation_matrix(Entity* entity); +void delete_entity(s32 entityIndex); +void delete_entity_and_unload_data(s32 entityIndex); +void _delete_shadow(s32 shadowIndex); +void reload_world_entity_data(void); +s32 entity_get_collision_flags(Entity* entity); +void entity_free_static_data(EntityBlueprint* data); +s32 create_entity_shadow(Entity* entity, f32 x, f32 y, f32 z); +void update_entity_shadow_position(Entity* entity); + +void update_entities(void) { + s32 i; + + D_801512BC = 0; + entity_numEntities = 0; + entity_updateCounter++; + + for (i = 0; i < MAX_ENTITIES; i++) { + Entity* entity = get_entity_by_index(i); + + if (entity != NULL) { + entity_numEntities++; + + if (!(entity->flags & ENTITY_FLAG_SKIP_UPDATE)) { + if (entity->flags & ENTITY_FLAG_BOUND_SCRIPT_DIRTY) { + entity->flags &= ~ENTITY_FLAG_BOUND_SCRIPT_DIRTY; + if (!(entity->flags & ENTITY_FLAG_8000)) { + entity->flags |= ENTITY_FLAG_2000000; + } + entity->boundScript = start_script(entity->boundScriptBytecode, EVT_PRIORITY_A, EVT_FLAG_RUN_IMMEDIATELY); + } + + if (entity->flags & ENTITY_FLAG_2000000) { + if (does_script_exist(entity->boundScript->id)) { + if (entity->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { + update_model_animator(entity->virtualModelIndex); + } else { + exec_entity_model_commandlist(entity->virtualModelIndex); + } + + if (entity->flags & ENTITY_FLAG_ALWAYS_FACE_CAMERA) { + entity->rotation.y = -gCameras[gCurrentCameraID].currentYaw; + } + + if (!(entity->flags & ENTITY_FLAG_SKIP_UPDATE_TRANSFORM_MATRIX)) { + update_entity_transform_matrix(entity); + } + continue; + } else { + entity->flags &= ~ENTITY_FLAG_2000000; + } + } + + if (entity->collisionTimer == 0) { + entity->collisionFlags = entity_get_collision_flags(entity); + + if (entity->collisionFlags) { + EntityCallback handleCollision = entity->blueprint->fpHandleCollision; + + if (handleCollision != NULL && handleCollision(entity) != 0) { + entity->collisionTimer = 10; + entity->flags |= ENTITY_FLAG_DETECTED_COLLISION; + } + } + } else { + entity->collisionTimer--; + if (entity->flags & ENTITY_FLAG_CONTINUOUS_COLLISION) { + if (entity->collisionTimer == 0) { + entity->flags &= ~(ENTITY_FLAG_DISABLE_COLLISION | ENTITY_FLAG_CONTINUOUS_COLLISION); + } else { + entity->flags |= ENTITY_FLAG_DISABLE_COLLISION; + } + } else if (entity->collisionTimer == 0) { + entity->flags &= ~ENTITY_FLAG_DETECTED_COLLISION; + entity->flags &= ~ENTITY_FLAG_PARTNER_COLLISION; + entity->collisionFlags = 0; + } + } + + if (entity->flags & ENTITY_FLAG_ALWAYS_FACE_CAMERA) { + entity->rotation.y = -gCameras[gCurrentCameraID].currentYaw; + } + + if (!gGameStatusPtr->disableScripts) { + if (entity->updateScriptCallback != NULL) { + entity->updateScriptCallback(entity); + } + + if (entity->scriptReadPos != NULL) { + if (entity->scriptDelay != 0) { + entity->scriptDelay--; + if (entity->scriptDelay == 0) { + while (step_entity_commandlist(entity)); + } + } + } + } + + if (!(entity->flags & ENTITY_FLAG_SKIP_UPDATE_TRANSFORM_MATRIX)) { + update_entity_transform_matrix(entity); + } + + if (!(entity->flags & ENTITY_FLAG_DISABLE_COLLISION)) { + update_entity_inverse_rotation_matrix(entity); + } + + if (entity->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { + update_model_animator(entity->virtualModelIndex); + } else { + exec_entity_model_commandlist(entity->virtualModelIndex); + } + + if (entity->shadowIndex >= 0) { + update_entity_shadow_position(entity); + } + + if (entity->flags & ENTITY_FLAG_PENDING_INSTANCE_DELETE) { + delete_entity(entity->listIndex); + } + + if (entity->flags & ENTITY_FLAG_PENDING_FULL_DELETE) { + delete_entity_and_unload_data(entity->listIndex); + } + } + } + } + + update_shadows(); + gCurrentHiddenPanels.tryFlipTrigger = FALSE; +} + +void update_shadows(void) { + s32 i; + + entity_numShadows = 0; + + for (i = 0; i < MAX_SHADOWS; i++) { + Shadow* shadow = get_shadow_by_index(i); + + if (shadow != NULL) { + entity_numShadows++; + + if (!(shadow->flags & ENTITY_FLAG_SKIP_UPDATE)) { + if (shadow->flags & ENTITY_FLAG_ALWAYS_FACE_CAMERA) { + shadow->rotation.y = -gCameras[gCurrentCameraID].currentYaw; + } + + update_shadow_transform_matrix(shadow); + + if (shadow->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { + update_model_animator(shadow->entityModelID); + } else { + exec_entity_model_commandlist(shadow->entityModelID); + } + + if (shadow->flags & ENTITY_FLAG_PENDING_INSTANCE_DELETE) { + _delete_shadow(shadow->listIndex); + } + } + } + } +} + +void set_entity_commandlist(Entity* entity, s32* entityScript) { + entity->scriptReadPos = entityScript; + entity->scriptDelay = 1; + entity->savedReadPos[0] = entity->scriptReadPos; +} + +s32 step_entity_commandlist(Entity* entity) { + s32* args = entity->scriptReadPos; + s32 ret; + s32 labelId; + void (*tempfunc)(Entity*); + + switch (*args++) { + case ENTITY_SCRIPT_OP_End: + entity->scriptDelay = -1; + entity->updateScriptCallback = NULL; + entity->scriptReadPos = NULL; + ret = FALSE; + break; + case ENTITY_SCRIPT_OP_Jump: + entity->scriptReadPos = (s32*)*args; + entity->scriptDelay = 1; + entity->savedReadPos[0] = entity->scriptReadPos; + ret = TRUE; + break; + case ENTITY_SCRIPT_OP_Call: + tempfunc = (void (*)(Entity*))(*args++); + entity->scriptReadPos = args; + (tempfunc)(entity); + ret = TRUE; + break; + case ENTITY_SCRIPT_OP_SetCallback: + entity->scriptDelay = *args++; + entity->updateScriptCallback = (s32 (*)(Entity*)) *args++; + entity->scriptReadPos = args++; + ret = FALSE; + break; + case ENTITY_SCRIPT_OP_Goto: + entity->scriptReadPos = entity->savedReadPos[*args]; + ret = TRUE; + break; + case ENTITY_SCRIPT_OP_Label: + labelId = *args++; + entity->savedReadPos[labelId] = args; + entity->scriptReadPos = args; + ret = TRUE; + break; + case ENTITY_SCRIPT_OP_RestartBoundScript: + if (entity->boundScriptBytecode != NULL) { + entity->flags |= ENTITY_FLAG_BOUND_SCRIPT_DIRTY; + } + entity->scriptReadPos = args++; + ret = TRUE; + break; + case ENTITY_SCRIPT_OP_SetFlags: + entity->flags |= *args++; + entity->scriptReadPos = args++; + ret = TRUE; + break; + case ENTITY_SCRIPT_OP_ClearFlags: + entity->flags &= ~*args++; + entity->scriptReadPos = args++; + ret = TRUE; + break; + case ENTITY_SCRIPT_OP_PlaySound: + sfx_play_sound(*args++); + entity->scriptReadPos = args++; + ret = TRUE; + break; + default: + args++; + entity->scriptReadPos = args++; + ret = TRUE; + break; + } + return ret; +} + +void exec_entity_commandlist(Entity* entity) { + while (step_entity_commandlist(entity)); +} + +void func_8010FD98(void* arg0, s32 alpha) { + if (alpha >= 255) { + gDPSetRenderMode(gMainGfxPos++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2); + gDPSetCombineMode(gMainGfxPos++, G_CC_MODULATEIA, G_CC_MODULATEIA); + } else { + gDPSetCombineMode(gMainGfxPos++, PM_CC_01, PM_CC_02); + gDPSetPrimColor(gMainGfxPos++, 0, 0, 0, 0, 0, alpha); + } +} + +void func_8010FE44(void* arg0) { + func_8010FD98(arg0, D_8014AFB0); +} + +void entity_model_set_shadow_color(void* data) { + s32 alpha = (s32)data; + + gDPSetCombineLERP(gMainGfxPos++, 0, 0, 0, 0, PRIMITIVE, 0, TEXEL0, 0, 0, 0, 0, 0, TEXEL0, 0, PRIMITIVE, 0); + gDPSetPrimColor(gMainGfxPos++, 0, 0, 0, 0, 0, alpha); +} + +void render_entities(void) { + s32 i; + + for (i = 0; i < MAX_ENTITIES; i++) { + Entity* entity = get_entity_by_index(i); + + if (entity != NULL) { + if (!gGameStatusPtr->isBattle) { + if (gEntityHideMode != ENTITY_HIDE_MODE_0 && + !(entity->flags & ENTITY_FLAG_IGNORE_DISTANCE_CULLING) && + dist2D(gPlayerStatusPtr->position.x, + gPlayerStatusPtr->position.z, + entity->position.x, + entity->position.z) > 200.0f + ) { + continue; + } + + if (gEntityHideMode == ENTITY_HIDE_MODE_1) { + if (!(entity->flags & ENTITY_FLAG_DRAW_IF_CLOSE_HIDE_MODE1)) { + continue; + } + } else if (gEntityHideMode == ENTITY_HIDE_MODE_2) { + if (!(entity->flags & ENTITY_FLAG_DRAW_IF_CLOSE_HIDE_MODE2)) { + continue; + } + } + } + + if (!(entity->flags & ENTITY_FLAG_HIDDEN)) { + if (entity->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { + if (D_8014AFB0 == 255) { + if (entity->renderSetupFunc != NULL) { + set_animator_render_callback( + entity->virtualModelIndex, + (void*)(u32) entity->listIndex, + (void (*)(void*)) entity->renderSetupFunc + ); + } + } else { + set_animator_render_callback( + entity->virtualModelIndex, + (void*)(u32) entity->listIndex, + func_8010FE44 + ); + } + + if (entity->gfxBaseAddr == NULL) { + render_animated_model(entity->virtualModelIndex, &entity->transformMatrix); + } else { + render_animated_model_with_vertices(entity->virtualModelIndex, + &entity->transformMatrix, + entity->vertexSegment, + entity->gfxBaseAddr); + } + } else { + if (D_8014AFB0 == 255) { + if (entity->renderSetupFunc != NULL) { + bind_entity_model_setupGfx( + entity->virtualModelIndex, + (void*)(u32) entity->listIndex, + (void (*)(void*)) entity->renderSetupFunc + ); + } else { + get_entity_model(entity->virtualModelIndex)->fpSetupGfxCallback = NULL; + } + } else { + bind_entity_model_setupGfx(entity->virtualModelIndex, (void*)(u32)entity->listIndex, func_8010FE44); + } + + if (entity->gfxBaseAddr == NULL) { + draw_entity_model_A(entity->virtualModelIndex, &entity->transformMatrix); + } else { + draw_entity_model_B(entity->virtualModelIndex, + &entity->transformMatrix, + entity->vertexSegment, + entity->gfxBaseAddr); + } + } + } + } + } + + render_shadows(); +} + +void render_shadows(void) { + s32 i; + + for (i = 0; i < MAX_SHADOWS; i++) { + Shadow* shadow = get_shadow_by_index(i); + + if (shadow != NULL) { + if (shadow->flags & ENTITY_FLAG_HIDDEN) { + if (shadow->flags & ENTITY_FLAG_FADING_AWAY) { + shadow->alpha -= 20; + if (shadow->alpha <= 20) { + shadow->flags |= ENTITY_FLAG_PENDING_INSTANCE_DELETE; + } + } + } else if (shadow->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { + if (shadow->vertexArray == NULL) { + render_animated_model(shadow->entityModelID, &shadow->transformMatrix); + } else { + render_animated_model_with_vertices(shadow->entityModelID, + &shadow->transformMatrix, + shadow->vertexSegment, + shadow->vertexArray); + } + } else { + if (shadow->flags & ENTITY_FLAG_FADING_AWAY) { + shadow->alpha -= 20; + if (shadow->alpha <= 20) { + shadow->flags |= ENTITY_FLAG_PENDING_INSTANCE_DELETE; + } + } + + bind_entity_model_setupGfx(shadow->entityModelID, (void*)(u32)shadow->alpha, entity_model_set_shadow_color); + + if (shadow->vertexArray == NULL) { + draw_entity_model_A(shadow->entityModelID, &shadow->transformMatrix); + } else { + draw_entity_model_B(shadow->entityModelID, + &shadow->transformMatrix, + shadow->vertexSegment, + shadow->vertexArray); + } + } + } + } +} + +void update_entity_transform_matrix(Entity* entity) { + Matrix4f sp18; + Matrix4f sp58; + Matrix4f sp98; + Matrix4f spD8; + Matrix4f sp118; + Matrix4f sp158; + Matrix4f sp198; + + if (entity->updateMatrixOverride != NULL) { + entity->updateMatrixOverride(entity); + return; + } + + guTranslateF(sp58, entity->position.x, entity->position.y, entity->position.z); + guRotateF(spD8, entity->rotation.x, 1.0f, 0.0f, 0.0f); + guRotateF(sp118, entity->rotation.y, 0.0f, 1.0f, 0.0f); + guRotateF(sp158, entity->rotation.z, 0.0f, 0.0f, 1.0f); + guMtxCatF(sp158, spD8, sp18); + guMtxCatF(sp18, sp118, sp98); + guScaleF(sp198, entity->scale.x, entity->scale.y, entity->scale.z); + guMtxCatF(sp198, sp98, sp18); + guMtxCatF(sp18, sp58, sp98); + guMtxF2L(sp98, &entity->transformMatrix); +} + +void update_shadow_transform_matrix(Shadow* shadow) { + Matrix4f sp18; + Matrix4f sp58; + Matrix4f sp98; + Matrix4f spD8; + Matrix4f sp118; + Matrix4f sp158; + Matrix4f sp198; + + guTranslateF(sp58, shadow->position.x, shadow->position.y, shadow->position.z); + guRotateF(sp118, shadow->rotation.x, 1.0f, 0.0f, 0.0f); + guRotateF(spD8, shadow->rotation.y, 0.0f, 1.0f, 0.0f); + guRotateF(sp158, shadow->rotation.z, 0.0f, 0.0f, 1.0f); + guMtxCatF(sp158, sp118, sp98); + guMtxCatF(spD8, sp98, sp98); + guScaleF(sp198, shadow->scale.x, shadow->scale.y, shadow->scale.z); + guMtxCatF(sp198, sp98, sp18); + guMtxCatF(sp18, sp58, sp98); + guMtxF2L(sp98, &shadow->transformMatrix); +} + +void update_entity_inverse_rotation_matrix(Entity* entity) { + Matrix4f sp18; + Matrix4f sp58; + + guRotateF(sp18, -entity->rotation.y, 0.0f, 1.0f, 0.0f); + guRotateF(sp58, -entity->rotation.z, 0.0f, 0.0f, 1.0f); + guMtxCatF(sp18, sp58, sp18); + guRotateF(sp58, -entity->rotation.x, 1.0f, 0.0f, 0.0f); + guMtxCatF(sp18, sp58, entity->inverseTransformMatrix); + + entity->effectiveSize = sqrtf(((SQ(entity->aabb.x) + SQ(entity->aabb.z)) * 0.25f) + SQ(entity->aabb.y)); +} + +Entity* get_entity_by_index(s32 index) { + return (*gCurrentEntityListPtr)[index & 0xFFF]; +} + +Shadow* get_shadow_by_index(s32 index) { + return (*gCurrentShadowListPtr)[index & 0xFFF]; +} + +EntityList* get_entity_list(void) { + EntityList* ret; + + if (!gGameStatusPtr->isBattle) { + ret = &gWorldEntityList; + } else { + ret = &gBattleEntityList; + } + return ret; +} + +ShadowList* get_shadow_list(void) { + ShadowList* ret; + + if (!gGameStatusPtr->isBattle) { + ret = &gWorldShadowList; + } else { + ret = &gBattleShadowList; + } + return ret; +} + +s32 entity_start_script(Entity* entity) { + if (entity->boundScriptBytecode != NULL) { + entity->flags |= ENTITY_FLAG_BOUND_SCRIPT_DIRTY; + return 1; + } + return 0; +} + +u32 get_entity_type(s32 index) { + Entity* entity = get_entity_by_index(index); + + if (entity == NULL) { + return -1; + } else { + return entity->blueprint->entityType; + } +} + +void delete_entity(s32 entityIndex) { + Entity* entity = get_entity_by_index(entityIndex); + + if (entity->dataBuf.any != NULL) { + heap_free(entity->dataBuf.any); + } + + if (!(entity->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL)) { + free_entity_model_by_index(entity->virtualModelIndex); + } else { + delete_model_animator(get_animator_by_index(entity->virtualModelIndex)); + } + + if (entity->shadowIndex >= 0) { + Shadow* shadow = get_shadow_by_index(entity->shadowIndex); + + shadow->flags |= ENTITY_FLAG_FADING_AWAY; + } + + heap_free((*gCurrentEntityListPtr)[entityIndex]); + (*gCurrentEntityListPtr)[entityIndex] = NULL; +} + +void delete_entity_and_unload_data(s32 entityIndex) { + Entity* entity = get_entity_by_index(entityIndex); + + if (entity->dataBuf.any != NULL) { + heap_free(entity->dataBuf.any); + } + + if (!(entity->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL)) { + free_entity_model_by_index(entity->virtualModelIndex); + } else { + delete_model_animator(get_animator_by_index(entity->virtualModelIndex)); + } + + entity_free_static_data(entity->blueprint); + + if (entity->shadowIndex >= 0) { + Shadow* shadow = get_shadow_by_index(entity->shadowIndex); + + shadow->flags |= ENTITY_FLAG_FADING_AWAY; + } + + heap_free((*gCurrentEntityListPtr)[entityIndex]); + (*gCurrentEntityListPtr)[entityIndex] = NULL; +} + +void _delete_shadow(s32 shadowIndex) { + Shadow* shadow = get_shadow_by_index(shadowIndex); + + free_entity_model_by_index(shadow->entityModelID); + heap_free((*gCurrentShadowListPtr)[shadowIndex]); + (*gCurrentShadowListPtr)[shadowIndex] = NULL; +} + +s32 entity_get_collision_flags(Entity* entity) { + u32 listIndex = entity->listIndex; + s32 entityFlags = 0; + u32 flag; + + if (entity->flags & ENTITY_FLAG_PARTNER_COLLISION) { + entityFlags = ENTITY_COLLISION_PARTNER; + entity->flags &= ~ENTITY_FLAG_PARTNER_COLLISION; + } + + flag = gCollisionStatus.currentFloor; + if (flag != -1 && (flag & COLLISION_WITH_ENTITY_BIT) && listIndex == (u8)flag) { + entityFlags |= ENTITY_COLLISION_PLAYER_TOUCH_FLOOR; + } + + flag = gCollisionStatus.lastTouchedFloor; + if (flag != -1 && (flag & COLLISION_WITH_ENTITY_BIT) && listIndex == (u8)flag) { + entityFlags |= ENTITY_COLLISION_PLAYER_LAST_FLOOR; + } + + flag = gCollisionStatus.currentCeiling; + if (flag != -1 && (flag & COLLISION_WITH_ENTITY_BIT) && listIndex == (u8)flag) { + entityFlags |= ENTITY_COLLISION_PLAYER_TOUCH_CEILING; + } + + flag = gCollisionStatus.pushingAgainstWall; + if (flag != -1 && (flag & COLLISION_WITH_ENTITY_BIT) && listIndex == (u8)flag) { + entityFlags |= ENTITY_COLLISION_PLAYER_PUSHING_AGAINST; + } + + flag = gCollisionStatus.lastWallHammered; + if (flag != -1 && (flag & COLLISION_WITH_ENTITY_BIT) && listIndex == (u8)flag) { + entityFlags |= ENTITY_COLLISION_PLAYER_HAMMER; + } + + flag = gCollisionStatus.currentWall; + if (flag != -1 && (flag & COLLISION_WITH_ENTITY_BIT) && listIndex == (u8)flag && gPlayerStatusPtr->pressedButtons & BUTTON_A) { + entityFlags |= ENTITY_COLLISION_PLAYER_TOUCH_WALL; + } + + return entityFlags; +} + +s32 entity_try_partner_interaction_trigger(s32 entityIdx) { + s32 interacted = FALSE; + u32 entityType = get_entity_type(entityIdx); + s32 partnerID = get_current_partner_id(); + Entity* entity; + + switch (partnerID) { + case PARTNER_BOMBETTE: + switch (entityType) { + default: + return FALSE; + case ENTITY_TYPE_BLUE_SWITCH: + case ENTITY_TYPE_RED_SWITCH: + case ENTITY_TYPE_MULTI_TRIGGER_BLOCK: + case ENTITY_TYPE_BRICK_BLOCK: + case ENTITY_TYPE_MULTI_COIN_BRICK: + case ENTITY_TYPE_YELLOW_BLOCK: + case ENTITY_TYPE_SINGLE_TRIGGER_BLOCK: + case ENTITY_TYPE_HIDDEN_YELLOW_BLOCK: + case ENTITY_TYPE_HIDDEN_RED_BLOCK: + case ENTITY_TYPE_RED_BLOCK: + case ENTITY_TYPE_HAMMER1_BLOCK: + case ENTITY_TYPE_HAMMER1_BLOCK_TINY: + case ENTITY_TYPE_SUPER_BLOCK: + case ENTITY_TYPE_BOMBABLE_ROCK: + entity = get_entity_by_index(entityIdx); + entity->flags |= ENTITY_FLAG_PARTNER_COLLISION; + interacted = TRUE; + } + break; + case PARTNER_KOOPER: + switch (entityType) { + default: + return FALSE; + case ENTITY_TYPE_BLUE_SWITCH: + case ENTITY_TYPE_RED_SWITCH: + case ENTITY_TYPE_MULTI_TRIGGER_BLOCK: + case ENTITY_TYPE_BRICK_BLOCK: + case ENTITY_TYPE_MULTI_COIN_BRICK: + case ENTITY_TYPE_YELLOW_BLOCK: + case ENTITY_TYPE_SINGLE_TRIGGER_BLOCK: + case ENTITY_TYPE_HIDDEN_YELLOW_BLOCK: + case ENTITY_TYPE_HIDDEN_RED_BLOCK: + case ENTITY_TYPE_RED_BLOCK: + case ENTITY_TYPE_HEALING_BLOCK: + case ENTITY_TYPE_1C: + case ENTITY_TYPE_SAVE_POINT: + case ENTITY_TYPE_SUPER_BLOCK: + entity = get_entity_by_index(entityIdx); + entity->flags |= ENTITY_FLAG_PARTNER_COLLISION; + interacted = TRUE; + } + break; + } + return interacted; +} + +s32 test_player_entity_aabb(Entity* entity) { + f32 yTemp = entity->position.y - (gPlayerStatus.position.y + gPlayerStatus.colliderHeight); + f32 xCollRadius; + f32 zCollRadius; + f32 xDist; + f32 zDist; + + if (yTemp > 0.0f || gPlayerStatus.colliderHeight + entity->aabb.y < fabsf(yTemp)) { + return 0; + } + + xCollRadius = (gPlayerStatus.colliderDiameter + entity->aabb.x) * 0.5; + xDist = fabsf(gPlayerStatus.position.x - entity->position.x); + zCollRadius = ((gPlayerStatus.colliderDiameter + entity->aabb.z) * 0.5); + zDist = fabsf(gPlayerStatus.position.z - entity->position.z); + + if (xCollRadius < xDist || zCollRadius < zDist) { + return 0; + } + + return 1; +} + +s32 is_player_action_state(s8 actionState) { + return actionState == gPlayerStatus.actionState; +} + +void entity_set_render_script(Entity* entity, EntityModelScript* cmdList) { + if (!(entity->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL)) { + set_entity_model_render_command_list(entity->virtualModelIndex, cmdList); + } +} + +void entity_reset_collision(Entity* entity) { + entity->collisionTimer = 0; + entity->flags &= ~ENTITY_FLAG_DETECTED_COLLISION; +} + +void load_area_specific_entity_data(void) { + if (!isAreaSpecificEntityDataLoaded) { + if (gGameStatusPtr->areaID == AREA_JAN || gGameStatusPtr->areaID == AREA_IWA) { + dma_copy(entity_jan_iwa_ROM_START, entity_jan_iwa_ROM_END, (void*)AREA_SPECIFIC_ENTITY_VRAM); + } else if (gGameStatusPtr->areaID == AREA_SBK || gGameStatusPtr->areaID == AREA_OMO) { + dma_copy(entity_sbk_omo_ROM_START, entity_sbk_omo_ROM_END, (void*)AREA_SPECIFIC_ENTITY_VRAM); + } else { + dma_copy(entity_default_ROM_START, entity_default_ROM_END, (void*)AREA_SPECIFIC_ENTITY_VRAM); + } + + isAreaSpecificEntityDataLoaded = TRUE; + } +} + +void clear_entity_data(s32 arg0) { + s32 i; + + D_801516FC = 1; + entity_numEntities = 0; + entity_numShadows = 0; + entity_updateCounter = 0; + D_80151304 = 0; + + if (!gGameStatusPtr->isBattle) { + gEntityHideMode = ENTITY_HIDE_MODE_0; + } + + isAreaSpecificEntityDataLoaded = FALSE; + gCurrentHiddenPanels.panelsCount = 0; + gCurrentHiddenPanels.activateISpy = FALSE; + if (!arg0) { + D_80151344 = 0; + } + D_8014AFB0 = 255; + + if (!gGameStatusPtr->isBattle) { + wEntityDataLoadedSize = 0; + for (i = 0; i < MAX_ENTITIES; i++) { + wEntityBlueprint[i] = NULL; + } + } else { + bEntityDataLoadedSize = 0; + for (i = 0; i < 4; i++) { + bEntityBlueprint[i] = NULL; + } + } + + if (!gGameStatusPtr->isBattle) { + gEntityHeapBottom = WORLD_ENTITY_HEAP_BOTTOM; + gEntityHeapBase = WORLD_ENTITY_HEAP_BASE; + } else { + gEntityHeapBottom = (s32) BattleEntityHeapBottom; + gEntityHeapBase = gEntityHeapBottom + 0x3000; + } + + gCurrentEntityListPtr = get_entity_list(); + gCurrentShadowListPtr = get_shadow_list(); + + for (i = 0; i < MAX_ENTITIES; i++) { + (*gCurrentEntityListPtr)[i] = NULL; + } + + for (i = 0; i < MAX_SHADOWS; i++) { + (*gCurrentShadowListPtr)[i] = NULL; + } +} + +void init_entity_data(void) { + if (!gGameStatusPtr->isBattle) { + gEntityHeapBottom = WORLD_ENTITY_HEAP_BOTTOM; + gEntityHeapBase = WORLD_ENTITY_HEAP_BASE; + reload_world_entity_data(); + } else { + s32 i; + + for (i = 0; i < 4; i++) { + bEntityBlueprint[i] = 0; + } + gEntityHeapBottom = (s32) BattleEntityHeapBottom; + gEntityHeapBase = gEntityHeapBottom + 0x3000; + } + gCurrentEntityListPtr = get_entity_list(); + gCurrentShadowListPtr = get_shadow_list(); + entity_numEntities = 0; + entity_numShadows = 0; +} + +void reload_world_entity_data(void) { + s32 i; + s32 totalSize = 0; + s32 temp1; + s32 dataLength; + void* gfxData; + void* animData; + + for (i = 0; i < MAX_ENTITIES; i++) { + EntityBlueprint* bp = wEntityBlueprint[i]; + if (bp == NULL) { + break; + } + + if (!(bp->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL)) { + void* gfxData; + + dataLength = ((bp->dma.end - bp->dma.start) >> 2); + gfxData = (void*)(gEntityHeapBase - totalSize * 4 - dataLength * 4); + totalSize += dma_copy(bp->dma.start, bp->dma.end, gfxData) >> 2; + } else { + DmaEntry* dmaList = bp->dmaList; + + if (bp->entityType == ENTITY_TYPE_RESET_MUNCHLESIA) { + gfxData = (void*)gEntityHeapBottom; + temp1 = dma_copy(dmaList[0].start, dmaList[0].end, gfxData) >> 2; + dma_copy(dmaList[1].start, dmaList[1].end, (void*)(gEntityHeapBottom + temp1 * 4)) >> 2; + animData = (void*)(gEntityHeapBottom + temp1 * 4); + entity_swizzle_anim_pointers(bp, animData, gfxData); + } else { + s32 temp5; + s32 q; + + dataLength = ((dmaList[0].end - dmaList[0].start) >> 2); + q = gEntityHeapBase - totalSize * 4; + gfxData = (void*)(q - dataLength * 4); + totalSize += dma_copy(dmaList[0].start, dmaList[0].end, gfxData) >> 2; + + dataLength = ((dmaList[1].end - dmaList[1].start) >> 2); + q = gEntityHeapBase - totalSize * 4; + animData = (void*)(q - dataLength * 4); + totalSize += dma_copy(dmaList[1].start, dmaList[1].end, animData) >> 2; + + entity_swizzle_anim_pointers(bp, animData, gfxData); + } + } + } +} + +void entity_swizzle_anim_pointers(EntityBlueprint* entityData, void* baseAnim, void* baseGfx) { + StaticAnimatorNode* node; + s32* ptr = (s32*)((s32)baseAnim + (s32)entityData->modelAnimationNodes); + + while (TRUE) { + if (*ptr == -1) { + *ptr = 0; + return; + } + node = (StaticAnimatorNode*)((s32)baseAnim + ((*ptr) & 0xFFFF)); + *ptr++ = (s32)node; + + if ((s32)node->displayList != -1) { + node->displayList = (Gfx*)((s32)baseGfx + ((s32)(node->displayList) & 0xFFFF)); + } else { + node->displayList = NULL; + } + + if ((s32)node->sibling != -1) { + node->sibling = (StaticAnimatorNode*)((s32)baseAnim + ((s32)(node->sibling) & 0xFFFF)); + } else { + node->sibling = NULL; + } + + if ((s32)node->child != -1) { + node->child = (StaticAnimatorNode*)((s32)baseAnim + ((s32)(node->child) & 0xFFFF)); + } else { + node->child = NULL; + } + + if ((s32)node->vtxList != -1) { + node->vtxList = (Vtx*)((s32)baseGfx + ((s32)(node->vtxList) & 0xFFFFF)); + } else { + node->vtxList = NULL; + } + } +} + +s32 is_entity_data_loaded(Entity* entity, EntityBlueprint* blueprint, s32* loadedStart, s32* loadedEnd) { + EntityBlueprint** blueprints; + s32 i; + s32 ret; + s32 size; + DmaEntry* entDmaList; + + *loadedStart = 0; + *loadedEnd = 0; + ret = FALSE; + + if (!gGameStatusPtr->isBattle) { + blueprints = wEntityBlueprint; + } else { + blueprints = bEntityBlueprint; + } + + for (i = 0; i < MAX_ENTITIES; i++, blueprints++) { + EntityBlueprint* bp = *blueprints; + if (bp == NULL) { + blueprints[0] = blueprint; + blueprints[1] = NULL; + ret = TRUE; + if (blueprint->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { + s32 size; + entDmaList = blueprint->dmaList; + size = (entDmaList[0].end - entDmaList[0].start) >> 2; + *loadedEnd = *loadedStart + size; + } + break; + } else { + DmaEntry* bpDmaList = bp->dmaList; + do {} while (0); // TODO find better match + entDmaList = blueprint->dmaList; + if (bpDmaList == entDmaList) { + if (blueprint->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { + s32 size = (bpDmaList[0].end - bpDmaList[0].start) >> 2; + *loadedEnd = *loadedStart + size; + } + break; + } else if (bp == blueprint) { + if (bp->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { + s32 size = (entDmaList[0].end - entDmaList[0].start) >> 2; + *loadedEnd = *loadedStart + size; + } + break; + } else { + if (bp->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { + s32 size = (bpDmaList[0].end - bpDmaList[0].start) >> 2; + *loadedEnd = *loadedStart = *loadedStart + size; + size = (bpDmaList[1].end - bpDmaList[1].start) >> 2; + *loadedStart = *loadedStart + size; + } else { + *loadedStart += (bp->dma.end - bp->dma.start) >> 2; + } + } + } + } + + return ret; +} + +void load_simple_entity_data(Entity* entity, EntityBlueprint* bp, s32 listIndex) { + s32 loadedStart; + s32 loadedEnd; + s32 entitySize; + u32 temp; + s32 totalSize; + + entity->vertexSegment = 0xA; + if (!gGameStatusPtr->isBattle) { + totalSize = wEntityDataLoadedSize; + } else { + totalSize = bEntityDataLoadedSize; + } + + if (is_entity_data_loaded(entity, bp, &loadedStart, &loadedEnd)) { + if (totalSize + ((bp->dma.end - bp->dma.start) >> 2) > 0x5FFCU) { + get_entity_type(entity->listIndex); + get_entity_type(entity->listIndex); + PANIC(); + } + entitySize = (bp->dma.end - bp->dma.start) >> 2; + entity->gfxBaseAddr = (void*)(gEntityHeapBase - totalSize * 4 - entitySize * 4); + totalSize += dma_copy(bp->dma.start, bp->dma.end, entity->gfxBaseAddr) >> 2; + get_entity_type(entity->listIndex); + } else { + entitySize = (bp->dma.end - bp->dma.start) >> 2; + entity->gfxBaseAddr = (void*)(gEntityHeapBase - loadedStart * 4 - entitySize * 4); + get_entity_type(entity->listIndex); + } + + if (!gGameStatusPtr->isBattle) { + wEntityDataLoadedSize = totalSize; + } else { + bEntityDataLoadedSize = totalSize; + } +} + +void load_split_entity_data(Entity* entity, EntityBlueprint* entityData, s32 listIndex) { + s32 swizzlePointers = FALSE; + s32 loadedStart, loadedEnd; + void* animBaseAddr; + s16* animationScript; + StaticAnimatorNode** animationNodes; + s32 specialSize; + s32 dma1size; + s32 dma2size_1; + s32 dma2size_2; + s32 totalLoaded; + + if (entityData->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { + DmaEntry* dmaList = entityData->dmaList; + entity->vertexSegment = 0xA; + + switch (entityData->entityType) { + case ENTITY_TYPE_RESET_MUNCHLESIA: + case ENTITY_TYPE_MUNCHLESIA_ENVELOP: + case ENTITY_TYPE_MUNCHLESIA_CHEWING: + case ENTITY_TYPE_MUNCHLESIA_RESET1: + specialSize = 0x1000; + break; + case ENTITY_TYPE_MUNCHLESIA_GRAB: + case ENTITY_TYPE_MUNCHLESIA_BEGIN_CHEW: + case ENTITY_TYPE_MUNCHLESIA_SPIT_OUT: + case ENTITY_TYPE_MUNCHLESIA_RESET2: + specialSize = 0x2BC0; + break; + default: + specialSize = 0; + break; + } + + if (specialSize != 0) { + if (entityData->entityType == ENTITY_TYPE_RESET_MUNCHLESIA) { + is_entity_data_loaded(entity, entityData, &loadedStart, &loadedEnd); + } + specialSize -= 0x1000; + + dma1size = dma_copy(dmaList[0].start, dmaList[0].end, (void*)(gEntityHeapBottom + specialSize * 4)) / 4; + entity->gfxBaseAddr = (void*)(gEntityHeapBottom + specialSize * 4); + dma_copy(dmaList[1].start, dmaList[1].end, (void*)(gEntityHeapBottom + specialSize * 4 + dma1size * 4)); + animBaseAddr = (void*)(gEntityHeapBottom + specialSize * 4 + dma1size * 4); + swizzlePointers = TRUE; + } else if (is_entity_data_loaded(entity, entityData, &loadedStart, &loadedEnd)) { + if (!gGameStatusPtr->isBattle) { + totalLoaded = wEntityDataLoadedSize; + } else { + totalLoaded = bEntityDataLoadedSize; + } + + if ((totalLoaded + ((dmaList[0].end - dmaList[0].start) >> 2)) > 0x5FFCU) { + get_entity_type(entity->listIndex); + PANIC(); + } + + if ((totalLoaded + ((dmaList[1].end - dmaList[1].start) >> 2)) > 0x5FFCU) { + get_entity_type(entity->listIndex); + PANIC(); + } + + dma2size_1 = dma_copy(dmaList[0].start, dmaList[0].end, dmaList[0].start + ((gEntityHeapBase - totalLoaded * 4 - (s32)dmaList[0].end) >> 2) * 4) >> 2; + entity->gfxBaseAddr = (void*)(gEntityHeapBase - totalLoaded * 4 - dma2size_1 * 4); + totalLoaded += dma2size_1; + + dma2size_2 = dma_copy(dmaList[1].start, dmaList[1].end, dmaList[1].start + ((gEntityHeapBase - totalLoaded * 4 - (s32)dmaList[1].end) >> 2) * 4) >> 2; + animBaseAddr = (void*)(gEntityHeapBase - totalLoaded * 4 - dma2size_2 * 4); + totalLoaded += dma2size_2; + get_entity_type(entity->listIndex); + + if (!gGameStatusPtr->isBattle) { + wEntityDataLoadedSize = totalLoaded; + } else { + bEntityDataLoadedSize = totalLoaded; + } + swizzlePointers = TRUE; + } else { + u32 temp = (dmaList[0].end - dmaList[0].start) >> 2; + entity->gfxBaseAddr = (void*)(gEntityHeapBase - loadedStart * 4 - temp * 4); + temp = (dmaList[1].end - dmaList[1].start) >> 2; + animBaseAddr = (void*)(gEntityHeapBase - loadedEnd * 4 - temp * 4); + get_entity_type(entity->listIndex); + } + } else { + entity->virtualModelIndex = create_model_animator(entityData->renderCommandList); + load_model_animator_tree(entity->virtualModelIndex, entityData->modelAnimationNodes); + update_model_animator(entity->virtualModelIndex); + return; + } + animationScript = entityData->renderCommandList; + animationNodes = (StaticAnimatorNode**)((s32)animBaseAddr + (s32)entityData->modelAnimationNodes); + if (swizzlePointers) { + entity_swizzle_anim_pointers(entityData, animBaseAddr, entity->gfxBaseAddr); + } + entity->virtualModelIndex = create_mesh_animator(animationScript, animBaseAddr); + load_mesh_animator_tree(entity->virtualModelIndex, animationNodes); + update_model_animator(entity->virtualModelIndex); + entity->flags |= ENTITY_FLAG_HAS_ANIMATED_MODEL; +} + +s32 func_80111790(EntityBlueprint* data) { + s32 i; + + for (i = 0; i < ARRAY_COUNT(*gCurrentEntityListPtr); i++) { + Entity* entity = (*gCurrentEntityListPtr)[i]; + + if (entity != NULL && entity->blueprint->dma.start != NULL) { + if (entity->blueprint->dma.start == entity->blueprint) { + return TRUE; + } + } + } + return FALSE; +} + +void entity_free_static_data(EntityBlueprint* data) { + s32 freeSlot; + s32 size; + EntityBlueprint* bp; + + for (freeSlot = 0; freeSlot < MAX_ENTITIES; freeSlot++) { + bp = wEntityBlueprint[freeSlot]; + if (bp == NULL) { + break; + } + } + + if (freeSlot < MAX_ENTITIES) { + bp = wEntityBlueprint[freeSlot - 1]; + if (bp == data) { + if (bp->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { + DmaEntry* dmaList = bp->dmaList; + size = ((dmaList[0].end - dmaList[0].start) >> 2); + size += ((dmaList[1].end - dmaList[1].start) >> 2); + if (!func_80111790(bp)) { + wEntityBlueprint[freeSlot - 1] = NULL; + wEntityDataLoadedSize -= size; + } + } else { + size = (bp->dma.end - bp->dma.start) >> 2; + if (!func_80111790(bp)) { + wEntityBlueprint[freeSlot - 1] = NULL; + wEntityDataLoadedSize -= size; + } + } + } + } +} + +s32 create_entity(EntityBlueprint* bp, ...) { + va_list ap; + EntityBlueprint** bpPtr; + f32 x, y, z; + f32 rotY; + s32 listIndex; + Entity* entity; + s32* args; + + va_start(ap, bp); + // needed to match + bpPtr = &bp; + *bpPtr = bp; + + load_area_specific_entity_data(); + + x = va_arg(ap, s32); + y = va_arg(ap, s32); + z = va_arg(ap, s32); + rotY = va_arg(ap, s32); + + args = &CreateEntityVarArgBuffer[2]; + + *args-- = 0; + *args-- = 0; + *args = 0; + + for (listIndex = 3; listIndex > 0; listIndex--) { + s32 arg = va_arg(ap, s32); + + if (arg == MAKE_ENTITY_END) { + break; + } + *args++ = arg; + } + + va_end(ap); + + for (listIndex = 0; listIndex < ARRAY_COUNT(*gCurrentEntityListPtr); listIndex++) { + if ((*gCurrentEntityListPtr)[listIndex] == NULL) { + break; + } + } + + if (listIndex >= MAX_ENTITIES) { + return -1; + } + + (*gCurrentEntityListPtr)[listIndex] = entity = heap_malloc(sizeof(*entity)); + mem_clear(entity, sizeof(*entity)); + entity->dataBuf.any = NULL; + if (bp->typeDataSize != 0) { + entity->dataBuf.any = heap_malloc(bp->typeDataSize); + mem_clear(entity->dataBuf.any, bp->typeDataSize); + } + entity->type = bp->entityType; + entity->listIndex = listIndex; + entity->boundScript = NULL; + entity->updateMatrixOverride = NULL; + entity->blueprint = bp; + entity->scriptReadPos = bp->updateEntityScript; + entity->scriptDelay = entity->scriptReadPos != NULL ? 1 : 0; + entity->savedReadPos[0] = bp->updateEntityScript; + entity->updateScriptCallback = NULL; + entity->flags = bp->flags | ENTITY_FLAG_CREATED; + entity->collisionFlags = 0; + entity->collisionTimer = 0; + entity->renderSetupFunc = NULL; + entity->position.x = x; + entity->position.y = y; + entity->position.z = z; + entity->rotation.x = 0.0f; + entity->rotation.y = rotY; + entity->rotation.z = 0.0f; + entity->scale.x = 1.0f; + entity->scale.y = 1.0f; + entity->scale.z = 1.0f; + entity->aabb.x = bp->aabbSize[0]; + entity->aabb.y = bp->aabbSize[1]; + entity->aabb.z = bp->aabbSize[2]; + entity->unk_05 = 1; + entity->unk_08 = -1; + entity->alpha = 255; + entity->virtualModelIndex = -1; + entity->shadowIndex = -1; + entity->gfxBaseAddr = NULL; + + if (!(bp->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL)) { + if (bp->dma.start != 0) { + load_simple_entity_data(entity, bp, listIndex); + } + if (bp->renderCommandList != NULL) { + entity->virtualModelIndex = load_entity_model(bp->renderCommandList); + exec_entity_model_commandlist(entity->virtualModelIndex); + } + } else { + load_split_entity_data(entity, bp, listIndex); + } + + if (bp->entityType != ENTITY_TYPE_SHADOW && (entity->flags & (ENTITY_FLAG_FIXED_SHADOW_SIZE | ENTITY_FLAG_HAS_SHADOW))) { + create_entity_shadow(entity, x, y, z); + } + + switch (bp->entityType) { + case ENTITY_TYPE_BLUE_SWITCH: + case ENTITY_TYPE_RED_SWITCH: + case ENTITY_TYPE_SIMPLE_SPRING: + case ENTITY_TYPE_SCRIPT_SPRING: + case ENTITY_TYPE_STAR_BOX_LAUCHER: + entity->flags |= ENTITY_FLAG_4000; + break; + } + + if (bp->fpInit != NULL) { + bp->fpInit(entity); + } + + update_entity_transform_matrix(entity); + return entity->listIndex; +} + +s32 create_shadow_from_data(ShadowBlueprint* bp, f32 x, f32 y, f32 z) { + Shadow* shadow; + s32 i; + + for (i = 0; i < ARRAY_COUNT(*gCurrentShadowListPtr); i++) { + if ((*gCurrentShadowListPtr)[i] == NULL) { + break; + } + } + + ASSERT(i < ARRAY_COUNT(*gCurrentShadowListPtr)); + + shadow = heap_malloc(sizeof(*shadow)); + (*gCurrentShadowListPtr)[i] = shadow; + mem_clear(shadow, sizeof(*shadow)); + shadow->listIndex = i; + shadow->flags = bp->flags | ENTITY_FLAG_CREATED; + shadow->alpha = 128; + shadow->unk_06 = 0x80; + shadow->position.x = x; + shadow->position.y = y; + shadow->position.z = z; + shadow->scale.x = 1.0f; + shadow->scale.y = 1.0f; + shadow->scale.z = 1.0f; + + if (bp->animModelNode != NULL) { + shadow->flags |= ENTITY_FLAG_HAS_ANIMATED_MODEL; + shadow->entityModelID = create_model_animator(bp->renderCommandList); + load_model_animator_tree(shadow->entityModelID, bp->animModelNode); + } else { + shadow->entityModelID = load_entity_model(bp->renderCommandList); + } + + if (bp->onCreateCallback != NULL) { + bp->onCreateCallback(shadow); + } + update_shadow_transform_matrix(shadow); + return shadow->listIndex; +} + +s32 MakeEntity(Evt* script, s32 isInitialCall) { + Bytecode* args = script->ptrReadPos; + EntityBlueprint* entityData; + s32 x, y, z; + s32 flags; + s32 nextArg; + s32 entityIndex; + s32 endOfArgs; + s32* varArgBufPos; + + if (isInitialCall != TRUE) { + return ApiStatus_DONE2; + } + + entityData = (EntityBlueprint*)evt_get_variable(script, *args++); + varArgBufPos = &CreateEntityVarArgBuffer[2]; + endOfArgs = MAKE_ENTITY_END; + x = evt_get_variable(script, *args++); + y = evt_get_variable(script, *args++); + z = evt_get_variable(script, *args++); + flags = evt_get_variable(script, *args++); + + *varArgBufPos-- = 0; + *varArgBufPos-- = 0; + *varArgBufPos = 0; + + do { + nextArg = evt_get_variable(script, *args++); + + if (nextArg != endOfArgs) { + *varArgBufPos++ = nextArg; + } + } while (nextArg != endOfArgs); + + entityIndex = create_entity(entityData, x, y, z, flags, CreateEntityVarArgBuffer[0], CreateEntityVarArgBuffer[1], CreateEntityVarArgBuffer[2], endOfArgs); + gLastCreatedEntityIndex = entityIndex; + script->varTable[0] = entityIndex; + return ApiStatus_DONE2; +} + +ApiStatus SetEntityCullMode(Evt* script, s32 isInitialCall) { + Entity* entity = get_entity_by_index(gLastCreatedEntityIndex); + Bytecode* args = script->ptrReadPos; + s32 mode = evt_get_variable(script, *args++); + + if (mode == 0) { + entity->flags |= ENTITY_FLAG_DRAW_IF_CLOSE_HIDE_MODE1; + } else if (mode == 1) { + entity->flags |= ENTITY_FLAG_DRAW_IF_CLOSE_HIDE_MODE2; + } else if (mode == 2) { + entity->flags |= ENTITY_FLAG_DRAW_IF_CLOSE_HIDE_MODE2 | ENTITY_FLAG_DRAW_IF_CLOSE_HIDE_MODE1; + } else { + entity->flags |= ENTITY_FLAG_IGNORE_DISTANCE_CULLING | ENTITY_FLAG_DRAW_IF_CLOSE_HIDE_MODE2 | + ENTITY_FLAG_DRAW_IF_CLOSE_HIDE_MODE1; + } + return ApiStatus_DONE2; +} + +ApiStatus UseDynamicShadow(Evt* script, s32 isInitialCall) { + Entity* entity = get_entity_by_index(gLastCreatedEntityIndex); + Bytecode* args = script->ptrReadPos; + + if (evt_get_variable(script, *args++)) { + Shadow* shadow; + + entity->flags |= ENTITY_FLAG_HAS_DYNAMIC_SHADOW; + shadow = get_shadow_by_index(entity->shadowIndex); + shadow->flags |= ENTITY_FLAG_SHADOW_POS_DIRTY; + } else { + entity->flags &= ~ENTITY_FLAG_HAS_DYNAMIC_SHADOW; + } + + return ApiStatus_DONE2; +} + +ApiStatus AssignScript(Evt* script, s32 isInitialCall) { + Bytecode* args = script->ptrReadPos; + + if (isInitialCall == TRUE) { + EvtScript* toBind = (EvtScript*)evt_get_variable(script, *args++); + + get_entity_by_index(gLastCreatedEntityIndex)->boundScriptBytecode = toBind; + return ApiStatus_DONE2; + } + + return ApiStatus_DONE1; +} + +ApiStatus AssignSwitchFlag(Evt* script, s32 isInitialCall) { + Bytecode* args = script->ptrReadPos; + + if (isInitialCall == TRUE) { + s32 areaFlag = evt_get_variable(script, *args++); + Entity* entity = get_entity_by_index(gLastCreatedEntityIndex); + SwitchData* data = entity->dataBuf.swtch; + + data->areaFlagIndex = areaFlag; + if (get_area_flag(areaFlag) != 0) { + entity->flags |= ENTITY_FLAG_PENDING_INSTANCE_DELETE; + } + return ApiStatus_DONE2; + } + + return ApiStatus_DONE1; +} + +ApiStatus AssignBlockFlag(Evt* script, s32 isInitialCall) { + Bytecode* args = script->ptrReadPos; + + if (isInitialCall == TRUE) { + s32 index = evt_get_variable_index(script, *args++); + + BlockData* data = get_entity_by_index(gLastCreatedEntityIndex)->dataBuf.block; + data->gameFlagIndex = index; + + return ApiStatus_DONE2; + } + + return ApiStatus_DONE1; +} + +ApiStatus AssignChestFlag(Evt* script, s32 isInitialCall) { + Bytecode* args = script->ptrReadPos; + + if (isInitialCall == TRUE) { + ChestData* data = get_entity_by_index(gLastCreatedEntityIndex)->dataBuf.chest; + data->gameFlagIndex = evt_get_variable_index(script, *args); + + return ApiStatus_DONE2; + } + + return ApiStatus_DONE1; +} + +ApiStatus AssignPanelFlag(Evt* script, s32 isInitialCall) { + Bytecode* args = script->ptrReadPos; + + if (isInitialCall == TRUE) { + HiddenPanelData* data = get_entity_by_index(gLastCreatedEntityIndex)->dataBuf.hiddenPanel; + + data->pickupVar = evt_get_variable_index(script, *args++); + return ApiStatus_DONE2; + } + + return ApiStatus_DONE1; +} + +ApiStatus AssignCrateFlag(Evt* script, s32 isInitialCall) { + Bytecode* args = script->ptrReadPos; + + if (isInitialCall == TRUE) { + WoodenCrateData* data = get_entity_by_index(gLastCreatedEntityIndex)->dataBuf.crate; + + data->globalFlagIndex = evt_get_variable_index(script, *args++); + return ApiStatus_DONE2; + } + + return ApiStatus_DONE1; +} + +s32 create_entity_shadow(Entity* entity, f32 x, f32 y, f32 z) { + u16 staticFlags = entity->blueprint->flags; + s32 type; + s16 shadowIndex; + + if (staticFlags & ENTITY_FLAG_FIXED_SHADOW_SIZE) { + if (staticFlags & ENTITY_FLAG_SQUARE_SHADOW) { + type = 2; + } else { + type = 3; + } + } else { + type = ((staticFlags >> 11) ^ 1) & 1; + } + + shadowIndex = create_shadow_type(type, x, y, z); + entity->shadowIndex = shadowIndex; + + get_shadow_by_index(shadowIndex)->flags |= ENTITY_FLAG_DARK_SHADOW | ENTITY_FLAG_SHADOW_POS_DIRTY; + + return entity->shadowIndex; +} + +s32 create_shadow_type(s32 type, f32 x, f32 y, f32 z) { + s32 isFixedSize = FALSE; + ShadowBlueprint* bp = &CircularShadowA; + s32 shadowIndex; + + switch (type) { + case 2: + isFixedSize = TRUE; + case 0: + bp = &CircularShadowA; + break; + case 3: + isFixedSize = TRUE; + case 1: + bp = &SquareShadow; + break; + case 5: + isFixedSize = TRUE; + case 4: + bp = &CircularShadowB; + break; + } + + shadowIndex = create_shadow_from_data(bp, x, y, z); + + if (isFixedSize) { + get_shadow_by_index(shadowIndex)->flags |= ENTITY_FLAG_FIXED_SHADOW_SIZE; + } + + return shadowIndex; +} + +void delete_shadow(s32 shadowIndex) { + _delete_shadow(shadowIndex); +} + +void update_entity_shadow_position(Entity* entity) { + Shadow* shadow = get_shadow_by_index(entity->shadowIndex); + + if (shadow != NULL) { + f32 rayX; + f32 rayY; + f32 rayZ; + f32 hitYaw; + f32 hitPitch; + f32 hitLength; + f32 origHitLength; + + if (entity->alpha < 255) { + shadow->alpha = entity->alpha / 2; + } else { + u8 alphaTemp; + + if (shadow->flags & ENTITY_FLAG_DARK_SHADOW) { + alphaTemp = 160; + } else { + alphaTemp = 128; + } + shadow->alpha = alphaTemp; + } + + if (!(entity->flags & ENTITY_FLAG_HAS_DYNAMIC_SHADOW)) { + if (shadow->flags & ENTITY_FLAG_SHADOW_POS_DIRTY) { + shadow->flags &= ~ENTITY_FLAG_SHADOW_POS_DIRTY; + } else { + return; + } + } + + rayX = entity->position.x; + rayY = entity->position.y; + rayZ = entity->position.z; + + if (!entity_raycast_down(&rayX, &rayY, &rayZ, &hitYaw, &hitPitch, &hitLength) && hitLength == 32767.0f) { + hitLength = 0.0f; + } + + origHitLength = hitLength; + + if (shadow->flags & ENTITY_FLAG_FIXED_SHADOW_SIZE) { + hitLength = 212.5f; + shadow->scale.x = entity->aabb.x / hitLength; + shadow->scale.z = entity->aabb.z / hitLength; + } else { + hitLength = ((hitLength / 150.0f) + 0.95) * 250.0; + shadow->scale.x = (entity->aabb.x / hitLength) * entity->scale.x; + shadow->scale.z = (entity->aabb.z / hitLength) * entity->scale.z; + } + + shadow->position.x = entity->position.x; + shadow->position.z = entity->position.z; + shadow->position.y = rayY; + entity->shadowPosY = rayY; + shadow->rotation.x = hitYaw; + shadow->rotation.z = hitPitch; + shadow->rotation.y = entity->rotation.y; + + if (entity->position.y < rayY) { + shadow->flags |= ENTITY_FLAG_SKIP_UPDATE; + entity->position.y = rayY + 10.0f; + } else { + shadow->flags &= ~ENTITY_FLAG_SKIP_UPDATE; + } + + shadow->flags = (shadow->flags & ~ENTITY_FLAG_HIDDEN) | ((u16)entity->flags & ENTITY_FLAG_HIDDEN); + if (!(entity->flags & ENTITY_FLAG_400) && origHitLength == 0.0f) { + shadow->flags |= ENTITY_FLAG_HIDDEN; + } + } else { + entity->shadowPosY = 0.0f; + } +} + +s32 entity_raycast_down(f32* x, f32* y, f32* z, f32* hitYaw, f32* hitPitch, f32* hitLength) { + f32 hitX, hitY, hitZ; + f32 hitDepth; + f32 hitNx, hitNy, hitNz; + s32 entityID; + s32 colliderID; + s32 hitID; + s32 ret; + + hitDepth = 32767.0f; + *hitLength = 32767.0f; + entityID = test_ray_entities(*x, *y, *z, 0.0f, -1.0f, 0.0f, &hitX, &hitY, &hitZ, &hitDepth, &hitNx, &hitNy, &hitNz); + hitID = -1; + ret = FALSE; + + if ((entityID >= 0) && ((get_entity_type(entityID) != ENTITY_TYPE_PUSH_BLOCK) || (hitNx == 0.0f && hitNz == 0.0f && hitNy == 1.0))) { + hitID = entityID | COLLISION_WITH_ENTITY_BIT; + } + + colliderID = test_ray_colliders(0x10000, *x, *y, *z, 0.0f, -1.0f, 0.0f, &hitX, &hitY, &hitZ, &hitDepth, &hitNx, + &hitNy, &hitNz); + if (colliderID >= 0) { + hitID = colliderID; + } + + if (hitID >= 0) { + *hitLength = hitDepth; + *y = hitY; + *hitYaw = -atan2(0.0f, 0.0f, hitNz * 100.0f, hitNy * 100.0f); + *hitPitch = -atan2(0.0f, 0.0f, hitNx * 100.0f, hitNy * 100.0f); + ret = TRUE; + } else { + *hitYaw = 0.0f; + *hitPitch = 0.0f; + } + return ret; +} + +void set_standard_shadow_scale(Shadow* shadow, f32 height) { + if (!gGameStatusPtr->isBattle) { + shadow->scale.x = 0.13 - (height / 2600.0f); + } else { + shadow->scale.x = 0.12 - (height / 3600.0f); + } + + if (shadow->scale.x < 0.01) { + shadow->scale.x = 0.01f; + } + shadow->scale.z = shadow->scale.x; +} + +void set_npc_shadow_scale(Shadow* shadow, f32 height, f32 npcRadius) { + if (!gGameStatusPtr->isBattle) { + shadow->scale.x = 0.13 - (height / 2600.0f); + } else { + shadow->scale.x = 0.12 - (height / 3600.0f); + } + + if (shadow->scale.x < 0.01) { + shadow->scale.x = 0.01f; + } + + if (npcRadius > 60.0f) { + shadow->scale.z = shadow->scale.x * 2.0f; + } else { + shadow->scale.z = shadow->scale.x; + } +} + +void set_peach_shadow_scale(Shadow* shadow, f32 scale) { + PlayerStatus* playerStatus = &gPlayerStatus; + f32 phi_f2 = 0.12f; + + if (!gGameStatusPtr->isBattle) { + switch (playerStatus->anim) { + //TODO raw player anims + case 0xC0018: + case 0xC0019: + case 0xC001A: + case 0xD0008: + shadow->scale.x = 0.26f - (scale / 2600.0f); + if (shadow->scale.x < 0.01) { + shadow->scale.x = 0.01f; + } + shadow->scale.z = 0.13f - (scale / 2600.0f); + if (shadow->scale.z < 0.01) { + shadow->scale.z = 0.01f; + } + return; + } + + phi_f2 = 0.16f; + } + + shadow->scale.x = phi_f2 - (scale / 3600.0f); + if (shadow->scale.x < 0.01) { + shadow->scale.x = 0.01f; + } + shadow->scale.z = shadow->scale.x; +} + +s32 is_block_on_ground(Entity* block) { + f32 x = block->position.x; + f32 y = block->position.y; + f32 z = block->position.z; + f32 hitYaw; + f32 hitPitch; + f32 hitLength; + s32 ret; + + entity_raycast_down(&x, &y, &z, &hitYaw, &hitPitch, &hitLength); + + ret = hitLength; + if (ret == 32767) { + ret = FALSE; + } + + return ret; +} diff --git a/src/filemenu/filemenu_common.c b/src/filemenu/filemenu_common.c index 4f7baf9da1..5176849efe 100644 --- a/src/filemenu/filemenu_common.c +++ b/src/filemenu/filemenu_common.c @@ -181,14 +181,14 @@ BSS u16 D_802517E0[2][0x400] ALIGNED(16); BSS u8 filemenu_glyphBuffer[20][0x80]; #endif -void filemenu_draw_rect(s32 ulx, s32 uly, s32 lrx, s32 lry, s32 tileDescriptor, s32 uls, s32 ult, s32 dsdx, s32 dtdy) { +void filemenu_draw_rect(s32 ulx, s32 uly, s32 lrx, s32 lry, s32 tileIdx, s32 uls, s32 ult, s32 dsdx, s32 dtdy) { if (ulx <= -2688 || uly <= -2688 || lrx <= 0 || lry <= 0) { return; } if (ulx >= 1280 || uly >= 960 || lrx >= 2688 || lry >= 2688) { return; } - gSPScisTextureRectangle(gMainGfxPos++, ulx, uly, lrx, lry, tileDescriptor, uls, ult, dsdx, dtdy); + gSPScisTextureRectangle(gMainGfxPos++, ulx, uly, lrx, lry, tileIdx, uls, ult, dsdx, dtdy); } void filemenu_set_selected(MenuPanel* menu, s32 col, s32 row) { diff --git a/src/game_states.c b/src/game_states.c new file mode 100644 index 0000000000..77f279b994 --- /dev/null +++ b/src/game_states.c @@ -0,0 +1,180 @@ +#include "common.h" + +extern GameMode gMainGameState[2]; // TODO rename + +void state_delegate_NOP(void) { +} + +void clear_game_modes(void) { + GameMode* gameMode; + s32 i; + + for (gameMode = gMainGameState, i = 0; i < ARRAY_COUNT(gMainGameState); i++, gameMode++) { + gameMode->flags = 0; + } +} + +GameMode* set_next_game_mode(GameMode* arg0) { + GameMode* gameMode; + s32 i; + + for (gameMode = gMainGameState, i = 0; i < ARRAY_COUNT(gMainGameState); i++, gameMode++) { + if (gameMode->flags == 0) { + break; + } + } + + ASSERT(i < ARRAY_COUNT(gMainGameState)); + + gameMode->flags = 1 | 2; + gameMode->init = arg0->init; + gameMode->step = arg0->step; + gameMode->render = arg0->render; + gameMode->unk_0C = NULL; + + if (gameMode->init == NULL) { + gameMode->init = state_delegate_NOP; + } + if (gameMode->step == NULL) { + gameMode->step = state_delegate_NOP; + } + if (gameMode->unk_0C == NULL) { + gameMode->unk_0C = state_delegate_NOP; + } + if (gameMode->render == NULL) { + gameMode->render = state_delegate_NOP; + } + + gameMode->renderAux = state_delegate_NOP; + gameMode->init(); + + return gameMode; +} + +GameMode* set_game_mode_slot(s32 i, GameMode* mode) { + GameMode* gameMode = &gMainGameState[i]; + + ASSERT(i < ARRAY_COUNT(gMainGameState)); + + gameMode->flags = 2 | 1; + gameMode->init = mode->init; + gameMode->step = mode->step; + gameMode->render = mode->render; + gameMode->unk_0C = NULL; + if (gameMode->init == NULL) gameMode->init = state_delegate_NOP; + if (gameMode->step == NULL) gameMode->step = state_delegate_NOP; + if (gameMode->unk_0C == NULL) gameMode->unk_0C = state_delegate_NOP; + if (gameMode->render == NULL) gameMode->render = state_delegate_NOP; + + gameMode->renderAux = state_delegate_NOP; + gameMode->init(); + + return gameMode; +} + +void game_mode_set_fpDrawAuxUI(s32 i, void (*fn)(void)) { + GameMode* gameMode = &gMainGameState[i]; + + ASSERT(i < ARRAY_COUNT(gMainGameState)); + + gameMode->renderAux = fn; + gameMode->flags |= 0x20; + + if (fn == NULL) { + gameMode->renderAux = state_delegate_NOP; + } +} + +void func_80112DD4(s32 i) { + gMainGameState[i].flags |= 4; +} + +void func_80112DFC(s32 i) { + gMainGameState[i].flags |= 8; +} + +void func_80112E24(s32 i) { + gMainGameState[i].flags &= ~0x1C; +} + +void func_80112E4C(s32 i) { + gMainGameState[i].flags &= ~0x0C; + gMainGameState[i].flags |= 0x10; +} + +void step_current_game_mode(void) { + GameMode* gameMode = gMainGameState; + s32 i; + + for (i = 0; i < ARRAY_COUNT(gMainGameState); i++, gameMode++) { + if (gameMode->flags != 0) { + if (!(gameMode->flags & 4)) { + if (!(gameMode->flags & 8)) { + gameMode->flags &= ~2; + gameMode->step(); + } + } + } + } +} + +void state_do_unk(void) { + GameMode* gameMode = gMainGameState; + s32 i; + + for (i = 0; i < ARRAY_COUNT(gMainGameState); i++, gameMode++) { + if (gameMode->flags != 0) { + if (!(gameMode->flags & 4)) { + if (!(gameMode->flags & 0x10)) { + gameMode->unk_0C(); + } + } + } + } +} + +void state_render_backUI(void) { + GameMode* gameMode = gMainGameState; + s32 i; + + for (i = 0; i < ARRAY_COUNT(gMainGameState); i++, gameMode++) { + if (gameMode->flags != 0) { + if (!(gameMode->flags & 4)) { + if (!(gameMode->flags & 0x10)) { + gameMode->render(); + } + } + } + } +} + +void state_render_frontUI(void) { + GameMode* gameMode = gMainGameState; + s32 i; + + for (i = 0; i < ARRAY_COUNT(gMainGameState); i++, gameMode++) { + if (gameMode->flags != 0) { + if (!(gameMode->flags & 4)) { + if (!(gameMode->flags & 2)) { + if (gameMode->flags & 0x20) { + gameMode->renderAux(); + } + } + } + } + } + + // re-initialization needed - evidence of inlining? or just copy/pasting? + gameMode = &gMainGameState[0]; + for (i = 0; i < ARRAY_COUNT(gMainGameState); i++, gameMode++) { + if (gameMode->flags != 0) { + if (!(gameMode->flags & 4)) { + if (!(gameMode->flags & 2)) { + if (gameMode->flags & 0x10) { + gameMode->render(); + } + } + } + } + } +} diff --git a/src/a5dd0_len_114e0.c b/src/model.c similarity index 71% rename from src/a5dd0_len_114e0.c rename to src/model.c index 689b388886..785343fec2 100644 --- a/src/a5dd0_len_114e0.c +++ b/src/model.c @@ -1,40 +1,15 @@ #include "common.h" -#include "model.h" #include "ld_addrs.h" -#include "stdlib/stdarg.h" -#include "entity.h" -#include "hud_element.h" +#include "model.h" #include "effects.h" -#include "nu/nusys.h" +#include "hud_element.h" #include "model_clear_render_tasks.h" -#include "gcc/string.h" - -#if VERSION_IQUE -// TODO: remove if sections are split in iQue release -extern Addr entity_jan_iwa_ROM_START; -extern Addr entity_jan_iwa_ROM_END; -extern Addr entity_default_ROM_START; -extern Addr entity_default_ROM_END; -extern Addr entity_sbk_omo_ROM_START; -extern Addr entity_sbk_omo_ROM_END; -#endif +#include "nu/nusys.h" +#define MAP_TEXTURE_MEMORY_SIZE 0x20000 +#define BTL_TEXTURE_MEMORY_SIZE 0x8000 extern Addr MapTextureMemory; -#ifdef SHIFT -extern Addr WorldEntityHeapBottom; -extern Addr WorldEntityHeapBase; -#define WORLD_ENTITY_HEAP_BOTTOM (s32) WorldEntityHeapBottom -#define WORLD_ENTITY_HEAP_BASE (s32) WorldEntityHeapBase -// TODO this only refers to one of 3 overlays which happen to share the same address space -// but don't necessarily have to -#define AREA_SPECIFIC_ENTITY_VRAM (s32) entity_default_VRAM -#else -#define WORLD_ENTITY_HEAP_BOTTOM 0x80250000 -#define WORLD_ENTITY_HEAP_BASE 0x80267FF0 -#define AREA_SPECIFIC_ENTITY_VRAM 0x802BAE00 -#endif - typedef struct Fog { /* 0x00 */ s32 enabled; /* 0x04 */ Color4i color; @@ -42,8 +17,6 @@ typedef struct Fog { /* 0x18 */ s32 endDistance; } Fog; // size = 0x1C -extern s32 D_801516FC; - extern Gfx D_8014B7F8[]; extern Gfx D_8014B820[]; extern Gfx D_8014B848[]; @@ -107,10 +80,6 @@ extern Gfx D_8014C110[]; extern Gfx D_8014C138[]; extern Gfx D_8014C160[]; -s32 D_8014AFB0 = 0xFF; - -s32 D_8014AFB4[] = {0, 0, 0}; - Gfx* D_8014AFC0[] = { D_8014B7F8, D_8014B910, D_8014B820, D_8014B938, D_8014B848, D_8014B960, D_8014B870, D_8014B988, D_8014B898, D_8014BA20, D_8014B9B0, D_8014BAC0, D_8014B8C0, D_8014B9D8, D_8014B8E8, D_8014BA00, D_8014BB60, D_8014BC78, D_8014BB88, D_8014BCA0, D_8014BBB0, D_8014BCC8, D_8014BBD8, D_8014BCF8, D_8014BC00, D_8014BD88, D_8014BD18, D_8014BC28, D_8014BD40, D_8014BC50, D_8014BD68, D_8014BE78, D_8014BF90, D_8014BEA0, D_8014BFB8, D_8014BEC8, D_8014BFE0, D_8014BEF0, D_8014C008, D_8014BF18, D_8014C098, D_8014C028, D_8014BF40, D_8014C050, D_8014BF68, D_8014C078, D_8014BA48, D_8014BA70, D_8014BA98, D_8014BDB0, D_8014BDD8, D_8014BE00, D_8014C0C0, D_8014C0E8, D_8014C110, D_8014BB10, D_8014BB38, D_8014BE28, D_8014BE50, D_8014C138, D_8014C160, NULL }; Gfx D_8014B0B8[21][5] = { @@ -411,7 +380,7 @@ Gfx D_8014B400[21][5] = { }, }; -void* mdl_textureBaseAddress = (void*) &MapTextureMemory; +void* TextureHeapBase = (void*) &MapTextureMemory; u8 mdl_bgMultiplyColorA = 0; u8 mdl_bgMultiplyColorR = 0; @@ -1052,7 +1021,7 @@ s32 mdl_renderTaskBasePriorities[RENDER_MODE_COUNT] = { [RENDER_MODE_CLOUD_NO_ZB] = 700000, }; -s8 D_8014C248[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +b8 D_8014C248 = FALSE; // BSS extern ModelCustomGfxBuilderList* gCurrentCustomModelGfxBuildersPtr; @@ -1065,25 +1034,9 @@ extern HudCacheEntry* gHudElementCacheTableRaster; extern HudCacheEntry* gHudElementCacheTablePalette; extern ModelNode** gCurrentModelTreeRoot; extern ModelTransformGroupList* gCurrentTransformGroups; -extern s8 gMsgGlobalWaveCounter[0x4]; extern ModelCustomGfxList* gCurrentCustomModelGfxPtr; -extern s32 gLastCreatedEntityIndex; -extern GameMode gMainGameState[2]; // TODO rename -extern s32 gEntityHeapBottom; -extern s32 entity_numShadows; -extern s32 entity_area_specific_data_is_loaded; -extern s32 entity_updateCounter; - -extern s32 wEntityDataLoadedSize; -extern s32 bEntityDataLoadedSize; - -extern EntityBlueprint* wEntityBlueprint[30]; -extern EntityBlueprint* bEntityBlueprint[4]; - -extern s32* D_801516F4; - -extern TextureHeader gCurrentTileDescriptor; +extern TextureHeader gCurrentTextureHeader; extern ModelList wModelList; extern ModelList bModelList; @@ -1115,7 +1068,7 @@ extern s32 texPannerMainU[MAX_TEX_PANNERS]; extern s32 texPannerMainV[MAX_TEX_PANNERS]; extern s32 texPannerAuxU[MAX_TEX_PANNERS]; extern s32 texPannerAuxV[MAX_TEX_PANNERS]; -extern void* mdl_nextTextureAddress; +extern void* TextureHeapPos; extern u16 mdl_currentTransformGroupChildIndex; extern u16 D_80153226; extern ModelNode* D_80153370; @@ -1132,1899 +1085,17 @@ extern Addr BattleEntityHeapBottom; // todo ??? extern u16 depthCopyBuffer[16]; -void update_shadows(void); -s32 step_entity_commandlist(Entity* entity); -void entity_swizzle_anim_pointers(EntityBlueprint* entityData, void* baseAnim, void* baseGfx); -void render_shadows(void); -void update_entity_transform_matrix(Entity* entity); -void update_shadow_transform_matrix(Shadow* shadow); -void update_entity_inverse_rotation_matrix(Entity* entity); -void delete_entity(s32 entityIndex); -void delete_entity_and_unload_data(s32 entityIndex); -void _delete_shadow(s32 shadowIndex); -void reload_world_entity_data(void); -s32 entity_get_collision_flags(Entity* entity); -void entity_free_static_data(EntityBlueprint* data); -s32 create_entity_shadow(Entity* entity, f32 x, f32 y, f32 z); -void update_entity_shadow_position(Entity* entity); void func_80117D00(Model* model); void appendGfx_model_group(void* model); void render_transform_group_node(ModelNode* node); void render_transform_group(void* group); -void func_801180E8(TextureHeader*, Gfx**, IMG_PTR raster, PAL_PTR palette, IMG_PTR auxRaster, PAL_PTR auxPalette, u8, u8, u16, u16); +void make_texture_gfx(TextureHeader*, Gfx**, IMG_PTR raster, PAL_PTR palette, IMG_PTR auxRaster, PAL_PTR auxPalette, u8, u8, u16, u16); void load_model_transforms(ModelNode* model, ModelNode* parent, Matrix4f mdlTxMtx, s32 treeDepth); s32 is_identity_fixed_mtx(Mtx* mtx); void build_custom_gfx(void); MATCHING_BSS(0x3A0); -void update_entities(void) { - s32 i; - - D_801512BC = 0; - entity_numEntities = 0; - entity_updateCounter++; - - for (i = 0; i < MAX_ENTITIES; i++) { - Entity* entity = get_entity_by_index(i); - - if (entity != NULL) { - entity_numEntities++; - - if (!(entity->flags & ENTITY_FLAG_SKIP_UPDATE)) { - if (entity->flags & ENTITY_FLAG_BOUND_SCRIPT_DIRTY) { - entity->flags &= ~ENTITY_FLAG_BOUND_SCRIPT_DIRTY; - if (!(entity->flags & ENTITY_FLAG_8000)) { - entity->flags |= ENTITY_FLAG_2000000; - } - entity->boundScript = start_script(entity->boundScriptBytecode, EVT_PRIORITY_A, EVT_FLAG_RUN_IMMEDIATELY); - } - - if (entity->flags & ENTITY_FLAG_2000000) { - if (does_script_exist(entity->boundScript->id)) { - if (entity->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { - update_model_animator(entity->virtualModelIndex); - } else { - exec_entity_model_commandlist(entity->virtualModelIndex); - } - - if (entity->flags & ENTITY_FLAG_ALWAYS_FACE_CAMERA) { - entity->rotation.y = -gCameras[gCurrentCameraID].currentYaw; - } - - if (!(entity->flags & ENTITY_FLAG_SKIP_UPDATE_TRANSFORM_MATRIX)) { - update_entity_transform_matrix(entity); - } - continue; - } else { - entity->flags &= ~ENTITY_FLAG_2000000; - } - } - - if (entity->collisionTimer == 0) { - entity->collisionFlags = entity_get_collision_flags(entity); - - if (entity->collisionFlags) { - EntityCallback handleCollision = entity->blueprint->fpHandleCollision; - - if (handleCollision != NULL && handleCollision(entity) != 0) { - entity->collisionTimer = 10; - entity->flags |= ENTITY_FLAG_DETECTED_COLLISION; - } - } - } else { - entity->collisionTimer--; - if (entity->flags & ENTITY_FLAG_CONTINUOUS_COLLISION) { - if (entity->collisionTimer == 0) { - entity->flags &= ~(ENTITY_FLAG_DISABLE_COLLISION | ENTITY_FLAG_CONTINUOUS_COLLISION); - } else { - entity->flags |= ENTITY_FLAG_DISABLE_COLLISION; - } - } else if (entity->collisionTimer == 0) { - entity->flags &= ~ENTITY_FLAG_DETECTED_COLLISION; - entity->flags &= ~ENTITY_FLAG_PARTNER_COLLISION; - entity->collisionFlags = 0; - } - } - - if (entity->flags & ENTITY_FLAG_ALWAYS_FACE_CAMERA) { - entity->rotation.y = -gCameras[gCurrentCameraID].currentYaw; - } - - if (!gGameStatusPtr->disableScripts) { - if (entity->updateScriptCallback != NULL) { - entity->updateScriptCallback(entity); - } - - if (entity->scriptReadPos != NULL) { - if (entity->scriptDelay != 0) { - entity->scriptDelay--; - if (entity->scriptDelay == 0) { - while (step_entity_commandlist(entity)); - } - } - } - } - - if (!(entity->flags & ENTITY_FLAG_SKIP_UPDATE_TRANSFORM_MATRIX)) { - update_entity_transform_matrix(entity); - } - - if (!(entity->flags & ENTITY_FLAG_DISABLE_COLLISION)) { - update_entity_inverse_rotation_matrix(entity); - } - - if (entity->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { - update_model_animator(entity->virtualModelIndex); - } else { - exec_entity_model_commandlist(entity->virtualModelIndex); - } - - if (entity->shadowIndex >= 0) { - update_entity_shadow_position(entity); - } - - if (entity->flags & ENTITY_FLAG_PENDING_INSTANCE_DELETE) { - delete_entity(entity->listIndex); - } - - if (entity->flags & ENTITY_FLAG_PENDING_FULL_DELETE) { - delete_entity_and_unload_data(entity->listIndex); - } - } - } - } - - update_shadows(); - gCurrentHiddenPanels.tryFlipTrigger = FALSE; -} - -void update_shadows(void) { - s32 i; - - entity_numShadows = 0; - - for (i = 0; i < MAX_SHADOWS; i++) { - Shadow* shadow = get_shadow_by_index(i); - - if (shadow != NULL) { - entity_numShadows++; - - if (!(shadow->flags & ENTITY_FLAG_SKIP_UPDATE)) { - if (shadow->flags & ENTITY_FLAG_ALWAYS_FACE_CAMERA) { - shadow->rotation.y = -gCameras[gCurrentCameraID].currentYaw; - } - - update_shadow_transform_matrix(shadow); - - if (shadow->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { - update_model_animator(shadow->entityModelID); - } else { - exec_entity_model_commandlist(shadow->entityModelID); - } - - if (shadow->flags & ENTITY_FLAG_PENDING_INSTANCE_DELETE) { - _delete_shadow(shadow->listIndex); - } - } - } - } -} - -void set_entity_commandlist(Entity* entity, s32* entityScript) { - entity->scriptReadPos = entityScript; - entity->scriptDelay = 1; - entity->savedReadPos[0] = entity->scriptReadPos; -} - -s32 step_entity_commandlist(Entity* entity) { - s32* args = entity->scriptReadPos; - s32 ret; - s32 labelId; - void (*tempfunc)(Entity*); - - switch (*args++) { - case ENTITY_SCRIPT_OP_End: - entity->scriptDelay = -1; - entity->updateScriptCallback = NULL; - entity->scriptReadPos = NULL; - ret = FALSE; - break; - case ENTITY_SCRIPT_OP_Jump: - entity->scriptReadPos = (s32*)*args; - entity->scriptDelay = 1; - entity->savedReadPos[0] = entity->scriptReadPos; - ret = TRUE; - break; - case ENTITY_SCRIPT_OP_Call: - tempfunc = (void (*)(Entity*))(*args++); - entity->scriptReadPos = args; - (tempfunc)(entity); - ret = TRUE; - break; - case ENTITY_SCRIPT_OP_SetCallback: - entity->scriptDelay = *args++; - entity->updateScriptCallback = (s32 (*)(Entity*)) *args++; - entity->scriptReadPos = args++; - ret = FALSE; - break; - case ENTITY_SCRIPT_OP_Goto: - entity->scriptReadPos = entity->savedReadPos[*args]; - ret = TRUE; - break; - case ENTITY_SCRIPT_OP_Label: - labelId = *args++; - entity->savedReadPos[labelId] = args; - entity->scriptReadPos = args; - ret = TRUE; - break; - case ENTITY_SCRIPT_OP_RestartBoundScript: - if (entity->boundScriptBytecode != NULL) { - entity->flags |= ENTITY_FLAG_BOUND_SCRIPT_DIRTY; - } - entity->scriptReadPos = args++; - ret = TRUE; - break; - case ENTITY_SCRIPT_OP_SetFlags: - entity->flags |= *args++; - entity->scriptReadPos = args++; - ret = TRUE; - break; - case ENTITY_SCRIPT_OP_ClearFlags: - entity->flags &= ~*args++; - entity->scriptReadPos = args++; - ret = TRUE; - break; - case ENTITY_SCRIPT_OP_PlaySound: - sfx_play_sound(*args++); - entity->scriptReadPos = args++; - ret = TRUE; - break; - default: - args++; - entity->scriptReadPos = args++; - ret = TRUE; - break; - } - return ret; -} - -void exec_entity_commandlist(Entity* entity) { - while (step_entity_commandlist(entity)); -} - -void func_8010FD98(void* arg0, s32 alpha) { - if (alpha >= 255) { - gDPSetRenderMode(gMainGfxPos++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2); - gDPSetCombineMode(gMainGfxPos++, G_CC_MODULATEIA, G_CC_MODULATEIA); - } else { - gDPSetCombineMode(gMainGfxPos++, PM_CC_01, PM_CC_02); - gDPSetPrimColor(gMainGfxPos++, 0, 0, 0, 0, 0, alpha); - } -} - -void func_8010FE44(void* arg0) { - func_8010FD98(arg0, D_8014AFB0); -} - -void entity_model_set_shadow_color(void* data) { - s32 alpha = (s32)data; - - gDPSetCombineLERP(gMainGfxPos++, 0, 0, 0, 0, PRIMITIVE, 0, TEXEL0, 0, 0, 0, 0, 0, TEXEL0, 0, PRIMITIVE, 0); - gDPSetPrimColor(gMainGfxPos++, 0, 0, 0, 0, 0, alpha); -} - -void render_entities(void) { - s32 i; - - for (i = 0; i < MAX_ENTITIES; i++) { - Entity* entity = get_entity_by_index(i); - - if (entity != NULL) { - if (!gGameStatusPtr->isBattle) { - if (gEntityHideMode != ENTITY_HIDE_MODE_0 && - !(entity->flags & ENTITY_FLAG_IGNORE_DISTANCE_CULLING) && - dist2D(gPlayerStatusPtr->position.x, - gPlayerStatusPtr->position.z, - entity->position.x, - entity->position.z) > 200.0f - ) { - continue; - } - - if (gEntityHideMode == ENTITY_HIDE_MODE_1) { - if (!(entity->flags & ENTITY_FLAG_DRAW_IF_CLOSE_HIDE_MODE1)) { - continue; - } - } else if (gEntityHideMode == ENTITY_HIDE_MODE_2) { - if (!(entity->flags & ENTITY_FLAG_DRAW_IF_CLOSE_HIDE_MODE2)) { - continue; - } - } - } - - if (!(entity->flags & ENTITY_FLAG_HIDDEN)) { - if (entity->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { - if (D_8014AFB0 == 0xFF) { - if (entity->renderSetupFunc != NULL) { - set_animator_render_callback( - entity->virtualModelIndex, - (void*)(u32) entity->listIndex, - (void (*)(void*)) entity->renderSetupFunc - ); - } - } else { - set_animator_render_callback( - entity->virtualModelIndex, - (void*)(u32) entity->listIndex, - func_8010FE44 - ); - } - - if (entity->gfxBaseAddr == NULL) { - render_animated_model(entity->virtualModelIndex, &entity->transformMatrix); - } else { - render_animated_model_with_vertices(entity->virtualModelIndex, - &entity->transformMatrix, - entity->vertexSegment, - entity->gfxBaseAddr); - } - } else { - if (D_8014AFB0 == 0xFF) { - if (entity->renderSetupFunc != NULL) { - bind_entity_model_setupGfx( - entity->virtualModelIndex, - (void*)(u32) entity->listIndex, - (void (*)(void*)) entity->renderSetupFunc - ); - } else { - get_entity_model(entity->virtualModelIndex)->fpSetupGfxCallback = NULL; - } - } else { - bind_entity_model_setupGfx(entity->virtualModelIndex, (void*)(u32)entity->listIndex, func_8010FE44); - } - - if (entity->gfxBaseAddr == NULL) { - draw_entity_model_A(entity->virtualModelIndex, &entity->transformMatrix); - } else { - draw_entity_model_B(entity->virtualModelIndex, - &entity->transformMatrix, - entity->vertexSegment, - entity->gfxBaseAddr); - } - } - } - } - } - - render_shadows(); -} - -void render_shadows(void) { - s32 i; - - for (i = 0; i < MAX_SHADOWS; i++) { - Shadow* shadow = get_shadow_by_index(i); - - if (shadow != NULL) { - if (shadow->flags & ENTITY_FLAG_HIDDEN) { - if (shadow->flags & ENTITY_FLAG_FADING_AWAY) { - shadow->alpha -= 20; - if (shadow->alpha <= 20) { - shadow->flags |= ENTITY_FLAG_PENDING_INSTANCE_DELETE; - } - } - } else if (shadow->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { - if (shadow->vertexArray == NULL) { - render_animated_model(shadow->entityModelID, &shadow->transformMatrix); - } else { - render_animated_model_with_vertices(shadow->entityModelID, - &shadow->transformMatrix, - shadow->vertexSegment, - shadow->vertexArray); - } - } else { - if (shadow->flags & ENTITY_FLAG_FADING_AWAY) { - shadow->alpha -= 20; - if (shadow->alpha <= 20) { - shadow->flags |= ENTITY_FLAG_PENDING_INSTANCE_DELETE; - } - } - - bind_entity_model_setupGfx(shadow->entityModelID, (void*)(u32)shadow->alpha, entity_model_set_shadow_color); - - if (shadow->vertexArray == NULL) { - draw_entity_model_A(shadow->entityModelID, &shadow->transformMatrix); - } else { - draw_entity_model_B(shadow->entityModelID, - &shadow->transformMatrix, - shadow->vertexSegment, - shadow->vertexArray); - } - } - } - } -} - -void update_entity_transform_matrix(Entity* entity) { - Matrix4f sp18; - Matrix4f sp58; - Matrix4f sp98; - Matrix4f spD8; - Matrix4f sp118; - Matrix4f sp158; - Matrix4f sp198; - - if (entity->updateMatrixOverride != NULL) { - entity->updateMatrixOverride(entity); - return; - } - - guTranslateF(sp58, entity->position.x, entity->position.y, entity->position.z); - guRotateF(spD8, entity->rotation.x, 1.0f, 0.0f, 0.0f); - guRotateF(sp118, entity->rotation.y, 0.0f, 1.0f, 0.0f); - guRotateF(sp158, entity->rotation.z, 0.0f, 0.0f, 1.0f); - guMtxCatF(sp158, spD8, sp18); - guMtxCatF(sp18, sp118, sp98); - guScaleF(sp198, entity->scale.x, entity->scale.y, entity->scale.z); - guMtxCatF(sp198, sp98, sp18); - guMtxCatF(sp18, sp58, sp98); - guMtxF2L(sp98, &entity->transformMatrix); -} - -void update_shadow_transform_matrix(Shadow* shadow) { - Matrix4f sp18; - Matrix4f sp58; - Matrix4f sp98; - Matrix4f spD8; - Matrix4f sp118; - Matrix4f sp158; - Matrix4f sp198; - - guTranslateF(sp58, shadow->position.x, shadow->position.y, shadow->position.z); - guRotateF(sp118, shadow->rotation.x, 1.0f, 0.0f, 0.0f); - guRotateF(spD8, shadow->rotation.y, 0.0f, 1.0f, 0.0f); - guRotateF(sp158, shadow->rotation.z, 0.0f, 0.0f, 1.0f); - guMtxCatF(sp158, sp118, sp98); - guMtxCatF(spD8, sp98, sp98); - guScaleF(sp198, shadow->scale.x, shadow->scale.y, shadow->scale.z); - guMtxCatF(sp198, sp98, sp18); - guMtxCatF(sp18, sp58, sp98); - guMtxF2L(sp98, &shadow->transformMatrix); -} - -void update_entity_inverse_rotation_matrix(Entity* entity) { - Matrix4f sp18; - Matrix4f sp58; - - guRotateF(sp18, -entity->rotation.y, 0.0f, 1.0f, 0.0f); - guRotateF(sp58, -entity->rotation.z, 0.0f, 0.0f, 1.0f); - guMtxCatF(sp18, sp58, sp18); - guRotateF(sp58, -entity->rotation.x, 1.0f, 0.0f, 0.0f); - guMtxCatF(sp18, sp58, entity->inverseTransformMatrix); - - entity->effectiveSize = sqrtf(((SQ(entity->aabb.x) + SQ(entity->aabb.z)) * 0.25f) + SQ(entity->aabb.y)); -} - -Entity* get_entity_by_index(s32 index) { - return (*gCurrentEntityListPtr)[index & 0xFFF]; -} - -Shadow* get_shadow_by_index(s32 index) { - return (*gCurrentShadowListPtr)[index & 0xFFF]; -} - -EntityList* get_entity_list(void) { - EntityList* ret; - - if (!gGameStatusPtr->isBattle) { - ret = &gWorldEntityList; - } else { - ret = &gBattleEntityList; - } - return ret; -} - -ShadowList* get_shadow_list(void) { - ShadowList* ret; - - if (!gGameStatusPtr->isBattle) { - ret = &gWorldShadowList; - } else { - ret = &gBattleShadowList; - } - return ret; -} - -s32 entity_start_script(Entity* entity) { - if (entity->boundScriptBytecode != NULL) { - entity->flags |= ENTITY_FLAG_BOUND_SCRIPT_DIRTY; - return 1; - } - return 0; -} - -u32 get_entity_type(s32 index) { - Entity* entity = get_entity_by_index(index); - - if (entity == NULL) { - return -1; - } else { - return entity->blueprint->entityType; - } -} - -void delete_entity(s32 entityIndex) { - Entity* entity = get_entity_by_index(entityIndex); - - if (entity->dataBuf.any != NULL) { - heap_free(entity->dataBuf.any); - } - - if (!(entity->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL)) { - free_entity_model_by_index(entity->virtualModelIndex); - } else { - delete_model_animator(get_animator_by_index(entity->virtualModelIndex)); - } - - if (entity->shadowIndex >= 0) { - Shadow* shadow = get_shadow_by_index(entity->shadowIndex); - - shadow->flags |= ENTITY_FLAG_FADING_AWAY; - } - - heap_free((*gCurrentEntityListPtr)[entityIndex]); - (*gCurrentEntityListPtr)[entityIndex] = NULL; -} - -void delete_entity_and_unload_data(s32 entityIndex) { - Entity* entity = get_entity_by_index(entityIndex); - - if (entity->dataBuf.any != NULL) { - heap_free(entity->dataBuf.any); - } - - if (!(entity->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL)) { - free_entity_model_by_index(entity->virtualModelIndex); - } else { - delete_model_animator(get_animator_by_index(entity->virtualModelIndex)); - } - - entity_free_static_data(entity->blueprint); - - if (entity->shadowIndex >= 0) { - Shadow* shadow = get_shadow_by_index(entity->shadowIndex); - - shadow->flags |= ENTITY_FLAG_FADING_AWAY; - } - - heap_free((*gCurrentEntityListPtr)[entityIndex]); - (*gCurrentEntityListPtr)[entityIndex] = NULL; -} - -void _delete_shadow(s32 shadowIndex) { - Shadow* shadow = get_shadow_by_index(shadowIndex); - - free_entity_model_by_index(shadow->entityModelID); - heap_free((*gCurrentShadowListPtr)[shadowIndex]); - (*gCurrentShadowListPtr)[shadowIndex] = NULL; -} - -s32 entity_get_collision_flags(Entity* entity) { - u32 listIndex = entity->listIndex; - s32 entityFlags = 0; - u32 flag; - - if (entity->flags & ENTITY_FLAG_PARTNER_COLLISION) { - entityFlags = ENTITY_COLLISION_PARTNER; - entity->flags &= ~ENTITY_FLAG_PARTNER_COLLISION; - } - - flag = gCollisionStatus.currentFloor; - if (flag != -1 && (flag & COLLISION_WITH_ENTITY_BIT) && listIndex == (u8)flag) { - entityFlags |= ENTITY_COLLISION_PLAYER_TOUCH_FLOOR; - } - - flag = gCollisionStatus.lastTouchedFloor; - if (flag != -1 && (flag & COLLISION_WITH_ENTITY_BIT) && listIndex == (u8)flag) { - entityFlags |= ENTITY_COLLISION_PLAYER_LAST_FLOOR; - } - - flag = gCollisionStatus.currentCeiling; - if (flag != -1 && (flag & COLLISION_WITH_ENTITY_BIT) && listIndex == (u8)flag) { - entityFlags |= ENTITY_COLLISION_PLAYER_TOUCH_CEILING; - } - - flag = gCollisionStatus.pushingAgainstWall; - if (flag != -1 && (flag & COLLISION_WITH_ENTITY_BIT) && listIndex == (u8)flag) { - entityFlags |= ENTITY_COLLISION_PLAYER_PUSHING_AGAINST; - } - - flag = gCollisionStatus.lastWallHammered; - if (flag != -1 && (flag & COLLISION_WITH_ENTITY_BIT) && listIndex == (u8)flag) { - entityFlags |= ENTITY_COLLISION_PLAYER_HAMMER; - } - - flag = gCollisionStatus.currentWall; - if (flag != -1 && (flag & COLLISION_WITH_ENTITY_BIT) && listIndex == (u8)flag && gPlayerStatusPtr->pressedButtons & BUTTON_A) { - entityFlags |= ENTITY_COLLISION_PLAYER_TOUCH_WALL; - } - - return entityFlags; -} - -s32 entity_try_partner_interaction_trigger(s32 entityIdx) { - s32 interacted = FALSE; - u32 entityType = get_entity_type(entityIdx); - s32 partnerID = get_current_partner_id(); - Entity* entity; - - switch (partnerID) { - case PARTNER_BOMBETTE: - switch (entityType) { - default: - return FALSE; - case ENTITY_TYPE_BLUE_SWITCH: - case ENTITY_TYPE_RED_SWITCH: - case ENTITY_TYPE_MULTI_TRIGGER_BLOCK: - case ENTITY_TYPE_BRICK_BLOCK: - case ENTITY_TYPE_MULTI_COIN_BRICK: - case ENTITY_TYPE_YELLOW_BLOCK: - case ENTITY_TYPE_SINGLE_TRIGGER_BLOCK: - case ENTITY_TYPE_HIDDEN_YELLOW_BLOCK: - case ENTITY_TYPE_HIDDEN_RED_BLOCK: - case ENTITY_TYPE_RED_BLOCK: - case ENTITY_TYPE_HAMMER1_BLOCK: - case ENTITY_TYPE_HAMMER1_BLOCK_TINY: - case ENTITY_TYPE_SUPER_BLOCK: - case ENTITY_TYPE_BOMBABLE_ROCK: - entity = get_entity_by_index(entityIdx); - entity->flags |= ENTITY_FLAG_PARTNER_COLLISION; - interacted = TRUE; - } - break; - case PARTNER_KOOPER: - switch (entityType) { - default: - return FALSE; - case ENTITY_TYPE_BLUE_SWITCH: - case ENTITY_TYPE_RED_SWITCH: - case ENTITY_TYPE_MULTI_TRIGGER_BLOCK: - case ENTITY_TYPE_BRICK_BLOCK: - case ENTITY_TYPE_MULTI_COIN_BRICK: - case ENTITY_TYPE_YELLOW_BLOCK: - case ENTITY_TYPE_SINGLE_TRIGGER_BLOCK: - case ENTITY_TYPE_HIDDEN_YELLOW_BLOCK: - case ENTITY_TYPE_HIDDEN_RED_BLOCK: - case ENTITY_TYPE_RED_BLOCK: - case ENTITY_TYPE_HEALING_BLOCK: - case ENTITY_TYPE_1C: - case ENTITY_TYPE_SAVE_POINT: - case ENTITY_TYPE_SUPER_BLOCK: - entity = get_entity_by_index(entityIdx); - entity->flags |= ENTITY_FLAG_PARTNER_COLLISION; - interacted = TRUE; - } - break; - } - return interacted; -} - -s32 test_player_entity_aabb(Entity* entity) { - f32 yTemp = entity->position.y - (gPlayerStatus.position.y + gPlayerStatus.colliderHeight); - f32 xCollRadius; - f32 zCollRadius; - f32 xDist; - f32 zDist; - - if (yTemp > 0.0f || gPlayerStatus.colliderHeight + entity->aabb.y < fabsf(yTemp)) { - return 0; - } - - xCollRadius = (gPlayerStatus.colliderDiameter + entity->aabb.x) * 0.5; - xDist = fabsf(gPlayerStatus.position.x - entity->position.x); - zCollRadius = ((gPlayerStatus.colliderDiameter + entity->aabb.z) * 0.5); - zDist = fabsf(gPlayerStatus.position.z - entity->position.z); - - if (xCollRadius < xDist || zCollRadius < zDist) { - return 0; - } - - return 1; -} - -s32 is_player_action_state(s8 actionState) { - return actionState == gPlayerStatus.actionState; -} - -void entity_set_render_script(Entity* entity, EntityModelScript* cmdList) { - if (!(entity->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL)) { - set_entity_model_render_command_list(entity->virtualModelIndex, cmdList); - } -} - -void entity_reset_collision(Entity* entity) { - entity->collisionTimer = 0; - entity->flags &= ~ENTITY_FLAG_DETECTED_COLLISION; -} - -void load_area_specific_entity_data(void) { - if (!entity_area_specific_data_is_loaded) { - if (gGameStatusPtr->areaID == AREA_JAN || gGameStatusPtr->areaID == AREA_IWA) { - dma_copy(entity_jan_iwa_ROM_START, entity_jan_iwa_ROM_END, (void*)AREA_SPECIFIC_ENTITY_VRAM); - } else if (gGameStatusPtr->areaID == AREA_SBK || gGameStatusPtr->areaID == AREA_OMO) { - dma_copy(entity_sbk_omo_ROM_START, entity_sbk_omo_ROM_END, (void*)AREA_SPECIFIC_ENTITY_VRAM); - } else { - dma_copy(entity_default_ROM_START, entity_default_ROM_END, (void*)AREA_SPECIFIC_ENTITY_VRAM); - } - - entity_area_specific_data_is_loaded = TRUE; - } -} - -void clear_entity_data(s32 arg0) { - s32 i; - - D_801516FC = 1; - entity_numEntities = 0; - entity_numShadows = 0; - entity_updateCounter = 0; - D_80151304 = 0; - - if (!gGameStatusPtr->isBattle) { - gEntityHideMode = ENTITY_HIDE_MODE_0; - } - - entity_area_specific_data_is_loaded = FALSE; - gCurrentHiddenPanels.panelsCount = 0; - gCurrentHiddenPanels.activateISpy = FALSE; - if (!arg0) { - D_80151344 = 0; - } - D_8014AFB0 = 0xFF; - - if (!gGameStatusPtr->isBattle) { - wEntityDataLoadedSize = 0; - for (i = 0; i < MAX_ENTITIES; i++) { - wEntityBlueprint[i] = NULL; - } - } else { - bEntityDataLoadedSize = 0; - for (i = 0; i < 4; i++) { - bEntityBlueprint[i] = NULL; - } - } - - if (!gGameStatusPtr->isBattle) { - gEntityHeapBottom = WORLD_ENTITY_HEAP_BOTTOM; - gEntityHeapBase = WORLD_ENTITY_HEAP_BASE; - } else { - gEntityHeapBottom = (s32) BattleEntityHeapBottom; - gEntityHeapBase = gEntityHeapBottom + 0x3000; - } - - gCurrentEntityListPtr = get_entity_list(); - gCurrentShadowListPtr = get_shadow_list(); - - for (i = 0; i < MAX_ENTITIES; i++) { - (*gCurrentEntityListPtr)[i] = NULL; - } - - for (i = 0; i < MAX_SHADOWS; i++) { - (*gCurrentShadowListPtr)[i] = NULL; - } -} - -void init_entity_data(void) { - if (!gGameStatusPtr->isBattle) { - gEntityHeapBottom = WORLD_ENTITY_HEAP_BOTTOM; - gEntityHeapBase = WORLD_ENTITY_HEAP_BASE; - reload_world_entity_data(); - } else { - s32 i; - - for (i = 0; i < 4; i++) { - bEntityBlueprint[i] = 0; - } - gEntityHeapBottom = (s32) BattleEntityHeapBottom; - gEntityHeapBase = gEntityHeapBottom + 0x3000; - } - gCurrentEntityListPtr = get_entity_list(); - gCurrentShadowListPtr = get_shadow_list(); - entity_numEntities = 0; - entity_numShadows = 0; -} - -void reload_world_entity_data(void) { - s32 i; - s32 totalSize = 0; - s32 temp1; - s32 dataLength; - void* gfxData; - void* animData; - - for (i = 0; i < MAX_ENTITIES; i++) { - EntityBlueprint* bp = wEntityBlueprint[i]; - if (bp == NULL) { - break; - } - - if (!(bp->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL)) { - void* gfxData; - - dataLength = ((bp->dma.end - bp->dma.start) >> 2); - gfxData = (void*)(gEntityHeapBase - totalSize * 4 - dataLength * 4); - totalSize += dma_copy(bp->dma.start, bp->dma.end, gfxData) >> 2; - } else { - DmaEntry* dmaList = bp->dmaList; - - if (bp->entityType == ENTITY_TYPE_RESET_MUNCHLESIA) { - gfxData = (void*)gEntityHeapBottom; - temp1 = dma_copy(dmaList[0].start, dmaList[0].end, gfxData) >> 2; - dma_copy(dmaList[1].start, dmaList[1].end, (void*)(gEntityHeapBottom + temp1 * 4)) >> 2; - animData = (void*)(gEntityHeapBottom + temp1 * 4); - entity_swizzle_anim_pointers(bp, animData, gfxData); - } else { - s32 temp5; - s32 q; - - dataLength = ((dmaList[0].end - dmaList[0].start) >> 2); - q = gEntityHeapBase - totalSize * 4; - gfxData = (void*)(q - dataLength * 4); - totalSize += dma_copy(dmaList[0].start, dmaList[0].end, gfxData) >> 2; - - dataLength = ((dmaList[1].end - dmaList[1].start) >> 2); - q = gEntityHeapBase - totalSize * 4; - animData = (void*)(q - dataLength * 4); - totalSize += dma_copy(dmaList[1].start, dmaList[1].end, animData) >> 2; - - entity_swizzle_anim_pointers(bp, animData, gfxData); - } - } - } -} - -void entity_swizzle_anim_pointers(EntityBlueprint* entityData, void* baseAnim, void* baseGfx) { - StaticAnimatorNode* node; - s32* ptr = (s32*)((s32)baseAnim + (s32)entityData->modelAnimationNodes); - - while (TRUE) { - if (*ptr == -1) { - *ptr = 0; - return; - } - node = (StaticAnimatorNode*)((s32)baseAnim + ((*ptr) & 0xFFFF)); - *ptr++ = (s32)node; - - if ((s32)node->displayList != -1) { - node->displayList = (Gfx*)((s32)baseGfx + ((s32)(node->displayList) & 0xFFFF)); - } else { - node->displayList = NULL; - } - - if ((s32)node->sibling != -1) { - node->sibling = (StaticAnimatorNode*)((s32)baseAnim + ((s32)(node->sibling) & 0xFFFF)); - } else { - node->sibling = NULL; - } - - if ((s32)node->child != -1) { - node->child = (StaticAnimatorNode*)((s32)baseAnim + ((s32)(node->child) & 0xFFFF)); - } else { - node->child = NULL; - } - - if ((s32)node->vtxList != -1) { - node->vtxList = (Vtx*)((s32)baseGfx + ((s32)(node->vtxList) & 0xFFFFF)); - } else { - node->vtxList = NULL; - } - } -} - -s32 is_entity_data_loaded(Entity* entity, EntityBlueprint* blueprint, s32* loadedStart, s32* loadedEnd) { - EntityBlueprint** blueprints; - s32 i; - s32 ret; - s32 size; - DmaEntry* entDmaList; - - *loadedStart = 0; - *loadedEnd = 0; - ret = FALSE; - - if (!gGameStatusPtr->isBattle) { - blueprints = wEntityBlueprint; - } else { - blueprints = bEntityBlueprint; - } - - for (i = 0; i < MAX_ENTITIES; i++, blueprints++) { - EntityBlueprint* bp = *blueprints; - if (bp == NULL) { - blueprints[0] = blueprint; - blueprints[1] = NULL; - ret = TRUE; - if (blueprint->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { - s32 size; - entDmaList = blueprint->dmaList; - size = (entDmaList[0].end - entDmaList[0].start) >> 2; - *loadedEnd = *loadedStart + size; - } - break; - } else { - DmaEntry* bpDmaList = bp->dmaList; - do {} while (0); // TODO find better match - entDmaList = blueprint->dmaList; - if (bpDmaList == entDmaList) { - if (blueprint->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { - s32 size = (bpDmaList[0].end - bpDmaList[0].start) >> 2; - *loadedEnd = *loadedStart + size; - } - break; - } else if (bp == blueprint) { - if (bp->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { - s32 size = (entDmaList[0].end - entDmaList[0].start) >> 2; - *loadedEnd = *loadedStart + size; - } - break; - } else { - if (bp->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { - s32 size = (bpDmaList[0].end - bpDmaList[0].start) >> 2; - *loadedEnd = *loadedStart = *loadedStart + size; - size = (bpDmaList[1].end - bpDmaList[1].start) >> 2; - *loadedStart = *loadedStart + size; - } else { - *loadedStart += (bp->dma.end - bp->dma.start) >> 2; - } - } - } - } - - return ret; -} - -void load_simple_entity_data(Entity* entity, EntityBlueprint* bp, s32 listIndex) { - s32 loadedStart; - s32 loadedEnd; - s32 entitySize; - u32 temp; - s32 totalSize; - - entity->vertexSegment = 0xA; - if (!gGameStatusPtr->isBattle) { - totalSize = wEntityDataLoadedSize; - } else { - totalSize = bEntityDataLoadedSize; - } - - if (is_entity_data_loaded(entity, bp, &loadedStart, &loadedEnd)) { - if (totalSize + ((bp->dma.end - bp->dma.start) >> 2) > 0x5FFCU) { - get_entity_type(entity->listIndex); - get_entity_type(entity->listIndex); - PANIC(); - } - entitySize = (bp->dma.end - bp->dma.start) >> 2; - entity->gfxBaseAddr = (void*)(gEntityHeapBase - totalSize * 4 - entitySize * 4); - totalSize += dma_copy(bp->dma.start, bp->dma.end, entity->gfxBaseAddr) >> 2; - get_entity_type(entity->listIndex); - } else { - entitySize = (bp->dma.end - bp->dma.start) >> 2; - entity->gfxBaseAddr = (void*)(gEntityHeapBase - loadedStart * 4 - entitySize * 4); - get_entity_type(entity->listIndex); - } - - if (!gGameStatusPtr->isBattle) { - wEntityDataLoadedSize = totalSize; - } else { - bEntityDataLoadedSize = totalSize; - } -} - -void load_split_entity_data(Entity* entity, EntityBlueprint* entityData, s32 listIndex) { - s32 swizzlePointers = FALSE; - s32 loadedStart, loadedEnd; - void* animBaseAddr; - s16* animationScript; - StaticAnimatorNode** animationNodes; - s32 specialSize; - s32 dma1size; - s32 dma2size_1; - s32 dma2size_2; - s32 totalLoaded; - - if (entityData->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { - DmaEntry* dmaList = entityData->dmaList; - entity->vertexSegment = 0xA; - - switch (entityData->entityType) { - case ENTITY_TYPE_RESET_MUNCHLESIA: - case ENTITY_TYPE_MUNCHLESIA_ENVELOP: - case ENTITY_TYPE_MUNCHLESIA_CHEWING: - case ENTITY_TYPE_MUNCHLESIA_RESET1: - specialSize = 0x1000; - break; - case ENTITY_TYPE_MUNCHLESIA_GRAB: - case ENTITY_TYPE_MUNCHLESIA_BEGIN_CHEW: - case ENTITY_TYPE_MUNCHLESIA_SPIT_OUT: - case ENTITY_TYPE_MUNCHLESIA_RESET2: - specialSize = 0x2BC0; - break; - default: - specialSize = 0; - break; - } - - if (specialSize != 0) { - if (entityData->entityType == ENTITY_TYPE_RESET_MUNCHLESIA) { - is_entity_data_loaded(entity, entityData, &loadedStart, &loadedEnd); - } - specialSize -= 0x1000; - - dma1size = dma_copy(dmaList[0].start, dmaList[0].end, (void*)(gEntityHeapBottom + specialSize * 4)) / 4; - entity->gfxBaseAddr = (void*)(gEntityHeapBottom + specialSize * 4); - dma_copy(dmaList[1].start, dmaList[1].end, (void*)(gEntityHeapBottom + specialSize * 4 + dma1size * 4)); - animBaseAddr = (void*)(gEntityHeapBottom + specialSize * 4 + dma1size * 4); - swizzlePointers = TRUE; - } else if (is_entity_data_loaded(entity, entityData, &loadedStart, &loadedEnd)) { - if (!gGameStatusPtr->isBattle) { - totalLoaded = wEntityDataLoadedSize; - } else { - totalLoaded = bEntityDataLoadedSize; - } - - if ((totalLoaded + ((dmaList[0].end - dmaList[0].start) >> 2)) > 0x5FFCU) { - get_entity_type(entity->listIndex); - PANIC(); - } - - if ((totalLoaded + ((dmaList[1].end - dmaList[1].start) >> 2)) > 0x5FFCU) { - get_entity_type(entity->listIndex); - PANIC(); - } - - dma2size_1 = dma_copy(dmaList[0].start, dmaList[0].end, dmaList[0].start + ((gEntityHeapBase - totalLoaded * 4 - (s32)dmaList[0].end) >> 2) * 4) >> 2; - entity->gfxBaseAddr = (void*)(gEntityHeapBase - totalLoaded * 4 - dma2size_1 * 4); - totalLoaded += dma2size_1; - - dma2size_2 = dma_copy(dmaList[1].start, dmaList[1].end, dmaList[1].start + ((gEntityHeapBase - totalLoaded * 4 - (s32)dmaList[1].end) >> 2) * 4) >> 2; - animBaseAddr = (void*)(gEntityHeapBase - totalLoaded * 4 - dma2size_2 * 4); - totalLoaded += dma2size_2; - get_entity_type(entity->listIndex); - - if (!gGameStatusPtr->isBattle) { - wEntityDataLoadedSize = totalLoaded; - } else { - bEntityDataLoadedSize = totalLoaded; - } - swizzlePointers = TRUE; - } else { - u32 temp = (dmaList[0].end - dmaList[0].start) >> 2; - entity->gfxBaseAddr = (void*)(gEntityHeapBase - loadedStart * 4 - temp * 4); - temp = (dmaList[1].end - dmaList[1].start) >> 2; - animBaseAddr = (void*)(gEntityHeapBase - loadedEnd * 4 - temp * 4); - get_entity_type(entity->listIndex); - } - } else { - entity->virtualModelIndex = create_model_animator(entityData->renderCommandList); - load_model_animator_tree(entity->virtualModelIndex, entityData->modelAnimationNodes); - update_model_animator(entity->virtualModelIndex); - return; - } - animationScript = entityData->renderCommandList; - animationNodes = (StaticAnimatorNode**)((s32)animBaseAddr + (s32)entityData->modelAnimationNodes); - if (swizzlePointers) { - entity_swizzle_anim_pointers(entityData, animBaseAddr, entity->gfxBaseAddr); - } - entity->virtualModelIndex = create_mesh_animator(animationScript, animBaseAddr); - load_mesh_animator_tree(entity->virtualModelIndex, animationNodes); - update_model_animator(entity->virtualModelIndex); - entity->flags |= ENTITY_FLAG_HAS_ANIMATED_MODEL; -} - -s32 func_80111790(EntityBlueprint* data) { - s32 i; - - for (i = 0; i < ARRAY_COUNT(*gCurrentEntityListPtr); i++) { - Entity* entity = (*gCurrentEntityListPtr)[i]; - - if (entity != NULL && entity->blueprint->dma.start != NULL) { - if (entity->blueprint->dma.start == entity->blueprint) { - return TRUE; - } - } - } - return FALSE; -} - -void entity_free_static_data(EntityBlueprint* data) { - s32 freeSlot; - s32 size; - EntityBlueprint* bp; - - for (freeSlot = 0; freeSlot < MAX_ENTITIES; freeSlot++) { - bp = wEntityBlueprint[freeSlot]; - if (bp == NULL) { - break; - } - } - - if (freeSlot < MAX_ENTITIES) { - bp = wEntityBlueprint[freeSlot - 1]; - if (bp == data) { - if (bp->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL) { - DmaEntry* dmaList = bp->dmaList; - size = ((dmaList[0].end - dmaList[0].start) >> 2); - size += ((dmaList[1].end - dmaList[1].start) >> 2); - if (!func_80111790(bp)) { - wEntityBlueprint[freeSlot - 1] = NULL; - wEntityDataLoadedSize -= size; - } - } else { - size = (bp->dma.end - bp->dma.start) >> 2; - if (!func_80111790(bp)) { - wEntityBlueprint[freeSlot - 1] = NULL; - wEntityDataLoadedSize -= size; - } - } - } - } -} - -s32 create_entity(EntityBlueprint* bp, ...) { - va_list ap; - EntityBlueprint** bpPtr; - f32 x, y, z; - f32 rotY; - s32 listIndex; - Entity* entity; - s32* args; - - va_start(ap, bp); - // needed to match - bpPtr = &bp; - *bpPtr = bp; - - load_area_specific_entity_data(); - - x = va_arg(ap, s32); - y = va_arg(ap, s32); - z = va_arg(ap, s32); - rotY = va_arg(ap, s32); - - args = &CreateEntityVarArgBuffer[2]; - - *args-- = 0; - *args-- = 0; - *args = 0; - - for (listIndex = 3; listIndex > 0; listIndex--) { - s32 arg = va_arg(ap, s32); - - if (arg == MAKE_ENTITY_END) { - break; - } - *args++ = arg; - } - - va_end(ap); - - for (listIndex = 0; listIndex < ARRAY_COUNT(*gCurrentEntityListPtr); listIndex++) { - if ((*gCurrentEntityListPtr)[listIndex] == NULL) { - break; - } - } - - if (listIndex >= MAX_ENTITIES) { - return -1; - } - - (*gCurrentEntityListPtr)[listIndex] = entity = heap_malloc(sizeof(*entity)); - mem_clear(entity, sizeof(*entity)); - entity->dataBuf.any = NULL; - if (bp->typeDataSize != 0) { - entity->dataBuf.any = heap_malloc(bp->typeDataSize); - mem_clear(entity->dataBuf.any, bp->typeDataSize); - } - entity->type = bp->entityType; - entity->listIndex = listIndex; - entity->boundScript = NULL; - entity->updateMatrixOverride = NULL; - entity->blueprint = bp; - entity->scriptReadPos = bp->updateEntityScript; - entity->scriptDelay = entity->scriptReadPos != NULL ? 1 : 0; - entity->savedReadPos[0] = bp->updateEntityScript; - entity->updateScriptCallback = NULL; - entity->flags = bp->flags | ENTITY_FLAG_CREATED; - entity->collisionFlags = 0; - entity->collisionTimer = 0; - entity->renderSetupFunc = NULL; - entity->position.x = x; - entity->position.y = y; - entity->position.z = z; - entity->rotation.x = 0.0f; - entity->rotation.y = rotY; - entity->rotation.z = 0.0f; - entity->scale.x = 1.0f; - entity->scale.y = 1.0f; - entity->scale.z = 1.0f; - entity->aabb.x = bp->aabbSize[0]; - entity->aabb.y = bp->aabbSize[1]; - entity->aabb.z = bp->aabbSize[2]; - entity->unk_05 = 1; - entity->unk_08 = -1; - entity->alpha = 255; - entity->virtualModelIndex = -1; - entity->shadowIndex = -1; - entity->gfxBaseAddr = NULL; - - if (!(bp->flags & ENTITY_FLAG_HAS_ANIMATED_MODEL)) { - if (bp->dma.start != 0) { - load_simple_entity_data(entity, bp, listIndex); - } - if (bp->renderCommandList != NULL) { - entity->virtualModelIndex = load_entity_model(bp->renderCommandList); - exec_entity_model_commandlist(entity->virtualModelIndex); - } - } else { - load_split_entity_data(entity, bp, listIndex); - } - - if (bp->entityType != ENTITY_TYPE_SHADOW && (entity->flags & (ENTITY_FLAG_FIXED_SHADOW_SIZE | ENTITY_FLAG_HAS_SHADOW))) { - create_entity_shadow(entity, x, y, z); - } - - switch (bp->entityType) { - case ENTITY_TYPE_BLUE_SWITCH: - case ENTITY_TYPE_RED_SWITCH: - case ENTITY_TYPE_SIMPLE_SPRING: - case ENTITY_TYPE_SCRIPT_SPRING: - case ENTITY_TYPE_STAR_BOX_LAUCHER: - entity->flags |= ENTITY_FLAG_4000; - break; - } - - if (bp->fpInit != NULL) { - bp->fpInit(entity); - } - - update_entity_transform_matrix(entity); - return entity->listIndex; -} - -s32 create_shadow_from_data(ShadowBlueprint* bp, f32 x, f32 y, f32 z) { - Shadow* shadow; - s32 i; - - for (i = 0; i < ARRAY_COUNT(*gCurrentShadowListPtr); i++) { - if ((*gCurrentShadowListPtr)[i] == NULL) { - break; - } - } - - ASSERT(i < ARRAY_COUNT(*gCurrentShadowListPtr)); - - shadow = heap_malloc(sizeof(*shadow)); - (*gCurrentShadowListPtr)[i] = shadow; - mem_clear(shadow, sizeof(*shadow)); - shadow->listIndex = i; - shadow->flags = bp->flags | ENTITY_FLAG_CREATED; - shadow->alpha = 128; - shadow->unk_06 = 0x80; - shadow->position.x = x; - shadow->position.y = y; - shadow->position.z = z; - shadow->scale.x = 1.0f; - shadow->scale.y = 1.0f; - shadow->scale.z = 1.0f; - - if (bp->animModelNode != NULL) { - shadow->flags |= ENTITY_FLAG_HAS_ANIMATED_MODEL; - shadow->entityModelID = create_model_animator(bp->renderCommandList); - load_model_animator_tree(shadow->entityModelID, bp->animModelNode); - } else { - shadow->entityModelID = load_entity_model(bp->renderCommandList); - } - - if (bp->onCreateCallback != NULL) { - bp->onCreateCallback(shadow); - } - update_shadow_transform_matrix(shadow); - return shadow->listIndex; -} - -s32 MakeEntity(Evt* script, s32 isInitialCall) { - Bytecode* args = script->ptrReadPos; - EntityBlueprint* entityData; - s32 x, y, z; - s32 flags; - s32 nextArg; - s32 entityIndex; - s32 endOfArgs; - s32* varArgBufPos; - - if (isInitialCall != TRUE) { - return ApiStatus_DONE2; - } - - entityData = (EntityBlueprint*)evt_get_variable(script, *args++); - varArgBufPos = &CreateEntityVarArgBuffer[2]; - endOfArgs = MAKE_ENTITY_END; - x = evt_get_variable(script, *args++); - y = evt_get_variable(script, *args++); - z = evt_get_variable(script, *args++); - flags = evt_get_variable(script, *args++); - - *varArgBufPos-- = 0; - *varArgBufPos-- = 0; - *varArgBufPos = 0; - - do { - nextArg = evt_get_variable(script, *args++); - - if (nextArg != endOfArgs) { - *varArgBufPos++ = nextArg; - } - } while (nextArg != endOfArgs); - - entityIndex = create_entity(entityData, x, y, z, flags, CreateEntityVarArgBuffer[0], CreateEntityVarArgBuffer[1], CreateEntityVarArgBuffer[2], endOfArgs); - gLastCreatedEntityIndex = entityIndex; - script->varTable[0] = entityIndex; - return ApiStatus_DONE2; -} - -ApiStatus SetEntityCullMode(Evt* script, s32 isInitialCall) { - Entity* entity = get_entity_by_index(gLastCreatedEntityIndex); - Bytecode* args = script->ptrReadPos; - s32 mode = evt_get_variable(script, *args++); - - if (mode == 0) { - entity->flags |= ENTITY_FLAG_DRAW_IF_CLOSE_HIDE_MODE1; - } else if (mode == 1) { - entity->flags |= ENTITY_FLAG_DRAW_IF_CLOSE_HIDE_MODE2; - } else if (mode == 2) { - entity->flags |= ENTITY_FLAG_DRAW_IF_CLOSE_HIDE_MODE2 | ENTITY_FLAG_DRAW_IF_CLOSE_HIDE_MODE1; - } else { - entity->flags |= ENTITY_FLAG_IGNORE_DISTANCE_CULLING | ENTITY_FLAG_DRAW_IF_CLOSE_HIDE_MODE2 | - ENTITY_FLAG_DRAW_IF_CLOSE_HIDE_MODE1; - } - return ApiStatus_DONE2; -} - -ApiStatus UseDynamicShadow(Evt* script, s32 isInitialCall) { - Entity* entity = get_entity_by_index(gLastCreatedEntityIndex); - Bytecode* args = script->ptrReadPos; - - if (evt_get_variable(script, *args++)) { - Shadow* shadow; - - entity->flags |= ENTITY_FLAG_HAS_DYNAMIC_SHADOW; - shadow = get_shadow_by_index(entity->shadowIndex); - shadow->flags |= ENTITY_FLAG_SHADOW_POS_DIRTY; - } else { - entity->flags &= ~ENTITY_FLAG_HAS_DYNAMIC_SHADOW; - } - - return ApiStatus_DONE2; -} - -ApiStatus AssignScript(Evt* script, s32 isInitialCall) { - Bytecode* args = script->ptrReadPos; - - if (isInitialCall == TRUE) { - EvtScript* toBind = (EvtScript*)evt_get_variable(script, *args++); - - get_entity_by_index(gLastCreatedEntityIndex)->boundScriptBytecode = toBind; - return ApiStatus_DONE2; - } - - return ApiStatus_DONE1; -} - -ApiStatus AssignSwitchFlag(Evt* script, s32 isInitialCall) { - Bytecode* args = script->ptrReadPos; - - if (isInitialCall == TRUE) { - s32 areaFlag = evt_get_variable(script, *args++); - Entity* entity = get_entity_by_index(gLastCreatedEntityIndex); - SwitchData* data = entity->dataBuf.swtch; - - data->areaFlagIndex = areaFlag; - if (get_area_flag(areaFlag) != 0) { - entity->flags |= ENTITY_FLAG_PENDING_INSTANCE_DELETE; - } - return ApiStatus_DONE2; - } - - return ApiStatus_DONE1; -} - -ApiStatus AssignBlockFlag(Evt* script, s32 isInitialCall) { - Bytecode* args = script->ptrReadPos; - - if (isInitialCall == TRUE) { - s32 index = evt_get_variable_index(script, *args++); - - BlockData* data = get_entity_by_index(gLastCreatedEntityIndex)->dataBuf.block; - data->gameFlagIndex = index; - - return ApiStatus_DONE2; - } - - return ApiStatus_DONE1; -} - -ApiStatus AssignChestFlag(Evt* script, s32 isInitialCall) { - Bytecode* args = script->ptrReadPos; - - if (isInitialCall == TRUE) { - ChestData* data = get_entity_by_index(gLastCreatedEntityIndex)->dataBuf.chest; - data->gameFlagIndex = evt_get_variable_index(script, *args); - - return ApiStatus_DONE2; - } - - return ApiStatus_DONE1; -} - -ApiStatus AssignPanelFlag(Evt* script, s32 isInitialCall) { - Bytecode* args = script->ptrReadPos; - - if (isInitialCall == TRUE) { - HiddenPanelData* data = get_entity_by_index(gLastCreatedEntityIndex)->dataBuf.hiddenPanel; - - data->pickupVar = evt_get_variable_index(script, *args++); - return ApiStatus_DONE2; - } - - return ApiStatus_DONE1; -} - -ApiStatus AssignCrateFlag(Evt* script, s32 isInitialCall) { - Bytecode* args = script->ptrReadPos; - - if (isInitialCall == TRUE) { - WoodenCrateData* data = get_entity_by_index(gLastCreatedEntityIndex)->dataBuf.crate; - - data->globalFlagIndex = evt_get_variable_index(script, *args++); - return ApiStatus_DONE2; - } - - return ApiStatus_DONE1; -} - -s32 create_entity_shadow(Entity* entity, f32 x, f32 y, f32 z) { - u16 staticFlags = entity->blueprint->flags; - s32 type; - s16 shadowIndex; - - if (staticFlags & ENTITY_FLAG_FIXED_SHADOW_SIZE) { - if (staticFlags & ENTITY_FLAG_SQUARE_SHADOW) { - type = 2; - } else { - type = 3; - } - } else { - type = ((staticFlags >> 11) ^ 1) & 1; - } - - shadowIndex = create_shadow_type(type, x, y, z); - entity->shadowIndex = shadowIndex; - - get_shadow_by_index(shadowIndex)->flags |= ENTITY_FLAG_DARK_SHADOW | ENTITY_FLAG_SHADOW_POS_DIRTY; - - return entity->shadowIndex; -} - -s32 create_shadow_type(s32 type, f32 x, f32 y, f32 z) { - s32 isFixedSize = FALSE; - ShadowBlueprint* bp = &CircularShadowA; - s32 shadowIndex; - - switch (type) { - case 2: - isFixedSize = TRUE; - case 0: - bp = &CircularShadowA; - break; - case 3: - isFixedSize = TRUE; - case 1: - bp = &SquareShadow; - break; - case 5: - isFixedSize = TRUE; - case 4: - bp = &CircularShadowB; - break; - } - - shadowIndex = create_shadow_from_data(bp, x, y, z); - - if (isFixedSize) { - get_shadow_by_index(shadowIndex)->flags |= ENTITY_FLAG_FIXED_SHADOW_SIZE; - } - - return shadowIndex; -} - -void delete_shadow(s32 shadowIndex) { - _delete_shadow(shadowIndex); -} - -void update_entity_shadow_position(Entity* entity) { - Shadow* shadow = get_shadow_by_index(entity->shadowIndex); - - if (shadow != NULL) { - f32 rayX; - f32 rayY; - f32 rayZ; - f32 hitYaw; - f32 hitPitch; - f32 hitLength; - f32 origHitLength; - - if (entity->alpha < 255) { - shadow->alpha = entity->alpha / 2; - } else { - u8 alphaTemp; - - if (shadow->flags & ENTITY_FLAG_DARK_SHADOW) { - alphaTemp = 160; - } else { - alphaTemp = 128; - } - shadow->alpha = alphaTemp; - } - - if (!(entity->flags & ENTITY_FLAG_HAS_DYNAMIC_SHADOW)) { - if (shadow->flags & ENTITY_FLAG_SHADOW_POS_DIRTY) { - shadow->flags &= ~ENTITY_FLAG_SHADOW_POS_DIRTY; - } else { - return; - } - } - - rayX = entity->position.x; - rayY = entity->position.y; - rayZ = entity->position.z; - - if (!entity_raycast_down(&rayX, &rayY, &rayZ, &hitYaw, &hitPitch, &hitLength) && hitLength == 32767.0f) { - hitLength = 0.0f; - } - - origHitLength = hitLength; - - if (shadow->flags & ENTITY_FLAG_FIXED_SHADOW_SIZE) { - hitLength = 212.5f; - shadow->scale.x = entity->aabb.x / hitLength; - shadow->scale.z = entity->aabb.z / hitLength; - } else { - hitLength = ((hitLength / 150.0f) + 0.95) * 250.0; - shadow->scale.x = (entity->aabb.x / hitLength) * entity->scale.x; - shadow->scale.z = (entity->aabb.z / hitLength) * entity->scale.z; - } - - shadow->position.x = entity->position.x; - shadow->position.z = entity->position.z; - shadow->position.y = rayY; - entity->shadowPosY = rayY; - shadow->rotation.x = hitYaw; - shadow->rotation.z = hitPitch; - shadow->rotation.y = entity->rotation.y; - - if (entity->position.y < rayY) { - shadow->flags |= ENTITY_FLAG_SKIP_UPDATE; - entity->position.y = rayY + 10.0f; - } else { - shadow->flags &= ~ENTITY_FLAG_SKIP_UPDATE; - } - - shadow->flags = (shadow->flags & ~ENTITY_FLAG_HIDDEN) | ((u16)entity->flags & ENTITY_FLAG_HIDDEN); - if (!(entity->flags & ENTITY_FLAG_400) && origHitLength == 0.0f) { - shadow->flags |= ENTITY_FLAG_HIDDEN; - } - } else { - entity->shadowPosY = 0.0f; - } -} - -s32 entity_raycast_down(f32* x, f32* y, f32* z, f32* hitYaw, f32* hitPitch, f32* hitLength) { - f32 hitX, hitY, hitZ; - f32 hitDepth; - f32 hitNx, hitNy, hitNz; - s32 entityID; - s32 colliderID; - s32 hitID; - s32 ret; - - hitDepth = 32767.0f; - *hitLength = 32767.0f; - entityID = test_ray_entities(*x, *y, *z, 0.0f, -1.0f, 0.0f, &hitX, &hitY, &hitZ, &hitDepth, &hitNx, &hitNy, &hitNz); - hitID = -1; - ret = FALSE; - - if ((entityID >= 0) && ((get_entity_type(entityID) != ENTITY_TYPE_PUSH_BLOCK) || (hitNx == 0.0f && hitNz == 0.0f && hitNy == 1.0))) { - hitID = entityID | COLLISION_WITH_ENTITY_BIT; - } - - colliderID = test_ray_colliders(0x10000, *x, *y, *z, 0.0f, -1.0f, 0.0f, &hitX, &hitY, &hitZ, &hitDepth, &hitNx, - &hitNy, &hitNz); - if (colliderID >= 0) { - hitID = colliderID; - } - - if (hitID >= 0) { - *hitLength = hitDepth; - *y = hitY; - *hitYaw = -atan2(0.0f, 0.0f, hitNz * 100.0f, hitNy * 100.0f); - *hitPitch = -atan2(0.0f, 0.0f, hitNx * 100.0f, hitNy * 100.0f); - ret = TRUE; - } else { - *hitYaw = 0.0f; - *hitPitch = 0.0f; - } - return ret; -} - -void set_standard_shadow_scale(Shadow* shadow, f32 height) { - if (!gGameStatusPtr->isBattle) { - shadow->scale.x = 0.13 - (height / 2600.0f); - } else { - shadow->scale.x = 0.12 - (height / 3600.0f); - } - - if (shadow->scale.x < 0.01) { - shadow->scale.x = 0.01f; - } - shadow->scale.z = shadow->scale.x; -} - -void set_npc_shadow_scale(Shadow* shadow, f32 height, f32 npcRadius) { - if (!gGameStatusPtr->isBattle) { - shadow->scale.x = 0.13 - (height / 2600.0f); - } else { - shadow->scale.x = 0.12 - (height / 3600.0f); - } - - if (shadow->scale.x < 0.01) { - shadow->scale.x = 0.01f; - } - - if (npcRadius > 60.0f) { - shadow->scale.z = shadow->scale.x * 2.0f; - } else { - shadow->scale.z = shadow->scale.x; - } -} - -void set_peach_shadow_scale(Shadow* shadow, f32 scale) { - PlayerStatus* playerStatus = &gPlayerStatus; - f32 phi_f2 = 0.12f; - - if (!gGameStatusPtr->isBattle) { - switch (playerStatus->anim) { - case 0xC0018: - case 0xC0019: - case 0xC001A: - case 0xD0008: - shadow->scale.x = 0.26f - (scale / 2600.0f); - if (shadow->scale.x < 0.01) { - shadow->scale.x = 0.01f; - } - shadow->scale.z = 0.13f - (scale / 2600.0f); - if (shadow->scale.z < 0.01) { - shadow->scale.z = 0.01f; - } - return; - } - - phi_f2 = 0.16f; - } - - shadow->scale.x = phi_f2 - (scale / 3600.0f); - if (shadow->scale.x < 0.01) { - shadow->scale.x = 0.01f; - } - shadow->scale.z = shadow->scale.x; -} - -s32 is_block_on_ground(Entity* block) { - f32 x = block->position.x; - f32 y = block->position.y; - f32 z = block->position.z; - f32 hitYaw; - f32 hitPitch; - f32 hitLength; - s32 ret; - - entity_raycast_down(&x, &y, &z, &hitYaw, &hitPitch, &hitLength); - - ret = hitLength; - if (ret == 32767) { - ret = FALSE; - } - - return ret; -} - -void state_delegate_NOP(void) { -} - -void clear_game_modes(void) { - GameMode* gameMode; - s32 i; - - for (gameMode = gMainGameState, i = 0; i < ARRAY_COUNT(gMainGameState); i++, gameMode++) { - gameMode->flags = 0; - } -} - -GameMode* set_next_game_mode(GameMode* arg0) { - GameMode* gameMode; - s32 i; - - for (gameMode = gMainGameState, i = 0; i < ARRAY_COUNT(gMainGameState); i++, gameMode++) { - if (gameMode->flags == 0) { - break; - } - } - - ASSERT(i < ARRAY_COUNT(gMainGameState)); - - gameMode->flags = 1 | 2; - gameMode->init = arg0->init; - gameMode->step = arg0->step; - gameMode->render = arg0->render; - gameMode->unk_0C = NULL; - - if (gameMode->init == NULL) { - gameMode->init = state_delegate_NOP; - } - if (gameMode->step == NULL) { - gameMode->step = state_delegate_NOP; - } - if (gameMode->unk_0C == NULL) { - gameMode->unk_0C = state_delegate_NOP; - } - if (gameMode->render == NULL) { - gameMode->render = state_delegate_NOP; - } - - gameMode->renderAux = state_delegate_NOP; - gameMode->init(); - - return gameMode; -} - -GameMode* set_game_mode_slot(s32 i, GameMode* mode) { - GameMode* gameMode = &gMainGameState[i]; - - ASSERT(i < ARRAY_COUNT(gMainGameState)); - - gameMode->flags = 2 | 1; - gameMode->init = mode->init; - gameMode->step = mode->step; - gameMode->render = mode->render; - gameMode->unk_0C = NULL; - if (gameMode->init == NULL) gameMode->init = state_delegate_NOP; - if (gameMode->step == NULL) gameMode->step = state_delegate_NOP; - if (gameMode->unk_0C == NULL) gameMode->unk_0C = state_delegate_NOP; - if (gameMode->render == NULL) gameMode->render = state_delegate_NOP; - - gameMode->renderAux = state_delegate_NOP; - gameMode->init(); - - return gameMode; -} - -void game_mode_set_fpDrawAuxUI(s32 i, void (*fn)(void)) { - GameMode* gameMode = &gMainGameState[i]; - - ASSERT(i < ARRAY_COUNT(gMainGameState)); - - gameMode->renderAux = fn; - gameMode->flags |= 0x20; - - if (fn == NULL) { - gameMode->renderAux = state_delegate_NOP; - } -} - -void func_80112DD4(s32 i) { - gMainGameState[i].flags |= 4; -} - -void func_80112DFC(s32 i) { - gMainGameState[i].flags |= 8; -} - -void func_80112E24(s32 i) { - gMainGameState[i].flags &= ~0x1C; -} - -void func_80112E4C(s32 i) { - gMainGameState[i].flags &= ~0x0C; - gMainGameState[i].flags |= 0x10; -} - -void step_current_game_mode(void) { - GameMode* gameMode = gMainGameState; - s32 i; - - for (i = 0; i < ARRAY_COUNT(gMainGameState); i++, gameMode++) { - if (gameMode->flags != 0) { - if (!(gameMode->flags & 4)) { - if (!(gameMode->flags & 8)) { - gameMode->flags &= ~2; - gameMode->step(); - } - } - } - } -} - -void state_do_unk(void) { - GameMode* gameMode = gMainGameState; - s32 i; - - for (i = 0; i < ARRAY_COUNT(gMainGameState); i++, gameMode++) { - if (gameMode->flags != 0) { - if (!(gameMode->flags & 4)) { - if (!(gameMode->flags & 0x10)) { - gameMode->unk_0C(); - } - } - } - } -} - -void state_render_backUI(void) { - GameMode* gameMode = gMainGameState; - s32 i; - - for (i = 0; i < ARRAY_COUNT(gMainGameState); i++, gameMode++) { - if (gameMode->flags != 0) { - if (!(gameMode->flags & 4)) { - if (!(gameMode->flags & 0x10)) { - gameMode->render(); - } - } - } - } -} - -void state_render_frontUI(void) { - GameMode* gameMode = gMainGameState; - s32 i; - - for (i = 0; i < ARRAY_COUNT(gMainGameState); i++, gameMode++) { - if (gameMode->flags != 0) { - if (!(gameMode->flags & 4)) { - if (!(gameMode->flags & 2)) { - if (gameMode->flags & 0x20) { - gameMode->renderAux(); - } - } - } - } - } - - // re-initialization needed - evidence of inlining? or just copy/pasting? - gameMode = &gMainGameState[0]; - for (i = 0; i < ARRAY_COUNT(gMainGameState); i++, gameMode++) { - if (gameMode->flags != 0) { - if (!(gameMode->flags & 4)) { - if (!(gameMode->flags & 2)) { - if (gameMode->flags & 0x10) { - gameMode->render(); - } - } - } - } - } -} - void appendGfx_model(void* data) { Model* model = data; s32 mtxPushMode; @@ -3161,12 +1232,14 @@ void appendGfx_model(void* data) { case EXTRA_TILE_4: prop = get_model_property(modelNode, MODEL_PROP_KEY_SPECIAL); if (prop != NULL) { - s32 v1 = prop->data.s; - u16 a2 = prop->dataType; - s32 a1 = prop->dataType; - func_801180E8(textureHeader, gfxPos, textureHandle->raster, textureHandle->palette, textureHandle->auxRaster, textureHandle->auxPalette, - (v1 >> 12) & 0xF, (v1 >> 16) & 0xF, - a2 & 0xFFF, (a1 >> 12) & 0xFFF); + s32 shift = prop->data.s; + u16 offsetS = prop->dataType; + s32 offsetT = prop->dataType; + make_texture_gfx(textureHeader, gfxPos, + textureHandle->raster, textureHandle->palette, + textureHandle->auxRaster, textureHandle->auxPalette, + (shift >> 12) & 0xF, (shift >> 16) & 0xF, + offsetS & 0xFFF, (offsetT >> 12) & 0xFFF); } else { gSPDisplayList((*gfxPos)++, textureHandle->gfx); @@ -3657,44 +1730,48 @@ void appendGfx_model(void* data) { gDPPipeSync((*gfxPos)++); } -void func_80114B58(u32 romOffset, TextureHandle* handle, TextureHeader* header, s32 mainSize, s32 mainPalSize, s32 auxSize, s32 auxPalSize) { +void load_texture_impl(u32 romOffset, TextureHandle* handle, TextureHeader* header, s32 mainSize, s32 mainPalSize, s32 auxSize, s32 auxPalSize) { Gfx** temp; - handle->raster = (IMG_PTR) mdl_nextTextureAddress; + // load main img + palette to texture heap + handle->raster = (IMG_PTR) TextureHeapPos; if (mainPalSize != 0) { - handle->palette = (PAL_PTR) (mdl_nextTextureAddress + mainSize); + handle->palette = (PAL_PTR) (TextureHeapPos + mainSize); } else { handle->palette = NULL; } - dma_copy((u8*) romOffset, (u8*) (romOffset + mainSize + mainPalSize), mdl_nextTextureAddress); + dma_copy((u8*) romOffset, (u8*) (romOffset + mainSize + mainPalSize), TextureHeapPos); romOffset += mainSize + mainPalSize; - mdl_nextTextureAddress += mainSize + mainPalSize; + TextureHeapPos += mainSize + mainPalSize; + + // load aux img + palette to texture heap if (auxSize != 0) { - handle->auxRaster = (IMG_PTR) mdl_nextTextureAddress; + handle->auxRaster = (IMG_PTR) TextureHeapPos; if (auxPalSize != 0) { - handle->auxPalette = (PAL_PTR) (mdl_nextTextureAddress + auxSize); + handle->auxPalette = (PAL_PTR) (TextureHeapPos + auxSize); } else { handle->auxPalette = NULL; } - dma_copy((u8*) romOffset, (u8*) (romOffset + auxSize + auxPalSize), mdl_nextTextureAddress); - mdl_nextTextureAddress += auxSize + auxPalSize; + dma_copy((u8*) romOffset, (u8*) (romOffset + auxSize + auxPalSize), TextureHeapPos); + TextureHeapPos += auxSize + auxPalSize; } else { handle->auxPalette = NULL; handle->auxRaster = NULL; } - handle->gfx = (Gfx*) mdl_nextTextureAddress; + // copy header data and create a display list for the texture + handle->gfx = (Gfx*) TextureHeapPos; memcpy(&handle->header, header, sizeof(*header)); - func_801180E8(header, (Gfx**)&mdl_nextTextureAddress, handle->raster, handle->palette, handle->auxRaster, handle->auxPalette, 0, 0, 0, 0); + make_texture_gfx(header, (Gfx**) &TextureHeapPos, handle->raster, handle->palette, handle->auxRaster, handle->auxPalette, 0, 0, 0, 0); - temp = (Gfx**) &mdl_nextTextureAddress; + temp = (Gfx**) &TextureHeapPos; gSPEndDisplayList((*temp)++); } -void load_tile_header(ModelNodeProperty* propertyName, s32 romOffset, s32 size) { +void load_texture_by_name(ModelNodeProperty* propertyName, s32 romOffset, s32 size) { char* textureName = (char*)propertyName->data.p; u32 baseOffset = romOffset; - s32 textureID = 0; + s32 textureIdx = 0; u32 paletteSize; u32 rasterSize; u32 auxPaletteSize; @@ -3709,11 +1786,12 @@ void load_tile_header(ModelNodeProperty* propertyName, s32 romOffset, s32 size) } while (romOffset < baseOffset + size) { - dma_copy((u8*)romOffset, (u8*)romOffset + sizeof(gCurrentTileDescriptor), &gCurrentTileDescriptor); - header = &gCurrentTileDescriptor; + dma_copy((u8*)romOffset, (u8*)romOffset + sizeof(gCurrentTextureHeader), &gCurrentTextureHeader); + header = &gCurrentTextureHeader; rasterSize = header->mainW * header->mainH; + // compute mipmaps size if (header->mainBitDepth == G_IM_SIZ_4b) { if (header->extraTiles == EXTRA_TILE_MIPMAPS) { s32 d = 2; @@ -3731,29 +1809,27 @@ void load_tile_header(ModelNodeProperty* propertyName, s32 romOffset, s32 size) d *= 2; } } - } else { - do {} while (0); - if (header->mainBitDepth == G_IM_SIZ_16b) { - if (header->extraTiles == EXTRA_TILE_MIPMAPS) { - s32 d = 2; - while (header->mainW / d >= 4 && header->mainH / d > 0) { - rasterSize += header->mainW / d * header->mainH / d; - d *= 2; - } + } else if (header->mainBitDepth == G_IM_SIZ_16b) { + if (header->extraTiles == EXTRA_TILE_MIPMAPS) { + s32 d = 2; + while (header->mainW / d >= 4 && header->mainH / d > 0) { + rasterSize += header->mainW / d * header->mainH / d; + d *= 2; } - rasterSize *= 2; - } else if (header->mainBitDepth == G_IM_SIZ_32b) { - if (header->extraTiles == EXTRA_TILE_MIPMAPS) { - s32 d = 2; - while (header->mainW / d >= 2 && header->mainH / d > 0) { - rasterSize += header->mainW / d * header->mainH / d; - d *= 2; - } - } - rasterSize *= 4; } + rasterSize *= 2; + } else if (header->mainBitDepth == G_IM_SIZ_32b) { + if (header->extraTiles == EXTRA_TILE_MIPMAPS) { + s32 d = 2; + while (header->mainW / d >= 2 && header->mainH / d > 0) { + rasterSize += header->mainW / d * header->mainH / d; + d *= 2; + } + } + rasterSize *= 4; } + // compute palette size if (header->mainFmt == G_IM_FMT_CI) { paletteSize = 0x20; if (header->mainBitDepth == G_IM_SIZ_8b) { @@ -3763,6 +1839,7 @@ void load_tile_header(ModelNodeProperty* propertyName, s32 romOffset, s32 size) paletteSize = 0; } + // compute aux tile size if (header->extraTiles == EXTRA_TILE_AUX_INDEPENDENT) { auxRasterSize = header->auxW * header->auxH; if (header->auxBitDepth == G_IM_SIZ_4b) { @@ -3789,53 +1866,58 @@ void load_tile_header(ModelNodeProperty* propertyName, s32 romOffset, s32 size) } if (strcmp(textureName, header->name) == 0) { + // found the texture with `textureName` break; } - textureID++; + textureIdx++; mainSize = rasterSize + paletteSize + sizeof(*header); romOffset += mainSize; romOffset += auxRasterSize + auxPaletteSize; } if (romOffset >= baseOffset + 0x40000) { + // did not find the texture with `textureName` (*mdl_currentModelTreeNodeInfo)[mdl_treeIterPos].textureID = 0; return; } - (*mdl_currentModelTreeNodeInfo)[mdl_treeIterPos].textureID = textureID + 1; + (*mdl_currentModelTreeNodeInfo)[mdl_treeIterPos].textureID = textureIdx + 1; textureHandle = &mdl_textureHandles[(*mdl_currentModelTreeNodeInfo)[mdl_treeIterPos].textureID]; romOffset += sizeof(*header); if (textureHandle->gfx == NULL) { - func_80114B58(romOffset, textureHandle, header, rasterSize, paletteSize, auxRasterSize, auxPaletteSize); - func_80115498(romOffset + rasterSize + paletteSize + auxRasterSize + auxPaletteSize, (*mdl_currentModelTreeNodeInfo)[mdl_treeIterPos].textureID, baseOffset, size); + load_texture_impl(romOffset, textureHandle, header, rasterSize, paletteSize, auxRasterSize, auxPaletteSize); + load_texture_variants(romOffset + rasterSize + paletteSize + auxRasterSize + auxPaletteSize, (*mdl_currentModelTreeNodeInfo)[mdl_treeIterPos].textureID, baseOffset, size); } - } -void func_80115498(u32 romOffset, s32 textureID, s32 baseOffset, s32 size) { +// loads variations for current texture by looping through the following textures until a non-variant is found +void load_texture_variants(u32 romOffset, s32 textureID, s32 baseOffset, s32 size) { u32 offset; - TextureHeader sp20; + TextureHeader iterTextureHeader; + TextureHeader* header; + TextureHandle* textureHandle; u32 rasterSize; s32 paletteSize; u32 auxRasterSize; u32 auxPaletteSize; s32 bitDepth; s32 mainSize; - TextureHeader* header; s32 currentTextureID = textureID; - for (offset = romOffset; offset < baseOffset + size;) { - dma_copy((u8*)offset, (u8*)offset + sizeof(sp20), &sp20); - header = &sp20; - if (header->unk_28 == 0) { + dma_copy((u8*)offset, (u8*)offset + sizeof(iterTextureHeader), &iterTextureHeader); + header = &iterTextureHeader; + + if (!header->isVariant) { + // done reading variants break; } rasterSize = header->mainW * header->mainH; + // compute mipmaps size if (header->mainBitDepth == G_IM_SIZ_4b) { if (header->extraTiles == EXTRA_TILE_MIPMAPS) { s32 d = 2; @@ -3853,29 +1935,27 @@ void func_80115498(u32 romOffset, s32 textureID, s32 baseOffset, s32 size) { d *= 2; } } - } else { - do {} while (0); - if (header->mainBitDepth == G_IM_SIZ_16b) { - if (header->extraTiles == EXTRA_TILE_MIPMAPS) { - s32 d = 2; - while (header->mainW / d >= 4 && header->mainH / d > 0) { - rasterSize += header->mainW / d * header->mainH / d; - d *= 2; - } + } else if (header->mainBitDepth == G_IM_SIZ_16b) { + if (header->extraTiles == EXTRA_TILE_MIPMAPS) { + s32 d = 2; + while (header->mainW / d >= 4 && header->mainH / d > 0) { + rasterSize += header->mainW / d * header->mainH / d; + d *= 2; } - rasterSize *= 2; - } else if (header->mainBitDepth == G_IM_SIZ_32b) { - if (header->extraTiles == EXTRA_TILE_MIPMAPS) { - s32 d = 2; - while (header->mainW / d >= 2 && header->mainH / d > 0) { - rasterSize += header->mainW / d * header->mainH / d; - d *= 2; - } - } - rasterSize *= 4; } + rasterSize *= 2; + } else if (header->mainBitDepth == G_IM_SIZ_32b) { + if (header->extraTiles == EXTRA_TILE_MIPMAPS) { + s32 d = 2; + while (header->mainW / d >= 2 && header->mainH / d > 0) { + rasterSize += header->mainW / d * header->mainH / d; + d *= 2; + } + } + rasterSize *= 4; } + // compute palette size if (header->mainFmt == G_IM_FMT_CI) { paletteSize = 0x20; if (header->mainBitDepth == G_IM_SIZ_8b) { @@ -3885,6 +1965,7 @@ void func_80115498(u32 romOffset, s32 textureID, s32 baseOffset, s32 size) { paletteSize = 0; } + // compute aux tile size if (header->extraTiles == EXTRA_TILE_AUX_INDEPENDENT) { auxRasterSize = header->auxW * header->auxH; if (header->auxBitDepth == G_IM_SIZ_4b) { @@ -3909,8 +1990,12 @@ void func_80115498(u32 romOffset, s32 textureID, s32 baseOffset, s32 size) { auxPaletteSize = 0; auxRasterSize = 0; } - currentTextureID = ++textureID; - func_80114B58(offset + sizeof(*header), &mdl_textureHandles[currentTextureID], header, rasterSize, paletteSize, auxRasterSize, auxPaletteSize); + + textureID++; + currentTextureID = textureID; + textureHandle = &mdl_textureHandles[currentTextureID]; + load_texture_impl(offset + sizeof(*header), textureHandle, header, rasterSize, paletteSize, auxRasterSize, auxPaletteSize); + mainSize = rasterSize + paletteSize + sizeof(*header); offset += mainSize; offset += auxRasterSize + auxPaletteSize; @@ -3931,7 +2016,8 @@ ModelNodeProperty* get_model_property(ModelNode* node, ModelPropertyKeys key) { return NULL; } -void _load_model_textures(ModelNode* model, s32 romOffset, s32 size) { +// load textures used by models, starting from current model +void load_next_model_textures(ModelNode* model, s32 romOffset, s32 texSize) { if (model->type != SHAPE_TYPE_MODEL) { if (model->groupData != NULL) { s32 numChildren = model->groupData->numChildren; @@ -3940,25 +2026,31 @@ void _load_model_textures(ModelNode* model, s32 romOffset, s32 size) { s32 i; for (i = 0; i < numChildren; i++) { - _load_model_textures(model->groupData->childList[i], romOffset, size); + load_next_model_textures(model->groupData->childList[i], romOffset, texSize); } } } } else { ModelNodeProperty* propTextureName = get_model_property(model, MODEL_PROP_KEY_TEXTURE_NAME); if (propTextureName != NULL) { - load_tile_header(propTextureName, romOffset, size); + load_texture_by_name(propTextureName, romOffset, texSize); } } mdl_treeIterPos++; } -void load_model_textures(ModelNode* model, s32 romOffset, s32 size) { - s32 battleOffset = ((gGameStatusPtr->isBattle != 0) << 17); // TODO FIX +// load all textures used by models, starting from the root +void mdl_load_all_textures(ModelNode* rootModel, s32 romOffset, s32 size) { + s32 baseOffset = 0; + + // textures are loaded to the upper half of the texture heap when not in the world + if (gGameStatusPtr->isBattle != 0) { + baseOffset = MAP_TEXTURE_MEMORY_SIZE; + } - mdl_nextTextureAddress = mdl_textureBaseAddress + battleOffset; + TextureHeapPos = TextureHeapBase + baseOffset; - if (model != NULL && romOffset != 0 && size != 0) { + if (rootModel != NULL && romOffset != 0 && size != 0) { s32 i; for (i = 0; i < ARRAY_COUNT(mdl_textureHandles); i++) { @@ -3966,8 +2058,8 @@ void load_model_textures(ModelNode* model, s32 romOffset, s32 size) { } mdl_treeIterPos = 0; - if (model != NULL) { - _load_model_textures(model, romOffset, size); + if (rootModel != NULL) { + load_next_model_textures(rootModel, romOffset, size); } } } @@ -4110,15 +2202,15 @@ void mdl_create_model(ModelBlueprint* bp, s32 arg1) { prop = get_model_property(node, MODEL_PROP_KEY_SPECIAL); modelIdx = 0; if (prop != NULL) { - s32 temp_s1 = (u8) prop->data.s / 16; + s32 replaceWithFlame = (prop->data.s >> 4) & 0xF; - if (temp_s1 != 0) { + if (replaceWithFlame != 0) { prop = get_model_property(node, MODEL_PROP_KEY_BOUNDING_BOX); if (prop != NULL) { ModelBoundingBox* bb = (ModelBoundingBox*) prop; fx_flame( - temp_s1 - 1, (bb->minX + bb->maxX) * 0.5f, bb->minY, (bb->minZ + bb->maxZ) * 0.5f, 1.0f, &effect + replaceWithFlame - 1, (bb->minX + bb->maxX) * 0.5f, bb->minY, (bb->minZ + bb->maxZ) * 0.5f, 1.0f, &effect ); return; } @@ -4152,7 +2244,7 @@ void mdl_create_model(ModelBlueprint* bp, s32 arg1) { prop = get_model_property(node, MODEL_PROP_KEY_GROUP_TYPE); if (prop != NULL) { - prop = &prop[1]; + prop++; } } @@ -4658,7 +2750,7 @@ void render_transform_group(void* data) { } } -void func_801180E8(TextureHeader* header, Gfx** gfxPos, IMG_PTR raster, PAL_PTR palette, IMG_PTR auxRaster, PAL_PTR auxPalette, u8 arg6, u8 arg7, u16 arg8, u16 arg9) { +void make_texture_gfx(TextureHeader* header, Gfx** gfxPos, IMG_PTR raster, PAL_PTR palette, IMG_PTR auxRaster, PAL_PTR auxPalette, u8 auxShiftS, u8 auxShiftT, u16 auxOffsetS, u16 auxOffsetT) { s32 mainWidth, mainHeight; s32 auxWidth, auxHeight; s32 mainFmt; @@ -4833,22 +2925,22 @@ void func_801180E8(TextureHeader* header, Gfx** gfxPos, IMG_PTR raster, PAL_PTR case G_IM_SIZ_4b: gDPScrollTextureBlockHalfHeight_4b((*gfxPos)++, raster, mainFmt, mainWidth, mainHeight, 0, mainWrapW, mainWrapH, mainMasks, mainMaskt, G_TX_NOLOD, G_TX_NOLOD, - arg8, arg9, arg6, arg7); + auxOffsetS, auxOffsetT, auxShiftS, auxShiftT); break; case G_IM_SIZ_8b: gDPScrollTextureBlockHalfHeight((*gfxPos)++, raster, mainFmt, G_IM_SIZ_8b, mainWidth, mainHeight, 0, mainWrapW, mainWrapH, mainMasks, mainMaskt, G_TX_NOLOD, G_TX_NOLOD, - arg8, arg9, arg6, arg7); + auxOffsetS, auxOffsetT, auxShiftS, auxShiftT); break; case G_IM_SIZ_16b: gDPScrollTextureBlockHalfHeight((*gfxPos)++, raster, mainFmt, G_IM_SIZ_16b, mainWidth, mainHeight, 0, mainWrapW, mainWrapH, mainMasks, mainMaskt, G_TX_NOLOD, G_TX_NOLOD, - arg8, arg9, arg6, arg7); + auxOffsetS, auxOffsetT, auxShiftS, auxShiftT); break; case G_IM_SIZ_32b: gDPScrollTextureBlockHalfHeight((*gfxPos)++, raster, mainFmt, G_IM_SIZ_32b, mainWidth, mainHeight, 0, mainWrapW, mainWrapH, mainMasks, mainMaskt, G_TX_NOLOD, G_TX_NOLOD, - arg8, arg9, arg6, arg7); + auxOffsetS, auxOffsetT, auxShiftS, auxShiftT); break; } break; @@ -4887,25 +2979,25 @@ void func_801180E8(TextureHeader* header, Gfx** gfxPos, IMG_PTR raster, PAL_PTR gDPScrollMultiTile_4b((*gfxPos)++, auxRaster, lodDivisor, 1, auxFmt, auxWidth, auxHeight, 0, 0, auxWidth - 1, auxHeight - 1, auxPaletteIndex, auxWrapW, auxWrapH, auxMasks, auxMaskt, - arg6, arg7, arg8, arg9); + auxShiftS, auxShiftT, auxOffsetS, auxOffsetT); break; case G_IM_SIZ_8b: gDPScrollMultiTile((*gfxPos)++, auxRaster, lodDivisor, 1, auxFmt, G_IM_SIZ_8b, auxWidth, auxHeight, 0, 0, auxWidth - 1, auxHeight - 1, auxPaletteIndex, auxWrapW, auxWrapH, auxMasks, auxMaskt, - arg6, arg7, arg8, arg9); + auxShiftS, auxShiftT, auxOffsetS, auxOffsetT); break; case G_IM_SIZ_16b: gDPScrollMultiTile((*gfxPos)++, auxRaster, lodDivisor, 1, auxFmt, G_IM_SIZ_16b, auxWidth, auxHeight, 0, 0, auxWidth - 1, auxHeight - 1, auxPaletteIndex, auxWrapW, auxWrapH, auxMasks, auxMaskt, - arg6, arg7, arg8, arg9); + auxShiftS, auxShiftT, auxOffsetS, auxOffsetT); break; case G_IM_SIZ_32b: gDPScrollMultiTile((*gfxPos)++, auxRaster, lodDivisor, 1, auxFmt, G_IM_SIZ_32b, auxWidth, auxHeight, 0, 0, auxWidth - 1, auxHeight - 1, auxPaletteIndex, auxWrapW, auxWrapH, auxMasks, auxMaskt, - arg6, arg7, arg8, arg9); + auxShiftS, auxShiftT, auxOffsetS, auxOffsetT); break; } } @@ -4916,24 +3008,24 @@ Model* get_model_from_list_index(s32 listIndex) { return (*gCurrentModels)[listIndex]; } -void load_data_for_models(ModelNode* model, s32 romOffset, s32 size) { +void load_data_for_models(ModelNode* rootModel, s32 texturesOffset, s32 size) { Matrix4f mtx; guMtxIdentF(mtx); - if (romOffset != 0) { - load_model_textures(model, romOffset, size); + if (texturesOffset != 0) { + mdl_load_all_textures(rootModel, texturesOffset, size); } - *gCurrentModelTreeRoot = model; + *gCurrentModelTreeRoot = rootModel; mdl_treeIterPos = 0; - if (model != NULL) { - load_model_transforms(model, NULL, mtx, 0); + if (rootModel != NULL) { + load_model_transforms(rootModel, NULL, mtx, 0); } } -void load_model_transforms(ModelNode* model, ModelNode* parent, Matrix4f mdlTxMtx, s32 treeDepth) { +void load_model_transforms(ModelNode* model, ModelNode* parent, Matrix4f mdlTransformMtx, s32 treeDepth) { Matrix4f sp10; Mtx sp50; ModelBlueprint modelBP; @@ -4949,7 +3041,7 @@ void load_model_transforms(ModelNode* model, ModelNode* parent, Matrix4f mdlTxMt Matrix4f spA0; guMtxL2F(spA0, model->groupData->transformMatrix); - guMtxCatF(spA0, mdlTxMtx, sp10); + guMtxCatF(spA0, mdlTransformMtx, sp10); } groupTypeProperty = get_model_property(model, MODEL_PROP_KEY_GROUP_TYPE); @@ -4962,7 +3054,7 @@ void load_model_transforms(ModelNode* model, ModelNode* parent, Matrix4f mdlTxMt if (model->type != SHAPE_TYPE_GROUP || groupType == 0) { for (i = 0; i < model->groupData->numChildren; i++) { load_model_transforms(model->groupData->childList[i], model, - model->groupData->transformMatrix != NULL ? sp10 : mdlTxMtx, treeDepth + 1); + model->groupData->transformMatrix != NULL ? sp10 : mdlTransformMtx, treeDepth + 1); } (*mdl_currentModelTreeNodeInfo)[mdl_treeIterPos].modelIndex = -1; @@ -4972,7 +3064,7 @@ void load_model_transforms(ModelNode* model, ModelNode* parent, Matrix4f mdlTxMt } } - guMtxF2L(mdlTxMtx, &sp50); + guMtxF2L(mdlTransformMtx, &sp50); modelBPptr->flags = 0; modelBPptr->mdlNode = model; modelBPptr->groupData = parent->groupData; @@ -6098,16 +4190,15 @@ void mdl_draw_hidden_panel_surface(Gfx** arg0, u16 treeIndex) { } void* mdl_get_next_texture_address(s32 size) { - u32 offset = mdl_nextTextureAddress - mdl_textureBaseAddress + 0x3F; + u32 offset = TextureHeapPos - TextureHeapBase + 0x3F; offset = (offset >> 6) << 6; - if (size + offset > 0x28000) { + if (size + offset > MAP_TEXTURE_MEMORY_SIZE + BTL_TEXTURE_MEMORY_SIZE) { return NULL; } else { - return mdl_textureBaseAddress + offset; + return TextureHeapBase + offset; } - } void mdl_set_all_fog_mode(s32 fogMode) { diff --git a/src/pause/pause_common.h b/src/pause/pause_common.h index f7a5f2669b..e8dfa161c4 100644 --- a/src/pause/pause_common.h +++ b/src/pause/pause_common.h @@ -126,7 +126,7 @@ void pause_set_cursor_pos_immediate(s32 windowID, s32 posX, s32 posY); void pause_set_cursor_opacity(s32 val); void pause_draw_menu_label(s32 index, s32 x, s32 y); s32 pause_get_total_equipped_bp_cost(void); -void pause_draw_rect(s32 ulx, s32 uly, s32 lrx, s32 lry, s32 tileDescriptor, s32 uls, s32 ult, s32 dsdx, s32 dtdy); +void pause_draw_rect(s32 ulx, s32 uly, s32 lrx, s32 lry, s32 tileIdx, s32 uls, s32 ult, s32 dsdx, s32 dtdy); s32 pause_get_menu_msg(s32 index); s32 pause_interp_vertical_scroll(s32 deltaBefore); void pause_sort_item_list(s16* arr, s32 len, s32 (*compare)(s16*, s16 *)); diff --git a/src/pause/pause_main.c b/src/pause/pause_main.c index cd9ad323c3..b1c06e2399 100644 --- a/src/pause/pause_main.c +++ b/src/pause/pause_main.c @@ -845,14 +845,14 @@ s32 pause_get_total_equipped_bp_cost(void) { return totalCost; } -void pause_draw_rect(s32 ulx, s32 uly, s32 lrx, s32 lry, s32 tileDescriptor, s32 uls, s32 ult, s32 dsdx, s32 dtdy) { +void pause_draw_rect(s32 ulx, s32 uly, s32 lrx, s32 lry, s32 tileIdx, s32 uls, s32 ult, s32 dsdx, s32 dtdy) { if (ulx <= -2688 || uly <= -2688 || lrx <= 0 || lry <= 0) { return; } if (ulx >= 1280 || uly >= 960 || lrx >= 2688 || lry >= 2688) { return; } - gSPScisTextureRectangle(gMainGfxPos++, ulx, uly, lrx, lry, tileDescriptor, uls, ult, dsdx, dtdy); + gSPScisTextureRectangle(gMainGfxPos++, ulx, uly, lrx, lry, tileIdx, uls, ult, dsdx, dtdy); } void pause_sort_item_list(s16* arr, s32 len, s32 (*compare)(s16*, s16 *)) { diff --git a/src/state_battle.c b/src/state_battle.c index 861aacf253..be0ffe0ed2 100644 --- a/src/state_battle.c +++ b/src/state_battle.c @@ -195,7 +195,7 @@ void state_step_end_battle(void) { set_background_size(296, 200, 12, 20); } - load_model_textures(mapSettings->modelTreeRoot, get_asset_offset(wMapTexName, &sizeTemp), sizeTemp); + mdl_load_all_textures(mapSettings->modelTreeRoot, get_asset_offset(wMapTexName, &sizeTemp), sizeTemp); calculate_model_sizes(); npc_reload_all(); diff --git a/src/state_file_select.c b/src/state_file_select.c index c2dfc026d2..48aedca37d 100644 --- a/src/state_file_select.c +++ b/src/state_file_select.c @@ -57,7 +57,7 @@ void state_init_file_select(void) { general_heap_create(); hud_element_set_aux_cache(0, 0); hud_element_clear_cache(); - load_model_textures(0, 0, 0); + mdl_load_all_textures(NULL, 0, 0); gCameras[CAM_DEFAULT].updateMode = CAM_UPDATE_MODE_6; gCameras[CAM_DEFAULT].needsInit = TRUE; gCameras[CAM_DEFAULT].nearClip = 16; diff --git a/src/state_title_screen.c b/src/state_title_screen.c index 02ba8f78c9..b4e58f047f 100644 --- a/src/state_title_screen.c +++ b/src/state_title_screen.c @@ -100,7 +100,7 @@ void state_init_title_screen(void) { gOverrideFlags = 0; timeFreezeMode = 0; - D_8014C248[0] = 1; + D_8014C248 = TRUE; general_heap_create(); clear_printers(); sfx_set_reverb_mode(0); diff --git a/src/world/area_hos/hos_05/hos_05_5_intro.c b/src/world/area_hos/hos_05/hos_05_5_intro.c index 9fbcbe429b..dcb6753071 100644 --- a/src/world/area_hos/hos_05/hos_05_5_intro.c +++ b/src/world/area_hos/hos_05/hos_05_5_intro.c @@ -1910,11 +1910,6 @@ EvtScript N(EVS_Intro_Main) = { f32 N(AnimBowser_FlyOff_Time) = 0.0; -#if VERSION_PAL -API_CALLABLE(N(AnimBowser_FlyOff)); -INCLUDE_ASM(ApiResult, "world/area_hos/hos_05/hos_05_5_intro", AnimBowser_FlyOff); -asm(".section .data"); -#else API_CALLABLE(N(AnimBowser_FlyOff)) { Npc* bowserMain = resolve_npc(script, NPC_Bowser_Body); Npc* bowserProp = resolve_npc(script, NPC_Bowser_Prop); @@ -1931,20 +1926,15 @@ API_CALLABLE(N(AnimBowser_FlyOff)) { bowserMain->colliderPos.y = bowserMain->pos.y; bowserProp->colliderPos.y = bowserProp->pos.y; N(AnimBowser_FlyOff_Time)++; - if (N(AnimBowser_FlyOff_Time) > 40.0f) { + if (N(AnimBowser_FlyOff_Time) > (int)(40 * DT)) { return ApiStatus_DONE1; } else { return ApiStatus_BLOCK; } } -#endif f32 N(AnimKammy_FlyOff_Time) = 0.0; -#if VERSION_PAL -API_CALLABLE(N(AnimKammy_FlyOff)); -INCLUDE_ASM(ApiResult, "world/area_hos/hos_05/hos_05_5_intro", AnimKammy_FlyOff); -#else API_CALLABLE(N(AnimKammy_FlyOff)) { Npc* kammy = resolve_npc(script, NPC_Kammy); @@ -1958,13 +1948,12 @@ API_CALLABLE(N(AnimKammy_FlyOff)) { 40.0f, &kammy->pos.y); kammy->colliderPos.y = kammy->pos.y; N(AnimKammy_FlyOff_Time)++; - if (N(AnimKammy_FlyOff_Time) > 40.0f) { + if (N(AnimKammy_FlyOff_Time) > (int)(40 * DT)) { return ApiStatus_DONE1; } else { return ApiStatus_BLOCK; } } -#endif API_CALLABLE(N(func_80244934_A2EB74)) { if (isInitialCall) { diff --git a/src/world/area_mgm/mgm_02/mgm_02.h b/src/world/area_mgm/mgm_02/mgm_02.h index a781314b14..6610529665 100644 --- a/src/world/area_mgm/mgm_02/mgm_02.h +++ b/src/world/area_mgm/mgm_02/mgm_02.h @@ -44,3 +44,7 @@ extern EvtScript N(EVS_Main); extern EvtScript N(EVS_Dummy); extern EvtScript N(EVS_InitializeMinigame); extern NpcGroupList N(DefaultNPCs); + +#if VERSION_PAL +extern s32 N(pal_variable); +#endif diff --git a/src/world/area_mgm/mgm_02/mgm_02_0_header.c b/src/world/area_mgm/mgm_02/mgm_02_0_header.c index 004409bec5..bc11773e4d 100644 --- a/src/world/area_mgm/mgm_02/mgm_02_0_header.c +++ b/src/world/area_mgm/mgm_02/mgm_02_0_header.c @@ -1,7 +1,6 @@ #include "mgm_02.h" #if VERSION_PAL -extern s32 N(pal_variable); s32 N(get_tattle)(void) { s32 msgID = MSG_MapTattle_mgm_02; if (N(pal_variable) != 0) { diff --git a/src/world/area_mgm/mgm_02/mgm_02_2_npc.c b/src/world/area_mgm/mgm_02/mgm_02_2_npc.c index 165137adb2..af0661af72 100644 --- a/src/world/area_mgm/mgm_02/mgm_02_2_npc.c +++ b/src/world/area_mgm/mgm_02/mgm_02_2_npc.c @@ -438,7 +438,7 @@ API_CALLABLE(N(RunMinigame)) { gameFinished = FALSE; hittingPeachBlock = FALSE; - data = get_enemy(0)->varTablePtr[0]; + data = get_enemy(SCOREKEEPER_ENEMY_IDX)->varTablePtr[SMASH_DATA_VAR_IDX]; for (i = 0; i < NUM_BOXES; i++) { if (data->box[i].npcID != -1) { diff --git a/src/world/world.c b/src/world/world.c index 4f6d060227..2ee8d1a903 100644 --- a/src/world/world.c +++ b/src/world/world.c @@ -199,10 +199,10 @@ void load_map_by_IDs(s16 areaID, s16 mapID, s16 loadType) { sfx_reset_door_sounds(); if (!skipLoadingAssets) { - s32 thing = get_asset_offset(wMapTexName, &decompressedSize); + s32 texturesOffset = get_asset_offset(wMapTexName, &decompressedSize); if (mapSettings->modelTreeRoot != NULL) { - load_data_for_models(mapSettings->modelTreeRoot, thing, decompressedSize); + load_data_for_models(mapSettings->modelTreeRoot, texturesOffset, decompressedSize); } } diff --git a/tools/build/configure.py b/tools/build/configure.py index f27fcc36bf..c87e0b6db2 100755 --- a/tools/build/configure.py +++ b/tools/build/configure.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -from functools import cache +from functools import lru_cache import os import shutil from typing import List, Dict, Optional, Set, Union @@ -21,6 +21,7 @@ YAY0_COMPRESS_TOOL = f"{BUILD_TOOLS}/yay0/Yay0compress" CRC_TOOL = f"{BUILD_TOOLS}/rom/n64crc" + def exec_shell(command: List[str]) -> str: ret = subprocess.run(command, stdout=subprocess.PIPE, text=True) return ret.stdout @@ -238,6 +239,12 @@ def write_ninja_rules( command=f"$python {BUILD_TOOLS}/mapfs/combine.py $version $out $in", ) + ninja.rule( + "tex", + description="tex $out", + command=f"$python {BUILD_TOOLS}/mapfs/tex.py $out $tex_dir", + ) + ninja.rule( "pack_title_data", description="pack_title_data $out", @@ -400,7 +407,7 @@ class Configure: return [str(v) for v in ret.values()] - @cache + @lru_cache(maxsize=None) def resolve_asset_path(self, path: Path) -> Path: parts = list(path.parts) @@ -887,7 +894,15 @@ class Configure: ) elif name.endswith("_tex"): compress = False - bin_path = path + tex_dir = path.parent / name + build( + bin_path, + [tex_dir], + "tex", + variables={ + "tex_dir": str(tex_dir) + } + ) elif name.endswith("_shape"): map_name = "_".join(name.split("_")[:-1]) diff --git a/tools/build/img/build.py b/tools/build/img/build.py index 5823b7647e..6489fb9ec7 100755 --- a/tools/build/img/build.py +++ b/tools/build/img/build.py @@ -6,6 +6,7 @@ from glob import glob import png # type: ignore + def unpack_color(s): r = (s >> 11) & 0x1F g = (s >> 6) & 0x1F @@ -47,12 +48,11 @@ def reversed_if(iterator, cond): class Converter: - def __init__(self, mode, infile, outfile, *argv): + def __init__(self, mode, infile, flip_x: bool = False, flip_y: bool = False): self.mode = mode self.infile = infile - self.outfile = outfile - self.flip_x = "--flip-x" in argv - self.flip_y = "--flip-y" in argv + self.flip_x = flip_x + self.flip_y = flip_y assert self.flip_x == False, "flip_x is not supported" @@ -64,151 +64,150 @@ class Converter: print(self.infile + ": warning: " + msg, file=stderr) def convert(self): + out_bytes = bytearray() + out_width = 0 + out_height = 0 img = png.Reader(self.infile) if self.mode == "rgba32": - with open(self.outfile, "wb") as f: - for row in reversed_if(img.asRGBA()[2], self.flip_y): - f.write(row) + (out_width, out_height, data, info) = img.asRGBA() + for row in reversed_if(data, self.flip_y): + out_bytes += row elif self.mode == "rgba16": - with open(self.outfile, "wb") as f: - for row in reversed_if(img.asRGBA()[2], self.flip_y): - for rgba in iter_in_groups(row, 4): - if rgba[3] not in (0, 0xFF): - self.warn("alpha mask mode but translucent pixels used") + (out_width, out_height, data, info) = img.asRGBA() + for row in reversed_if(data, self.flip_y): + for rgba in iter_in_groups(row, 4): + if rgba[3] not in (0, 0xFF): + self.warn("alpha mask mode but translucent pixels used") - color = pack_color(*rgba) - f.write(color.to_bytes(2, byteorder="big")) + color = pack_color(*rgba) + out_bytes += color.to_bytes(2, byteorder="big") elif self.mode == "ci8": - with open(self.outfile, "wb") as f: - for row in reversed_if(img.read()[2], self.flip_y): - f.write(row) + (out_width, out_height, data, info) = img.read() + for row in reversed_if(data, self.flip_y): + out_bytes += row elif self.mode == "ci4": - with open(self.outfile, "wb") as f: - for row in reversed_if(img.read()[2], self.flip_y): - for a, b in iter_in_groups(row, 2): - byte = (a << 4) | b - byte = byte & 0xFF - f.write(byte.to_bytes(1, byteorder="big")) + (out_width, out_height, data, info) = img.read() + for row in reversed_if(data, self.flip_y): + for a, b in iter_in_groups(row, 2): + byte = (a << 4) | b + byte = byte & 0xFF + out_bytes += byte.to_bytes(1, byteorder="big") elif self.mode == "palette": img.preamble(True) palette = img.palette(alpha="force") - with open(self.outfile, "wb") as f: - for rgba in palette: - if rgba[3] not in (0, 0xFF): - self.warn("alpha mask mode but translucent pixels used") + for rgba in palette: + if rgba[3] not in (0, 0xFF): + self.warn("alpha mask mode but translucent pixels used") - color = pack_color(*rgba) - f.write(color.to_bytes(2, byteorder="big")) + color = pack_color(*rgba) + out_bytes += color.to_bytes(2, byteorder="big") elif self.mode == "ia4": - with open(self.outfile, "wb") as f: - for row in reversed_if(img.asRGBA()[2], self.flip_y): - for c1, c2 in iter_in_groups(iter_in_groups(row, 4), 2): - i1 = rgb_to_intensity(*c1[:3]) - a1 = c1[3] + (out_width, out_height, data, info) = img.asRGBA() + for row in reversed_if(data, self.flip_y): + for c1, c2 in iter_in_groups(iter_in_groups(row, 4), 2): + i1 = rgb_to_intensity(*c1[:3]) + a1 = c1[3] - i2 = rgb_to_intensity(*c2[:3]) - a2 = c2[3] + i2 = rgb_to_intensity(*c2[:3]) + a2 = c2[3] - i1 = i1 >> 5 - i2 = i2 >> 5 + i1 = i1 >> 5 + i2 = i2 >> 5 - if a1 not in (0, 0xFF) or a2 not in (0, 0xFF): - self.warn("alpha mask mode but translucent pixels used") - if c1[0] != c1[1] != c1[2]: - self.warn("grayscale mode but image is not") - if c2[0] != c2[1] != c2[2]: - self.warn("grayscale mode but image is not") + if a1 not in (0, 0xFF) or a2 not in (0, 0xFF): + self.warn("alpha mask mode but translucent pixels used") + if c1[0] != c1[1] != c1[2]: + self.warn("grayscale mode but image is not") + if c2[0] != c2[1] != c2[2]: + self.warn("grayscale mode but image is not") - a1 = 1 if a1 > 128 else 0 - a2 = 1 if a2 > 128 else 0 + a1 = 1 if a1 > 128 else 0 + a2 = 1 if a2 > 128 else 0 - h = (i1 << 1) | a1 - l = (i2 << 1) | a2 + h = (i1 << 1) | a1 + l = (i2 << 1) | a2 - byte = (h << 4) | l - f.write(byte.to_bytes(1, byteorder="big")) + byte = (h << 4) | l + out_bytes += byte.to_bytes(1, byteorder="big") elif self.mode == "ia8": - with open(self.outfile, "wb") as f: - for row in reversed_if(img.asRGBA()[2], self.flip_y): - for rgba in iter_in_groups(row, 4): - i = rgb_to_intensity(*rgba[:3]) - a = rgba[3] + (out_width, out_height, data, info) = img.asRGBA() + for row in reversed_if(data, self.flip_y): + for rgba in iter_in_groups(row, 4): + i = rgb_to_intensity(*rgba[:3]) + a = rgba[3] - i = floor(15 * (i / 0xFF)) - a = floor(15 * (a / 0xFF)) + i = floor(15 * (i / 0xFF)) + a = floor(15 * (a / 0xFF)) - if rgba[0] != rgba[1] != rgba[2]: - self.warn("grayscale mode but image is not") + if rgba[0] != rgba[1] != rgba[2]: + self.warn("grayscale mode but image is not") - byte = (i << 4) | a - f.write(byte.to_bytes(1, byteorder="big")) + byte = (i << 4) | a + out_bytes += byte.to_bytes(1, byteorder="big") elif self.mode == "ia16": - with open(self.outfile, "wb") as f: - for row in reversed_if(img.asRGBA()[2], self.flip_y): - for rgba in iter_in_groups(row, 4): - i = rgb_to_intensity(*rgba[:3]) - a = rgba[3] + (out_width, out_height, data, info) = img.asRGBA() + for row in reversed_if(data, self.flip_y): + for rgba in iter_in_groups(row, 4): + i = rgb_to_intensity(*rgba[:3]) + a = rgba[3] - if rgba[0] != rgba[1] != rgba[2]: - self.warn("grayscale mode but image is not") + if rgba[0] != rgba[1] != rgba[2]: + self.warn("grayscale mode but image is not") - f.write(bytes((i, a))) + out_bytes += bytes((i, a)) elif self.mode == "i4": - with open(self.outfile, "wb") as f: - for row in reversed_if(img.asRGBA()[2], self.flip_y): - for c1, c2 in iter_in_groups(iter_in_groups(row, 4), 2): - if c1[3] != 0xFF or c2[3] != 0xFF: - self.warn("discarding alpha channel") + (out_width, out_height, data, info) = img.asRGBA() + for row in reversed_if(data, self.flip_y): + for c1, c2 in iter_in_groups(iter_in_groups(row, 4), 2): + if c1[3] != 0xFF or c2[3] != 0xFF: + self.warn("discarding alpha channel") - i1 = rgb_to_intensity(*c1[:3]) - i2 = rgb_to_intensity(*c2[:3]) + i1 = rgb_to_intensity(*c1[:3]) + i2 = rgb_to_intensity(*c2[:3]) - i1 = floor(15 * (i1 / 0xFF)) - i2 = floor(15 * (i2 / 0xFF)) + i1 = floor(15 * (i1 / 0xFF)) + i2 = floor(15 * (i2 / 0xFF)) - if c1[0] != c1[1] != c1[2]: - self.warn("grayscale mode but image is not") - if c2[0] != c2[1] != c2[2]: - self.warn("grayscale mode but image is not") + if c1[0] != c1[1] != c1[2]: + self.warn("grayscale mode but image is not") + if c2[0] != c2[1] != c2[2]: + self.warn("grayscale mode but image is not") - byte = (i1 << 4) | i2 - f.write(byte.to_bytes(1, byteorder="big")) + byte = (i1 << 4) | i2 + out_bytes += byte.to_bytes(1, byteorder="big") elif self.mode == "i8": - with open(self.outfile, "wb") as f: - for row in reversed_if(img.asRGBA()[2], self.flip_y): - for rgba in iter_in_groups(row, 4): - if rgba[3] != 0xFF or rgba[3] != 0xFF: - self.warn("discarding alpha channel") - if rgba[0] != rgba[1] != rgba[2]: - self.warn("grayscale mode but image is not") + (out_width, out_height, data, info) = img.asRGBA() + for row in reversed_if(data, self.flip_y): + for rgba in iter_in_groups(row, 4): + if rgba[3] != 0xFF or rgba[3] != 0xFF: + self.warn("discarding alpha channel") + if rgba[0] != rgba[1] != rgba[2]: + self.warn("grayscale mode but image is not") - i = rgb_to_intensity(*rgba[:3]) - f.write(i.to_bytes(1, byteorder="big")) + i = rgb_to_intensity(*rgba[:3]) + out_bytes += i.to_bytes(1, byteorder="big") elif self.mode == "party": - data = img.read()[2] + (out_width, out_height, data, info) = img.read() img.preamble(True) palette = img.palette(alpha="force") - with open(self.outfile, "wb") as f: - # palette - for rgba in palette: - if rgba[3] not in (0, 0xFF): - self.warn("alpha mask mode but translucent pixels used") + # palette + for rgba in palette: + if rgba[3] not in (0, 0xFF): + self.warn("alpha mask mode but translucent pixels used") - color = pack_color(*rgba) - f.write(color.to_bytes(2, byteorder="big")) + color = pack_color(*rgba) + out_bytes += color.to_bytes(2, byteorder="big") - assert f.tell() == 0x200, "palette has wrong size" + # ci 8 + for row in reversed_if(data, self.flip_y): + out_bytes += row - # ci 8 - for row in reversed_if(data, self.flip_y): - f.write(row) - - f.write(b"\0\0\0\0\0\0\0\0\0\0") # padding + out_bytes += b"\0\0\0\0\0\0\0\0\0\0" # padding elif self.mode == "bg": - width, height, data, info = img.read() + (out_width, out_height, data, info) = img.read() img.preamble(True) palettes = [img.palette(alpha="force")] @@ -217,52 +216,56 @@ class Converter: pal.preamble(True) palettes.append(pal.palette(alpha="force")) - with open(self.outfile, "wb") as f: - baseaddr = 0x80200000 # gBackgroundImage - headers_len = 0x10 * len(palettes) - palettes_len = 0x200 * len(palettes) + baseaddr = 0x80200000 # gBackgroundImage + headers_len = 0x10 * len(palettes) + palettes_len = 0x200 * len(palettes) - # header (struct BackgroundHeader) - for i, palette in enumerate(palettes): - f.write( - (baseaddr + palettes_len + headers_len).to_bytes( - 4, byteorder="big" - ) - ) # raster offset - f.write( - (baseaddr + headers_len + 0x200 * i).to_bytes( - 4, byteorder="big" - ) - ) # palette offset - f.write((12).to_bytes(2, byteorder="big")) # startX - f.write((20).to_bytes(2, byteorder="big")) # startY - f.write((width).to_bytes(2, byteorder="big")) # width - f.write((height).to_bytes(2, byteorder="big")) # height + # header (struct BackgroundHeader) + for i, palette in enumerate(palettes): + out_bytes += (baseaddr + palettes_len + headers_len).to_bytes( + 4, byteorder="big" + ) # raster offset + out_bytes += (baseaddr + headers_len + 0x200 * i).to_bytes( + 4, byteorder="big" + ) # palette offset + out_bytes += (12).to_bytes(2, byteorder="big") # startX + out_bytes += (20).to_bytes(2, byteorder="big") # startY + out_bytes += (out_width).to_bytes(2, byteorder="big") # width + out_bytes += (out_height).to_bytes(2, byteorder="big") # height - assert f.tell() == headers_len + for palette in palettes: + # palette + for rgba in palette: + if rgba[3] not in (0, 0xFF): + self.warn("alpha mask mode but translucent pixels used") - for palette in palettes: - # palette - for rgba in palette: - if rgba[3] not in (0, 0xFF): - self.warn("alpha mask mode but translucent pixels used") + color = pack_color(*rgba) + out_bytes += color.to_bytes(2, byteorder="big") - color = pack_color(*rgba) - f.write(color.to_bytes(2, byteorder="big")) - - assert f.tell() == palettes_len + headers_len - - # ci 8 - for row in reversed_if(data, self.flip_y): - f.write(row) + # ci 8 + for row in reversed_if(data, self.flip_y): + out_bytes += row else: print("unsupported mode", file=stderr) exit(1) + return (out_bytes, out_width, out_height) + if __name__ == "__main__": if len(argv) < 4: print("usage: build.py MODE INFILE OUTFILE [--flip-x] [--flip-y]") exit(1) - Converter(*argv[1:]).convert() + mode = argv[1] + infile = argv[2] + outfile = argv[3] + + flip_x = "--flip-x" in argv + flip_y = "--flip-y" in argv + + (out_bytes, out_width, out_height) = Converter( + mode, infile, flip_x, flip_y + ).convert() + with open(argv[3], "wb") as f: + f.write(out_bytes) diff --git a/tools/build/mapfs/tex.py b/tools/build/mapfs/tex.py new file mode 100644 index 0000000000..113cbbf64a --- /dev/null +++ b/tools/build/mapfs/tex.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 + +import argparse +from pathlib import Path +from sys import argv, path +path.append(str(Path(__file__).parent.parent.parent / "splat")) +path.append(str(Path(__file__).parent.parent.parent / "splat_ext")) +from tex_archives import TexArchive + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Texture archives") + parser.add_argument("bin_out", type=Path, help="Output binary file path") + parser.add_argument("tex_dir", type=Path, help="File path to input tex subdirectory") + parser.add_argument( + "--endian", choices=["big", "little"], default="big", help="Output endianness" + ) + args = parser.parse_args() + + TexArchive.build(args.bin_out, args.tex_dir, args.endian) diff --git a/tools/build/sprite/sprites.py b/tools/build/sprite/sprites.py index fc32fae875..197145862e 100755 --- a/tools/build/sprite/sprites.py +++ b/tools/build/sprite/sprites.py @@ -2,7 +2,7 @@ import argparse from dataclasses import dataclass -from functools import cache +from functools import lru_cache from pathlib import Path import sys from typing import List @@ -95,7 +95,7 @@ SPECIAL_RASTER_BYTES = ( ) -@cache +@lru_cache(maxsize=None) def get_asset_path(asset: str) -> Path: for sdir in ASSET_STACK: potential_path = ASSET_DIR / sdir / "sprite" / asset diff --git a/tools/splat/util/color.py b/tools/splat/util/color.py index 6d75cbd7cd..fc3b242316 100644 --- a/tools/splat/util/color.py +++ b/tools/splat/util/color.py @@ -17,3 +17,11 @@ def unpack_color(data): b = ceil(0xFF * (b / 31)) return r, g, b, a + +def pack_color(r, g, b, a): + r = r >> 3 + g = g >> 3 + b = b >> 3 + a = a >> 7 + + return (r << 11) | (g << 6) | (b << 1) | a diff --git a/tools/splat_ext/pm_map_data.py b/tools/splat_ext/pm_map_data.py index 8337058f5f..6ba7d8f724 100644 --- a/tools/splat_ext/pm_map_data.py +++ b/tools/splat_ext/pm_map_data.py @@ -1,5 +1,6 @@ -import os +import os, sys from pathlib import Path +from typing import List from segtypes.n64.segment import N64Segment from util.n64.Yay0decompress import Yay0Decompressor from util.color import unpack_color @@ -9,6 +10,10 @@ import png # type: ignore import yaml as yaml_loader import n64img.image +SPLAT_EXT_DIR = os.path.dirname(os.path.abspath(__file__)) +sys.path.append(str(Path(SPLAT_EXT_DIR))) +from tex_archives import TexArchive + script_dir = Path(os.path.dirname(os.path.realpath(__file__))) @@ -69,6 +74,8 @@ class N64SegPm_map_data(N64Segment): self.files = yaml_loader.load(f.read(), Loader=yaml_loader.SafeLoader) def split(self, rom_bytes): + assert isinstance(self.rom_start, int) + fs_dir = options.opts.asset_path / self.dir / self.name (fs_dir / "title").mkdir(parents=True, exist_ok=True) (fs_dir / "party").mkdir(parents=True, exist_ok=True) @@ -104,6 +111,7 @@ class N64SegPm_map_data(N64Segment): bytes = Yay0Decompressor.decompress_python(bytes) if name.startswith("party_"): + assert path is not None with open(path, "wb") as f: # CI-8 w = png.Writer(150, 105, palette=parse_palette(bytes[:0x200])) @@ -143,7 +151,7 @@ class N64SegPm_map_data(N64Segment): w = 128 h = 32 img = n64img.image.CI4( - data=bytes[0x10 : 0x10 + w * h], width=w, height=h + data=bytes[0x10 : 0x10 + (w * h // 2)], width=w, height=h ) img.palette = parse_palette(bytes[0x810:0x830]) img.write(fs_dir / "title/copyright.png") @@ -189,7 +197,10 @@ class N64SegPm_map_data(N64Segment): write_bg_png( bytes, fs_dir / "bg" / f"{name}.alt.png", header_offset=0x10 ) + elif name.endswith("_tex"): + TexArchive.extract(bytes, fs_dir / "tex" / name) else: + assert path is not None with open(path, "wb") as f: f.write(bytes) diff --git a/tools/splat_ext/tex_archives.py b/tools/splat_ext/tex_archives.py new file mode 100644 index 0000000000..7d5f422faf --- /dev/null +++ b/tools/splat_ext/tex_archives.py @@ -0,0 +1,642 @@ +from dataclasses import dataclass +import os +import struct +import json +from pathlib import Path + +import png +import n64img.image +from util.color import unpack_color, pack_color +from segtypes.n64.palette import iter_in_groups + +from sys import path + +path.append(str(Path(__file__).parent.parent / "build")) +from img.build import Converter + + +def decode_null_terminated_ascii(data): + length = 0 + for byte in data: + if byte == 0: + break + length += 1 + + return data[:length].decode("ascii") + + +def parse_palette(data): + palette = [] + + for a, b in iter_in_groups(data, 2): + palette.append(unpack_color([a, b])) + + return palette + + +FMT_RGBA = 0 +FMT_CI = 2 +FMT_IA = 3 +FMT_I = 4 + +DEPTH_4_BIT = 0 +DEPTH_8_BIT = 1 +DEPTH_16_BIT = 2 +DEPTH_32_BIT = 3 + +# extra tile modes +TILES_BASIC = 0 +TILES_MIPMAPS = 1 +TILES_SHARED_AUX = 2 +TILES_INDEPENDENT_AUX = 3 + +aux_combine_modes = { + 0x00: "None", # multiply main * prim, ignore aux + 0x08: "Multiply", # multiply main * aux * prim + 0x0D: "ModulateAlpha", # use prim color, but multiply alpha by the difference between main and aux red channels + 0x10: "LerpMainAux", # use prim alpha to lerp between main and aux color, use main alpha +} +aux_combine_modes_inv = {v: k for k, v in aux_combine_modes.items()} + +wrap_modes = { + 0: "Repeat", + 1: "Mirror", + 2: "Clamp", +} +wrap_modes_inv = {v: k for k, v in wrap_modes.items()} + +# correspond to modes provided to gSetTextureFilter, only 0 and 2 are ever used +filter_modes = { + 0: "Nearest", + 2: "Bilerp", + 3: "Average", +} +filter_modes_inv = {v: k for k, v in filter_modes.items()} + + +def get_format_name(fmt, depth): + # get image from bytes for valid combinations of fmt and bit depth + if fmt == FMT_RGBA: + if depth == DEPTH_16_BIT: + return "RGBA16" + if depth == DEPTH_32_BIT: + return "RGBA32" + elif fmt == FMT_CI: + if depth == DEPTH_4_BIT: + return "CI4" + elif depth == DEPTH_8_BIT: + return "CI8" + elif fmt == FMT_IA: + if depth == DEPTH_4_BIT: + return "IA4" + elif depth == DEPTH_8_BIT: + return "IA8" + elif depth == DEPTH_16_BIT: + return "IA16" + elif fmt == FMT_I: + if depth == DEPTH_4_BIT: + return "I4" + elif depth == DEPTH_8_BIT: + return "I8" + else: + raise Exception(f"Invalid format/depth pair: {fmt} and {depth}") + + +def get_format_code(name): + # get image from bytes for valid combinations of fmt and bit depth + if name == "RGBA16": + return (FMT_RGBA, DEPTH_16_BIT) + elif name == "RGBA32": + return (FMT_RGBA, DEPTH_32_BIT) + elif name == "CI4": + return (FMT_CI, DEPTH_4_BIT) + elif name == "CI8": + return (FMT_CI, DEPTH_8_BIT) + elif name == "IA4": + return (FMT_IA, DEPTH_4_BIT) + elif name == "IA8": + return (FMT_IA, DEPTH_8_BIT) + elif name == "IA16": + return (FMT_IA, DEPTH_16_BIT) + elif name == "I4": + return (FMT_I, DEPTH_4_BIT) + elif name == "I8": + return (FMT_I, DEPTH_8_BIT) + else: + raise Exception(f"Invalid format: {name}") + + +# class for reading a tex file buffer one chunk at a time +@dataclass +class TexBuffer: + data: bytes + pos: int = 0 + + @property + def capacity(self): + return len(self.data) + + def get(self, count): + amt = int(min(count, self.capacity - self.pos)) + ret = self.data[self.pos : self.pos + amt] + self.pos += amt + return ret + + def remaining(self): + return self.capacity - self.pos + + +class TexImage: + # utility function for unpacking aux/main property pairs from a single byte + def split_byte(self, byte): + return (byte >> 4 & 0xF), (byte & 0xF) + + # utility function for unpacking aux/main property pairs from a single byte + def pack_byte(self, aux, main): + return ((aux & 0xF) << 4) | (main & 0xF) + + # get n64img object from the buffer + def get_n64_img(self, texbuf: TexBuffer, fmt, depth, w, h): + # calculate size for bit depth + if depth == DEPTH_4_BIT: + size = w * h // 2 + elif depth == DEPTH_8_BIT: + size = w * h + elif depth == DEPTH_16_BIT: + size = w * h * 2 + elif depth == DEPTH_32_BIT: + size = w * h * 4 + else: + raise Exception(f"Invalid bit depth: {depth}") + + bytes = texbuf.get(size) + + # get image from bytes for valid combinations of fmt and bit depth + fmt_name = get_format_name(fmt, depth) + if fmt_name == "RGBA16": + img = n64img.image.RGBA16(data=bytes, width=w, height=h) + elif fmt_name == "RGBA32": + img = n64img.image.RGBA32(data=bytes, width=w, height=h) + elif fmt_name == "CI4": + img = n64img.image.CI4(data=bytes, width=w, height=h) + elif fmt_name == "CI8": + img = n64img.image.CI8(data=bytes, width=w, height=h) + elif fmt_name == "IA4": + img = n64img.image.IA4(data=bytes, width=w, height=h) + elif fmt_name == "IA8": + img = n64img.image.IA8(data=bytes, width=w, height=h) + elif fmt_name == "IA16": + img = n64img.image.IA16(data=bytes, width=w, height=h) + elif fmt_name == "I4": + img = n64img.image.I4(data=bytes, width=w, height=h) + elif fmt_name == "I8": + img = n64img.image.I8(data=bytes, width=w, height=h) + else: + raise Exception(f"Invalid format: {fmt_name}") + + img.flip_v = True + return img + + # get palette from the buffer + def get_n64_pal(self, texbuf, fmt, depth): + if fmt == FMT_CI: + if depth == DEPTH_4_BIT: + return parse_palette(texbuf.get(0x20)) + elif depth == DEPTH_8_BIT: + return parse_palette(texbuf.get(0x200)) + + # extract texture properties and rasters from buffer + def from_bytes(self, texbuf: TexBuffer): + # strip area prefix and original extension suffix + raw_name = decode_null_terminated_ascii(texbuf.get(32)) + self.img_name = raw_name[4:-3] + self.raw_ext = raw_name[-3:] + + ( + self.aux_width, + self.main_width, + self.aux_height, + self.main_height, + self.is_variant, + self.extra_tiles, + self.combine_mode, + fmts, + depths, + hwraps, + vwraps, + self.filter_mode, + ) = struct.unpack(">HHHHBBBBBBBB", texbuf.get(16)) + + # unpack upper/lower nibbles for aux/main + (self.aux_fmt, self.main_fmt) = self.split_byte(fmts) + (self.aux_depth, self.main_depth) = self.split_byte(depths) + (self.aux_hwrap, self.main_hwrap) = self.split_byte(hwraps) + (self.aux_vwrap, self.main_vwrap) = self.split_byte(vwraps) + + self.has_mipmaps = False + self.has_aux = False + + # main img only + if self.extra_tiles == TILES_BASIC: + self.main_img = self.get_n64_img( + texbuf, + self.main_fmt, + self.main_depth, + self.main_width, + self.main_height, + ) + if self.main_fmt == FMT_CI: + self.main_img.palette = self.get_n64_pal( + texbuf, self.main_fmt, self.main_depth + ) + # main img + mipmaps + elif self.extra_tiles == TILES_MIPMAPS: + self.has_mipmaps = True + self.main_img = self.get_n64_img( + texbuf, + self.main_fmt, + self.main_depth, + self.main_width, + self.main_height, + ) + # read mipmaps + self.mipmaps = [] + divisor = 2 + if self.main_width >= (32 >> self.main_depth): + while True: + if (self.main_width // divisor) <= 0: + break + mmw = self.main_width // divisor + mmh = self.main_height // divisor + mipmap = self.get_n64_img( + texbuf, self.main_fmt, self.main_depth, mmw, mmh + ) + self.mipmaps.append(mipmap) + + divisor = divisor * 2 + if (self.main_width // divisor) < (16 >> self.main_depth): + break + # read palette and assign to all images + if self.main_fmt == FMT_CI: + shared_pal = self.get_n64_pal(texbuf, self.main_fmt, self.main_depth) + self.main_img.palette = shared_pal + for mipmap in self.mipmaps: + mipmap.palette = shared_pal + + # main + aux (shared attributes) + elif self.extra_tiles == TILES_SHARED_AUX: + self.has_aux = True + self.main_img = self.get_n64_img( + texbuf, + self.main_fmt, + self.main_depth, + self.main_width, + self.main_height // 2, + ) + self.aux_img = self.get_n64_img( + texbuf, + self.main_fmt, + self.main_depth, + self.main_width, + self.main_height // 2, + ) + if self.main_fmt == FMT_CI: + shared_pal = self.get_n64_pal(texbuf, self.main_fmt, self.main_depth) + self.main_img.palette = shared_pal + self.aux_img.palette = shared_pal + + # main + aux (independent attributes) + elif self.extra_tiles == TILES_INDEPENDENT_AUX: + self.has_aux = True + # read main + self.main_img = self.get_n64_img( + texbuf, + self.main_fmt, + self.main_depth, + self.main_width, + self.main_height, + ) + if self.main_fmt == FMT_CI: + pal = self.get_n64_pal(texbuf, self.main_fmt, self.main_depth) + self.main_img.palette = pal + # read aux + self.aux_img = self.get_n64_img( + texbuf, self.aux_fmt, self.aux_depth, self.aux_width, self.aux_height + ) + if self.aux_fmt == FMT_CI: + self.aux_img.palette = self.get_n64_pal( + texbuf, self.aux_fmt, self.aux_depth + ) + + # constructs a dictionary entry for the tex archive for this texture + def get_json_entry(self): + out = {} + out["name"] = self.img_name + + # only a single texture in 'tst_tex' has 'rgb', otherwise this is always 'tif' + if self.raw_ext != "tif": + out["ext"] = self.raw_ext + + out["main"] = { + "format": get_format_name(self.main_fmt, self.main_depth), + "hwrap": wrap_modes.get(self.main_hwrap), + "vwrap": wrap_modes.get(self.main_vwrap), + } + + if self.has_aux: + if self.extra_tiles == TILES_SHARED_AUX: + out["aux"] = { + "format": "Shared", + "hwrap": wrap_modes.get(self.aux_hwrap), + "vwrap": wrap_modes.get(self.aux_vwrap), + } + else: + out["aux"] = { + "format": get_format_name(self.aux_fmt, self.aux_depth), + "hwrap": wrap_modes.get(self.aux_hwrap), + "vwrap": wrap_modes.get(self.aux_vwrap), + } + + if self.has_mipmaps: + out["hasMipmaps"] = True + + if self.filter_mode == 2: + out["filter"] = True + + out["combine"] = aux_combine_modes.get(self.combine_mode) + + if self.is_variant: + out["variant"] = True + + return out + + def save_images(self, tex_path): + self.main_img.write(tex_path / f"{self.img_name}.png") + if self.has_aux: + self.aux_img.write(tex_path / f"{self.img_name}_AUX.png") + if self.has_mipmaps: + for idx, mipmap in enumerate(self.mipmaps): + mipmap.write(tex_path / f"{self.img_name}_MM{idx + 1}.png") + + def read_json_img(self, img_data, tile_name, img_name): + fmt_str = img_data.get("format") + if fmt_str == None: + raise Exception(f"Texture {img_name} is missing 'format' for '{tile_name}'") + + hwrap_str = img_data.get("hwrap", "Missing") + hwrap = wrap_modes_inv.get(hwrap_str) + if hwrap == None: + raise Exception(f"Texture {img_name} has invalid 'hwrap' for '{tile_name}'") + + vwrap_str = img_data.get("vwrap", "Missing") + vwrap = wrap_modes_inv.get(vwrap_str) + if vwrap == None: + raise Exception(f"Texture {img_name} has invalid 'vwrap' for '{tile_name}'") + + return fmt_str, hwrap, vwrap + + def get_img_file(self, fmt_str, img_file): + (out_img, out_w, out_h) = Converter( + mode=fmt_str.lower(), infile=img_file, flip_y=True + ).convert() + + out_pal = bytearray() + if fmt_str == "CI4" or fmt_str == "CI8": + img = png.Reader(img_file) + img.preamble(True) + palette = img.palette(alpha="force") + for rgba in palette: + if rgba[3] not in (0, 0xFF): + self.warn("alpha mask mode but translucent pixels used") + + color = pack_color(*rgba) + out_pal += color.to_bytes(2, byteorder="big") + + return (out_img, out_pal, out_w, out_h) + + # read texture properties from dictionary and load images + def from_json(self, tex_path: Path, json_data): + self.img_name = json_data["name"] + + if "ext" in json_data: + self.raw_ext = json_data["ext"] + else: + self.raw_ext = "tif" + + # read data for main tile + main_data = json_data.get("main") + if main_data == None: + raise Exception(f"Texture {self.img_name} has no definition for 'main'") + + (main_fmt_name, self.main_hwrap, self.main_vwrap) = self.read_json_img( + main_data, "main", self.img_name + ) + (self.main_fmt, self.main_depth) = get_format_code(main_fmt_name) + + # read main image + img_path = str(tex_path / f"{self.img_name}.png") + if not os.path.isfile(img_path): + raise Exception(f"Could not find main image for texture: {self.img_name}") + ( + self.main_img, + self.main_pal, + self.main_width, + self.main_height, + ) = self.get_img_file(main_fmt_name, img_path) + + # read data for aux tile + self.has_aux = "aux" in json_data + if self.has_aux: + aux_data = json_data.get("aux") + (aux_fmt_name, self.aux_hwrap, self.aux_vwrap) = self.read_json_img( + aux_data, "aux", self.img_name + ) + + if aux_fmt_name == "Shared": + # aux tiles have blank attributes in SHARED mode + aux_fmt_name = main_fmt_name + self.aux_fmt = 0 + self.aux_depth = 0 + self.aux_hwrap = 0 + self.aux_vwrap = 0 + self.extra_tiles = TILES_SHARED_AUX + else: + (self.aux_fmt, self.aux_depth) = get_format_code(aux_fmt_name) + self.extra_tiles = TILES_INDEPENDENT_AUX + + # read aux image + img_path = str(tex_path / f"{self.img_name}_AUX.png") + if not os.path.isfile(img_path): + raise Exception( + f"Could not find AUX image for texture: {self.img_name}" + ) + ( + self.aux_img, + self.aux_pal, + self.aux_width, + self.aux_height, + ) = self.get_img_file(aux_fmt_name, img_path) + if self.extra_tiles == TILES_SHARED_AUX: + # aux tiles have blank sizes in SHARED mode + self.main_height *= 2 + self.aux_width = 0 + self.aux_height = 0 + + else: + self.aux_fmt = 0 + self.aux_depth = 0 + self.aux_hwrap = 0 + self.aux_vwrap = 0 + self.aux_width = 0 + self.aux_height = 0 + self.extra_tiles = TILES_BASIC + + # read mipmaps + self.has_mipmaps = json_data.get("hasMipmaps", False) + if self.has_mipmaps: + self.mipmaps = [] + mipmap_idx = 1 + divisor = 2 + if self.main_width >= (32 >> self.main_depth): + while True: + if (self.main_width // divisor) <= 0: + break + mmw = self.main_width // divisor + mmh = self.main_height // divisor + + img_path = str(tex_path / f"{self.img_name}_MM{mipmap_idx}.png") + if not os.path.isfile(img_path): + raise Exception( + f"Texture {self.img_name} is missing mipmap level {mipmap_idx} (size = {mmw} x {mmh})" + ) + + (raster, pal, width, height) = self.get_img_file( + main_fmt_name, img_path + ) + self.mipmaps.append(raster) + if width != mmw or height != mmh: + raise Exception( + f"Texture {self.img_name} has wrong size for mipmap level {mipmap_idx} \n" + + f"MM{mipmap_idx} size = {width} x {height}, but should be = {mmw} x {mmh}" + ) + + divisor = divisor * 2 + mipmap_idx += 1 + if (self.main_width // divisor) < (16 >> self.main_depth): + break + self.extra_tiles = TILES_MIPMAPS + + # read filter mode + if json_data.get("filter", False): + self.filter_mode = 2 + else: + self.filter_mode = 0 + + # read tile combine mode + combine_str = json_data.get("combine", "Missing") + self.combine = aux_combine_modes_inv.get(combine_str) + if self.combine == None: + raise Exception(f"Texture {self.img_name} has invalid 'combine'") + + self.is_variant = json_data.get("variant", False) + + # write texture header and image raster/palettes to byte array + def add_bytes(self, tex_name: str, bytes: bytearray): + # form raw name and write to header + raw_name = tex_name[:4] + self.img_name + self.raw_ext + name_bytes = raw_name.encode("ascii") + bytes += name_bytes + + # pad name out to 32 bytes + pad_len = 32 - len(name_bytes) + assert pad_len > 0 + bytes += b"\0" * pad_len + + # write header fields + bytes += struct.pack( + ">HHHHBBBBBBBB", + self.aux_width, + self.main_width, + self.aux_height, + self.main_height, + self.is_variant, + self.extra_tiles, + self.combine, + self.pack_byte(self.aux_fmt, self.main_fmt), + self.pack_byte(self.aux_depth, self.main_depth), + self.pack_byte(self.aux_hwrap, self.main_hwrap), + self.pack_byte(self.aux_vwrap, self.main_vwrap), + self.filter_mode, + ) + + # write rasters and palettes + if self.extra_tiles == TILES_BASIC: + bytes += self.main_img + if self.main_fmt == FMT_CI: + bytes += self.main_pal + elif self.extra_tiles == TILES_MIPMAPS: + bytes += self.main_img + for mipmap in self.mipmaps: + bytes += mipmap + if self.main_fmt == FMT_CI: + bytes += self.main_pal + elif self.extra_tiles == TILES_SHARED_AUX: + bytes += self.main_img + bytes += self.aux_img + if self.main_fmt == FMT_CI: + bytes += self.main_pal + elif self.extra_tiles == TILES_INDEPENDENT_AUX: + bytes += self.main_img + if self.main_fmt == FMT_CI: + bytes += self.main_pal + bytes += self.aux_img + if self.aux_fmt == FMT_CI: + bytes += self.aux_pal + + +class TexArchive: + @staticmethod + def extract(bytes, tex_path: Path): + textures = [] + texbuf = TexBuffer(bytes) + + while texbuf.remaining() > 0: + img = TexImage() + img.from_bytes(texbuf) + textures.append(img) + + tex_path.mkdir(parents=True, exist_ok=True) + + out = [] + for texture in textures: + texture.save_images(tex_path) + out.append(texture.get_json_entry()) + + json_out = json.dumps(out, sort_keys=False, indent=4) + + json_fn = str(tex_path) + ".json" + with open(json_fn, "w") as f: + f.write(json_out) + + @staticmethod + def build(out_path: Path, tex_path: Path, endian: str = "big"): + out_bytes = bytearray() + tex_name = os.path.basename(tex_path) + + json_fn = str(tex_path) + ".json" + with open(json_fn, "r") as json_file: + json_str = json_file.read() + json_data = json.loads(json_str) + + if len(json_data) > 128: + raise Exception( + f"Maximum number of textures (128) exceeded by {tex_name} ({len(json_data)})`" + ) + + for img_data in json_data: + img = TexImage() + img.from_json(tex_path, img_data) + img.add_bytes(tex_name, out_bytes) + + with open(out_path, "wb") as out_bin: + out_bin.write(out_bytes) diff --git a/ver/ique/asm/bss3.s b/ver/ique/asm/bss3.s index d479a321b9..f4ec03c395 100644 --- a/ver/ique/asm/bss3.s +++ b/ver/ique/asm/bss3.s @@ -106,7 +106,7 @@ dlabel entity_numShadows dlabel gSpriteShadingProfile .space 4 -dlabel entity_area_specific_data_is_loaded +dlabel isAreaSpecificEntityDataLoaded .space 4 dlabel entity_updateCounter @@ -178,7 +178,7 @@ dlabel D_801516FC dlabel gMainGameState .space 0x00000040 -dlabel gCurrentTileDescriptor +dlabel gCurrentTextureHeader .space 0x00000030 dlabel wModelList @@ -268,7 +268,7 @@ dlabel texPannerAuxU dlabel texPannerAuxV .space 0x00000040 -dlabel mdl_nextTextureAddress +dlabel TextureHeapPos .space 4 dlabel mdl_currentTransformGroupChildIndex diff --git a/ver/ique/splat.yaml b/ver/ique/splat.yaml index 076696bc7c..37e641ef2b 100644 --- a/ver/ique/splat.yaml +++ b/ver/ique/splat.yaml @@ -401,7 +401,9 @@ segments: vram: 0x8010dab0 subsegments: - [0xA4990, hasm, bss3] - - [0xA4990, c, a5dd0_len_114e0] + - [0xA4990, c, entity] + - [auto, c, game_states] + - [auto, c, model] - [0xB3140, c, B4580] - [0xB5E70, c, entity_model] - [0xB8370, c, worker] @@ -419,7 +421,9 @@ segments: - [0xDD6B0, c, sprite_shading] - [0xDE8C0, c, audio/sfx] - [0xDFAA0, c, audio/e0b30_len_b80] - - [0xE0620, .data, a5dd0_len_114e0] + - [0xE0620, .data, entity] + - [auto, .data, game_states] + - [auto, .data, model] - [0xE18C0, .data, B4580] - [0xE18D0, .data, entity_model] - [0xE18F0, .data, msg] diff --git a/ver/jp/undefined_syms.txt b/ver/jp/undefined_syms.txt index 77a7b09a93..7c88d825a5 100644 --- a/ver/jp/undefined_syms.txt +++ b/ver/jp/undefined_syms.txt @@ -176,7 +176,7 @@ game_mode_set_fpDrawAuxUI = 0x80117F94; step_current_game_mode = 0x80118088; state_render_backUI = 0x80118168; state_render_frontUI = 0x801181D4; -load_model_textures = 0x8011AE34; +mdl_load_all_textures = 0x8011AE34; clear_model_data = 0x8011AF54; init_model_data = 0x8011B1F8; calculate_model_sizes = 0x8011B33C; diff --git a/ver/pal/asm/nonmatchings/world/area_hos/hos_05/hos_05_5_intro/AnimBowser_FlyOff.s b/ver/pal/asm/nonmatchings/world/area_hos/hos_05/hos_05_5_intro/AnimBowser_FlyOff.s deleted file mode 100644 index 3362bb6745..0000000000 --- a/ver/pal/asm/nonmatchings/world/area_hos/hos_05/hos_05_5_intro/AnimBowser_FlyOff.s +++ /dev/null @@ -1,70 +0,0 @@ -.set noat /* allow manual use of $at */ -.set noreorder /* don't insert nops after branches */ - -/* Generated by spimdisasm 1.11.1 */ - -glabel hos_05_AnimBowser_FlyOff -/* A9A8B4 80244774 27BDFFD0 */ addiu $sp, $sp, -0x30 -/* A9A8B8 80244778 AFB00018 */ sw $s0, 0x18($sp) -/* A9A8BC 8024477C 0080802D */ daddu $s0, $a0, $zero -/* A9A8C0 80244780 AFB1001C */ sw $s1, 0x1C($sp) -/* A9A8C4 80244784 00A0882D */ daddu $s1, $a1, $zero -/* A9A8C8 80244788 24050007 */ addiu $a1, $zero, 0x7 -/* A9A8CC 8024478C AFBF0028 */ sw $ra, 0x28($sp) -/* A9A8D0 80244790 AFB30024 */ sw $s3, 0x24($sp) -/* A9A8D4 80244794 0C0B42B0 */ jal resolve_npc -/* A9A8D8 80244798 AFB20020 */ sw $s2, 0x20($sp) -/* A9A8DC 8024479C 0200202D */ daddu $a0, $s0, $zero -/* A9A8E0 802447A0 24050008 */ addiu $a1, $zero, 0x8 -/* A9A8E4 802447A4 0C0B42B0 */ jal resolve_npc -/* A9A8E8 802447A8 0040902D */ daddu $s2, $v0, $zero -/* A9A8EC 802447AC 12200004 */ beqz $s1, .LPAL_802447C0 -/* A9A8F0 802447B0 0040982D */ daddu $s3, $v0, $zero -/* A9A8F4 802447B4 C640003C */ lwc1 $f0, 0x3C($s2) -/* A9A8F8 802447B8 3C018025 */ lui $at, %hi(hos_05_AnimBowser_FlyOff_InitialY) -/* A9A8FC 802447BC E420F314 */ swc1 $f0, %lo(hos_05_AnimBowser_FlyOff_InitialY)($at) -.LPAL_802447C0: -/* A9A900 802447C0 3C018025 */ lui $at, %hi(hos_05_AnimBowser_FlyOff_InitialY) -/* A9A904 802447C4 C420F314 */ lwc1 $f0, %lo(hos_05_AnimBowser_FlyOff_InitialY)($at) -/* A9A908 802447C8 24040003 */ addiu $a0, $zero, 0x3 -/* A9A90C 802447CC 44050000 */ mfc1 $a1, $f0 -/* A9A910 802447D0 3C0143FA */ lui $at, (0x43FA0000 >> 16) -/* A9A914 802447D4 44810000 */ mtc1 $at, $f0 -/* A9A918 802447D8 44853000 */ mtc1 $a1, $f6 -/* A9A91C 802447DC 3C108025 */ lui $s0, %hi(hos_05_AnimBowser_FlyOff_Time) -/* A9A920 802447E0 2610AE70 */ addiu $s0, $s0, %lo(hos_05_AnimBowser_FlyOff_Time) -/* A9A924 802447E4 46003180 */ add.s $f6, $f6, $f0 -/* A9A928 802447E8 3C014220 */ lui $at, (0x42200000 >> 16) -/* A9A92C 802447EC 44811000 */ mtc1 $at, $f2 -/* A9A930 802447F0 8E070000 */ lw $a3, 0x0($s0) -/* A9A934 802447F4 44063000 */ mfc1 $a2, $f6 -/* A9A938 802447F8 2642003C */ addiu $v0, $s2, 0x3C -/* A9A93C 802447FC AFA20014 */ sw $v0, 0x14($sp) -/* A9A940 80244800 0C090439 */ jal interp_value_with_easing -/* A9A944 80244804 E7A20010 */ swc1 $f2, 0x10($sp) -/* A9A948 80244808 C640003C */ lwc1 $f0, 0x3C($s2) -/* A9A94C 8024480C 3C013F80 */ lui $at, (0x3F800000 >> 16) -/* A9A950 80244810 44811000 */ mtc1 $at, $f2 -/* A9A954 80244814 E660003C */ swc1 $f0, 0x3C($s3) -/* A9A958 80244818 C6000000 */ lwc1 $f0, 0x0($s0) -/* A9A95C 8024481C C644003C */ lwc1 $f4, 0x3C($s2) -/* A9A960 80244820 46020000 */ add.s $f0, $f0, $f2 -/* A9A964 80244824 E6440070 */ swc1 $f4, 0x70($s2) -/* A9A968 80244828 C662003C */ lwc1 $f2, 0x3C($s3) -/* A9A96C 8024482C 3C014204 */ lui $at, (0x42040000 >> 16) -/* A9A970 80244830 44812000 */ mtc1 $at, $f4 -/* A9A974 80244834 24020001 */ addiu $v0, $zero, 0x1 -/* A9A978 80244838 E6620070 */ swc1 $f2, 0x70($s3) -/* A9A97C 8024483C 4600203C */ c.lt.s $f4, $f0 -/* A9A980 80244840 00000000 */ nop -/* A9A984 80244844 45010002 */ bc1t .LPAL_80244850 -/* A9A988 80244848 E6000000 */ swc1 $f0, 0x0($s0) -/* A9A98C 8024484C 0000102D */ daddu $v0, $zero, $zero -.LPAL_80244850: -/* A9A990 80244850 8FBF0028 */ lw $ra, 0x28($sp) -/* A9A994 80244854 8FB30024 */ lw $s3, 0x24($sp) -/* A9A998 80244858 8FB20020 */ lw $s2, 0x20($sp) -/* A9A99C 8024485C 8FB1001C */ lw $s1, 0x1C($sp) -/* A9A9A0 80244860 8FB00018 */ lw $s0, 0x18($sp) -/* A9A9A4 80244864 03E00008 */ jr $ra -/* A9A9A8 80244868 27BD0030 */ addiu $sp, $sp, 0x30 diff --git a/ver/pal/asm/nonmatchings/world/area_hos/hos_05/hos_05_5_intro/AnimKammy_FlyOff.s b/ver/pal/asm/nonmatchings/world/area_hos/hos_05/hos_05_5_intro/AnimKammy_FlyOff.s deleted file mode 100644 index 9f026e1771..0000000000 --- a/ver/pal/asm/nonmatchings/world/area_hos/hos_05/hos_05_5_intro/AnimKammy_FlyOff.s +++ /dev/null @@ -1,57 +0,0 @@ -.set noat /* allow manual use of $at */ -.set noreorder /* don't insert nops after branches */ - -/* Generated by spimdisasm 1.11.1 */ - -glabel hos_05_AnimKammy_FlyOff -/* A9A9AC 8024486C 27BDFFD8 */ addiu $sp, $sp, -0x28 -/* A9A9B0 80244870 AFB00018 */ sw $s0, 0x18($sp) -/* A9A9B4 80244874 00A0802D */ daddu $s0, $a1, $zero -/* A9A9B8 80244878 24050009 */ addiu $a1, $zero, 0x9 -/* A9A9BC 8024487C AFBF0020 */ sw $ra, 0x20($sp) -/* A9A9C0 80244880 0C0B42B0 */ jal resolve_npc -/* A9A9C4 80244884 AFB1001C */ sw $s1, 0x1C($sp) -/* A9A9C8 80244888 12000004 */ beqz $s0, .LPAL_8024489C -/* A9A9CC 8024488C 0040882D */ daddu $s1, $v0, $zero -/* A9A9D0 80244890 C620003C */ lwc1 $f0, 0x3C($s1) -/* A9A9D4 80244894 3C018025 */ lui $at, %hi(hos_05_AnimKammy_FlyOff_InitialY) -/* A9A9D8 80244898 E420F318 */ swc1 $f0, %lo(hos_05_AnimKammy_FlyOff_InitialY)($at) -.LPAL_8024489C: -/* A9A9DC 8024489C 3C018025 */ lui $at, %hi(hos_05_AnimKammy_FlyOff_InitialY) -/* A9A9E0 802448A0 C420F318 */ lwc1 $f0, %lo(hos_05_AnimKammy_FlyOff_InitialY)($at) -/* A9A9E4 802448A4 24040003 */ addiu $a0, $zero, 0x3 -/* A9A9E8 802448A8 44050000 */ mfc1 $a1, $f0 -/* A9A9EC 802448AC 3C0143FA */ lui $at, (0x43FA0000 >> 16) -/* A9A9F0 802448B0 44810000 */ mtc1 $at, $f0 -/* A9A9F4 802448B4 44853000 */ mtc1 $a1, $f6 -/* A9A9F8 802448B8 3C108025 */ lui $s0, %hi(hos_05_AnimKammy_FlyOff_Time) -/* A9A9FC 802448BC 2610AE74 */ addiu $s0, $s0, %lo(hos_05_AnimKammy_FlyOff_Time) -/* A9AA00 802448C0 46003180 */ add.s $f6, $f6, $f0 -/* A9AA04 802448C4 3C014220 */ lui $at, (0x42200000 >> 16) -/* A9AA08 802448C8 44811000 */ mtc1 $at, $f2 -/* A9AA0C 802448CC 8E070000 */ lw $a3, 0x0($s0) -/* A9AA10 802448D0 44063000 */ mfc1 $a2, $f6 -/* A9AA14 802448D4 2622003C */ addiu $v0, $s1, 0x3C -/* A9AA18 802448D8 AFA20014 */ sw $v0, 0x14($sp) -/* A9AA1C 802448DC 0C090439 */ jal interp_value_with_easing -/* A9AA20 802448E0 E7A20010 */ swc1 $f2, 0x10($sp) -/* A9AA24 802448E4 C6020000 */ lwc1 $f2, 0x0($s0) -/* A9AA28 802448E8 3C013F80 */ lui $at, (0x3F800000 >> 16) -/* A9AA2C 802448EC 44810000 */ mtc1 $at, $f0 -/* A9AA30 802448F0 3C014204 */ lui $at, (0x42040000 >> 16) -/* A9AA34 802448F4 44812000 */ mtc1 $at, $f4 -/* A9AA38 802448F8 46001080 */ add.s $f2, $f2, $f0 -/* A9AA3C 802448FC C620003C */ lwc1 $f0, 0x3C($s1) -/* A9AA40 80244900 24020001 */ addiu $v0, $zero, 0x1 -/* A9AA44 80244904 E6200070 */ swc1 $f0, 0x70($s1) -/* A9AA48 80244908 4602203C */ c.lt.s $f4, $f2 -/* A9AA4C 8024490C 00000000 */ nop -/* A9AA50 80244910 45010002 */ bc1t .LPAL_8024491C -/* A9AA54 80244914 E6020000 */ swc1 $f2, 0x0($s0) -/* A9AA58 80244918 0000102D */ daddu $v0, $zero, $zero -.LPAL_8024491C: -/* A9AA5C 8024491C 8FBF0020 */ lw $ra, 0x20($sp) -/* A9AA60 80244920 8FB1001C */ lw $s1, 0x1C($sp) -/* A9AA64 80244924 8FB00018 */ lw $s0, 0x18($sp) -/* A9AA68 80244928 03E00008 */ jr $ra -/* A9AA6C 8024492C 27BD0028 */ addiu $sp, $sp, 0x28 diff --git a/ver/us/asm/bss3.s b/ver/us/asm/bss3.s index 3dc9d3f079..50ec1bebc0 100644 --- a/ver/us/asm/bss3.s +++ b/ver/us/asm/bss3.s @@ -106,7 +106,7 @@ dlabel entity_numShadows dlabel gSpriteShadingProfile .space 4 -dlabel entity_area_specific_data_is_loaded +dlabel isAreaSpecificEntityDataLoaded .space 4 dlabel entity_updateCounter @@ -178,7 +178,7 @@ dlabel D_801516FC dlabel gMainGameState .space 0x00000040 -dlabel gCurrentTileDescriptor +dlabel gCurrentTextureHeader .space 0x00000030 dlabel wModelList @@ -268,7 +268,7 @@ dlabel texPannerAuxU dlabel texPannerAuxV .space 0x00000040 -dlabel mdl_nextTextureAddress +dlabel TextureHeapPos .space 4 dlabel mdl_currentTransformGroupChildIndex diff --git a/ver/us/splat.yaml b/ver/us/splat.yaml index 12eddd7579..4e347d5116 100644 --- a/ver/us/splat.yaml +++ b/ver/us/splat.yaml @@ -824,7 +824,9 @@ segments: follows_vram: engine1 subsegments: - [0xA5DD0, hasm, bss3] - - [0xA5DD0, c, a5dd0_len_114e0] + - [0xA5DD0, c, entity] + - [0xA9290, c, game_states] + - [0xA9790, c, model] - [0xB4580, c, B4580] - [0xB72B0, c, entity_model] - [0xB97B0, c, worker] @@ -842,7 +844,9 @@ segments: - [0xDE740, c, sprite_shading] - [0xDF950, c, audio/sfx] - [0xE0B30, c, audio/e0b30_len_b80] - - [0xE16B0, .data, a5dd0_len_114e0] + - [0xE16B0, .data, entity] + - [0xE16C0, .data, game_states] + - [0xE16C0, .data, model] - [0xE2950, .data, B4580] - [0xE2960, .data, entity_model] - [0xE2980, .data, msg] diff --git a/ver/us/symbol_addrs.txt b/ver/us/symbol_addrs.txt index 45e0adee73..d18b309423 100644 --- a/ver/us/symbol_addrs.txt +++ b/ver/us/symbol_addrs.txt @@ -3998,12 +3998,12 @@ state_do_unk = 0x80112EEC; // type:func rom:0xA95EC state_render_backUI = 0x80112F58; // type:func rom:0xA9658 state_render_frontUI = 0x80112FC4; // type:func rom:0xA96C4 appendGfx_model = 0x80113090; // type:func rom:0xA9790 -func_80114B58 = 0x80114B58; // type:func rom:0xAB258 -load_tile_header = 0x80114D6C; // type:func rom:0xAB46C -func_80115498 = 0x80115498; // type:func rom:0xABB98 +load_texture_impl = 0x80114B58; // type:func rom:0xAB258 +load_texture_by_name = 0x80114D6C; // type:func rom:0xAB46C +load_texture_variants = 0x80115498; // type:func rom:0xABB98 get_model_property = 0x80115B0C; // type:func rom:0xAC20C -_load_model_textures = 0x80115B44; // type:func rom:0xAC244 -load_model_textures = 0x80115C24; // type:func rom:0xAC324 +load_next_model_textures = 0x80115B44; // type:func rom:0xAC244 +mdl_load_all_textures = 0x80115C24; // type:func rom:0xAC324 mdl_get_child_count = 0x80115CA8; // type:func rom:0xAC3A8 clear_model_data = 0x80115D44; // type:func rom:0xAC444 init_model_data = 0x80115FE8; // type:func rom:0xAC6E8 @@ -4016,7 +4016,7 @@ appendGfx_model_group = 0x80117C94; // type:func rom:0xAE394 func_80117D00 = 0x80117D00; // type:func rom:0xAE400 render_transform_group_node = 0x80117E74; // type:func rom:0xAE574 render_transform_group = 0x8011800C; // type:func rom:0xAE70C -func_801180E8 = 0x801180E8; // type:func rom:0xAE7E8 +make_texture_gfx = 0x801180E8; // type:func rom:0xAE7E8 get_model_from_list_index = 0x8011AD30; // type:func rom:0xB1430 load_data_for_models = 0x8011AD48; // type:func rom:0xB1448 load_model_transforms = 0x8011ADC8; // type:func rom:0xB14C8 @@ -4493,7 +4493,7 @@ D_8014B0B8 = 0x8014B0B8; // rom:0xE17B8 D_8014B0BC = 0x8014B0BC; // rom:0xE17BC D_8014B400 = 0x8014B400; // rom:0xE1B00 D_8014B404 = 0x8014B404; // rom:0xE1B04 -mdl_textureBaseAddress = 0x8014B748; // rom:0xE1E48 +TextureHeapBase = 0x8014B748; // rom:0xE1E48 mdl_bgMultiplyColorA = 0x8014B74C; // rom:0xE1E4C mdl_bgMultiplyColorR = 0x8014B74D; // rom:0xE1E4D mdl_bgMultiplyColorG = 0x8014B74E; // rom:0xE1E4E