void CK6_MapMiscFlagsCheck(CK_object *obj) { if (obj->user3 == 0) { int tileX = obj->clipRects.tileXmid; int tileY = RF_UnitToTile(obj->clipRects.unitY1 + (obj->clipRects.unitY2 - obj->clipRects.unitY1)/2); uint16_t tile = CA_TileAtPos(tileX, tileY, 1); uint8_t miscValue = TI_ForeMisc(tile); if (miscValue == MISCFLAG_TELEPORT) CK_AnimateMapTeleporter(tileX, tileY); } }
void CK6_RocketFly(CK_object *obj) { if (!ck_nextX && !ck_nextY) { if (!SD_SoundPlaying()) SD_PlaySound(SOUND_ROCKETFLY); int delta = SD_GetSpriteSync() * 32; // Will we reach a new tile? if (obj->user2 > delta) { // No... keep moving in the same direction. obj->user2 -= delta; int dirX = ck_infoplaneArrowsX[obj->user1]; if (dirX == 1) { // Moving right. ck_nextX += delta; } else if (dirX == -1) { // Moving left ck_nextX -= delta; } int dirY = ck_infoplaneArrowsY[obj->user1]; if (dirY == 1) { // Moving down ck_nextY += delta; } else if (dirY == -1) { // Moving up ck_nextY -= delta; } } else { // Move to next tile. int dirX = ck_infoplaneArrowsX[obj->user1]; if (dirX == 1) { // Moving right. ck_nextX += obj->user2; } else if (dirX == -1) { // Moving left ck_nextX -= obj->user2; } int dirY = ck_infoplaneArrowsY[obj->user1]; if (dirY == 1) { // Moving down ck_nextY += obj->user2; } else if (dirY == -1) { // Moving up ck_nextY -= obj->user2; } int tileX = (uint16_t)RF_UnitToTile(obj->posX + ck_nextX); int tileY = (uint16_t)RF_UnitToTile(obj->posY + ck_nextY); obj->user1 = CA_TileAtPos(tileX, tileY, 2) - 0x5B; if ((obj->user1 < 0) || (obj->user1 > 8)) { obj->posX += ck_nextX; obj->posY += ck_nextY; CK_SetAction2(obj, CK_GetActionByName("CK6_ACT_RocketSit0")); ck_keenObj->posX = RF_TileToUnit(tileX + 1) + 0x10; ck_keenObj->posY = RF_TileToUnit(tileY + 1); ck_keenObj->type = CT_Player; ck_keenObj->gfxChunk = 0xBD; ck_keenObj->clipped = CLIP_normal; CK_SetAction(ck_keenObj, CK_GetActionByName("CK_ACT_MapKeenStart")); ck_gameState.ep.ck6.inRocket ^= 1; return; } delta -= obj->user2; obj->user2 = 256 - delta; // Move in the new direction. dirX = ck_infoplaneArrowsX[obj->user1]; if (dirX == 1) { // Moving right. ck_nextX += delta; } else if (dirX == -1) { // Moving left ck_nextX -= delta; } dirY = ck_infoplaneArrowsY[obj->user1]; if (dirY == 1) { // Moving down ck_nextY += delta; } else if (dirY == -1) { // Moving up ck_nextY -= delta; } } } }
// TODO: Cache stuff here instead of spawner handlers void CK6_ScanInfoLayer() { //TODO: Work out where to store current map number, etc. int mapW = CA_MapHeaders[ca_mapOn]->width; int mapH = CA_MapHeaders[ca_mapOn]->height; for (int y = 0; y < mapH; ++y) { for (int x = 0; x < mapW; ++x) { int infoValue = CA_TileAtPos(x, y, 2); switch (infoValue) { case 1: CK_SpawnKeen(x, y, 1); CK_DemoSignSpawn(); ca_graphChunkNeeded[175] |= ca_levelbit; ck6_lumpsNeeded[Lump_Keen] = true; break; case 2: CK_SpawnKeen(x, y, -1); CK_DemoSignSpawn(); ca_graphChunkNeeded[175] |= ca_levelbit; ck6_lumpsNeeded[Lump_Keen] = true; break; case 3: CK_DemoSignSpawn(); ca_graphChunkNeeded[175] |= ca_levelbit; CK_SpawnMapKeen(x, y); ck6_lumpsNeeded[Lump_Mapkeen] = true; break; // Bloogs case 6: if (ck_gameState.difficulty < D_Hard) break; case 5: if (ck_gameState.difficulty < D_Normal) break; case 4: ck6_lumpsNeeded[Lump_Bloog] = true; CK6_SpawnBloog(x, y); break; case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: { int color = (infoValue - 7) % 4; ck6_lumpsNeeded[Lump_BloogletR + color] = true; CK6_SpawnBlooglet(x, y, infoValue - 7); break; } case 15: case 16: CK6_SpawnMapCliff(x, y, infoValue - 15); break; case 24: ck6_lumpsNeeded[Lump_Molly] = true; CK6_SpawnMolly(x, y); break; // Fleex case 20: if (ck_gameState.difficulty < D_Hard) break; case 19: if (ck_gameState.difficulty < D_Normal) break; case 18: ck6_lumpsNeeded[Lump_Fleex] = true; CK6_SpawnFleex(x, y); break; case 25: RF_SetScrollBlock(x, y, true); break; case 26: RF_SetScrollBlock(x, y, false); break; // Platforms case 27: case 28: case 29: case 30: CK_SpawnAxisPlatform(x, y, infoValue - 27, false); ck6_lumpsNeeded[Lump_Platform] = true; break; case 32: CK_SpawnFallPlat(x, y); ck6_lumpsNeeded[Lump_Platform] = true; break; case 33: if (ck_gameState.difficulty > D_Easy) break; case 34: if (ck_gameState.difficulty > D_Normal) break; case 35: CK_SpawnStandPlatform(x, y); ck6_lumpsNeeded[Lump_Platform] = true; break; case 36: case 37: case 38: case 39: CK_SpawnGoPlat(x, y, infoValue - 36, false); ck6_lumpsNeeded[Lump_Platform] = true; ck6_lumpsNeeded[Lump_PlatBip] = true; break; case 40: CK_SneakPlatSpawn(x, y); ck6_lumpsNeeded[Lump_Platform] = true; break; // Bobbas case 43: if (ck_gameState.difficulty < D_Hard) break; case 42: if (ck_gameState.difficulty < D_Normal) break; case 41: ck6_lumpsNeeded[Lump_Bobba] = true; CK6_SpawnBobba(x, y); break; case 44: case 45: CK6_SpawnSatelliteLoading(x, y, infoValue - 44); break; // Nospike case 49: if (ck_gameState.difficulty < D_Hard) break; case 48: if (ck_gameState.difficulty < D_Normal) break; case 47: ck6_lumpsNeeded[Lump_Nospike] = true; CK6_SpawnNospike(x, y); break; // Gik case 52: if (ck_gameState.difficulty < D_Hard) break; case 51: if (ck_gameState.difficulty < D_Normal) break; case 50: ck6_lumpsNeeded[Lump_Gik] = true; CK6_SpawnGik(x, y); break; // Turrets case 53: case 54: case 55: case 56: ck6_lumpsNeeded[Lump_Turret] = true; CK_TurretSpawn(x, y, infoValue - 53); break; case 69: // Spawn extra stunner if Keen has low ammo if (ck_gameState.numShots >= 5) break; infoValue = 68; case 57: case 58: case 59: case 60: case 61: case 62: case 63: case 64: case 65: case 66: case 67: case 68: CK_SpawnItem(x, y, infoValue - 57); ck6_lumpsNeeded[ck6_itemLumps[infoValue - 57]] = true; break; // Orbatrices case 72: if (ck_gameState.difficulty < D_Hard) break; case 71: if (ck_gameState.difficulty < D_Normal) break; case 70: ck6_lumpsNeeded[Lump_Orbatrix] = true; CK6_SpawnOrbatrix(x, y); break; // Bip case 75: if (ck_gameState.difficulty < D_Hard) break; case 74: if (ck_gameState.difficulty < D_Normal) break; case 73: ck6_lumpsNeeded[Lump_Bip] = true; ck6_lumpsNeeded[Lump_PlatBip] = true; ck6_lumpsNeeded[Lump_Bipship] = true; CK6_SpawnBipship(x, y); break; // Flects case 78: if (ck_gameState.difficulty < D_Hard) break; case 77: if (ck_gameState.difficulty < D_Normal) break; case 76: ck6_lumpsNeeded[Lump_Flect] = true; CK6_SpawnFlect(x, y); break; // Blorbs case 81: if (ck_gameState.difficulty < D_Hard) break; case 80: if (ck_gameState.difficulty < D_Normal) break; case 79: ck6_lumpsNeeded[Lump_Blorb] = true; CK6_SpawnBlorb(x, y); break; // Ceilicks case 84: if (ck_gameState.difficulty < D_Hard) break; case 83: if (ck_gameState.difficulty < D_Normal) break; case 82: ck6_lumpsNeeded[Lump_Ceilick] = true; CK6_SpawnCeilick(x, y); break; // Bloogguards case 87: if (ck_gameState.difficulty < D_Hard) break; case 86: if (ck_gameState.difficulty < D_Normal) break; case 85: ck6_lumpsNeeded[Lump_Bloogguard] = true; CK6_SpawnBloogguard(x, y); break; // Grabbiter case 88: CK6_SpawnGrabbiter(x, y); break; // Satellite case 89: CK6_SpawnSatellite(x, y); break; // Story Items case 99: ck6_lumpsNeeded[Lump_Rope] = true; CK6_SpawnRope(x, y); break; case 100: ck6_lumpsNeeded[Lump_Sandwich] = true; CK6_SpawnSandwich(x, y); break; case 101: ck6_lumpsNeeded[Lump_Passcard] = true; CK6_SpawnPasscard(x, y); break; // Babobbas case 104: if (ck_gameState.difficulty < D_Hard) break; case 103: if (ck_gameState.difficulty < D_Normal) break; case 102: ck6_lumpsNeeded[Lump_Babobba] = true; CK6_SpawnBabobba(x, y); break; case 105: CK6_SpawnRocket(x, y, infoValue - 105); break; } } } for (CK_object *obj = ck_keenObj; obj != NULL; obj = obj->next) { if (obj->active != OBJ_ALWAYS_ACTIVE) obj->active = OBJ_INACTIVE; } // TODO: Some more stuff (including opening elevator after breaking fuses) if (ck_gameState.currentLevel == 0) { //int keenYTilePos = RF_UnitToTile(ck_keenObj->posY); } for (int i = 0; i < MAXLUMPS; i++) if (ck6_lumpsNeeded[i]) for (int j = ck6_lumpStarts[i]; j <= ck6_lumpEnds[i]; j++) CA_CacheGrChunk(j); }
void CK6_ToggleBigSwitch(CK_object *obj, bool dir) { // Replace switch tiles int ty = dir ? obj->clipRects.tileY2 : obj->clipRects.tileY1 - 2; int tx = obj->clipRects.tileX1 - 1; uint16_t *infoTile = CA_TilePtrAtPos(tx + 1, ty + 1, 2); while (!*infoTile) { tx++; infoTile++; } uint16_t *fgTile = CA_TilePtrAtPos(tx, ty, 1); uint16_t tile_array[6]; for (int y = 0; y < 3; y++) { for (int x = 0; x < 2; x++) { tile_array[2 * y + x] = *fgTile + TI_ForeAnimTile(*fgTile); fgTile++; } fgTile += CA_GetMapWidth() - 2; } RF_ReplaceTiles(tile_array, 1, tx, ty, 2, 3); // Apply the switch effect infoTile = CA_TilePtrAtPos(tx + 1, ty + 1, 2); int destX = *infoTile >> 8; int destY = *infoTile & 0xFF; SD_PlaySound(SOUND_KEENOUTOFAMMO); infoTile = CA_TilePtrAtPos(destX, destY, 2); if (*infoTile >= 0x5B && *infoTile < 0x5B + 8) { // Toggle a goplat arrow static uint16_t infoPlaneInverses[8] = {2, 3, 0, 1, 6, 7, 4, 5}; *infoTile = infoPlaneInverses[(*infoTile - 0x5B)] + 0x5B; } else { fgTile = CA_TilePtrAtPos(destX, destY, 1); int miscValue = TI_ForeMisc(*fgTile) & 0x7F; if (miscValue == MISCFLAG_ACTIVEZAPPER) { uint16_t start = CA_TileAtPos(0, 0, 1); uint16_t mid = CA_TileAtPos(1, 0, 1); uint16_t end = CA_TileAtPos(2, 0, 1); RF_ReplaceTiles(&start, 1, destX, destY, 1, 1); destY++; while (TI_ForeMisc(CA_TileAtPos(destX, destY, 1)) == MISCFLAG_DEADLY) { RF_ReplaceTiles(&mid, 1, destX, destY, 1, 1); destY++; } RF_ReplaceTiles(&end, 1, destX, destY, 1, 1); } else if (miscValue == MISCFLAG_INACTIVEZAPPER) { uint16_t start = CA_TileAtPos(3, 0, 1); uint16_t mid = CA_TileAtPos(4, 0, 1); uint16_t end = CA_TileAtPos(5, 0, 1); RF_ReplaceTiles(&start, 1, destX, destY, 1, 1); destY++; while (TI_ForeMisc(CA_TileAtPos(destX, destY, 1)) != MISCFLAG_INACTIVEZAPPER) { RF_ReplaceTiles(&mid, 1, destX, destY, 1, 1); destY++; } RF_ReplaceTiles(&end, 1, destX, destY, 1, 1); } else if (miscValue == MISCFLAG_BRIDGE) { for (int y = destY; y < destY + 2; ++y) { for (int x = destX - ((y == destY) ? 0 : 1); x < CA_GetMapWidth(); ++x) { uint16_t currentTile = CA_TileAtPos(x, y, 1); if (!TI_ForeAnimTile(currentTile)) break; uint16_t newTile = currentTile + TI_ForeAnimTile(currentTile); RF_ReplaceTiles(&newTile, 1, x, y, 1, 1); } } } else { // Toggle a B block *infoTile ^= 0x1F; } } }