// 231: 130/130 // RB_MakeInstanceReflective // param_1 is BSP result // param_2 is instance void FUN_800abab0(int param_1,int param_2) { ushort uVar1; undefined *puVar2; puVar2 = PTR_DAT_8008d2ac; if ((*(short *)(param_1 + 0x3e) == 0) || (*(short *)(param_1 + 0x42) != 0)) { *(undefined4 *)(param_2 + 0x70) = 0x4000; } else { *(uint *)(param_2 + 0x70) = (uint)(*(ushort *)(param_1 + 0x70) >> 6) & 0xff | ((uint)*(ushort *)(param_1 + 0x72) & 0x3fc0) << 2 | ((uint)(*(ushort *)(param_1 + 0x74) >> 6) & 0xff) << 0x10; // quit if more than one player if (1 < (byte)puVar2[0x1ca8]) { return; } // if there is one player // quadblock -> flags uVar1 = *(ushort *)(*(int *)(param_1 + 0x80) + 0x12); if ((uVar1 & 0x2000) == 0) { // visible? if ((uVar1 & 1) != 0) { // make instance reflective *(uint *)(param_2 + 0x28) = *(uint *)(param_2 + 0x28) | 0x4000; // split line *(undefined2 *)(param_2 + 0x56) = *(undefined2 *)(*(int *)(puVar2 + 0x160) + 0x186); return; } // reflective (ice) if ((uVar1 & 4) != 0) { // make instance reflective *(uint *)(param_2 + 0x28) = *(uint *)(param_2 + 0x28) | 0x4000; // split line *(undefined2 *)(param_2 + 0x56) = *(undefined2 *)(*(int *)(puVar2 + 0x160) + 0x184); return; } } } // instance is not reflective *(uint *)(param_2 + 0x28) = *(uint *)(param_2 + 0x28) & 0xffffbfff; return; } // RB_Player_KillPlayer void FUN_800abbb4(int param_1,int param_2) { undefined *puVar1; uint uVar2; int iVar3; short *psVar4; undefined *puVar5; short sVar6; int iVar7; // boolIsTeamAlive short local_18 [4]; uVar2 = *(uint *)PTR_DAT_8008d2ac; // quit if not in battle mode, or if // either driver is nullptr if ((uVar2 & 0x20) == 0) return; if (param_1 == 0) return; if (param_2 == 0) return; // If you dont have a Point Limit (battle) if ((uVar2 & 0x4000) == 0) { // If you dont have a Life Limit (battle) if ((uVar2 & 0x8000) == 0) { // Quit the function return; } // If you are here, this is LIFE limit // subtract a life from player iVar3 = *(int *)(param_2 + 0x4e4) + -1; iVar7 = 0; // if player is alive if (0 < iVar3) { // set new number of lives *(int *)(param_2 + 0x4e4) = iVar3; // leave function return; } // if you get here, then player is out of lives // array of boolIsTeamAlive memset(local_18,0,8); sVar6 = 0; // VehPtr_Dead_Init *(undefined4 *)(param_2 + 0x54) = 0x80067930; puVar1 = PTR_DAT_8008d2ac; // set lives to zero *(undefined4 *)(param_2 + 0x4e4) = 0; // the race (or battle) is now over for this driver *(uint *)(param_2 + 0x2c8) = *(uint *)(param_2 + 0x2c8) | 0x2000000; iVar3 = 0; puVar5 = puVar1; // if there are players if (puVar1[0x1ca8] != '\0') { // loop through all players do { // If the race is not over for this driver if ((*(uint *)(*(int *)(puVar5 + 0x24ec) + 0x2c8) & 0x2000000) == 0) { // array[driver->teamID] = 1 local_18[*(int *)(*(int *)(puVar5 + 0x24ec) + 0x4e8)] = 1; } // if race is over for this player else { // keep count of drivers dead iVar7 = iVar7 + 1; } iVar3 = iVar3 + 1; puVar5 = puVar5 + 4; } while (iVar3 < (int)(uint)(byte)puVar1[0x1ca8]); } // dead driver -> battleHUD.teamID uVar2 = *(uint *)(param_2 + 0x4e8); if ( // if driver team exists ((*(uint *)(PTR_DAT_8008d2ac + 0x1dd8) & 1 << (uVar2 & 0x1f)) != 0) && // if no remaining players alive on team (local_18[uVar2] == 0) ) { if ((int)((uint)(byte)PTR_DAT_8008d2ac[0x1ca8] - iVar7) < 3) { // increment gGT Standing Points by 1, // record how many times players finished in each rank *(int *)(PTR_DAT_8008d2ac + (uVar2 * 3 + ((uint)(byte)PTR_DAT_8008d2ac[0x1ca8] - iVar7)) * 4 + 0x1e80) = *(int *)(PTR_DAT_8008d2ac + (uVar2 * 3 + ((uint)(byte)PTR_DAT_8008d2ac[0x1ca8] - iVar7)) * 4 + 0x1e80) + 1; } // save the rank that each team finished *(uint *)(PTR_DAT_8008d2ac + *(int *)(param_2 + 0x4e8) * 4 + 0x1da8) = (uint)(byte)PTR_DAT_8008d2ac[0x1ca8] - iVar7; } // count all living teams puVar1 = PTR_DAT_8008d2ac; uVar2 = 0; psVar4 = local_18; // loop through all teams do { if ( // if team exists ((*(uint *)(PTR_DAT_8008d2ac + 0x1dd8) & 1 << (uVar2 & 0x1f)) != 0) && // if someone is alive on this team (*psVar4 != 0) ) { // count living teams sVar6 = sVar6 + 1; } uVar2 = uVar2 + 1; psVar4 = psVar4 + 1; } while ((int)uVar2 < 4); // if there is not only one team alive if (sVar6 != 1) { // no winner found yet return; } // at this point, a winner is found, // end the game for all drivers iVar3 = 0; puVar5 = PTR_DAT_8008d2ac; // if there are players if (PTR_DAT_8008d2ac[0x1ca8] != '\0') { // loop through all players do { // The race (or battle) is now over for this driver *(uint *)(*(int *)(puVar5 + 0x24ec) + 0x2c8) = *(uint *)(*(int *)(puVar5 + 0x24ec) + 0x2c8) | 0x2000000; iVar3 = iVar3 + 1; puVar5 = puVar5 + 4; } while (iVar3 < (int)(uint)(byte)puVar1[0x1ca8]); } } // if Point Limit else { // if driver hit themself if (*(int *)(param_2 + 0x4e8) == *(int *)(param_1 + 0x4e8)) { // subtract a point iVar3 = *(int *)(PTR_DAT_8008d2ac + *(int *)(param_2 + 0x4e8) * 4 + 0x1d90) + -1; if (iVar3 < -9) { // can't go lower than -9 return; } // save new score *(int *)(PTR_DAT_8008d2ac + *(int *)(param_2 + 0x4e8) * 4 + 0x1d90) = iVar3; return; } // add point to player who got a hit iVar3 = *(int *)(PTR_DAT_8008d2ac + *(int *)(param_1 + 0x4e8) * 4 + 0x1d90) + 1; // if scores is less than 100 if (iVar3 < 100) { // increment score *(int *)(PTR_DAT_8008d2ac + *(int *)(param_1 + 0x4e8) * 4 + 0x1d90) = iVar3; } puVar1 = PTR_DAT_8008d2ac; // if amount of points earned by this driver is not equal to the winning amount if (*(int *)(PTR_DAT_8008d2ac + *(int *)(param_1 + 0x4e8) * 4 + 0x1d90) != *(int *)(PTR_DAT_8008d2ac + 0x1d8c)) { // quit function return; } // if this is a time-limit game if ((*(uint *)PTR_DAT_8008d2ac & 0x10000) != 0) { // quit return; } // if this is not a time-limit game, // and the last kill has been made, // then end the game iVar3 = 0; puVar5 = PTR_DAT_8008d2ac; // if there are drivers if (PTR_DAT_8008d2ac[0x1ca8] != '\0') { // loop through all drivers do { // the race (or battle) is now over for this driver *(uint *)(*(int *)(puVar5 + 0x24ec) + 0x2c8) = *(uint *)(*(int *)(puVar5 + 0x24ec) + 0x2c8) | 0x2000000; iVar3 = iVar3 + 1; puVar5 = puVar5 + 4; } while (iVar3 < (int)(uint)(byte)puVar1[0x1ca8]); } } // MainGameEnd_Initialize FUN_8003a3fc(); return; } // RB_Player_ModifyWumpa void FUN_800abefc(int param_1,int param_2) { // param_1 is address of player/AI structure // param_2 is number of wumpa fruit to add // get current number of wumpa fruit char cVar1; cVar1 = *(char *)(param_1 + 0x30); if ( // if unlimited wumpa cheat is disabled ((*(uint *)(PTR_DAT_8008d2ac + 8) & 0x200) == 0) && ( ( // if wumpa fruit are being added, not subtracted -1 < param_2 || // if driver is not using mask weapon ((*(uint *)(param_1 + 0x2c8) & 0x800000) == 0) ) ) ) { if ( // if wumpa is increasing (0 < param_2) && // if this driver is not an AI ((*(uint *)(param_1 + 0x2c8) & 0x100000) == 0) ) { // increment how much fruit was collected by this driver *(char *)(param_1 + 0x569) = *(char *)(param_1 + 0x569) + (char)param_2; } // get new total amount of wumpa fruit (current + added amount) param_2 = (uint)*(byte *)(param_1 + 0x30) + param_2; // store the new value into current number of wumpa fruit *(undefined *)(param_1 + 0x30) = (char)param_2; // If total wumpa is negative if (param_2 * 0x1000000 < 0) { // reset wumpa fruit to zero *(undefined *)(param_1 + 0x30) = 0; } // if wumpa fruit count is more than 10 if ('\n' < *(char *)(param_1 + 0x30)) { // set amount of wumpa fruit to 10 *(undefined *)(param_1 + 0x30) = 10; } // if amount of wumpa was less than 10, and then changed to be 10 if ((cVar1 < '\n') && (*(char *)(param_1 + 0x30) == '\n')) { // Play "juiced up" sound FUN_80028468(0x41,1); // 10 frames *(undefined4 *)(param_1 + 0x4e0) = 10; } } return; } // RB_MinePool_Init void FUN_800abfec(void) { int iVar1; undefined *puVar2; int iVar3; // LIST_Clear taken list FUN_80031734(&DAT_800b2e9c); // LIST_Clear free list FUN_80031734(&DAT_800b2ea8); // If you are not in Crystal Challenge if ((*(uint *)PTR_DAT_8008d2ac & 0x8000000) == 0) { // if this is dragon mines boss race if ( // If you are in Boss Race ((int)*(uint *)PTR_DAT_8008d2ac < 0) && // If level is Dragon Mines (*(int *)(PTR_DAT_8008d2ac + 0x1a10) == 1) ) { // three mines max iVar1 = 3; } // if this is not dragon mines boss race else { // ten mines max, // applies to Arcade, VS, Battle, etc iVar1 = 10; if ( // If you are in Boss Race (*(int *)PTR_DAT_8008d2ac < 0) && ( // boss race for Papu and Oxide, // ten mines max iVar1 = 10, // If the level is Roo's Tubes *(int *)(PTR_DAT_8008d2ac + 0x1a10) == 6 ) ) { // Ripper Roo can only place 7 TNTs // before the last TNTs explode iVar1 = 7; } } } // if this is crystal challenge else { // 40 items max iVar1 = 0x28; } iVar3 = 0; if (iVar1 != 0) { puVar2 = &DAT_800b2eb4; do { // LIST_AddFront free list FUN_80031744(&DAT_800b2ea8,puVar2); iVar3 = iVar3 + 1; puVar2 = puVar2 + 0xc; } while (iVar3 < iVar1); } return; } // RB_MinePool_Remove // param_1 = struct MineWeapon void FUN_800ac0e4(int param_1) { if (*(int *)(param_1 + 0x18) != 0) { // LIST_RemoveMember taken list FUN_800317e4(&DAT_800b2e9c,*(undefined4 *)(param_1 + 0x18)); // LIST_AddFront free list FUN_80031744(&DAT_800b2ea8,*(undefined4 *)(param_1 + 0x18)); // MineWeapon is now destroyed *(undefined2 *)(param_1 + 0x14) = 1; // MineWeapon has no WeaponSlot231 pointer anymore *(undefined4 *)(param_1 + 0x18) = 0; } return; } // RB_MinePool_Add // param_1 = struct MineWeapon void FUN_800ac13c(int param_1) { int iVar1; // if no more items on free list // (800b2ea8 + 8 = 800b2eb0) if (DAT_800b2eb0 == 0) { // remove oldest mine // RB_MinePool_Remove // (800b2e9c + 4 = 800b2ea0) (taken->last) // (*(int*)800b2ea0 + 8) (taken->last->mineWeapon) FUN_800ac0e4(*(undefined4 *)(DAT_800b2ea0 + 8)); } // LIST_RemoveBack free list iVar1 = FUN_800318ec(&DAT_800b2ea8); // weaponSlot231->MineWeapon = param_1 (mineWeapon) *(int *)(iVar1 + 8) = param_1; // mineWeapon->weaponSlot231 = weaponSlot231 *(int *)(param_1 + 0x18) = iVar1; // LIST_AddFront taken list FUN_80031744(&DAT_800b2e9c,iVar1); return; } // hazard can be a Mine instance, // or level instance (spider, armadillo, etc) // RB_Hazard_HurtDriver // return 1 if driver was hurt, // return 0 if driver was not hurt (mask grab, mask weapon, etc) int FUN_800ac1b0(int param_1,undefined4 param_2, param_3, param_4) { // if this driver is not an AI if ((*(uint *)(param_1 + 0x2c8) & 0x100000) == 0) { // Player_ChangeState return FUN_80064568(param_1,param_2,param_3,param_4); } // If driver is an AI else { if ( // if Level ID == 13, if this is Oxide Station (*(int *)(PTR_DAT_8008d2ac + 0x1a10) == 0xd) && // If you are in "Boss Mode" (0x80000000) (*(int *)PTR_DAT_8008d2ac < 0)) { // override effect to spinning out, // this make Oxide spin out param_2 = 1; } // BOTS_ChangeState return FUN_80016b00(param_1,param_2); } } // RB_Hazard_CollideWithDrivers // param_1 weapon instance // param_2 boolCanSkipParent // param_3 collision radius // param_4 mineParent_driverInst int FUN_800ac220(int param_1,short param_2,uint param_3,int param_4) { ushort uVar1; int iVar2; int iVar3; int iVar4; int iVar5; undefined *puVar6; int iVar7; int iVar8; int iVar9; iVar7 = 0; puVar6 = PTR_DAT_8008d2ac; do { // Get pointer to player (9900C) iVar2 = *(int *)(puVar6 + 0x24ec); if ( // If pointer is not nullptr (iVar2 != 0) && // If you're not being mask grabbed (*(char *)(iVar2 + 0x376) != '\x05') ) { // get instance from driver iVar5 = *(int *)(iVar2 + 0x1c); // get X distance and Z distance between player and object iVar3 = *(int *)(iVar5 + 0x44) - *(int *)(param_1 + 0x44); iVar4 = *(int *)(iVar5 + 0x4c) - *(int *)(param_1 + 0x4c); // instance -> model -> modelID uVar1 = *(ushort *)(*(int *)(param_1 + 0x18) + 0x10); // get Y distance between player and object iVar2 = *(int *)(iVar5 + 0x48) - *(int *)(param_1 + 0x48); if ( // red or green potion ((uint)uVar1 - 0x46 < 2) || ( ( iVar8 = iVar3 * iVar3, // nitro uVar1 == 6 || // tnt (uVar1 == 0x27) ) ) ) { iVar9 = iVar2 * iVar2; iVar8 = iVar3 * iVar3 + iVar4 * iVar4; } else { iVar9 = iVar4 * iVar4; } // if distance is less than param_3 if (((uint)(iVar8 + iVar9) < param_3) && // if driver did not hit their own mine (((param_2 == 0 || (iVar5 != param_4)) && (iVar2 * iVar2 < (int)(param_3 << 2))))) { // driver who hit the mine return iVar5; } } iVar7 = iVar7 + 1; puVar6 = puVar6 + 4; if (7 < iVar7) { return 0; } } while( true ); } // RB_Hazard_CollideWithBucket // param_1 - mine Inst, // param_2 - mine Thread (unused) // param_3 - bucket // param_4 - boolCanSkipParent // param_5 - radius // param_6 - mineParent_driverInst int FUN_800ac350 (int param_1,undefined4 param_2,int param_3,short param_4,uint param_5,int param_6) { int iVar1; int iVar2; int iVar3; int iVar4; // loop through all members in linked list if (param_3 != 0) { do { // get instance from thread iVar4 = *(int *)(param_3 + 0x34); // get distance (x, y, z) between two instances iVar1 = *(int *)(iVar4 + 0x44) - *(int *)(param_1 + 0x44); iVar2 = *(int *)(iVar4 + 0x4c) - *(int *)(param_1 + 0x4c); iVar3 = *(int *)(iVar4 + 0x48) - *(int *)(param_1 + 0x48); if ( // if distance is less than collision radius ((uint)(iVar1 * iVar1 + iVar2 * iVar2 + iVar3 * iVar3) < param_5) && ((param_4 == 0 || (iVar4 != param_6))) ) { // return the instance that collided return iVar4; } // check the next member in the linked list param_3 = *(int *)(param_3 + 0x10); // loop through all member in linked list } while (param_3 != 0); } return 0; } // RB_Hazard_ThCollide_Generic_Alt void FUN_800ac3f8(undefined4 *param_1) { // RB_Hazard_ThCollide_Generic // only really uses *param_1 for thread FUN_800ac4b8(*param_1,param_1[1],param_1[2],param_1[3]); return; } // RB_Hazard_ThCollide_Missile // removes 2D target from player undefined4 FUN_800ac42c(int param_1) { int iVar1; int *piVar2; // thread -> instance -> thread -> object piVar2 = *(int **)(*(int *)(*(int *)(param_1 + 0x34) + 0x6c) + 0x30); // thread -> instance -> model -> modelID == missile if (*(short *)(*(int *)(*(int *)(param_1 + 0x34) + 0x18) + 0x10) == 0x29) { // The first 4 bytes of missile object is // the pointer to the player it was chasing // iVar1 = player iVar1 = *piVar2; // if the player is valid if (iVar1 != 0) { // remove 2D square-target being drawn on the player's screen *(uint *)(iVar1 + 0x2c8) = *(uint *)(iVar1 + 0x2c8) & 0xfbffffff; } // play audio of explosion FUN_8002f0dc(0x4c); // stop audio of moving FUN_8002e724(piVar2 + 9); // This thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; } return 1; } // RB_Hazard_ThCollide_Generic // param_1 - thread // param_2 - thread (again? unused) // param_3 - funcThCollide (unused) // param_4 - unknown, unused undefined4 FUN_800ac4b8(int param_1) { ushort uVar1; int iVar2; undefined4 uVar3; int iVar4; int *piVar5; // thread->instance iVar4 = *(int *)(param_1 + 0x34); // instance->thread->object piVar5 = *(int **)(*(int *)(iVar4 + 0x6c) + 0x30); if ( ( // if mineWeapon->crateInst (piVar5[2] != 0) && // instance -> thread (iVar2 = *(int *)(piVar5[2] + 0x6c), iVar2 != 0) ) && // thread -> object (iVar2 = *(int *)(iVar2 + 0x30), iVar2 != 0) ) { // unpause cooldown (boolPauseCooldown) *(undefined2 *)(iVar2 + 4) = 0; } // get model ID from inside model pointer uVar1 = *(ushort *)(*(int *)(iVar4 + 0x18) + 0x10); // If this is red beaker or green beaker if ((uint)uVar1 - 0x46 < 2) { // play sound of glass shatter FUN_8002f0dc(0x3f,iVar4); // RB_MinePool_Remove FUN_800ac0e4(piVar5); } else { // if this is a Nitro if (uVar1 == 6) { // sound of glass shatter uVar3 = 0x3f; } else { // if this is not a TNT if (uVar1 != 0x27) { return 1; } // at this point, it must be TNT // if driver hit the TNT if (*piVar5 != 0) { // quit, explosion is handled // by TNT thread instead return 1; } // if no driver hit TNT, // handle explosion here // play sound of tnt explosion uVar3 = 0x3d; } // play sound FUN_8002f0dc(uVar3,iVar4); // RB_MinePool_Remove FUN_800ac0e4(piVar5); // RB_Explosion_InitGeneric FUN_800b1630(iVar4); // set scale (x, y, z) to zero *(undefined2 *)(iVar4 + 0x20) = 0; *(undefined2 *)(iVar4 + 0x1e) = 0; *(undefined2 *)(iVar4 + 0x1c) = 0; // make invisible *(uint *)(iVar4 + 0x28) = *(uint *)(iVar4 + 0x28) | 0x80; } // this thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; return 1; } // RB_Potion_OnShatter_TeethCallback // param_2 Lev Hitbox (bsp) void FUN_800ac5e8(undefined4 param_1,int param_2) { int iVar1; // bsp->hitbox.instDef iVar1 = *(int *)(param_2 + 0x1c); if ( ( // if InstDef exists (iVar1 != 0) && (*(int *)(iVar1 + 0x2c) != 0) ) && // modelID == STATIC_TEETH (*(short *)(iVar1 + 0x3c) == 0x70) ) { // RB_Teeth_OpenDoor FUN_800ba220(*(int *)(iVar1 + 0x2c)); } return; } // RB_Potion_OnShatter_TeethSearch void FUN_800ac638(int param_1) { // This function is not a waste, // if potion explodes while sitting next to teeth, // either cause another driver hit it, // or cause too many potions in MinePool, // then this is the only way for teeth to open // position DAT_1f800108 = *(undefined2 *)(param_1 + 0x44); DAT_1f80010a = *(undefined2 *)(param_1 + 0x48); DAT_1f80010c = *(undefined2 *)(param_1 + 0x4c); // hitRadius and hitRadiusSquared DAT_1f80010e = 0x140; DAT_1f800110 = 0x19000; // thread DAT_1f800120 = *(undefined4 *)(param_1 + 0x6c); // inst->modelPtr->modelID DAT_1f800114 = *(undefined2 *)(*(int *)(param_1 + 0x18) + 0x10); // RB_Potion_OnShatter_TeethCallback DAT_1f800130 = FUN_800ac5e8; // THREAD_StartSearch_Self FUN_80042544(&DAT_1f800108); return; } // RB_Potion_ThTick_InAir void FUN_800ac6b4(int param_1) { bool bVar1; short sVar2; undefined *puVar3; int iVar4; int iVar5; int iVar6; int iVar7; undefined2 local_28; short local_26; undefined2 local_24; undefined2 local_20; short local_1e; undefined2 local_1c; puVar3 = PTR_DAT_8008d2ac; // get instance from thread iVar6 = *(int *)(param_1 + 0x34); // instance -> thread -> object iVar7 = *(int *)(*(int *)(iVar6 + 0x6c) + 0x30); // X position *(int *)(iVar6 + 0x44) = *(int *)(iVar6 + 0x44) + ((int)*(short *)(iVar7 + 0xc) * *(int *)(PTR_DAT_8008d2ac + 0x1d04) >> 5); // Y position *(int *)(iVar6 + 0x48) = *(int *)(iVar6 + 0x48) + ((int)*(short *)(iVar7 + 0xe) * *(int *)(puVar3 + 0x1d04) >> 5); // Z position *(int *)(iVar6 + 0x4c) = *(int *)(iVar6 + 0x4c) + ((int)*(short *)(iVar7 + 0x10) * *(int *)(puVar3 + 0x1d04) >> 5); // gravity, decrease velocity over time iVar4 = (uint)*(ushort *)(iVar7 + 0xe) - ((*(int *)(puVar3 + 0x1d04) << 2) >> 5); *(undefined2 *)(iVar7 + 0xe) = (short)iVar4; // terminal velocity if (iVar4 * 0x10000 >> 0x10 < -0x60) { *(undefined2 *)(iVar7 + 0xe) = 0xffa0; } // reduce cooldown time, set from GenericMine_ThTick iVar4 = (uint)*(ushort *)(iVar7 + 0x2a) - (uint)*(ushort *)(PTR_DAT_8008d2ac + 0x1d04); *(undefined2 *)(iVar7 + 0x2a) = (short)iVar4; // if below zero, then set to zero if (iVar4 * 0x10000 < 0) { *(undefined2 *)(iVar7 + 0x2a) = 0; } // posBottom local_28 = *(undefined2 *)(iVar6 + 0x44); local_26 = *(short *)(iVar6 + 0x48) + -0x40; local_24 = *(undefined2 *)(iVar6 + 0x4c); // posTop local_20 = *(undefined2 *)(iVar6 + 0x44); local_1e = *(short *)(iVar6 + 0x48) + 0x100; local_1c = *(undefined2 *)(iVar6 + 0x4c); DAT_1f80012c = 0x1040; DAT_1f800130 = 0; DAT_1f80012a = 0x41; // numPlyrCurrGame is less than 3 if ((byte)PTR_DAT_8008d2ac[0x1ca8] < 3) { DAT_1f80012a = 0x43; } DAT_1f800134 = **(undefined4 **)(PTR_DAT_8008d2ac + 0x160); // COLL_SearchTree_FindQuadblock_Touching FUN_8001eb0c(&local_28,&local_20,&DAT_1f800108,0); // RB_MakeInstanceReflective FUN_800abab0(&DAT_1f800108,iVar6); if ((DAT_1f8002ac & 4) != 0) { // RB_GenericMine_ThDestroy FUN_800ad250(param_1,iVar6,iVar7); } // did not hit bsp hitbox if (DAT_1f80014a == 0) { if (DAT_1f800146 != 0) { // Rot_AxisAngle FUN_8005f89c(iVar6 + 0x30,&DAT_1f800178,0); // hitbox minY iVar4 = (int)DAT_1f800126; // instance posY iVar5 = *(int *)(iVar6 + 0x48); if (iVar4 + 0x30 < iVar5) { return; } // if no cooldown if (*(short *)(iVar7 + 0x2a) == 0) { *(int *)(iVar6 + 0x48) = iVar4; sVar2 = DAT_1f800126; // reset cooldown (3.84s) // if potion hits ground, and hit within 3.84s, // then it counts in EndOfRace comments as hit by moving potion, // but will count as motionless potion if hit after 3.84s of // hitting the ground (after initially being Potion_InAir) *(undefined2 *)(iVar7 + 0x2a) = 0xf00; // clear velocity *(undefined2 *)(iVar7 + 0xc) = 0; *(undefined2 *)(iVar7 + 0xe) = 0; *(undefined2 *)(iVar7 + 0x10) = 0; // max height *(short *)(iVar7 + 0x12) = sVar2; // remove flag "| 2" *(ushort *)(iVar7 + 0x28) = *(ushort *)(iVar7 + 0x28) & 0xfffd; // ThTick_SetAndExec(self, RB_GenericMine_ThTick) FUN_800716ec(param_1,FUN_800acb60); return; } if (iVar5 <= iVar4) { *(int *)(iVar6 + 0x48) = iVar4; } if ((*(int *)(iVar6 + 0x48) - iVar5) + 0x28 <= (int)*(short *)(iVar7 + 0xe)) { return; } *(short *)(iVar7 + 0xe) = (*(short *)(iVar6 + 0x48) - (short)iVar5) + 0x28; return; } // if did not touch quadblock in range [-0x40, 0x100], // check again with range [-0x900, 0x100] // posBottom local_28 = *(undefined2 *)(iVar6 + 0x44); local_26 = *(short *)(iVar6 + 0x48) + -0x900; local_24 = *(undefined2 *)(iVar6 + 0x4c); // COLL_SearchTree_FindQuadblock_Touching FUN_8001eb0c(&local_28,&local_20,&DAT_1f800108,0); // if quadblock exists within 0x900 units of Y axis, // do not destroy the potion, let it keep flying if (DAT_1f800146 != 0) { return; } } // This is not a waste, // Potion_OnShatter_SearchTeeth fails // to open Teeth while the potion is airborne // If hit bsp hitbox else { bVar1 = true; if (((((*DAT_1f800150 & 0x80) != 0) && (iVar4 = *(int *)(DAT_1f800150 + 0x1c), iVar4 != 0)) && (*(short *)(iVar4 + 0x3c) == 0x70)) && (*(int *)(iVar4 + 0x2c) != 0)) { // if door is closed if ((DAT_8008d728 & 1) == 0) { // RB_Teeth_OpenDoor FUN_800ba220(); } else { bVar1 = false; } } if (!bVar1) { return; } } // hit TEETH door, // or no quadblock exists within 0x900 units of Y axis // RB_GenericMine_ThDestroy FUN_800ad250(param_1,iVar6,iVar7); return; } // RB_GenericMine_LInB void FUN_800aca50(int param_1) { // This is for Nitro crates // in Crystal Challenge, not // for crates dropped by players undefined *puVar1; int iVar2; undefined4 *puVar3; // RB_Default_LInB FUN_800b4fe4(param_1); if ( // If this Instance's thread does not exist (*(int *)(param_1 + 0x6c) == 0) && // If you are in Crystal Challenge ((*(uint *)PTR_DAT_8008d2ac & 0x8000000) != 0) ) { // THREAD_BirthWithObject // 0x2c = size // 0 = no relation to param4 // 0x300 = SmallStackPool // 0x4 = "mine" thread bucket iVar2 = FUN_8004205c(0x2c0304,FUN_800acb60,s_nitro_800ab9f4,0); // Give thread to Instance *(int *)(param_1 + 0x6c) = iVar2; // If the thread created successfully if (iVar2 != 0) { // Give Instance to thread *(int *)(iVar2 + 0x34) = param_1; puVar1 = PTR_DAT_8008d2ac; // Instance->thread->funcThCollide *(undefined4 *)(*(int *)(param_1 + 0x6c) + 0x28) = 0x800ac4b8; // Instance->thread->playerthread = Player->Instance->thread *(undefined4 *)(*(int *)(param_1 + 0x6c) + 0xc) = *(undefined4 *)(*(int *)(*(int *)(puVar1 + 0x24ec) + 0x1c) + 0x6c); // Instance->thread->modelIndex = Instance->Model->modelIndex *(undefined2 *)(*(int *)(param_1 + 0x6c) + 0x44) = *(undefined2 *)(*(int *)(param_1 + 0x18) + 0x10); // Get Nitro object attached to Instance's thread puVar3 = *(undefined4 **)(*(int *)(param_1 + 0x6c) + 0x30); // Get Instance attached to player puVar3[1] = *(undefined4 *)(*(int *)(puVar1 + 0x24ec) + 0x1c); *(undefined2 *)(puVar3 + 3) = 0; *(undefined2 *)((int)puVar3 + 0xe) = 0; *(undefined2 *)(puVar3 + 4) = 0; *(undefined2 *)(puVar3 + 9) = 0; *(undefined2 *)(puVar3 + 5) = 0; *(undefined2 *)((int)puVar3 + 0x26) = 0; *puVar3 = 0; puVar3[2] = 0; *(undefined2 *)(puVar3 + 10) = 0; // RB_MinePool_Add FUN_800ac13c(puVar3); // mineWeapon->posY = instance->posY *(undefined2 *)((int)puVar3 + 0x12) = *(undefined2 *)(param_1 + 0x48); } } return; } // RB_GenericMine_ThTick // TNT, Nitro, Potion void FUN_800acb60(int param_1) { short sVar1; ushort uVar2; undefined2 uVar3; undefined *puVar4; int iVar5; int iVar6; code *pcVar7; undefined4 uVar8; undefined4 uVar9; undefined4 uVar10; int *piVar11; int iVar12; int *piVar13; // get instance from thread iVar12 = *(int *)(param_1 + 0x34); // instance -> thread -> object piVar13 = *(int **)(*(int *)(iVar12 + 0x6c) + 0x30); // if weapon is "thrown" like Komodo Joe, // this is offset 0x28 if ((*(ushort *)(piVar13 + 10) & 2) != 0) { // instance -> model -> modelID == TNT if (*(short *)(*(int *)(iVar12 + 0x18) + 0x10) == 0x27) { // RB_TNT_ThTick_ThrowOffHead pcVar7 = FUN_800ad310; // set scale (x, y, z) *(undefined2 *)(iVar12 + 0x1c) = 0x800; *(undefined2 *)(iVar12 + 0x1e) = 0x800; *(undefined2 *)(iVar12 + 0x20) = 0x800; } // Potion else { // cooldown of 0.24s *(undefined2 *)((int)piVar13 + 0x2a) = 0xf0; // RB_Potion_ThTick_InAir pcVar7 = FUN_800ac6b4; } // ThTick_SetAndExec FUN_800716ec(param_1,pcVar7); } // reduce cooldown iVar5 = (uint)*(ushort *)((int)piVar13 + 0x2a) - (uint)*(ushort *)(PTR_DAT_8008d2ac + 0x1d04); *(undefined2 *)((int)piVar13 + 0x2a) = (short)iVar5; // if negative, then set zero if (iVar5 * 0x10000 < 0) { *(undefined2 *)((int)piVar13 + 0x2a) = 0; } // instance -> animFrame sVar1 = *(short *)(iVar12 + 0x54); // INSTANCE_GetNumAnimFrames iVar5 = FUN_80030f58(iVar12,0); // if animation is not over if ((int)sVar1 + 1 < iVar5) { // increment animation frame *(short *)(iVar12 + 0x54) = *(short *)(iVar12 + 0x54) + 1; } // if animation is over else { // restart animation *(undefined2 *)(iVar12 + 0x54) = 0; } // increment posY by velY * time iVar5 = *(int *)(iVar12 + 0x48) + ((int)*(short *)((int)piVar13 + 0xe) * *(int *)(PTR_DAT_8008d2ac + 0x1d04) >> 5); *(int *)(iVar12 + 0x48) = iVar5; // if height is higher than max height if (iVar5 < (int)*(short *)((int)piVar13 + 0x12)) { *(int *)(iVar12 + 0x48) = (int)*(short *)((int)piVar13 + 0x12); } // decrease velocity by time, this is artificial gravity (negative acceleration) iVar5 = (uint)*(ushort *)((int)piVar13 + 0xe) - ((*(int *)(PTR_DAT_8008d2ac + 0x1d04) << 2) >> 5); *(undefined2 *)((int)piVar13 + 0xe) = (short)iVar5; if (iVar5 * 0x10000 >> 0x10 < -0x60) { *(undefined2 *)((int)piVar13 + 0xe) = 0xffa0; } // If scale is under 0x1000 if (*(short *)(iVar12 + 0x1c) < 0x1000) { // make scale larger each frame *(short *)(iVar12 + 0x1c) = *(short *)(iVar12 + 0x1c) + 0x200; *(short *)(iVar12 + 0x1e) = *(short *)(iVar12 + 0x1e) + 0x200; *(short *)(iVar12 + 0x20) = *(short *)(iVar12 + 0x20) + 0x200; } // if scale is done growing else { // set to the intended size *(undefined2 *)(iVar12 + 0x1c) = 0x1000; *(undefined2 *)(iVar12 + 0x1e) = 0x1000; *(undefined2 *)(iVar12 + 0x20) = 0x1000; } uVar8 = 0x3840; // instance -> model -> modelID is red beaker or green beaker if ((uint)*(ushort *)(*(int *)(iVar12 + 0x18) + 0x10) - 0x46 < 2) { uVar8 = 0x1900; } // RB_Hazard_CollideWithDrivers iVar5 = FUN_800ac220(iVar12,(int)*(short *)(piVar13 + 9),uVar8,piVar13[1]); // if no collision if (iVar5 == 0) goto LAB_800ad17c; // get driver who hit tnt (or nitro) // from the object attached to thread iVar5 = *(int *)(*(int *)(iVar5 + 0x6c) + 0x30); // if mineWeapon->crateInst, if inst->thread, if thread->object if (((piVar13[2] != 0) && (iVar6 = *(int *)(piVar13[2] + 0x6c), iVar6 != 0)) && (iVar6 = *(int *)(iVar6 + 0x30), iVar6 != 0)) { // unpause cooldown (boolPauseCooldown) *(undefined2 *)(iVar6 + 4) = 0; } // instance -> model -> modelID uVar2 = *(ushort *)(*(int *)(iVar12 + 0x18) + 0x10); // red beaker or green beaker if ((uint)uVar2 - 0x46 < 2) { // count times hit by motionless potion uVar8 = 2; // if fly-forward timer is still active if (*(short *)((int)piVar13 + 0x2a) != 0) { // moving potion uVar8 = 4; } // RB_Hazard_HurtDriver (spin out) iVar6 = FUN_800ac1b0(iVar5,1,*(undefined4 *)(*(int *)(piVar13[1] + 0x6c) + 0x30),uVar8); // if collision, and if this was a red potion if ((iVar6 != 0) && ((*(ushort *)(piVar13 + 10) & 1) != 0)) { // RB_RainCloud_Init FUN_800b1220(iVar5); } puVar4 = PTR_DAT_8008d2ac; // if this driver is not an AI if ((*(uint *)(iVar5 + 0x2c8) & 0x100000) == 0) { // current fade value (bright white) *(undefined2 *)(PTR_DAT_8008d2ac + (uint)*(byte *)(iVar5 + 0x4a) * 0x110 + 0x17a) = 0x1fff; // desired fade value (neutral) *(undefined2 *)(puVar4 + (uint)*(byte *)(iVar5 + 0x4a) * 0x110 + 0x17c) = 0x1000; // fade step *(undefined2 *)(puVar4 + (uint)*(byte *)(iVar5 + 0x4a) * 0x110 + 0x17e) = 0xff78; } // This block of code only executes for // red beaker or green beaker // make player icon red // If this is a red beaker uVar8 = 0x1e; // instance -> model -> modelID == GreanBeaker if (*(short *)(*(int *)(iVar12 + 0x18) + 0x10) == 0x47) { // make player icon green uVar8 = 0xffffffe2; } LAB_800ace88: // set icon damage timer *(undefined4 *)(iVar5 + 0x4ac) = uVar8; LAB_800ad174: // RB_GenericMine_ThDestroy FUN_800ad250(param_1,iVar12,piVar13); } else { // if driver->instTntRecv is valid if (*(int *)(iVar5 + 0x18) != 0) { // RB_Hazard_HurtDriver (blasted) FUN_800ac1b0(iVar5,2,0,2); // driver->instTntRecv iVar6 = *(int *)(iVar5 + 0x18); // icon damage timer, draw icon as red *(undefined4 *)(iVar5 + 0x4ac) = 0x1e; // set scale (x, y, z) to zero *(undefined2 *)(iVar6 + 0x20) = 0; *(undefined2 *)(iVar6 + 0x1e) = 0; *(undefined2 *)(iVar6 + 0x1c) = 0; // make invisible *(uint *)(*(int *)(iVar5 + 0x18) + 0x28) = *(uint *)(*(int *)(iVar5 + 0x18) + 0x28) | 0x80; // driver -> instTntRecv -> thread iVar6 = *(int *)(*(int *)(iVar5 + 0x18) + 0x6c); // this thread is now dead *(uint *)(iVar6 + 0x1c) = *(uint *)(iVar6 + 0x1c) | 0x800; // erase instTntRecv *(undefined4 *)(iVar5 + 0x18) = 0; goto LAB_800ad174; } // if driver has squished timer if (*(short *)(iVar5 + 0x404) != 0) { // RB_Hazard_HurtDriver (blasted) FUN_800ac1b0(iVar5,2,0,2); uVar8 = 0x1e; goto LAB_800ace88; } // if model is Nitro if (uVar2 == 6) { // RB_Hazard_HurtDriver (blasted) FUN_800ac1b0(iVar5,2,*(undefined4 *)(*(int *)(piVar13[1] + 0x6c) + 0x30),2); // Why does icon turn red in gameplay? // icon damage timer, draw icon as green *(undefined4 *)(iVar5 + 0x4ac) = 0xffffffe2; goto LAB_800ad174; } // if model is TNT if (uVar2 == 0x27) { // RB_Hazard_HurtDriver (keep driving?) iVar6 = FUN_800ac1b0(iVar5,0,*(undefined4 *)(*(int *)(piVar13[1] + 0x6c) + 0x30),2); if (iVar6 == 0) goto LAB_800ad174; // if Instance has no InstDef, // if this TNT is not part of the level, // use existing thread if (*(int *)(iVar12 + 0x2c) == 0) { // icon damage timer, draw icon as red *(undefined4 *)(iVar5 + 0x4ac) = 0x1e; // give driver to tnt object *piVar13 = iVar5; // driver -> instTntRecv *(int *)(iVar5 + 0x18) = iVar12; // RB_MinePool_Remove FUN_800ac0e4(piVar13); // play Hit TNT "bounce" sound FUN_8002f0dc(0x50,iVar12); *(undefined4 *)(iVar12 + 0x70) = 0; *(uint *)(iVar12 + 0x28) = *(uint *)(iVar12 + 0x28) | 0x200; *(undefined2 *)((int)piVar13 + 0xe) = 0x30; *(undefined2 *)(piVar13 + 3) = 0; *(undefined2 *)(piVar13 + 4) = 0; *(undefined2 *)(piVar13 + 7) = 0; *(undefined2 *)((int)piVar13 + 0x1e) = 0; *(undefined2 *)(piVar13 + 8) = 0; *(undefined2 *)((int)piVar13 + 0x12) = 0x3fff; // ThTick_SetAndExec RB_TNT_ThTick_ThrowOnHead FUN_800716ec(param_1,FUN_800ad710); } // if this TNT has an InstDef, then it is part of LEV, // kill the old thread and birth a new one (why?) else { // DAT_800ab9fc // "tnt1" // create thread for TNT, get an Instance // ThTick = RB_GenericMine_ThTick, but set later to RB_TNT_ThTick_ThrowOnHead // 0x300 flag = SmallStackPool // 4 = "mine" thread bucket iVar6 = FUN_800309a4(0x27,&DAT_800ab9fc,0x300,4,FUN_800acb60,0x2c,0); // get rotation of player and assign to tnt uVar9 = *(undefined4 *)(iVar12 + 0x34); uVar10 = *(undefined4 *)(iVar12 + 0x38); uVar8 = *(undefined4 *)(iVar12 + 0x3c); *(undefined4 *)(iVar6 + 0x30) = *(undefined4 *)(iVar12 + 0x30); *(undefined4 *)(iVar6 + 0x34) = uVar9; *(undefined4 *)(iVar6 + 0x38) = uVar10; *(undefined4 *)(iVar6 + 0x3c) = uVar8; // X, Y, Z positions of instance uVar9 = *(undefined4 *)(iVar12 + 0x44); uVar10 = *(undefined4 *)(iVar12 + 0x48); uVar8 = *(undefined4 *)(iVar12 + 0x4c); // finish last rotation variable *(undefined4 *)(iVar6 + 0x40) = *(undefined4 *)(iVar12 + 0x40); // X, Y, Z positions of TNT instanece *(undefined4 *)(iVar6 + 0x44) = uVar9; *(undefined4 *)(iVar6 + 0x48) = uVar10; *(undefined4 *)(iVar6 + 0x4c) = uVar8; // set funcThDestroy to remove instance from instance pool *(undefined4 *)(*(int *)(iVar6 + 0x6c) + 0x24) = 0x80041dfc; // set funcThCollide *(undefined4 *)(*(int *)(iVar6 + 0x6c) + 0x28) = 0x800ac4b8; // Get object from thread piVar11 = *(int **)(*(int *)(iVar6 + 0x6c) + 0x30); // mineWeapon->instParent piVar11[1] = *(int *)(iVar5 + 0x1c); *(undefined2 *)(piVar11 + 9) = 10; *(undefined2 *)(piVar11 + 5) = 0; *(undefined2 *)((int)piVar11 + 0x26) = 0; piVar11[2] = 0; *(undefined2 *)(piVar11 + 10) = 0; // get posY uVar3 = *(undefined2 *)(iVar12 + 0x48); // give driver to tnt object (mineWeapon) *piVar11 = iVar5; // set mineWeapon posY *(undefined2 *)((int)piVar11 + 0x12) = uVar3; // driver -> instTntRecv *(int *)(iVar5 + 0x18) = iVar6; // TNT bounce sound FUN_8002f0dc(0x50,iVar6); *(undefined4 *)(iVar6 + 0x70) = 0; *(uint *)(iVar6 + 0x28) = *(uint *)(iVar6 + 0x28) | 0x200; *(undefined2 *)((int)piVar11 + 0xe) = 0x30; *(undefined2 *)(piVar11 + 3) = 0; *(undefined2 *)(piVar11 + 4) = 0; *(undefined2 *)(piVar11 + 7) = 0; *(undefined2 *)((int)piVar11 + 0x1e) = 0; *(undefined2 *)(piVar11 + 8) = 0; // set RB_TNT_ThTick_ThrowOnHead *(undefined4 *)(*(int *)(iVar6 + 0x6c) + 0x2c) = 0x800ad710; // RB_MinePool_Remove FUN_800ac0e4(piVar13); // set scale (x, y, z) to zero *(undefined2 *)(iVar12 + 0x20) = 0; *(undefined2 *)(iVar12 + 0x1e) = 0; *(undefined2 *)(iVar12 + 0x1c) = 0; // make invisible *(uint *)(iVar12 + 0x28) = *(uint *)(iVar12 + 0x28) | 0x80; // this thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; } } } LAB_800ad17c: // frameCount_DontHurtParent if (*(short *)(piVar13 + 9) != 0) { *(short *)(piVar13 + 9) = *(short *)(piVar13 + 9) + -1; } // if mineWeapon->boolDestroyed == 0 if (*(short *)(piVar13 + 5) == 0) { return; } // if thread is dead, quit function // this is if GenericMine_ThDestroy already ran if ((*(uint *)(param_1 + 0x1c) & 0x800) != 0) { return; } // === If destroyed from MinePool overflow === // instance -> model -> modelID sVar1 = *(short *)(*(int *)(iVar12 + 0x18) + 0x10); // if model is Nitro if (sVar1 == 6) { // glass shatter uVar8 = 0x3f; } else { // if model is not TNT if (sVar1 != 0x27) { // if model is green or red beaker if ((ushort)(*(short *)(*(int *)(iVar12 + 0x18) + 0x10) - 0x46U) < 2) { // glass shatter sound FUN_8002f0dc(0x3f,iVar12); // RB_Explosion_InitPotion FUN_800b1458(iVar12); } goto LAB_800ad21c; } // tnt explosoin sound uVar8 = 0x3d; } // play sound FUN_8002f0dc(uVar8,iVar12); // RB_Blowup_Init FUN_800b18f8(iVar12); LAB_800ad21c: // this thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; return; } // RB_GenericMine_ThDestroy void FUN_800ad250(int param_1,int param_2,undefined4 param_3) { short sVar1; undefined4 uVar2; // instance -> model -> modelID sVar1 = *(short *)(*(int *)(param_2 + 0x18) + 0x10); // if model is Nitro if (sVar1 == 6) { // glass shatter sound uVar2 = 0x3f; } else { // if model is not TNT if (sVar1 != 0x27) { // play sound of glass shatter FUN_8002f0dc(0x3f,param_2); // RB_Explosion_InitPotion FUN_800b1458(param_2); goto LAB_800ad2c8; } // explosion sound uVar2 = 0x3d; } // play sound FUN_8002f0dc(uVar2,param_2); // RB_Blowup_Init FUN_800b18f8(param_2); LAB_800ad2c8: // Set scale (x, y, z) to zero *(undefined2 *)(param_2 + 0x20) = 0; *(undefined2 *)(param_2 + 0x1e) = 0; *(undefined2 *)(param_2 + 0x1c) = 0; // make invisible *(uint *)(param_2 + 0x28) = *(uint *)(param_2 + 0x28) | 0x80; // RB_MinePool_Remove FUN_800ac0e4(param_3); // this thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; return; } // RB_TNT_ThTick_ThrowOffHead // In air, after spamming L1 or R1, // will explode on impact with ground void FUN_800ad310(int param_1) { int iVar1; int *piVar2; // thread -> instance iVar1 = *(int *)(param_1 + 0x34); // instance -> thread -> object (tnt) piVar2 = *(int **)(*(int *)(iVar1 + 0x6c) + 0x30); *(int *)(iVar1 + 0x48) = *(int *)(iVar1 + 0x48) + ((int)*(short *)((int)piVar2 + 0xe) * *(int *)(PTR_DAT_8008d2ac + 0x1d04) >> 5); if (*(short *)((int)piVar2 + 0x12) == 0x3fff) { *(undefined2 *)((int)piVar2 + 0x12) = *(undefined2 *)(*(int *)(*piVar2 + 0x1c) + 0x48); } if (*(int *)(iVar1 + 0x48) <= (int)*(short *)((int)piVar2 + 0x12)) { // plays tnt explosion sound 3D FUN_8002f0dc(0x3d,iVar1); // RB_Blowup_Init FUN_800b18f8(iVar1); // Set scale (x, y, z) to zero *(undefined2 *)(iVar1 + 0x20) = 0; *(undefined2 *)(iVar1 + 0x1e) = 0; *(undefined2 *)(iVar1 + 0x1c) = 0; // make invisible *(uint *)(iVar1 + 0x28) = *(uint *)(iVar1 + 0x28) | 0x80; // this thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; // tntObject -> driver -> tntRecv = 0 *(undefined4 *)(*piVar2 + 0x18) = 0; } iVar1 = (uint)*(ushort *)((int)piVar2 + 0xe) - ((*(int *)(PTR_DAT_8008d2ac + 0x1d04) << 2) >> 5); *(undefined2 *)((int)piVar2 + 0xe) = (short)iVar1; if (iVar1 * 0x10000 >> 0x10 < -0x60) { *(undefined2 *)((int)piVar2 + 0xe) = 0xffa0; } // this skips $RA backup/restore, faster than JR $RA FUN_80071694(param_1); return; } // RB_TNT_ThTick_SitOnHead void FUN_800ad44c(int param_1) { char cVar1; short sVar2; undefined2 uVar3; int iVar4; int *piVar5; int iVar6; // thread->instance iVar6 = *(int *)(param_1 + 0x34); // instance->thread->object (tnt) piVar5 = *(int **)(*(int *)(iVar6 + 0x6c) + 0x30); // CopyMatrix // To: TNT instance // From: obj->driverWhoHitMe->instance // Delta: TNT -> 0x1c (position relative to driver) FUN_800313c8(iVar6,*(undefined4 *)(*piVar5 + 0x1c),piVar5 + 7); // Get Kart State cVar1 = *(char *)(*piVar5 + 0x376); // If crashing, spinning out, or being mask-grabbed if (((cVar1 == '\x01') || (cVar1 == '\x05')) || (cVar1 == '\x03')) { // Play explosion sound FUN_8002f0dc(0x3d,iVar6); // RB_Blowup_Init FUN_800b18f8(iVar6); LAB_800ad4ec: // reset TNT-related pointers *(undefined2 *)(iVar6 + 0x20) = 0; *(undefined2 *)(iVar6 + 0x1e) = 0; *(undefined2 *)(iVar6 + 0x1c) = 0; // make invisible *(uint *)(iVar6 + 0x28) = *(uint *)(iVar6 + 0x28) | 0x80; // this thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; // tnt->driver->tntRecv = 0 *(undefined4 *)(*piVar5 + 0x18) = 0; // this skips $RA backup/restore, faster than JR $RA FUN_80071694(param_1); } else { // If you are already blasted if (cVar1 == '\x06') { // Play explosion sound FUN_8002f0dc(0x3d,iVar6); // RB_Explosion_InitGeneric FUN_800b1630(iVar6); goto LAB_800ad4ec; } } // if this driver is not an AI if ((*(uint *)(*piVar5 + 0x2c8) & 0x100000) == 0) { // if player did not start jumping this frame if ((*(uint *)(*piVar5 + 0x2c8) & 0x400) == 0) goto LAB_800ad5f8; if (*(short *)((int)piVar5 + 0x22) != 0) { *(short *)((int)piVar5 + 0x22) = *(short *)((int)piVar5 + 0x22) + -1; goto LAB_800ad5f8; } *(undefined2 *)((int)piVar5 + 0x22) = 0; } else { iVar4 = FUN_8003ea28(); if (iVar4 != (iVar4 / 0x10e) * 0x10e) goto LAB_800ad5f8; } // set scale (x, y, z) *(undefined2 *)(iVar6 + 0x20) = 0x800; *(undefined2 *)(iVar6 + 0x1e) = 0x800; *(undefined2 *)(iVar6 + 0x1c) = 0x800; // tnt->driver->tntRecv = 0 *(undefined4 *)(*piVar5 + 0x18) = 0; *(undefined2 *)(piVar5 + 3) = 0; *(undefined2 *)((int)piVar5 + 0xe) = 0x30; *(undefined2 *)(piVar5 + 4) = 0; *(undefined2 *)(piVar5 + 7) = 0; *(undefined2 *)((int)piVar5 + 0x1e) = 0; *(undefined2 *)(piVar5 + 8) = 0; // assign RB_TNT_ThTick_ThrowOffHead FUN_800716ec(param_1,FUN_800ad310); LAB_800ad5f8: // Get how many frames the TNT has // been on top of someone's head sVar2 = *(short *)((int)piVar5 + 0x16); // If there is time remaining until TNT blows up, // which takes 0x5a frames, 3 seconds if (sVar2 < 0x5a) { // If frame is any of these 6 numbers if ((((sVar2 == 0) || (sVar2 == 0x14)) || ((sVar2 == 0x28 || ((sVar2 == 0x3c || (sVar2 == 0x46)))))) || (sVar2 == 0x50)) { // Make a "honk" sound FUN_8002f0dc(0x3e,iVar6); } // add to the frame counter *(short *)((int)piVar5 + 0x16) = *(short *)((int)piVar5 + 0x16) + 1; } // If time runs out else { // Blow up // RB_Hazard_HurtDriver (blasted) FUN_800ac1b0(*piVar5,2,*(undefined4 *)(*(int *)(piVar5[1] + 0x6c) + 0x30),0); // icon damage timer, draw icon as red *(undefined4 *)(*piVar5 + 0x4ac) = 0x1e; // play 3D sound for TNT explosion FUN_8002f0dc(0x3d,iVar6); // RB_Blowup_Init FUN_800b18f8(iVar6); // this thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; // tnt->driver->tntRecv = 0 *(undefined4 *)(*piVar5 + 0x18) = 0; // this skips $RA backup/restore, faster than JR $RA FUN_80071694(param_1); } // set scale of TNT, given frame of animation uVar3 = *(undefined2 *)(&DAT_800b295c + (int)*(short *)((int)piVar5 + 0x16) * 4); *(undefined2 *)(iVar6 + 0x20) = uVar3; *(undefined2 *)(iVar6 + 0x1c) = uVar3; *(undefined2 *)(iVar6 + 0x1e) = *(undefined2 *)(&DAT_800b295e + (int)*(short *)((int)piVar5 + 0x16) * 4); return; } // RB_TNT_ThTick_ThrowOnHead // In air, after hitting, before spamming L1 or R1 void FUN_800ad710(int param_1) { int iVar1; int *piVar2; int iVar3; undefined2 local_38; undefined2 local_36; undefined2 local_34; undefined auStack48 [32]; // get instance from thread iVar3 = *(int *)(param_1 + 0x34); // instance -> thread -> object piVar2 = *(int **)(*(int *)(iVar3 + 0x6c) + 0x30); // alter height of TNT as it flies onto a driver's head iVar1 = (uint)*(ushort *)((int)piVar2 + 0x1e) + ((int)*(short *)((int)piVar2 + 0xe) * *(int *)(PTR_DAT_8008d2ac + 0x1d04) >> 5); // new height of TNT *(undefined2 *)((int)piVar2 + 0x1e) = (short)iVar1; // if TNT velocity moves downward if (*(short *)((int)piVar2 + 0xe) < 0) { // 0x800b2ac4 // BSS before Baron_ThTick, // determines height of TNT for each player // if TNT landed on head if ((iVar1 * 0x10000 >> 0x10 < (int)*(short *)(&DAT_800b2ac4 + (int)(short)(&DAT_80086e84)[*(byte *)(*piVar2 + 0x4a)] * 2)) && (*(short *)((int)piVar2 + 0x1e) = *(short *)(&DAT_800b2ac4 + (int)(short)(&DAT_80086e84)[*(byte *)(*piVar2 + 0x4a)] * 2), *(short *)(iVar3 + 0x1c) == 0x800)) { // Set TNT timer to 0, it blows up at 0x5a *(undefined2 *)((int)piVar2 + 0x16) = 0; // RNG iVar1 = FUN_8003ea28(); // Set number of required jumps to 8, with some RNG to mix it up *(short *)((int)piVar2 + 0x22) = 8 - ((short)iVar1 + (short)(iVar1 / 2) * -2); // play sound that you hit a TNT FUN_8002f0dc(0x51,iVar3); *(char *)(iVar3 + 0x50) = *(char *)(*(int *)(*piVar2 + 0x1c) + 0x50) + -1; *(char *)(iVar3 + 0x51) = *(char *)(*(int *)(*piVar2 + 0x1c) + 0x51) + -1; // assign RB_TNT_ThTick_SitOnHead FUN_800716ec(param_1,FUN_800ad44c); } } // CopyMatrix // To: TNT instance // From: obj->driverWhoHitMe->instance // Delta: TNT -> 0x1c (position relative to driver) FUN_800313c8(iVar3,*(undefined4 *)(*piVar2 + 0x1c),piVar2 + 7); // rotation local_38 = 0; local_36 = *(undefined2 *)((int)piVar2 + 0x26); local_34 = 0; // convert 3 rotation shorts into rotation matrix FUN_8006c2a4(auStack48,&local_38); FUN_8006c3b0(iVar3 + 0x30,iVar3 + 0x30,auStack48); // reduce time remaining until TNT lands on head iVar1 = (uint)*(ushort *)((int)piVar2 + 0xe) - ((*(int *)(PTR_DAT_8008d2ac + 0x1d04) << 2) >> 5); *(undefined2 *)((int)piVar2 + 0xe) = (short)iVar1; // set a minimum value (-0x60) if (iVar1 * 0x10000 >> 0x10 < -0x60) { *(undefined2 *)((int)piVar2 + 0xe) = 0xffa0; } // rotation *(short *)((int)piVar2 + 0x26) = *(short *)((int)piVar2 + 0x26) + 0x100; // if scale is small if (*(short *)(iVar3 + 0x1c) < 0x801) { // set min scale *(undefined2 *)(iVar3 + 0x1c) = 0x800; *(undefined2 *)(iVar3 + 0x1e) = 0x800; *(undefined2 *)(iVar3 + 0x20) = 0x800; } // if scale is large else { // reduce scale *(short *)(iVar3 + 0x1c) = *(short *)(iVar3 + 0x1c) + -0x100; *(short *)(iVar3 + 0x1e) = *(short *)(iVar3 + 0x1e) + -0x100; *(short *)(iVar3 + 0x20) = *(short *)(iVar3 + 0x20) + -0x100; } return; } // RB_Explosion_ThTick, // shatter or explosion void FUN_800ad92c(int param_1) { short sVar1; int iVar2; int iVar3; // thread -> instance iVar3 = *(int *)(param_1 + 0x34); // instance -> animFrame sVar1 = *(short *)(iVar3 + 0x54); // INSTANCE_GetNumAnimFrames iVar2 = FUN_80030f58(iVar3,0); // if instance is not at end of animation if ((int)sVar1 + 1 < iVar2) { // increment animation frame *(short *)(iVar3 + 0x54) = *(short *)(iVar3 + 0x54) + 1; } // if animation is done else { // This thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; } // this skips $RA backup/restore, faster than JR $RA FUN_80071694(param_1); return; } // RB_Hazard_CollLevInst (tnt, potion, warpball, etc) (not hazard? moving explosive?) // param_1 - BSP result // param_2 - bsp (hitbox) undefined4 FUN_800ad9ac(int param_1,undefined4 param_2) { int iVar1; undefined4 uVar2; int iVar3; int iVar4; if ((((**(byte **)(param_1 + 0x48) & 0x80) != 0) && (iVar1 = *(int *)(*(byte **)(param_1 + 0x48) + 0x1c), iVar1 != 0)) && // instance = instDef->instance (lev only) (iVar4 = *(int *)(iVar1 + 0x2c), iVar4 != 0)) { // get modelID from InstDef iVar3 = (int)*(short *)(iVar1 + 0x3c); // ThreadMeta iVar1 = FUN_8001d094(iVar3); // if funcLevThreadsBirth is not nullptr if ((iVar1 != 0) && (*(code **)(iVar1 + 8) != (code *)0x0)) { // execute funcLevThreadsBirth, make thread for this instance // upon collision with the instance, let it run thread->funcThCollide uVar2 = (**(code **)(iVar1 + 8))(iVar4,param_2,param_1); // if not PU_WUMPA_FRUIT if (iVar3 != 2) { // useless if (iVar3 < 2) { return uVar2; } // anything except for // 7: PU_FRUIT_CRATE, // 8: PU_RANDOM_CRATE (weapon box) if (8 < iVar3) { return uVar2; } if (iVar3 < 7) { return uVar2; } } return 0; } } // make potion open teeth, // or make warpball turn around return 1; } // RB_Hazard_InterpolateValue int FUN_800ada90(ushort param_1,ushort param_2,short param_3) { uint uVar1; int iVar2; uint uVar3; ushort uVar4; uVar4 = param_1; // if current rotation is not desired rotation if ((int)(short)param_1 != (int)(short)param_2) { // get difference between them uVar3 = (int)(short)param_2 - (int)(short)param_1 & 0xfff; // if difference is huge if (0x7ff < uVar3) { // rotate a negative direction uVar3 = uVar3 - 0x1000; } uVar1 = uVar3; if ((int)uVar3 < 0) { uVar1 = -uVar3; } // rotation speed iVar2 = (int)param_3; // if rotation speed is less than // remaining needed rotation if (iVar2 <= (int)uVar1) { if ((int)uVar3 < 1) { uVar4 = param_1 & 0xfff; if (-1 < (int)uVar3) goto LAB_800adb44; // new rotation is old rotation - speed param_2 = param_1 - (short)(iVar2 * *(int *)(PTR_DAT_8008d2ac + 0x1d04) >> 5); } else { // new rotation is old rotation + speed param_2 = param_1 + (short)(iVar2 * *(int *)(PTR_DAT_8008d2ac + 0x1d04) >> 5); } } // set new rotation, which is calculated rotation, // or the desired rotation if (desired-curr < speed) uVar4 = param_2 & 0xfff; } LAB_800adb44: return (int)(short)uVar4; } // RB_MovingExplosive_ThTick // function for moving bomb, shiledbomb, or missile void FUN_800adb50(int param_1) { short sVar1; undefined *puVar2; short sVar3; code *pcVar4; undefined2 uVar5; int iVar6; undefined4 uVar7; int iVar8; int *piVar9; int iVar10; undefined2 local_30; short local_2e; undefined2 local_2c; undefined2 local_28; short local_26; undefined2 local_24; // get instance from thread iVar10 = *(int *)(param_1 + 0x34); // get object, from thread, from instance piVar9 = *(int **)(*(int *)(iVar10 + 0x6c) + 0x30); piVar9[0x12] = piVar9[0x12] + *(int *)(PTR_DAT_8008d2ac + 0x1d04); // instance -> model -> modelID sVar3 = *(short *)(*(int *)(iVar10 + 0x18) + 0x10); // if model is missile if (sVar3 == 0x29) { if ((*(uint *)(param_1 + 0x1c) & 0x800) == 0) { uVar7 = 0x4b; goto LAB_800adc00; } } else { // if model is bomb if (sVar3 == 0x3b) { uVar7 = 0x48; } else { // if model is not blue or green shield if ((sVar3 != 0x56) && (sVar3 != 0x5e)) goto LAB_800adc08; // if model is blue or green shield uVar7 = 0x59; } LAB_800adc00: // PlaySound3D_Flags, // offset 0x24 FUN_8002f31c(piVar9 + 9,uVar7,iVar10); } LAB_800adc08: // driver -> invisibleTimer if (*(int *)(*piVar9 + 0x28) == 0) { if ( (*(int *)(*piVar9 + 0x2cc) < 0) && // instance -> model -> objectID == missile (*(short *)(*(int *)(iVar10 + 0x18) + 0x10) == 0x29) ) { piVar9[0x15] = 10; } } // if driver is invisible else { // erase pointer to driver, // cause tracker can't find invisible driver *piVar9 = 0; } // "tracker" can be missile, bomb, or shield // get driver the tracker is chasing iVar8 = *piVar9; if ( // if driver is invalid (iVar8 == 0) || (*(short *)((int)piVar9 + 0x22) != 0) ) { if (*(short *)((int)piVar9 + 0x22) != 0) { *(short *)((int)piVar9 + 0x22) = *(short *)((int)piVar9 + 0x22) + -1; } } else { if (piVar9[0x15] == 0) { // get distance between tracker and the driver being chased iVar6 = (*(int *)(iVar8 + 0x2d4) >> 8) - *(int *)(iVar10 + 0x44); iVar8 = (*(int *)(iVar8 + 0x2dc) >> 8) - *(int *)(iVar10 + 0x4c); piVar9[10] = iVar6 * iVar6 + iVar8 * iVar8; LAB_800add14: // get direction, given X and Y distance to travel sVar3 = ratan2(iVar6,iVar8); } else { piVar9[0x15] = piVar9[0x15] + -1; iVar8 = *(int *)(*piVar9 + 0x20); if (iVar8 != 0) { // Get X and Y differences between two instances iVar6 = *(int *)(iVar8 + 0x44) - *(int *)(iVar10 + 0x44); iVar8 = *(int *)(iVar8 + 0x4c) - *(int *)(iVar10 + 0x4c); goto LAB_800add14; } sVar3 = *(short *)((int)piVar9 + 0x1e); piVar9[0x15] = 0; } // instance -> model -> modelID sVar1 = *(short *)(*(int *)(iVar10 + 0x18) + 0x10); // DYNAMIC_BOMB or DYNAMIC_SHIELD if ((sVar1 == 0x3b) || (sVar1 == 0x56)) { // RB_Hazard_InterpolateValue sVar3 = FUN_800ada90((int)*(short *)((int)piVar9 + 0x1e),(int)sVar3,4); *(short *)((int)piVar9 + 0x1e) = sVar3; // Sine(angle) iVar8 = FUN_8003d184((int)sVar3); // posX += velocity >> 7 *(short *)(piVar9 + 4) = (short)((uint)(iVar8 * 3) >> 7); // Cosine(angle) iVar8 = FUN_8003d1c0((int)*(short *)((int)piVar9 + 0x1e)); // posZ += velocity >> 7 sVar3 = (short)((uint)(iVar8 * 3) >> 7); *(short *)(piVar9 + 5) = sVar3; // if bomb is rolled backwards if ((*(ushort *)((int)piVar9 + 0x16) & 0x20) != 0) { *(short *)(piVar9 + 5) = -sVar3; *(short *)(piVar9 + 4) = -*(short *)(piVar9 + 4); } } // if 0x29 (MISSILE) else { // if 10 wumpa were not used if ((*(ushort *)((int)piVar9 + 0x16) & 1) == 0) { // RB_Hazard_InterpolateValue sVar3 = FUN_800ada90((int)*(short *)((int)piVar9 + 0x1e),(int)sVar3,0x40); *(short *)((int)piVar9 + 0x1e) = sVar3; // Sine(angle) iVar8 = FUN_8003d184((int)sVar3); // posX += velocity >> 8 *(short *)(piVar9 + 4) = (short)((uint)(iVar8 * 5) >> 8); // Cosine(angle) iVar8 = FUN_8003d1c0((int)*(short *)((int)piVar9 + 0x1e)); // posZ += velocity >> 8 uVar5 = (undefined2)((uint)(iVar8 * 5) >> 8); } // if 10 wumpa were used else { // RB_Hazard_InterpolateValue sVar3 = FUN_800ada90((int)*(short *)((int)piVar9 + 0x1e),(int)sVar3,0x80); *(short *)((int)piVar9 + 0x1e) = sVar3; // Sine(angle) iVar8 = FUN_8003d184((int)sVar3); // posX += velocity >> 7 *(short *)(piVar9 + 4) = (short)((uint)(iVar8 * 3) >> 7); // Cosine(angle) iVar8 = FUN_8003d1c0((int)*(short *)((int)piVar9 + 0x1e)); // posZ += velocity >> 7 uVar5 = (undefined2)((uint)(iVar8 * 3) >> 7); } // posZ += velocity *(undefined2 *)(piVar9 + 5) = uVar5; *(undefined2 *)(piVar9 + 6) = 0; *(undefined2 *)(piVar9 + 7) = 0; *(undefined2 *)((int)piVar9 + 0x1a) = *(undefined2 *)((int)piVar9 + 0x1e); // convert 3 rotation shorts into rotation matrix FUN_8006c2a4(iVar10 + 0x30,piVar9 + 6); } } // instance -> animFrame sVar3 = *(short *)(iVar10 + 0x54); // INSTANCE_GetNumAnimFrames iVar8 = FUN_80030f58(iVar10,0); // if instance is not at end of animation if ((int)sVar3 + 1 < iVar8) { // increment animation frame *(short *)(iVar10 + 0x54) = *(short *)(iVar10 + 0x54) + 1; } // if animation finished else { // go back to first frame of animation *(undefined2 *)(iVar10 + 0x54) = 0; } if ( ( // if instance -> model -> modelID == missile (*(short *)(*(int *)(iVar10 + 0x18) + 0x10) == 0x29) && // numPlyrCurrGame < 2 ((byte)PTR_DAT_8008d2ac[0x1ca8] < 2) ) && ( // DAT_800b2ae4 // "shieldbomb" // Make Instane in Particle Pool iVar8 = FUN_80040308(0,*(undefined4 *)(PTR_DAT_8008d2ac + 0x2114),&DAT_800b2ae4), iVar8 != 0 ) ) { // Position in a particle struct *(int *)(iVar8 + 0x24) = *(int *)(iVar10 + 0x44) << 8; *(int *)(iVar8 + 0x2c) = *(int *)(iVar10 + 0x48) << 8; *(int *)(iVar8 + 0x34) = *(int *)(iVar10 + 0x4c) << 8; } puVar2 = PTR_DAT_8008d2ac; // posX *(int *)(iVar10 + 0x44) = *(int *)(iVar10 + 0x44) + ((int)*(short *)(piVar9 + 4) * *(int *)(PTR_DAT_8008d2ac + 0x1d04) >> 5); // posY *(int *)(iVar10 + 0x48) = *(int *)(iVar10 + 0x48) + ((int)*(short *)((int)piVar9 + 0x12) * *(int *)(puVar2 + 0x1d04) >> 5); // posZ *(int *)(iVar10 + 0x4c) = *(int *)(iVar10 + 0x4c) + ((int)*(short *)(piVar9 + 5) * *(int *)(puVar2 + 0x1d04) >> 5); // If this is bomb if (*(short *)(*(int *)(iVar10 + 0x18) + 0x10) == 0x3b) { // if bomb is forwards if ((*(ushort *)((int)piVar9 + 0x16) & 0x20) == 0) { // rotation sVar3 = *(short *)(piVar9 + 6) + 0x200; } // if bomb is backwards else { // rotation sVar3 = *(short *)(piVar9 + 6) + -0x200; } // rotation *(short *)(piVar9 + 6) = sVar3; // convert 3 rotation shorts into rotation matrix FUN_8006c2a4(iVar10 + 0x30,piVar9 + 6); } local_30 = *(undefined2 *)(iVar10 + 0x44); local_2e = *(short *)(iVar10 + 0x48) + -0x40; local_2c = *(undefined2 *)(iVar10 + 0x4c); local_28 = *(undefined2 *)(iVar10 + 0x44); local_26 = *(short *)(iVar10 + 0x48) + 0x100; local_24 = *(undefined2 *)(iVar10 + 0x4c); DAT_1f80012c = 0x1040; DAT_1f800130 = 0; DAT_1f80012a = 0x41; // numPlyrCurrGame < 3 if ((byte)PTR_DAT_8008d2ac[0x1ca8] < 3) { DAT_1f80012a = 0x43; } DAT_1f800134 = **(undefined4 **)(PTR_DAT_8008d2ac + 0x160); // COLL_SearchTree_FindQuadblock_Touching FUN_8001eb0c(&local_30,&local_28,&DAT_1f800108,0); // RB_MakeInstanceReflective FUN_800abab0(&DAT_1f800108,iVar10); puVar2 = PTR_DAT_8008d2ac; if ((DAT_1f8002ac & 4) != 0) { // negate velocity in all directions *(short *)(piVar9 + 4) = -*(short *)(piVar9 + 4); *(short *)(piVar9 + 5) = -*(short *)(piVar9 + 5); *(short *)((int)piVar9 + 0x12) = -*(short *)((int)piVar9 + 0x12); // posX += -VelX *(int *)(iVar10 + 0x44) = *(int *)(iVar10 + 0x44) + ((int)*(short *)(piVar9 + 4) * *(int *)(puVar2 + 0x1d04) >> 5); // posY += -VelY *(int *)(iVar10 + 0x48) = *(int *)(iVar10 + 0x48) + ((int)*(short *)((int)piVar9 + 0x12) * *(int *)(puVar2 + 0x1d04) >> 5); // posZ += -VelZ *(int *)(iVar10 + 0x4c) = *(int *)(iVar10 + 0x4c) + ((int)*(short *)(piVar9 + 5) * *(int *)(puVar2 + 0x1d04) >> 5); // RB_MovingExplosive_Explode FUN_800ae478(param_1,iVar10,piVar9); return; } if (DAT_1f80014a == 0) { if (DAT_1f800146 == 0) { // hitbox local_30 = *(undefined2 *)(iVar10 + 0x44); *(undefined2 *)(iVar10 + 0x56) = 0; local_2e = *(short *)(iVar10 + 0x48) + -0x900; local_2c = *(undefined2 *)(iVar10 + 0x4c); // COLL_SearchTree_FindQuadblock_Touching FUN_8001eb0c(&local_30,&local_28,&DAT_1f800108,0); if (DAT_1f800146 == 0) goto LAB_800ae42c; iVar8 = *(int *)(PTR_DAT_8008d2ac + 0x1d04) << 2; // if instance -> model -> modelID == missile if (*(short *)(*(int *)(iVar10 + 0x18) + 0x10) == 0x29) { iVar8 = *(int *)(PTR_DAT_8008d2ac + 0x1d04) << 3; } iVar8 = (int)*(short *)((int)piVar9 + 0x12) - (iVar8 >> 5); *(undefined2 *)((int)piVar9 + 0x12) = (short)iVar8; if (iVar8 * 0x10000 >> 0x10 < -0x60) { *(undefined2 *)((int)piVar9 + 0x12) = 0xffa0; } } else { *(undefined2 *)((int)piVar9 + 0x12) = 0; // DYNAMIC_ROCKET if (*(short *)(*(int *)(iVar10 + 0x18) + 0x10) == 0x29) { // Rot_AxisAngle FUN_8005f89c(iVar10 + 0x30,&DAT_1f800178,(int)*(short *)((int)piVar9 + 0x1e)); } // position *(int *)(iVar10 + 0x44) = (int)(short)DAT_1f800124; *(int *)(iVar10 + 0x48) = (int)DAT_1f800124._2_2_ + 0x30; *(int *)(iVar10 + 0x4c) = (int)DAT_1f800128; } } else { // if instance -> model -> modelID DAT_1f800114 = *(undefined2 *)(*(int *)(iVar10 + 0x18) + 0x10); // RB_Hazard_CollLevInst iVar8 = FUN_800ad9ac(&DAT_1f800108,param_1); if (iVar8 == 1) { if ((((*DAT_1f800150 & 0x80) != 0) && (iVar8 = *(int *)(DAT_1f800150 + 0x1c), iVar8 != 0)) && ((*(int *)(iVar8 + 0x2c) != 0 && (*(short *)(iVar8 + 0x3c) == 0x70)))) { // RB_Teeth_OpenDoor FUN_800ba220(); } goto LAB_800ae42c; } } // RB_Hazard_CollideWithDrivers iVar8 = FUN_800ac220(iVar10,(int)*(short *)(piVar9 + 8),0x2400,piVar9[2]); // if no driver hit if (iVar8 == 0) { // RB_Hazard_CollideWithBucket, check Mine threadbucket iVar8 = FUN_800ac350(iVar10,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b7c), (int)*(short *)(piVar9 + 8),0x2400,piVar9[2]); // if mine was not hit if (iVar8 == 0) { // instance -> model -> modelID is not bomb if (*(short *)(*(int *)(iVar10 + 0x18) + 0x10) != 0x3b) { LAB_800ae440: if (*(short *)(piVar9 + 8) == 0) { return; } *(short *)(piVar9 + 8) = *(short *)(piVar9 + 8) + -1; return; } // if you are here, this must be a bomb // RB_Hazard_CollideWithBucket, check Tracking threadbucket iVar8 = FUN_800ac350(iVar10,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1ba4), (int)*(short *)(piVar9 + 8),0x2400,piVar9[2]); // if no collision if (iVar8 == 0) { if ((*(ushort *)((int)piVar9 + 0x16) & 2) == 0) goto LAB_800ae440; } // if bomb collides with Tracker else { // instance -> model -> modelID != missile if (*(short *)(*(int *)(iVar8 + 0x18) + 0x10) != 0x29) { // quit, warpball collisions dont matter return; } // this must be a missile // instance -> thread -> funcThCollide pcVar4 = *(code **)(*(int *)(iVar8 + 0x6c) + 0x28); // execute funcThCollide (*pcVar4)(*(int *)(iVar8 + 0x6c),param_1,pcVar4,0); } } // if mine was hit else { // instance -> thread -> funcThCollide pcVar4 = *(code **)(*(int *)(iVar8 + 0x6c) + 0x28); // execute funcThCollide (*pcVar4)(*(int *)(iVar8 + 0x6c),param_1,pcVar4,0); } } // if driver was hit else { // icon damage timer, draw icon as red *(undefined4 *)(*(int *)(*(int *)(iVar8 + 0x6c) + 0x30) + 0x4ac) = 0x1e; // thread -> inst -> object -> offset0x0 == ??? if (*(int *)(*(int *)(iVar8 + 0x6c) + 0x30) == *piVar9) { // flags *(ushort *)((int)piVar9 + 0x16) = *(ushort *)((int)piVar9 + 0x16) | 0x10; } } LAB_800ae42c: // RB_MovingExplosive_Explode FUN_800ae478(param_1,iVar10,piVar9); return; } // RB_MovingExplosive_Explode void FUN_800ae478(int param_1,int param_2,int *param_3) { undefined4 uVar1; int iVar2; // if instance -> model -> modelID == bomb if (*(short *)(*(int *)(param_2 + 0x18) + 0x10) == 0x3b) { // bomb explode uVar1 = 0x49; *(undefined4 *)(param_3[1] + 0x10) = 0; } // missile else { iVar2 = *param_3; if (iVar2 != 0) { // remove 2D square-target being drawn on the player's screen *(uint *)(iVar2 + 0x2c8) = *(uint *)(iVar2 + 0x2c8) & 0xfbffffff; } // missile explode uVar1 = 0x4c; } // play explosion sound FUN_8002f0dc(uVar1,param_2); // stop audio of rolling, // offset 0x24 of object FUN_8002e724(param_3 + 9); // RB_Burst_Init FUN_800b2154(param_2); // This thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; return; } // RB_Warpball_FadeAway void FUN_800ae524(int param_1) { short sVar1; int iVar2; int *piVar3; int iVar4; // get object from thread piVar3 = *(int **)(param_1 + 0x30); // get instance from thread iVar4 = *(int *)(param_1 + 0x34); // frame counter more than 5 if (5 < (uint)piVar3[0xc]) { iVar4 = *piVar3; if (iVar4 != 0) { // remove 2D square-target being drawn on the player's screen *(uint *)(iVar4 + 0x2c8) = *(uint *)(iVar4 + 0x2c8) & 0xfbffffff; } // remove active wrapball flag *(uint *)PTR_DAT_8008d2ac = *(uint *)PTR_DAT_8008d2ac & 0xffffefff; // This thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; return; } // frame counter sVar1 = *(short *)(piVar3 + 0xc); iVar2 = (int)sVar1 * 6; // set scale (x, y, z) *(undefined2 *)(iVar4 + 0x1c) = *(undefined2 *)(&DAT_800b2c88 + iVar2); *(undefined2 *)(iVar4 + 0x1e) = *(undefined2 *)(&DAT_800b2c8a + iVar2); *(undefined2 *)(iVar4 + 0x20) = *(undefined2 *)(&DAT_800b2c8c + iVar2); *(int *)(iVar4 + 0x48) = piVar3[0xe] + *(int *)(&DAT_800b2cac + (int)sVar1 * 4); // increment counter piVar3[0xc] = piVar3[0xc] + 1; return; } // RB_Warpball_Death void FUN_800ae604(int param_1) { int iVar1; // get object from thread iVar1 = *(int *)(param_1 + 0x30); *(undefined4 *)(iVar1 + 0x38) = *(undefined4 *)(*(int *)(param_1 + 0x34) + 0x48); *(undefined2 *)(*(int *)(iVar1 + 0xc) + 0x10) = 0; *(undefined4 *)(iVar1 + 0x30) = 0; // play sound of warpball death FUN_8002f0dc(0x4f); // stop audio of moving FUN_8002e724(iVar1 + 0x24); // ThTick_SetAndExec RB_Warpball_FadeAway FUN_800716ec(param_1,&FUN_800ae524); return; } // RB_Warpball_NewPathNode // param1 position data from LEV path // param2 driver object int FUN_800ae668(int param_1,int param_2) { byte bVar1; bool bVar2; int iVar3; uint uVar4; int iVar5; bVar2 = false; // if no driver is chased if (param_2 == 0) { LAB_800ae750: return *(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x14c) + (uint)*(byte *)(param_1 + 8) * 0xc ; } // pathPoint -> next index uVar4 = (uint)*(byte *)(param_1 + 9); // if driver is not near that point if ((uint)*(byte *)(param_2 + 0x494) != uVar4) { // if next point is valid if (*(byte *)(param_1 + 9) != 0xff) { iVar5 = 0; iVar3 = param_1; do { // path index if (*(char *)(iVar3 + 9) == -1) { bVar1 = *(byte *)(iVar3 + 8); } // path index else { bVar1 = *(byte *)(iVar3 + 9); } // path node iVar3 = *(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x14c) + (uint)bVar1 * 0xc; iVar5 = iVar5 + 1; // compare path index if (*(char *)(param_2 + 0x494) == *(char *)(iVar3 + 8)) { bVar2 = true; break; } } while (iVar5 * 0x10000 >> 0x10 < 3); } if (!bVar2) goto LAB_800ae750; uVar4 = (uint)*(byte *)(param_1 + 9); } // new path node return *(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x14c) + uVar4 * 0xc; } // RB_Warpball_Start void FUN_800ae778(undefined4 *param_1) { undefined4 uVar1; int iVar2; iVar2 = 0; uVar1 = param_1[0xf]; do { // RB_Warpball_NewPathNode uVar1 = FUN_800ae668(uVar1,*param_1); iVar2 = iVar2 + 1; } while (iVar2 * 0x10000 < 1); // node param_1[0xf] = uVar1; // RB_Warpball_NewPathNode uVar1 = FUN_800ae668(uVar1,*param_1); param_1[0x10] = uVar1; return; } // RB_Warpball_GetDriverTarget // param1 - warpball object // param2 - warpball instance int FUN_800ae7dc(int param_1,int param_2) { ushort uVar1; int iVar2; short *psVar3; int iVar4; int iVar5; int iVar6; int iVar7; short *psVar8; int iVar9; int iVar10; undefined4 local_30; undefined4 local_28; short local_24; iVar10 = 0; // if 10 wumpa fruit were not used if ((*(ushort *)(param_1 + 0x16) & 1) == 0) { // loop counter iVar7 = 0; iVar6 = 0; // for iVar7 = 0; iVar7 < 8; iVar7++ do { // check next driver until you get the driver // farthest in the lead, that has not finished race iVar6 = *(int *)(PTR_DAT_8008d2ac + (iVar6 >> 0xe) + 0x250c); if ( ( // if driver is valid (iVar6 != 0) && // if driver is not the same as driver that fired warpball (iVar6 != *(int *)(param_1 + 4)) ) && // if the race is not over for this driver ((*(uint *)(iVar6 + 0x2c8) & 0x2000000) == 0) ) { return iVar6; } // increment loop counter iVar7 = iVar7 + 1; // loop index << 0xe iVar6 = iVar7 * 0x10000; } while (iVar7 * 0x10000 >> 0x10 < 8); } // if 10 wumpa fruit were used else { // start of lev->path iVar6 = *(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x14c); // node1 psVar8 = (short *)(iVar6 + (uint)*(byte *)(*(int *)(param_1 + 0x3c) + 8) * 0xc); // node2 psVar3 = (short *)(iVar6 + (uint)*(byte *)(psVar8 + 4) * 0xc); uVar1 = *(ushort *)(iVar6 + 6); iVar9 = (uint)uVar1 * 8; // direction from node1 to node2 local_28 = CONCAT22(psVar8[1] - psVar3[1],*psVar8 - *psVar3); local_24 = psVar8[2] - psVar3[2]; // MATH_VectorNormalize FUN_8003d378(&local_28); local_30 = CONCAT22(*(short *)(param_2 + 0x48) - psVar8[1],*(short *)(param_2 + 0x44) - *psVar8) ; setCopControlWord(2,0,local_28); setCopControlWord(2,0x800,(int)local_24); setCopReg(2,0,local_30); setCopReg(2,0x800,(int)(short)(*(short *)(param_2 + 0x4c) - psVar8[2])); copFunction(2,0x406012); iVar4 = getCopReg(2,0xc800); getCopReg(2,0xd000); iVar6 = 0x7fffffff; // loop counter iVar7 = 0; iVar4 = (uint)(ushort)psVar8[3] * 8 + (iVar4 >> 0xc) + 0x200; if (uVar1 == 0) { trap(0x1c00); } if ((iVar9 == -1) && (iVar4 == -0x80000000)) { trap(0x1800); } iVar2 = 0; // for iVar7 = 0; iVar7 < 8; iVar7++ do { // pointer to structure of each player iVar5 = *(int *)(PTR_DAT_8008d2ac + (iVar2 >> 0x10) * 4 + 0x24ec); if ( ( // if pointer is not nullptr (iVar5 != 0) && ((*(uint *)(param_1 + 0x34) & 1 << (iVar2 >> 0x10 & 0x1fU)) == 0) ) && ( ( // If the race is not over for this player (*(uint *)(iVar5 + 0x2c8) & 0x2000000) == 0 && // If you are not being mask-grabbed (*(char *)(iVar5 + 0x376) != '\x05') ) ) ) { iVar2 = iVar4 % iVar9 - *(int *)(iVar5 + 0x488); if (iVar2 < 0) { iVar2 = iVar2 + iVar9; } if (iVar2 < iVar6) { iVar6 = iVar2; iVar10 = iVar5; } } // increment loop counter iVar7 = iVar7 + 1; iVar2 = iVar7 * 0x10000; } while (iVar7 * 0x10000 >> 0x10 < 8); } return iVar10; } // RB_Warpball_SetTargetDriver void FUN_800aeaac(int *param_1) { undefined *puVar1; int iVar2; int iVar3; int iVar4; int iVar5; int local_20; int local_1c; // driver being chased iVar2 = *param_1; // if driver is valid if (iVar2 != 0) { // driver -> distanceToFinish iVar5 = *(int *)(iVar2 + 0x488); // path node iVar2 = *(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x14c) + (uint)*(byte *)(iVar2 + 0x495) * 0xc; iVar4 = iVar2; while ((iVar3 = iVar2, puVar1 = PTR_DAT_8008d2ac, // distance is less than path node distance iVar5 <= (int)((uint)*(ushort *)(iVar3 + 6) << 3) && // path node is not first node (iVar3 != *(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x14c)))) { // RB_Warpball_NewPathNode iVar2 = FUN_800ae668(iVar3,*param_1); iVar4 = iVar3; } iVar2 = 0; local_1c = 0; local_20 = param_1[0xf]; if ((*(ushort *)((int)param_1 + 0x16) & 4) == 0) { iVar5 = 0; do { iVar5 = *(int *)((int)&local_20 + (iVar5 >> 0xe)); if (iVar5 != 0) { iVar3 = 0; do { if (iVar5 == iVar4) { *(ushort *)((int)param_1 + 0x16) = *(ushort *)((int)param_1 + 0x16) & 0xfff7 | 4; break; } if (*(byte *)(iVar5 + 0xb) != 0xff) { // path node local_1c = *(int *)(*(int *)(puVar1 + 0x160) + 0x14c) + (uint)*(byte *)(iVar5 + 0xb) * 0xc; } iVar3 = iVar3 + 1; // path node iVar5 = *(int *)(*(int *)(puVar1 + 0x160) + 0x14c) + (uint)*(byte *)(iVar5 + 10) * 0xc; } while (iVar3 * 0x10000 >> 0x10 < 3); } iVar2 = iVar2 + 1; } while ((iVar2 * 0x10000 >> 0x10 < 2) && (iVar5 = iVar2 * 0x10000, (*(ushort *)((int)param_1 + 0x16) & 4) == 0)); } // path node iVar2 = param_1[0xf]; iVar5 = 0; do { if (iVar2 == iVar4) { *(ushort *)((int)param_1 + 0x16) = *(ushort *)((int)param_1 + 0x16) & 0xfff7 | 4; return; } // RB_Warpball_NewPathNode iVar2 = FUN_800ae668(iVar2,*param_1); iVar5 = iVar5 + 1; } while (iVar5 * 0x10000 >> 0x10 < 3); } return; } // RB_Warpball_SeekDriver // param1 warpball object void FUN_800aece0(undefined4 *param_1,uint param_2,int param_3) { int iVar1; if ( // if driver is valid (param_3 != 0) && // if path node index is valid ((param_2 & 0xff) != 0xff) ) { // pointer to path node iVar1 = *(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x14c) + (param_2 & 0xff) * 0xc; while ( // driver distanceToFinish < pathNode -> distanceToFinish (*(int *)(param_3 + 0x488) <= (int)((uint)*(ushort *)(iVar1 + 6) << 3) && // node is not first node (iVar1 != *(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x14c)) ) ) { // RB_Warpball_NewPathNode iVar1 = FUN_800ae668(iVar1,*param_1); } // path index = pathPtr2 - pathPtr1 *(char *)(param_1 + 0x11) = (char)((iVar1 - *(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x14c)) * -0x55555555 >> 2); } return; } // RB_Warpball_TurnAround void FUN_800aede0(int param_1) { ushort uVar1; undefined *puVar2; short sVar3; undefined2 uVar4; int *piVar5; int iVar6; // thread -> object piVar5 = *(int **)(param_1 + 0x30); uVar1 = *(ushort *)((int)piVar5 + 0x16); // thread -> instance iVar6 = *(int *)(param_1 + 0x34); if ( // if not snap to point??? ((uVar1 & 0x100) != 0) || // if no driver is being chased (*piVar5 == 0) ) { if ((uVar1 & 4) != 0) { *(ushort *)((int)piVar5 + 0x16) = uVar1 & 0xfffb | 0x208; } // turn around // velX = -velX // velZ = -velZ // velY = -velY *(short *)(piVar5 + 4) = -*(short *)(piVar5 + 4); *(short *)(piVar5 + 5) = -*(short *)(piVar5 + 5); *(short *)((int)piVar5 + 0x12) = -*(short *)((int)piVar5 + 0x12); puVar2 = PTR_DAT_8008d2ac; // posX += velX *(int *)(iVar6 + 0x44) = *(int *)(iVar6 + 0x44) + ((int)*(short *)(piVar5 + 4) * *(int *)(PTR_DAT_8008d2ac + 0x1d04) >> 5); // posY += velY *(int *)(iVar6 + 0x48) = *(int *)(iVar6 + 0x48) + ((int)*(short *)((int)piVar5 + 0x12) * *(int *)(puVar2 + 0x1d04) >> 5); // posZ += velZ *(int *)(iVar6 + 0x4c) = *(int *)(iVar6 + 0x4c) + ((int)*(short *)(piVar5 + 5) * *(int *)(puVar2 + 0x1d04) >> 5); // increment counter sVar3 = *(short *)((int)piVar5 + 0x52) + 1; *(short *)((int)piVar5 + 0x52) = sVar3; if ( // if count too high (0x78 < sVar3) || // pointer to driver being chased, // is null, so warpball is chasing nobody (*piVar5 == 0) ) { *(undefined4 *)(piVar5[1] + 0x10) = 0; // play sound warpball death FUN_8002f0dc(0x4f,iVar6); // RB_Warpball_Death FUN_800ae604(param_1); } // if attempted to turn around 3 times if ((*(ushort *)((int)piVar5 + 0x52) & 3) == 0) { // move backwards on path // start = end (current) piVar5[0x10] = piVar5[0xf]; // set new end to 10 path indices ahead of current piVar5[0xf] = *(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x14c) + (uint)*(byte *)(piVar5[0xf] + 10) * 0xc; } // rotation uVar4 = ratan2((int)*(short *)piVar5[0xf] - *(int *)(iVar6 + 0x44), (int)((short *)piVar5[0xf])[2] - *(int *)(iVar6 + 0x4c)); // rotation *(undefined2 *)((int)piVar5 + 0x1a) = uVar4; } return; } // RB_Warpball_ThTick void FUN_800aef9c(int param_1) { ushort uVar1; bool bVar2; undefined *puVar3; short sVar4; undefined2 uVar5; int iVar6; int iVar7; undefined4 uVar8; code *pcVar9; uint uVar10; int *piVar11; short sVar12; ushort uVar13; short *psVar14; int iVar15; short *psVar16; int iVar17; int iVar18; int iVar19; undefined2 local_48; short local_46; undefined2 local_44; undefined2 local_40; short local_3e; undefined2 local_3c; int local_38; int local_34; int local_30; // thread -> instance iVar17 = *(int *)(param_1 + 0x34); // thread -> object piVar11 = *(int **)(param_1 + 0x30); // save short inst position in object *(undefined2 *)(piVar11 + 0x13) = *(undefined2 *)(iVar17 + 0x44); *(undefined2 *)((int)piVar11 + 0x4e) = *(undefined2 *)(iVar17 + 0x48); *(undefined2 *)(piVar11 + 0x14) = *(undefined2 *)(iVar17 + 0x4c); // instance -> animFrame sVar12 = *(short *)(iVar17 + 0x54); // INSTANCE_GetNumAnimFrames iVar6 = FUN_80030f58(iVar17,0); // if animation is finished if ((int)sVar12 + 1 < iVar6) { // increment animFrame *(short *)(iVar17 + 0x54) = *(short *)(iVar17 + 0x54) + 1; } // if animation is finished else { // restart animation *(undefined2 *)(iVar17 + 0x54) = 0; } // If driver pointer is not zero if (*piVar11 != 0) { if ( // if you are being mask-grabbed (*(char *)(*piVar11 + 0x376) == '\x05') && ((*(ushort *)((int)piVar11 + 0x16) & 4) != 0) ) { *(ushort *)((int)piVar11 + 0x16) = *(ushort *)((int)piVar11 + 0x16) & 0xfffb | 0x18; // pointer to desired position on path, given path index iVar6 = *(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x14c) + (uint)*(byte *)((int)piVar11 + 0x45) * 0xc; piVar11[0xf] = iVar6; // RB_Warpball_NewPathNode iVar6 = FUN_800ae668(iVar6,*piVar11); piVar11[0x10] = iVar6; // RB_Warpball_GetDriverTarget iVar6 = FUN_800ae7dc(piVar11,iVar17); // set driver being chased by warpball *piVar11 = iVar6; // RB_Warpball_SetTargetDriver FUN_800aeaac(piVar11); } if ((*(ushort *)((int)piVar11 + 0x16) & 0x204) == 0) { // RB_Warpball_GetDriverTarget iVar6 = FUN_800ae7dc(piVar11,iVar17); // set driver being chased by warpball *piVar11 = iVar6; // if driver exists if (iVar6 != 0) { // RB_Warpball_SetTargetDriver FUN_800aeaac(piVar11); } } } // get driver the warpball is chasing iVar6 = *piVar11; *(ushort *)((int)piVar11 + 0x16) = *(ushort *)((int)piVar11 + 0x16) & 0xfdff; // if no driver is bein chased if (iVar6 == 0) { LAB_800af580: puVar3 = PTR_DAT_8008d2ac; // move in the direction the warpball was shot in // increase posX by velX *(int *)(iVar17 + 0x44) = *(int *)(iVar17 + 0x44) + ((int)*(short *)(piVar11 + 4) * *(int *)(PTR_DAT_8008d2ac + 0x1d04) >> 5); // increase posY by velY *(int *)(iVar17 + 0x48) = *(int *)(iVar17 + 0x48) + ((int)*(short *)((int)piVar11 + 0x12) * *(int *)(puVar3 + 0x1d04) >> 5); // increase posZ by velZ *(int *)(iVar17 + 0x4c) = *(int *)(iVar17 + 0x4c) + ((int)*(short *)(piVar11 + 5) * *(int *)(puVar3 + 0x1d04) >> 5); } else { // get distance from tracker to target iVar19 = (*(int *)(iVar6 + 0x2d4) >> 8) - *(int *)(iVar17 + 0x44); iVar18 = (*(int *)(iVar6 + 0x2dc) >> 8) - *(int *)(iVar17 + 0x4c); iVar15 = (*(int *)(iVar6 + 0x2d8) >> 8) - *(int *)(iVar17 + 0x48); iVar7 = iVar19 * iVar19 + iVar18 * iVar18; // save distance piVar11[10] = iVar7; // RB_GetThread_ClosestTracker uVar8 = FUN_800b28c0(iVar6); // give tracker thread to driver *(undefined4 *)(*piVar11 + 0x4a4) = uVar8; if ((piVar11[5] & 0xc0000U) != 0) { sVar12 = 0x100; if ((*(ushort *)((int)piVar11 + 0x16) & 4) == 0) { // pointer to position on path psVar16 = (short *)piVar11[0xf]; // distance from instance to next point iVar19 = (int)*psVar16 - *(int *)(iVar17 + 0x44); iVar18 = (int)psVar16[2] - *(int *)(iVar17 + 0x4c); iVar15 = (int)psVar16[1] - *(int *)(iVar17 + 0x48); // distance to next point iVar7 = iVar19 * iVar19 + iVar18 * iVar18; // low distance if (iVar7 < 0x4000) { // snap to next point??? *(ushort *)((int)piVar11 + 0x16) = *(ushort *)((int)piVar11 + 0x16) & 0xfff7 | 0x100; } else { sVar12 = 0x100; if (iVar7 < 0x24000) { sVar12 = 0x400; } } } if ((iVar7 < 0x90000) && (iVar6 = 0x400 - (iVar7 >> 9), sVar12 = (short)iVar6, iVar6 * 0x10000 >> 0x10 < 0x100)) { sVar12 = 0x100; } if (0 < *(short *)(piVar11 + 8)) { sVar12 = 0x40; } sVar4 = ratan2(iVar19,iVar18); *(undefined2 *)(piVar11 + 6) = 0; // RB_Hazard_InterpolateValue uVar5 = FUN_800ada90((int)*(short *)((int)piVar11 + 0x1a),(int)sVar4,(int)sVar12); *(undefined2 *)((int)piVar11 + 0x1a) = uVar5; *(undefined2 *)(piVar11 + 7) = 0; // Sine(angle) iVar6 = FUN_8003d184((int)*(short *)((int)piVar11 + 0x1a)); *(short *)(piVar11 + 4) = (short)((uint)(iVar6 * 7) >> 8); // Cosine(angle) iVar6 = FUN_8003d1c0((int)*(short *)((int)piVar11 + 0x1a)); *(short *)(piVar11 + 5) = (short)((uint)(iVar6 * 7) >> 8); if (iVar15 < 1) { if (iVar15 < 0) { iVar6 = (uint)*(ushort *)((int)piVar11 + 0x12) - ((*(int *)(PTR_DAT_8008d2ac + 0x1d04) << 2) >> 5); *(undefined2 *)((int)piVar11 + 0x12) = (short)iVar6; if (iVar6 * 0x10000 >> 0x10 < iVar15) { *(undefined2 *)((int)piVar11 + 0x12) = (short)iVar15; } uVar5 = 0xffa0; if (*(short *)((int)piVar11 + 0x12) < -0x60) goto LAB_800af34c; } } else { iVar6 = (uint)*(ushort *)((int)piVar11 + 0x12) + ((*(int *)(PTR_DAT_8008d2ac + 0x1d04) << 2) >> 5); *(undefined2 *)((int)piVar11 + 0x12) = (short)iVar6; if (iVar15 < iVar6 * 0x10000 >> 0x10) { *(undefined2 *)((int)piVar11 + 0x12) = (short)iVar15; } if (0x60 < *(short *)((int)piVar11 + 0x12)) { uVar5 = 0x60; LAB_800af34c: *(undefined2 *)((int)piVar11 + 0x12) = uVar5; } } goto LAB_800af580; } // path nodes psVar16 = (short *)piVar11[0x10]; psVar14 = (short *)piVar11[0xf]; // distance local_38 = (int)*psVar16 - (int)*psVar14; local_34 = (int)psVar16[1] - (int)psVar14[1]; local_30 = (int)psVar16[2] - (int)psVar14[2]; // distance iVar6 = FUN_8006c618(local_38 * local_38 + local_34 * local_34 + local_30 * local_30); iVar7 = piVar11[0xb] + (*(int *)(PTR_DAT_8008d2ac + 0x1d04) * 0x70 >> 5); if (iVar6 <= iVar7) { iVar7 = iVar7 - iVar6; do { psVar14 = psVar16; // RB_Warpball_NewPathNode psVar16 = (short *)FUN_800ae668(psVar14,*piVar11); // distance local_38 = (int)*psVar16 - (int)*psVar14; local_34 = (int)psVar16[1] - (int)psVar14[1]; local_30 = (int)psVar16[2] - (int)psVar14[2]; // distance iVar6 = FUN_8006c618(local_38 * local_38 + local_34 * local_34 + local_30 * local_30); bVar2 = iVar6 <= iVar7; iVar7 = iVar7 - iVar6; } while (bVar2); iVar7 = iVar7 + iVar6; } piVar11[0xb] = iVar7; // path nodes *(short **)(piVar11 + 0xf) = psVar14; *(short **)(piVar11 + 0x10) = psVar16; if (iVar6 == 0) { iVar15 = 0; } else { // percentage between points iVar15 = (iVar7 << 0xc) / iVar6; if (iVar6 == 0) { trap(0x1c00); } if ((iVar6 == -1) && (iVar7 << 0xc == -0x80000000)) { trap(0x1800); } } // position = path node + distance * percentage *(int *)(iVar17 + 0x44) = (int)*psVar14 + (local_38 * iVar15 >> 0xc); *(int *)(iVar17 + 0x48) = (int)psVar14[1] + (local_34 * iVar15 >> 0xc); *(int *)(iVar17 + 0x4c) = (int)psVar14[2] + (local_30 * iVar15 >> 0xc); // adjust rotation, given distX and distZ uVar8 = ratan2(local_38,local_30); *(undefined2 *)((int)piVar11 + 0x1a) = (short)uVar8; // Sine(angle) iVar6 = FUN_8003d184(uVar8); // velX *(short *)(piVar11 + 4) = (short)((uint)(iVar6 * 7) >> 8); // Cosine(angle) iVar6 = FUN_8003d1c0(uVar8); // velZ *(short *)(piVar11 + 5) = (short)((uint)(iVar6 * 7) >> 8); // velY *(undefined2 *)((int)piVar11 + 0x12) = 0; } // PlaySound3D_Flags // warpball moving FUN_8002f31c(piVar11 + 9,0x4e,iVar17); local_48 = *(undefined2 *)(iVar17 + 0x44); local_46 = *(short *)(iVar17 + 0x48) + -0x80; local_44 = *(undefined2 *)(iVar17 + 0x4c); local_40 = *(undefined2 *)(iVar17 + 0x44); local_3e = *(short *)(iVar17 + 0x48) + 0x80; local_3c = *(undefined2 *)(iVar17 + 0x4c); DAT_1f80012c = 0x1040; DAT_1f800130 = 0; // If you have 3 or 4 screens DAT_1f80012a = 0x41; // numPlyrCurrGame < 3 if ((byte)PTR_DAT_8008d2ac[0x1ca8] < 3) { DAT_1f80012a = 0x43; } DAT_1f800134 = **(undefined4 **)(PTR_DAT_8008d2ac + 0x160); // COLL_SearchTree_FindQuadblock_Touching FUN_8001eb0c(&local_48,&local_40,&DAT_1f800108,0); // RB_MakeInstanceReflective FUN_800abab0(&DAT_1f800108,iVar17); if ((DAT_1f8002ac & 4) != 0) { // RB_Warpball_TurnAround FUN_800aede0(param_1); } if (DAT_1f80014a != 0) { DAT_1f800114 = 0x36; // RB_Hazard_CollLevInst iVar6 = FUN_800ad9ac(&DAT_1f800108,param_1); if (iVar6 == 1) { // RB_Warpball_TurnAround FUN_800aede0(param_1); } } if (DAT_1f800146 == 0) { // hitbox local_48 = *(undefined2 *)(iVar17 + 0x44); local_46 = *(short *)(iVar17 + 0x48) + -0x900; local_44 = *(undefined2 *)(iVar17 + 0x4c); // COLL_SearchTree_FindQuadblock_Touching FUN_8001eb0c(&local_48,&local_40,&DAT_1f800108,0); if (DAT_1f800146 != 0) { *(ushort *)((int)piVar11 + 0x16) = *(ushort *)((int)piVar11 + 0x16) | 0x100; if (*(char *)(DAT_1f800188 + 0x3e) != -1) { *(char *)((int)piVar11 + 0x45) = *(char *)(DAT_1f800188 + 0x3e); } if (DAT_1f800146 != 0) goto LAB_800af82c; } if (((*(ushort *)((int)piVar11 + 0x16) & 0xc) != 0) || (*piVar11 == 0)) { // RB_Warpball_TurnAround FUN_800aede0(param_1); } } else { *(ushort *)((int)piVar11 + 0x16) = *(ushort *)((int)piVar11 + 0x16) | 0x100; if (*(char *)(DAT_1f800188 + 0x3e) != -1) { *(char *)((int)piVar11 + 0x45) = *(char *)(DAT_1f800188 + 0x3e); } *(undefined2 *)((int)piVar11 + 0x12) = 0; if (((*(ushort *)((int)piVar11 + 0x16) & 0xc) != 0) && (*(int *)(iVar17 + 0x48) < (int)DAT_1f800124._2_2_)) { *(int *)(iVar17 + 0x48) = (int)DAT_1f800124._2_2_; *(char *)(iVar17 + 0x50) = *(char *)(DAT_1f800188 + 0x14) + -1; } } LAB_800af82c: if ( (DAT_800b2c84 != 0) && // if particle effect (piVar11[3] != 0) ) { // update particle effect that surrounds warpball *(int *)(piVar11[3] + 0x24) = *(int *)(iVar17 + 0x44) << 8; *(int *)(piVar11[3] + 0x2c) = (*(int *)(iVar17 + 0x48) + (uint)DAT_800b2c84) * 0x100; *(int *)(piVar11[3] + 0x34) = *(int *)(iVar17 + 0x4c) << 8; uVar10 = (uint)DAT_800b2c84; *(int *)(piVar11[3] + 0x3c) = uVar10 << 8; *(int *)(piVar11[3] + 0x44) = uVar10 * 0xc0; *(int *)(piVar11[3] + 0x4c) = uVar10 << 7; *(char *)(piVar11[3] + 0x18) = *(char *)(iVar17 + 0x50) + '\x01'; *(undefined2 *)(piVar11[3] + 0x10) = 0xffff; } // RB_Hazard_CollideWithDrivers iVar6 = FUN_800ac220(iVar17,(int)*(short *)(piVar11 + 8),0x9000,piVar11[2]); // if no driver was hit if (iVar6 == 0) { // RB_Hazard_CollideWithBucket, check Mine threadbucket iVar6 = FUN_800ac350(iVar17,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b7c), (int)*(short *)(piVar11 + 8),0x2400,piVar11[2]); // if mine was hit by mine if (iVar6 != 0) { // Get OnDestroy pcVar9 = *(code **)(*(int *)(iVar6 + 0x6c) + 0x28); // destroy the mine (*pcVar9)(*(int *)(iVar6 + 0x6c),param_1,pcVar9,0); } } // if a driver was hit else { // get the driver object iVar6 = *(int *)(*(int *)(iVar6 + 0x6c) + 0x30); // if driver hit was not the driver who used the weapon if (iVar6 != piVar11[1]) { uVar13 = *(ushort *)((int)piVar11 + 0x16) & 4; // RB_Hazard_HurtDriver (blasted) FUN_800ac1b0(iVar6,2,piVar11[1],0); // icon damage timer, draw icon as red *(undefined4 *)(iVar6 + 0x4ac) = 0x1e; uVar1 = *(ushort *)((int)piVar11 + 0x16); *(ushort *)((int)piVar11 + 0x16) = uVar1 | 0x40; // if the driver hit, was the driver in first place if ( ( // if 10 wumpa were not used ((uVar1 & 1) == 0) && // if driver hit, was the intended target (*piVar11 == iVar6) ) || // driver hit was in first place (*(short *)(iVar6 + 0x482) == 0) ) { *(undefined4 *)(piVar11[1] + 0x10) = 0; // RB_Warpball_Death FUN_800ae604(param_1); return; } piVar11[0xd] = piVar11[0xd] | 1 << ((uint)*(byte *)(iVar6 + 0x4a) & 0x1f); puVar3 = PTR_DAT_8008d2ac; iVar7 = (int)*(short *)(iVar6 + 0x482); // loop counter iVar15 = iVar7; // for iVar15 = iVar7; iVar15 < 8; iVar15++ while (iVar15 < 8) { if (*(int *)(puVar3 + ((iVar7 << 0x10) >> 0xe) + 0x250c) != 0) { piVar11[0xd] = piVar11[0xd] | 1 << ((uint)*(byte *)(*(int *)(puVar3 + ((iVar7 << 0x10) >> 0xe) + 0x250c) + 0x4a) & 0x1f); } // increment loop counter iVar7 = iVar7 + 1; iVar15 = iVar7 * 0x10000 >> 0x10; } // if the targetted driver was just blasted if (*piVar11 == iVar6) { // no target is being seeked *(ushort *)((int)piVar11 + 0x16) = *(ushort *)((int)piVar11 + 0x16) & 0xfffb; // RB_Warpball_GetDriverTarget iVar17 = FUN_800ae7dc(piVar11,iVar17); // set driver being chased by warpball *piVar11 = iVar17; // if no driver is found if (iVar17 == 0) { *(undefined4 *)(piVar11[1] + 0x10) = 0; // RB_Warpball_Death FUN_800ae604(param_1); } else { // RB_Warpball_SetTargetDriver FUN_800aeaac(piVar11); } // if driver is targetted if (uVar13 != 0) { // RB_Warpball_SeekDriver FUN_800aece0(piVar11,(uint)*(byte *)(iVar6 + 0x495),iVar6); } if ( // if intended target was destroyed ((*(ushort *)((int)piVar11 + 0x16) & 4) == 0) && // there was a target last frame (uVar13 != 0) ) { // path point index if (*(byte *)(piVar11 + 0x11) != 0xff) { // get pathNode iVar6 = *(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x14c) + (uint)*(byte *)(piVar11 + 0x11) * 0xc; piVar11[0xf] = iVar6; // RB_Warpball_NewPathNode iVar6 = FUN_800ae668(iVar6,*piVar11); piVar11[0x10] = iVar6; } *(ushort *)((int)piVar11 + 0x16) = *(ushort *)((int)piVar11 + 0x16) | 8; } } } } // frameCount_DontHurtParent if (*(short *)(piVar11 + 8) != 0) { *(short *)(piVar11 + 8) = *(short *)(piVar11 + 8) + -1; } return; } // RB_MaskWeapon_FadeAway void FUN_800afb70(int param_1) { ushort uVar1; short sVar2; int iVar3; int iVar4; int iVar5; // thread -> instance iVar4 = *(int *)(param_1 + 0x34); // instance -> thread -> object iVar5 = *(int *)(*(int *)(iVar4 + 0x6c) + 0x30); // Sine(angle) iVar3 = FUN_8003d184((int)*(short *)(iVar5 + 2)); DAT_1f800130._2_2_ = 0x40; DAT_1f800130._0_2_ = (undefined2) ((((int)((uint)*(ushort *)(iVar5 + 6) << 0x10) >> 0x15) * -4 + 0x40) * iVar3 >> 0xc); // Cosine(angle) iVar3 = FUN_8003d1c0((int)*(short *)(iVar5 + 2)); DAT_1f800134._0_2_ = (undefined2) ((((int)((uint)*(ushort *)(iVar5 + 6) << 0x10) >> 0x15) * -4 + 0x40) * iVar3 >> 0xc); // Copy Matrix: // To: Mask // From: Player FUN_800313c8(iVar4,*(undefined4 *)(*(int *)(*(int *)(param_1 + 0xc) + 0x30) + 0x1c),&DAT_1f800130) ; // alter angle for rotation *(short *)(iVar5 + 2) = *(short *)(iVar5 + 2) + -0x100; // decrease scale (x, y, z) *(short *)(iVar4 + 0x1c) = *(short *)(iVar4 + 0x1c) + -0x100; *(short *)(iVar4 + 0x20) = *(short *)(iVar4 + 0x20) + -0x100; *(short *)(iVar4 + 0x1e) = *(short *)(iVar4 + 0x1e) + -0x100; DAT_1f800130._0_2_ = 0; DAT_1f800130._2_2_ = 0x40; DAT_1f800134._0_2_ = 0; // Copy Matrix: // To: Mask (Beam within mask obj?) // From: Player FUN_800313c8(*(undefined4 *)(iVar5 + 8), *(undefined4 *)(*(int *)(*(int *)(param_1 + 0xc) + 0x30) + 0x1c),&DAT_1f800130); DAT_1f800128 = 0; DAT_1f80012a = *(undefined2 *)(iVar5 + 2); DAT_1f80012c._0_2_ = 0; // convert 3 rotation shorts into rotation matrix FUN_8006c2a4(&DAT_1f800108,&DAT_1f800128); iVar3 = *(int *)(iVar5 + 8) + 0x30; FUN_8006c3b0(iVar3,iVar3,&DAT_1f800108); // decrease scale (x, y, z) *(short *)(*(int *)(iVar5 + 8) + 0x1c) = *(short *)(*(int *)(iVar5 + 8) + 0x1c) + -0x100; *(short *)(*(int *)(iVar5 + 8) + 0x1e) = *(short *)(*(int *)(iVar5 + 8) + 0x1e) + -0x100; *(short *)(*(int *)(iVar5 + 8) + 0x20) = *(short *)(*(int *)(iVar5 + 8) + 0x20) + -0x100; uVar1 = *(ushort *)(*(int *)(iVar5 + 8) + 0x22); if (uVar1 < 0x1000) { *(short *)(*(int *)(iVar5 + 8) + 0x22) = uVar1 + 0x200; } if (*(short *)(iVar5 + 6) < 0x200) { sVar2 = *(short *)(iVar5 + 6) + *(short *)(PTR_DAT_8008d2ac + 0x1d04); *(short *)(iVar5 + 6) = sVar2; if (0x200 < sVar2) { *(undefined2 *)(iVar5 + 6) = 0x200; } } else { // INSTANCE_Death FUN_80030aa8(*(undefined4 *)(iVar5 + 8)); // This thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; } return; } // RB_MaskWeapon_ThTick void FUN_800afdbc(int param_1) { short sVar1; undefined *puVar2; undefined *puVar3; int iVar4; uint uVar5; int iVar6; int iVar7; int iVar8; int iVar9; int iVar10; int iVar11; puVar2 = PTR_DAT_8008d2ac; // (mask) thread -> instance iVar10 = *(int *)(param_1 + 0x34); // instance -> thread -> object iVar9 = *(int *)(*(int *)(iVar10 + 0x6c) + 0x30); // (mask) thread -> (player) parentthread -> instance iVar11 = *(int *)(*(int *)(param_1 + 0xc) + 0x34); // thread -> parentthread -> (Driver*)object -> invisibleTimer == 0 if (*(int *)(*(int *)(*(int *)(param_1 + 0xc) + 0x30) + 0x28) == 0) { // If driver is visible // iteration counter iVar4 = 0; // numPlyrCurrGame is not zero if (PTR_DAT_8008d2ac[0x1ca8] != '\0') { iVar8 = 0x168; iVar6 = 0; iVar7 = iVar10; // For iVar4 = 0; iVar4 < numPlyrCurrGame; iVar4++ do { puVar3 = puVar2 + iVar8; iVar8 = iVar8 + 0x110; *(undefined **)(iVar7 + 0x74) = puVar3; iVar7 = iVar7 + 0x88; // keep count of loop iteration iVar4 = iVar4 + 1; *(undefined **)(*(int *)(iVar9 + 8) + iVar6 + 0x74) = puVar3; iVar6 = iVar6 + 0x88; } while (iVar4 < (int)(uint)(byte)puVar2[0x1ca8]); } } // if driver is invisible else { // count loop iteration uVar5 = 0; // if numPlyrCurrGame is not zero if (PTR_DAT_8008d2ac[0x1ca8] != '\0') { iVar7 = 0; iVar4 = iVar10; // for uVar5 = 0; uVar5 < numPlyrCurrGame; uVar5++ do { if (uVar5 != (uint)*(byte *)(*(int *)(*(int *)(param_1 + 0xc) + 0x30) + 0x4a)) { *(undefined4 *)(iVar4 + 0x74) = 0; *(undefined4 *)(*(int *)(iVar9 + 8) + iVar7 + 0x74) = 0; } iVar4 = iVar4 + 0x88; // increment loop counter uVar5 = uVar5 + 1; iVar7 = iVar7 + 0x88; } while ((int)uVar5 < (int)(uint)(byte)puVar2[0x1ca8]); } } // if driverInst is not reflective if ((*(uint *)(iVar11 + 0x28) & 0x4000) == 0) { // mask is not reflective *(uint *)(iVar10 + 0x28) = *(uint *)(iVar10 + 0x28) & 0xffffbfff; } // if driverInst is reflective else { // mask is reflective *(uint *)(iVar10 + 0x28) = *(uint *)(iVar10 + 0x28) | 0x4000; // copy split line *(undefined2 *)(iVar10 + 0x56) = *(undefined2 *)(iVar11 + 0x56); // mask beam is reflective *(uint *)(*(int *)(iVar9 + 8) + 0x28) = *(uint *)(*(int *)(iVar9 + 8) + 0x28) | 0x4000; // copy split line *(undefined2 *)(*(int *)(iVar9 + 8) + 0x56) = *(undefined2 *)(iVar11 + 0x56); } *(undefined *)(iVar10 + 0x50) = *(undefined *)(iVar11 + 0x50); *(undefined *)(iVar10 + 0x51) = *(undefined *)(iVar11 + 0x51); // Sine(angle) iVar4 = FUN_8003d184((int)*(short *)(iVar9 + 2)); DAT_1f800130._0_2_ = (short)(((iVar4 << 6) >> 0xc) * (int)*(short *)(iVar9 + 0x12) >> 0xc); DAT_1f800130._2_2_ = *(short *)(&DAT_800b2cc4 + (int)*(short *)(*(int *)(iVar9 + 8) + 0x54) * 2) + 0x40; // Cosine(angle) iVar4 = FUN_8003d1c0((int)*(short *)(iVar9 + 2)); DAT_1f800128 = 0; DAT_1f800134._0_2_ = (short)(((iVar4 << 6) >> 0xc) * (int)*(short *)(iVar9 + 0x12) >> 0xc); DAT_1f80012a = *(undefined2 *)(iVar9 + 2); DAT_1f80012c._0_2_ = 0; if ((*(ushort *)(iVar9 + 4) & 1) == 0) { // Copy Matrix: // To: Mask // From: Player FUN_800313c8(iVar10,iVar11,&DAT_1f800130); // convert 3 rotation shorts into rotation matrix FUN_8006c2a4(&DAT_1f800108,&DAT_1f800128); FUN_8006c3b0(iVar10 + 0x30,iVar10 + 0x30,&DAT_1f800108); } else { *(int *)(iVar10 + 0x44) = (int)*(short *)(iVar9 + 0xc) + (int)(short)DAT_1f800130; *(int *)(iVar10 + 0x48) = (int)*(short *)(iVar9 + 0xe) + (int)DAT_1f800130._2_2_; *(int *)(iVar10 + 0x4c) = (int)*(short *)(iVar9 + 0x10) + (int)(short)DAT_1f800134; // convert 3 rotation shorts into rotation matrix FUN_8006c2a4(iVar10 + 0x30,&DAT_1f800128); } DAT_1f800130._0_2_ = 0; DAT_1f800130._2_2_ = 0x40; DAT_1f800134._0_2_ = 0; DAT_1f800128 = 0; DAT_1f80012a = *(undefined2 *)(iVar9 + 2); DAT_1f80012c._0_2_ = 0; if ((*(ushort *)(iVar9 + 4) & 1) == 0) { FUN_800313c8(*(undefined4 *)(iVar9 + 8),iVar11,&DAT_1f800130); // convert 3 rotation shorts into rotation matrix FUN_8006c2a4(&DAT_1f800108,&DAT_1f800128); // mask -> beam -> object iVar11 = *(int *)(iVar9 + 8) + 0x30; FUN_8006c3b0(iVar11,iVar11,&DAT_1f800108); } else { *(int *)(*(int *)(iVar9 + 8) + 0x44) = (int)*(short *)(iVar9 + 0xc); *(int *)(*(int *)(iVar9 + 8) + 0x48) = (int)*(short *)(iVar9 + 0xe) + (int)DAT_1f800130._2_2_; *(int *)(*(int *)(iVar9 + 8) + 0x4c) = (int)*(short *)(iVar9 + 0x10) + (int)(short)DAT_1f800134; // convert 3 rotation shorts into rotation matrix FUN_8006c2a4(*(int *)(iVar9 + 8) + 0x30,&DAT_1f800128); } // get animFrame sVar1 = *(short *)(*(int *)(iVar9 + 8) + 0x54); // INSTANCE_GetNumAnimFrames iVar11 = FUN_80030f58(*(int *)(iVar9 + 8),0); // if animation is not finished if ((int)sVar1 + 1 < iVar11) { // increment animation frame *(short *)(*(int *)(iVar9 + 8) + 0x54) = *(short *)(*(int *)(iVar9 + 8) + 0x54) + 1; } // if animation is finished else { // restart animation *(undefined2 *)(*(int *)(iVar9 + 8) + 0x54) = 0; } // adjust rotation *(short *)(iVar9 + 2) = *(short *)(iVar9 + 2) + -0x100; // If duration is over if (*(short *)(iVar9 + 6) == 0) { // end duration *(undefined2 *)(iVar9 + 6) = 0; // ThTick_SetAndExec RB_MaskWeapon_FadeAway FUN_800716ec(param_1,FUN_800afb70); } // if duration is not over else { // reduce duration time by milliseconds iVar11 = (uint)*(ushort *)(iVar9 + 6) - (uint)*(ushort *)(PTR_DAT_8008d2ac + 0x1d04); // set new duration *(undefined2 *)(iVar9 + 6) = (short)iVar11; // check for negatives if (iVar11 * 0x10000 < 0) { *(undefined2 *)(iVar9 + 6) = 0; } } // make Beam visible *(uint *)(*(int *)(iVar9 + 8) + 0x28) = *(uint *)(*(int *)(iVar9 + 8) + 0x28) & 0xffffff7f; // Set Beam Scale (x, y, z) *(undefined2 *)(*(int *)(iVar9 + 8) + 0x1c) = *(undefined2 *)(iVar9 + 0x12); *(undefined2 *)(*(int *)(iVar9 + 8) + 0x1e) = *(undefined2 *)(iVar9 + 0x12); *(undefined2 *)(*(int *)(iVar9 + 8) + 0x20) = *(undefined2 *)(iVar9 + 0x12); *(undefined2 *)(*(int *)(iVar9 + 8) + 0x22) = 0; // make Head visible *(uint *)(iVar10 + 0x28) = *(uint *)(iVar10 + 0x28) & 0xffffff7f; // Set Head Scale (x, y, z) *(undefined2 *)(iVar10 + 0x1c) = *(undefined2 *)(iVar9 + 0x12); *(undefined2 *)(iVar10 + 0x1e) = *(undefined2 *)(iVar9 + 0x12); *(undefined2 *)(iVar10 + 0x20) = *(undefined2 *)(iVar9 + 0x12); return; } // RB_ShieldDark_Pop void FUN_800b0278(int param_1) { int *piVar1; int iVar2; undefined2 local_18; undefined2 local_16; undefined2 local_14; // This is a weapon thread // get instance from thread iVar2 = *(int *)(param_1 + 0x34); // get object from thread from instance piVar1 = *(int **)(*(int *)(iVar2 + 0x6c) + 0x30); local_18 = 0; local_16 = 0; local_14 = 0; // get the driver that shot this weapon // Copy matrix // To: shield instance, highlight instance, etc // From: thread (shield) -> parentthread (player) -> object (driver) -> instance FUN_800313c8(iVar2,*(undefined4 *)(*(int *)(*(int *)(param_1 + 0xc) + 0x30) + 0x1c),&local_18); FUN_800313c8(piVar1[2],*(undefined4 *)(*(int *)(*(int *)(param_1 + 0xc) + 0x30) + 0x1c),&local_18) ; // set rotation *(undefined4 *)(iVar2 + 0x30) = 0x1000; *(undefined4 *)(iVar2 + 0x34) = 0; *(undefined4 *)(iVar2 + 0x38) = 0x1000; *(undefined4 *)(iVar2 + 0x3c) = 0; *(undefined2 *)(iVar2 + 0x40) = 0x1000; // set rotation *(undefined4 *)(piVar1[2] + 0x30) = 0x1000; *(undefined4 *)(piVar1[2] + 0x34) = 0; *(undefined4 *)(piVar1[2] + 0x38) = 0x1000; *(undefined4 *)(piVar1[2] + 0x3c) = 0; *(undefined2 *)(piVar1[2] + 0x40) = 0x1000; // if animation is not done if (*piVar1 < 0xb) { // set scale *(undefined2 *)(iVar2 + 0x1c) = *(undefined2 *)(&DAT_800b2d14 + *piVar1 * 4); *(undefined2 *)(iVar2 + 0x1e) = *(undefined2 *)(&DAT_800b2d16 + *piVar1 * 4); *(undefined2 *)(iVar2 + 0x20) = *(undefined2 *)(&DAT_800b2d14 + *piVar1 * 4); // set scale *(undefined2 *)(piVar1[2] + 0x1c) = *(undefined2 *)(&DAT_800b2d14 + *piVar1 * 4); *(undefined2 *)(piVar1[2] + 0x1e) = *(undefined2 *)(&DAT_800b2d16 + *piVar1 * 4); *(undefined2 *)(piVar1[2] + 0x20) = *(undefined2 *)(&DAT_800b2d14 + *piVar1 * 4); *piVar1 = *piVar1 + 1; } // if animation is done else { // play 3D sound for "green shield fade away" FUN_8002f0dc(0x58,iVar2); // INSTANCE_Death FUN_80030aa8(piVar1[2]); FUN_80030aa8(piVar1[3]); // this thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; } return; } // RB_ShieldDark_ThTick void FUN_800b0454(int param_1) { ushort uVar1; undefined2 uVar2; undefined *puVar3; short sVar4; undefined *puVar5; int iVar6; undefined4 uVar7; int iVar8; uint uVar9; int iVar10; undefined4 *puVar11; int iVar12; undefined4 uVar13; undefined4 uVar14; int *piVar15; int iVar16; undefined2 local_20; undefined2 local_1e; undefined2 local_1c; // thread -> instance iVar16 = *(int *)(param_1 + 0x34); // instance -> thread -> object piVar15 = *(int **)(*(int *)(iVar16 + 0x6c) + 0x30); local_20 = 0; local_1e = 0; local_1c = 0; // if highlight cooldown is gone if (*(short *)((int)piVar15 + 0x16) == 0) { *(short *)((int)piVar15 + 0x12) = *(short *)((int)piVar15 + 0x12) + 0x100; // highlight is now visible *(uint *)(piVar15[3] + 0x28) = *(uint *)(piVar15[3] + 0x28) & 0xffffff7f; iVar10 = (int)*(short *)((int)piVar15 + 0x12); iVar8 = iVar10; if (iVar10 < 0) { iVar8 = iVar10 + 0xfff; } // if highlight is finished if ((iVar10 + (iVar8 >> 0xc) * -0x1000) * 0x10000 >> 0x10 == 0x400) { // cooldown is 30 frames (one second) *(undefined2 *)((int)piVar15 + 0x16) = 0x1e; *(undefined2 *)((int)piVar15 + 0x12) = 0xc00; // make highlight invisible *(uint *)(piVar15[3] + 0x28) = *(uint *)(piVar15[3] + 0x28) | 0x80; } } // if highlight cooldown is not done else { // decrease counter, make invisible when this is zero *(short *)((int)piVar15 + 0x16) = *(short *)((int)piVar15 + 0x16) + -1; // make invisible *(uint *)(piVar15[3] + 0x28) = *(uint *)(piVar15[3] + 0x28) | 0x80; // if timer runs out (last frame) if (*(short *)((int)piVar15 + 0x16) == 0) { // make visible *(uint *)(piVar15[3] + 0x28) = *(uint *)(piVar15[3] + 0x28) & 0xffffff7f; } } puVar3 = PTR_DAT_8008d2ac; // If the driver that used this weapon is visible // thread -> parentthread -> object -> invisibility == 0 if (*(int *)(*(int *)(*(int *)(param_1 + 0xc) + 0x30) + 0x28) == 0) { // loop counter iVar8 = 0; // if numPlyrCurrGame is not zero if (PTR_DAT_8008d2ac[0x1ca8] != '\0') { iVar12 = 0x168; iVar6 = 0; iVar10 = iVar16; // for iVar8 = 0; iVar8 < numPlyrCurrGame; iVar8++ do { puVar5 = puVar3 + iVar12; iVar12 = iVar12 + 0x110; *(undefined **)(iVar10 + 0x74) = puVar5; iVar10 = iVar10 + 0x88; *(undefined **)(piVar15[2] + iVar6 + 0x74) = puVar5; // increment loop counter iVar8 = iVar8 + 1; *(undefined **)(piVar15[3] + iVar6 + 0x74) = puVar5; iVar6 = iVar6 + 0x88; } while (iVar8 < (int)(uint)(byte)puVar3[0x1ca8]); } } else { // loop counter uVar9 = 0; // if numPlyrCurrGame is not zero if (PTR_DAT_8008d2ac[0x1ca8] != '\0') { iVar10 = 0; iVar8 = iVar16; // for iVar9 = 0; iVar9 < numPlyrCurrGame; iVar9++ do { if (uVar9 != (uint)*(byte *)(*(int *)(*(int *)(param_1 + 0xc) + 0x30) + 0x4a)) { *(undefined4 *)(iVar8 + 0x74) = 0; *(undefined4 *)(piVar15[2] + iVar10 + 0x74) = 0; *(undefined4 *)(piVar15[3] + iVar10 + 0x74) = 0; } iVar8 = iVar8 + 0x88; // increment loop counter uVar9 = uVar9 + 1; iVar10 = iVar10 + 0x88; } while ((int)uVar9 < (int)(uint)(byte)puVar3[0x1ca8]); } } // Copy matrix // To: shield instance, highlight instance, etc // From: thread (shield) -> parentthread (player) -> object (driver) -> instance FUN_800313c8(iVar16,*(undefined4 *)(*(int *)(*(int *)(param_1 + 0xc) + 0x30) + 0x1c),&local_20); FUN_800313c8(piVar15[2],*(undefined4 *)(*(int *)(*(int *)(param_1 + 0xc) + 0x30) + 0x1c),&local_20 ); FUN_800313c8(piVar15[3],*(undefined4 *)(*(int *)(*(int *)(param_1 + 0xc) + 0x30) + 0x1c),&local_20 ); // set rotation variables *(undefined4 *)(iVar16 + 0x30) = 0x1000; *(undefined4 *)(iVar16 + 0x34) = 0; *(undefined4 *)(iVar16 + 0x38) = 0x1000; *(undefined4 *)(iVar16 + 0x3c) = 0; *(undefined2 *)(iVar16 + 0x40) = 0x1000; // set rotation variables *(undefined4 *)(piVar15[2] + 0x30) = 0x1000; *(undefined4 *)(piVar15[2] + 0x34) = 0; *(undefined4 *)(piVar15[2] + 0x38) = 0x1000; *(undefined4 *)(piVar15[2] + 0x3c) = 0; *(undefined2 *)(piVar15[2] + 0x40) = 0x1000; // convert 3 rotation shorts into rotation matrix FUN_8006c2a4(piVar15[3] + 0x30,piVar15 + 4); puVar3 = PTR_DAT_8008d2ac; // if animation is not done if (*piVar15 < 8) { // set scale *(undefined2 *)(iVar16 + 0x1c) = *(undefined2 *)(&DAT_800b2cf4 + *piVar15 * 4); *(undefined2 *)(iVar16 + 0x1e) = *(undefined2 *)(&DAT_800b2cf6 + *piVar15 * 4); *(undefined2 *)(iVar16 + 0x20) = *(undefined2 *)(&DAT_800b2cf4 + *piVar15 * 4); // set scale *(undefined2 *)(piVar15[2] + 0x1c) = *(undefined2 *)(&DAT_800b2cf4 + *piVar15 * 4); *(undefined2 *)(piVar15[2] + 0x1e) = *(undefined2 *)(&DAT_800b2cf6 + *piVar15 * 4); *(undefined2 *)(piVar15[2] + 0x20) = *(undefined2 *)(&DAT_800b2cf4 + *piVar15 * 4); *piVar15 = *piVar15 + 1; } // if animation is done else { // set scale *(undefined2 *)(iVar16 + 0x1c) = (&DAT_800b2d40)[(*(uint *)(PTR_DAT_8008d2ac + 0x1cec) % 6) * 2]; *(undefined2 *)(iVar16 + 0x1e) = (&DAT_800b2d42)[(*(uint *)(puVar3 + 0x1cec) % 6) * 2]; *(undefined2 *)(iVar16 + 0x20) = (&DAT_800b2d40)[(*(uint *)(puVar3 + 0x1cec) % 6) * 2]; // set scale *(undefined2 *)(piVar15[2] + 0x1c) = (&DAT_800b2d40)[(*(uint *)(puVar3 + 0x1cec) % 6) * 2]; *(undefined2 *)(piVar15[2] + 0x1e) = (&DAT_800b2d42)[(*(uint *)(puVar3 + 0x1cec) % 6) * 2]; *(undefined2 *)(piVar15[2] + 0x20) = (&DAT_800b2d40)[(*(uint *)(puVar3 + 0x1cec) % 6) * 2]; // set scale *(undefined2 *)(piVar15[3] + 0x1c) = (&DAT_800b2d40)[(*(uint *)(puVar3 + 0x1cec) % 6) * 2]; *(undefined2 *)(piVar15[3] + 0x1e) = (&DAT_800b2d42)[(*(uint *)(puVar3 + 0x1cec) % 6) * 2]; *(undefined2 *)(piVar15[3] + 0x20) = (&DAT_800b2d40)[(*(uint *)(puVar3 + 0x1cec) % 6) * 2]; } // if this is not a blue shield, // meaning it must fade eventually if ((*(ushort *)((int)piVar15 + 6) & 4) == 0) { // duration sVar4 = *(short *)(piVar15 + 1); // if out of time if (*(short *)(piVar15 + 1) == 0) { // erase bubble instance from driver *(undefined4 *)(*(int *)(*(int *)(param_1 + 0xc) + 0x30) + 0x14) = 0; goto LAB_800b0d6c; } // subtract 32ms by hand, instead of using in-game timer? *(ushort *)(piVar15 + 1) = sVar4 - 0x20U; iVar8 = (uint)(ushort)(sVar4 - 0x20U) << 0x10; // last full second? if (iVar8 >> 0x10 < 0x780) { sVar4 = (short)(((0x3c - (iVar8 >> 0x15)) * 0xc00) / 0x3c) + 0x400; // transparency *(short *)(iVar16 + 0x22) = sVar4; *(short *)(piVar15[2] + 0x22) = sVar4; *(short *)(piVar15[3] + 0x22) = sVar4; } } puVar3 = PTR_DAT_8008d2ac; uVar1 = *(ushort *)((int)piVar15 + 6); if ( ( (((uVar1 & 1) != 0) || ((uVar1 & 8) != 0)) || ( // thread -> parentthread -> (Driver*)object iVar8 = *(int *)(*(int *)(param_1 + 0xc) + 0x30), // if race ended for this driver (*(uint *)(iVar8 + 0x2c8) & 0x2000000) != 0 ) ) // if driver is being mask grabbed || (*(char *)(iVar8 + 0x376) == '\x05') ) { // thread -> parentthread -> (Driver*)object iVar16 = *(int *)(*(int *)(param_1 + 0xc) + 0x30); if ((*(ushort *)((int)piVar15 + 6) & 8) != 0) { *(undefined2 *)(PTR_DAT_8008d2ac + (uint)*(byte *)(iVar16 + 0x4a) * 0x110 + 0x17a) = 0x1fff; // tileView based on... // thread -> parentthread -> (Driver*)object -> index *(undefined2 *) (puVar3 + (uint)*(byte *)(*(int *)(*(int *)(param_1 + 0xc) + 0x30) + 0x4a) * 0x110 + 0x17c) = 0x1000; // tileView based on... // thread -> parentthread -> (Driver*)object -> index *(undefined2 *) (puVar3 + (uint)*(byte *)(*(int *)(*(int *)(param_1 + 0xc) + 0x30) + 0x4a) * 0x110 + 0x17e) = 0xff78; } *piVar15 = 0; *(undefined4 *)(iVar16 + 0x14) = 0; // RB_ShieldDark_Pop is from being mask-grabbed, // or from colliding with another player // execute, then assign per-frame funcPtr to thread FUN_800716ec(param_1,FUN_800b0278); return; } if ((uVar1 & 2) == 0) { return; } *(undefined4 *)(iVar8 + 0x14) = 0; *(char *)(iVar8 + 0x55c) = *(char *)(iVar8 + 0x55c) + '\x01'; FUN_80026440(iVar8,8,0); FUN_800264c0(iVar8,8,0x7f); // green shield uVar7 = 0x5e; if ((*(ushort *)((int)piVar15 + 6) & 4) != 0) { // blue shield uVar7 = 0x56; } // create a thread, get an instance // 0x200 flag = MediumStackPool // 0xd = "other" thread bucket iVar10 = FUN_800309a4(uVar7,s_shieldbomb_800aba04,0x200,0xd,FUN_800adb50,0x58, // driver -> instane -> thread *(undefined4 *)(*(int *)(iVar8 + 0x1c) + 0x6c)); // if driver is not an AI (human) if ((*(uint *)(iVar8 + 0x2c8) & 0x100000) == 0) { // make driver talk FUN_8002cbe8(0xd,(int)(short)(&DAT_80086e84)[*(byte *)(iVar8 + 0x4a)],0x10); } uVar13 = *(undefined4 *)(iVar16 + 0x34); uVar14 = *(undefined4 *)(iVar16 + 0x38); uVar7 = *(undefined4 *)(iVar16 + 0x3c); *(undefined4 *)(iVar10 + 0x30) = *(undefined4 *)(iVar16 + 0x30); *(undefined4 *)(iVar10 + 0x34) = uVar13; *(undefined4 *)(iVar10 + 0x38) = uVar14; *(undefined4 *)(iVar10 + 0x3c) = uVar7; uVar13 = *(undefined4 *)(iVar16 + 0x44); uVar14 = *(undefined4 *)(iVar16 + 0x48); uVar7 = *(undefined4 *)(iVar16 + 0x4c); *(undefined4 *)(iVar10 + 0x40) = *(undefined4 *)(iVar16 + 0x40); *(undefined4 *)(iVar10 + 0x44) = uVar13; *(undefined4 *)(iVar10 + 0x48) = uVar14; *(undefined4 *)(iVar10 + 0x4c) = uVar7; // set funcThDestroy to remove instance from instance pool *(undefined4 *)(*(int *)(iVar10 + 0x6c) + 0x24) = 0x80041dfc; // set scale (x, y, z) *(undefined2 *)(iVar10 + 0x1c) = 0x400; *(undefined2 *)(iVar10 + 0x1e) = 0x400; *(undefined2 *)(iVar10 + 0x20) = 0x400; // a 4th scale value??? *(undefined2 *)(iVar10 + 0x22) = 0x400; // get object from thread puVar11 = *(undefined4 **)(*(int *)(iVar10 + 0x6c) + 0x30); // frame timer to zero *(undefined2 *)((int)puVar11 + 0x16) = 0; puVar11[1] = iVar8; *puVar11 = 0; puVar11[0x12] = 0; puVar11[9] = 0; uVar2 = *(undefined2 *)(iVar8 + 0x39a); *(undefined2 *)((int)puVar11 + 0x12) = 0; *(undefined2 *)((int)puVar11 + 0x1e) = uVar2; *(short *)(puVar11 + 4) = (short)((int)*(short *)(*(int *)(iVar8 + 0x1c) + 0x34) * 3 >> 7); sVar4 = *(short *)(*(int *)(iVar8 + 0x1c) + 0x40); *(undefined2 *)(puVar11 + 8) = 10; *(undefined2 *)((int)puVar11 + 0x22) = 0; *(short *)(puVar11 + 5) = (short)((int)sVar4 * 3 >> 7); puVar11[2] = *(undefined4 *)(iVar8 + 0x1c); LAB_800b0d6c: // green shield fade away sound FUN_8002f0dc(0x58,iVar16); // INSTANCE_Death // shield and highlight FUN_80030aa8(piVar15[2]); FUN_80030aa8(piVar15[3]); // This thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; return; } // RB_Player_ToggleInvisible void FUN_800b0dbc(void) { undefined *puVar1; undefined *puVar2; int iVar3; uint uVar4; int iVar5; int iVar6; int iVar7; puVar2 = PTR_DAT_8008d2ac; // player thread iVar7 = *(int *)(PTR_DAT_8008d2ac + 0x1b2c); puVar1 = PTR_DAT_8008d2ac; // loop through player threads while (iVar7 != 0) { // driver object iVar6 = *(int *)(iVar7 + 0x30); PTR_DAT_8008d2ac = puVar1; if ( // if driver is invisible (*(int *)(iVar6 + 0x28) != 0) && (uVar4 = 0, puVar2[0x1ca8] != '\0') ) { iVar5 = 0; // loop through InstanceDrawPerPlayer do { // if this is not the screen of the invisible driver if (uVar4 != (uint)*(byte *)(iVar6 + 0x4a)) { // make driver instance invisible on this screen iVar3 = *(int *)(iVar6 + 0x1c) + iVar5; *(uint *)(iVar3 + 0xb8) = *(uint *)(iVar3 + 0xb8) & 0xffffffbf; } uVar4 = uVar4 + 1; iVar5 = iVar5 + 0x88; } while ((int)uVar4 < (int)(uint)(byte)puVar1[0x1ca8]); } // thread -> sibling thread iVar7 = *(int *)(iVar7 + 0x10); puVar1 = PTR_DAT_8008d2ac; } PTR_DAT_8008d2ac = puVar1; return; } // RB_Player_ToggleFlicker (after damage in battle mode) void FUN_800b0e68(void) { undefined *puVar1; undefined *puVar2; int iVar3; int iVar4; int iVar5; int iVar6; int iVar7; puVar2 = PTR_DAT_8008d2ac; // player thread iVar6 = *(int *)(PTR_DAT_8008d2ac + 0x1b2c); puVar1 = PTR_DAT_8008d2ac; while (iVar6 != 0) { // driver object iVar7 = *(int *)(iVar6 + 0x30); PTR_DAT_8008d2ac = puVar1; if ( ( // invincible timer (0x2a0 < *(int *)(iVar7 + 0x24)) && // odd number frames ((*(uint *)(puVar2 + 0x1cec) & 1) != 0) ) && (iVar5 = 0, puVar2[0x1ca8] != '\0') ) { iVar4 = 0; // on all screens do { // make driver invisible iVar3 = *(int *)(iVar7 + 0x1c) + iVar4; iVar5 = iVar5 + 1; *(uint *)(iVar3 + 0xb8) = *(uint *)(iVar3 + 0xb8) & 0xffffffbf; iVar4 = iVar4 + 0x88; } while (iVar5 < (int)(uint)(byte)puVar1[0x1ca8]); } // thread -> sibling thread iVar6 = *(int *)(iVar6 + 0x10); puVar1 = PTR_DAT_8008d2ac; } PTR_DAT_8008d2ac = puVar1; return; } // RB_RainCloud_FadeAway void FUN_800b0f1c(int param_1) { int iVar1; int iVar2; int *piVar3; // thread -> instance iVar1 = *(int *)(param_1 + 0x34); // thread -> parent -> instance iVar2 = *(int *)(*(int *)(param_1 + 0xc) + 0x34); // instance -> thread -> object piVar3 = *(int **)(*(int *)(iVar1 + 0x6c) + 0x30); // set X and Y *(int *)(iVar1 + 0x44) = *(int *)(iVar1 + 0x44) + *(int *)(iVar2 + 0x44) >> 1; *(int *)(iVar1 + 0x48) = *(int *)(iVar1 + 0x48) + *(int *)(iVar2 + 0x48) + 0x80 >> 1; iVar2 = *(int *)(iVar2 + 0x4c); // shrink scale (x, y, z) *(short *)(iVar1 + 0x1c) = *(short *)(iVar1 + 0x1c) + -0x100; *(short *)(iVar1 + 0x1e) = *(short *)(iVar1 + 0x1e) + -0x100; *(short *)(iVar1 + 0x20) = *(short *)(iVar1 + 0x20) + -0x100; // set Z *(int *)(iVar1 + 0x4c) = *(int *)(iVar1 + 0x4c) + iVar2 >> 1; iVar2 = *piVar3; // animation? *(int *)(iVar2 + 8) = *(int *)(iVar2 + 8) + -2; if (*(short *)(iVar1 + 0x1c) < 0) { FUN_8003112c(PTR_DAT_8008d2ac + 0x19e8,*piVar3); // This thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; } return; } // RB_RainCloud_ThTick void FUN_800b1000(int param_1) { short sVar1; int iVar2; int iVar3; int iVar4; int iVar5; int iVar6; // get instance from thread iVar3 = *(int *)(param_1 + 0x34); // get object from thread iVar5 = *(int *)(param_1 + 0x30); // get animation frame from instance sVar1 = *(short *)(iVar3 + 0x54); // thread -> parentthread -> object iVar4 = *(int *)(*(int *)(param_1 + 0xc) + 0x30); // thread -> parentthread -> instance iVar6 = *(int *)(*(int *)(param_1 + 0xc) + 0x34); // INSTANCE_GetNumAnimFrames iVar2 = FUN_80030f58(iVar3,0); // if you have not reached the end of the animation if ((int)sVar1 + 1 < iVar2) { // increment animation frame *(short *)(iVar3 + 0x54) = *(short *)(iVar3 + 0x54) + 1; } // if animation is done else { // restart animation *(undefined2 *)(iVar3 + 0x54) = 0; } // set scale of one instance to half the scale of another *(undefined2 *)(iVar3 + 0x1c) = (short)((int)*(short *)(iVar3 + 0x1c) + (int)*(short *)(iVar6 + 0x1c) >> 1); *(undefined2 *)(iVar3 + 0x1e) = (short)((int)*(short *)(iVar3 + 0x1e) + (int)*(short *)(iVar6 + 0x1e) >> 1); *(undefined2 *)(iVar3 + 0x20) = (short)((int)*(short *)(iVar3 + 0x20) + (int)*(short *)(iVar6 + 0x20) >> 1); *(int *)(iVar3 + 0x44) = *(int *)(iVar3 + 0x44) + *(int *)(iVar6 + 0x44) >> 1; *(int *)(iVar3 + 0x48) = *(int *)(iVar3 + 0x48) + *(int *)(iVar6 + 0x48) + ((int)*(short *)(iVar3 + 0x1e) * 5 >> 7) >> 1; *(int *)(iVar3 + 0x4c) = *(int *)(iVar3 + 0x4c) + *(int *)(iVar6 + 0x4c) >> 1; // if driver is not using mask weapon if ((*(uint *)(iVar4 + 0x2c8) & 0x800000) == 0) { // if ms remaining is not zero if (*(short *)(iVar5 + 4) != 0) { // reduce by elapsed time iVar2 = (uint)*(ushort *)(iVar5 + 4) - (uint)*(ushort *)(PTR_DAT_8008d2ac + 0x1d04); *(undefined2 *)(iVar5 + 4) = (short)iVar2; // solve for negatives if (iVar2 * 0x10000 < 0) { *(undefined2 *)(iVar5 + 4) = 0; } if (*(short *)(iVar5 + 6) != 1) { return; } // If your weapon is "no weapon" if (*(char *)(iVar4 + 0x36) == '\x0f') { return; } // at this point, you must have a weapon if (*(short *)(iVar4 + 0x3c) != 0) { return; } // set weapon to "weapon roulette" to make it spin *(undefined *)(iVar4 + 0x36) = 0x10; // you are always 5 frames away from new weapon, // so you get weapon 5 frames after cloud dies *(undefined2 *)(iVar4 + 0x3a) = 5; // you hold zero of this item *(undefined *)(iVar4 + 0x37) = 0; return; } // at this point, you must not // have cloud above you *(undefined2 *)(iVar5 + 4) = 0; // erase cloudTh pointer *(undefined4 *)(iVar4 + 0x4a0) = 0; if ( (*(short *)(iVar5 + 6) == 1) && // If your weapon is not "no weapon" (*(char *)(iVar4 + 0x36) != '\x0f') ) { // erase item roll timer *(undefined2 *)(iVar4 + 0x3a) = 0; // pick random weapon for driver FUN_80060f0c(iVar4,0x800b0000); } } else { *(undefined2 *)(iVar5 + 4) = 0; // erase pointer to cloud thread *(undefined4 *)(iVar4 + 0x4a0) = 0; } // ThTick_SetAndExec RB_RainCloud_FadeAway FUN_800716ec(param_1,FUN_800b0f1c); return; } // RB_RainCloud_Init void FUN_800b1220(int param_1) { int iVar1; int iVar2; undefined4 uVar3; int *piVar4; // if driver -> cloudTh is invalid if (*(int *)(param_1 + 0x4a0) == 0) { // make a thread for "cloud", and return an instance // 0x300 flag = SmallStackPool // 0xd = "other" thread bucket iVar1 = FUN_800309a4(0x42,s_cloud1_800aba10,0x300,0xd,FUN_800b1000,8, // driver -> instance -> thread *(undefined4 *)(*(int *)(param_1 + 0x1c) + 0x6c)); // set funcThDestroy to remove instance from instance pool *(undefined4 *)(*(int *)(iVar1 + 0x6c) + 0x24) = 0x80041dfc; // Set rotation, 5 direction vectors *(undefined4 *)(iVar1 + 0x30) = 0x1000; *(undefined4 *)(iVar1 + 0x34) = 0; *(undefined4 *)(iVar1 + 0x38) = 0x1000; *(undefined4 *)(iVar1 + 0x3c) = 0; *(undefined2 *)(iVar1 + 0x40) = 0x1000; // cloud->posX = driver->posX *(undefined4 *)(iVar1 + 0x44) = *(undefined4 *)(*(int *)(param_1 + 0x1c) + 0x44); // cloud->posY = driver->posY + 0x80 *(int *)(iVar1 + 0x48) = *(int *)(*(int *)(param_1 + 0x1c) + 0x48) + 0x80; // cloud->posZ = driver->posZ uVar3 = *(undefined4 *)(*(int *)(param_1 + 0x1c) + 0x4c); *(undefined2 *)(iVar1 + 0x22) = 0x800; *(undefined4 *)(iVar1 + 0x4c) = uVar3; *(undefined *)(iVar1 + 0x50) = *(undefined *)(*(int *)(param_1 + 0x1c) + 0x50); *(undefined *)(iVar1 + 0x51) = *(undefined *)(*(int *)(param_1 + 0x1c) + 0x51); // JitPool_Add -- Rain Pool iVar2 = FUN_800310d4(PTR_DAT_8008d2ac + 0x19e8); if (iVar2 != 0) { *(undefined4 *)(iVar2 + 8) = 0x1e; *(int *)(iVar2 + 0x24) = iVar1; *(undefined2 *)(iVar2 + 0xc) = 0; *(undefined2 *)(iVar2 + 0xe) = 0; *(undefined2 *)(iVar2 + 0x10) = 0; *(undefined2 *)(iVar2 + 0x14) = 0; *(undefined2 *)(iVar2 + 0x16) = 0xffd8; *(undefined2 *)(iVar2 + 0x18) = 0; *(undefined2 *)(iVar2 + 0x1c) = *(undefined2 *)(*(int *)(param_1 + 0x1c) + 0x44); *(short *)(iVar2 + 0x1e) = *(short *)(*(int *)(param_1 + 0x1c) + 0x48) + 0x80; *(undefined2 *)(iVar2 + 0x20) = *(undefined2 *)(*(int *)(param_1 + 0x1c) + 0x4c); } // raincloud instance -> thread -> object piVar4 = *(int **)(*(int *)(iVar1 + 0x6c) + 0x30); // set duration to about 7.68s *(undefined2 *)(piVar4 + 1) = 0x1e00; *piVar4 = iVar2; // used by driver 0x50a *(undefined2 *)((int)piVar4 + 6) = 1; if ( // if driver has no weapon (*(char *)(param_1 + 0x36) == '\x0f') || (*(short *)(param_1 + 0x3c) != 0) ) { // used by driver 0x50a *(undefined2 *)((int)piVar4 + 6) = 0; } // driver -> thread = cloud -> thread *(undefined4 *)(param_1 + 0x4a0) = *(undefined4 *)(iVar1 + 0x6c); } // if cloud already exists, and // driver hits another red potion else { // set duration to 8 seconds *(undefined2 *)(*(int *)(*(int *)(param_1 + 0x4a0) + 0x30) + 4) = 0x1e00; // random number iVar1 = FUN_8003ea28(0x42); // random (related to driver offset 0x50a) *(undefined2 *)(*(int *)(*(int *)(param_1 + 0x4a0) + 0x30) + 6) = (short)((iVar1 % 400) / 100); } return; } // RB_Explosion_InitPotion void FUN_800b1458(int param_1) { int iVar1; int iVar2; undefined4 uVar3; undefined4 uVar4; undefined4 uVar5; int iVar6; int local_40; char *local_3c; undefined4 local_38; undefined4 local_34; code *local_30; undefined4 local_2c; undefined4 local_28; // green explosion local_40 = 0x45; // if instance -> model -> modelID == red beaker if (*(short *)(*(int *)(param_1 + 0x18) + 0x10) == 0x46) { // red explosion local_40 = 0x44; } // string local_3c = s_shatter1_800aba28; // 0x300 flag = SmallStackPool local_38 = 0x300; // 0xd = "other" thread bucket local_34 = 0xd; // RB_Explosion_ThTick local_30 = FUN_800ad92c; local_2c = 0; local_28 = 0; // create thread for shatter iVar1 = FUN_80030a50(&local_40); iVar6 = 0; *(uint *)(iVar1 + 0x28) = *(uint *)(iVar1 + 0x28) | 0xa00; // copy position and rotation from one instance to the other uVar3 = *(undefined4 *)(param_1 + 0x34); uVar4 = *(undefined4 *)(param_1 + 0x38); uVar5 = *(undefined4 *)(param_1 + 0x3c); *(undefined4 *)(iVar1 + 0x30) = *(undefined4 *)(param_1 + 0x30); *(undefined4 *)(iVar1 + 0x34) = uVar3; *(undefined4 *)(iVar1 + 0x38) = uVar4; *(undefined4 *)(iVar1 + 0x3c) = uVar5; uVar3 = *(undefined4 *)(param_1 + 0x44); uVar4 = *(undefined4 *)(param_1 + 0x48); uVar5 = *(undefined4 *)(param_1 + 0x4c); *(undefined4 *)(iVar1 + 0x40) = *(undefined4 *)(param_1 + 0x40); *(undefined4 *)(iVar1 + 0x44) = uVar3; *(undefined4 *)(iVar1 + 0x48) = uVar4; *(undefined4 *)(iVar1 + 0x4c) = uVar5; // set funcThDestroy to remove instance from instance pool *(undefined4 *)(*(int *)(iVar1 + 0x6c) + 0x24) = 0x80041dfc; // set scale *(undefined2 *)(iVar1 + 0x20) = 0x800; *(undefined2 *)(iVar1 + 0x1e) = 0x800; *(undefined2 *)(iVar1 + 0x1c) = 0x800; // particles for potion shatter do { // DAT_800b2d58 // unknown // Create instance in particle pool iVar2 = FUN_80040308(0,*(undefined4 *)(PTR_DAT_8008d2ac + 0x2118),&DAT_800b2d58); if (iVar2 != 0) { *(int *)(iVar2 + 0x24) = *(int *)(iVar2 + 0x24) + *(int *)(iVar1 + 0x44) * 0x100; *(int *)(iVar2 + 0x2c) = *(int *)(iVar2 + 0x2c) + *(int *)(iVar1 + 0x48) * 0x100; *(int *)(iVar2 + 0x34) = *(int *)(iVar2 + 0x34) + *(int *)(iVar1 + 0x4c) * 0x100; if (local_40 == 0x45) { *(undefined4 *)(iVar2 + 0x5c) = 1; *(undefined4 *)(iVar2 + 100) = 0xc800; } else { *(undefined4 *)(iVar2 + 0x5c) = 0xc800; *(undefined4 *)(iVar2 + 100) = 1; } *(undefined4 *)(iVar2 + 0x6c) = 1; // Particle_FuncPtr_PotionShatter *(undefined4 *)(iVar2 + 0x1c) = 0x8003eae0; *(int *)(iVar2 + 0x20) = local_40; } iVar6 = iVar6 + 1; } while (iVar6 < 5); // RB_Potion_OnShatter_TeethSearch FUN_800ac638(param_1); return; } // RB_Explosion_InitGeneric void FUN_800b1630(int param_1) { int iVar1; undefined4 uVar2; undefined4 uVar3; undefined4 uVar4; undefined4 local_28; char *local_24; undefined4 local_20; undefined4 local_1c; code *local_18; undefined4 local_14; undefined4 local_10; // Spawn exploded box local_28 = 0x26; // string local_24 = s_explosion1_800aba44; // 0x300 flag = SmallStackPool local_20 = 0x300; // 0xd = "other" thread bucket local_1c = 0xd; // RB_Explosion_ThTick local_18 = FUN_800ad92c; local_14 = 0; local_10 = 0; // create thread for explosion iVar1 = FUN_80030a50(&local_28); // copy position and rotation from one instance to the other uVar2 = *(undefined4 *)(param_1 + 0x34); uVar3 = *(undefined4 *)(param_1 + 0x38); uVar4 = *(undefined4 *)(param_1 + 0x3c); *(undefined4 *)(iVar1 + 0x30) = *(undefined4 *)(param_1 + 0x30); *(undefined4 *)(iVar1 + 0x34) = uVar2; *(undefined4 *)(iVar1 + 0x38) = uVar3; *(undefined4 *)(iVar1 + 0x3c) = uVar4; uVar2 = *(undefined4 *)(param_1 + 0x44); uVar3 = *(undefined4 *)(param_1 + 0x48); uVar4 = *(undefined4 *)(param_1 + 0x4c); *(undefined4 *)(iVar1 + 0x40) = *(undefined4 *)(param_1 + 0x40); *(undefined4 *)(iVar1 + 0x44) = uVar2; *(undefined4 *)(iVar1 + 0x48) = uVar3; *(undefined4 *)(iVar1 + 0x4c) = uVar4; // instance -> model -> modelID == TNT if (*(short *)(*(int *)(param_1 + 0x18) + 0x10) == 0x27) { // set color to red uVar2 = 0xad10000; } // not TNT else { // set color to green uVar2 = 0x1eac000; } // set color *(undefined4 *)(iVar1 + 0x24) = uVar2; // set scale *(undefined2 *)(iVar1 + 0x22) = 0x1000; // set funcThDestroy to remove instance from instance pool *(undefined4 *)(*(int *)(iVar1 + 0x6c) + 0x24) = 0x80041dfc; return; } // RB_Blowup_ProcessBucket void FUN_800b1714(int param_1) { undefined *puVar1; undefined *puVar2; int iVar3; int iVar4; int *piVar5; int iVar6; puVar1 = PTR_DAT_8008d2ac; if (param_1 != 0) { do { puVar2 = PTR_DAT_8008d2ac; piVar5 = *(int **)(param_1 + 0x30); iVar6 = 0; if (puVar1[0x1ca8] != '\0') { iVar4 = 0; do { if ((*piVar5 != 0) && (iVar3 = piVar5[1] + iVar4, piVar5[1] != 0)) { *(uint *)(iVar3 + 0xb8) = *(uint *)(iVar3 + 0xb8) & (*(uint *)(*piVar5 + iVar4 + 0xb8) | 0xffffffbf); *(undefined4 *)(piVar5[1] + iVar4 + 0xe4) = *(undefined4 *)(*piVar5 + iVar4 + 0xe4); *(undefined2 *)(piVar5[1] + iVar4 + 0xdc) = *(undefined2 *)(*piVar5 + iVar4 + 0xdc); *(undefined2 *)(piVar5[1] + iVar4 + 0xde) = *(undefined2 *)(*piVar5 + iVar4 + 0xde); } iVar6 = iVar6 + 1; iVar4 = iVar4 + 0x88; } while (iVar6 < (int)(uint)(byte)puVar2[0x1ca8]); } param_1 = *(int *)(param_1 + 0x10); } while (param_1 != 0); } return; } // RB_Blowup_ThTick void FUN_800b17f0(int param_1) { short sVar1; int iVar2; int *piVar3; // get object from thread piVar3 = *(int **)(param_1 + 0x30); do { // get instance pointer iVar2 = piVar3[1]; // if instance is valid if (iVar2 != 0) { // instance -> animFrame sVar1 = *(short *)(iVar2 + 0x54); // INSTANCE_GetNumAnimFrames iVar2 = FUN_80030f58(iVar2,0); // if animation is not done if ((int)sVar1 + 1 < iVar2) { // increment animation frame *(short *)(piVar3[1] + 0x54) = *(short *)(piVar3[1] + 0x54) + 1; } // if animation is done else { // INSTANCE_Death FUN_80030aa8(piVar3[1]); piVar3[1] = 0; } } // get instance pointer iVar2 = *piVar3; // if instance if (iVar2 != 0) { // instance -> animFrame sVar1 = *(short *)(iVar2 + 0x54); // INSTANCE_GetNumAnimFrames iVar2 = FUN_80030f58(iVar2,0); // if animation is not over if ((int)sVar1 + 1 < iVar2) { // increment animation frame *(short *)(*piVar3 + 0x54) = *(short *)(*piVar3 + 0x54) + 1; } // if animation is done else { // INSTANCE_Death FUN_80030aa8(*piVar3); *piVar3 = 0; } } // if either instance has been erased if ((piVar3[1] == 0) && (*piVar3 == 0)) { // This thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; } // this skips $RA backup/restore, faster than JR $RA FUN_80071694(param_1); } while( true ); } // RB_Blowup_Init void FUN_800b18f8(int param_1) { int iVar1; int iVar2; undefined4 uVar3; undefined4 uVar4; undefined4 uVar5; int *piVar6; undefined4 local_30; char *local_2c; undefined4 local_28; undefined4 local_24; code *local_20; undefined4 local_1c; undefined4 local_18; // spawn explosion local_30 = 0x26; // string local_2c = s_blowup_800aba60; // 0x300 flag = SmallStackPool local_28 = 0x300; // 8 = "blowup" thread bucket local_24 = 8; // RB_Blowup_ThTick local_20 = FUN_800b17f0; local_1c = 0xc; local_18 = 0; // initialize thread for blowup iVar1 = FUN_80030a50(&local_30); *(uint *)(iVar1 + 0x28) = *(uint *)(iVar1 + 0x28) | 0x2040000; // instance -> thread -> object piVar6 = *(int **)(*(int *)(iVar1 + 0x6c) + 0x30); // set explosion instance piVar6[1] = iVar1; // copy position and rotation from weapon to explosion uVar3 = *(undefined4 *)(param_1 + 0x34); uVar4 = *(undefined4 *)(param_1 + 0x38); uVar5 = *(undefined4 *)(param_1 + 0x3c); *(undefined4 *)(iVar1 + 0x30) = *(undefined4 *)(param_1 + 0x30); *(undefined4 *)(iVar1 + 0x34) = uVar3; *(undefined4 *)(iVar1 + 0x38) = uVar4; *(undefined4 *)(iVar1 + 0x3c) = uVar5; uVar3 = *(undefined4 *)(param_1 + 0x44); uVar4 = *(undefined4 *)(param_1 + 0x48); uVar5 = *(undefined4 *)(param_1 + 0x4c); *(undefined4 *)(iVar1 + 0x40) = *(undefined4 *)(param_1 + 0x40); *(undefined4 *)(iVar1 + 0x44) = uVar3; *(undefined4 *)(iVar1 + 0x48) = uVar4; *(undefined4 *)(iVar1 + 0x4c) = uVar5; // if instance -> model -> modelID == tnt if (*(short *)(*(int *)(param_1 + 0x18) + 0x10) == 0x27) { // set color to red uVar3 = 0xad10000; } // if it is not tnt else { // set color to green uVar3 = 0x1eac000; } // set color *(undefined4 *)(iVar1 + 0x24) = uVar3; // set scale *(undefined2 *)(iVar1 + 0x22) = 0x1000; // green shockwave iVar1 = 0x45; // if instance -> model -> modelID == tnt if (*(short *)(*(int *)(param_1 + 0x18) + 0x10) == 0x27) { // red shockwave iVar1 = 0x44; } // INSTANCE_Birth3D -- ptrModel, name, thread iVar1 = FUN_8003086c(*(undefined4 *)(PTR_DAT_8008d2ac + iVar1 * 4 + 0x2160), s_shockwave1_800aba78); // set shockwave instance *piVar6 = iVar1; // instane flags *(uint *)(iVar1 + 0x28) = *(uint *)(iVar1 + 0x28) | 0x200; // set showckwave position to weapon position *(undefined4 *)(iVar1 + 0x44) = *(undefined4 *)(param_1 + 0x44); *(undefined4 *)(iVar1 + 0x48) = *(undefined4 *)(param_1 + 0x48); *(undefined4 *)(iVar1 + 0x4c) = *(undefined4 *)(param_1 + 0x4c); // shockwaveInst -> model -> modelHeader, // there is only one header in this model iVar2 = *(int *)(*(int *)(iVar1 + 0x18) + 0x14); // modelHeader -> flags // set flag to always point to camera *(ushort *)(iVar2 + 0x16) = *(ushort *)(iVar2 + 0x16) | 2; // Do it again? Should this be explosion instance? iVar2 = *(int *)(*(int *)(iVar1 + 0x18) + 0x14); *(ushort *)(iVar2 + 0x56) = *(ushort *)(iVar2 + 0x56) | 2; // Instance -> matrix, Identity 3x3 rotation *(undefined4 *)(iVar1 + 0x30) = 0x1000; *(undefined4 *)(iVar1 + 0x34) = 0; *(undefined4 *)(iVar1 + 0x38) = 0x1000; *(undefined4 *)(iVar1 + 0x3c) = 0; *(undefined2 *)(iVar1 + 0x40) = 0x1000; // put weapon position on scratchpad DAT_1f800108 = *(undefined2 *)(param_1 + 0x44); DAT_1f80010a = *(undefined2 *)(param_1 + 0x48); DAT_1f80010c = *(undefined2 *)(param_1 + 0x4c); // if you're in boss mode if (*(int *)PTR_DAT_8008d2ac < 0) { // hitRadius and hitRadiusSquared DAT_1f80010e = 0x100; _DAT_1f800110 = 0x10000; } // if you're not in boss mode else { // hitRadius and hitRadiusSquared DAT_1f80010e = 0x140; _DAT_1f800110 = 0x19000; } // RB_Burst_CollThBucket DAT_1f800130 = FUN_800b1e90; // instance -> thread DAT_1f800120 = *(undefined4 *)(param_1 + 0x6c); // thread -> model -> modelID DAT_1f800114 = *(undefined2 *)(*(int *)(param_1 + 0x18) + 0x10); // THREAD_StartSearch_Self FUN_80042544(&DAT_1f800108); // check collision with all robotcar thread FUN_800425d4(*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b40),&DAT_1f800108,0); // check collision with all Mine thread FUN_800425d4(*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b7c),&DAT_1f800108,0); // If this is TNT if (*(short *)(*(int *)(param_1 + 0x18) + 0x10) == 0x27) { // pointer to first player thread uVar3 = *(undefined4 *)(PTR_DAT_8008d2ac + 0x1b2c); } // if not TNT else { // hitRadius and hitRadiusSquared DAT_1f80010e = 0x80; _DAT_1f800110 = 0x4000; // pointer to first player thread uVar3 = *(undefined4 *)(PTR_DAT_8008d2ac + 0x1b2c); } // check collision with player threads FUN_800425d4(uVar3,&DAT_1f800108,0); // RB_Burst_CollLevInst DAT_1f800130 = FUN_800b20a4; return; } // RB_Burst_ProcessBucket void FUN_800b1bd8(int param_1) { undefined *puVar1; undefined *puVar2; int iVar3; int iVar4; int *piVar5; int iVar6; puVar1 = PTR_DAT_8008d2ac; if (param_1 != 0) { do { puVar2 = PTR_DAT_8008d2ac; piVar5 = *(int **)(param_1 + 0x30); iVar6 = 0; if (puVar1[0x1ca8] != '\0') { iVar4 = 0; do { if (piVar5[1] != 0) { iVar3 = *piVar5 + iVar4; if (*piVar5 != 0) { *(uint *)(iVar3 + 0xb8) = *(uint *)(iVar3 + 0xb8) & (*(uint *)(piVar5[1] + iVar4 + 0xb8) | 0xffffffbf); *(undefined4 *)(*piVar5 + iVar4 + 0xe4) = *(undefined4 *)(piVar5[1] + iVar4 + 0xe4); *(undefined2 *)(*piVar5 + iVar4 + 0xdc) = *(undefined2 *)(piVar5[1] + iVar4 + 0xdc); *(undefined2 *)(*piVar5 + iVar4 + 0xde) = *(undefined2 *)(piVar5[1] + iVar4 + 0xde); } iVar3 = piVar5[2] + iVar4; if (piVar5[2] != 0) { *(uint *)(iVar3 + 0xb8) = *(uint *)(iVar3 + 0xb8) & (*(uint *)(piVar5[1] + iVar4 + 0xb8) | 0xffffffbf); *(undefined4 *)(piVar5[2] + iVar4 + 0xe4) = *(undefined4 *)(piVar5[1] + iVar4 + 0xe4); *(undefined2 *)(piVar5[2] + iVar4 + 0xdc) = *(undefined2 *)(piVar5[1] + iVar4 + 0xdc); *(undefined2 *)(piVar5[2] + iVar4 + 0xde) = *(undefined2 *)(piVar5[1] + iVar4 + 0xde); } } iVar6 = iVar6 + 1; iVar4 = iVar4 + 0x88; } while (iVar6 < (int)(uint)(byte)puVar2[0x1ca8]); } param_1 = *(int *)(param_1 + 0x10); } while (param_1 != 0); } return; } // RB_Burst_ThTick void FUN_800b1d2c(int param_1) { short sVar1; int iVar2; int *piVar3; // thread -> object piVar3 = *(int **)(param_1 + 0x30); // get instance pointer iVar2 = piVar3[1]; // get instance pointer if (iVar2 != 0) { // instance -> animFrame sVar1 = *(short *)(iVar2 + 0x54); // INSTANCE_GetNumAnimFrames iVar2 = FUN_80030f58(iVar2,0); // if animation is not done if ((int)sVar1 + 1 < iVar2) { // increment animation frame *(short *)(piVar3[1] + 0x54) = *(short *)(piVar3[1] + 0x54) + 1; } // if animation is done else { // INSTANCE_Death FUN_80030aa8(piVar3[1]); piVar3[1] = 0; } } // get instance pointer iVar2 = piVar3[2]; // if instance is valid if (iVar2 != 0) { // get animation frame sVar1 = *(short *)(iVar2 + 0x54); // INSTANCE_GetNumAnimFrames iVar2 = FUN_80030f58(iVar2,0); // if animation is not done if ((int)sVar1 + 1 < iVar2) { // increment animation frame *(short *)(piVar3[2] + 0x54) = *(short *)(piVar3[2] + 0x54) + 1; } // if animation is done else { // INSTANCE_Death FUN_80030aa8(piVar3[2]); piVar3[2] = 0; } } // get instance pointer iVar2 = *piVar3; // if instance is valid if (iVar2 != 0) { // instance -> animationFrame sVar1 = *(short *)(iVar2 + 0x54); // INSTANCE_GetNumAnimFrames iVar2 = FUN_80030f58(iVar2,0); // if animation is not done if ((int)sVar1 + 1 < iVar2) { // increase animation frame *(short *)(*piVar3 + 0x54) = *(short *)(*piVar3 + 0x54) + 1; } // if animation is done else { // INSTANCE_Death FUN_80030aa8(*piVar3); *piVar3 = 0; } } // if instances have been erased if ((piVar3[1] == 0) && (piVar3[2] == 0)) { // This thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; } return; } // RB_Burst_CollThBucket // callback when searching thread buckets void FUN_800b1e90(int param_1,int param_2) { undefined *puVar1; code *pcVar2; short sVar3; undefined4 uVar4; undefined4 uVar5; int iVar6; int iVar7; // BSP_Meta -> weaponthread -> object iVar7 = *(int *)(*(int *)(param_1 + 0x18) + 0x30); // get modelID from thread sVar3 = *(short *)(param_2 + 0x44); // if this is a player of any kind, or robotcar of any kind if ((sVar3 == 0x18) || (sVar3 == 0x3f)) { // BSP_Meta -> weaponthread -> modelID sVar3 = *(short *)(*(int *)(param_1 + 0x18) + 0x44); // nitro, green beaker, red beaker, TNT if ((sVar3 == 6) || (((sVar3 == 0x46 || (sVar3 == 0x47)) || (sVar3 == 0x27)))) { // RB_Hazard_HurtDriver (blasted) FUN_800ac1b0 (*(undefined4 *)(param_2 + 0x30),2, *(undefined4 *)(*(int *)(*(int *)(iVar7 + 4) + 0x6c) + 0x30),2); } else { iVar6 = *(int *)(*(int *)(*(int *)(iVar7 + 8) + 0x6c) + 0x30); // missile if (sVar3 == 0x29) { uVar4 = *(undefined4 *)(param_2 + 0x30); uVar5 = 3; } // bomb else { uVar4 = *(undefined4 *)(param_2 + 0x30); uVar5 = 1; } // RB_Hazard_HurtDriver (blasted) FUN_800ac1b0(uVar4,2,iVar6,uVar5); if ((int)*(short *)(iVar6 + 0x552) < *(int *)(iVar7 + 0x48)) { *(undefined2 *)(iVar6 + 0x552) = *(undefined2 *)(iVar7 + 0x48); } } puVar1 = PTR_DAT_8008d2ac; // thread -> driver object -> flags // if this driver is not an AI if ((*(uint *)(*(int *)(param_2 + 0x30) + 0x2c8) & 0x100000) == 0) { *(undefined2 *) (PTR_DAT_8008d2ac + (uint)*(byte *)(*(int *)(param_2 + 0x30) + 0x4a) * 0x110 + 0x17a) = 0x1fff; *(undefined2 *)(puVar1 + (uint)*(byte *)(*(int *)(param_2 + 0x30) + 0x4a) * 0x110 + 0x17c) = 0x1000; *(undefined2 *)(puVar1 + (uint)*(byte *)(*(int *)(param_2 + 0x30) + 0x4a) * 0x110 + 0x17e) = 0xff78; } // icon damage timer, draw icon as red *(undefined4 *)(*(int *)(param_2 + 0x30) + 0x4ac) = 0x1e; // get modelID from thread sVar3 = *(short *)(param_2 + 0x44); } // not DYNAMIC_ROCKET if (sVar3 != 0x29) { if (sVar3 < 0x2a) { // not nitro and not STATIC_CRATE_TNT if ((sVar3 != 6) && (sVar3 != 0x27)) { return; } } else { // return if anything that isn't beakers if (0x47 < sVar3) { return; } if (sVar3 < 0x46) { return; } } } // get funcThCollide pcVar2 = *(code **)(param_2 + 0x28); // if function pointer is valid if (pcVar2 != (code *)0x0) { // execute funcThCollide (*pcVar2)(param_2,*(undefined4 *)(param_1 + 0x18),pcVar2,3); } return; } // RB_Burst_CollLevInst (bsp callback) // param_1 - 1f800108 // param_2 - bsp (hitbox) void FUN_800b20a4(int param_1,int param_2) { short sVar1; int iVar2; int iVar3; // bsp->hitbox.instDef iVar2 = *(int *)(param_2 + 0x1c); if ( // if InstDef exists (iVar2 != 0) && // InstDef -> Instance (iVar3 = *(int *)(iVar2 + 0x2c), iVar3 != 0) ) { // modelID sVar1 = *(short *)(iVar2 + 0x3c); if (6 < sVar1) { // check 7 and 8, // 7: PU_FRUIT_CRATE // 8: PU_RANDOM_CRATE (weapon box) if (sVar1 < 9) { // ThreadMeta iVar2 = FUN_8001d094(); // if funcLevThreadsBirth is not nullptr if ((iVar2 != 0) && (*(code **)(iVar2 + 8) != (code *)0x0)) { // execute funcLevThreadsBirth, make thread for this instance // upon collision with the instance, let it run thread->funcThCollide (**(code **)(iVar2 + 8))(iVar3,*(undefined4 *)(param_1 + 0x18),param_1); } } else { // modelID == teeth if (sVar1 == 0x70) { // RB_Teeth_OpenDoor FUN_800ba220(iVar3); } } } } return; } // RB_Burst_Init void FUN_800b2154(int param_1) { undefined *puVar1; int iVar2; int iVar3; int *piVar4; int iVar5; undefined4 local_40; char *local_3c; undefined4 local_38; undefined4 local_34; code *local_30; undefined4 local_2c; undefined4 local_28; // instance -> thread -> object iVar5 = *(int *)(*(int *)(param_1 + 0x6c) + 0x30); // model index of explosion local_40 = 0x2b; // string local_3c = s_explosion1_800aba44; // small stack pool local_38 = 0x300; // 7 = "burst" thread bucket local_34 = 7; // RB_Burst_ThTick local_30 = FUN_800b1d2c; local_2c = 0xc; local_28 = 0; // initialize thread for burst iVar2 = FUN_80030a50(&local_40); // get thread from instance iVar3 = *(int *)(iVar2 + 0x6c); // get object from thread piVar4 = *(int **)(iVar3 + 0x30); piVar4[1] = iVar2; *(char *)(iVar2 + 0x50) = *(char *)(iVar2 + 0x50) + -2; *(undefined4 *)(iVar2 + 0x44) = *(undefined4 *)(param_1 + 0x44); puVar1 = PTR_DAT_8008d2ac; *(int *)(iVar2 + 0x48) = *(int *)(param_1 + 0x48) + -0x30; *(undefined4 *)(iVar2 + 0x4c) = *(undefined4 *)(param_1 + 0x4c); // if more than 2 screens if (2 < (byte)puVar1[0x1ca8]) { // divide scale by 2 *(short *)(iVar2 + 0x1c) = *(short *)(iVar2 + 0x1c) >> 1; *(short *)(iVar2 + 0x1e) = *(short *)(iVar2 + 0x1e) >> 1; *(short *)(iVar2 + 0x20) = *(short *)(iVar2 + 0x20) >> 1; } // set rotation to identity matrix *(undefined4 *)(iVar2 + 0x30) = 0x1000; *(undefined4 *)(iVar2 + 0x34) = 0; *(undefined4 *)(iVar2 + 0x38) = 0x1000; *(undefined4 *)(iVar2 + 0x3c) = 0; *(undefined2 *)(iVar2 + 0x40) = 0x1000; puVar1 = PTR_DAT_8008d2ac; // instance -> model -> modelHeader iVar2 = *(int *)(*(int *)(iVar2 + 0x18) + 0x14); // header -> flags: always face camera *(ushort *)(iVar2 + 0x16) = *(ushort *)(iVar2 + 0x16) | 2; // INSTANCE_Birth3D -- ptrModel, name, thread iVar2 = FUN_8003086c(*(undefined4 *)(puVar1 + 0x220c),s_explosion2_800aba94,iVar3); piVar4[2] = iVar2; // instance flags *(uint *)(iVar2 + 0x28) = *(uint *)(iVar2 + 0x28) | 0x2000000; *(char *)(iVar2 + 0x50) = *(char *)(iVar2 + 0x50) + -2; // X position *(undefined4 *)(iVar2 + 0x44) = *(undefined4 *)(param_1 + 0x44); puVar1 = PTR_DAT_8008d2ac; // Y position *(int *)(iVar2 + 0x48) = *(int *)(param_1 + 0x48) + -0x30; // Z position *(undefined4 *)(iVar2 + 0x4c) = *(undefined4 *)(param_1 + 0x4c); // if more than 2 screens if (2 < (byte)puVar1[0x1ca8]) { // scale (x, y, z) *(short *)(iVar2 + 0x1c) = *(short *)(iVar2 + 0x1c) >> 1; *(short *)(iVar2 + 0x1e) = *(short *)(iVar2 + 0x1e) >> 1; *(short *)(iVar2 + 0x20) = *(short *)(iVar2 + 0x20) >> 1; } *(undefined2 *)(iVar2 + 0x32) = 0xf000; *(undefined2 *)(iVar2 + 0x30) = 0; *(undefined2 *)(iVar2 + 0x34) = 0; *(undefined2 *)(iVar2 + 0x36) = 0x1000; *(undefined2 *)(iVar2 + 0x38) = 0; *(undefined2 *)(iVar2 + 0x3a) = 0; *(undefined2 *)(iVar2 + 0x3c) = 0; *(undefined2 *)(iVar2 + 0x3e) = 0; *(undefined2 *)(iVar2 + 0x40) = 0x1000; puVar1 = PTR_DAT_8008d2ac; // instance -> model -> modelHeader iVar2 = *(int *)(*(int *)(iVar2 + 0x18) + 0x14); // header -> flags: always face camera *(ushort *)(iVar2 + 0x16) = *(ushort *)(iVar2 + 0x16) | 2; // INSTANCE_Birth3D -- ptrModel, name, thread iVar2 = FUN_8003086c(*(undefined4 *)(puVar1 + 0x2270),s_shockwave1_800aba78,iVar3); *piVar4 = iVar2; // instance flags *(uint *)(iVar2 + 0x28) = *(uint *)(iVar2 + 0x28) | 0x2040000; *(char *)(iVar2 + 0x50) = *(char *)(iVar2 + 0x50) + -2; *(undefined4 *)(iVar2 + 0x44) = *(undefined4 *)(param_1 + 0x44); puVar1 = PTR_DAT_8008d2ac; *(int *)(iVar2 + 0x48) = *(int *)(param_1 + 0x48) + -0x30; *(undefined4 *)(iVar2 + 0x4c) = *(undefined4 *)(param_1 + 0x4c); // if more than two screens if (2 < (byte)puVar1[0x1ca8]) { // set scale (x, y, z) *(short *)(iVar2 + 0x1c) = *(short *)(iVar2 + 0x1c) >> 1; *(short *)(iVar2 + 0x1e) = *(short *)(iVar2 + 0x1e) >> 1; *(short *)(iVar2 + 0x20) = *(short *)(iVar2 + 0x20) >> 1; } // identity matrix *(undefined4 *)(iVar2 + 0x30) = 0x1000; *(undefined4 *)(iVar2 + 0x34) = 0; *(undefined4 *)(iVar2 + 0x38) = 0x1000; *(undefined4 *)(iVar2 + 0x3c) = 0; *(undefined2 *)(iVar2 + 0x40) = 0x1000; // instance -> model -> modelHeader iVar3 = *(int *)(*(int *)(iVar2 + 0x18) + 0x14); // header -> flags: always face camera *(ushort *)(iVar3 + 0x16) = *(ushort *)(iVar3 + 0x16) | 2; iVar2 = *(int *)(*(int *)(iVar2 + 0x18) + 0x14); *(ushort *)(iVar2 + 0x56) = *(ushort *)(iVar2 + 0x56) | 2; DAT_1f800108 = *(undefined2 *)(param_1 + 0x44); DAT_1f80010a = *(undefined2 *)(param_1 + 0x48); DAT_1f80010c = *(undefined2 *)(param_1 + 0x4c); // instance -> model -> modelID == missile if (*(short *)(*(int *)(param_1 + 0x18) + 0x10) == 0x29) { // hitRadius and hitRadiusSquared DAT_1f80010e = 0x80; _DAT_1f800110 = 0x4000; } else { // instance -> thread -> object if ((*(ushort *)(*(int *)(*(int *)(param_1 + 0x6c) + 0x30) + 0x16) & 1) == 0) { // hitRadius and hitRadiusSquared DAT_1f80010e = 0x140; _DAT_1f800110 = 0x19000; } else { // hitRadius and hitRadiusSquared DAT_1f80010e = 0x200; _DAT_1f800110 = 0x40000; } } // RB_Burst_CollThBucket (callback for threadbucket collision) DAT_1f800130 = FUN_800b1e90; // instance -> thread DAT_1f800120 = *(undefined4 *)(param_1 + 0x6c); // instance -> model -> modelID DAT_1f800114 = *(undefined2 *)(*(int *)(param_1 + 0x18) + 0x10); // check collision with all Player thread FUN_800425d4(*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b2c),&DAT_1f800108, *(undefined4 *)(*(int *)(*(int *)(iVar5 + 4) + 0x1c) + 0x6c)); // check collision with all Robotcar thread FUN_800425d4(*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b40),&DAT_1f800108, *(undefined4 *)(*(int *)(*(int *)(iVar5 + 4) + 0x1c) + 0x6c)); // check collision with all Mine thread FUN_800425d4(*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b7c),&DAT_1f800108,0); // check collision with all Tracking thread FUN_800425d4(*(undefined4 *)(PTR_DAT_8008d2ac + 0x1ba4),&DAT_1f800108,0); // RB_Burst_CollLevInst (callback for BSP collision) DAT_1f800130 = FUN_800b20a4; // THREAD_StartSearch_Self FUN_80042544(&DAT_1f800108); return; } // RB_Burst_DrawAll void FUN_800b25b8(int param_1) { char cVar1; undefined4 in_zero; undefined4 in_at; int iVar2; int *piVar3; int iVar4; int *piVar5; int iVar6; int iVar7; int iVar8; int iVar9; int iVar10; int local_70 [4]; int local_60 [4]; undefined4 local_50; uint local_4c; int local_48; int local_44; int local_40; int local_38; int local_34; int local_30; // numPlyrCurrGame cVar1 = *(char *)(param_1 + 0x1ca8); iVar8 = 0; // if numPlyrCurrGame is not zero if (cVar1 != '\0') { piVar3 = local_60; piVar5 = local_70; iVar10 = 0x168; iVar9 = param_1; do { // pointer to first burst thread iVar7 = *(int *)(param_1 + 0x1bb8); iVar6 = param_1 + iVar10 + 0x28; *piVar5 = 0x10000; *piVar3 = 0; iVar2 = *(int *)(iVar9 + 0x180); FUN_800718fc(iVar6); FUN_800718dc(iVar6); while (iVar7 != 0) { iVar6 = *(int *)(iVar7 + 0x30); iVar4 = *(int *)(iVar6 + 4); local_50 = CONCAT22(*(undefined2 *)(iVar4 + 0x48),*(undefined2 *)(iVar4 + 0x44)); local_4c = local_4c & 0xffff0000 | (uint)*(ushort *)(iVar4 + 0x4c); setCopReg(2,in_zero,local_50); setCopReg(2,in_at,local_4c); // rtv0tr cop2 $0480012 v0 * rotmatrix + tr vector copFunction(2,0x480012); local_38 = getCopReg(2,0x19); local_48 = local_38; local_34 = getCopReg(2,0x1a); local_44 = local_34; local_30 = getCopReg(2,0x1b); local_40 = local_30; if (local_38 < 0) { local_38 = -local_38; } if (local_34 < 0) { local_34 = -local_34; } if (local_30 < 0) { local_30 = -local_30; } if (((local_38 < 0x100) && (local_34 < 0x100)) && (local_30 < iVar2 << 1)) { if ((int)*(short *)(iVar4 + 0x54) < *piVar5) { *piVar5 = (int)*(short *)(iVar4 + 0x54); *piVar3 = iVar7; } if (*(short *)(*(int *)(iVar6 + 4) + 0x54) == 1) { *(undefined2 *)(iVar9 + 0x17c) = 0x1000; *(undefined2 *)(iVar9 + 0x17e) = 0xff78; *(short *)(iVar9 + 0x17a) = ((short)local_38 + (short)local_34) * -8 + 0x1fff; } } // thread = thread->next iVar7 = *(int *)(iVar7 + 0x10); } iVar9 = iVar9 + 0x110; piVar3 = piVar3 + 1; piVar5 = piVar5 + 1; iVar8 = iVar8 + 1; iVar10 = iVar10 + 0x110; } while (iVar8 < (int)(uint)*(byte *)(param_1 + 0x1ca8)); // numPlyrCurrGame cVar1 = *(char *)(param_1 + 0x1ca8); } // iteration counter iVar8 = 0; // if numPlyrCurrGame is not zero if (cVar1 != '\0') { iVar10 = 0x168; iVar9 = 0; piVar5 = local_60; // for iVar8 = 0; iVar8 < numPlyrCurrGame; iVar8++ do { // pointer to first burst thread iVar7 = *(int *)(param_1 + 0x1bb8); if (iVar7 != 0) { iVar2 = param_1 + iVar10; do { piVar3 = *(int **)(iVar7 + 0x30); if ((*piVar5 == 0) || (*piVar5 == iVar7)) { if (piVar3[1] != 0) { *(int *)(piVar3[1] + iVar9 + 0x74) = iVar2; } if (piVar3[2] != 0) { *(int *)(piVar3[2] + iVar9 + 0x74) = iVar2; } if (*piVar3 != 0) { *(int *)(*piVar3 + iVar9 + 0x74) = iVar2; } } else { if (piVar3[1] != 0) { *(undefined4 *)(piVar3[1] + iVar9 + 0x74) = 0; } if (piVar3[2] != 0) { *(undefined4 *)(piVar3[2] + iVar9 + 0x74) = 0; } if (*piVar3 != 0) { *(undefined4 *)(*piVar3 + iVar9 + 0x74) = 0; } } iVar7 = *(int *)(iVar7 + 0x10); } while (iVar7 != 0); } iVar10 = iVar10 + 0x110; iVar9 = iVar9 + 0x88; // increment loop counter iVar8 = iVar8 + 1; piVar5 = piVar5 + 1; } while (iVar8 < (int)(uint)*(byte *)(param_1 + 0x1ca8)); } return; } // RB_GetThread_ClosestTracker (warpball or missile) int FUN_800b28c0(int param_1) { int iVar1; int iVar2; int iVar3; int iVar4; int iVar5; // assume farthest position iVar4 = 0x3fffffff; // pointer to first Tracking thread iVar3 = *(int *)(PTR_DAT_8008d2ac + 0x1ba4); // return thread = nullptr iVar5 = 0; // loop through all threads while (iVar3 != 0) { if ( // if first item in thread's object is param_1, // meaning, if tracker is chasing this driver (**(int **)(iVar3 + 0x30) == param_1) && ( // get distance between posX and posZ of // driver->instSelf->position, and tracker's position, iVar1 = *(int *)(*(int *)(param_1 + 0x1c) + 0x44) - *(int *)(*(int *)(iVar3 + 0x34) + 0x44), iVar2 = *(int *)(*(int *)(param_1 + 0x1c) + 0x4c) - *(int *)(*(int *)(iVar3 + 0x34) + 0x4c), // if this is a new closest distance iVar1 = iVar1 * iVar1 + iVar2 * iVar2, iVar1 < iVar4 ) ) { // save closest distance iVar4 = iVar1; // save thread iVar5 = iVar3; } // thread = thread->next iVar3 = *(int *)(iVar3 + 0x10); } // return thread of cloest tracker return iVar5; } // 800b2e9c LinkedList MinePool_Taken // 800b2ea8 LinkedList MinePool_Free // 800b2eb4 char MineData[0x32][0xC] // max 50 members, 0xC bytes each // 800b310c char baron[0x8] // 800b3114 char drumbuddy[0xC] // 800b3120 next function // RB_Baron_ThTick void FUN_800b3120(int param_1) { undefined *puVar1; int iVar2; int iVar3; short sVar4; int iVar5; int iVar6; int iVar7; short sStack32; undefined2 uStack30; undefined2 uStack28; // get instance from thread iVar6 = *(int *)(param_1 + 0x34); // get object from thread iVar5 = *(int *)(param_1 + 0x30); // instance -> animFrame sVar4 = *(short *)(iVar6 + 0x54); // INSTANCE_GetNumAnimFrames iVar2 = FUN_80030f58(iVar6,0); // if animation is not over if ((int)sVar4 + 1 < iVar2) { // increment animation frame *(short *)(iVar6 + 0x54) = *(short *)(iVar6 + 0x54) + 1; } // if animation is over else { // restart animation *(undefined2 *)(iVar6 + 0x54) = 0; } puVar1 = PTR_DAT_8008d2ac; // LEV -> numSpawnType2_PosRot if (*(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x140) != 0) { // LEV -> ptrSpawnType2_PosRot iVar7 = **(int **)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x144); iVar2 = (int)*(short *)(iVar5 + 0x2c) + 1; if (iVar7 == 0) { trap(0x1c00); } if ((iVar7 == -1) && (iVar2 == -0x80000000)) { trap(0x1800); } // get frame index in animation sVar4 = (short)(iVar2 % iVar7); *(short *)(iVar5 + 0x2c) = sVar4; // instance -> model -> modelID == N Gin Labs Barrel if (*(short *)(*(int *)(iVar6 + 0x18) + 0x10) == 0x55) { // 16th frame if (sVar4 == 0x10) { // play sound of barrel hitting ground FUN_8002f0dc(0xc,iVar6); } // frame 0-16 if (*(short *)(iVar5 + 0x2c) < 0x11) { // stop audio FUN_8002e724(iVar5 + 0x24); } // frame 17+ else { // PlaySound3D_Flags // sound of barrel moving FUN_8002f31c(iVar5 + 0x24,0x74,iVar6); } // LEV -> ptrSpawn1 rotX sStack32 = *(short *)((int)*(short *)(iVar5 + 0x2c) * 0xc + *(int *)(*(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x144) + 4) + 6); // LEV -> ptrSpawn1 rotY uStack30 = *(undefined2 *) ((int)*(short *)(iVar5 + 0x2c) * 0xc + *(int *)(*(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x144) + 4) + 8); // LEV -> ptrSpawn1 rotZ uStack28 = *(undefined2 *) ((int)*(short *)(iVar5 + 0x2c) * 0xc + *(int *)(*(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x144) + 4) + 10); // convert rotation to matrix FUN_8006c2a4(iVar6 + 0x30,&sStack32); puVar1 = PTR_DAT_8008d2ac; // LEV -> ptrSpawn1 posX *(int *)(iVar6 + 0x44) = (int)*(short *)((int)*(short *)(iVar5 + 0x2c) * 0xc + *(int *)(*(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x144) + 4)); // LEV -> ptrSpawn1 posY *(int *)(iVar6 + 0x48) = (int)*(short *)((int)*(short *)(iVar5 + 0x2c) * 0xc + *(int *)(*(int *)(*(int *)(puVar1 + 0x160) + 0x144) + 4) + 2); // LEV -> ptrSpawn1 posZ *(int *)(iVar6 + 0x4c) = (int)*(short *)((int)*(short *)(iVar5 + 0x2c) * 0xc + *(int *)(*(int *)(*(int *)(puVar1 + 0x160) + 0x144) + 4) + 4); // adjust posX and posZ, // this centers the barrel on the nav points *(int *)(iVar6 + 0x44) = *(int *)(iVar6 + 0x44) + 0x111; *(int *)(iVar6 + 0x4c) = *(int *)(iVar6 + 0x4c) + -0x110; } // [Unused, Baron plane] // if this is not N Gin Labs Barrel else { // LEV -> ptrSpawn1 rotX uStack30 = *(undefined2 *) ((int)*(short *)(iVar5 + 0x2c) * 0xc + *(int *)(*(int *)(*(int *)(puVar1 + 0x160) + 0x144) + 4) + 8); // LEV -> ptrSpawn1 rotY sStack32 = -*(short *)((int)sVar4 * 0xc + *(int *)(*(int *)(*(int *)(puVar1 + 0x160) + 0x144) + 4) + 6); // LEV -> ptrSpawn1 rotZ uStack28 = *(undefined2 *) ((int)*(short *)(iVar5 + 0x2c) * 0xc + *(int *)(*(int *)(*(int *)(puVar1 + 0x160) + 0x144) + 4) + 10); // convert rotation to matrix FUN_8006c2a4(iVar6 + 0x30,&sStack32); puVar1 = PTR_DAT_8008d2ac; // LEV -> ptrSpawn1 posX *(int *)(iVar6 + 0x44) = (int)*(short *)((int)*(short *)(iVar5 + 0x2c) * 0xc + *(int *)(*(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x144) + 4)); // LEV -> ptrSpawn1 posY *(int *)(iVar6 + 0x48) = (int)*(short *)((int)*(short *)(iVar5 + 0x2c) * 0xc + *(int *)(*(int *)(*(int *)(puVar1 + 0x160) + 0x144) + 4) + 2); // LEV -> ptrSpawn1 posZ *(int *)(iVar6 + 0x4c) = (int)*(short *)((int)*(short *)(iVar5 + 0x2c) * 0xc + *(int *)(*(int *)(*(int *)(puVar1 + 0x160) + 0x144) + 4) + 4); } // [Unused, Baron plane] // if "other?" instance exists, // update instance position if (*(int *)(iVar5 + 0x28) != 0) { iVar2 = (int)*(short *)(iVar5 + 0x2c) + 0x78; if (iVar7 == 0) { trap(0x1c00); } if ((iVar7 == -1) && (iVar2 == -0x80000000)) { trap(0x1800); } iVar3 = (int)*(short *)(iVar5 + 0x2c) + 0x78; if (iVar7 == 0) { trap(0x1c00); } if ((iVar7 == -1) && (iVar3 == -0x80000000)) { trap(0x1800); } // LEV -> ptrSpawn1 uStack30 = *(undefined2 *) ((iVar3 % iVar7) * 0xc + *(int *)(*(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x144) + 4) + 8); iVar3 = (int)*(short *)(iVar5 + 0x2c) + 0x78; if (iVar7 == 0) { trap(0x1c00); } if ((iVar7 == -1) && (iVar3 == -0x80000000)) { trap(0x1800); } // LEV -> ptrSpawn1 uStack28 = *(undefined2 *) ((iVar3 % iVar7) * 0xc + *(int *)(*(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x144) + 4) + 10); // LEV -> ptrSpawn1 sStack32 = -*(short *)((iVar2 % iVar7) * 0xc + *(int *)(*(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x144) + 4) + 6) ; // new instance rotation matrix FUN_8006c2a4(*(int *)(iVar5 + 0x28) + 0x30,&sStack32); puVar1 = PTR_DAT_8008d2ac; iVar2 = (int)*(short *)(iVar5 + 0x2c) + 0x78; if (iVar7 == 0) { trap(0x1c00); } if ((iVar7 == -1) && (iVar2 == -0x80000000)) { trap(0x1800); } // instance->matrix.t[0] *(int *)(*(int *)(iVar5 + 0x28) + 0x44) = (int)*(short *)((iVar2 % iVar7) * 0xc + *(int *)(*(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x144) + 4)); iVar2 = (int)*(short *)(iVar5 + 0x2c) + 0x78; if (iVar7 == 0) { trap(0x1c00); } if ((iVar7 == -1) && (iVar2 == -0x80000000)) { trap(0x1800); } // instance->matrix.t[1] *(int *)(*(int *)(iVar5 + 0x28) + 0x48) = (int)*(short *)((iVar2 % iVar7) * 0xc + *(int *)(*(int *)(*(int *)(puVar1 + 0x160) + 0x144) + 4) + 2); iVar2 = (int)*(short *)(iVar5 + 0x2c) + 0x78; if (iVar7 == 0) { trap(0x1c00); } if ((iVar7 == -1) && (iVar2 == -0x80000000)) { trap(0x1800); } // instance->matrix.t[2] *(int *)(*(int *)(iVar5 + 0x28) + 0x4c) = (int)*(short *)((iVar2 % iVar7) * 0xc + *(int *)(*(int *)(*(int *)(puVar1 + 0x160) + 0x144) + 4) + 4); // adjust posX and posZ, // this centers the baron on the nav points *(int *)(*(int *)(iVar5 + 0x28) + 0x44) = *(int *)(*(int *)(iVar5 + 0x28) + 0x44) + 0x21f; *(int *)(*(int *)(iVar5 + 0x28) + 0x4c) = *(int *)(*(int *)(iVar5 + 0x28) + 0x4c) + -0x21f; } // instance -> model -> modelID == N Gin Labs Barrel if ((*(short *)(*(int *)(iVar6 + 0x18) + 0x10) == 0x55) && // get driver who hit barrel // RB_Hazard_CollideWithDrivers (iVar2 = FUN_800ac220(iVar6,0,0x19000,0), iVar2 != 0)) { // RB_Hazard_HurtDriver (squish) FUN_800ac1b0(*(undefined4 *)(*(int *)(iVar2 + 0x6c) + 0x30),3,0,0); } } return; } // RB_Baron_LInB void FUN_800b37d4(int param_1) { // N Gin Labs Barrel // [also something else?] undefined2 uVar1; int iVar2; int iVar3; // If this Instance's thread does not exist if (*(int *)(param_1 + 0x6c) == 0) { // THREAD_BirthWithObject // 0x30 = size // 0 = no relation to param4 // 0x300 = SmallStackPool // 0x3 = static thread bucket iVar2 = FUN_8004205c(0x300303,&FUN_800b3120,s_baron_800b310c,0); // Give thread to instance *(int *)(param_1 + 0x6c) = iVar2; // if thread is valid if (iVar2 != 0) { // Get object created by the thread iVar3 = *(int *)(iVar2 + 0x30); // Give instance to thread *(int *)(iVar2 + 0x34) = param_1; // unused for baron plane, // barrel#0 does "0/2" just gets zero iVar2 = strlen(param_1 + 8); uVar1 = 1; if (*(char *)(iVar2 + param_1 + 7) == '0') { uVar1 = (undefined2)(**(int **)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x13c) / 2); } // starting node *(undefined2 *)(iVar3 + 0x2c) = uVar1; // Set scale (x, y, z) *(undefined2 *)(param_1 + 0x1c) = 0x1000; *(undefined2 *)(param_1 + 0x1e) = 0x1000; *(undefined2 *)(param_1 + 0x20) = 0x1000; // only need to set 0x28 -> 0x0, // the rest is unused for baron *(undefined2 *)(iVar3 + 0x1a) = 4; *(undefined2 *)(iVar3 + 0x22) = 0x18; *(undefined2 *)(iVar3 + 6) = 0; *(undefined4 *)(iVar3 + 0x28) = 0; // instance->model->modelID == DYNAMIC_VONLABASS if (*(short *)(*(int *)(param_1 + 0x18) + 0x10) == 0x4f) { // make invisible *(uint *)(param_1 + 0x28) = *(uint *)(param_1 + 0x28) | 0x80; } *(undefined4 *)(iVar3 + 0x24) = 0; } } return; } // RB_Blade_ThTick void FUN_800b38e4(int param_1) { int iVar1; short *psVar2; // rotation x, y, z undefined2 uStack32; short sStack30; short sStack28; // get object from thread psVar2 = *(short **)(param_1 + 0x30); // get instance from thread iVar1 = *(int *)(param_1 + 0x34); do { // get rotation data from Instance->instDef (from LEV) // rotX uStack32 = *(undefined2 *)(*(int *)(iVar1 + 0x2c) + 0x36); // rotY sStack30 = *(short *)(*(int *)(iVar1 + 0x2c) + 0x38) + 0x400; // rotZ sStack28 = *psVar2; // increment rotation *psVar2 = *psVar2 + 0x100; // turn rotation into matrix FUN_8006c2a4(iVar1 + 0x30,&uStack32); // set scale *(undefined2 *)(iVar1 + 0x20) = 0x1000; *(undefined2 *)(iVar1 + 0x1e) = 0x1000; *(undefined2 *)(iVar1 + 0x1c) = 0x1000; // this skips $RA backup/restore, faster than JR $RA FUN_80071694(param_1); } while( true ); } // RB_Blade_LInB void FUN_800b3978(int param_1) { // These "blades" are on hot air skyway blimps. // One "blade" is a group of three fins, // Four "blades" instances total, from two airship int iVar1; // if thread's instance is null if (*(int *)(param_1 + 0x6c) == 0) { // THREAD_BirthWithObject // 0x4 = size // 0 = no relation to param4 // 0x300 = SmallStackPool // 0x3 = static thread bucket iVar1 = FUN_8004205c(0x40303,FUN_800b38e4,s_blade_800b38dc,0); // Give thread to instance *(int *)(param_1 + 0x6c) = iVar1; // if thread created correctly if (iVar1 != 0) { // give instance to thread *(int *)(iVar1 + 0x34) = param_1; // set rotation to zero **(undefined2 **)(iVar1 + 0x30) = 0; } } return; } // RB_Bubbles_RoosTubes void FUN_800b39dc(void) { short sVar1; short sVar2; short sVar3; int iVar4; int iVar5; int iVar6; int iVar7; int iVar8; int iVar9; int iVar10; short *psVar11; int iVar12; int iVar13; if ( ( // if less than 2 screens ((byte)PTR_DAT_8008d2ac[0x1ca8] < 2) && // level ID == 6 (*(int *)(PTR_DAT_8008d2ac + 0x1a10) == 6) ) && // LEV -> numSpawn2 (1 < *(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x138)) ) { // LEV -> ptrSpawn2 iVar4 = *(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x13c); iVar8 = *(int *)(iVar4 + 0xc); psVar11 = (short *)(iVar8 + 6); if (psVar11 != (short *)0x0) { // gGT->JitPools.particle.free.count iVar13 = *(int *)(PTR_DAT_8008d2ac + 0x19a0); // pointer to player 1 address iVar5 = *(int *)(PTR_DAT_8008d2ac + 0x24ec); // timer iVar7 = *(int *)(PTR_DAT_8008d2ac + 0x1cec); // spawn positions in SpawnType2 iVar12 = *(int *)(iVar4 + 8) + -1; // currentX iVar9 = *(int *)(iVar5 + 0x2d4); // currentZ iVar10 = *(int *)(iVar5 + 0x2dc); // previousX iVar6 = *(int *)(iVar5 + 0x2e0); // previousZ iVar4 = *(int *)(iVar5 + 0x2e8); if (0 < iVar12) { do { if (iVar13 < 0x14) { return; } if ((iVar7 + iVar12 & 7U) == 0) { sVar1 = psVar11[0]; sVar2 = psVar11[1]; sVar3 = psVar11[2]; // currentX - previousX iVar8 = ((iVar9 - iVar6 >> 4) + (iVar9 >> 8)) - (int)sVar1; // absolute value if (iVar8 < 0) { iVar8 = -iVar8; } // currentZ - previousZ iVar5 = ((iVar10 - iVar4 >> 4) + (iVar10 >> 8)) - (int)sVar3; // absolute value if (iVar5 < 0) { iVar5 = -iVar5; } // if velocity is low if (iVar8 + iVar5 < 0x1681) { // Spawn bubbles in Roo's Tubes if you move slowly. // Otherwise, if you move fast, then dont bother // Create instance in particle pool iVar8 = FUN_80040308(0,*(undefined4 *)(PTR_DAT_8008d2ac + 0x2130), &DAT_800b3bc0); iVar13 = iVar13 + -1; // quit if particle fails if (iVar8 == 0) { return; } *(undefined2 *)(iVar8 + 0x1a) = 0x7fff; *(undefined *)(iVar8 + 0x18) = 8; *(int *)(iVar8 + 0x24) = *(int *)(iVar8 + 0x24) + (int)sVar1 * 0x100; *(int *)(iVar8 + 0x2c) = *(int *)(iVar8 + 0x2c) + (int)sVar2 * 0x100; *(int *)(iVar8 + 0x34) = *(int *)(iVar8 + 0x34) + (int)sVar3 * 0x100; } } iVar12 = iVar12 + -1; psVar11 = psVar11 + 3; } while (0 < iVar12); } } } return; } // RB_CrateAny_ThTick_Explode void FUN_800b3d04(int param_1) { short sVar1; int iVar2; int iVar3; // thread -> instance iVar3 = *(int *)(param_1 + 0x34); do { // instance -> animFrame sVar1 = *(short *)(iVar3 + 0x54); // INSTANCE_GetNumAnimFrames iVar2 = FUN_80030f58(iVar3,0); // if animation is not over if ((int)sVar1 + 1 < iVar2) { // increment frame counter *(short *)(iVar3 + 0x54) = *(short *)(iVar3 + 0x54) + 1; } // if animation is over else { // This thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; // INSTANCE_Death FUN_80030aa8(iVar3); } // this skips $RA backup/restore, faster than JR $RA FUN_80071694(param_1); } while( true ); } // RB_CrateAny_ThTick_Grow void FUN_800b3d7c(int param_1) { short sVar1; int iVar2; int *piVar3; // get object from thread piVar3 = *(int **)(param_1 + 0x30); // get instance from thread iVar2 = *(int *)(param_1 + 0x34); do { // instance -> model -> modelID sVar1 = *(short *)(*(int *)(iVar2 + 0x18) + 0x10); // If this is Relic 1s, 2s, or 3s crate if (((sVar1 == 0x5c) || (sVar1 == 100)) || (sVar1 == 0x65)) { // erase thread pointer *(undefined4 *)(iVar2 + 0x6c) = 0; // This thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; } // If cooldown timer is done if (*piVar3 == 0) { //if scale is small if (*(short *)(iVar2 + 0x1c) < 0x1000) { // slowly increase scale (x, y, z) *(short *)(iVar2 + 0x1c) = *(short *)(iVar2 + 0x1c) + 0x100; *(short *)(iVar2 + 0x1e) = *(short *)(iVar2 + 0x1e) + 0x100; *(short *)(iVar2 + 0x20) = *(short *)(iVar2 + 0x20) + 0x100; } else { // set max scale (x, y, z) *(undefined2 *)(iVar2 + 0x1c) = 0x1000; *(undefined2 *)(iVar2 + 0x1e) = 0x1000; *(undefined2 *)(iVar2 + 0x20) = 0x1000; // erase thread *(undefined4 *)(iVar2 + 0x6c) = 0; // increase instance->animFrame *(short *)(iVar2 + 0x54) = *(short *)(iVar2 + 0x54) + 1; // This thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; } } // if cooldown timer is not done else { // if cooldown is not paused (boolPauseCooldown) if (*(short *)(piVar3 + 1) == 0) { // reduce cooldown *piVar3 = *piVar3 + -1; } } // this skips $RA backup/restore, faster than JR $RA FUN_80071694(param_1); } while( true ); } // RB_CrateWeapon_ThCollide // param_1 is the box thread // param_4 is 1f800108 undefined4 FUN_800b3e7c(int param_1,int param_2,undefined4 param_3,int param_4) { undefined4 uVar1; undefined *puVar2; undefined4 in_zero; undefined4 in_at; ushort uVar3; int iVar4; int iVar5; int iVar6; undefined *puVar7; short sVar8; int *piVar9; int iVar10; undefined4 uStack112; char *pcStack108; undefined4 uStack104; undefined4 uStack100; undefined *puStack96; undefined4 uStack92; undefined4 uStack88; undefined2 uStack80; short sStack78; undefined2 uStack76; undefined auStack72 [32]; undefined4 uStack40; undefined4 uStack36; short sStack32; short sStack30; // get object from thread piVar9 = *(int **)(param_1 + 0x30); // get instance from thread iVar10 = *(int *)(param_1 + 0x34); if ( // if frame timer is running (*piVar9 != 0) || ( // scale is not zero, and not 0x1000 ( *(short *)(iVar10 + 0x1c) != 0 && (*(short *)(iVar10 + 0x1c) != 0x1000) ) ) ) { LAB_800b420c: uVar3 = *(ushort *)(param_4 + 0xc) & 0x7fff; if (((int)*(short *)(param_4 + 0xc) & 0x8000U) != 0) { *(ushort *)(param_4 + 0xc) = uVar3; if ( ( ( // if modelID is not nitro (uVar3 != 6) && // if modelID is not tnt (uVar3 != 0x27) ) && // if modelID is not red beaker (uVar3 != 0x46) ) && // if model is not green beaker (uVar3 != 0x47) ) { return 0; } // if modelID is a mine of any kind, // offset4 = 1, prevent crate from growing back *(undefined2 *)(piVar9 + 1) = 1; } return 0; } // At this point, this the first frame of collision // 30-frame timer *piVar9 = 0x1e; if (*(short *)(iVar10 + 0x1c) != 0x1000) goto LAB_800b420c; // set crate scale (x, y, z) to zero *(undefined2 *)(iVar10 + 0x1c) = 0; *(undefined2 *)(iVar10 + 0x1e) = 0; *(undefined2 *)(iVar10 + 0x20) = 0; // Create an instance of explosion // box exploded model uStack112 = 0x26; // string pcStack108 = s_explosion1_800b3cbc; // small stack pool uStack104 = 0x300; // "other" thread bucket uStack100 = 0xd; // RB_CrateAny_ThTick_Explode puStack96 = &FUN_800b3d04; uStack92 = 0; uStack88 = 0; // initialize thread for explosion iVar4 = FUN_80030a50(&uStack112); // set color *(undefined4 *)(iVar4 + 0x24) = 0xfafafa0; // set alpha *(undefined2 *)(iVar4 + 0x22) = 0x1000; // create random rotation vector // {0, rand&0xfff, 0} uStack80 = 0; iVar5 = FUN_80078be8(); iVar6 = iVar5; if (iVar5 < 0) { iVar6 = iVar5 + 0xfff; } sStack78 = (short)iVar5 + (short)(iVar6 >> 0xc) * -0x1000; uStack76 = 0; // copy explosion position to crate position *(undefined4 *)(iVar4 + 0x44) = *(undefined4 *)(iVar10 + 0x44); *(undefined4 *)(iVar4 + 0x48) = *(undefined4 *)(iVar10 + 0x48); *(undefined4 *)(iVar4 + 0x4c) = *(undefined4 *)(iVar10 + 0x4c); // make rotation matrix from rand vector FUN_8006c2a4(auStack72,&uStack80); // explosion = crate + rotation FUN_8006c3b0(iVar4 + 0x30,iVar10 + 0x30,auStack72); // play sound for breaking box FUN_8002f0dc(0x3c,iVar10); // get modelID from what? sVar8 = *(short *)(param_4 + 0xc); if ( // if model is Bomb (sVar8 == 0x3b) || // if model is Missile (sVar8 == 0x29) ) { LAB_800b3fe4: // if this is not human player if (sVar8 != 0x18) { iVar6 = *(int *)(*(int *)(param_2 + 0x30) + 4); // If this is an AI, not a human if ((*(uint *)(iVar6 + 0x2c8) & 0x100000) != 0) { return 1; } goto code_r0x800b4024; } } else { // if this is not human player if (sVar8 != 0x18) { // if model is not blue shield if (sVar8 != 0x56) { // if model is not green shield if (sVar8 != 0x5e) { return 1; } sVar8 = *(short *)(param_4 + 0xc); } goto LAB_800b3fe4; } } // driver = thread -> object iVar6 = *(int *)(param_2 + 0x30); code_r0x800b4024: if ( // If your weapon is not "no weapon" (*(char *)(iVar6 + 0x36) != '\x0f') && // If "no weapon" timer is zero (*(short *)(iVar6 + 0x3c) == 0) ) { return 1; } // if you have a quantity of any weapon if (*(char *)(iVar6 + 0x37) != '\0') { return 1; } // If you dont want to fire a weapon if ((*(uint *)(iVar6 + 0x2c8) & 0x8000) == 0) { if ( // if thread to "cloud" is valid (*(int *)(iVar6 + 0x4a0) != 0) && // driver -> cloudthread -> object -> 0x6 (*(short *)(*(int *)(*(int *)(iVar6 + 0x4a0) + 0x30) + 6) == 1) ) { return 1; } // if driver has no "clock" effect on them if (*(short *)(iVar6 + 0xc) == 0) { // set weapon ID to "roulette" *(undefined *)(iVar6 + 0x36) = 0x10; // increment number of weapon boxes hit *(char *)(iVar6 + 0x568) = *(char *)(iVar6 + 0x568) + '\x01'; puVar2 = PTR_DAT_8008d2ac; // timer for weapon roulette (90 frames, 3 seconds) *(undefined2 *)(iVar6 + 0x3a) = 0x5a; // If there is no weapon roulette if ((*(uint *)puVar2 & 0x800000) == 0) { // Play weapon roulette shuffle sound FUN_80028468(0x5d,0); // start drawing weapon roulette *(uint *)PTR_DAT_8008d2ac = *(uint *)PTR_DAT_8008d2ac | 0x800000; } *(undefined4 *)(iVar6 + 0x4b0) = 5; *(undefined2 *)(iVar6 + 0x3c) = 0; // if you have 10 wumpa fruit if (*(char *)(iVar6 + 0x30) == '\n') { *(undefined4 *)(iVar6 + 0x4e0) = 10; } puVar2 = PTR_DAT_8008d2ac; // instance position from matrix uStack40 = CONCAT22(*(undefined2 *)(iVar10 + 0x48),*(undefined2 *)(iVar10 + 0x44)); uStack36 = CONCAT22(uStack36._2_2_,*(undefined2 *)(iVar10 + 0x4c)); // gGT->tileView[driver->driverID] puVar7 = PTR_DAT_8008d2ac + (uint)*(byte *)(iVar6 + 0x4a) * 0x110; // tileView 0x28 (matrix) gte_SetRotMatrix(puVar5 + 0x168 + 0x28); gte_SetTransMatrix(puVar5 + 0x168 + 0x28); // driver position into GTE setCopReg(2,in_zero,uStack40); setCopReg(2,in_at,uStack36); // Perspective Transformation (Single) copFunction(2,0x180001); // screenspace position of driver uVar1 = getCopReg(2,0xe); sStack32 = (short)uVar1; // TileView_rect.x *(short *)(iVar6 + 0x4b4) = // tileView variable sStack32 + *(short *)(PTR_DAT_8008d2ac + (uint)*(byte *)(iVar6 + 0x4a) * 0x110 + 0x184); sStack30 = (short)((uint)uVar1 >> 0x10); // TileView_rect.y *(short *)(iVar6 + 0x4b6) = // tileView variable sStack30 + *(short *)(puVar2 + (uint)*(byte *)(iVar6 + 0x4a) * 0x110 + 0x186); return 1; } return 1; } return 1; } // RB_CrateWeapon_LInC undefined4 FUN_800b4278(int param_1,undefined4 param_2,undefined4 param_3) { code *pcVar1; undefined4 uVar2; undefined4 *puVar3; int iVar4; // Get the Instance's thread iVar4 = *(int *)(param_1 + 0x6c); // if there is no thread if (iVar4 == 0) { // THREAD_BirthWithObject // 0x8 = size // 0 = no relation to param4 // 0x300 flag = SmallStackPool // 0x3 = static thread bucket iVar4 = FUN_8004205c(0x80303,&FUN_800b3d7c,s_crate_800b3cd8,0); // give thread to instance *(int *)(param_1 + 0x6c) = iVar4; // if the thread failed to init if (iVar4 == 0) { // quit return 0; } // Get the Crate object that the thread built puVar3 = *(undefined4 **)(iVar4 + 0x30); // give instance to thread *(int *)(iVar4 + 0x34) = param_1; // RB_CrateWeapon_ThCollide. smash crate when hit *(undefined4 *)(iVar4 + 0x28) = 0x800b3e7c; // initialize crate object *puVar3 = 0; *(undefined2 *)(puVar3 + 1) = 0; } // Get instance's funcThCollide pcVar1 = *(code **)(iVar4 + 0x28); // if there is no pointer if (pcVar1 == (code *)0x0) { // quit uVar2 = 0; } // if there is a pointer else { // execute the function pointer uVar2 = (*pcVar1)(iVar4,param_2,pcVar1,param_3); } return uVar2; } // RB_CrateFruit_ThCollide undefined4 FUN_800b432c(int param_1,int param_2,undefined4 param_3,int param_4) { short sVar1; undefined *puVar2; undefined4 in_zero; undefined4 in_at; ushort uVar3; int iVar4; undefined *puVar5; int *piVar6; undefined4 *puVar7; undefined4 uVar8; undefined4 uVar9; undefined4 uVar10; int iVar11; undefined4 local_48; char *local_44; undefined4 local_40; undefined4 local_3c; undefined *local_38; undefined4 local_34; undefined4 local_30; undefined4 local_28; uint local_24; short local_20 [2]; undefined4 local_1c; // get object from thread piVar6 = *(int **)(param_1 + 0x30); // get instance from thread iVar11 = *(int *)(param_1 + 0x34); if ( // If first member of object is zero (*piVar6 == 0) && ( // scale is zero (*(short *)(iVar11 + 0x1c) == 0 || // scale ix 0x1000 (*(short *)(iVar11 + 0x1c) == 0x1000)) ) ) { *piVar6 = 0x1e; // if scale is 0x1000 if (*(short *)(iVar11 + 0x1c) == 0x1000) { // set scale to zero (x, y, z) *(undefined2 *)(iVar11 + 0x1c) = 0; *(undefined2 *)(iVar11 + 0x1e) = 0; *(undefined2 *)(iVar11 + 0x20) = 0; // spawn an explosion // 0x26 = model ID // 0x300 flag = SmallStackPool // 0xd = "other" thread bucket local_48 = 0x26; local_44 = s_explosion1_800b3cbc; local_40 = 0x300; local_3c = 0xd; // RB_CrateAny_ThTick_Explode local_38 = &FUN_800b3d04; local_34 = 0; local_30 = 0; // create thread for explosion iVar4 = FUN_80030a50(&local_48); // set color *(undefined4 *)(iVar4 + 0x24) = 0xf2953a0; // set scale *(undefined2 *)(iVar4 + 0x22) = 0x1000; // explosion matrix = crate matrix uVar8 = *(undefined4 *)(iVar11 + 0x34); uVar9 = *(undefined4 *)(iVar11 + 0x38); uVar10 = *(undefined4 *)(iVar11 + 0x3c); *(undefined4 *)(iVar4 + 0x30) = *(undefined4 *)(iVar11 + 0x30); *(undefined4 *)(iVar4 + 0x34) = uVar8; *(undefined4 *)(iVar4 + 0x38) = uVar9; *(undefined4 *)(iVar4 + 0x3c) = uVar10; uVar8 = *(undefined4 *)(iVar11 + 0x44); uVar9 = *(undefined4 *)(iVar11 + 0x48); uVar10 = *(undefined4 *)(iVar11 + 0x4c); *(undefined4 *)(iVar4 + 0x40) = *(undefined4 *)(iVar11 + 0x40); *(undefined4 *)(iVar4 + 0x44) = uVar8; *(undefined4 *)(iVar4 + 0x48) = uVar9; *(undefined4 *)(iVar4 + 0x4c) = uVar10; // play sound for breaking box FUN_8002f0dc(0x3c,iVar11); // random number of wumpa to grab iVar4 = FUN_8003ea28(); iVar11 = iVar4; if (iVar4 < 0) { iVar11 = iVar4 + 3; } iVar11 = iVar4 + (iVar11 >> 2) * -4 + 5; // get type of object that broke fruit crate sVar1 = *(short *)(param_4 + 0xc); // if this was a player if (sVar1 == 0x18) { // get driver object iVar4 = *(int *)(param_2 + 0x30); // 5 frame cooldown between getting each wumpa *(undefined4 *)(iVar4 + 0x4b8) = 5; // set number of wumpa to pick up *(int *)(iVar4 + 0x4c0) = iVar11; // input vector is driver->instSelf->matrix.t[] position local_28 = CONCAT22(*(undefined2 *)(*(int *)(iVar4 + 0x1c) + 0x48), *(undefined2 *)(*(int *)(iVar4 + 0x1c) + 0x44)); local_24 = local_24 & 0xffff0000 | (uint)*(ushort *)(*(int *)(iVar4 + 0x1c) + 0x4c); puVar5 = PTR_DAT_8008d2ac + (uint)*(byte *)(iVar4 + 0x4a) * 0x110; gte_SetRotMatrix(puVar5 + 0x168 + 0x28); gte_SetTransMatrix(puVar5 + 0x168 + 0x28); setCopReg(2,in_zero,local_28); setCopReg(2,in_at,local_24); // Perspective Transformation (Single) copFunction(2,0x180001); puVar7 = (undefined4 *)local_20; uVar8 = getCopReg(2,0xe); local_20[0] = (short)uVar8; puVar5 = PTR_DAT_8008d2ac + (uint)*(byte *)(iVar4 + 0x4a) * 0x110; } // if this is not a player else { // If this is not: // DYNAMIC_BOMB // DYNAMIC_ROCKET // DYNAMIC_SHIELD (blue) // DYNAMIC_SHIELD_GREEN if (((sVar1 != 0x3b) && (sVar1 != 0x29)) && ((sVar1 != 0x56 && (sVar1 != 0x5e)))) { return 1; } // if this was an item that a player threw, // then give wumpa to that player // get object of driver who threw the weapon iVar4 = *(int *)(*(int *)(param_2 + 0x30) + 4); // 5 frame cooldown between getting each wumpa *(undefined4 *)(iVar4 + 0x4b8) = 5; // set number of wumpa to pick up *(int *)(iVar4 + 0x4c0) = iVar11; // input vector is driver->instSelf->matrix.t[] position local_28 = CONCAT22(*(undefined2 *)(*(int *)(iVar4 + 0x1c) + 0x48), *(undefined2 *)(*(int *)(iVar4 + 0x1c) + 0x44)); local_24 = local_24 & 0xffff0000 | (uint)*(ushort *)(*(int *)(iVar4 + 0x1c) + 0x4c); // tileView of driver puVar5 = PTR_DAT_8008d2ac + (uint)*(byte *)(iVar4 + 0x4a) * 0x110; // gGT->tileView[driver->driverID]->0x28 (matrix) gte_SetRotMatrix(puVar5 + 0x168 + 0x28); gte_SetTransMatrix(puVar5 + 0x168 + 0x28); // load driver position into GTE setCopReg(2,in_zero,local_28); setCopReg(2,in_at,local_24); // Perspective Transformation (Single) copFunction(2,0x180001); // get screenspace position of driver puVar7 = &local_1c; local_1c = getCopReg(2,0xe); puVar5 = PTR_DAT_8008d2ac + (uint)*(byte *)(iVar4 + 0x4a) * 0x110; // screen posX local_20[0] = (short)local_1c; } puVar2 = PTR_DAT_8008d2ac; // driver->PickupWumpaHUD.startX = screen posX + tileView startX *(short *)(iVar4 + 0x4bc) = local_20[0] + *(short *)(puVar5 + 0x184); // driver->PickupWumpaHUD.startY = screen posY + tileView startY - 0x14 *(short *)(iVar4 + 0x4be) = *(short *)((int)puVar7 + 2) + *(short *)(puVar2 + (uint)*(byte *)(iVar4 + 0x4a) * 0x110 + 0x186) + -0x14; return 1; } } uVar3 = *(ushort *)(param_4 + 0xc) & 0x7fff; if (((int)*(short *)(param_4 + 0xc) & 0x8000U) != 0) { *(ushort *)(param_4 + 0xc) = uVar3; if ((((uVar3 != 6) && (uVar3 != 0x27)) && (uVar3 != 0x46)) && (uVar3 != 0x47)) { return 0; } // offset4 = 1, prevent crate from growing back *(undefined2 *)(piVar6 + 1) = 1; } return 0; } // RB_CrateFruit_LInC undefined4 FUN_800b471c(int param_1,undefined4 param_2,undefined4 param_3) { code *pcVar1; undefined4 uVar2; undefined4 *puVar3; int iVar4; // Get the instance's thread iVar4 = *(int *)(param_1 + 0x6c); // if there is no thread if (iVar4 == 0) { // THREAD_BirthWithObject // 0x8 = size // 0 = no relation to param4 // 0x300 = SmallStackPool // 0x3 = static thread bucket iVar4 = FUN_8004205c(0x80303,&FUN_800b3d7c,s_fruit_crate_800b3ce0,0); // give thread to instance *(int *)(param_1 + 0x6c) = iVar4; // if thread failed if (iVar4 == 0) { // quit return 0; } // get the object attached to thread puVar3 = *(undefined4 **)(iVar4 + 0x30); // give Instance to thread *(int *)(iVar4 + 0x34) = param_1; // RB_CrateFruit_ThCollide *(undefined4 *)(iVar4 + 0x28) = 0x800b432c; // initialize crate object // no cooldown *puVar3 = 0; // not smashed *(undefined2 *)(puVar3 + 1) = 0; } // get the funcThCollide pcVar1 = *(code **)(iVar4 + 0x28); // if there is no function if (pcVar1 == (code *)0x0) { // do nothing uVar2 = 0; } // if there is a function else { // execute uVar2 = (*pcVar1)(iVar4,param_2,pcVar1,param_3); } return uVar2; } // RB_CrateTime_ThCollide undefined4 FUN_800b47d0(int param_1,int param_2,undefined4 param_3,int param_4) { // is param2 is PTR_DAT_8008d2ac + 0x1b2c // which is pointer to first player thread int *piVar1; undefined4 uVar2; undefined4 in_zero; undefined4 in_at; ushort uVar3; int iVar4; int iVar5; int iVar6; undefined *puVar7; short sVar8; undefined *puVar9; int iVar10; int *piVar11; undefined4 local_78; char *local_74; undefined4 local_70; undefined4 local_6c; undefined *local_68; undefined4 local_64; undefined4 local_60; undefined2 local_58; short local_56; undefined2 local_54; undefined auStack80 [32]; undefined4 local_30; undefined4 local_2c; short local_28; short sStack38; // get object from thread piVar11 = *(int **)(param_1 + 0x30); // get instance from thread iVar10 = *(int *)(param_1 + 0x34); if ((*piVar11 != 0) || ((*(short *)(iVar10 + 0x1c) != 0 && (*(short *)(iVar10 + 0x1c) != 0x1000))) ) { LAB_800b4b38: uVar3 = *(ushort *)(param_4 + 0xc) & 0x7fff; if (((int)*(short *)(param_4 + 0xc) & 0x8000U) != 0) { *(ushort *)(param_4 + 0xc) = uVar3; if ( ( ( // PU_EXPLOSIVE_CRATE (nitro) (uVar3 != 6) && // STATIC_CRATE_TNT (uVar3 != 0x27) ) && // STATIC_BEAKER_RED (uVar3 != 0x46) ) && // STATIC_BEAKER_GREEN (uVar3 != 0x47) ) { return 0; } // offset4 = 1, prevent crate from growing back *(undefined2 *)(piVar11 + 1) = 1; } return 0; } // == assume first frame of hit == *piVar11 = 0x1e; // if scale is not 0x1000 if (*(short *)(iVar10 + 0x1c) != 0x1000) goto LAB_800b4b38; // set scale to zero (x, y, z) *(undefined2 *)(iVar10 + 0x1c) = 0; *(undefined2 *)(iVar10 + 0x1e) = 0; *(undefined2 *)(iVar10 + 0x20) = 0; // spawn an exploded box // 0x26 = model index // 0x300 flag = SmallStackPool // 0xd = "other" thread bucket local_78 = 0x26; local_74 = s_explosion1_800b3cbc; local_70 = 0x300; local_6c = 0xd; // RB_CrateAny_ThTick_Explode local_68 = &FUN_800b3d04; local_64 = 0; local_60 = 0; // create thread for explosion iVar4 = FUN_80030a50(&local_78); // set color *(undefined4 *)(iVar4 + 0x24) = 0x80ff000; // set scale[4] *(undefined2 *)(iVar4 + 0x22) = 0x1000; // random vector {0, rand&0xfff, 0} local_58 = 0; iVar5 = FUN_80078be8(); iVar6 = iVar5; if (iVar5 < 0) { iVar6 = iVar5 + 0xfff; } local_56 = (short)iVar5 + (short)(iVar6 >> 0xc) * -0x1000; local_54 = 0; // set exploded box position to the position of the original crate *(undefined4 *)(iVar4 + 0x44) = *(undefined4 *)(iVar10 + 0x44); *(undefined4 *)(iVar4 + 0x48) = *(undefined4 *)(iVar10 + 0x48); *(undefined4 *)(iVar4 + 0x4c) = *(undefined4 *)(iVar10 + 0x4c); // make matrix from rand vector FUN_8006c2a4(auStack80,&local_58); // explosion matrix = crate matrix + random rotation FUN_8006c3b0(iVar4 + 0x30,iVar10 + 0x30,auStack80); // play sound for breaking box FUN_8002f0dc(0x3c,iVar10); // get modelID, from what kind of struct? sVar8 = *(short *)(param_4 + 0xc); // bomb or missle "bombtracker" if ((sVar8 == 0x3b) || (sVar8 == 0x29)) { LAB_800b493c: // if human player of any kind if (sVar8 == 0x18) goto LAB_800b4974; // pointer to player object, plus 4, driver #2 ??? iVar6 = *(int *)(*(int *)(param_2 + 0x30) + 4); // if this driver is an AI if ((*(uint *)(iVar6 + 0x2c8) & 0x100000) != 0) { return 1; } } else { // not DYNAMIC_PLAYER if (sVar8 != 0x18) { // not DYNAMIC_SHIELD (blue) if (sVar8 != 0x56) { // not DYNAMIC_SHIELD_GREEN if (sVar8 != 0x5e) goto LAB_800b4b2c; sVar8 = *(short *)(param_4 + 0xc); } goto LAB_800b493c; } LAB_800b4974: iVar6 = *(int *)(param_2 + 0x30); } // increment amount of time crates that are broken *(char *)(iVar6 + 0x32) = *(char *)(iVar6 + 0x32) + '\x01'; puVar9 = PTR_DAT_8008d2ac; // See model IDs in common.h, at 0x2160 // instance -> model -> modelID sVar8 = *(short *)(*(int *)(iVar10 + 0x18) + 0x10); // if model is a 1s crate if (sVar8 == 0x5c) { // Get current amount of frozen time piVar1 = (int *)(PTR_DAT_8008d2ac + 0x1e20); // you broke a 1s crate *(undefined4 *)(PTR_DAT_8008d2ac + 0x1e24) = 1; // increase amount of frozen time // by 0x3c0, which is 960, which is 1 second iVar4 = *piVar1 + 0x3c0; } // If model is not a 1s crate else { // if model is a 2s crate if (sVar8 == 100) { // Get current amount of frozen time piVar1 = (int *)(PTR_DAT_8008d2ac + 0x1e20); // you broke a 2s crate *(undefined4 *)(PTR_DAT_8008d2ac + 0x1e24) = 2; // increase amount of frozen time // by 0x780, 0x3c0*2, which is 2 seconds iVar4 = *piVar1 + 0x780; } // If model is not 1s crate or 2s crate, // then assume model is a 3s crate else { // make driver talk FUN_8002cbe8(0x13,(int)(short)(&DAT_80086e84)[*(byte *)(iVar6 + 0x4a)],0x10); puVar9 = PTR_DAT_8008d2ac; // Get current amount of frozen time piVar1 = (int *)(PTR_DAT_8008d2ac + 0x1e20); // you broke a 3s crate *(undefined4 *)(PTR_DAT_8008d2ac + 0x1e24) = 3; // increase amount of frozen time // by 0xb40, 0x3c0*3, which is 3 seconds iVar4 = *piVar1 + 0xb40; } } // Set current amount of frozen time *(int *)(puVar9 + 0x1e20) = iVar4; // Main EXE uses this when drawing string with time crate number *(undefined4 *)(iVar6 + 0x4b0) = 10; puVar9 = PTR_DAT_8008d2ac; local_30 = CONCAT22(*(undefined2 *)(iVar10 + 0x48),*(undefined2 *)(iVar10 + 0x44)); local_2c = CONCAT22(local_2c._2_2_,*(undefined2 *)(iVar10 + 0x4c)); // tileView of driver puVar7 = PTR_DAT_8008d2ac + (uint)*(byte *)(iVar6 + 0x4a) * 0x110; // tileView -> 0x28 (matrix) r0 = (MATRIX *)(PTR_DAT_8008d2ac + (uint)*(byte *)(iVar6 + 0x4a) * 0x110 + 400); gte_SetRotMatrix(r0); gte_SetTransMatrix(r0); // 3D position gte_ldv0(&local_30); gte_rtps(); // 2D position gte_stsxy(&uVar2); // screen posX local_28 = (short)uVar2; // driver->PickupHUD.startX = screen posX + tileView rect.x *(short *)(iVar6 + 0x4b4) = local_28 + *(short *)(PTR_DAT_8008d2ac + (uint)*(byte *)(iVar6 + 0x4a) * 0x110 + 0x184); // screen posY sStack38 = (short)((uint)uVar2 >> 0x10); // driver->PickupHUD.startY = screen posY + tileView rect.y *(short *)(iVar6 + 0x4b6) = sStack38 + *(short *)(puVar9 + (uint)*(byte *)(iVar6 + 0x4a) * 0x110 + 0x186); LAB_800b4b2c: // offset4 = 1, prevent crate from growing back *(undefined2 *)(piVar11 + 1) = 1; return 1; } // RB_CrateTime_LInC undefined4 FUN_800b4ba8(int param_1,undefined4 param_2,undefined4 param_3) { code *pcVar1; undefined4 uVar2; undefined4 *puVar3; int iVar4; // Get thread from instance iVar4 = *(int *)(param_1 + 0x6c); // if there is no thread if (iVar4 == 0) { // Naughty Dog made a string mistake, // this is DEFINITELY a timebox, not fruit crate // THREAD_BirthWithObject // 0x8 = size // 0 = no relation to param4 // 0x300 = SmallStackPool // 0x3 = static thread bucket iVar4 = FUN_8004205c(0x80303,&FUN_800b3d7c,s_fruit_crate_800b3ce0,0); // give thread to Instance *(int *)(param_1 + 0x6c) = iVar4; // if the thread failed if (iVar4 == 0) { // quit return 0; } // get the object attached to thread puVar3 = *(undefined4 **)(iVar4 + 0x30); // give instance to thread *(int *)(iVar4 + 0x34) = param_1; // RB_CrateTime_ThCollide, smash crate *(undefined4 *)(iVar4 + 0x28) = 0x800b47d0; // initialize object *puVar3 = 0; *(undefined2 *)(puVar3 + 1) = 0; } // get thread's funcThCollide pcVar1 = *(code **)(iVar4 + 0x28); // if the funcPtr does not exist if (pcVar1 == (code *)0x0) { // do nothing uVar2 = 0; } // if there is a function else { // execute it uVar2 = (*pcVar1)(iVar4,param_2,pcVar1,param_3); } return uVar2; } // RB_Crystal_ThCollide undefined4 FUN_800b4c5c(int param_1,int param_2,undefined4 param_3,int param_4) { short sVar1; undefined *puVar2; undefined4 in_zero; undefined4 in_at; undefined4 uVar3; undefined *puVar4; int iVar5; int iVar6; undefined4 local_18; uint local_14; short local_10; short sStack14; puVar2 = PTR_DAT_8008d2ac; // scratchpad modelID sVar1 = *(short *)(param_4 + 0xc); // get crystal instance from thread iVar6 = *(int *)(param_1 + 0x34); if ( // if this is a player of any kind (sVar1 == 0x18) || ( uVar3 = 0, // if this is a robotcar of any kind sVar1 == 0x3f ) ) { // driverThread->driverObj iVar5 = *(int *)(param_2 + 0x30); // If this is player if (sVar1 == 0x18) { // crystal position local_18 = CONCAT22(*(undefined2 *)(iVar6 + 0x48),*(undefined2 *)(iVar6 + 0x44)); local_14 = local_14 & 0xffff0000 | (uint)*(ushort *)(iVar6 + 0x4c); // tileView -> 0x28 (matrix) puVar4 = PTR_DAT_8008d2ac + (uint)*(byte *)(iVar5 + 0x4a) * 0x110; r0 = (MATRIX *)(PTR_DAT_8008d2ac + (uint)*(byte *)(iVar6 + 0x4a) * 0x110 + 400); gte_SetRotMatrix(r0); gte_SetTransMatrix(r0); // driver position gte_ldv0(&local_18); gte_rtps(); // get screen position gte_stsxy(&uVar3); // screenX local_10 = (short)uVar3; *(short *)(iVar5 + 0x4bc) = local_10 + *(short *)(PTR_DAT_8008d2ac + (uint)*(byte *)(iVar5 + 0x4a) * 0x110 + 0x184); // screenY sStack14 = (short)((uint)uVar3 >> 0x10); sVar1 = *(short *)(puVar2 + (uint)*(byte *)(iVar5 + 0x4a) * 0x110 + 0x186); // 5 frame cooldown between getting each wumpa *(undefined4 *)(iVar5 + 0x4b8) = 5; // one collectable item is picked up *(int *)(iVar5 + 0x4c0) = *(int *)(iVar5 + 0x4c0) + 1; *(short *)(iVar5 + 0x4be) = sStack14 + sVar1 + -0x14; } // set scale to zero (x, y, z) *(undefined2 *)(iVar6 + 0x1c) = 0; *(undefined2 *)(iVar6 + 0x1e) = 0; *(undefined2 *)(iVar6 + 0x20) = 0; // erase thread *(undefined4 *)(iVar6 + 0x6c) = 0; // play sound for picking up FUN_8002f0dc(0x43,iVar6); uVar3 = 1; // This thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; } return uVar3; } // RB_Crystal_ThTick void FUN_800b4dd8(int param_1) { int iVar1; int iVar2; int iVar3; // get instance from thread iVar3 = *(int *)(param_1 + 0x34); // get object from thread iVar2 = *(int *)(param_1 + 0x30); // Not sure why there's two of these? // Rotate on the Y axis // convert 3 rotation shorts into rotation matrix *(short *)(iVar2 + 2) = *(short *)(iVar2 + 2) + 0x40; FUN_8006c2a4(iVar3 + 0x30,iVar2); // Rotate on the Y axis // convert 3 rotation shorts into rotation matrix *(short *)(iVar2 + 2) = *(short *)(iVar2 + 2) + 0x40; FUN_8006c2a4(iVar3 + 0x30,iVar2); // Sine(angle) iVar1 = FUN_8003d184((int)*(short *)(iVar2 + 2)); *(int *)(iVar3 + 0x48) = (int)*(short *)(*(int *)(iVar3 + 0x2c) + 0x32) + ((iVar1 << 4) >> 0xc) + 0x30; // Vector_SpecLightSpin3D FUN_8005741c(iVar3,iVar2,s_O_O_O_800b5968); return; } // RB_Crystal_LInC undefined4 FUN_800b4e7c(int param_1,undefined4 param_2,undefined4 param_3) { undefined4 uVar1; code *pcVar2; int iVar3; // Check this Instance's thread iVar3 = *(int *)(param_1 + 0x6c); // If there is no thread if (iVar3 == 0) { // THREAD_BirthWithObject // 0x8 = size // 0 = no relation to param4 // 0x300 = SmallStackPool // 0x3 = static thread bucket iVar3 = FUN_8004205c(0x80303,FUN_800b4dd8,s_crystal_800b3cec,0); // give thread to instance *(int *)(param_1 + 0x6c) = iVar3; // if the thread failed to build if (iVar3 == 0) { // quit return 0; } // Give instance to thread *(int *)(iVar3 + 0x34) = param_1; // RB_Crystal_ThCollide, collect crystal *(undefined4 *)(iVar3 + 0x28) = 0x800b4c5c; // Get thread from instance iVar3 = *(int *)(param_1 + 0x6c); } uVar1 = 0; if ( // if there is a thread (iVar3 != 0) && ( // get the funcThCollide pcVar2 = *(code **)(iVar3 + 0x28), // if there is a function pointer pcVar2 != (code *)0x0 ) ) { // if scale is zero, and object is not drawn if (*(short *)(param_1 + 0x1c) == 0) { // do nothing uVar1 = 0; } // if object is drawn else { // execute function pointer uVar1 = (*pcVar2)(iVar3,param_2,pcVar2,param_3); } } return uVar1; } // RB_Crystal_LInB void FUN_800b4f48(int param_1) { int iVar1; undefined2 *puVar2; // If this Instance has no thread if (*(int *)(param_1 + 0x6c) == 0) { // THREAD_BirthWithObject // 0x8 = size // 0 = no relation to param4 // 0x300 = SmallStackPool // 0x3 = "static" iVar1 = FUN_8004205c(0x80303,FUN_800b4dd8,s_crystal_800b3cec,0); // give thread to Instance *(int *)(param_1 + 0x6c) = iVar1; // If the thread failed if (iVar1 == 0) { // quit return; } // get the object that the thread created puVar2 = *(undefined2 **)(iVar1 + 0x30); // give instance to thread *(int *)(iVar1 + 0x34) = param_1; // RB_Crystal_ThCollide, collect crystal *(undefined4 *)(iVar1 + 0x28) = 0x800b4c5c; // set rotX, rotY, and rotZ to zero *puVar2 = 0; puVar2[1] = 0; puVar2[2] = 0; // set color *(undefined4 *)(param_1 + 0x24) = 0xd22fff0; // instance flags, specular light *(uint *)(param_1 + 0x28) = *(uint *)(param_1 + 0x28) | 0x20000; } // RB_Default_LInB FUN_800b4fe4(param_1); return; } // RB_Default_LInB // used by wumpabox, weaponbox, timebox, as funcptr, // or called directly from other LevInstDefBirth funcptrs void FUN_800b4fe4(int param_1) { _DAT_1f80013c = 0x3000; _DAT_1f800140 = 0; // high-LOD collision (8 triangles) DAT_1f80013a = 2; // Get pointer to LEV _DAT_1f800144 = **(undefined4 **)(PTR_DAT_8008d2ac + 0x160); // Make a hitbox DAT_1f800108 = *(undefined2 *)(param_1 + 0x44); DAT_1f80010a = *(short *)(param_1 + 0x48) + -0x180; DAT_1f80010c = *(undefined2 *)(param_1 + 0x4c); DAT_1f800112 = *(short *)(param_1 + 0x48) + 0x80; DAT_1f800110 = DAT_1f800108; DAT_1f800114 = DAT_1f80010c; // COLL_SearchTree_FindQuadblock_Touching FUN_8001eb0c(&DAT_1f800108,&DAT_1f800110,&DAT_1f800118,0); // depending on quadblock found in BSP search, // choose to make instance reflective // RB_MakeInstanceReflective FUN_800abab0(&DAT_1f800118,param_1); return; } // RB_CtrLetter_ThCollide bool FUN_800b5090(int param_1,int param_2,undefined4 param_3,int param_4) { bool bVar1; short sVar2; short sVar3; undefined2 uVar4; MATRIX *r0; undefined *puVar5; int iVar6; int iVar7; long *r0_00; int iVar8; undefined *puVar9; // puVar9+0x00 undefined auStack40 [16]; // puVar9+0x10 undefined2 uStack24; undefined2 uStack22; // puVar9+0x18 undefined2 uStack20; // ... (more stack variables) puVar9 = auStack40; // get instance from thread iVar8 = *(int *)(param_1 + 0x34); // only continue if letter was hit by a player bVar1 = *(short *)(param_4 + 0xc) == 0x18; if (bVar1) { // get object from thread, // get position from instance matrix uStack24 = *(undefined2 *)(iVar8 + 0x44); iVar7 = *(int *)(param_2 + 0x30); uStack22 = *(undefined2 *)(iVar8 + 0x48); uStack20 = *(undefined2 *)(iVar8 + 0x4c); // 80090000 puVar5 = &DAT_80090000; // gGT->tileView[driver->driverID]->0x28 (matrix) r0 = (MATRIX *)(PTR_DAT_8008d2ac + 0x168 + (uint)*(byte *)(iVar7 + 0x4a) * 0x110 + 0x28); gte_SetRotMatrix(r0); gte_SetTransMatrix(r0); // load position of driver gte_ldv0((SVECTOR *)(puVar9 + 0x10)); // perspective project gte_rtps(); // get screenspace position of driver r0_00 = (long *)(puVar9 + 0x18); gte_stsxy(r0_00); // 8008d2ac iVar6 = *(int *)(puVar5 + -0x2d54); // driver->letterHUD.startX *(short *)(iVar7 + 0x4c8) = // &r0_00 + 0x0 (screen posX) *(short *)(puVar9 + 0x18) + // gGT->tileView[driver->driverID].rect.x *(short *)(iVar6 + (uint)*(byte *)(iVar7 + 0x4a) * 0x110 + 0x168 + 0x1c); // &r0_00 + 0x2 (screen posY) sVar2 = *(short *)((int)r0_00 + 2); // gGT->tileView[driver->driverID].rect.y sVar3 = *(short *)(iVar6 + (uint)*(byte *)(iVar7 + 0x4a) * 0x110 + 0x168 + 0x1e); // should last 10 frames *(undefined2 *)(iVar7 + 0x4c4) = 10; // driver->letterHUD.startY = screenPosY + rect.y - 0x14 *(short *)(iVar7 + 0x4ca) = sVar2 + sVar3 + -0x14; // modelID uVar4 = *(undefined2 *)(*(int *)(iVar8 + 0x18) + 0x10); // increment number of CTR Letters collected *(int *)(iVar7 + 0x4cc) = *(int *)(iVar7 + 0x4cc) + 1; // modelID of letter hit *(undefined2 *)(iVar7 + 0x4c6) = uVar4; // Set Scale (X, Y, Z) to zero, make the 3D letter invisible *(undefined2 *)(iVar8 + 0x1c) = 0; *(undefined2 *)(iVar8 + 0x1e) = 0; *(undefined2 *)(iVar8 + 0x20) = 0; // erase thread *(undefined4 *)(iVar8 + 0x6c) = 0; // Make it completely invisible, stop drawing letter entirely *(uint *)(iVar8 + 0x28) = *(uint *)(iVar8 + 0x28) | 0x80; // Play a "ding" sound FUN_80028468(100,1); // This thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; } return bVar1; } // RB_CtrLetter_LInC undefined4 FUN_800b5210(int param_1,undefined4 param_2,undefined4 param_3) { undefined4 uVar1; code *pcVar2; int iVar3; // Get the thread of this Instance iVar3 = *(int *)(param_1 + 0x6c); // If there is no thread if (iVar3 == 0) { // This is a "world" letter, not a "hud" letter // 800b3cf4 // "ctr" // THREAD_BirthWithObject // 0x4 = size // 0 = no relation to param4 // 0x300 = SmallStackPool // 0x3 = "static" thread bucket iVar3 = FUN_8004205c(0x40303,FUN_800b52dc,&DAT_800b3cf4,0); // save thread pointer to Instance *(int *)(param_1 + 0x6c) = iVar3; // If the thread failed to initialize if (iVar3 == 0) { // return failure return 0; } // save Instance pointer to the thread *(int *)(iVar3 + 0x34) = param_1; // RB_CtrLetter_ThCollide *(undefined4 *)(iVar3 + 0x28) = 0x800b5090; // set iVar3 back to the thread pointer that // it was set to originally iVar3 = *(int *)(param_1 + 0x6c); } // At this point, we must have a valid thread uVar1 = 0; if ( // if we have a valid thread (iVar3 != 0) && ( // get funcThCollide pcVar2 = *(code **)(iVar3 + 0x28), // If this is a valid funcPtr pcVar2 != (code *)0x0 ) ) { // If the scale of this object is not zero if (*(short *)(param_1 + 0x1c) == 0) { // No event executed uVar1 = 0; } // If this object has a scale, // and therefore the object is drawn else { // Execute th->funcThCollide pointer uVar1 = (*pcVar2)(iVar3,param_2,pcVar2,param_3); } } return uVar1; } // RB_CtrLetter_ThTick void FUN_800b52dc(int param_1) { int iVar1; int iVar2; // get instance from thread iVar2 = *(int *)(param_1 + 0x34); // get object from thread iVar1 = *(int *)(param_1 + 0x30); // Spin on the Y axis *(short *)(iVar1 + 2) = *(short *)(iVar1 + 2) + 0x40; // (iVar2 + 0x30) is matrix // (iVar1) is vec3s rotation // Convert rotations into a matrix FUN_8006c2a4(iVar2 + 0x30,iVar1); // Vector_SpecLightSpin3D FUN_8005741c(iVar2,iVar1,&DAT_800b5970); return; } // RB_CtrLetter_LInB void FUN_800b5334(int param_1) { int iVar1; undefined2 *puVar2; if (*(int *)(param_1 + 0x6c) == 0) { // This is a "world" letter, not a "hud" letter // 800b3cf4 // "ctr" // THREAD_BirthWithObject // 0x8 = size // 0 = no relation to param4 // 0x300 = SmallStackPool // 0x3 = "static" thread bucket iVar1 = FUN_8004205c(0x80303,FUN_800b52dc,&DAT_800b3cf4,0); // Save the thread into Instance *(int *)(param_1 + 0x6c) = iVar1; // If the thread failed if (iVar1 == 0) { // Quit return; } // Get the pointer to the token that the thread created puVar2 = *(undefined2 **)(iVar1 + 0x30); // RB_CtrLetter_ThCollide *(undefined4 *)(iVar1 + 0x28) = 0x800b5090; *(int *)(iVar1 + 0x34) = param_1; // Initialize the CTR-Letter object *puVar2 = 0; puVar2[1] = 0; puVar2[2] = 0; // Set Instance's Scale of 3D letter (X, Y, Z) *(undefined2 *)(param_1 + 0x1c) = 0x1800; *(undefined2 *)(param_1 + 0x1e) = 0x1800; *(undefined2 *)(param_1 + 0x20) = 0x1800; // Set the color *(undefined4 *)(param_1 + 0x24) = 0xffc8000; // Set flags *(uint *)(param_1 + 0x28) = *(uint *)(param_1 + 0x28) | 0x30000; } // RB_Default_LInB FUN_800b4fe4(param_1); return; } // RB_Banner_Animate_Init // param_1 pointer to banner modelHeader int FUN_800b53e0(int param_1) { byte bVar1; uint uVar2; uint uVar3; uint *puVar4; byte *pbVar5; byte *pbVar6; int iVar7; short sVar8; sVar8 = 0; // modelHeader->ptrCommands, skip 2 bytes (skip numColors) puVar4 = (uint *)(*(short **)(param_1 + 0x20) + 2); // modelHeader->ptrVertexData pbVar5 = (byte *)(*(int *)(param_1 + 0x24) + *(int *)(*(int *)(param_1 + 0x24) + 0x18)); // if less than 64 colors found, quit if (**(short **)(param_1 + 0x20) < 0x40) { return 0; } if (*puVar4 != 0xffffffff) { uVar2 = *puVar4; do { if ((uVar2 & 0xffff0000) == 0) { LAB_800b563c: puVar4 = puVar4 + 1; } else { if (-1 < (int)uVar2) { if ((uVar2 & 0x4000000) == 0) { _DAT_1f800300 = (uint)CONCAT12(pbVar5[2],(ushort)*pbVar5); _DAT_1f800304 = _DAT_1f800304 & 0xffff0000 | (uint)pbVar5[1]; *(uint *)((uint)*(byte *)((int)puVar4 + 2) * 8 + 0x1f800000) = _DAT_1f800300; (&DAT_1f800004)[(uint)*(byte *)((int)puVar4 + 2) * 2] = _DAT_1f800304; sVar8 = sVar8 + 1; uVar3 = *puVar4 & 0xffff01ff; *puVar4 = uVar3; bVar1 = *pbVar5; pbVar5 = pbVar5 + 3; uVar2 = (uint)(bVar1 >> 2); } else { _DAT_1f800300 = *(uint *)((uVar2 >> 0xd & 0x7f8) + 0x1f800000); _DAT_1f800304 = (&DAT_1f800004)[(uint)*(byte *)((int)puVar4 + 2) * 2]; uVar3 = *puVar4 & 0xf7ff01ff; *puVar4 = uVar3; uVar2 = (int)(_DAT_1f800300 << 0x10) >> 0x12; } *puVar4 = uVar3 | uVar2 << 9; goto LAB_800b563c; } iVar7 = 0; pbVar6 = pbVar5 + 1; do { if ((*puVar4 & 0x4000000) == 0) { _DAT_1f800300 = (uint)CONCAT12(pbVar6[1],(ushort)*pbVar5); sVar8 = sVar8 + 1; _DAT_1f800304 = _DAT_1f800304 & 0xffff0000 | (uint)*pbVar6; *(uint *)((uint)*(byte *)((int)puVar4 + 2) * 8 + 0x1f800000) = _DAT_1f800300; (&DAT_1f800004)[(uint)*(byte *)((int)puVar4 + 2) * 2] = _DAT_1f800304; pbVar6 = pbVar6 + 3; uVar3 = *puVar4 & 0xffff01ff; *puVar4 = uVar3; bVar1 = *pbVar5; pbVar5 = pbVar5 + 3; uVar2 = (uint)(bVar1 >> 2); } else { _DAT_1f800300 = *(uint *)((*puVar4 >> 0xd & 0x7f8) + 0x1f800000); _DAT_1f800304 = (&DAT_1f800004)[(uint)*(byte *)((int)puVar4 + 2) * 2]; uVar3 = *puVar4 & 0xf7ff01ff; *puVar4 = uVar3; uVar2 = (int)(_DAT_1f800300 << 0x10) >> 0x12; } *puVar4 = uVar3 | uVar2 << 9; iVar7 = iVar7 + 1; puVar4 = puVar4 + 1; } while (iVar7 * 0x10000 >> 0x10 < 3); } uVar2 = *puVar4; } while (uVar2 != 0xffffffff); } // Only if there are four players, // do not wave the banner, leave it flat if (3 < (byte)PTR_DAT_8008d2ac[0x1ca8]) { // modelHeader->ptrVertexData uVar2 = *(int *)(param_1 + 0x24) + *(int *)(*(int *)(param_1 + 0x24) + 0x18); uVar3 = uVar2 + (int)sVar8 * 3; while (uVar2 < uVar3) { *(undefined *)(uVar2 + 1) = 0x80; uVar2 = uVar2 + 3; } } return (int)sVar8; } // RB_Banner_Animate_Play void FUN_800b56c4(int param_1,short param_2) { byte bVar1; int iVar2; uint uVar3; undefined4 *puVar4; undefined4 *puVar5; byte *pbVar6; int iVar7; byte *pbVar8; undefined4 uVar9; // modelHeader -> ptrColors puVar4 = *(undefined4 **)(param_1 + 0x2c); iVar7 = 0; uVar9 = *puVar4; puVar5 = puVar4; do { puVar5 = puVar5 + 1; iVar7 = iVar7 + 1; *puVar4 = *puVar5; puVar4 = puVar4 + 1; } while (iVar7 * 0x10000 >> 0x10 < 0x3f); *puVar4 = uVar9; // modelHeader -> ptrColors iVar7 = *(int *)(param_1 + 0x2c); // modelHeader->ptrVertexData pbVar6 = (byte *)(*(int *)(param_1 + 0x24) + *(int *)(*(int *)(param_1 + 0x24) + 0x18)); pbVar8 = pbVar6 + (int)param_2 * 3; do { if (pbVar8 <= pbVar6) { return; } bVar1 = *(byte *)(((((uint)*pbVar6 << 0x10) >> 0x12) + 10 & 0x3f) * 4 + iVar7); uVar3 = (int)((uint)*pbVar6 << 0x10) >> 0x10; if (uVar3 < 0x40) { iVar2 = uVar3 << 2; LAB_800b5788: bVar1 = (char)(((uint)bVar1 - 0x80) * iVar2 >> 8) + 0x80; } else { if (0xc0 < uVar3) { iVar2 = (0x100 - uVar3) * 4; goto LAB_800b5788; } } pbVar6[1] = bVar1; pbVar6 = pbVar6 + 3; } while( true ); } // RB_Banner_ThTick void FUN_800b57b4(int param_1) { // thread -> object -> 2??? // Basically checks if banner should wave, // which does not happen in 3P or 4P multiplayer if (*(short *)(*(int *)(param_1 + 0x30) + 2) != 0) { // RB_Banner_Animate_Play FUN_800b56c4( // thread -> instance -> model -> pointerModelHeaders *(undefined4 *)(*(int *)(*(int *)(param_1 + 0x34) + 0x18) + 0x14), // frame index? *(short *)(*(int *)(param_1 + 0x30) + 2) ); } return; } // RB_Banner_LInB void FUN_800b57f8(int param_1) { undefined *puVar1; int iVar2; uint uVar3; char cVar4; int iVar5; char *pcVar6; char *pcVar7; undefined2 *puVar8; // If this instance has no thread if (*(int *)(param_1 + 0x6c) == 0) { // THREAD_BirthWithObject // 0x4 = size // 0 = no relation to param4 // 0x300 = SmallStackPool // 0x3 = "static" thread bucket iVar2 = FUN_8004205c(0x40303,FUN_800b57b4,s_startbanner_800b3cf8,0); // give thread to instance *(int *)(param_1 + 0x6c) = iVar2; // if the thread built successfully if (iVar2 != 0) { // if more than 3 screens if (3 < (byte)PTR_DAT_8008d2ac[0x1ca8]) { // there is no function per frame, // so the flag does not wave *(undefined4 *)(iVar2 + 0x2c) = 0; } puVar1 = PTR_DAT_8008d2ac; // get the object created with the thread puVar8 = *(undefined2 **)(iVar2 + 0x30); // give Instance to thread *(int *)(iVar2 + 0x34) = param_1; // initialize the object *puVar8 = 0; puVar8[1] = 0; // Pointer to Startbanner model iVar2 = *(int *)(puVar1 + 0x23f8); // if startbanner model is loaded if (iVar2 != 0) { // instance -> model *(int *)(param_1 + 0x18) = iVar2; // RB_Banner_Animate_Init // pass model -> modelHeader uVar3 = FUN_800b53e0(*(undefined4 *)(iVar2 + 0x14)); puVar8[1] = (short)uVar3; if ((uVar3 & 0xffff) != 0) { iVar2 = 0; // instance -> model -> modelHeader -> ptrColors pcVar7 = *(char **)(*(int *)(*(int *)(param_1 + 0x18) + 0x14) + 0x2c); pcVar6 = pcVar7 + 1; // iVar2 = 0; iVar4 < 0x40; iVar2++ do { uVar3 = (iVar2 << 0x10) >> 9; // approximate trigonometry iVar5 = (&DAT_800845a0)[uVar3 & 0x3ff]; if ((uVar3 & 0x400) == 0) { iVar5 = iVar5 << 0x10; } iVar5 = iVar5 >> 0x10; if ((uVar3 & 0x800) != 0) { iVar5 = -iVar5; } cVar4 = (char)(iVar5 >> 6) + -0x80; // if more than 3 screens if (3 < (byte)PTR_DAT_8008d2ac[0x1ca8]) { cVar4 = -0x80; } iVar2 = iVar2 + 1; pcVar6[1] = cVar4; *pcVar6 = cVar4; pcVar6 = pcVar6 + 4; *pcVar7 = cVar4; pcVar7 = pcVar7 + 4; } while (iVar2 * 0x10000 >> 0x10 < 0x40); } } } } return; } // RB_Armadillo_ThTick_TurnAround void FUN_800b5984(int param_1) { char cVar1; short sVar2; undefined2 uVar3; int iVar4; code *pcVar5; int iVar6; int iVar7; int iVar8; // thread -> object iVar8 = *(int *)(param_1 + 0x30); // thread -> instance iVar7 = *(int *)(param_1 + 0x34); // infinite loop? do { // if current rotation is the desired rotation, then stop spinning if ((int)*(short *)(iVar8 + 2) == (int)*(short *)(iVar8 + 10)) { // instance->animFrame sVar2 = *(short *)(iVar7 + 0x54); // INSTANCE_GetNumAnimFrames iVar4 = FUN_80030f58(iVar7,0); // if animation is not done if ((int)sVar2 + 1 < iVar4) goto LAB_800b5a08; // if animation is done // invert velX, to reverse armadillo direction *(short *)(iVar8 + 6) = -*(short *)(iVar8 + 6); // unused // numFramesSpinning *(undefined2 *)(iVar8 + 0x12) = 0; // invert velZ, to reverse armadillo direction *(short *)(iVar8 + 0xe) = -*(short *)(iVar8 + 0xe); // if direction is zero if (*(short *)(iVar8 + 0x1a) == 0) { // play armadillo roll sound FUN_8002f0dc(0x70,iVar7); // go the other way, direction = 1 *(undefined2 *)(iVar8 + 0x1a) = 1; } // if direction is 1 else { // play armadillo roll sound FUN_8002f0dc(0x70,iVar7); // go the other way, direction = 0 *(undefined2 *)(iVar8 + 0x1a) = 0; } // set animation to 1 (rolling) *(undefined *)(iVar7 + 0x52) = 1; // reset animation frame *(undefined2 *)(iVar7 + 0x54) = 0; // Change ThTick to RB_Armadillo_ThTick_Rolling FUN_800716ec(param_1,&FUN_800b5b74); } else { // RB_Hazard_InterpolateValue // rotate armadillo to desired rotation uVar3 = FUN_800ada90((int)*(short *)(iVar8 + 2),(int)*(short *)(iVar8 + 10),0x100); *(undefined2 *)(iVar8 + 2) = uVar3; // convert 3 rotation shorts into rotation matrix FUN_8006c2a4(iVar7 + 0x30,iVar8); LAB_800b5a08: // increment animation frame *(short *)(iVar7 + 0x54) = *(short *)(iVar7 + 0x54) + 1; } // check for collision with human drivers iVar4 = FUN_800314e0(iVar7,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b2c),0x2400); // if there is no collision with human drivers if (iVar4 == 0) { // check for collision with AI drivers iVar4 = FUN_800314e0(iVar7,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b40),0x2400); // if there is no collision with AI drivers if (iVar4 == 0) { // check for collision with Mines (tnt, beaker, etc) iVar4 = FUN_800314e0(iVar7,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b7c),0x2400); // if there is a collision if (iVar4 != 0) { // instance -> thread -> funcThCollide pcVar5 = *(code **)(*(int *)(iVar4 + 0x6c) + 0x28); // execute funcThCollide (*pcVar5)(*(int *)(iVar4 + 0x6c)); } } // if there is collision with an AI driver else { // RB_Hazard_HurtDriver (spin out) FUN_800ac1b0(*(undefined4 *)(*(int *)(iVar4 + 0x6c) + 0x30),1,0,0); } } // if there is collision with human drivers else { // get driver object iVar6 = *(int *)(*(int *)(iVar4 + 0x6c) + 0x30); // get kart state cVar1 = *(char *)(iVar6 + 0x376); // RB_Hazard_HurtDriver (spin out) iVar4 = FUN_800ac1b0(iVar6,1,0,0); // if change state worked, and if kart was not // already spinning out before this if ((iVar4 != 0) && (cVar1 != '\x03')) { // play armadillo hit sound FUN_80028494(0x71,1,(uint)*(ushort *)(iVar6 + 0x2ca) & 1); } } // this skips $RA backup/restore, faster than JR $RA FUN_80071694(param_1); } while( true ); } // RB_Armadillo_ThTick_Rolling void FUN_800b5b74(int param_1) { char cVar1; short sVar2; int iVar3; code *pcVar4; int iVar5; undefined2 *puVar6; int iVar7; undefined2 uStack40; undefined2 uStack38; undefined2 uStack36; // thread -> object puVar6 = *(undefined2 **)(param_1 + 0x30); // thread -> instance iVar7 = *(int *)(param_1 + 0x34); // infinite loop? do { // if time at edge is zero if (puVar6[0xe] == 0) { // if Time Rolling < 0x500 (1.333 seconds) if ((short)puVar6[8] < 0x500) { // increase Time Rolling // add 32 milliseconds, assuming 30fps puVar6[8] = puVar6[8] + 0x20; // if direction is zero if (puVar6[0xd] == 0) { // increase distance from spawn sVar2 = puVar6[10] + 1; } // if direction is 1 else { // decrease distance from spawn sVar2 = puVar6[10] + -1; } // set distance from spawn puVar6[10] = sVar2; // instance -> animationFrame sVar2 = *(short *)(iVar7 + 0x54); // instance -> posX += velX *(int *)(iVar7 + 0x44) = *(int *)(iVar7 + 0x44) + (int)(short)puVar6[3]; // instance -> posZ += velZ *(int *)(iVar7 + 0x4c) = *(int *)(iVar7 + 0x4c) + (int)(short)puVar6[7]; // INSTANCE_GetNumAnimFrames iVar3 = FUN_80030f58(iVar7); // if animation is not done if ((int)sVar2 + 1 < iVar3) { // increment animation frame *(short *)(iVar7 + 0x54) = *(short *)(iVar7 + 0x54) + 1; } // if animation is done else { // restart animation *(undefined2 *)(iVar7 + 0x54) = 0; } // Check for collision with human drivers iVar3 = FUN_800314e0(iVar7,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b2c),0x2400); // if armadillo did not collide with any human driver if (iVar3 == 0) { // Check for collision with AI drivers iVar3 = FUN_800314e0(iVar7,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b40),0x2400); // if there is no collision with AIs if (iVar3 == 0) { // Check for collision with Mines (tnts, beakers, etc) iVar3 = FUN_800314e0(iVar7,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b7c),0x2400); // if there is a collision if (iVar3 != 0) { // funcThCollide pcVar4 = *(code **)(*(int *)(iVar3 + 0x6c) + 0x28); // execute funcThCollide (*pcVar4)(*(int *)(iVar3 + 0x6c)); } } // if there is collision with AIs else { // RB_Hazard_HurtDriver (spin out) FUN_800ac1b0(*(undefined4 *)(*(int *)(iVar3 + 0x6c) + 0x30),1,0,0); } } // if armadillo collided with a driver else { // instance -> thread -> (Driver*) object iVar5 = *(int *)(*(int *)(iVar3 + 0x6c) + 0x30); // get kart state cVar1 = *(char *)(iVar5 + 0x376); // RB_Hazard_HurtDriver (spin out) iVar3 = FUN_800ac1b0(iVar5,1,0,0); // if change state worked, and if kart was not // already spinning out before this if ((iVar3 != 0) && (cVar1 != '\x03')) { // play armadillo hit sound FUN_80028494(0x71,1,(uint)*(ushort *)(iVar5 + 0x2ca) & 1); } } } // if armadillo rolled for more than 0x500 frames else { // CTR_MatrixToRot // iVar7+30 = armadillo inst->matrix FUN_80021edc(&uStack40,iVar7 + 0x30,0x11); // reset rotation, // reset timeRolling *puVar6 = uStack38; puVar6[1] = uStack40; puVar6[8] = 0; puVar6[2] = uStack36; // set animation index to zero (jumping) *(undefined *)(iVar7 + 0x52) = 0; // reset animation *(undefined2 *)(iVar7 + 0x54) = 0; // set desired rotation, 180 degrees from current iVar5 = (int)(short)puVar6[1] + 0x800; iVar3 = iVar5; if (iVar5 < 0) { iVar3 = (int)(short)puVar6[1] + 0x17ff; } puVar6[5] = (short)iVar5 + (short)(iVar3 >> 0xc) * -0x1000; // Change thread to RB_Armadillo_ThTick_TurnAround FUN_800716ec(param_1,&FUN_800b5984); } } // if you are waiting at edge // before rolling again else { // reduce by one frame puVar6[0xe] = puVar6[0xe] + -1; } // this skips $RA backup/restore, faster than JR $RA FUN_80071694(param_1); } while( true ); } // RB_Armadillo_ThCollide void FUN_800b5dbc(int param1, int param_2, int param_3, int param_4) { // check if modelID is player // modelID is 0xc of BSP meta return (uint)(*(short *)(param_4 + 0xc) == 0x18); } // RB_Armadillo_LInB void FUN_800b5dd0(int param_1) { undefined2 uVar1; undefined *puVar2; int iVar3; int iVar4; undefined2 *puVar5; undefined2 local_18; undefined2 local_16; undefined2 local_14; // If this instance has no thread if (*(int *)(param_1 + 0x6c) == 0) { // THREAD_BirthWithObject // 0x20 = size // 0 = no relation to param4 // 0x300 = SmallStackPool // 0x3 = "static" thread bucket iVar3 = FUN_8004205c(0x200303,&FUN_800b5b74,s_armadillo_800b5978,0); // give thread to instance *(int *)(param_1 + 0x6c) = iVar3; // if thread exists if (iVar3 != 0) { // Set animation to 1 (rolling) *(undefined *)(param_1 + 0x52) = 1; // get the object created by the thread puVar5 = *(undefined2 **)(iVar3 + 0x30); // give instance to thread *(int *)(iVar3 + 0x34) = param_1; // set funcThCollide to hurt the player *(undefined4 *)(iVar3 + 0x28) = 0x800b5dbc; // time rolling puVar5[8] = 0; // unused // numFramesSpinning puVar5[9] = 0; // CTR_MatrixToRot // param1+30 = armadillo inst->matrix FUN_80021edc(&local_18,param_1 + 0x30,0x11); // rotX *puVar5 = local_16; // rotY puVar5[1] = local_18; // rotY + 180 degrees iVar4 = (int)(short)puVar5[1] + 0x800; // rotZ puVar5[2] = local_14; // set desired rotation, 180 degrees from current iVar3 = iVar4; if (iVar4 < 0) { iVar3 = (int)(short)puVar5[1] + 0x17ff; } puVar5[5] = (short)iVar4 + (short)(iVar3 >> 0xc) * -0x1000; // posX puVar5[0xb] = *(undefined2 *)(param_1 + 0x44); // posZ uVar1 = *(undefined2 *)(param_1 + 0x4c); // set direction to zero // move away from spawn puVar5[0xd] = 0; // distFromSpawn puVar5[10] = 0; // posZ puVar5[0xc] = uVar1; // velX from forward direction of Instance MATRIX puVar5[3] = *(short *)(param_1 + 0x34) >> 7; puVar2 = PTR_DAT_8008d2ac; // velZ from forward direction of Instance MATRIX puVar5[7] = *(short *)(param_1 + 0x40) >> 7; // config -> Level -> trial_data -> numPointers if (0 < **(int **)(*(int *)(puVar2 + 0x160) + 0x134)) { // get length of instance's name iVar3 = strlen(param_1 + 8); // time at edge // puts armadillos on different cycles puVar5[0xe] = *(undefined2 *) (*(int *)(*(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x134) + 8) + // armadillo ID ((uint)*(byte *)(iVar3 + param_1 + 7) - 0x30) * 2); } } } return; } // RB_Fireball_ThTick void FUN_800b5f50(int param_1) { short sVar1; ushort uVar2; ushort uVar3; undefined *puVar4; code *pcVar5; undefined2 uVar6; int iVar7; int iVar8; int iVar9; short *psVar10; uint uVar11; // get object from thread psVar10 = *(short **)(param_1 + 0x30); // get instance from thread iVar9 = *(int *)(param_1 + 0x34); // cooldown timer uVar2 = psVar10[2]; uVar11 = 0; // if cooldown is over if (psVar10[2] == 0) { // make invisible *(uint *)(iVar9 + 0x28) = *(uint *)(iVar9 + 0x28) | 0x80; puVar4 = PTR_DAT_8008d2ac; if ((int)*(short *)(*(int *)(iVar9 + 0x2c) + 0x32) + -0x440 <= *(int *)(iVar9 + 0x48)) { // velY uVar11 = (uint)(ushort)psVar10[6]; // Change height by elapsed time *(int *)(iVar9 + 0x48) = *(int *)(iVar9 + 0x48) + ((int)psVar10[6] * *(int *)(PTR_DAT_8008d2ac + 0x1d04) >> 5); // subtract velY, which makes fireball move down iVar7 = (uint)(ushort)psVar10[6] - (*(int *)(puVar4 + 0x1d04) * 10 >> 5); // set new velY psVar10[6] = (short)iVar7; // terminal velocity if (iVar7 * 0x10000 >> 0x10 < -200) { // cant fall faster psVar10[6] = -200; } // Create instance in particle pool iVar7 = FUN_80040308(0,*(undefined4 *)(PTR_DAT_8008d2ac + 0x213c),&DAT_800b6344); if (iVar7 != 0) { // posX and posY *(int *)(iVar7 + 0x24) = *(int *)(iVar7 + 0x24) + *(int *)(iVar9 + 0x44) * 0x100; *(int *)(iVar7 + 0x2c) = *(int *)(iVar7 + 0x2c) + *(int *)(iVar9 + 0x48) * 0x100; iVar8 = *(int *)(iVar9 + 0x4c); *(undefined2 *)(iVar7 + 0x1a) = 0x1e00; // posZ *(int *)(iVar7 + 0x34) = *(int *)(iVar7 + 0x34) + iVar8 * 0x100; // velY iVar8 = (int)psVar10[6] * -0x180; // negative range if (iVar8 < -0x7fff) { iVar8 = -0x7fff; } uVar6 = (undefined2)iVar8; // positive range if (0x7fff < iVar8) { uVar6 = 0x7fff; } // particle velY *(undefined2 *)(iVar7 + 0x30) = uVar6; } // check for collision with players iVar7 = FUN_800314e0(iVar9,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b2c),0x10000); // if there is no collision if ((iVar7 == 0) && // check for collision with robotcars (iVar7 = FUN_800314e0(iVar9,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b40),0x10000), // if there is no collision iVar7 == 0)) { // check for collision with mines (tnt, beaker, etc) iVar7 = FUN_800314e0(iVar9,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b7c),0x10000); // if there is a collision if (iVar7 != 0) { // instance -> thread -> funcThCollide pcVar5 = *(code **)(*(int *)(iVar7 + 0x6c) + 0x28); // execute funcThCollide (*pcVar5)(*(int *)(iVar7 + 0x6c)); } } // if you collide with any driver at all else { // RB_Hazard_HurtDriver (burn) FUN_800ac1b0(*(undefined4 *)(*(int *)(iVar7 + 0x6c) + 0x30),4,0,0); } } // cycle timer *psVar10 = *psVar10 - *(short *)(PTR_DAT_8008d2ac + 0x1d04); if ( (-1 < (int)(uVar11 << 0x10)) && // if fireball is far down (psVar10[6] < 0) ) { // direction is now up psVar10[7] = 1; } // animation index sVar1 = *(short *)(iVar9 + 0x54); // INSTANCE_GetNumAnimFrames iVar7 = FUN_80030f58(iVar9,0); // increase frames if ((int)sVar1 + 1 < iVar7) { *(short *)(iVar9 + 0x54) = *(short *)(iVar9 + 0x54) + 1; } // reset animation to zero else { *(undefined2 *)(iVar9 + 0x54) = 0; } // if cycle is over if (*psVar10 < 1) { *(int *)(iVar9 + 0x48) = (int)*(short *)(*(int *)(iVar9 + 0x2c) + 0x32) + -0x440; // velY, psVar10[6] = 200; *(undefined2 *)(iVar9 + 0x54) = 0; // direction is down psVar10[7] = 0; // reset cycle to 2880ms, 2.8 seconds *psVar10 = 0xb40; // play sound FUN_8002f0dc(0x81, iVar9); } } // if cooldown is not over else { // elapsed time per frame ~32 uVar3 = *(ushort *)(PTR_DAT_8008d2ac + 0x1d04); // reduce timer psVar10[2] = (short)((uint)uVar2 - (uint)uVar3); // do not go below zero if ((int)(((uint)uVar2 - (uint)uVar3) * 0x10000) < 0) { // set to zero psVar10[2] = 0; } } return; } // RB_Fireball_ThCollide void FUN_800b625c(int param1, int param_2, int param_3, int param_4) { // check if modelID is player // modelID is 0xc of BSP meta return (uint)(*(short *)(param_4 + 0xc) == 0x18); } // RB_Fireball_LInB void FUN_800b6270(int param_1) { int iVar1; uint uVar2; undefined2 *puVar3; // If there is no thread for this instance if (*(int *)(param_1 + 0x6c) == 0) { // THREAD_BirthWithObject // 0x10 = size // 0 = no relation to param4 // 0x300 = SmallStackPool // 0x3 = "static" thread bucket iVar1 = FUN_8004205c(0x100303,&FUN_800b5f50,s_fireball_800b5f44,0); // give thread to instance *(int *)(param_1 + 0x6c) = iVar1; // if the thread built successfully if (iVar1 != 0) { // get the object attached to the thread puVar3 = *(undefined2 **)(iVar1 + 0x30); // set funcThCollide to burn the player *(undefined4 *)(iVar1 + 0x28) = 0x800b625c; // give instance to thread *(int *)(iVar1 + 0x34) = param_1; // set scale (x, y, z) of fireball *(undefined2 *)(param_1 + 0x1c) = 0x4000; *(undefined2 *)(param_1 + 0x1e) = 0x4000; *(undefined2 *)(param_1 + 0x20) = 0x4000; // set animation to 0 *(undefined *)(param_1 + 0x52) = 0; iVar1 = strlen(param_1 + 8); // fireball ID uVar2 = (uint)*(byte *)(iVar1 + param_1 + 7) - 0x30; puVar3[1] = (short)uVar2; puVar3[3] = 0; // velY (96) puVar3[6] = 0x60; // direction is down puVar3[7] = 0; // reset cycle timer *puVar3 = 0; // set cooldown of fireball // depending on ID if ((uVar2 & 1) == 0) { puVar3[2] = 0; } else { puVar3[2] = 0x5a0; } } } return; } // RB_FlameJet_Particles void FUN_800b64c0(int param_1,int param_2) { undefined2 uVar1; undefined *puVar2; int iVar3; int iVar4; int iVar5; // Create (ordinary) instance in particle pool iVar3 = FUN_80040308(0,*(undefined4 *)(PTR_DAT_8008d2ac + 0x213c),&DAT_800b6c20); puVar2 = PTR_DAT_8008d2ac; // if instance created successfully if (iVar3 != 0) { // position of particles *(int *)(iVar3 + 0x24) = *(int *)(iVar3 + 0x24) + *(int *)(param_1 + 0x44) * 0x100; *(int *)(iVar3 + 0x2c) = *(int *)(iVar3 + 0x2c) + (*(int *)(param_1 + 0x48) + 0x32) * 0x100; *(int *)(iVar3 + 0x34) = *(int *)(iVar3 + 0x34) + *(int *)(param_1 + 0x4c) * 0x100; // dirZ uVar1 = *(undefined2 *)(param_2 + 4); // velY = 0 *(undefined2 *)(iVar3 + 0x30) = 0; // velX *(undefined2 *)(iVar3 + 0x28) = uVar1; // velZ = dirZ *(undefined2 *)(iVar3 + 0x38) = *(undefined2 *)(param_2 + 8); iVar4 = FUN_8006c684(puVar2 + 0x252c); // Sine(angle) iVar4 = FUN_8003d184(*(int *)(PTR_DAT_8008d2ac + 0x1cec) * 0x100 + (iVar4 >> 0x18) & 0xfff); *(undefined2 *)(iVar3 + 0x32) = (short)(iVar4 >> 4); *(undefined2 *)(iVar3 + 0x1a) = 0x1e00; *(char *)(iVar3 + 0x18) = *(char *)(param_1 + 0x50) + -1; // odd-numbered frames if ((*(uint *)(PTR_DAT_8008d2ac + 0x1cec) & 1) != 0) { *(int *)(iVar3 + 0x44) = -*(int *)(iVar3 + 0x44); *(short *)(iVar3 + 0x48) = -*(short *)(iVar3 + 0x48); } } // if there is one player if (((byte)PTR_DAT_8008d2ac[0x1ca8] < 2) && ( // Create (heat) instance in particle pool iVar4 = FUN_80040308(0,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b24),&DAT_800b6a94), iVar4 != 0 )) { // position *(int *)(iVar4 + 0x24) = *(int *)(iVar4 + 0x24) + *(int *)(iVar3 + 0x24); *(int *)(iVar4 + 0x2c) = *(int *)(iVar4 + 0x2c) + 0x1000 + *(int *)(iVar3 + 0x2c); *(int *)(iVar4 + 0x34) = *(int *)(iVar4 + 0x34) + *(int *)(iVar3 + 0x34); // dirX uVar1 = *(undefined2 *)(param_2 + 4); // velY *(undefined2 *)(iVar4 + 0x30) = 0; // velX *(undefined2 *)(iVar4 + 0x28) = uVar1; // velZ = dirZ *(undefined2 *)(iVar4 + 0x38) = *(undefined2 *)(param_2 + 8); iVar5 = *(int *)(iVar4 + 0x3c) + -0x400; uVar1 = *(undefined2 *)(iVar3 + 0x32); iVar3 = *(int *)(iVar4 + 0x3c) + -0x600; *(int *)(iVar4 + 0x44) = iVar5; *(int *)(iVar4 + 0x4c) = iVar3; *(undefined2 *)(iVar4 + 0x1a) = 0x1e00; *(undefined2 *)(iVar4 + 0x32) = uVar1; *(undefined2 *)(iVar4 + 0x40) = (short)((0x4a00 - *(int *)(iVar4 + 0x3c)) / 7); *(undefined2 *)(iVar4 + 0x48) = (short)((0x4600 - iVar5) / 7); *(undefined2 *)(iVar4 + 0x50) = (short)((0x4400 - iVar3) / 7); *(undefined *)(iVar4 + 0x18) = *(undefined *)(param_1 + 0x50); } return; } // RB_FlameJet_ThTick void FUN_800b6728(int param_1) { int iVar1; int *piVar2; int iVar3; undefined4 local_48; undefined4 local_44; int local_40; int local_3c; undefined4 local_38; undefined4 local_34; undefined4 local_30; undefined4 local_2c; undefined4 local_28; int local_24; undefined4 local_20; undefined4 local_1c; // specular light direction? local_48 = DAT_800b64ac; local_44 = DAT_800b64b0; // get object from thread piVar2 = *(int **)(param_1 + 0x30); // get instance from thread iVar3 = *(int *)(param_1 + 0x34); // hitbox info local_34 = DAT_800b6d40; local_30 = DAT_800b6d44; local_2c = DAT_800b6d48; local_1c = 0; local_40 = iVar3; local_3c = param_1; local_24 = param_1; // if cooldown exists while (*(short *)((int)piVar2 + 0xe) != 0) { // reduce cooldown *(short *)((int)piVar2 + 0xe) = *(short *)((int)piVar2 + 0xe) + -1; // this skips $RA backup/restore, faster than JR $RA FUN_80071694(param_1); } do { iVar1 = *piVar2; // in first 45 frames (1.5 seconds) if (iVar1 < 0x2d) { // spawn particles and enable burn on collision // PlaySound3D_Flags // sound of fire, offset 0x10 FUN_8002f31c(piVar2 + 4,0x68,iVar3); // offset 0xC (see asm) *(short *)(piVar2 + 3) = *(short *)(piVar2 + 3) + 0x100; // RB_FlameJet_Particles FUN_800b64c0(iVar3,piVar2); // get first Player thread local_38 = *(undefined4 *)(PTR_DAT_8008d2ac + 0x1b2c); // check for collision iVar1 = FUN_800315ac(&local_40); // if there is no collision if (iVar1 == 0) { // get first robotcar thread local_38 = *(undefined4 *)(PTR_DAT_8008d2ac + 0x1b40); // check for collision iVar1 = FUN_800315ac(&local_40,4); // if there is no collision if (iVar1 == 0) { // get first Mine thread local_38 = *(undefined4 *)(PTR_DAT_8008d2ac + 0x1b7c); // check for collision iVar1 = FUN_800315ac(&local_40,4); // if there is collision if (iVar1 != 0) { // instance -> thread local_28 = *(undefined4 *)(iVar1 + 0x6c); // instance -> thread -> funcThCollide local_20 = *(undefined4 *)(*(int *)(iVar1 + 0x6c) + 0x28); // RB_Hazard_ThCollide_Generic_Alt FUN_800ac3f8(&local_28); } goto LAB_800b6908; } } // RB_Hazard_HurtDriver (burn) FUN_800ac1b0(*(undefined4 *)(*(int *)(iVar1 + 0x6c) + 0x30),4,0,0); } else { // on 45th frame (after 1.5 seconds) if (iVar1 == 0x2d) { // if audioPtr is valid if (piVar2[4] != 0) { // stop audio FUN_8002e724(piVar2 + 4); } } else { // repeat cycle every 105 (3.5 seconds) if (0x69 < iVar1) { *piVar2 = 0; } } } LAB_800b6908: // increment frame *piVar2 = *piVar2 + 1; // Vector_SpecLightNoSpin3D // instance, inst->instDef->rot[3], specLightDir FUN_800576b8(iVar3,*(int *)(iVar3 + 0x2c) + 0x36,&local_48); // this skips $RA backup/restore, faster than JR $RA FUN_80071694(param_1); } while( true ); } // RB_FlameJet_LInB void FUN_800b6938(int param_1) { short sVar1; int iVar2; undefined4 *puVar3; // Instance color: Yellow *(undefined4 *)(param_1 + 0x24) = 0xdca6000; // specular light *(uint *)(param_1 + 0x28) = *(uint *)(param_1 + 0x28) | 0x30000; if (*(int *)(param_1 + 0x6c) == 0) { // THREAD_BirthWithObject // 0x14 = size // 0 = no relation to param4 // 0x300 = SmallStackPool // 0x3 = static thread bucket iVar2 = FUN_8004205c(0x140303,FUN_800b6728,s_flamejet_800b64b4,0); // give thread to instance *(int *)(param_1 + 0x6c) = iVar2; // if thread built correctly if (iVar2 != 0) { // object from thread puVar3 = *(undefined4 **)(iVar2 + 0x30); // give instance to thread *(int *)(iVar2 + 0x34) = param_1; // cycle timer *puVar3 = 0; // cooldown *(undefined2 *)((int)puVar3 + 0xe) = 0; // dirX puVar3[1] = (int)*(short *)(param_1 + 0x34) * -0x4b >> 5; sVar1 = *(short *)(param_1 + 0x40); puVar3[4] = 0; // dirZ puVar3[2] = (int)sVar1 * 0x4b >> 5; // hitbox DAT_800b6d44._2_2_ = 0x40; DAT_800b6d40._0_2_ = 0xffc0; DAT_800b6d40._2_2_ = 0xffc0; DAT_800b6d48._0_2_ = 0x80; DAT_800b6d48._2_2_ = 0x140; DAT_800b6d44._0_2_ = 0; // LEV -> trial_data -> numPointers if (0 < **(int **)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x134)) { // probably strlen iVar2 = FUN_80077cc8(param_1 + 8); // cooldown *(undefined2 *)((int)puVar3 + 0xe) = *(undefined2 *) (*(int *)(*(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x134) + 8) + // flamejet ID from string ((uint)*(byte *)(iVar2 + param_1 + 7) - 0x30) * 2); } } } return; } // RB_Follower_ProcessBucket void FUN_800b6d58(int param_1) { undefined *puVar1; undefined *puVar2; uint uVar3; uint uVar4; int iVar5; int iVar6; puVar1 = PTR_DAT_8008d2ac; // if first thread exists if (param_1 != 0) { // loop through all threads do { puVar2 = PTR_DAT_8008d2ac; // if thread is not dead if ((*(uint *)(param_1 + 0x1c) & 0x800) == 0) { // object iVar6 = *(int *)(param_1 + 0x30); // instance iVar5 = *(int *)(param_1 + 0x34); // driver ID attached uVar4 = (uint)*(byte *)(*(int *)(iVar6 + 4) + 0x4a); uVar3 = 0; // loop for number of players if (puVar1[0x1ca9] != '\0') { do { // if this camera does not belong // to the driver that shot the weapon if (uVar4 != uVar3) { *(uint *)(iVar5 + 0xb8) = *(uint *)(iVar5 + 0xb8) & 0xffffffbf; } uVar3 = uVar3 + 1; iVar5 = iVar5 + 0x88; } while ((int)uVar3 < (int)(uint)(byte)puVar2[0x1ca9]); } iVar5 = *(int *)(*(int *)(iVar6 + 8) + 0x34) + uVar4 * 0x88; *(uint *)(iVar5 + 0xb8) = *(uint *)(iVar5 + 0xb8) & 0xffffffbf; } // follower->next param_1 = *(int *)(param_1 + 0x10); } while (param_1 != 0); } return; } // RB_Follower_ThTick void FUN_800b6e10(int param_1) { char cVar1; int iVar2; int *piVar3; int iVar4; // thread -> object piVar3 = *(int **)(param_1 + 0x30); // pointer to driver iVar4 = piVar3[1]; // something from object iVar2 = *piVar3; // driver state cVar1 = *(char *)(iVar4 + 0x376); // reduce life by one frame *piVar3 = iVar2 + -1; if ( ( (0 < iVar2 + -1) && (( // driver state (cVar1 == '\0' || (cVar1 == '\x02')) && // aren't these always equal? (*(int *)(piVar3[2] + 0x20) == piVar3[3]) )) ) && (-1 < *(short *)(iVar4 + 0x38e)) ) { // thread -> instance iVar2 = *(int *)(param_1 + 0x34); // if scale is small if (*(short *)(iVar2 + 0x1c) < 0x800) { // double the scale (x, y, z) *(short *)(iVar2 + 0x1c) = *(short *)(iVar2 + 0x1c) << 1; *(short *)(iVar2 + 0x1e) = *(short *)(iVar2 + 0x1e) << 1; *(short *)(iVar2 + 0x20) = *(short *)(iVar2 + 0x20) << 1; } // Change X, Y, Z, of mine, to the // midpoint between the current driver position, // and the position where the driver "was" at time of firing weapon *(int *)(iVar2 + 0x44) = (int)*(short *)((int)piVar3 + 0x10) + (*(int *)(iVar4 + 0x2d4) >> 8) >> 1; *(int *)(iVar2 + 0x48) = (int)*(short *)((int)piVar3 + 0x12) + (*(int *)(iVar4 + 0x2d8) >> 8) >> 1; *(int *)(iVar2 + 0x4c) = (int)*(short *)((int)piVar3 + 0x14) + (*(int *)(iVar4 + 0x2dc) >> 8) >> 1; return; } // This thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; return; } // RB_Follower_Init void FUN_800b6f00(int param_1,int param_2) { int iVar1; undefined4 *puVar2; int iVar3; undefined4 uVar4; undefined4 uVar5; undefined4 uVar6; if ( ( // driver->speed > 0x1e00 (0x1e00 < *(short *)(param_1 + 0x38e)) && // if driver is not an AI ((*(uint *)(param_1 + 0x2c8) & 0x100000) == 0) ) && ( // cameraBuffer[driver -> index] (*(uint *)(PTR_DAT_8008d2ac + (uint)*(byte *)(param_1 + 0x4a) * 0xdc + 0x1508) & 0x10000) == 0 ) ) { // create a thread and an Instance // 0x18 - Follower size // 0x300 flag = SmallStackPool // 0xb = "follower" thread bucket iVar1 = FUN_800309a4((int)*(short *)(param_2 + 0x44),s_follower_800b6d4c,0x300,0xb, &FUN_800b6e10,0x18,0); // if that worked successfully if (iVar1 != 0) { // set the scale *(undefined2 *)(iVar1 + 0x1c) = 0x200; *(undefined2 *)(iVar1 + 0x1e) = 0x200; *(undefined2 *)(iVar1 + 0x20) = 0x200; // get instance from thread iVar3 = *(int *)(param_2 + 0x34); // copy position and rotation from one instance to another uVar4 = *(undefined4 *)(iVar3 + 0x34); uVar5 = *(undefined4 *)(iVar3 + 0x38); uVar6 = *(undefined4 *)(iVar3 + 0x3c); *(undefined4 *)(iVar1 + 0x30) = *(undefined4 *)(iVar3 + 0x30); *(undefined4 *)(iVar1 + 0x34) = uVar4; *(undefined4 *)(iVar1 + 0x38) = uVar5; *(undefined4 *)(iVar1 + 0x3c) = uVar6; uVar4 = *(undefined4 *)(iVar3 + 0x44); uVar5 = *(undefined4 *)(iVar3 + 0x48); uVar6 = *(undefined4 *)(iVar3 + 0x4c); *(undefined4 *)(iVar1 + 0x40) = *(undefined4 *)(iVar3 + 0x40); *(undefined4 *)(iVar1 + 0x44) = uVar4; *(undefined4 *)(iVar1 + 0x48) = uVar5; *(undefined4 *)(iVar1 + 0x4c) = uVar6; // Get the thread iVar1 = *(int *)(iVar1 + 0x6c); // set funcThDestroy to remove instance from instance pool *(undefined4 *)(iVar1 + 0x24) = 0x80041dfc; // get the object attached to the thread puVar2 = *(undefined4 **)(iVar1 + 0x30); // thread lasts 7 frames *puVar2 = 7; // driver puVar2[1] = param_1; // thread puVar2[2] = param_2; // thread -> timesDestroyed (it's used???) puVar2[3] = *(undefined4 *)(param_2 + 0x20); // save position of driver *(undefined2 *)((int)puVar2 + 0x10) = *(undefined2 *)(iVar3 + 0x44); *(undefined2 *)((int)puVar2 + 0x12) = *(undefined2 *)(iVar3 + 0x48); *(undefined2 *)((int)puVar2 + 0x14) = *(undefined2 *)(iVar3 + 0x4c); } } return; } // RB_Fruit_ThTick // This is useless, both thread death and pointer erasing // happen inside RB_Fruit_ThCollide anyway void FUN_800b706c(int param_1) { int iVar1; // thread -> instance iVar1 = *(int *)(param_1 + 0x34); // erase (instance -> thread) *(undefined4 *)(iVar1 + 0x6c) = 0; do { // This thread is now dead *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; // this skips $RA backup/restore, faster than JR $RA FUN_80071694(param_1); // erase (instance -> thread) *(undefined4 *)(iVar1 + 0x6c) = 0; } while( true ); } // RB_Fruit_ThCollide void FUN_800b70a8(int param_1,int param_2,undefined4 param_3,int param_4) { short sVar1; short sVar2; undefined4 uVar3; MATRIX *r0; int iVar5; long *r0_00; int iVar6; int iVar7; int *piVar8; undefined *puVar9; undefined auStack40 [16]; undefined2 uStack24; undefined2 uStack22; undefined2 uStack20; puVar9 = auStack40; piVar8 = *(int **)(param_1 + 0x30); sVar1 = *(short *)(param_4 + 0xc); iVar7 = *(int *)(param_1 + 0x34); if ((sVar1 == 0x18) || (uVar3 = 0, sVar1 == 0x3f)) { iVar6 = *(int *)(param_2 + 0x30); if (sVar1 == 0x18) { // position 3D uStack24 = *(undefined2 *)(iVar7 + 0x44); uStack22 = *(undefined2 *)(iVar7 + 0x48); uStack20 = *(undefined2 *)(iVar7 + 0x4c); // tileView -> 0x28 (matrix) r0 = (MATRIX *)(PTR_DAT_8008d2ac + (uint)*(byte *)(iVar6 + 0x4a) * 0x110 + 400); gte_SetRotMatrix(r0); gte_SetTransMatrix(r0); // position 3D gte_ldv0(&uStack24); gte_rtps(); // screen 2D result gte_stsxy(r0_00); // gGT iVar5 = PTR_DAT_8008d2ac; // screenX *(short *)(iVar6 + 0x4bc) = *(short *)(puVar9 + 0x18) + *(short *)(iVar5 + (uint)*(byte *)(iVar6 + 0x4a) * 0x110 + 0x184); // screenY sVar1 = *(short *)((int)r0_00 + 2); sVar2 = *(short *)(iVar5 + (uint)*(byte *)(iVar6 + 0x4a) * 0x110 + 0x186); // frames *(undefined4 *)(iVar6 + 0x4b8) = 5; // remaining HUD elements *(int *)(iVar6 + 0x4c0) = *(int *)(iVar6 + 0x4c0) + 1; // screenY *(short *)(iVar6 + 0x4be) = sVar1 + sVar2 + -0x14; } *piVar8 = iVar6; // set scale to 0,0,0 *(undefined2 *)(iVar7 + 0x1c) = 0; *(undefined2 *)(iVar7 + 0x1e) = 0; *(undefined2 *)(iVar7 + 0x20) = 0; // erase instance->thread *(undefined4 *)(iVar7 + 0x6c) = 0; // play sound FUN_8002f0dc(0x43,iVar7); // return 1 uVar3 = 1; // kill thread *(uint *)(param_1 + 0x1c) = *(uint *)(param_1 + 0x1c) | 0x800; } return uVar3; } // RB_Fruit_LInB void FUN_800b722c(int param_1) { // RB_Default_LInB FUN_800b4fe4(param_1); *(undefined *)(param_1 + 0x52) = 0; *(uint *)(param_1 + 0x28) = *(uint *)(param_1 + 0x28) | 0x10; return; } // RB_Fruit_LInC // spawns for one frame then destroys undefined4 FUN_800b7260(int param_1,undefined4 param_2,undefined4 param_3) { undefined4 uVar1; code *pcVar2; int iVar3; // Get thread for this instance iVar3 = *(int *)(param_1 + 0x6c); // if there is no thread if (iVar3 == 0) { // THREAD_BirthWithObject // 0x4 = size // 0 = no relation to param4 // 0x300 = SmallStackPool // 0x3 = "static" thread bucket iVar3 = FUN_8004205c(0x40303,&FUN_800b706c,s_fruit_800b7064,0); // give thread to instance *(int *)(param_1 + 0x6c) = iVar3; // if thread failed if (iVar3 == 0) { // quit return 0; } // give instance to thread *(int *)(iVar3 + 0x34) = param_1; // set funcThCollide *(undefined4 *)(iVar3 + 0x28) = 0x800b70a8; // set back to thread iVar3 = *(int *)(param_1 + 0x6c); } uVar1 = 0; if ( // if thread is valid (iVar3 != 0) && ( // get funcThCollide pcVar2 = *(code **)(iVar3 + 0x28), // if it is a function pcVar2 != (code *)0x0 ) ) { // if scale is zero, and object is not drawn if (*(short *)(param_1 + 0x1c) == 0) { // do nothing uVar1 = 0; } // if object is drawn else { // execute function pointer uVar1 = (*pcVar2)(iVar3,param_2,pcVar2,param_3); } } return uVar1; } // RB_Minecart_ThTick void FUN_800b7338(int param_1) { ushort uVar1; undefined *puVar2; short sVar3; int iVar4; int iVar5; undefined4 uVar6; short *psVar7; int iVar8; // thread -> instance iVar8 = *(int *)(param_1 + 0x34); // thread -> object psVar7 = *(short **)(param_1 + 0x30); // instance -> animFrame sVar3 = *(short *)(iVar8 + 0x54); // INSTANCE_GetNumAnimFrames iVar4 = FUN_80030f58(iVar8,0); // if animation is not over if ((int)sVar3 + 1 < iVar4) { // increment animation frame *(short *)(iVar8 + 0x54) = *(short *)(iVar8 + 0x54) + 1; } // if animation is over else { // restart animation *(undefined2 *)(iVar8 + 0x54) = 0; } puVar2 = PTR_DAT_8008d2ac; // LEV -> numSpawn2 if (*(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x138) != 0) { // if not reached next point if (psVar7[3] < psVar7[0xf]) { // increment interpolation to next point psVar7[3] = psVar7[3] + 1; } // if reached next point else { // reset interpolation between points psVar7[3] = 1; // position index < num positions (LEV -> ptrSpawn2) if ((int)psVar7[10] + 1 < **(int **)(*(int *)(puVar2 + 0x160) + 0x13c)) { // increment position index psVar7[10] = psVar7[10] + 1; // pos1 = pos2 *psVar7 = psVar7[4]; psVar7[1] = psVar7[5]; psVar7[2] = psVar7[6]; } else { // back to first position psVar7[10] = 1; // Get spawn posX in LEV sVar3 = **(short **)(*(int *)(*(int *)(puVar2 + 0x160) + 0x13c) + 4); // set posX in Object *psVar7 = sVar3; // set posX in Instance *(int *)(iVar8 + 0x44) = (int)sVar3; // Get spawn posY in LEV sVar3 = *(short *)(*(int *)(*(int *)(*(int *)(puVar2 + 0x160) + 0x13c) + 4) + 2); // set posY in Object psVar7[1] = sVar3; // set posZ in Instance *(int *)(iVar8 + 0x48) = (int)sVar3; // Get spawn posZ in LEV sVar3 = *(short *)(*(int *)(*(int *)(*(int *)(puVar2 + 0x160) + 0x13c) + 4) + 4); // set posZ in Object psVar7[2] = sVar3; // set posZ in Instance *(int *)(iVar8 + 0x4c) = (int)sVar3; } puVar2 = PTR_DAT_8008d2ac; // index iVar4 = (int)psVar7[10]; // position psVar7[4] = *(short *)(iVar4 * 6 + *(int *)(*(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x13c) + 4)); psVar7[5] = *(short *)(iVar4 * 6 + *(int *)(*(int *)(*(int *)(puVar2 + 0x160) + 0x13c) + 4) + 2); uVar1 = *(ushort *)(iVar4 * 6 + *(int *)(*(int *)(*(int *)(puVar2 + 0x160) + 0x13c) + 4) + 4); psVar7[7] = *psVar7 - psVar7[4]; psVar7[6] = uVar1; iVar5 = (uint)(ushort)psVar7[2] - (uint)uVar1; iVar4 = iVar5 * 0x10000 >> 0x10; psVar7[9] = (short)iVar5; psVar7[8] = psVar7[1] - psVar7[5]; uVar6 = FUN_8006c618((int)psVar7[7] * (int)psVar7[7] + iVar4 * iVar4); // rotation with rtan2 sVar3 = FUN_8007173c((int)psVar7[8],uVar6); psVar7[0x10] = sVar3; sVar3 = FUN_8007173c((int)psVar7[7],(int)psVar7[9]); psVar7[0x11] = sVar3 + -0x800; if ( (psVar7[10] == 1) && // if instance->model->modelID == DYNAMIC_MINE_CART (*(short *)(*(int *)(iVar8 + 0x18) + 0x10) == 0x21) ) { psVar7[0xc] = psVar7[0x10]; psVar7[0xd] = psVar7[0x11]; psVar7[0xe] = psVar7[0x12]; } } // from array *(undefined *)(iVar8 + 0x50) = (&DAT_800b7b20)[(int)psVar7[10] * 2]; *(undefined *)(iVar8 + 0x51) = (&DAT_800b7b20)[(int)psVar7[10] * 2]; // interpolate points iVar4 = (int)psVar7[0xf]; // safety check if (iVar4 == 0) trap(0x1c00); if ((iVar4 == -1) && ((int)psVar7[3] * (int)psVar7[7] == -0x80000000)) trap(0x1800); // posX *(int *)(iVar8 + 0x44) = (int)*psVar7 - ((int)psVar7[3] * (int)psVar7[7]) / iVar4; // interpolate points iVar4 = (int)psVar7[0xf]; // safety check if (iVar4 == 0) trap(0x1c00); if ((iVar4 == -1) && ((int)psVar7[3] * (int)psVar7[7] == -0x80000000)) trap(0x1800); // posY *(int *)(iVar8 + 0x48) = (int)psVar7[1] - ((int)psVar7[3] * (int)psVar7[8]) / iVar4; // interpolate points iVar4 = (int)psVar7[0xf]; // safety check if (iVar4 == 0) trap(0x1c00); if ((iVar4 == -1) && ((int)psVar7[3] * (int)psVar7[7] == -0x80000000)) trap(0x1800); // posZ *(int *)(iVar8 + 0x4c) = (int)psVar7[2] - ((int)psVar7[3] * (int)psVar7[9]) / iVar4; // RB_Hazard_InterpolateValue x2 // interpolate current rotation to desired rotation sVar3 = FUN_800ada90((int)psVar7[0xd],(int)psVar7[0x11],(int)psVar7[0x13]); psVar7[0xd] = sVar3; sVar3 = FUN_800ada90((int)psVar7[0xc],(int)psVar7[0x10],(int)psVar7[0x13]); psVar7[0xc] = sVar3; // make matrix FUN_8006c2a4(iVar8 + 0x30,psVar7 + 0xc); // PlaySound3D_Flags // play minecart railroad sound FUN_8002f31c(psVar7 + 0x14,0x72,iVar8); // check for collision with all Players iVar4 = FUN_800314e0(iVar8,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b2c),0x10000); // if there is collision if ((iVar4 != 0) || // check for collision with all robotcars (iVar4 = FUN_800314e0(iVar8,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b40),0x10000), // if there is collision iVar4 != 0)) { // squish uVar6 = 3; // instance -> model -> modelID == DYNAMIC_SKUNK if (*(short *)(*(int *)(iVar8 + 0x18) + 0x10) == 0x50) { // spin out uVar6 = 1; } // RB_Hazard_HurtDriver (squish, or spinout) FUN_800ac1b0(*(undefined4 *)(*(int *)(iVar4 + 0x6c) + 0x30),uVar6,0,0); } } return; } // RB_Minecart_LInB void FUN_800b7814(int param_1) { undefined *puVar1; undefined2 uVar2; short sVar3; int iVar4; undefined4 uVar5; short *psVar6; // if there is already a thread for this instance if (*(int *)(param_1 + 0x6c) != 0) { // quit return; } // THREAD_BirthWithObject // 0x2c = size // 0 = no relation to param4 // 0x300 = SmallStackPool // 0x3 = "static" thread bucket iVar4 = FUN_8004205c(0x2c0303,&FUN_800b7338,s_minecart_800b732c,0); // give thread to instance *(int *)(param_1 + 0x6c) = iVar4; // if thread failed if (iVar4 == 0) { // quit return; } // get object that thread created psVar6 = *(short **)(iVar4 + 0x30); // give instance to thread *(int *)(iVar4 + 0x34) = param_1; // clear memory in object memset(psVar6,0,0x2c); // minecartID iVar4 = strlen(param_1 + 8); // start at beginning of path sVar3 = 1; // not minecart[0] if (*(char *)(iVar4 + param_1 + 7) != '0') { iVar4 = strlen(param_1 + 8); // minecart[1] if (*(char *)(iVar4 + param_1 + 7) == '1') { iVar4 = **(int **)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x13c); } // minecart[2] else { iVar4 = **(int **)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x13c) << 1; } sVar3 = (short)(iVar4 / 3); } // position index psVar6[10] = sVar3; // set scale (x,y,z) of instance *(undefined2 *)(param_1 + 0x1c) = 0x1000; *(undefined2 *)(param_1 + 0x1e) = 0x1000; *(undefined2 *)(param_1 + 0x20) = 0x1000; // minecart speed (8 frames between points) psVar6[0xf] = 8; // rotation speed psVar6[0x13] = 0x20; // instance -> model -> modelID sVar3 = *(short *)(*(int *)(param_1 + 0x18) + 0x10); // if DYNAMIC_SKUNK if (sVar3 == 0x50) { uVar2 = 0x2000; } else { // if not DYNAMIC_VONLABASS if (sVar3 != 0x4f) goto LAB_800b7980; // if DYNAMIC_VONLABASS uVar2 = 0x800; } // set scale again (x,y,z) of instance *(undefined2 *)(param_1 + 0x1c) = uVar2; *(undefined2 *)(param_1 + 0x1e) = uVar2; *(undefined2 *)(param_1 + 0x20) = uVar2; // speed (4 frames between points) psVar6[0xf] = 4; // rotation speed psVar6[0x13] = 0x18; LAB_800b7980: puVar1 = PTR_DAT_8008d2ac; // desired position index iVar4 = (int)psVar6[10]; // betweenPoints currFrame psVar6[3] = 0; // pos1 = points[desired-1] *psVar6 = *(short *)(iVar4 * 6 + *(int *)(*(int *)(*(int *)(puVar1 + 0x160) + 0x13c) + 4) + -6); psVar6[1] = *(short *)(iVar4 * 6 + *(int *)(*(int *)(*(int *)(puVar1 + 0x160) + 0x13c) + 4) + -4); psVar6[2] = *(short *)(iVar4 * 6 + *(int *)(*(int *)(*(int *)(puVar1 + 0x160) + 0x13c) + 4) + -2); // pos2 = points[desired] psVar6[4] = *(short *)(iVar4 * 6 + *(int *)(*(int *)(*(int *)(puVar1 + 0x160) + 0x13c) + 4)); psVar6[5] = *(short *)(iVar4 * 6 + *(int *)(*(int *)(*(int *)(puVar1 + 0x160) + 0x13c) + 4) + 2); psVar6[6] = *(short *)(iVar4 * 6 + *(int *)(*(int *)(*(int *)(puVar1 + 0x160) + 0x13c) + 4) + 4); // dirX psVar6[7] = *psVar6 - psVar6[4]; // dirZ iVar4 = (int)(((uint)(ushort)psVar6[2] - (uint)(ushort)psVar6[6]) * 0x10000) >> 0x10; psVar6[9] = (short)((uint)(ushort)psVar6[2] - (uint)(ushort)psVar6[6]); // dirY psVar6[8] = psVar6[1] - psVar6[5]; uVar5 = SquareRoot0((int)psVar6[7] * (int)psVar6[7] + iVar4 * iVar4); // rotate X, Y, Z sVar3 = ratan2((int)psVar6[8],uVar5); psVar6[0x10] = sVar3; sVar3 = ratan2((int)psVar6[7],(int)psVar6[9]); psVar6[0x11] = sVar3 + -0x800; psVar6[0x12] = 0; // erase audio data *(undefined4 *)(psVar6 + 0x14) = 0; return; } // RB_Orca_ThTick void FUN_800b7b8c(int param_1) { ushort uVar1; uint uVar2; int iVar3; int iVar4; int iVar5; short *psVar6; int iVar7; int iVar8; // thread -> object psVar6 = *(short **)(param_1 + 0x30); // thread -> instance iVar7 = *(int *)(param_1 + 0x34); // if cooldown if ((int)psVar6[7] != 0) { // subtract one frame uVar2 = (int)psVar6[7] - 1; psVar6[7] = (short)uVar2; // quit if cooldown is not done if ((uVar2 & 0xffff) != 0) { return; } // make orca visible (remove invisible flag) *(uint *)(iVar7 + 0x28) = *(uint *)(iVar7 + 0x28) & 0xffffff7f; return; } // number of frames in animation iVar3 = (int)psVar6[0x13]; // animIndex iVar8 = (int)psVar6[0xb]; // if less than 20 frames remain if (iVar3 + -0x14 < (int)psVar6[0xb]) { // total frames, minus 20 iVar8 = iVar3 + -0x14; } // direction uVar1 = psVar6[0x17]; // total frames, minus 23 iVar5 = iVar3 + -0x17; if (uVar1 == 0) { // subtract 26 frames iVar3 = iVar3 + -0x1a; if ((short)iVar8 <= iVar3) goto LAB_800b7c40; } else { iVar3 = iVar8 + -3; } iVar8 = iVar3; LAB_800b7c40: iVar3 = iVar8 << 0x10; if (iVar8 << 0x10 < 0) { iVar3 = 0; } iVar3 = iVar3 >> 0x10; if (iVar5 == 0) { trap(0x1c00); } if ((iVar5 == -1) && (iVar3 * psVar6[0x14] == -0x80000000)) { trap(0x1800); } *(int *)(iVar7 + 0x44) = (int)*psVar6 - (iVar3 * psVar6[0x14]) / iVar5; if (iVar5 == 0) { trap(0x1c00); } if ((iVar5 == -1) && (iVar3 * psVar6[0x15] == -0x80000000)) { trap(0x1800); } *(int *)(iVar7 + 0x48) = (int)psVar6[1] - (iVar3 * psVar6[0x15]) / iVar5; if (iVar5 == 0) { trap(0x1c00); } if ((iVar5 == -1) && (iVar3 * psVar6[0x16] == -0x80000000)) { trap(0x1800); } *(int *)(iVar7 + 0x4c) = (int)psVar6[2] - (iVar3 * psVar6[0x16]) / iVar5; // increment frame iVar8 = (int)*(short *)(iVar7 + 0x54) + 1; // if frame is less than number of frames in animation if (iVar8 < psVar6[0x13]) { if ( // if less than 2 players (1P only) ((byte)PTR_DAT_8008d2ac[0x1ca8] < 2) && // create splashes on specific frames ( ( // 45 frames between entry and exit, // 1.5 seconds // frame 5, coming out of the water iVar8 == 5 || // frame 49, back in water (iVar8 == 0x31) ) ) ) { // amount of particles to spawn iVar3 = 0xf; // splash effect in water do { // Create instance in particle pool iVar5 = FUN_80040308(0,*(undefined4 *)(PTR_DAT_8008d2ac + 0x2118),&DAT_800b80e4); if (iVar5 != 0) { *(int *)(iVar5 + 0x24) = *(int *)(iVar5 + 0x24) + *(int *)(iVar7 + 0x44) * 0x100 + (int)*(short *)(iVar5 + 0x28) * 0x10; *(int *)(iVar5 + 0x2c) = *(int *)(iVar5 + 0x2c) + *(int *)(iVar7 + 0x48) * 0x100 + (int)*(short *)(iVar5 + 0x30) * 2; iVar4 = *(int *)(iVar7 + 0x4c); *(undefined2 *)(iVar5 + 0x1a) = 0x1000; *(int *)(iVar5 + 0x34) = *(int *)(iVar5 + 0x34) + iVar4 * 0x100 + (int)*(short *)(iVar5 + 0x38) * 0x10; } iVar3 = iVar3 + -1; } while (iVar3 != 0); } // increment frame *(undefined2 *)(iVar7 + 0x54) = (short)iVar8; // direction if (uVar1 == 0) { // return to spawn psVar6[0xb] = psVar6[0xb] + -1; } // direction else { // move away from spawn psVar6[0xb] = psVar6[0xb] + 1; } } // if animation is done else { // make orca invisible *(uint *)(iVar7 + 0x28) = *(uint *)(iVar7 + 0x28) | 0x80; // 90-frame cooldown before // jumping out of water psVar6[7] = 0x5a; // reset animation *(undefined2 *)(iVar7 + 0x54) = 0; // reverse the direction psVar6[0x17] = uVar1 ^ 1; // alter rotation 180 degrees psVar6[9] = psVar6[9] + 0x800; // turn rotation into matrix FUN_8006c2a4(iVar7 + 0x30,psVar6 + 8); } return; } // RB_Orca_ThCollide void FUN_800b7eb8(int param1, int param_2, int param_3, int param_4) { // check if modelID is player // modelID is 0xc of BSP meta return (uint)(*(short *)(param_4 + 0xc) == 0x18); } // RB_Orca_LInB // This was the beta Whale on Polar Pass void FUN_800b7ecc(int param_1) { undefined *puVar1; undefined *puVar2; short sVar3; int iVar4; undefined4 *puVar5; undefined4 *puVar6; // orca would be out of water for 45 frames, // which is 1.5 seconds, and then a 3-second cooldown // If there is no thread for this instance if (*(int *)(param_1 + 0x6c) == 0) { // b7b84 // "orca" // THREAD_BirthWithObject // 0x30 = size // 0 = no relation to param4 // 0x300 = SmallStackPool // 0x3 = "static" thread bucket iVar4 = FUN_8004205c(0x300303,&FUN_800b7b8c,&DAT_800b7b84,0); // give thread to instance *(int *)(param_1 + 0x6c) = iVar4; // If the thread built properly if (iVar4 != 0) { // get object created with thread puVar6 = *(undefined4 **)(iVar4 + 0x30); // set funcThCollide, RB_Orca_ThCollide *(undefined4 *)(iVar4 + 0x28) = 0x800b7eb8; // give instance to thread *(int *)(iVar4 + 0x34) = param_1; // set scale (x, y, z) *(undefined2 *)(param_1 + 0x1c) = 0xc00; *(undefined2 *)(param_1 + 0x1e) = 0xc00; *(undefined2 *)(param_1 + 0x20) = 0xc00; // draw huge *(uint *)(param_1 + 0x28) = *(uint *)(param_1 + 0x28) | 0x8000000; // animFrame (negative?) *(short *)((int)puVar6 + 0x16) = -10; // direction, move away from spawn *(short *)((int)puVar6 + 0x2e) = 1; // instance->instDef->rot[3] *(short *)(puVar6 + 4) = *(short *)(*(int *)(param_1 + 0x2c) + 0x36); *(short *)((int)puVar6 + 0x12) = *(short *)(*(int *)(param_1 + 0x2c) + 0x38); *(short *)(puVar6 + 5) = *(short *)(*(int *)(param_1 + 0x2c) + 0x3a); // orcaID iVar4 = strlen(param_1 + 8); puVar1 = PTR_DAT_8008d2ac; iVar4 = (uint)*(byte *)(iVar4 + param_1 + 7) - 0x30; *(short *)((int)puVar6 + 6) = (short)iVar4; puVar2 = PTR_DAT_8008d2ac; // LEV -> numSpawn2 if (*(int *)(*(int *)(puVar1 + 0x160) + 0x138) != 0) { // start position puVar5 = *(undefined4 **)(iVar4 * 8 + *(int *)(*(int *)(puVar1 + 0x160) + 0x13c) + 0x24); sVar3 = *(short *)(puVar5 + 1); *puVar6 = *puVar5; *(short *)(puVar6 + 1) = sVar3; // end position iVar4 = *(int *)((int)*(short *)((int)puVar6 + 6) * 8 + *(int *)(*(int *)(puVar2 + 0x160) + 0x13c) + 0x24); sVar3 = *(short *)(iVar4 + 10); puVar6[2] = *(undefined4 *)(iVar4 + 6); *(short *)(puVar6 + 3) = sVar3; } // midpoint? *(short *)(puVar6 + 0xa) = *(short *)puVar6 - *(short *)(puVar6 + 2); *(short *)((int)puVar6 + 0x2a) = *(short *)((int)puVar6 + 2) - *(short *)((int)puVar6 + 10); *(short *)(puVar6 + 0xb) = *(short *)(puVar6 + 1) - *(short *)(puVar6 + 3); // INSTANCE_GetNumAnimFrames sVar3 = FUN_80030f58(param_1,0); puVar1 = PTR_DAT_8008d2ac; // set number of frames in animation *(short *)((int)puVar6 + 0x26) = sVar3; if ( // LEV -> trial_data -> numPointers (0 < **(int **)(*(int *)(puVar1 + 0x160) + 0x134)) && // get data depending on orcaID (sVar3 = *(short *)((*(int **)(*(int *)(puVar1 + 0x160) + 0x134))[2] + (int)*(short *)((int)puVar6 + 6) * 2), // if value is not zero, make invisible *(short *)((int)puVar6 + 0xe) = sVar3, sVar3 != 0) ) { // make invisible *(uint *)(param_1 + 0x28) = *(uint *)(param_1 + 0x28) | 0x80; } } } return; } // RB_Plant_ThTick_Eat void FUN_800b81e8(int param_1) { char cVar1; short sVar2; int iVar3; int iVar4; int iVar5; int iVar6; short *psVar7; // get object from thread psVar7 = *(short **)(param_1 + 0x30); // get instance from thread iVar6 = *(int *)(param_1 + 0x34); do { // get animation cVar1 = *(char *)(iVar6 + 0x52); // if animation is 5 if (cVar1 == '\x05') { // get animation frame sVar2 = *(short *)(iVar6 + 0x54); // INSTANCE_GetNumAnimFrames iVar3 = FUN_80030f58(iVar6,5); // if animation is not finished if ((int)sVar2 + 1 < iVar3) { // increment animation frame *(short *)(iVar6 + 0x54) = *(short *)(iVar6 + 0x54) + 1; } // if animation is finished else { // reset frame *(undefined2 *)(iVar6 + 0x54) = 0; // change animation to 6 *(undefined *)(iVar6 + 0x52) = 6; DAT_800b82bc: if (psVar7[3] != 0) { // Play PlantChew sound FUN_80028468(0x6e,0); } } } // if animation is not 5 else { if (cVar1 == '\x06') { // get animation frame sVar2 = *(short *)(iVar6 + 0x54); // INSTANCE_GetNumAnimFrames iVar3 = FUN_80030f58(iVar6,6); // if animation is not done if ((int)sVar2 + 1 < iVar3) { // advance animation by one frame sVar2 = *(short *)(iVar6 + 0x54) + 1; *(short *)(iVar6 + 0x54) = sVar2; // on a particular frame, play sound??? if (sVar2 == 0xf) goto DAT_800b82bc; } // if animation is done else { // reset animation frame *(undefined2 *)(iVar6 + 0x54) = 0; // increment number of times animation finished sVar2 = *psVar7; *psVar7 = sVar2 + 1; // if animation finished once if ((short)(sVar2 + 1) == 1) { // reset counter *psVar7 = 0; // reset animation *(undefined2 *)(iVar6 + 0x54) = 0; // change animation to 7 *(undefined *)(iVar6 + 0x52) = 7; } } } // if anim is not 6 else { // if animation is 7, spitting if (cVar1 == '\a') { // get animation frame sVar2 = *(short *)(iVar6 + 0x54); // INSTANCE_GetNumAnimFrames iVar3 = FUN_80030f58(iVar6,7); // if animation is not finished if ((int)sVar2 + 1 < iVar3) { // increase animation frame sVar2 = *(short *)(iVar6 + 0x54) + 1; *(short *)(iVar6 + 0x54) = sVar2; // on particular animation frame, // make the plant spit if (sVar2 == 0x19) { if (psVar7[3] != 0) { // Play PlantSpit sound FUN_80028468(0x6f,0); } // loop counter iVar3 = 0; // Spawn 4 tires being spat out // for iVar3 = 0; iVar3 < 4; iVar3++ do { // 2114 is group of textures for tireAnim iVar4 = FUN_80040308(0,*(undefined4 *)(PTR_DAT_8008d2ac + 0x2114), &DAT_800b8acc); if (iVar4 != 0) { *(int *)(iVar4 + 0x24) = *(int *)(iVar4 + 0x24) + (*(int *)(iVar6 + 0x44) + ((int)*(short *)(iVar6 + 0x34) * 9 >> 7)) * 0x100; *(int *)(iVar4 + 0x2c) = *(int *)(iVar4 + 0x2c) + (*(int *)(iVar6 + 0x48) + 0x20) * 0x100; *(int *)(iVar4 + 0x34) = *(int *)(iVar4 + 0x34) + (*(int *)(iVar6 + 0x4c) + ((int)*(short *)(iVar6 + 0x40) * 9 >> 7)) * 0x100; iVar5 = FUN_8003ea28(); *(short *)(iVar4 + 0x28) = *(short *)(iVar4 + 0x28) + (short)((iVar5 % 10 + 0x10) * (int)*(short *)(iVar6 + 0x34) >> 0xc) * 0x100; iVar5 = FUN_8003ea28(); sVar2 = *(short *)(iVar6 + 0x40); // Particle_FuncPtr_SpitTire *(undefined4 *)(iVar4 + 0x1c) = 0x8003ec18; *(int *)(iVar4 + 0x20) = iVar6; *(short *)(iVar4 + 0x38) = *(short *)(iVar4 + 0x38) + (short)((iVar5 % 10 + 0x10) * (int)sVar2 >> 0xc) * 0x100; } // next tire iVar3 = iVar3 + 1; } while (iVar3 < 4); } } // if spitting animation is done else { // Change animatino to rest, and reset animation *(undefined2 *)(iVar6 + 0x54) = 0; *(undefined *)(iVar6 + 0x52) = 0; // not eating anymore psVar7[3] = 0; // Change state to // RB_Plant_ThTick_Rest FUN_800716ec(param_1,&FUN_800b88a8); } } } } // this skips $RA backup/restore, faster than JR $RA FUN_80071694(param_1); } while( true ); } // RB_Plant_ThTick_Grab void FUN_800b84f0(int param_1) { short sVar1; int iVar2; undefined *puVar3; int iVar4; int iStack56; int iStack52; undefined4 uStack48; undefined4 uStack44; undefined4 uStack40; undefined4 uStack36; undefined4 uStack32; int iStack28; undefined4 uStack24; undefined4 uStack20; // thread -> instance iVar4 = *(int *)(param_1 + 0x34); uStack44 = DAT_800b8bec; uStack40 = DAT_800b8bf0; uStack36 = DAT_800b8bf4; uStack20 = 0; // instance iStack56 = iVar4; // thread iStack52 = param_1; iStack28 = param_1; do { // if grabbing driver if (*(char *)(iVar4 + 0x52) == '\x03') { // instance -> animFrame sVar1 = *(short *)(iVar4 + 0x54); // INSTANCE_GetNumAnimFrames iVar2 = FUN_80030f58(iVar4,3); puVar3 = PTR_DAT_8008d2ac; if ((int)sVar1 + 1 < iVar2) { *(short *)(iVar4 + 0x54) = *(short *)(iVar4 + 0x54) + 1; // mine thread bucket uStack48 = *(undefined4 *)(puVar3 + 0x1b7c); // get collision with thread bucket iVar2 = FUN_800315ac(&iStack56); // if collision if (iVar2 != 0) { // instance->thread uStack32 = *(undefined4 *)(iVar2 + 0x6c); // instance->thread->funcThCollide uStack24 = *(undefined4 *)(*(int *)(iVar2 + 0x6c) + 0x28); // RB_Hazard_ThCollide_Generic_Alt FUN_800ac3f8(&uStack32); } } else { // RB_Plant_ThTick_Eat puVar3 = &DAT_800b81e8; *(undefined2 *)(iVar4 + 0x54) = 0; *(undefined *)(iVar4 + 0x52) = 5; DAT_800b8638: FUN_800716ec(param_1,puVar3); } } // if grabbing mine (unused) else { if (*(char *)(iVar4 + 0x52) == '\x04') { // instance -> animFrame sVar1 = *(short *)(iVar4 + 0x54); // INSTANCE_GetNumAnimFrames iVar2 = FUN_80030f58(iVar4,4); if (iVar2 <= (int)sVar1 + 1) { // Change state to // RB_Plant_ThTick_Rest puVar3 = &FUN_800b88a8; // Change animation to Rest, restart animation *(undefined2 *)(iVar4 + 0x54) = 0; // Set animation to rest *(undefined *)(iVar4 + 0x52) = 0; goto DAT_800b8638; } *(short *)(iVar4 + 0x54) = *(short *)(iVar4 + 0x54) + 1; } } // this skips $RA backup/restore, faster than JR $RA FUN_80071694(param_1); } while( true ); } // RB_Plant_ThTick_Transition_HungryToRest void FUN_800b8650(int param_1) { int iVar1; // get instance from thread iVar1 = *(int *)(param_1 + 0x34); do { // If animation finished rewinding if ((int)*(short *)(iVar1 + 0x54) + -1 < 1) { // Reset animation *(undefined2 *)(iVar1 + 0x54) = 0; // Set animation to rest *(undefined *)(iVar1 + 0x52) = 0; // Change state to // RB_Plant_ThTick_Rest FUN_800716ec(param_1,&FUN_800b88a8); } // if animation is not done else { // play backwards *(short *)(iVar1 + 0x54) = *(short *)(iVar1 + 0x54) + -1; } // this skips $RA backup/restore, faster than JR $RA FUN_80071694(param_1); } while( true ); } // RB_Plant_ThTick_Hungry // Mouth near ground, ready to eat void FUN_800b86b4(int param_1) { short sVar1; undefined2 uVar2; int iVar3; int iVar4; int iVar5; short *psVar6; int iStack48; int iStack44; undefined4 uStack40; undefined4 uStack36; undefined4 uStack32; undefined4 uStack28; psVar6 = *(short **)(param_1 + 0x30); iVar5 = *(int *)(param_1 + 0x34); uStack36 = DAT_800b8bec; uStack32 = DAT_800b8bf0; uStack28 = DAT_800b8bf4; iStack48 = iVar5; iStack44 = param_1; do { if (*(char *)(iVar5 + 0x52) == '\x02') { // get animation frame sVar1 = *(short *)(iVar5 + 0x54); // INSTANCE_GetNumAnimFrames iVar3 = FUN_80030f58(iVar5,2); // if animation is not done if ((int)sVar1 + 1 < iVar3) { // advance animation by one frame *(short *)(iVar5 + 0x54) = *(short *)(iVar5 + 0x54) + 1; } // if animation is done else { // reset animation *(undefined2 *)(iVar5 + 0x54) = 0; // get number of times animation finished sVar1 = *psVar6; // increment counter by one *psVar6 = sVar1 + 1; // if animation finished 4 times if ((short)(sVar1 + 1) == 4) { // INSTANCE_GetNumAnimFrames uVar2 = FUN_80030f58(iVar5,1); // set animation to the last frame, // the animation will play backwards *(undefined2 *)(iVar5 + 0x54) = uVar2; // change animation to TransitionRestToHungry, // which will play backwards *(undefined *)(iVar5 + 0x52) = 1; // reset cycle counter *psVar6 = 0; // Change state to // RB_Plant_ThTick_Transition_HungryToRest FUN_800716ec(param_1,&FUN_800b8650); } } // Check for collision with human players uStack40 = *(undefined4 *)(PTR_DAT_8008d2ac + 0x1b2c); iVar3 = FUN_800315ac(&iStack48); // if no collision is found if (iVar3 == 0) { // If this is not Boss mode (papu is immune) if (-1 < *(int *)PTR_DAT_8008d2ac) { // Check for collision with robot cars uStack40 = *(undefined4 *)(PTR_DAT_8008d2ac + 0x1b40); iVar3 = FUN_800315ac(&iStack48,5); // if there is a collision if (iVar3 != 0) { // RB_Hazard_HurtDriver (mask grab) FUN_800ac1b0(*(undefined4 *)(*(int *)(iVar3 + 0x6c) + 0x30),5,0,0); // driver->plantEatingMe = "this" *(int *)(*(int *)(*(int *)(iVar3 + 0x6c) + 0x30) + 0x4a8) = param_1; // Reset animation *(undefined2 *)(iVar5 + 0x54) = 0; // Change animation to GrabDriver *(undefined *)(iVar5 + 0x52) = 3; *psVar6 = 0; // Change plant state to EndHunger (grab) goto DAT_800b8890; } } } // if player collides with plant else { // get pointer to Driver object iVar4 = *(int *)(*(int *)(iVar3 + 0x6c) + 0x30); // RB_Hazard_HurtDriver (mask grab) iVar3 = FUN_800ac1b0(iVar4,5,0,0); if (iVar3 != 0) { // Play PlantGrab sound FUN_80028468(0x6d,0); *(int *)(iVar4 + 0x4a8) = param_1; // Change animation to GrabDriver *(undefined *)(iVar5 + 0x52) = 3; // Reset animation *(undefined2 *)(iVar5 + 0x54) = 0; *psVar6 = 0; // plant is now eating psVar6[3] = 1; DAT_800b8890: // Change plant state to // RB_Plant_ThTick_Grab (grab or rest) FUN_800716ec(param_1,&FUN_800b84f0); } } } // this skips $RA backup/restore, faster than JR $RA FUN_80071694(param_1); } while( true ); } // RB_Plant_ThTick_Rest // Standing tall, not trying to eat void FUN_800b88a8(int param_1) { short sVar1; int iVar2; int iVar3; short *psVar4; // get plant object from thread psVar4 = *(short **)(param_1 + 0x30); // get instance from thread iVar3 = *(int *)(param_1 + 0x34); do { // cooldown if (psVar4[1] == 0) { // Set animation to rest if (*(char *)(iVar3 + 0x52) == '\0') { // Get animation frame sVar1 = *(short *)(iVar3 + 0x54); // INSTANCE_GetNumAnimFrames iVar2 = FUN_80030f58(iVar3,0); // if animation is not finished if ((int)sVar1 + 1 < iVar2) { DAT_800b8968: // Advance animation by one frame *(short *)(iVar3 + 0x54) = *(short *)(iVar3 + 0x54) + 1; } // if animation is done else { // reset animation *(undefined2 *)(iVar3 + 0x54) = 0; // get number of times this animation finished sVar1 = *psVar4; // increment number of times animation finished *psVar4 = sVar1 + 1; // if animation finished 3 times if ((short)(sVar1 + 1) == 3) { // change animation to TransitionRestToHungry *(undefined *)(iVar3 + 0x52) = 1; // reset animation counter *psVar4 = 0; } } } else { // If animation is TransitionRestToHungry if (*(char *)(iVar3 + 0x52) == '\x01') { // get animation frame sVar1 = *(short *)(iVar3 + 0x54); // INSTANCE_GetNumAnimFrames iVar2 = FUN_80030f58(iVar3,1); // if animation is not done, advance frame if ((int)sVar1 + 1 < iVar2) goto DAT_800b8968; // When transition is over, make the plant hungry // Set animation frame to zero *(undefined2 *)(iVar3 + 0x54) = 0; // Set animation to Hungry *(undefined *)(iVar3 + 0x52) = 2; // Change state to // RB_Plant_ThTick_Hungry FUN_800716ec(param_1,&FUN_800b86b4); } } } // cooldown else { psVar4[1] = psVar4[1] + -1; } // this skips $RA backup/restore, faster than JR $RA FUN_80071694(param_1); } while( true ); } // RB_Plant_LInB void FUN_800b89a4(int param_1) { int iVar1; undefined2 *puVar2; undefined2 *puVar3; // if instance has no thread if (*(int *)(param_1 + 0x6c) == 0) { // THREAD_BirthWithObject // 0x8 = size // 0 = no relation to param4 // 0x300 = SmallStackPool // 0x3 = "static" thread bucket iVar1 = FUN_8004205c(0x80303,FUN_800b88a8,s_plant_800b81e0,0); // give thread to instance *(int *)(param_1 + 0x6c) = iVar1; // if thread is valid if (iVar1 != 0) { // get object attached to thread puVar3 = *(undefined2 **)(iVar1 + 0x30); // give instance to thread *(int *)(iVar1 + 0x34) = param_1; // set scale (x, y, z) *(undefined2 *)(param_1 + 0x1c) = 0x2800; *(undefined2 *)(param_1 + 0x1e) = 0x2800; *(undefined2 *)(param_1 + 0x20) = 0x2800; // initialize plant data // frame timer *puVar3 = 0; // not eating puVar3[3] = 0; // initialize animation to frame zero of anim zero *(undefined2 *)(param_1 + 0x54) = 0; *(undefined *)(param_1 + 0x52) = 0; DAT_800b8bf0._2_2_ = 0x40; DAT_800b8bec._0_2_ = 0xffc0; DAT_800b8bec._2_2_ = 0xffc0; DAT_800b8bf4._0_2_ = 0x80; DAT_800b8bf4._2_2_ = 0x1e0; DAT_800b8bf0._0_2_ = 0; // LEV -> trial_data -> numPointers if (0 < **(int **)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x134)) { // strlen iVar1 = FUN_80077cc8(param_1 + 8); puVar2 = (undefined2 *) (*(int *)(*(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x134) + 8) + // plantID from string ((uint)*(byte *)(iVar1 + param_1 + 7) - 0x30) * 4); // position X and Y puVar3[1] = *puVar2; puVar3[2] = puVar2[1]; } } } return; } // RB_Seal_ThTick_TurnAround void FUN_800b8c00(int param_1) { char cVar1; short sVar2; undefined2 uVar3; int iVar4; code *pcVar5; int iVar6; int iVar7; // thread -> instance iVar7 = *(int *)(param_1 + 0x34); // thread -> object iVar6 = *(int *)(param_1 + 0x30); // instance -> animFrame sVar2 = *(short *)(iVar7 + 0x54); // INSTANCE_GetNumAnimFrames iVar4 = FUN_80030f58(iVar7,0); // if animation is not done if ((int)sVar2 + 2 < iVar4) { // increment animation *(short *)(iVar7 + 0x54) = *(short *)(iVar7 + 0x54) + 2; } // if animation is over else { // restart animation *(undefined2 *)(iVar7 + 0x54) = 0; // play sound of seal bark FUN_8002f0dc(0x77,iVar7); } // if current rotation is desired rotation if ((int)*(short *)(iVar6 + 0x12) == (int)*(short *)(iVar6 + 0x22)) { // reset numFramesSpinning *(undefined2 *)(iVar6 + 0x26) = 0; // set spawn rotation to desired rotation (why?) *(undefined2 *)(iVar6 + 0x18) = *(undefined2 *)(iVar6 + 0x10); *(undefined2 *)(iVar6 + 0x1a) = *(undefined2 *)(iVar6 + 0x12); *(undefined2 *)(iVar6 + 0x1c) = *(undefined2 *)(iVar6 + 0x14); // make a matrix FUN_8006c2a4(iVar7 + 0x30,iVar6 + 0x10); // ThTick_SetAndExec RB_Seal_ThTick_Move FUN_800716ec(param_1,FUN_800b8e1c); } // if desired rotation is not met yet else { // RB_Hazard_InterpolateValue x3 // rotCurrY to rotDesiredY uVar3 = FUN_800ada90((int)*(short *)(iVar6 + 0x12),(int)*(short *)(iVar6 + 0x22),0x80); *(undefined2 *)(iVar6 + 0x12) = uVar3; // rotCurrX to rotDesiredAltX uVar3 = FUN_800ada90((int)*(short *)(iVar6 + 0x10),(int)-*(short *)(iVar6 + 0x18),0x14); *(undefined2 *)(iVar6 + 0x10) = uVar3; // rotCurrZ to rotDesiredAltZ uVar3 = FUN_800ada90((int)*(short *)(iVar6 + 0x14),(int)-*(short *)(iVar6 + 0x1c),0x14); *(undefined2 *)(iVar6 + 0x14) = uVar3; // increase numFramesSpinning *(short *)(iVar6 + 0x26) = *(short *)(iVar6 + 0x26) + 1; // make a matrix FUN_8006c2a4(iVar7 + 0x30,iVar6 + 0x10); } // check for collision with all players iVar4 = FUN_800314e0(iVar7,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b2c),0x4000); // if no collision if (iVar4 == 0) { // check for collision with all robotcars iVar4 = FUN_800314e0(iVar7,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b40),0x4000); // if no collision if (iVar4 == 0) { // check for collision with all mines (tnts, beakers, etc) iVar4 = FUN_800314e0(iVar7,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b7c),0x4000); // if there is a collision if (iVar4 != 0) { // instance -> thread -> funcThCollide pcVar5 = *(code **)(*(int *)(iVar4 + 0x6c) + 0x28); // execute funcThCollide (*pcVar5)(*(int *)(iVar4 + 0x6c)); } } // if there is a collision with robotcar else { // RB_Hazard_HurtDriver (spin out) FUN_800ac1b0(*(undefined4 *)(*(int *)(iVar4 + 0x6c) + 0x30),1,0,0); } } // if there is a collision with player else { iVar6 = *(int *)(*(int *)(iVar4 + 0x6c) + 0x30); cVar1 = *(char *)(iVar6 + 0x376); // RB_Hazard_HurtDriver (spin out) iVar4 = FUN_800ac1b0(iVar6,1,0,0); // if change state worked, and if kart was not // already spinning out before this if ((iVar4 != 0) && (cVar1 != '\x03')) { // play sound FUN_80028494(0x78,1,(uint)*(ushort *)(iVar6 + 0x2ca) & 1); } } return; } // RB_Seal_ThTick_Move void FUN_800b8e1c(int param_1) { char cVar1; short sVar2; int iVar3; code *pcVar4; int iVar5; short *psVar6; int iVar7; // get instance from thread iVar7 = *(int *)(param_1 + 0x34); // get object from thread psVar6 = *(short **)(param_1 + 0x30); // instance -> animationFrame sVar2 = *(short *)(iVar7 + 0x54); // INSTANCE_GetNumAnimFrames iVar3 = FUN_80030f58(iVar7,0); // if animation is not done if ((int)sVar2 + 2 < iVar3) { // increase animation frame *(short *)(iVar7 + 0x54) = *(short *)(iVar7 + 0x54) + 2; } // if animation is done else { // restart animation *(undefined2 *)(iVar7 + 0x54) = 0; } // Position = // SpawnPosition - (Distance*Velocity) >> 5 // >> 5 is the same as / 0x2d *(int *)(iVar7 + 0x44) = (int)*psVar6 - ((int)psVar6[7] * (int)psVar6[0x14]) / 0x2d; *(int *)(iVar7 + 0x48) = (int)psVar6[1] - ((int)psVar6[7] * (int)psVar6[0x15]) / 0x2d; *(int *)(iVar7 + 0x4c) = (int)psVar6[2] - ((int)psVar6[7] * (int)psVar6[0x16]) / 0x2d; // If direction is zero if (psVar6[0xf] == 0) { // if you have not returned to spawn if (0 < psVar6[7]) { // reduce frame counter psVar6[7] = psVar6[7] + -1; // dont turn around goto LAB_800b8fdc; } // if you have not returned to spawn, dont turn around if (psVar6[7] != 0) goto LAB_800b8fdc; // === end of Move state === // rotDesiredAlt_Y sVar2 = psVar6[9]; // change direction psVar6[0xf] = 1; } // if direction is 1 else { // if you have not travelled far from spawn, // 0x2d = 45 frames = 1.5 seconds if (psVar6[7] < 0x2d) { // keep moving away from spawn psVar6[7] = psVar6[7] + 1; // dont turn around goto LAB_800b8fdc; } // if you have not reached max distance, dont turn around, // 0x2d = 45 frames = 1.5 seconds if (psVar6[7] != 0x2d) goto LAB_800b8fdc; // === end of Move state === // rotCurr_Y sVar2 = psVar6[9]; // change direction psVar6[0xf] = 0; } // === end of Move state === // turn around 180 degrees iVar5 = (int)sVar2 + 0x800; iVar3 = iVar5; if (iVar5 < 0) { iVar3 = (int)sVar2 + 0x17ff; } // 0x22, rotDesired psVar6[0x11] = (short)iVar5 + (short)(iVar3 >> 0xc) * -0x1000; // ThTick_SetAndExec RB_Seal_ThTick_TurnAround FUN_800716ec(param_1,&FUN_800b8c00); LAB_800b8fdc: // check for collision with all Players iVar3 = FUN_800314e0(iVar7,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b2c),0x4000); // if there is no collision if (iVar3 == 0) { // check for collision with all robotcars iVar3 = FUN_800314e0(iVar7,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b40),0x4000); // if there is no collision if (iVar3 == 0) { // check collision with all Mines (tnt, beaker, etc) iVar3 = FUN_800314e0(iVar7,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b7c),0x4000); // if there is a collision if (iVar3 != 0) { // instance -> thread -> funcThCollide pcVar4 = *(code **)(*(int *)(iVar3 + 0x6c) + 0x28); // execute funcThCollide (*pcVar4)(*(int *)(iVar3 + 0x6c)); } } // if there is a collision with robotcar else { // RB_Hazard_HurtDriver (spin out) FUN_800ac1b0(*(undefined4 *)(*(int *)(iVar3 + 0x6c) + 0x30),1,0,0); } } // if there is a collision with Player else { // instance -> thread -> object iVar7 = *(int *)(*(int *)(iVar3 + 0x6c) + 0x30); // kart -> state cVar1 = *(char *)(iVar7 + 0x376); // RB_Hazard_HurtDriver (spin out) iVar3 = FUN_800ac1b0(iVar7,1,0,0); // if change state worked, and if kart was not // already spinning out before this if ((iVar3 != 0) && (cVar1 != '\x03')) { // play sound of seal collision FUN_80028494(0x78,1,(uint)*(ushort *)(iVar7 + 0x2ca) & 1); } } return; } // RB_Seal_ThCollide void FUN_800b90d8(int param1, int param_2, int param_3, int param_4) { // check if modelID is player // modelID is 0xc of BSP meta return (uint)(*(short *)(param_4 + 0xc) == 0x18); } // RB_Seal_LInB void FUN_800b90ec(int param_1) { short sVar1; undefined *puVar2; undefined *puVar3; int iVar4; undefined4 *puVar5; undefined4 *puVar6; // If this instance has no thread if (*(int *)(param_1 + 0x6c) == 0) { // b8bf8 // "seal" // THREAD_BirthWithObject // 0x30 = size // 0 = no relation to param4 // 0x300 = SmallStackPool // 0x3 = "static" thread bucket iVar4 = FUN_8004205c(0x300303,FUN_800b8e1c,&DAT_800b8bf8,0); // give thread to instance *(int *)(param_1 + 0x6c) = iVar4; // if thread initialized successfully if (iVar4 != 0) { // Get object created with thread puVar6 = *(undefined4 **)(iVar4 + 0x30); // set funcThCollide *(undefined4 *)(iVar4 + 0x28) = 0x800b90d8; // give instance to thread *(int *)(iVar4 + 0x34) = param_1; // set scale (x,y,z) *(undefined2 *)(param_1 + 0x1c) = 0x2000; *(undefined2 *)(param_1 + 0x1e) = 0x2000; *(undefined2 *)(param_1 + 0x20) = 0x2000; // no distance from spawn *(short *)((int)puVar6 + 0xe) = 0; // direction moves away from spawn *(short *)((int)puVar6 + 0x1e) = 1; iVar4 = strlen(param_1 + 8); puVar2 = PTR_DAT_8008d2ac; // character minus '0', ascii index to int index iVar4 = (uint)*(byte *)(iVar4 + param_1 + 7) - 0x30; // sealID *(short *)((int)puVar6 + 6) = (short)iVar4; puVar3 = PTR_DAT_8008d2ac; // LEV -> numSpawn2 if (*(int *)(*(int *)(puVar2 + 0x160) + 0x138) != 0) { // use sealID to get spawn position of this seal puVar5 = *(undefined4 **)(iVar4 * 8 + *(int *)(*(int *)(puVar2 + 0x160) + 0x13c) + 4); sVar1 = *(short *)(puVar5 + 1); // spawnPosX, spawnPosY *puVar6 = *puVar5; // spawnPosZ *(short *)(puVar6 + 1) = sVar1; // use sealID to get spawnPosY iVar4 = *(int *)((int)*(short *)((int)puVar6 + 6) * 8 + *(int *)(*(int *)(puVar3 + 0x160) + 0x13c) + 4); // endPosZ sVar1 = *(short *)(iVar4 + 10); // endPosX, endPosY puVar6[2] = *(undefined4 *)(iVar4 + 6); // endPosZ *(short *)(puVar6 + 3) = sVar1; } // distance between spawnPos and endPos, used for velocity *(short *)(puVar6 + 10) = *(short *)puVar6 - *(short *)(puVar6 + 2); *(short *)((int)puVar6 + 0x2a) = *(short *)((int)puVar6 + 2) - *(short *)((int)puVar6 + 10); *(short *)(puVar6 + 0xb) = *(short *)(puVar6 + 1) - *(short *)(puVar6 + 3); // rotCurr (0x10) = instance->instDef->rot *(short *)(puVar6 + 4) = *(short *)(*(int *)(param_1 + 0x2c) + 0x36); *(short *)(puVar6 + 5) = *(short *)(*(int *)(param_1 + 0x2c) + 0x3a); sVar1 = *(short *)(*(int *)(param_1 + 0x2c) + 0x38); *(short *)((int)puVar6 + 0x12) = sVar1; // rotDesiredAlt (0x18) *(short *)(puVar6 + 6) = *(short *)(puVar6 + 4); *(short *)((int)puVar6 + 0x26) = 0; *(short *)((int)puVar6 + 0x1a) = sVar1; *(short *)(puVar6 + 7) = *(short *)(puVar6 + 5); // convert 3 rotation shorts into rotation matrix FUN_8006c2a4(param_1 + 0x30,puVar6 + 4); } } return; } // RB_Snowball_ThTick void FUN_800b92ac(int param_1) { short sVar1; undefined *puVar2; int iVar3; undefined4 uVar4; int iVar5; int iVar6; int iVar7; undefined2 uStack32; undefined2 uStack30; undefined2 uStack28; // get object from thread iVar6 = *(int *)(param_1 + 0x30); // get instance from thread iVar7 = *(int *)(param_1 + 0x34); do { if (*(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x140) != 0) { // instance -> model -> modelID sVar1 = *(short *)(*(int *)(iVar7 + 0x18) + 0x10); // Naughty Dog bug, the boulder has modelID: // TEMP_SNOWBALL (0x22), so the sound never plays, // set 1-byte 800b9304 to 0x22 to hear the sound // DYNAMIC_SNOWBALL if (sVar1 == 0x20) { // snowball roll uVar4 = 0x73; DAT_800b9328: // PlaySound3D_Flags FUN_8002f31c(iVar6 + 0xc,uVar4,iVar7); } else { // sewer speedway barrel if (sVar1 == 0x4e) { // barrel roll uVar4 = 0x74; goto DAT_800b9328; } } // get position index iVar5 = (int)*(short *)(iVar6 + 6); // if path is complete if ((int)*(short *)(iVar6 + 8) < iVar5) { // go backwards on the path iVar5 = (int)*(short *)(iVar6 + 8) * 2 - iVar5; } // Convert index to byte index, // 3 ints per position (x, y, z) iVar5 = iVar5 * 0xc; // RotX uStack32 = *(undefined2 *) (iVar5 + *(int *)((int)*(short *)(iVar6 + 10) * 8 + *(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x144) + 4) + 6); // RotY uStack30 = *(undefined2 *) (iVar5 + *(int *)((int)*(short *)(iVar6 + 10) * 8 + *(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x144) + 4) + 8); // RotZ uStack28 = *(undefined2 *) (iVar5 + *(int *)((int)*(short *)(iVar6 + 10) * 8 + *(int *)(*(int *)(PTR_DAT_8008d2ac + 0x160) + 0x144) + 4) + 10); // Make rotation matrix FUN_8006c2a4(iVar7 + 0x30,&uStack32); puVar2 = PTR_DAT_8008d2ac; // posX *(int *)(iVar7 + 0x44) = (int)*(short *)(iVar5 + *(int *)((int)*(short *)(iVar6 + 10) * 8 + *(int *)(*(int *)(puVar2 + 0x160) + 0x144) + 4) + 0); // posY *(int *)(iVar7 + 0x48) = (int)*(short *)(iVar5 + *(int *)((int)*(short *)(iVar6 + 10) * 8 + *(int *)(*(int *)(puVar2 + 0x160) + 0x144) + 4) + 2); // posZ *(int *)(iVar7 + 0x4c) = (int)*(short *)(iVar5 + *(int *)((int)*(short *)(iVar6 + 10) * 8 + *(int *)(*(int *)(puVar2 + 0x160) + 0x144) + 4) + 4); // Check for collision with Human drivers iVar5 = FUN_800314e0(iVar7,param_1,*(undefined4 *)(puVar2 + 0x1b2c),0x10000); if ((iVar5 != 0) || // Check for collision with AI drivers (iVar5 = FUN_800314e0(iVar7,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b40),0x10000), iVar5 != 0)) { // RB_Hazard_HurtDriver (squish) FUN_800ac1b0(*(undefined4 *)(*(int *)(iVar5 + 0x6c) + 0x30),3,0,0); } } // increment position index iVar3 = (int)*(short *)(iVar6 + 6) + 1; // double amount of points on path, which is // number of points in a full cycle iVar5 = (int)*(short *)(iVar6 + 8) << 1; if (iVar5 == 0) { trap(0x1c00); } if ((iVar5 == -1) && (iVar3 == -0x80000000)) { trap(0x1800); } // get next position index *(undefined2 *)(iVar6 + 6) = (short)(iVar3 % iVar5); // this skips $RA backup/restore, faster than JR $RA FUN_80071694(param_1); } while( true ); } // RB_Snowball_LInB void FUN_800b950c(int param_1) { short sVar1; undefined *puVar2; int iVar3; undefined2 *puVar4; if (*(int *)(param_1 + 0x6c) == 0) { // THREAD_BirthWithObject // 0x10 = size // 0 = no relation to param4 // 0x300 = SmallStackPool // 0x3 = "static" thread bucket iVar3 = FUN_8004205c(0x100303,FUN_800b92ac,s_snowball_800b92a0,0); // give thread to instance *(int *)(param_1 + 0x6c) = iVar3; // if thread built properly if (iVar3 != 0) { // thread -> object puVar4 = *(undefined2 **)(iVar3 + 0x30); // give instance to thread *(int *)(iVar3 + 0x34) = param_1; // rotX (unused) *puVar4 = 0; // probably strlen iVar3 = FUN_80077cc8(param_1 + 8); // gGT puVar2 = PTR_DAT_8008d2ac; // snowball ID iVar3 = (uint)*(byte *)(iVar3 + param_1 + 7) - 0x30; puVar4[5] = (short)iVar3; // number of points on path puVar4[4] = *(short *)(iVar3 * 8 + *(int *)(*(int *)(puVar2 + 0x160) + 0x144)) + -1; // Set scale (x, y, z) *(undefined2 *)(param_1 + 0x1c) = 0x1000; *(undefined2 *)(param_1 + 0x1e) = 0x1000; *(undefined2 *)(param_1 + 0x20) = 0x1000; // rotY (unused) puVar4[1] = *(short *)(param_1 + 0x34) >> 2; // rotZ (unused) sVar1 = *(short *)(param_1 + 0x40); // reset point index, beginning of path *(undefined4 *)(puVar4 + 6) = 0; // rotZ (unused) puVar4[2] = sVar1 >> 2; } } return; } // RB_Spider_DrawWebs // param_1 - threadbucket // param_2 - ptr first tileView void FUN_800b95fc(int param_1,int param_2) { short sVar1; ushort uVar2; int iVar3; int iVar4; MATRIX *r0; uint uVar5; uint *puVar6; int iVar7; uint *puVar8; int *piVar9; uint *puVar10; int iVar11; int iVar12; int iVar13; uint uVar14; uint uVar15; int iVar16; uint uVar17; uint uVar18; int iVar19; // if first thread is valid if (param_1 != 0) { iVar12 = 0; puVar10 = &DAT_1f800000; piVar9 = &DAT_1f800008; // all threads do { // thread -> instance -> instDef iVar3 = *(int *)(*(int *)(param_1 + 0x34) + 0x2c); // count number of spiders iVar12 = iVar12 + 1; // instDef->posZ sVar1 = *(short *)(iVar3 + 0x34); // instDef->posX uVar2 = *(ushort *)(iVar3 + 0x30); // thread -> instance -> posY iVar4 = *(int *)(*(int *)(param_1 + 0x34) + 0x48); // scratchpad meta data for generating Prims // puVar10 holds instDef->posY + 0x540, // piVar9 holds posX, posY, and posZ *puVar10 = (uint)uVar2 | (*(short *)(iVar3 + 0x32) + 0x540) * 0x10000; piVar9[-1] = (uint)uVar2 | (iVar4 + 0x60) * 0x10000; *piVar9 = (int)sVar1; // advance in scratchpad piVar9 = piVar9 + 3; // thread = thread -> sibling param_1 = *(int *)(param_1 + 0x10); // advance in scratchpad puVar10 = puVar10 + 3; } while (param_1 != 0); // backBuffer->primMem.curr puVar10 = *(uint **)(*(int *)(PTR_DAT_8008d2ac + 0x10) + 0x80); // if (primMem.curr + (numSpiders * numPlyrCurrGame * 6)) < primMem.endMin100 if (puVar10 + iVar12 * (uint)(byte)PTR_DAT_8008d2ac[0x1ca8] * 6 < *(uint **)(*(int *)(PTR_DAT_8008d2ac + 0x10) + 0x84)) { // loop through all players iVar3 = (byte)PTR_DAT_8008d2ac[0x1ca8] - 1; iVar4 = 0x1200; // if there are players if (-1 < iVar3) { uVar17 = 0xe1000a20; // 0x40 - LineF2 uVar15 = 0x42000000; // LineF2 length (prim header) uVar18 = 0x5000000; // bit mask for writing OT header uVar14 = 0xffffff; iVar11 = 0x1f800000; // loop through all players do { // tileView->0x28 (matrix) r0 = (MATRIX *)(param_2 + 0x28); // store on GTE gte_SetRotMatrix(r0); gte_SetTransMatrix(r0); // loop count, numSpiders iVar13 = iVar12; // scratchpad pointer iVar16 = iVar11; // if numSpiders != 0 if (iVar12 != 0) { // primMem offset 0xC puVar8 = puVar10 + 3; // loop through spiders do { // point0 gte_ldVXY0(iVar11); gte_ldVZ0(iVar11 + 8); // point1 gte_ldVXY1(iVar11 + 4); gte_ldVZ1(iVar11 + 8); // perspective projection gte_rtpt(); gte_stsxy01c((long *)(puVar10 + 4)); // depth of vertex on screen iVar7 = gte_stSZ1(); // color (gray) uVar5 = 0x3f; // if line is close enough to the screen // to be seen, then generate primitives if (iVar7 - 1U < 0x11ff) { puVar8[-2] = uVar17; puVar8[-1] = 0; if (0xa00 < iVar7) { iVar19 = (iVar4 - iVar7) * 0x3f; uVar5 = iVar19 >> 0xb; if (iVar19 < 0) { uVar5 = iVar19 + 0x7ff >> 0xb; } } // prim offset 0x4, // R,G,B,code(0x42) LINE_F2 *puVar8 = uVar5 | uVar5 << 8 | uVar5 << 0x10 | uVar15; iVar7 = iVar7 >> 6; if (0x3ff < iVar7) { iVar7 = 0x3ff; } // tileView 0xf4, ptrOT puVar6 = (uint *)(*(int *)(param_2 + 0xf4) + iVar7 * 4); puVar8 = puVar8 + 6; // prim header, OT and prim len *puVar10 = *puVar6 | uVar18; // ot header = prim address, without top byte uVar5 = (uint)puVar10 & uVar14; puVar10 = puVar10 + 6; // store OT *puVar6 = uVar5; } // next spider iVar12 = iVar12 + -1; // advance scratchpad iVar11 = iVar11 + 0xc; } while (iVar12 != 0); } // next player iVar3 = iVar3 + -1; // next tileView param_2 = param_2 + 0x110; // reset spider loop count, // reset scratchpad pointer iVar12 = iVar13; iVar11 = iVar16; } while (-1 < iVar3); } // backBuffer->primMem.curr *(uint **)(*(int *)(PTR_DAT_8008d2ac + 0x10) + 0x80) = puVar10; } } return; } // RB_Spider_ThTick void FUN_800b9848(int param_1) { char cVar1; short sVar2; int iVar3; code *pcVar4; int iVar5; short *psVar6; // get object from thread psVar6 = *(short **)(param_1 + 0x30); // get instance from thread iVar5 = *(int *)(param_1 + 0x34); // delay cycle by varying frames if (psVar6[2] != 0) { psVar6[2] = psVar6[2] + -1; return; } psVar6[4] = psVar6[4] + 1; // If spider is on ground if (psVar6[3] == 0) { // if animation finished more than 4 times if (4 < *psVar6) { // Play animation backwards sVar2 = *(short *)(iVar5 + 0x54) + -1; // if animation is at beginning if ((int)*(short *)(iVar5 + 0x54) + -1 < 1) { // reset animation frame *(undefined2 *)(iVar5 + 0x54) = 0; // reset counter *psVar6 = 0; // spider is now at ceiling psVar6[3] = 1; // set animation to WiggleLegsAndTeeth goto LAB_800b9a14; } // set new animation frame *(short *)(iVar5 + 0x54) = sVar2; // last frame of last animation if (sVar2 == 0xc) { // play sound: spider move up FUN_8002f0dc(0x79,iVar5); } goto LAB_800b9a1c; } // instance -> animation frame sVar2 = *(short *)(iVar5 + 0x54); // INSTANCE_GetNumAnimFrames iVar3 = FUN_80030f58(iVar5); // if animation is done if (iVar3 <= (int)sVar2 + 1) { // restart animation *(undefined2 *)(iVar5 + 0x54) = 0; // increment number of times animation finishes sVar2 = *psVar6; *psVar6 = sVar2 + 1; // if animation finishes 5 times if ((short)(sVar2 + 1) == 5) { // set animation to zero *(undefined *)(iVar5 + 0x52) = 0; // INSTANCE_GetNumAnimFrames sVar2 = FUN_80030f58(iVar5,0); // set animation frame to last frame *(short *)(iVar5 + 0x54) = sVar2 + -1; } goto LAB_800b9aa8; } } // if spider is near ceiling else { // if spider animation played more than 4 times if (4 < *psVar6) { // instance -> animationFrame sVar2 = *(short *)(iVar5 + 0x54); // INSTANCE_GetNumAnimFrames iVar3 = FUN_80030f58(iVar5,0); // if animation is not done if ((int)sVar2 + 1 < iVar3) { // increment number of frames *(short *)(iVar5 + 0x54) = *(short *)(iVar5 + 0x54) + 1; } // if animation finished else { // reset animation counter *psVar6 = 0; // move spider to ground psVar6[3] = 0; LAB_800b9a14: // set animation to WiggleLegsAndTeeth *(undefined *)(iVar5 + 0x52) = 1; } LAB_800b9a1c: // set posY, based on InstDef posY *(int *)(iVar5 + 0x48) = (int)*(short *)(*(int *)(iVar5 + 0x2c) + 0x32) + (int)*(short *)(&DAT_800b9da4 + (int)*(short *)(iVar5 + 0x54) * 2); // if animation frame is less than 11 if ((int)*(short *)(iVar5 + 0x54) < 0xb) { // change spider scaleX and scaleZ based on animation frame // scaleX *(short *)(*(int *)(psVar6 + 6) + 0x1c) = (short)(((int)*(short *)(iVar5 + 0x54) << 0xc) / 10) + 0x1800; // scaleZ *(short *)(*(int *)(psVar6 + 6) + 0x20) = (short)(((int)*(short *)(iVar5 + 0x54) << 0xc) / 10) + 0x1800; } goto LAB_800b9aa8; } // get animation frame sVar2 = *(short *)(iVar5 + 0x54); // INSTANCE_GetNumAnimFrames iVar3 = FUN_80030f58(iVar5); // if animation is finished if (iVar3 <= (int)sVar2 + 1) { // restart animation to frame zero *(undefined2 *)(iVar5 + 0x54) = 0; // increment number of times animation finishes sVar2 = *psVar6; *psVar6 = sVar2 + 1; // if animation finishes 5 times if ((short)(sVar2 + 1) == 5) { // set animation to ChangePosition *(undefined *)(iVar5 + 0x52) = 0; // set animation frame to zero *(undefined2 *)(iVar5 + 0x54) = 0; // play sound: spider move down FUN_8002f0dc(0x7a,iVar5); } goto LAB_800b9aa8; } } // increment animation frame *(short *)(iVar5 + 0x54) = *(short *)(iVar5 + 0x54) + 1; LAB_800b9aa8: // check for collision with all Players iVar3 = FUN_800314e0(iVar5,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b2c),0x9000); // if there is no collision if (iVar3 == 0) { // check for collision with all robot cars iVar3 = FUN_800314e0(iVar5,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b40),0x9000); // if there is no collision if (iVar3 == 0) { // check for collision with all Mines (tnts, beakers, etc) iVar5 = FUN_800314e0(iVar5,param_1,*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b7c),0x9000); // if there is a collision if (iVar5 != 0) { // instance -> thread -> funcThCollide pcVar4 = *(code **)(*(int *)(iVar5 + 0x6c) + 0x28); // execute collison pointer (*pcVar4)(*(int *)(iVar5 + 0x6c)); } } // if you collide with robotcar else { // RB_Hazard_HurtDriver (spin out) FUN_800ac1b0(*(undefined4 *)(*(int *)(iVar3 + 0x6c) + 0x30),1,0,0); } } // if you collide with player else { // instance -> thread -> object iVar3 = *(int *)(*(int *)(iVar3 + 0x6c) + 0x30); // kart state cVar1 = *(char *)(iVar3 + 0x376); // RB_Hazard_HurtDriver (spin out) iVar5 = FUN_800ac1b0(iVar3,1,0,0); if ((iVar5 != 0) && (cVar1 != '\x03')) { // Play sound FUN_80028468(0x7b,1); // make driver talk FUN_8002cbe8(1,(int)(short)(&DAT_80086e84)[*(byte *)(iVar3 + 0x4a)],0x10); } } return; } // RB_Spider_ThCollide (unused?) void FUN_800b9bc0(int param1, int param_2, int param_3, int param_4) { // check if modelID is player // modelID is 0xc of BSP meta return (uint)(*(short *)(param_4 + 0xc) == 0x18); } // RB_Spider_LInB void FUN_800b9bd4(int param_1) { int iVar1; int iVar2; undefined4 uVar3; undefined4 uVar4; undefined4 uVar5; undefined2 *puVar6; undefined2 local_18; undefined2 local_16; undefined2 local_14; // If this instance has no thread if (*(int *)(param_1 + 0x6c) == 0) { // b95e4 // "spider" // THREAD_BirthWithObject // 0x10 = size // 0 = no relation to param4 // 0x300 = SmallStackPool // 0xa = "spider" thread bucket iVar1 = FUN_8004205c(0x10030a,FUN_800b9848,0x800b95e4,0); // give thread to instance *(int *)(param_1 + 0x6c) = iVar1; // if thread built successfully if (iVar1 != 0) { // get object created with thread puVar6 = *(undefined2 **)(iVar1 + 0x30); // set funcThCollide, to make player spin out *(undefined4 *)(iVar1 + 0x28) = 0x800b9bc0; // give instance to thread *(int *)(iVar1 + 0x34) = param_1; // set scale (x,y,z) *(undefined2 *)(param_1 + 0x1c) = 0x1c00; *(undefined2 *)(param_1 + 0x1e) = 0x1c00; *(undefined2 *)(param_1 + 0x20) = 0x1c00; // set animation to 1 *(undefined *)(param_1 + 0x52) = 1; // spiderID iVar2 = strlen(param_1 + 8); puVar6[1] = (ushort)*(byte *)(iVar2 + param_1 + 7) - 0x30; // spider is near roof puVar6[3] = 1; // reset animation loop counter *puVar6 = 0; // depending on spiderID, set delay, // three different cycles total if (puVar6[1] == 3) { puVar6[2] = 0x5b; } else { if (puVar6[1] == 2) { puVar6[2] = 0x45; } else { puVar6[2] = 0; } } // INSTANCE_Birth3D -- ptrModel, name, thread iVar1 = FUN_8003086c(*(undefined4 *)(PTR_DAT_8008d2ac + 0x22ac), s_spidershadow_800b95ec,iVar1); // save instance *(int *)(puVar6 + 6) = iVar1; // copy position and rotation from one instance to another uVar3 = *(undefined4 *)(param_1 + 0x34); uVar4 = *(undefined4 *)(param_1 + 0x38); uVar5 = *(undefined4 *)(param_1 + 0x3c); *(undefined4 *)(iVar1 + 0x30) = *(undefined4 *)(param_1 + 0x30); *(undefined4 *)(iVar1 + 0x34) = uVar3; *(undefined4 *)(iVar1 + 0x38) = uVar4; *(undefined4 *)(iVar1 + 0x3c) = uVar5; uVar3 = *(undefined4 *)(param_1 + 0x44); uVar4 = *(undefined4 *)(param_1 + 0x48); uVar5 = *(undefined4 *)(param_1 + 0x4c); *(undefined4 *)(iVar1 + 0x40) = *(undefined4 *)(param_1 + 0x40); // Set position of spider shadow *(undefined4 *)(iVar1 + 0x44) = uVar3; *(undefined4 *)(iVar1 + 0x48) = uVar4; *(undefined4 *)(iVar1 + 0x4c) = uVar5; // X, Y, Z *(undefined4 *)(*(int *)(puVar6 + 6) + 0x44) = *(undefined4 *)(param_1 + 0x44); *(int *)(*(int *)(puVar6 + 6) + 0x48) = *(int *)(param_1 + 0x48) + -8; *(undefined4 *)(*(int *)(puVar6 + 6) + 0x4c) = *(undefined4 *)(param_1 + 0x4c); // Scale (x, y, z) *(undefined2 *)(*(int *)(puVar6 + 6) + 0x1c) = 0x2000; *(undefined2 *)(*(int *)(puVar6 + 6) + 0x1e) = 0x2000; *(undefined2 *)(*(int *)(puVar6 + 6) + 0x20) = 0x2000; local_18 = 0; local_14 = 0; local_16 = 0x200; // convert 3 rotation shorts into rotation matrix FUN_8006c2a4(*(int *)(puVar6 + 6) + 0x30,&local_18); *(int *)(param_1 + 0x48) = *(int *)(param_1 + 0x48) + 0x4c0; } } return; } // RB_StartText_ProcessBucket void FUN_800b9dd8() { // intentionally empty, // JR RA + NOP, 8 bytes large return; } // RB_StartText_LInB void FUN_800b9de0() { // intentionally empty // JR RA + NOP, 8 bytes large return; } // RB_Teeth_LInB void FUN_800b9df0(undefined4 param_1,int param_2) { // Do not make a thread for time trial, or relic. // Time Trial will be forever closed // Relic will be forever open *(char *)(param_2 + 0x50) = *(char *)(param_2 + 0x50) + '\x02'; // If in relic race if ((*(uint *)PTR_DAT_8008d2ac & 0x4000000) != 0) { // enable access through a door (disable collision) DAT_8008d728 = DAT_8008d728 | 1; // Make invisible *(uint *)(param_2 + 0x28) = *(uint *)(param_2 + 0x28) | 0x80; } return; } // RB_Teeth_BSP_Callback void FUN_800b9e44(short *param_1,int param_2) { short sVar1; int iVar2; int iVar3; int iVar4; sVar1 = *(short *)(param_2 + 0x44); // if not driver if (sVar1 != 0x18) { if (sVar1 < 0x19) { // if not nitro if (sVar1 != 6) { return; } } else { // if not potion or tnt if ((sVar1 != 0x1d) && (sVar1 != 0x27)) { return; } } } // thread on ScratchpadStruct iVar2 = *(int *)(param_1 + 0xc); // another instance iVar3 = *(int *)(param_2 + 0x34); // thread instance iVar4 = *(int *)(iVar2 + 0x34); if ((iVar3 != 0) && (iVar4 != 0)) { iVar2 = ((int)param_1[0] - *(int *)(iVar3 + 0x44)) * (int)*(short *)(iVar4 + 0x34) + ((int)param_1[2] - *(int *)(iVar3 + 0x4c)) * (int)*(short *)(iVar4 + 0x40); if (iVar2 < 0) { iVar2 = -iVar2; } if (0x100 < iVar2 >> 0xc) { return; } // thread (again) iVar2 = *(int *)(param_1 + 0xc); } // door is open **(undefined4 **)(iVar2 + 0x30) = 1; return; } // RB_Teeth_ThTick void FUN_800b9f0c(int param_1) { int iVar1; uint uVar2; int *piVar3; int iVar4; // get object from thread piVar3 = *(int **)(param_1 + 0x30); // get instance from thread iVar4 = *(int *)(param_1 + 0x34); // if door is not moving if (*piVar3 == 0) { // if timer is zero if (piVar3[1] == 0) goto LAB_800b9ff8; // reduce timer by milliseconds iVar1 = piVar3[1] - *(int *)(PTR_DAT_8008d2ac + 0x1d04); // set new timer piVar3[1] = iVar1; // if timer is up if (iVar1 < 1) { // play sound // teeth closing FUN_8002f0dc(0x75,iVar4); // timer is zero piVar3[1] = 0; // door is closing *piVar3 = -1; goto LAB_800b9fe8; } } // if door is moving else { // modify animation idex by direction *(short *)(iVar4 + 0x54) = *(short *)(iVar4 + 0x54) + *(short *)piVar3; // get number of frames in animation iVar1 = FUN_8005b0f4(iVar4,0); // if animation is not on last frame if ((int)*(short *)(iVar4 + 0x54) < iVar1) { // if animation when backwards past beginning if ((int)*(short *)(iVar4 + 0x54) < 0) { // set animation to beginning *(undefined2 *)(iVar4 + 0x54) = 0; // door is not moving *piVar3 = 0; // timer is zero piVar3[1] = 0; // remove access (enable collision) DAT_8008d728 = DAT_8008d728 & 0xfffffffe; } } // if animation is on last frame (or past) else { // set animation to last frame *(short *)(iVar4 + 0x54) = (short)iVar1 + -1; // door is not moving (fully open) *piVar3 = 0; // timer, 2 seconds piVar3[1] = 0x780; } LAB_800b9fe8: if (piVar3[1] == 0) { LAB_800b9ff8: if (-1 < *piVar3) goto LAB_800ba084; } } // Teeth instance position DAT_1f800108 = *(undefined2 *)(iVar4 + 0x44); DAT_1f80010a = *(undefined2 *)(iVar4 + 0x48); DAT_1f80010c = *(undefined2 *)(iVar4 + 0x4c); // hitRadius and hitRadiusSquared DAT_1f80010e = 0x300; _DAT_1f800110 = 0x90000; // RB_Teeth_BSP_Callback // not a BSP callback, ThreadBucket collision callback DAT_1f800130 = &FUN_800b9e44; DAT_1f800114 = 0x70; DAT_1f800120 = param_1; // If door wants to close, but Player or Mine // is in the way, then do not force the doors to close // pointer to first Player thread FUN_800425d4(*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b2c),&DAT_1f800108,0); // pointer to first Mine thread (tnt, beaker, etc) FUN_800425d4(*(undefined4 *)(PTR_DAT_8008d2ac + 0x1b7c),&DAT_1f800108,0); LAB_800ba084: // if no timer exists // (opening, closing, or full closed) if (piVar3[1] == 0) { // make visible uVar2 = *(uint *)(iVar4 + 0x28) & 0xffffff7f; } // if a timer is active // (fully open) else { // make invisible uVar2 = *(uint *)(iVar4 + 0x28) | 0x80; } // set flags *(uint *)(iVar4 + 0x28) = uVar2; return; } // RB_Teeth_LInC undefined4 FUN_800ba0c8(int param_1,int param_2,short *param_3) { int iVar1; undefined4 *puVar2; // This is the door you can shoot in tiger temple // If not in relic race, ignore the function, // there are no weapons to activate door anyways if ((*(uint *)PTR_DAT_8008d2ac & 0x4000000) == 0) { // get thread for this instance iVar1 = *(int *)(param_1 + 0x6c); // if there is no thread if (iVar1 == 0) { // THREAD_BirthWithObject // 0x8 = size // 0 = no relation to param4 // 0x300 = SmallStackPool // 0x3 = "static" thread bucket iVar1 = FUN_8004205c(0x80303,FUN_800b9f0c,s_teeth_800b9de8,0); // give thread to instance *(int *)(param_1 + 0x6c) = iVar1; // if thread failed if (iVar1 == 0) { // quit return 2; } // get object created with thread puVar2 = *(undefined4 **)(iVar1 + 0x30); // give instance to thread *(int *)(iVar1 + 0x34) = param_1; // door not moving *puVar2 = 0; // timer is zero puVar2[1] = 0; } // get object created by thread iVar1 = *(int *)(iVar1 + 0x30); // if collided object is a player if (param_3[6] == 0x18) { // if driver is using mask weapon if ((*(uint *)(*(int *)(param_2 + 0x30) + 0x2c8) & 0x800000) != 0) { // RB_Teeth_OpenDoor FUN_800ba220(param_1); } // if collided object is a player if (param_3[6] == 0x18) { return 2; } } // If collide with something // that is not a player // teeth->timeOpen == 0 (time to close) if (*(int *)(iVar1 + 4) == 0) { iVar1 = // (collObj.x - teethInst.x) * teethInst.matrix[0][2] ((int)*param_3 - *(int *)(param_1 + 0x44)) * (int)*(short *)(param_1 + 0x34) + // (collObj.z - teethInst.z) * teethInst.matrix[2][2] ((int)param_3[2] - *(int *)(param_1 + 0x4c)) * (int)*(short *)(param_1 + 0x40); if (iVar1 < 0) { iVar1 = -iVar1; } if (iVar1 >> 0xc < 0x81) { return 1; } return 2; } } return 2; } // RB_Teeth_OpenDoor void FUN_800ba220(int param_1) { int iVar1; // get thread for object iVar1 = *(int *)(param_1 + 0x6c); // if there is no thread, // just in case it wasn't initialized if (iVar1 == 0) { // THREAD_BirthWithObject // 0x8 = size // 0 = no relation to param4 // 0x300 flag = SmallStackPool // 0x3 = "static" thread bucket iVar1 = FUN_8004205c(0x80303,FUN_800b9f0c,s_teeth_800b9de8,0); // give thread to instance *(int *)(param_1 + 0x6c) = iVar1; // if thread failed if (iVar1 == 0) { // quit return; } // give instance to thread *(int *)(iVar1 + 0x34) = param_1; *(undefined4 *)(*(int *)(iVar1 + 0x30) + 4) = 0; } // play sound, // teeth opening FUN_8002f0dc(0x75,param_1); // door is open **(undefined4 **)(iVar1 + 0x30) = 1; // enable access through a door (disable collision) DAT_8008d728 = DAT_8008d728 | 1; return; } // RB_Turtle_ThTick void FUN_800ba2c0(int param_1) { short sVar1; short sVar2; int iVar3; short *psVar4; int iVar5; // thread -> object psVar4 = *(short **)(param_1 + 0x30); // thread -> instance iVar5 = *(int *)(param_1 + 0x34); // 0 from moment it hits bottom to moment it hits top if (psVar4[1] == 0) { sVar1 = *psVar4; // if less than 1.0 seconds // wait for rise if (*psVar4 < 0x3c0) { // get elapsed ms per frame ~32 sVar2 = *(short *)(PTR_DAT_8008d2ac + 0x1d04); // add milliseconds *psVar4 = sVar1 + sVar2; // Naughty Dog bug, should have just been: // if (0x3c0 < sVar1+sVar2) // *psVar4 = 0x3c0 // play sound // Then the original "if < 0x3c0" // goes to "else" next frame // if more than 1.5 seconds passed if (0x5a0 < (short)(sVar1 + sVar2)) { // lock to 1.5s *psVar4 = 0x5a0; } // if 1.5s passed if (*psVar4 == 0x5a0) { // play water sound FUN_8002f0dc(0x7d,iVar5); } } // if more than one second has passed // time to rise else { // turtle not fully down, // impacts jumping psVar4[4] = 1; // end of animation if ((int)*(short *)(iVar5 + 0x54) + -1 < 1) { // reset direction psVar4[1] = 1; // reset timer to zero *psVar4 = 0; } // playing animation else { // decrement frame (make turtle rise) *(short *)(iVar5 + 0x54) = *(short *)(iVar5 + 0x54) + -1; } } } // 1 from moment it hits top to moment it hits bottom else { // get timer sVar1 = *psVar4; // if less than 1.0 seconds // wait for time to fall if (*psVar4 < 0x3c0) { // get elaped time sVar2 = *(short *)(PTR_DAT_8008d2ac + 0x1d04); // add milliseconds *psVar4 = sVar1 + sVar2; // Naughty Dog bug, should be 0x3c0 // if more than 1.5s if (0x5a0 < (short)(sVar1 + sVar2)) { // lock to 1.5s *psVar4 = 0x5a0; } } // if more than 1.0s // time to fall else { // get animation frame sVar1 = *(short *)(iVar5 + 0x54); // INSTANCE_GetNumAnimFrames iVar3 = FUN_80030f58(iVar5,0); // if animation is not done if ((int)sVar1 + 1 < iVar3) { // increment frame (make turtle fall) *(short *)(iVar5 + 0x54) = *(short *)(iVar5 + 0x54) + 1; } // if animation is done else { // reset direction psVar4[1] = 0; // reset timer *psVar4 = 0; // turtle is fully down psVar4[4] = 0; } } } return; } // RB_Turtle_LInC undefined4 FUN_800ba420(int param_1,int param_2) { int iVar1; undefined uVar2; // get driver speed iVar1 = (int)*(short *)(*(int *)(param_2 + 0x30) + 0x38e); // absolute value if (iVar1 < 0) { iVar1 = -iVar1; } // if driver has high speed if (0x1400 < iVar1) { // small jump uVar2 = 1; // if turtleInst->thread->object->state != FullyDown if (*(short *)(*(int *)(*(int *)(param_1 + 0x6c) + 0x30) + 8) != 0) { // big jump uVar2 = 2; } // make the player jump *(undefined *)(*(int *)(param_2 + 0x30) + 0x366) = uVar2; return 2; } return 1; } // RB_Turtle_LInB void FUN_800ba470(int param_1) { undefined2 uVar1; int iVar2; undefined2 *puVar3; *(uint *)(param_1 + 0x28) = *(uint *)(param_1 + 0x28) | 0x2000; // if there is no thread for this instance if (*(int *)(param_1 + 0x6c) == 0) { // THREAD_BirthWithObject // 0xc = size // 0 = no relation to param4 // 0x300 flag = SmallStackPool // 0x3 = "static" thread bucket iVar2 = FUN_8004205c(0xc0303,&FUN_800ba2c0,s_turtle_800ba2b8,0); // give thread to instance *(int *)(param_1 + 0x6c) = iVar2; // if the thread built successfully if (iVar2 != 0) { // get object created with thread puVar3 = *(undefined2 **)(iVar2 + 0x30); // give instance to thread *(int *)(iVar2 + 0x34) = param_1; // set scale (x,y,z) *(undefined2 *)(param_1 + 0x1c) = 0x1000; *(undefined2 *)(param_1 + 0x1e) = 0x1000; *(undefined2 *)(param_1 + 0x20) = 0x1000; // get length of string attached to instance iVar2 = strlen(param_1 + 8); // turtleID puVar3[2] = (ushort)*(byte *)(iVar2 + param_1 + 7) - 0x30; // default direction (waste) puVar3[1] = 1; // reset timer *puVar3 = 0; // restart animation, set frame to zero *(undefined2 *)(param_1 + 0x54) = 0; // put turtles on different cycles, based on turtleID if ((puVar3[2] & 1) == 0) { // turtle is fully up puVar3[1] = 1; puVar3[4] = 1; } else { // turtle is fully down puVar3[1] = 0; puVar3[4] = 0; // INSTANCE_GetNumAnimFrames // last frame of fall animation uVar1 = FUN_80030f58(param_1,0); *(undefined2 *)(param_1 + 0x54) = uVar1; } } } return; }