#include "trig.h" #include "validate.h" #include "mem.h" #include "utils.h" #include "spidey.h" #include "baddy.h" #include "spool.h" #include "exp.h" EXPORT void* gTrigFile; EXPORT i16 **gTrigNodes; EXPORT i32 NumNodes; const i32 MAXPENDING = 16; EXPORT PendingListEntry PendingListArray[MAXPENDING]; EXPORT SCommandPoint* CommandPoints; EXPORT SCommandPoint* HashTable[256]; static int gTrigMenu[40]; static int gRestartPoints; EXPORT i32 Restart; EXPORT i32 RestartNode; EXPORT i32 gReStartDeathRelated; EXPORT i32 EndLevelNode; extern CSpecialDisplay *SpecialDisplayList; extern i32 JoelJewCheatCode; extern CPlayer* MechList; extern CBaddy* ControlBaddyList; extern CBaddy* BaddyList; extern CBody* EnvironmentalObjectList; extern CBody* PowerUpList; //@IGNORE void trigLog(const char*, ...) { printf("trigLog!"); } // @NotOk // SpecialDisplayList shitty ass polymorphism // need to understand what's type 9 void SendKillFromNode(i32 Node, i32 How) { print_if_false(Node >= 0 && Node < NumNodes, "Bad node sent to SendKillFromNode"); u16 *pLinkInfo = Trig_GetLinksPointer(Node); u16 NumLinks = *pLinkInfo; u16* nodeIndexPtr = pLinkInfo + 1; for (i32 i = 0; i < NumLinks; i++) { u16 nodeIndex = nodeIndexPtr[i]; i16 *node = reinterpret_cast(gTrigNodes[nodeIndex]); switch (*node) { case 1: if (node[1] == 409) { for ( CSpecialDisplay *cur = SpecialDisplayList; cur; cur = reinterpret_cast(cur->mNext)) { if (cur->mType == 9) { if (*reinterpret_cast(reinterpret_cast(cur)+0x6A) == nodeIndex) { cur->Die(); } } } } else { KillInList(nodeIndex, BaddyList, How); KillInList(nodeIndex, ControlBaddyList, How); KillInList(nodeIndex, EnvironmentalObjectList, How); } break; case 2: case 9: u32 v20; CItem* EnviroItem; v20 = reinterpret_cast(&node[node[1] + 2]); if (v20 & 2) v20 += 2; EnviroItem = Spool_FindEnviroItem(v20); if (EnviroItem) { if (How == 1) { Exp_HitEnvItem(EnviroItem, 0, 0xFFFF); } else { EnviroItem->mFlags |= 1; } } break; case 4: case 20: KillInList(nodeIndex, PowerUpList, How); break; default: break; } } } // @Ok void SendSuspendOrActivate(u16* pLinkInfo, i32 signalType) { switch(signalType) { case 4: case 5: break; default: print_if_false(0, "Bad signalType"); break; } print_if_false(*pLinkInfo !=0, "Node sending an activate or \n suspen is not lined\n to anything"); u16 numIters = *pLinkInfo; u16* nodeIndexPtr = pLinkInfo + 1; for (i32 i = 0; i < numIters; i++) { u16 *node = reinterpret_cast(gTrigNodes[nodeIndexPtr[i]]); switch(*node) { case 1: case 7: if (signalType == 5) { SendSuspend(reinterpret_cast(&BaddyList), nodeIndexPtr[i]); SendSuspend(reinterpret_cast(&ControlBaddyList), nodeIndexPtr[i]); SendSuspend(reinterpret_cast(&EnvironmentalObjectList), nodeIndexPtr[i]); } else { SendUnSuspend(BaddyList, nodeIndexPtr[i]); SendUnSuspend(ControlBaddyList, nodeIndexPtr[i]); SendUnSuspend(EnvironmentalObjectList, nodeIndexPtr[i]); } break; } } } // @Ok void SendUnSuspend(CBody* pList, i32 NodeIndex) { for (CBody* cur = pList; cur; cur = reinterpret_cast(cur->field_20)) { if (cur->field_DE == NodeIndex) cur->UnSuspend(); } } // @Ok void SendSignalToNode(CBody* pBody, i32 NodeIndex) { for (CBody* cur = pBody; cur; cur = reinterpret_cast(cur->field_20)) { if (cur->field_DE == NodeIndex) cur->field_44 |= 1; } } // @Ok INLINE void SendSuspend(CBody** ppList, i32 NodeIndex) { for (CBody* cur = *ppList; cur; cur = reinterpret_cast(cur->field_20)) { if (cur->field_DE == NodeIndex) cur->Suspend(ppList); } } // @Ok void KillInList(i32 Node, CBody* pList, i32 How) { for (CBody *cur = pList; cur; cur = reinterpret_cast(cur->field_20)) { if (cur->field_DE == Node) { switch (How) { case 0: cur->Die(); break; case 1: SHitInfo hitInfo; hitInfo.field_8 = cur->field_E2; hitInfo.field_C.vx = 0; hitInfo.field_C.vy = 0; hitInfo.field_C.vz = 0; hitInfo.field_0 = 4; cur->Hit(&hitInfo); break; } } } } // @BIGTODO void Trig_CreateObject(i32) { printf("Trig_CreateObject"); } // @Ok void Trig_ExecuteAutoexec(void) { print_if_false(gTrigFile != 0, "No trigger file"); EndLevelNode = 0xFFFF; if (JoelJewCheatCode) { for (i32 curNode = 0; curNode < NumNodes; curNode++) { u16 *v5 = reinterpret_cast(gTrigNodes[curNode]); if (*v5 == 15) { trigLog("*** Executing AUTOEXEC2 Node %i ***", curNode); ExecuteCommandList(v5 + 1, curNode, 1); return; } } } for (i32 curNode = 0; curNode < NumNodes; curNode++) { u16 *v5 = reinterpret_cast(gTrigNodes[curNode]); if (*v5 == 4) { trigLog("*** Executing AUTOEXEC Node %i ***", curNode); ExecuteCommandList(v5 + 1, curNode, 1); } } } // @Ok void Trig_ExecuteRestart(void) { print_if_false(RestartNode != 0xFFFF, "Tried to execute a restart with no restart node set"); print_if_false(*gTrigNodes[RestartNode] == 8, "Eh? Restart node isn't a restart node!"); print_if_false(MechList != 0, "Tried to execute a restart with a NULL MechList"); CVector v7; v7.vx = 0; v7.vy = 0; v7.vz = 0; CSVector *Position = reinterpret_cast(Trig_GetPosition(&v7, RestartNode)); MechList->mPos = v7; MechList->SetStartOrientation(Position); char *v3 = reinterpret_cast(&Position[1]); trigLog("*** Executing Restart Node: %s ***", v3); v3 = SkipString(v3); Trig_ZeroPendingList(); ExecuteCommandList(reinterpret_cast(v3), RestartNode, 1); } // @Ok void Trig_SetRestart(char *pName) { RestartNode = 0xFFFF; for (i32 curNode = 0; curNode < NumNodes; curNode++) { if (*gTrigNodes[curNode] == 8) { CVector v3; v3.vx = 0; v3.vy = 0; v3.vz = 0; u16* Position = Trig_GetPosition(&v3, curNode); if (Utils_CompareStrings(reinterpret_cast(&Position[3]), pName)) { RestartNode = curNode; trigLog("Set RestartNode = %i", curNode); if (!Utils_CompareStrings(pName, "re_start_death")) gReStartDeathRelated = 1; return; } } } print_if_false(0, "Restart point "); } // @Ok INLINE char *SkipString(char *pText) { while(*pText) pText++; pText++; return &pText[reinterpret_cast(pText) & 1]; } // @Ok void Trig_DeleteTrigFile(void) { if (gTrigFile) { Mem_Delete(reinterpret_cast(gTrigFile)); gTrigFile = 0; } Restart = 0; Trig_ZeroPendingList(); } // @BIGTODO void ExecuteCommandList(u16*, i32, i32) { printf("ExecuteCommandList"); } // @Ok void Trig_DoPendingCommandLists(void) { for (i32 i = 0; ipNextSimilar) { if (pSearch->Checksum == checksum) { pSearch->Collision = 1; if (!pSearch->Executed) { trigLog("\tCommandPoint Triggered: node %i", pSearch->NodeIndex); Trig_AddCommandListToPending(pSearch->NodeIndex, pSearch->pCommands); pSearch->Executed = 1; return pSearch; } } } return 0; } // @Ok INLINE SCommandPoint* GetCommandPoint(i32 Node) { if (Node != 0xFFF && *gTrigNodes[Node] == 6) { for (SCommandPoint *cur = CommandPoints; cur; cur = cur->pNext) { if (cur->NodeIndex == Node) return cur; } } return 0; } // @Ok SCommandPoint* CreateCommandPoint(u32 checksum, u16 node, u16* pCommands) { SCommandPoint* result = static_cast(DCMem_New(sizeof(SCommandPoint), 0, 1, 0, 1)); result->pNext = CommandPoints; CommandPoints = result; u32 index = (checksum) & 0xFF; result->pNextSimilar = HashTable[index]; HashTable[index] = result; result->Collision = 0; result->Executed = 0; result->NodeIndex = node; result->pCommands = pCommands; result->Checksum = checksum; result->PulsesReceived = 0; result->NumPulsesSet = 0; result->NumPulses = 0; return result; } // @Ok void Trig_DeleteCommandPoints(void) { for (i32 i = 0; i<256; i++) HashTable[i] = 0; for (SCommandPoint *cur = CommandPoints; cur; ) { SCommandPoint *next = cur->pNext; Mem_Delete(reinterpret_cast(cur)); cur = next; } CommandPoints = 0; Trig_ZeroPendingList(); } // @Ok INLINE void Trig_ZeroPendingList(void) { for (i32 i = 0; ipNext) { if (cur->Executed && !cur->Collision) cur->Executed = 0; } } // @Ok void* Trig_GetLinkInfoList( i32 a1, SLinkInfo* pLink, i32 count) { i32 result = 0; u16* linksPtr = reinterpret_cast(Trig_GetLinksPointer(a1)); if (*linksPtr) { u16 *v8 = linksPtr + 1; result = *linksPtr; if (result) { for (i32 i = 0; i(gTrigNodes[*v8]); pLink[i].field_0 = *v8; pLink[i].field_4 = *v11; if (*v11 == 1002) pLink[i].field_8 = v11[1]; else pLink[i].field_8 = 0; pLink[i].field_C = 0; } } } if (result <= count) { return reinterpret_cast(result); } return reinterpret_cast(count); } // @MEDIUMTODO int Trig_GetLevelId(void) { return 0x686868; } // @BIGTODO u16* Trig_GetPosition(CVector*, int) { return reinterpret_cast(0x13072024); } // @Ok INLINE u16* Trig_GetLinksPointer(int node) { print_if_false(node >= 0 && node < NumNodes, "Bad node sent to Trig_GetLinksPointer"); u16* trigNodePtr = reinterpret_cast(gTrigNodes[node]); i32 trigNodeValue = *reinterpret_cast(trigNodePtr); if (trigNodeValue <= 0xD) { if (trigNodeValue < 0xC) { switch (trigNodeValue) { case 1: return reinterpret_cast(trigNodePtr + 3); case 2: case 3: case 6: case 8: case 9: case 10: return reinterpret_cast(trigNodePtr + 1); case 5: return reinterpret_cast(trigNodePtr + 2); default: print_if_false(0, "Unrecognized node type in\n Trig_GetLinksPointer"); print_if_false(0, "Unrecognized node type in\n Trig_GetLinksPointer"); return 0; } } else { return reinterpret_cast(trigNodePtr + 1); } } else if (trigNodeValue <= 0x3E9) { if (trigNodeValue < 0x3E8) { if (trigNodeValue != 0x14) { print_if_false(0, "Unrecognized node type in\n Trig_GetLinksPointer"); print_if_false(0, "Unrecognized node type in\n Trig_GetLinksPointer"); return 0; } return reinterpret_cast(trigNodePtr + 2); } return reinterpret_cast(trigNodePtr + 1); } else if (trigNodeValue != 0x3EA) { print_if_false(0, "Unrecognized node type in\n Trig_GetLinksPointer"); print_if_false(0, "Unrecognized node type in\n Trig_GetLinksPointer"); return 0; } return reinterpret_cast(trigNodePtr + 2); } // @Ok void Trig_SendPulse(u16* pLinkInfo) { u16 NumLinks = pLinkInfo[0]; u16* pLink = &pLinkInfo[1]; for (i32 curLink = 0; curLink < NumLinks; curLink++) { Trig_SendPulseToNode(pLink[curLink]); } } // @Ok void Trig_SendSignalToLinks(u16* pLinkInfo) { print_if_false(*pLinkInfo != 0, "Node sending signal is not linked\n to anything"); u16 NumLinks = *pLinkInfo; u16 *pLink = pLinkInfo+1; for (i32 i = 0; i < NumLinks; i++) { u32 nodeIndex = pLink[i]; switch (*gTrigNodes[nodeIndex]) { case 1: case 7: SendSignalToNode(BaddyList, nodeIndex); SendSignalToNode(ControlBaddyList, nodeIndex); SendSignalToNode(EnvironmentalObjectList, nodeIndex); break; } } } // @Ok void Trig_ClearTrigMenu(void) { for (int i = 0; i<40; i++) { gTrigMenu[i] = 0; } gRestartPoints = 0; } // @Ok unsigned char* SkipFlags(unsigned char* pFlags) { while(*pFlags != 0xFF) pFlags++; return pFlags+1; } // @Ok void Trig_ResetCPCollisionFlags(void) { for(SCommandPoint *cur = CommandPoints; cur; cur = cur->pNext) { cur->Collision = 0; } } // @NotOk // check inline later INLINE u8 GetFlag(unsigned char flag, unsigned char *pFlags) { while (*pFlags != 0xFF) { if (*pFlags == flag) { return 1; } } return 0; } // @Ok void Trig_SendPulseToNode(i32 NodeIndex) { print_if_false(NodeIndex >= 0 && NodeIndex < NumNodes, "Bad node sent to Trig_SendPulseToNode"); trigLog("\tSending pulse to node %i", NodeIndex); SCommandPoint *pCommand; switch(*gTrigNodes[NodeIndex]) { case 1: case 5: case 7: case 20: Trig_CreateObject(NodeIndex); break; case 6: pCommand = GetCommandPoint(NodeIndex); print_if_false(pCommand != 0, "Sent pulse to command point node before command point was created"); pCommand->PulsesReceived++; Trig_AddCommandListToPending(NodeIndex, pCommand->pCommands); break; default: return; } } void validate_SLinkInfo(void) { VALIDATE_SIZE(SLinkInfo, 0x10); VALIDATE(SLinkInfo, field_0, 0x0); VALIDATE(SLinkInfo, field_4, 0x4); VALIDATE(SLinkInfo, field_8, 0x8); VALIDATE(SLinkInfo, field_C, 0xC); } void validate_SCommandPoint(void) { VALIDATE_SIZE(SCommandPoint, 0x18); VALIDATE(SCommandPoint, pCommands, 0x0); VALIDATE(SCommandPoint, Collision, 0x4); VALIDATE(SCommandPoint, Executed, 0x5); VALIDATE(SCommandPoint, NumPulsesSet, 0x6); VALIDATE(SCommandPoint, PulsesReceived, 0x7); VALIDATE(SCommandPoint, NumPulses, 0x8); VALIDATE(SCommandPoint, NodeIndex, 0xA); VALIDATE(SCommandPoint, Checksum, 0xC); VALIDATE(SCommandPoint, pNextSimilar, 0x10); VALIDATE(SCommandPoint, pNext, 0x14); } void validate_PendingListEntry(void) { VALIDATE_SIZE(PendingListEntry, 0x8); VALIDATE(PendingListEntry, NodeIndex, 0x0); VALIDATE(PendingListEntry, field_2, 0x2); VALIDATE(PendingListEntry, pCommands, 0x4); }