2018-11-19 17:16:01 +01:00
# include "global.h"
# include "event_object_movement.h"
# include "fieldmap.h"
2019-09-09 03:07:54 +02:00
# include "malloc.h"
2019-10-15 11:00:08 +02:00
# include "rotating_tile_puzzle.h"
2018-11-19 17:16:01 +01:00
# include "script_movement.h"
# include "constants/event_object_movement_constants.h"
2018-12-28 19:29:21 +01:00
# include "constants/event_objects.h"
2019-10-15 11:00:08 +02:00
# include "constants/metatile_labels.h"
2018-11-19 17:16:01 +01:00
2019-10-16 10:09:30 +02:00
extern const u8 RotatingTilePuzzle_Movement_ShiftRight [ ] ;
extern const u8 RotatingTilePuzzle_Movement_ShiftDown [ ] ;
extern const u8 RotatingTilePuzzle_Movement_ShiftLeft [ ] ;
extern const u8 RotatingTilePuzzle_Movement_ShiftUp [ ] ;
extern const u8 RotatingTilePuzzle_Movement_FaceRight [ ] ;
extern const u8 RotatingTilePuzzle_Movement_FaceDown [ ] ;
extern const u8 RotatingTilePuzzle_Movement_FaceLeft [ ] ;
extern const u8 RotatingTilePuzzle_Movement_FaceUp [ ] ;
# define ROTATE_COUNTERCLOCKWISE 0
# define ROTATE_CLOCKWISE 1
# define ROTATE_NONE 2
struct RotatingTileObject
2018-11-19 17:16:01 +01:00
{
2019-10-16 10:09:30 +02:00
u8 prevPuzzleTileNum ;
2018-11-19 17:16:01 +01:00
u8 eventTemplateId ;
} ;
2019-10-15 11:00:08 +02:00
struct RotatingTilePuzzle
2018-11-19 17:16:01 +01:00
{
2019-10-16 10:09:30 +02:00
struct RotatingTileObject objects [ EVENT_OBJECTS_COUNT ] ;
u8 numObjects ;
2019-10-15 11:00:08 +02:00
bool8 isTrickHouse ;
2018-11-19 17:16:01 +01:00
} ;
// This file's functions.
2019-10-16 10:09:30 +02:00
static void SaveRotatingTileObject ( u8 eventTemplateId , u8 arg1 ) ;
static void TurnUnsavedRotatingTileObject ( u8 eventTemplateId , u8 arg1 ) ;
2018-11-19 17:16:01 +01:00
// EWRAM vars
2019-10-15 11:00:08 +02:00
EWRAM_DATA static struct RotatingTilePuzzle * sRotatingTilePuzzle = NULL ;
2018-11-19 17:16:01 +01:00
// code
2019-10-15 11:00:08 +02:00
void InitRotatingTilePuzzle ( bool8 isTrickHouse )
2018-11-19 17:16:01 +01:00
{
2019-10-15 11:00:08 +02:00
if ( sRotatingTilePuzzle = = NULL )
sRotatingTilePuzzle = AllocZeroed ( sizeof ( * sRotatingTilePuzzle ) ) ;
2018-11-19 17:16:01 +01:00
2019-10-15 11:00:08 +02:00
sRotatingTilePuzzle - > isTrickHouse = isTrickHouse ;
2018-11-19 17:16:01 +01:00
}
2019-10-16 10:09:30 +02:00
void FreeRotatingTilePuzzle ( void )
2018-11-19 17:16:01 +01:00
{
u8 id ;
2019-10-15 11:00:08 +02:00
if ( sRotatingTilePuzzle ! = NULL )
FREE_AND_SET_NULL ( sRotatingTilePuzzle ) ;
2018-11-19 17:16:01 +01:00
2018-12-28 19:29:21 +01:00
id = GetEventObjectIdByLocalIdAndMap ( EVENT_OBJ_ID_PLAYER , 0 , 0 ) ;
2018-11-19 17:16:01 +01:00
EventObjectClearHeldMovementIfFinished ( & gEventObjects [ id ] ) ;
2019-09-16 06:22:50 +02:00
ScriptMovement_UnfreezeEventObjects ( ) ;
2018-11-19 17:16:01 +01:00
}
2019-10-16 10:09:30 +02:00
u16 MoveRotatingTileObjects ( u8 puzzleNumber )
2018-11-19 17:16:01 +01:00
{
u8 i ;
2019-10-15 11:00:08 +02:00
struct EventObjectTemplate * eventObjects = gSaveBlock1Ptr - > eventObjectTemplates ;
2018-11-19 17:16:01 +01:00
u16 localId = 0 ;
for ( i = 0 ; i < EVENT_OBJECT_TEMPLATES_COUNT ; i + + )
{
2019-10-15 11:00:08 +02:00
s32 puzzleTileStart ;
2019-10-16 10:09:30 +02:00
u8 puzzleTileNum ;
2019-10-15 11:00:08 +02:00
s16 x = eventObjects [ i ] . x + 7 ;
s16 y = eventObjects [ i ] . y + 7 ;
2018-11-19 17:16:01 +01:00
u16 metatile = MapGridGetMetatileIdAt ( x , y ) ;
2019-10-15 11:00:08 +02:00
if ( ! sRotatingTilePuzzle - > isTrickHouse )
2019-10-16 10:09:30 +02:00
puzzleTileStart = METATILE_MossdeepGym_YellowArrow_Right ;
2018-11-19 17:16:01 +01:00
else
2019-10-15 11:00:08 +02:00
puzzleTileStart = METATILE_TrickHousePuzzle_Arrow_YellowOnWhite_Right ;
2018-11-19 17:16:01 +01:00
2019-10-16 10:09:30 +02:00
// Object is on a metatile before the puzzle tile section
// UB: Because this is not if (metatile < puzzleTileStart), for the trick house (metatile - puzzleTileStart) below can result in casting a negative value to u8
if ( metatile < METATILE_MossdeepGym_YellowArrow_Right )
2018-11-19 17:16:01 +01:00
continue ;
2019-10-16 10:09:30 +02:00
// Object is on a metatile after the puzzle tile section (never occurs, in both cases the puzzle tiles are last)
2019-10-15 11:00:08 +02:00
if ( ( u8 ) ( ( metatile - puzzleTileStart ) / 8 ) > = 5 )
2018-11-19 17:16:01 +01:00
continue ;
2019-10-16 10:09:30 +02:00
// Object is on a metatile in puzzle tile section, but not one of the currently rotating color
2019-10-15 11:00:08 +02:00
if ( ( u8 ) ( ( metatile - puzzleTileStart ) / 8 ) ! = puzzleNumber )
2018-11-19 17:16:01 +01:00
continue ;
2019-10-16 10:09:30 +02:00
puzzleTileNum = ( u8 ) ( ( metatile - puzzleTileStart ) % 8 ) ;
// First 4 puzzle tiles are the colored arrows
if ( puzzleTileNum < 4 )
2018-11-19 17:16:01 +01:00
{
s8 x = 0 ;
s8 y = 0 ;
const u8 * movementScript ;
2019-10-16 10:09:30 +02:00
switch ( puzzleTileNum )
2018-11-19 17:16:01 +01:00
{
2019-10-16 10:09:30 +02:00
case 0 : // Right Arrow
movementScript = RotatingTilePuzzle_Movement_ShiftRight ;
2018-11-19 17:16:01 +01:00
x = 1 ;
break ;
2019-10-16 10:09:30 +02:00
case 1 : // Down Arrow
movementScript = RotatingTilePuzzle_Movement_ShiftDown ;
2018-11-19 17:16:01 +01:00
y = 1 ;
break ;
2019-10-16 10:09:30 +02:00
case 2 : // Left Arrow
movementScript = RotatingTilePuzzle_Movement_ShiftLeft ;
2018-11-19 17:16:01 +01:00
x = - 1 ;
break ;
2019-10-16 10:09:30 +02:00
case 3 : // Up Arrow
movementScript = RotatingTilePuzzle_Movement_ShiftUp ;
2018-11-19 17:16:01 +01:00
y = - 1 ;
break ;
default :
continue ;
}
2019-10-15 11:00:08 +02:00
eventObjects [ i ] . x + = x ;
eventObjects [ i ] . y + = y ;
if ( GetEventObjectIdByLocalIdAndMap ( eventObjects [ i ] . localId , gSaveBlock1Ptr - > location . mapNum , gSaveBlock1Ptr - > location . mapGroup ) ! = EVENT_OBJECTS_COUNT )
2018-11-19 17:16:01 +01:00
{
2019-10-16 10:09:30 +02:00
SaveRotatingTileObject ( i , puzzleTileNum ) ;
2019-10-15 11:00:08 +02:00
localId = eventObjects [ i ] . localId ;
2018-11-19 17:16:01 +01:00
ScriptMovement_StartObjectMovementScript ( localId , gSaveBlock1Ptr - > location . mapNum , gSaveBlock1Ptr - > location . mapGroup , movementScript ) ;
}
2019-10-16 10:09:30 +02:00
// Never reached in normal gameplay
2018-11-19 17:16:01 +01:00
else
{
2019-10-16 10:09:30 +02:00
TurnUnsavedRotatingTileObject ( i , puzzleTileNum ) ;
2018-11-19 17:16:01 +01:00
}
}
}
return localId ;
}
2019-10-16 10:09:30 +02:00
void TurnRotatingTileObjects ( void )
2018-11-19 17:16:01 +01:00
{
u8 i ;
2019-10-15 11:00:08 +02:00
s32 puzzleTileStart ;
struct EventObjectTemplate * eventObjects ;
2018-11-19 17:16:01 +01:00
2019-10-15 11:00:08 +02:00
if ( sRotatingTilePuzzle = = NULL )
2018-11-19 17:16:01 +01:00
return ;
2019-10-15 11:00:08 +02:00
if ( ! sRotatingTilePuzzle - > isTrickHouse )
2019-10-16 10:09:30 +02:00
puzzleTileStart = METATILE_MossdeepGym_YellowArrow_Right ;
2018-11-19 17:16:01 +01:00
else
2019-10-15 11:00:08 +02:00
puzzleTileStart = METATILE_TrickHousePuzzle_Arrow_YellowOnWhite_Right ;
2018-11-19 17:16:01 +01:00
2019-10-15 11:00:08 +02:00
eventObjects = gSaveBlock1Ptr - > eventObjectTemplates ;
2019-10-16 10:09:30 +02:00
for ( i = 0 ; i < sRotatingTilePuzzle - > numObjects ; i + + )
2018-11-19 17:16:01 +01:00
{
2019-10-16 10:09:30 +02:00
s32 rotation ;
s8 tileDifference ;
2018-11-19 17:16:01 +01:00
u8 eventObjectId ;
2019-10-15 11:00:08 +02:00
s16 x = eventObjects [ sRotatingTilePuzzle - > objects [ i ] . eventTemplateId ] . x + 7 ;
s16 y = eventObjects [ sRotatingTilePuzzle - > objects [ i ] . eventTemplateId ] . y + 7 ;
2018-11-19 17:16:01 +01:00
u16 metatile = MapGridGetMetatileIdAt ( x , y ) ;
2019-10-16 10:09:30 +02:00
// NOTE: The following 2 assignments and if else could all be replaced with rotation = ROTATE_COUNTERCLOCKWISE
// For an object to be saved in sRotatingTilePuzzle->objects, it must have been on a colored arrow tile
// After the first assignment, tileDifference will always be a number [0-3] representing which arrow tile the object is on now (0: right, 1: down, 2: left, 3: up)
// prevPuzzleTileNum will similarly be a number [0-3] representing the arrow tile the object just moved from
// All the puzzles are oriented counter-clockwise and can only move 1 step at a time, so the difference between the current tile and the previous tile will always either be -1 or 3 (0-1, 1-2, 2-3, 3-0)
// Which means tileDifference will always either be -1 or 3 after the below subtraction, and rotation will always be ROTATE_COUNTERCLOCKWISE after the following conditionals
tileDifference = ( u8 ) ( ( metatile - puzzleTileStart ) % 8 ) ;
tileDifference - = ( sRotatingTilePuzzle - > objects [ i ] . prevPuzzleTileNum ) ;
// Always true, see above
if ( tileDifference < 0 | | tileDifference = = 3 )
2018-11-19 17:16:01 +01:00
{
2019-10-16 10:09:30 +02:00
// Always false, see above
if ( tileDifference = = - 3 )
rotation = ROTATE_CLOCKWISE ;
2018-11-19 17:16:01 +01:00
else
2019-10-16 10:09:30 +02:00
rotation = ROTATE_COUNTERCLOCKWISE ;
2018-11-19 17:16:01 +01:00
}
else
{
2019-10-16 10:09:30 +02:00
if ( tileDifference > 0 )
rotation = ROTATE_CLOCKWISE ;
2018-11-19 17:16:01 +01:00
else
2019-10-16 10:09:30 +02:00
rotation = ROTATE_NONE ;
2018-11-19 17:16:01 +01:00
}
2019-10-15 11:00:08 +02:00
eventObjectId = GetEventObjectIdByLocalIdAndMap ( eventObjects [ sRotatingTilePuzzle - > objects [ i ] . eventTemplateId ] . localId , gSaveBlock1Ptr - > location . mapNum , gSaveBlock1Ptr - > location . mapGroup ) ;
2018-11-19 17:16:01 +01:00
if ( eventObjectId ! = EVENT_OBJECTS_COUNT )
{
const u8 * movementScript ;
u8 direction = gEventObjects [ eventObjectId ] . facingDirection ;
2019-10-16 10:09:30 +02:00
if ( rotation = = ROTATE_COUNTERCLOCKWISE )
2018-11-19 17:16:01 +01:00
{
switch ( direction )
{
case DIR_EAST :
2019-10-16 10:09:30 +02:00
movementScript = RotatingTilePuzzle_Movement_FaceUp ;
2019-10-15 11:00:08 +02:00
eventObjects [ sRotatingTilePuzzle - > objects [ i ] . eventTemplateId ] . movementType = MOVEMENT_TYPE_FACE_UP ;
2018-11-19 17:16:01 +01:00
break ;
case DIR_SOUTH :
2019-10-16 10:09:30 +02:00
movementScript = RotatingTilePuzzle_Movement_FaceRight ;
2019-10-15 11:00:08 +02:00
eventObjects [ sRotatingTilePuzzle - > objects [ i ] . eventTemplateId ] . movementType = MOVEMENT_TYPE_FACE_RIGHT ;
2018-11-19 17:16:01 +01:00
break ;
case DIR_WEST :
2019-10-16 10:09:30 +02:00
movementScript = RotatingTilePuzzle_Movement_FaceDown ;
2019-10-15 11:00:08 +02:00
eventObjects [ sRotatingTilePuzzle - > objects [ i ] . eventTemplateId ] . movementType = MOVEMENT_TYPE_FACE_DOWN ;
2018-11-19 17:16:01 +01:00
break ;
case DIR_NORTH :
2019-10-16 10:09:30 +02:00
movementScript = RotatingTilePuzzle_Movement_FaceLeft ;
2019-10-15 11:00:08 +02:00
eventObjects [ sRotatingTilePuzzle - > objects [ i ] . eventTemplateId ] . movementType = MOVEMENT_TYPE_FACE_LEFT ;
2018-11-19 17:16:01 +01:00
break ;
default :
continue ;
}
2019-10-15 11:00:08 +02:00
ScriptMovement_StartObjectMovementScript ( eventObjects [ sRotatingTilePuzzle - > objects [ i ] . eventTemplateId ] . localId ,
2018-11-19 17:16:01 +01:00
gSaveBlock1Ptr - > location . mapNum ,
gSaveBlock1Ptr - > location . mapGroup ,
movementScript ) ;
}
2019-10-16 10:09:30 +02:00
// Never reached
else if ( rotation = = ROTATE_CLOCKWISE )
2018-11-19 17:16:01 +01:00
{
switch ( direction )
{
case DIR_EAST :
2019-10-16 10:09:30 +02:00
movementScript = RotatingTilePuzzle_Movement_FaceDown ;
2019-10-15 11:00:08 +02:00
eventObjects [ sRotatingTilePuzzle - > objects [ i ] . eventTemplateId ] . movementType = MOVEMENT_TYPE_FACE_DOWN ;
2018-11-19 17:16:01 +01:00
break ;
case DIR_SOUTH :
2019-10-16 10:09:30 +02:00
movementScript = RotatingTilePuzzle_Movement_FaceLeft ;
2019-10-15 11:00:08 +02:00
eventObjects [ sRotatingTilePuzzle - > objects [ i ] . eventTemplateId ] . movementType = MOVEMENT_TYPE_FACE_LEFT ;
2018-11-19 17:16:01 +01:00
break ;
case DIR_WEST :
2019-10-16 10:09:30 +02:00
movementScript = RotatingTilePuzzle_Movement_FaceUp ;
2019-10-15 11:00:08 +02:00
eventObjects [ sRotatingTilePuzzle - > objects [ i ] . eventTemplateId ] . movementType = MOVEMENT_TYPE_FACE_UP ;
2018-11-19 17:16:01 +01:00
break ;
case DIR_NORTH :
2019-10-16 10:09:30 +02:00
movementScript = RotatingTilePuzzle_Movement_FaceRight ;
2019-10-15 11:00:08 +02:00
eventObjects [ sRotatingTilePuzzle - > objects [ i ] . eventTemplateId ] . movementType = MOVEMENT_TYPE_FACE_RIGHT ;
2018-11-19 17:16:01 +01:00
break ;
default :
continue ;
}
2019-10-15 11:00:08 +02:00
ScriptMovement_StartObjectMovementScript ( eventObjects [ sRotatingTilePuzzle - > objects [ i ] . eventTemplateId ] . localId ,
2018-11-19 17:16:01 +01:00
gSaveBlock1Ptr - > location . mapNum ,
gSaveBlock1Ptr - > location . mapGroup ,
movementScript ) ;
}
}
}
}
2019-10-16 10:09:30 +02:00
static void SaveRotatingTileObject ( u8 eventTemplateId , u8 puzzleTileNum )
2018-11-19 17:16:01 +01:00
{
2019-10-16 10:09:30 +02:00
sRotatingTilePuzzle - > objects [ sRotatingTilePuzzle - > numObjects ] . eventTemplateId = eventTemplateId ;
sRotatingTilePuzzle - > objects [ sRotatingTilePuzzle - > numObjects ] . prevPuzzleTileNum = puzzleTileNum ;
sRotatingTilePuzzle - > numObjects + + ;
2018-11-19 17:16:01 +01:00
}
2019-10-16 10:09:30 +02:00
// Functionally unused
static void TurnUnsavedRotatingTileObject ( u8 eventTemplateId , u8 puzzleTileNum )
2018-11-19 17:16:01 +01:00
{
2019-10-16 10:09:30 +02:00
s8 tileDifference ;
s32 rotation ;
2019-10-15 11:00:08 +02:00
s32 puzzleTileStart ;
2018-11-19 17:16:01 +01:00
u16 movementType ;
2019-10-15 11:00:08 +02:00
struct EventObjectTemplate * eventObjects = gSaveBlock1Ptr - > eventObjectTemplates ;
s16 x = eventObjects [ eventTemplateId ] . x + 7 ;
s16 y = eventObjects [ eventTemplateId ] . y + 7 ;
2018-11-19 17:16:01 +01:00
u16 metatile = MapGridGetMetatileIdAt ( x , y ) ;
2019-10-15 11:00:08 +02:00
if ( ! sRotatingTilePuzzle - > isTrickHouse )
2019-10-16 10:09:30 +02:00
puzzleTileStart = METATILE_MossdeepGym_YellowArrow_Right ;
2018-11-19 17:16:01 +01:00
else
2019-10-15 11:00:08 +02:00
puzzleTileStart = METATILE_TrickHousePuzzle_Arrow_YellowOnWhite_Right ;
2018-11-19 17:16:01 +01:00
2019-10-16 10:09:30 +02:00
tileDifference = ( u8 ) ( ( metatile - puzzleTileStart ) % 8 ) ;
tileDifference - = puzzleTileNum ;
if ( tileDifference < 0 | | tileDifference = = 3 )
rotation = ROTATE_COUNTERCLOCKWISE ;
else if ( tileDifference > 0 | | tileDifference = = - 3 )
rotation = ROTATE_CLOCKWISE ;
2018-11-19 17:16:01 +01:00
else
2019-10-16 10:09:30 +02:00
rotation = ROTATE_NONE ;
2018-11-19 17:16:01 +01:00
2019-10-15 11:00:08 +02:00
movementType = eventObjects [ eventTemplateId ] . movementType ;
2019-10-16 10:09:30 +02:00
if ( rotation = = ROTATE_COUNTERCLOCKWISE )
2018-11-19 17:16:01 +01:00
{
switch ( movementType )
{
case MOVEMENT_TYPE_FACE_RIGHT :
2019-10-15 11:00:08 +02:00
eventObjects [ eventTemplateId ] . movementType = MOVEMENT_TYPE_FACE_UP ;
2018-11-19 17:16:01 +01:00
break ;
case MOVEMENT_TYPE_FACE_DOWN :
2019-10-15 11:00:08 +02:00
eventObjects [ eventTemplateId ] . movementType = MOVEMENT_TYPE_FACE_RIGHT ;
2018-11-19 17:16:01 +01:00
break ;
case MOVEMENT_TYPE_FACE_LEFT :
2019-10-15 11:00:08 +02:00
eventObjects [ eventTemplateId ] . movementType = MOVEMENT_TYPE_FACE_DOWN ;
2018-11-19 17:16:01 +01:00
break ;
case MOVEMENT_TYPE_FACE_UP :
2019-10-15 11:00:08 +02:00
eventObjects [ eventTemplateId ] . movementType = MOVEMENT_TYPE_FACE_LEFT ;
2018-11-19 17:16:01 +01:00
break ;
default :
break ;
}
}
2019-10-16 10:09:30 +02:00
else if ( rotation = = ROTATE_CLOCKWISE )
2018-11-19 17:16:01 +01:00
{
switch ( movementType )
{
case MOVEMENT_TYPE_FACE_RIGHT :
2019-10-15 11:00:08 +02:00
eventObjects [ eventTemplateId ] . movementType = MOVEMENT_TYPE_FACE_DOWN ;
2018-11-19 17:16:01 +01:00
break ;
case MOVEMENT_TYPE_FACE_DOWN :
2019-10-15 11:00:08 +02:00
eventObjects [ eventTemplateId ] . movementType = MOVEMENT_TYPE_FACE_LEFT ;
2018-11-19 17:16:01 +01:00
break ;
case MOVEMENT_TYPE_FACE_LEFT :
2019-10-15 11:00:08 +02:00
eventObjects [ eventTemplateId ] . movementType = MOVEMENT_TYPE_FACE_UP ;
2018-11-19 17:16:01 +01:00
break ;
case MOVEMENT_TYPE_FACE_UP :
2019-10-15 11:00:08 +02:00
eventObjects [ eventTemplateId ] . movementType = MOVEMENT_TYPE_FACE_RIGHT ;
2018-11-19 17:16:01 +01:00
break ;
default :
break ;
}
}
}