papermario/src/trigger.c
Ethan Roseman a865cbdf17
Trigger funcs (#405)
* remove old tools, fix warnings

* almost match si_handle_print_debug_var

* si_goto_end_loop and warnings

* is_trigger_bound and create_trigger

* Cleanup + matching 2 non-matchings

* update_triggers (trigger.c complete)

* fix warnings

* PR comments, m2ctx.py fix
2021-08-29 22:44:17 +09:00

294 lines
8.0 KiB
C

#include "common.h"
void default_trigger_delegate(Trigger* self) {
self->flags.flags |= 2;
}
void clear_trigger_data(void) {
CollisionStatus* collisionStatus = &gCollisionStatus;
s32 i;
if (!gGameStatusPtr->isBattle) {
gCurrentTriggerListPtr = &wTriggerList;
} else {
gCurrentTriggerListPtr = &bTriggerList;
}
for (i = 0; i < ARRAY_COUNT(*gCurrentTriggerListPtr); i++) {
(*gCurrentTriggerListPtr)[i] = NULL;
}
gTriggerCount = 0;
collisionStatus->pushingAgainstWall = -1;
collisionStatus->currentFloor = -1;
collisionStatus->lastTouchedFloor = -1;
collisionStatus->currentCeiling = -1;
collisionStatus->unk_0A = -1;
collisionStatus->unk_0C = -1;
collisionStatus->unk_0E = -1;
collisionStatus->unk_10 = -1;
collisionStatus->currentWall = -1;
collisionStatus->lastWallHammered = -1;
collisionStatus->touchingWallTrigger = 0;
collisionStatus->bombetteExploded = -1;
collisionStatus->bombetteExplosionPos.x = 0.0f;
collisionStatus->bombetteExplosionPos.y = 0.0f;
collisionStatus->bombetteExplosionPos.z = 0.0f;
}
void init_trigger_list(void) {
if (!gGameStatusPtr->isBattle) {
gCurrentTriggerListPtr = &wTriggerList;
} else {
gCurrentTriggerListPtr = &bTriggerList;
}
gTriggerCount = 0;
}
Trigger* create_trigger(TriggerDefinition* def) {
Trigger* ret;
s32 i;
for (i = 0; i < ARRAY_COUNT(*gCurrentTriggerListPtr); i++) {
Trigger* listTrigger = (*gCurrentTriggerListPtr)[i];
if (listTrigger == NULL) {
break;
}
}
ASSERT(i < ARRAY_COUNT(*gCurrentTriggerListPtr));
(*gCurrentTriggerListPtr)[i] = ret = heap_malloc(sizeof(*ret));
gTriggerCount++;
ASSERT(ret != NULL);
ret->flags.flags = def->flags | 1;
ret->params1 = def->colliderIndex;
ret->params2 = def->flagIndex;
ret->unk_28 = def->unk_1C;
ret->unk_2C = def->unk_14;
ret->unk_30 = def->inputArg3;
ret->functionHandler = def->function;
if (ret->functionHandler == NULL) {
ret->functionHandler = default_trigger_delegate;
}
return ret;
}
void update_triggers(void) {
CollisionStatus* collisionStatus = &gCollisionStatus;
Trigger* listTrigger;
s32 i;
collisionStatus->touchingWallTrigger = 0;
for (i = 0; i < ARRAY_COUNT(*gCurrentTriggerListPtr); i++) {
listTrigger = (*gCurrentTriggerListPtr)[i];
if (listTrigger == NULL) {
continue;
}
if (!(listTrigger->flags.flags & 1)) {
continue;
}
if (listTrigger->flags.flags & 0x10) {
listTrigger->flags.flags |= 2;
continue;
}
if (listTrigger->flags.flags & 0x40) {
if (listTrigger->params2 == collisionStatus->currentWall) {
func_800E06C0(1);
}
if (listTrigger->params2 == collisionStatus->pushingAgainstWall) {
func_800E06C0(0);
} else {
continue;
}
}
if (listTrigger->flags.flags & 0x80) {
if (listTrigger->params2 != collisionStatus->currentFloor) {
continue;
}
}
if (listTrigger->flags.flags & 0x80000) {
if (listTrigger->params2 != collisionStatus->floorBelow) {
continue;
}
}
if (listTrigger->flags.flags & 0x100) {
if (listTrigger->params2 == collisionStatus->currentWall) {
collisionStatus->touchingWallTrigger = 1;
}
if ((listTrigger->params2 != collisionStatus->unk_0A) || !phys_can_player_interact()) {
continue;
}
}
if (listTrigger->flags.flags & 0x400) {
if (listTrigger->params2 != collisionStatus->currentWall) {
continue;
}
}
if (listTrigger->flags.flags & 0x200) {
if (listTrigger->params2 != collisionStatus->lastTouchedFloor) {
continue;
}
}
if (listTrigger->flags.flags & 0x800) {
if ((listTrigger->params2 != collisionStatus->currentFloor) ||
!(gGameStatusPtr->pressedButtons & 0x8000) || (gPlayerStatus.flags & 0x2000)) {
continue;
}
}
if (listTrigger->flags.flags & 0x1000) {
if (listTrigger->params2 != collisionStatus->lastWallHammered) {
continue;
}
}
if (listTrigger->flags.flags & 0x40000) {
if (listTrigger->params2 != collisionStatus->currentCeiling) {
continue;
}
}
if (listTrigger->flags.flags & 0x2000) {
if (listTrigger->params2 != collisionStatus->unk_0C) {
continue;
}
}
if (listTrigger->flags.flags & 0x4000) {
if (listTrigger->params2 != collisionStatus->unk_0E) {
continue;
}
}
if (listTrigger->flags.flags & 0x8000) {
if (listTrigger->params2 != collisionStatus->unk_10) {
continue;
}
}
if (listTrigger->flags.flags & 0x100000) {
f32* floats;
f32 dist;
if (collisionStatus->bombetteExploded < 0) {
continue;
}
floats = (f32*)listTrigger->params2;
dist = dist3D(floats[0], floats[1], floats[2],
collisionStatus->bombetteExplosionPos.x, collisionStatus->bombetteExplosionPos.y,
collisionStatus->bombetteExplosionPos.z);
if ((floats[3] * 0.5f) + 50.0f < dist) {
continue;
}
}
if (listTrigger->flags.flags & 0x10000 && get_global_flag(listTrigger->params1) == 0) {
continue;
}
if (listTrigger->flags.flags & 0x20000 && get_area_flag(listTrigger->params1) == 0) {
continue;
}
listTrigger->flags.flags |= 2;
}
for (i = 0; i < ARRAY_COUNT(*gCurrentTriggerListPtr); i++) {
listTrigger = (*gCurrentTriggerListPtr)[i];
if (listTrigger == NULL) {
continue;
}
if (listTrigger->flags.flags & 1) {
if (listTrigger->flags.flags & 2) {
if (listTrigger->functionHandler(listTrigger) == 0) {
listTrigger->flags.flags &= ~2;
}
}
}
}
}
void delete_trigger(Trigger* toDelete) {
s32 i;
for (i = 0; i < ARRAY_COUNT(*gCurrentTriggerListPtr); i++) {
if ((*gCurrentTriggerListPtr)[i] == toDelete) {
break;
}
}
if (i < ARRAY_COUNT(*gCurrentTriggerListPtr)) {
heap_free((*gCurrentTriggerListPtr)[i]);
(*gCurrentTriggerListPtr)[i] = NULL;
}
}
s32 is_trigger_bound(Trigger* trigger, EvtSource* script) {
s32 i;
for (i = 0; i < ARRAY_COUNT(*gCurrentTriggerListPtr); i++) {
Trigger* listTrigger = (*gCurrentTriggerListPtr)[i];
if (listTrigger == NULL || listTrigger == trigger) {
continue;
}
if (listTrigger->flags.flags & 1) {
if (listTrigger->flags.flags & 2) {
if (listTrigger->scriptSource == script) {
return TRUE;
}
}
}
}
return FALSE;
}
Trigger* get_trigger_by_id(s32 triggerID) {
return (*gCurrentTriggerListPtr)[triggerID];
}
/// @returns TRUE if colliderID is bound to an interaction trigger (press A) and the player can use it.
s32 should_collider_allow_interact(s32 colliderID) {
s32 i;
if (!phys_can_player_interact()) {
return FALSE;
}
for (i = 0; i < ARRAY_COUNT(*gCurrentTriggerListPtr); i++) {
Trigger* trigger = (*gCurrentTriggerListPtr)[i];
if (trigger != NULL &&
trigger->unk_30 != 0 &&
trigger->params2 == colliderID &&
trigger->flags.flags & 0x100) {
return TRUE;
}
}
return FALSE;
}