#include "scroll.h" #include "asm.h" #include "beanstalkSubtask.h" #include "collision.h" #include "common.h" #include "effects.h" #include "entity.h" #include "game.h" #include "kinstone.h" #include "manager/diggingCaveEntranceManager.h" #include "map.h" #include "object.h" #include "sound.h" #include "room.h" #include "physics.h" #include "player.h" #include "screen.h" #include "tileMap.h" #include "tiles.h" extern void UpdateScreenShake(void); extern void sub_0807C8B0(u16*, u32, u32); extern void sub_0807C810(); extern void DeleteSleepingEntities(void); extern void sub_0807BBE4(); extern void CreateCollisionDataBorderAroundRoom(); extern void sub_0805E248(); extern u8 gUpdateVisibleTiles; extern u16 gUnk_0200B640; extern MapDataDefinition** gCaveBorderMapData[]; extern u16 gUnk_02022830[0xc00]; extern u16 gUnk_020246B0[0xc00]; extern u8 gMapSpecialTileToActTile[]; void Scroll0(RoomControls*); void Scroll1(RoomControls*); void Scroll2(RoomControls*); void Scroll4(RoomControls*); void Scroll5(RoomControls*); void Scroll2Sub0(RoomControls*); void Scroll2Sub1(RoomControls*); void Scroll2Sub2(RoomControls*); void sub_0807FEC8(RoomControls*); void Scroll4Sub0(RoomControls*); void Scroll4Sub1(RoomControls*); void Scroll5Sub0(RoomControls*); void Scroll5Sub1(RoomControls*); void Scroll5Sub2(RoomControls*); void Scroll5Sub3(RoomControls*); void Scroll5Sub4(RoomControls*); void Scroll5Sub5(RoomControls*); u32 sub_080803D0(); u32 sub_08080278(); void sub_08080C80(MapDataDefinition*); void sub_08080368(); void FillActTileForLayer(MapLayer* mapLayer); bool32 IsPosInBorderTransitionRegion(const Transition* transition, u32 param_2, u32 param_3, u32 facing_direction); bool32 IsPosInTransitionRect(const Transition* transition, u32 param_2, u32 param_3, u32 facing_direction); void SetRoomTransitionTypeForAreaWarp(s32); void SetRoomTransitionTypeForBorderWarp(s32); void SetRoomTransitionTypeForArea2Warp(s32); void SetRoomTransitionTypeForBorder2Warp(s32); extern const s8 gShakeOffsets[]; void UpdateScroll(void) { static void (*const gUnk_0811E768[])(RoomControls*) = { Scroll0, Scroll1, Scroll2, NULL, Scroll4, Scroll5, }; gRoomControls.scroll_flags &= 0xfb; gUnk_0811E768[gRoomControls.scrollAction](&gRoomControls); } void Scroll0(RoomControls* controls) { controls->scrollAction = 1; controls->reload_flags = 0; controls->scrollSpeed = 4; Scroll1(controls); UpdateIsDiggingCave(); } // Scroll until target is at the center of the screen. void Scroll1(RoomControls* controls) { s32 uVar2; s32 diff; s32 unused; s32 uVar5; s32 targetValue; if (controls->camera_target != NULL) { // Scroll in x direction. unused = controls->scroll_x; targetValue = controls->camera_target->x.HALF.HI - 0x78; diff = controls->scroll_x - targetValue; if (diff != 0) { uVar5 = controls->scroll_x & 7; if (diff >= 1) { if (controls->origin_x < controls->scroll_x) { if (controls->scrollSpeed <= diff) { diff = controls->scrollSpeed; controls->scroll_flags |= 4; } controls->scroll_x = controls->scroll_x - diff; if (uVar5 - diff < 1) { gUpdateVisibleTiles = 1; } if (controls->origin_x >= controls->scroll_x) { controls->scroll_x = controls->origin_x; } } } else { uVar2 = controls->origin_x + controls->width - 0xf0; if (controls->scroll_x < uVar2) { if (-controls->scrollSpeed >= diff) { diff = -controls->scrollSpeed; controls->scroll_flags |= 4; } controls->scroll_x -= diff; if (uVar5 - diff > 7) { gUpdateVisibleTiles = 1; } if (controls->scroll_x >= uVar2) { controls->scroll_x = uVar2; } } } } // Scroll in y direction. unused = controls->scroll_y; targetValue = controls->camera_target->y.HALF.HI - 0x50; diff = controls->scroll_y - (targetValue); if (diff != 0) { uVar5 = controls->scroll_y & 7; if (diff >= 1) { if (controls->origin_y < controls->scroll_y) { if (controls->scrollSpeed <= diff) { diff = controls->scrollSpeed; controls->scroll_flags |= 4; } controls->scroll_y = controls->scroll_y - diff; if (uVar5 - diff < 1) { gUpdateVisibleTiles = 1; } if (controls->origin_y >= controls->scroll_y) { controls->scroll_y = controls->origin_y; } } } else { uVar2 = controls->origin_y + controls->height - DISPLAY_HEIGHT; if (controls->scroll_y < uVar2) { if (-controls->scrollSpeed >= diff) { diff = -controls->scrollSpeed; controls->scroll_flags |= 4; } controls->scroll_y -= diff; if (uVar5 - diff > 7) { gUpdateVisibleTiles = 1; } if (controls->scroll_y >= uVar2) { controls->scroll_y = uVar2; } } } } } UpdateScreenShake(); } void Scroll2(RoomControls* controls) { static void (*const Scroll2_SubActions[])(RoomControls*) = { Scroll2Sub0, Scroll2Sub1, Scroll2Sub2, }; Scroll2_SubActions[controls->scrollSubAction](controls); } void Scroll2Sub0(RoomControls* controls) { gUpdateVisibleTiles = 1; UpdateScrollVram(); controls->scrollSubAction = 1; gUpdateVisibleTiles = 0; } void Scroll2Sub1(RoomControls* controls) { controls->scrollSubAction = 2; controls->unk_18 = 0; gUpdateVisibleTiles = 2; } void Scroll2Sub2(RoomControls* controls) { Entity* target; gUpdateVisibleTiles = 2; controls->unk_18++; switch (controls->scroll_direction) { case 0: controls->scroll_y -= 4; target = controls->camera_target; if (target == &gPlayerEntity.base) { target->y.WORD = gPlayerEntity.base.y.WORD - Q_16_16(0.375); } if (controls->unk_18 == 0x28) { sub_0807FEC8(controls); } break; case 1: controls->scroll_x = controls->scroll_x + 4; if (controls->camera_target == &gPlayerEntity.base) { gPlayerEntity.base.x.WORD += Q_16_16(0.25); } if (controls->unk_18 == 0x3c) { sub_0807FEC8(controls); } break; case 2: controls->scroll_y = controls->scroll_y + 4; target = controls->camera_target; if (target == &gPlayerEntity.base) { target->y.WORD = gPlayerEntity.base.y.WORD + Q_16_16(0.375); } if (controls->unk_18 == 0x28) { sub_0807FEC8(controls); } break; case 3: controls->scroll_x -= 4; if (controls->camera_target == &gPlayerEntity.base) { gPlayerEntity.base.x.WORD -= Q_16_16(0.25); } if (controls->unk_18 == 0x3c) { sub_0807FEC8(controls); } break; } controls->shake_duration = 0; UpdateScreenShake(); } void sub_0807FEC8(RoomControls* controls) { controls->scrollAction = 0; MemFill32(0xffffffff, gPlayerState.path_memory, sizeof(gPlayerState.path_memory)); gPlayerState.startPosX = controls->camera_target->x.HALF.HI; gPlayerState.startPosY = controls->camera_target->y.HALF.HI; } void Scroll4(RoomControls* controls) { static void (*const Scroll4_SubActions[])(RoomControls*) = { Scroll4Sub0, Scroll4Sub1, }; Scroll4_SubActions[controls->scrollSubAction](controls); } void Scroll4Sub0(RoomControls* controls) { controls->scrollSubAction = 1; controls->unk_18 = 0; gUpdateVisibleTiles = 3; } void Scroll4Sub1(RoomControls* controls) { if ((gRoomTransition.frameCount & 1U) == 0) { gUpdateVisibleTiles = 3; if (++controls->unk_18 > 0x13) { controls->scrollAction = 0; ClearEventPriority(); } } } // Circular screen transition when entering a diggingCaveEntrance. void Scroll5(RoomControls* controls) { static void (*const Scroll5_SubActions[])(RoomControls*) = { Scroll5Sub0, Scroll5Sub1, Scroll5Sub2, Scroll5Sub3, Scroll5Sub4, Scroll5Sub5, }; Scroll5_SubActions[controls->scrollSubAction](controls); } void Scroll5Sub0(RoomControls* controls) { controls->scrollSubAction = 1; gScreen.lcd.displayControl |= DISPCNT_WIN1_ON; gScreen.controls.windowInsideControl = (u8)gScreen.controls.windowInsideControl | 0x1700; gScreen.controls.windowOutsideControl = (gScreen.controls.windowOutsideControl & 0xff00) | 7; gScreen.controls.window1HorizontalDimensions = 0xf0; gScreen.controls.window1VerticalDimensions = 0xf0; ResetActiveItems(); ResetPlayerAnimationAndAction(); if (gDiggingCaveEntranceTransition.isDiggingCave) { gPlayerEntity.base.animationState = 4; } else { gPlayerEntity.base.animationState = 0; } sub_080809D4(); } void Scroll5Sub1(RoomControls* controls) { controls->scrollSubAction = 2; controls->unk_18 = sub_080803D0() + 6; gUnk_0200B640 = sub_08080278(); LoadMapData(gCaveBorderMapData[gDiggingCaveEntranceTransition.entrance->type][0]); sub_0807C8B0(gMapTop.mapData, controls->width >> 4, controls->height >> 4); RenderMapLayerToSubTileMap(gMapDataTopSpecial, &gMapTop); } void Scroll5Sub2(RoomControls* controls) { s32 diffX; s32 diffY; s32 left; s32 right; s32 bottom; s32 top; controls->unk_18 -= 6; controls->unk_1a = (controls->unk_18 * 2) / 3; if (controls->unk_18 > 0x2a) { diffX = controls->camera_target->x.HALF.HI - controls->scroll_x; left = (diffX - controls->unk_18) + 8; if (left < 0) { left = 0; } right = diffX + controls->unk_18 - 8; if (right > DISPLAY_WIDTH) { right = DISPLAY_WIDTH; } diffY = controls->camera_target->y.HALF.HI - controls->scroll_y; bottom = (diffY - controls->unk_1a) + 8; if (bottom < 0) { bottom = 0; } top = diffY + controls->unk_1a - 8; if (top > DISPLAY_HEIGHT) { top = DISPLAY_HEIGHT; } gScreen.controls.window1HorizontalDimensions = ((left & 0xff) << 8) | (right & 0xff); gScreen.controls.window1VerticalDimensions = ((bottom & 0xff) << 8) | (top & 0xff); } if (controls->unk_18 == 0) { controls->scrollSubAction = 3; DeleteSleepingEntities(); sub_0807C810(); sub_08080C80(gCaveBorderMapData[gDiggingCaveEntranceTransition.entrance->type][1]); } else { gUpdateVisibleTiles = 4; } } void Scroll5Sub3(RoomControls* controls) { controls->scrollSubAction = 4; MemCopy(gMapBottom.mapData, gMapBottom.mapDataOriginal, sizeof(gMapBottom.mapData)); MemCopy(gMapTop.mapData, gMapTop.mapDataOriginal, sizeof(gMapTop.mapData)); sub_08080368(); gUnk_02034480.unk_00 = gUnk_0200B640; MemCopy(gUnk_02022830, gUnk_020246B0, 0x1800); FillActTileForLayer(&gMapBottom); FillActTileForLayer(&gMapTop); sub_0807BBE4(); CreateCollisionDataBorderAroundRoom(); sub_0805E248(); RenderMapLayerToSubTileMap(gMapDataBottomSpecial, &gMapBottom); RenderMapLayerToSubTileMap(gMapDataTopSpecial, &gMapTop); } void Scroll5Sub4(RoomControls* controls) { controls->scrollSubAction = 5; controls->unk_1c = 0xff; LoadRoom(); CallRoomProp5And7(); gUpdateVisibleTiles = 0; UpdateIsDiggingCave(); } void Scroll5Sub5(RoomControls* controls) { s32 diffX; s32 diffY; s32 left; s32 right; s32 bottom; s32 top; controls->unk_18 += 6; controls->unk_1a = (controls->unk_18 * 2) / 3; if (controls->unk_18 > 0x1e) { diffX = controls->camera_target->x.HALF.HI - controls->scroll_x; left = (diffX - controls->unk_18); if (left < 0) { left = 0; } right = diffX + controls->unk_18; if (right > DISPLAY_WIDTH) { right = DISPLAY_WIDTH; } diffY = controls->camera_target->y.HALF.HI - controls->scroll_y; bottom = (diffY - controls->unk_1a); if (bottom < 0) { bottom = 0; } top = diffY + controls->unk_1a; if (top > DISPLAY_HEIGHT) { top = DISPLAY_HEIGHT; } gScreen.controls.window1HorizontalDimensions = ((left & 0xff) << 8) | (right & 0xff); gScreen.controls.window1VerticalDimensions = ((bottom & 0xff) << 8) | (top & 0xff); } if (controls->unk_1c == 0) { controls->scrollAction = 0; controls->reload_flags = 0; ClearEventPriority(); gScreen.lcd.displayControl &= ~DISPCNT_WIN1_ON; gScreen.controls.windowInsideControl &= 0xff; gScreen.controls.windowOutsideControl &= 0xff00; } else { gUpdateVisibleTiles = 4; controls->unk_1c = 0; } } u32 sub_08080278(void) { u16* ptr1 = (u16*)gUnk_02022830; u16* mapBottomData = gMapBottom.mapData; u16* mapTopData = gMapTop.mapData; u16* mapBottomDataClone = gMapBottom.mapDataOriginal; u16* mapTopDataClone = gMapTop.mapDataOriginal; u32 width = gRoomControls.width >> 4; u32 height = (gRoomControls.height >> 4) << 6; u32 result; u32 y, x; for (result = 0, y = 0; y < height; y += 0x40) { for (x = 0; x < width; x++) { u32 tilePos = y + x; if (mapBottomDataClone[tilePos] != mapBottomData[tilePos]) { if (mapBottomData[tilePos] < 0x4000) { ptr1[0] = tilePos | 0x4000; ptr1[1] = mapBottomData[tilePos]; ptr1 += 2; result++; if (result >= 0x600) { return result; } } } if (mapTopDataClone[tilePos] != mapTopData[tilePos]) { if (mapTopData[tilePos] < 0x4000) { ptr1[0] = tilePos | 0x8000; ptr1[1] = mapTopData[tilePos]; ptr1 += 2; result++; if (result >= 0x800) { return result; } } } } } return result; } void sub_08080368(void) { u32 tmp; u32 index; u16* ptr; if ((gDiggingCaveEntranceTransition.previousArea != gRoomControls.area) && (gDiggingCaveEntranceTransition.previousArea != 0xff)) { gUnk_02034480.unk_00 = 0; } else { ptr = gUnk_020246B0; tmp = gUnk_02034480.unk_00 << 1; index = 0; while (index < tmp) { SetTileByIndex(ptr[1], ptr[0] & 0xfff, (ptr[0] >> 0xe)); ptr += 2; index += 2; } gUpdateVisibleTiles = 0; } } u32 sub_080803D0(void) { s32 delta_x, delta_y, dd_x, dd_y, pos_x, pos_y, scroll_x, scroll_y; s32 xy49, r4, r7, r8, delta_yy, delta_xx; scroll_x = gRoomControls.scroll_x - gRoomControls.origin_x; pos_x = gRoomControls.camera_target->x.HALF.HI - gRoomControls.origin_x; scroll_y = gRoomControls.scroll_y - gRoomControls.origin_y; pos_y = gRoomControls.camera_target->y.HALF.HI - gRoomControls.origin_y; dd_x = 0x3c; do { r7 = 0; dd_x += 6; delta_xx = dd_x * dd_x; dd_y = dd_x * 2 / 3; delta_yy = dd_y * dd_y; delta_x = dd_x; delta_y = 0; r4 = (-(dd_x * 2) + 1) * delta_yy + delta_xx * 2; xy49 = delta_x * delta_yy / delta_xx; // = x * 4/9 while (delta_y <= xy49) { if (scroll_y + 0xa8 > pos_y + delta_y) { if (scroll_x + 0xf8 > delta_x + pos_x) { r7 |= 1; } if (scroll_x < pos_x - delta_x + 8) { r7 |= 2; } } if (scroll_y < pos_y - delta_y + 8) { if (scroll_x + 0xf8 > delta_x + pos_x) { r7 |= 4; } if (scroll_x < pos_x - delta_x + 8) { r7 |= 8; } } if (r4 > 0) { r4 += ((-(delta_x << 0x2) + 4) * delta_yy) + (delta_xx * (6 + 4 * delta_y)); delta_x--; xy49 = delta_x * delta_yy / delta_xx; } else { r4 += (delta_xx * (6 + 4 * delta_y)); } delta_y++; } delta_x = 0; delta_y = dd_y; r4 = delta_yy * 2 + (delta_y * -2 + 1) * delta_xx; xy49 = delta_y * delta_xx / delta_yy; // y * 9 / 4 while (delta_x <= xy49) { if (scroll_y + 0xa8 > pos_y + delta_y) { if (scroll_x + 0xf8 > pos_x + delta_x) { r7 |= 0x10; } if (scroll_x < pos_x + 8 - delta_x) { r7 |= 0x20; } } if (scroll_y < pos_y - delta_y + 8) { if (scroll_x + 0xf8 > pos_x + delta_x) { r7 |= 0x40; } if (scroll_x < pos_x + 8 - delta_x) { r7 |= 0x80; } } if (r4 > 0) { r4 += delta_yy * (6 + (4 * delta_x)) + (delta_y * -4 + 4) * delta_xx; delta_y--; xy49 = delta_y * delta_xx / delta_yy; } else { r4 += delta_yy * (6 + (4 * delta_x)); } delta_x++; } } while (r7 != 0); return dd_x; } void UpdateIsDiggingCave(void) { switch (gRoomControls.area) { case AREA_LAKE_WOODS_CAVE: case AREA_HYRULE_DIG_CAVES: case AREA_DIG_CAVES: case AREA_CRENEL_DIG_CAVE: case AREA_VEIL_FALLS_DIG_CAVE: case AREA_CASTOR_WILDS_DIG_CAVE: case AREA_HYLIA_DIG_CAVES: gDiggingCaveEntranceTransition.isDiggingCave = 1; return; } gDiggingCaveEntranceTransition.isDiggingCave = 0; } void ClearTileMaps(void) { MemClear(&gRoomControls, sizeof(gRoomControls)); MemClear(&gDiggingCaveEntranceTransition, sizeof(gDiggingCaveEntranceTransition)); gRoomControls.unk_22 = 0xffff; gDiggingCaveEntranceTransition.previousArea = 0xff; gUnk_02034480.unk_00 = 0; MemClear(&gMapDataBottomSpecial, 0x8000); MemClear(&gMapDataTopSpecial, 0x8000); } bool32 DoApplicableTransition(u32 x, u32 y, u32 direction, u32 warp_types) { static bool32 (*const gUnk_0811E7AC[])(const Transition*, u32, u32, u32) = { IsPosInBorderTransitionRegion, IsPosInTransitionRect, IsPosInBorderTransitionRegion, IsPosInTransitionRect, }; const Transition* transition = gArea.pCurrentRoomInfo->exits; while (transition->warp_type != WARP_TYPE_END_OF_LIST) { if (((1 << transition->warp_type) & warp_types) != 0 && gUnk_0811E7AC[transition->warp_type](transition, x, y, direction)) { DoExitTransition(transition); return 1; } transition++; } return 0; } const Transition* FindApplicableAreaTransition(u32 pos_x, u32 pos_y) { const Transition* transition = gArea.pCurrentRoomInfo->exits; u32 warp_types = 0xa; while (transition->warp_type != WARP_TYPE_END_OF_LIST) { if (((1 << transition->warp_type) & warp_types) != 0 && IsPosInTransitionRect(transition, pos_x, pos_y, 0)) { return transition; } transition++; } return NULL; } bool32 IsPosInBorderTransitionRegion(const Transition* transition, u32 pos_x, u32 pos_y, u32 facing_direction) { u32 shapeBitmask; switch (facing_direction) { default: return FALSE; case 0: if (gRoomControls.width / 2 < pos_x) { shapeBitmask = TRANSITION_SHAPE_BORDER_NORTH_EAST; } else { shapeBitmask = TRANSITION_SHAPE_BORDER_NORTH_WEST; } break; case 1: if (gRoomControls.height / 2 < pos_y) { shapeBitmask = TRANSITION_SHAPE_BORDER_EAST_SOUTH; } else { shapeBitmask = TRANSITION_SHAPE_BORDER_EAST_NORTH; } break; case 2: if (gRoomControls.width / 2 < pos_x) { shapeBitmask = TRANSITION_SHAPE_BORDER_SOUTH_EAST; } else { shapeBitmask = TRANSITION_SHAPE_BORDER_SOUTH_WEST; } break; case 3: if (gRoomControls.height / 2 < pos_y) { shapeBitmask = TRANSITION_SHAPE_BORDER_WEST_SOUTH; } else { shapeBitmask = TRANSITION_SHAPE_BORDER_WEST_NORTH; } break; } if ((transition->shape & shapeBitmask) != 0) { return TRUE; } return FALSE; } bool32 IsPosInTransitionRect(const Transition* transition, u32 pos_x, u32 pos_y, u32 facing_direction) { static const u8 gShapeDimensions[] = { 6, 6, 6, 14, 14, 6, 22, 6 }; const u8* shape; u32 shape_x; u32 delta_x; u32 shape_y; u32 delta_y; shape = &gShapeDimensions[transition->shape * 2]; shape_x = shape[0]; delta_x = pos_x - transition->startX; if (delta_x + shape_x <= shape_x * 2) { shape_y = shape[1]; delta_y = pos_y - transition->startY; if (delta_y + shape_y <= shape_y * 2) { return TRUE; } } return FALSE; } void DoExitTransition(const Transition* data) { static void (*const sSetRoomTransitionTypes[])(s32) = { SetRoomTransitionTypeForAreaWarp, SetRoomTransitionTypeForBorderWarp, SetRoomTransitionTypeForArea2Warp, SetRoomTransitionTypeForBorder2Warp, }; PlayerRoomStatus* status; gRoomTransition.transitioningOut = 1; status = &gRoomTransition.player_status; if (data->endX <= 0x3ff) { status->start_pos_x = data->endX; } else { status->start_pos_x = gRoomControls.camera_target->x.HALF.HI | 0x8000; } if (data->endY <= 0x3ff) { status->start_pos_y = data->endY; } else { status->start_pos_y = gRoomControls.camera_target->y.HALF.HI | 0x8000; } status->area_next = data->area; status->room_next = data->room; status->layer = data->layer; status->spawn_type = data->transition_type; status->start_anim = data->facing_direction; if (data->transitionSFX != SFX_NONE) { SoundReq(data->transitionSFX); } sSetRoomTransitionTypes[data->warp_type](data->shape); } void SetRoomTransitionTypeForAreaWarp(s32 param_1) { gRoomTransition.type = TRANSITION_DEFAULT; } void SetRoomTransitionTypeForBorderWarp(s32 param_1) { if (CheckAreaOverworld(gRoomTransition.player_status.area_next)) { gRoomTransition.type = TRANSITION_DEFAULT; } else { gRoomTransition.type = TRANSITION_FADE_BLACK; } } void SetRoomTransitionTypeForArea2Warp(s32 param_1) { gRoomTransition.type = TRANSITION_CUT; } void SetRoomTransitionTypeForBorder2Warp(s32 param_1) { gRoomTransition.type = TRANSITION_CUT; } void DoExitTransitionWithType(const Transition* screenTransition, u32 transitionType) { DoExitTransition(screenTransition); gRoomTransition.type = transitionType; } void sub_08080930(u32 unused) { gRoomControls.scrollAction = 5; gRoomControls.scrollSubAction = 0; gRoomControls.reload_flags = 2; gRoomControls.scroll_direction = 0; SetInitializationPriority(); } MapLayer* GetLayerByIndex(u32 layerIndex) { if (layerIndex == LAYER_TOP) { return &gMapTop; } else { return &gMapBottom; } } void InitScreenShake(u32 time, u32 magnitude) { gRoomControls.shake_duration = time; gRoomControls.shake_magnitude = magnitude & 7; } void sub_08080974(u32 arg0, u32 arg1) { u32 var0, var1; RoomControls* roomControls = &gRoomControls; var0 = roomControls->origin_x; if (arg0 <= var0 + 120) { roomControls->scroll_x = var0; } else { var0 += roomControls->width; var1 = var0 - 120; if (arg0 < var1) { var1 = arg0; } roomControls->scroll_x = var1 - 120; } var0 = roomControls->origin_y; if (arg1 <= var0 + 80) { roomControls->scroll_y = var0; } else { var0 += roomControls->height; var1 = var0 - 80; if (arg1 < var1) { var1 = arg1; } roomControls->scroll_y = var1 - 80; } sub_080809D4(); gUpdateVisibleTiles = 1; } void sub_080809D4(void) { s32 x, y; s32 var1, var0; RoomControls* roomControls = &gRoomControls; roomControls->scroll_flags &= ~4; x = roomControls->camera_target->x.HALF.HI; var0 = roomControls->origin_x; if (x <= var0 + 120) { roomControls->scroll_x = var0; } else { var0 += roomControls->width; var1 = var0 - 120; if (x < var1) { var1 = (u16)roomControls->camera_target->x.HALF.HI; } roomControls->scroll_x = var1 - 120; } y = roomControls->camera_target->y.HALF.HI; var0 = roomControls->origin_y; if (y <= var0 + 80) { roomControls->scroll_y = var0; } else { var0 += roomControls->height; var1 = var0 - 80; if (y < var1) { var1 = (u16)roomControls->camera_target->y.HALF.HI; } roomControls->scroll_y = var1 - 80; } UpdateScreenShake(); gUpdateVisibleTiles = 1; } void UpdateDoorTransition() { u32 actTile; u32 x; u32 y; RoomControls* controls = &gRoomControls; if (gRoomControls.camera_target != &gPlayerEntity.base) { return; } if (gPlayerState.jump_status != 0) { return; } switch (gRoomControls.camera_target->action) { case 0x0f: if (gRoomControls.area == 0x48) { return; } case 1: case 9: case 0x18: case 0x1d: y = controls->camera_target->y.HALF.HI - controls->origin_y; x = controls->camera_target->x.HALF.HI - controls->origin_x; actTile = GetActTileAtTilePos( (((controls->camera_target->x.HALF.HI - controls->origin_x) >> 4) & 0x3F) | ((((controls->camera_target->y.HALF.HI - controls->origin_y) >> 4) & 0x3F) << 6), controls->camera_target->collisionLayer); gRoomTransition.stairs_idx = GetTileTypeAtRoomCoords(x, y, controls->camera_target->collisionLayer); switch (actTile) { case ACT_TILE_63: case ACT_TILE_241: case ACT_TILE_40: case ACT_TILE_41: DoApplicableTransition(x, y, 0xff, 10); break; } } } // fill the actTile for the whole layer void FillActTileForLayer(MapLayer* mapLayer) { u32 tilePos; u16* tileTypes = mapLayer->tileTypes; const u8* ptr = gMapTileTypeToActTile; u8* actTiles = mapLayer->actTiles; u16* mapData = mapLayer->mapData; for (tilePos = 0; tilePos < 0x40 * 0x40; tilePos++) { u16 tileIndex = mapData[tilePos]; if (tileIndex < 0x4000) { mapLayer->actTiles[tilePos] = ptr[tileTypes[tileIndex]]; } else { mapLayer->actTiles[tilePos] = gMapSpecialTileToActTile[tileIndex - 0x4000]; } } } void UpdateScreenShake(void) { const s8* screenShakeOffset; s32 roomOffsetX = (gRoomControls.scroll_x - gRoomControls.origin_x) & 0xf; s32 roomOffsetY = ((gRoomControls.scroll_y - gRoomControls.origin_y) & 0xf) + 8; if (gRoomControls.shake_duration != 0) { gRoomControls.shake_duration--; screenShakeOffset = &gShakeOffsets[gRoomControls.shake_magnitude * 0x10 + (gRoomControls.shake_duration & 0xe)]; if (gMapBottom.bgSettings != NULL) { gMapBottom.bgSettings->xOffset = screenShakeOffset[0] + roomOffsetX; gMapBottom.bgSettings->yOffset = screenShakeOffset[1] + roomOffsetY; } if (gMapTop.bgSettings != NULL) { gMapTop.bgSettings->xOffset = screenShakeOffset[0] + roomOffsetX; gMapTop.bgSettings->yOffset = screenShakeOffset[1] + roomOffsetY; } gRoomControls.aff_x = screenShakeOffset[0]; gRoomControls.aff_y = screenShakeOffset[1]; } else { if (gMapBottom.bgSettings != NULL) { gMapBottom.bgSettings->xOffset = roomOffsetX; gMapBottom.bgSettings->yOffset = roomOffsetY; } if (gMapTop.bgSettings != NULL) { gMapTop.bgSettings->xOffset = roomOffsetX; gMapTop.bgSettings->yOffset = roomOffsetY; } gRoomControls.aff_x = 0; gRoomControls.aff_y = 0; } } void sub_08080C80(MapDataDefinition* dataDefinition) { LoadMapData(dataDefinition); sub_0807C8B0(gMapBottom.mapData, gRoomControls.width / 16, gRoomControls.height / 16); sub_0807C8B0(gMapTop.mapData, gRoomControls.width / 16, gRoomControls.height / 16); } void sub_08080CB4(Entity* this) { Entity* effect; u32 tmp; u32 tmp2; u32 tmp3; u32 mask; if (this->type != this->animIndex) { InitAnimationForceUpdate(this, this->type); if (this->type == 0x5c) { const KinstoneWorldEvent* ptr = &gKinstoneWorldEvents[this->type2]; tmp = ptr->objPalette; tmp2 = tmp & 0xf; this->palette.raw = (tmp << 4) | tmp2; } } else { UpdateAnimationSingleFrame(this); if (this->spriteSettings.draw != 0) { switch (this->type) { case 0x60: if (((GenericEntity*)this)->field_0x6a.HALF.LO != 0) { ((GenericEntity*)this)->field_0x6a.HALF.LO--; } else { ((GenericEntity*)this)->field_0x6a.HALF.LO = (Random() & 0x1f) + 10; effect = CreateFx(this, FX_SPARKLE, 0); if (effect != NULL) { effect->spriteOffsetX = this->spriteOffsetX; effect->spriteOffsetY = this->spriteOffsetY; SortEntityAbove(this, effect); } } break; case 0x40: case 0x41: case 0x42: case 0x43: case 0x5c: case 0x62: if ((gRoomTransition.frameCount & 0xf) == 0) { CreateSparkleFx(this); } break; } } } }