2019-08-25 00:46:40 -04:00
# include <ultra64.h>
2020-06-02 12:44:34 -04:00
# ifdef NO_SEGMENTED_MEMORY
# include <string.h>
# endif
2019-08-25 00:46:40 -04:00
# include "sm64.h"
# include "audio/external.h"
2023-01-24 09:22:49 -05:00
# include "audio/synthesis.h"
2019-11-03 14:36:27 -05:00
# include "buffers/framebuffers.h"
2019-12-01 21:52:53 -05:00
# include "buffers/zbuffer.h"
2019-11-03 14:36:27 -05:00
# include "game/area.h"
2020-04-03 14:57:26 -04:00
# include "game/game_init.h"
2019-08-25 00:46:40 -04:00
# include "game/mario.h"
# include "game/memory.h"
# include "game/object_helpers.h"
# include "game/object_list_processor.h"
# include "game/save_file.h"
# include "game/sound_init.h"
2021-03-28 20:54:54 -04:00
# include "goddard/renderer.h"
2019-11-03 14:36:27 -05:00
# include "geo_layout.h"
# include "graph_node.h"
# include "level_script.h"
2020-06-02 12:44:34 -04:00
# include "level_misc_macros.h"
2021-09-23 17:37:05 -07:00
# include "level_commands.h"
2019-11-03 14:36:27 -05:00
# include "math_util.h"
2019-08-25 00:46:40 -04:00
# include "surface_collision.h"
# include "surface_load.h"
2021-09-07 12:13:40 +01:00
# include "string.h"
2021-08-10 21:53:43 +01:00
# include "game/puppycam2.h"
2021-09-07 12:13:40 +01:00
# include "game/puppyprint.h"
# include "game/puppylights.h"
2023-08-28 18:03:26 -04:00
# include "game/emutest.h"
2019-08-25 00:46:40 -04:00
2021-05-26 14:55:59 +01:00
# include "config.h"
2021-12-30 10:57:51 -06:00
# define NUM_PAINTINGS 45
2019-11-03 14:36:27 -05:00
# define CMD_GET(type, offset) (*(type *) (CMD_PROCESS_OFFSET(offset) + (u8 *) sCurrentCmd))
2019-08-25 00:46:40 -04:00
// These are equal
2019-11-03 14:36:27 -05:00
# define CMD_NEXT ((struct LevelCommand *) ((u8 *) sCurrentCmd + (sCurrentCmd->size << CMD_SIZE_SHIFT)))
# define NEXT_CMD ((struct LevelCommand *) ((sCurrentCmd->size << CMD_SIZE_SHIFT) + (u8 *) sCurrentCmd))
2019-08-25 00:46:40 -04:00
struct LevelCommand {
/*00*/ u8 type ;
/*01*/ u8 size ;
/*02*/ // variable sized argument data
} ;
2021-12-30 10:57:51 -06:00
enum ScriptStatus {
SCRIPT_RUNNING = 1 ,
SCRIPT_PAUSED = 0 ,
SCRIPT_PAUSED2 = - 1
} ;
2019-08-25 00:46:40 -04:00
2021-12-30 10:57:51 -06:00
static uintptr_t sStack [ NUM_TLB_SEGMENTS ] ;
2019-08-25 00:46:40 -04:00
static struct AllocOnlyPool * sLevelPool = NULL ;
static u16 sDelayFrames = 0 ;
static u16 sDelayFrames2 = 0 ;
static s16 sCurrAreaIndex = - 1 ;
2019-10-05 15:08:05 -04:00
static uintptr_t * sStackTop = sStack ;
static uintptr_t * sStackBase = NULL ;
2019-08-25 00:46:40 -04:00
static s16 sScriptStatus ;
static s32 sRegister ;
static struct LevelCommand * sCurrentCmd ;
static s32 eval_script_op ( s8 op , s32 arg ) {
2021-12-30 10:57:51 -06:00
s32 result = FALSE ;
2019-08-25 00:46:40 -04:00
switch ( op ) {
case 0 :
result = sRegister & arg ;
break ;
case 1 :
result = ! ( sRegister & arg ) ;
break ;
case 2 :
result = sRegister = = arg ;
break ;
case 3 :
result = sRegister ! = arg ;
break ;
case 4 :
result = sRegister < arg ;
break ;
case 5 :
result = sRegister < = arg ;
break ;
case 6 :
result = sRegister > arg ;
break ;
case 7 :
result = sRegister > = arg ;
break ;
}
return result ;
}
static void level_cmd_load_and_execute ( void ) {
main_pool_push_state ( ) ;
2021-08-22 13:39:47 +01:00
load_segment ( CMD_GET ( s16 , 2 ) , CMD_GET ( void * , 4 ) , CMD_GET ( void * , 8 ) , MEMORY_POOL_LEFT , CMD_GET ( void * , 16 ) , CMD_GET ( void * , 20 ) ) ;
2019-08-25 00:46:40 -04:00
2019-10-05 15:08:05 -04:00
* sStackTop + + = ( uintptr_t ) NEXT_CMD ;
* sStackTop + + = ( uintptr_t ) sStackBase ;
2019-08-25 00:46:40 -04:00
sStackBase = sStackTop ;
2019-11-03 14:36:27 -05:00
sCurrentCmd = segmented_to_virtual ( CMD_GET ( void * , 12 ) ) ;
2019-08-25 00:46:40 -04:00
}
static void level_cmd_exit_and_execute ( void ) {
2019-11-03 14:36:27 -05:00
void * targetAddr = CMD_GET ( void * , 12 ) ;
2019-08-25 00:46:40 -04:00
main_pool_pop_state ( ) ;
main_pool_push_state ( ) ;
2019-11-03 14:36:27 -05:00
load_segment ( CMD_GET ( s16 , 2 ) , CMD_GET ( void * , 4 ) , CMD_GET ( void * , 8 ) ,
2021-08-22 13:39:47 +01:00
MEMORY_POOL_LEFT , CMD_GET ( void * , 16 ) , CMD_GET ( void * , 20 ) ) ;
2019-08-25 00:46:40 -04:00
sStackTop = sStackBase ;
2019-10-05 15:08:05 -04:00
sCurrentCmd = segmented_to_virtual ( targetAddr ) ;
2019-08-25 00:46:40 -04:00
}
static void level_cmd_exit ( void ) {
main_pool_pop_state ( ) ;
sStackTop = sStackBase ;
2019-10-05 15:08:05 -04:00
sStackBase = ( uintptr_t * ) * ( - - sStackTop ) ;
2019-08-25 00:46:40 -04:00
sCurrentCmd = ( struct LevelCommand * ) * ( - - sStackTop ) ;
}
static void level_cmd_sleep ( void ) {
sScriptStatus = SCRIPT_PAUSED ;
if ( sDelayFrames = = 0 ) {
sDelayFrames = CMD_GET ( s16 , 2 ) ;
} else if ( - - sDelayFrames = = 0 ) {
sCurrentCmd = CMD_NEXT ;
sScriptStatus = SCRIPT_RUNNING ;
}
}
static void level_cmd_sleep2 ( void ) {
sScriptStatus = SCRIPT_PAUSED2 ;
if ( sDelayFrames2 = = 0 ) {
sDelayFrames2 = CMD_GET ( s16 , 2 ) ;
} else if ( - - sDelayFrames2 = = 0 ) {
sCurrentCmd = CMD_NEXT ;
sScriptStatus = SCRIPT_RUNNING ;
}
}
static void level_cmd_jump ( void ) {
2019-10-05 15:08:05 -04:00
sCurrentCmd = segmented_to_virtual ( CMD_GET ( void * , 4 ) ) ;
2019-08-25 00:46:40 -04:00
}
static void level_cmd_jump_and_link ( void ) {
2019-10-05 15:08:05 -04:00
* sStackTop + + = ( uintptr_t ) NEXT_CMD ;
sCurrentCmd = segmented_to_virtual ( CMD_GET ( void * , 4 ) ) ;
2019-08-25 00:46:40 -04:00
}
static void level_cmd_return ( void ) {
sCurrentCmd = ( struct LevelCommand * ) * ( - - sStackTop ) ;
}
static void level_cmd_jump_and_link_push_arg ( void ) {
2019-10-05 15:08:05 -04:00
* sStackTop + + = ( uintptr_t ) NEXT_CMD ;
2019-08-25 00:46:40 -04:00
* sStackTop + + = CMD_GET ( s16 , 2 ) ;
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_jump_repeat ( void ) {
s32 val = * ( sStackTop - 1 ) ;
if ( val = = 0 ) {
sCurrentCmd = ( struct LevelCommand * ) * ( sStackTop - 2 ) ;
} else if ( - - val ! = 0 ) {
* ( sStackTop - 1 ) = val ;
sCurrentCmd = ( struct LevelCommand * ) * ( sStackTop - 2 ) ;
} else {
sCurrentCmd = CMD_NEXT ;
sStackTop - = 2 ;
}
}
static void level_cmd_loop_begin ( void ) {
2019-10-05 15:08:05 -04:00
* sStackTop + + = ( uintptr_t ) NEXT_CMD ;
2019-08-25 00:46:40 -04:00
* sStackTop + + = 0 ;
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_loop_until ( void ) {
2021-12-30 10:57:51 -06:00
if ( eval_script_op ( CMD_GET ( u8 , 2 ) , CMD_GET ( s32 , 4 ) ) ) {
2019-08-25 00:46:40 -04:00
sCurrentCmd = CMD_NEXT ;
sStackTop - = 2 ;
} else {
sCurrentCmd = ( struct LevelCommand * ) * ( sStackTop - 2 ) ;
}
}
static void level_cmd_jump_if ( void ) {
2021-12-30 10:57:51 -06:00
if ( eval_script_op ( CMD_GET ( u8 , 2 ) , CMD_GET ( s32 , 4 ) ) ) {
2019-10-05 15:08:05 -04:00
sCurrentCmd = segmented_to_virtual ( CMD_GET ( void * , 8 ) ) ;
2019-08-25 00:46:40 -04:00
} else {
sCurrentCmd = CMD_NEXT ;
}
}
static void level_cmd_jump_and_link_if ( void ) {
2021-12-30 10:57:51 -06:00
if ( eval_script_op ( CMD_GET ( u8 , 2 ) , CMD_GET ( s32 , 4 ) ) ) {
2019-10-05 15:08:05 -04:00
* sStackTop + + = ( uintptr_t ) NEXT_CMD ;
sCurrentCmd = segmented_to_virtual ( CMD_GET ( void * , 8 ) ) ;
2019-08-25 00:46:40 -04:00
} else {
sCurrentCmd = CMD_NEXT ;
}
}
static void level_cmd_skip_if ( void ) {
2021-12-30 10:57:51 -06:00
if ( ! eval_script_op ( CMD_GET ( u8 , 2 ) , CMD_GET ( s32 , 4 ) ) ) {
2019-08-25 00:46:40 -04:00
do {
sCurrentCmd = CMD_NEXT ;
2021-12-30 10:57:51 -06:00
} while ( sCurrentCmd - > type = = LEVEL_CMD_SKIP | | sCurrentCmd - > type = = LEVEL_CMD_SKIPPABLE_NOP ) ;
2019-08-25 00:46:40 -04:00
}
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_skip ( void ) {
do {
sCurrentCmd = CMD_NEXT ;
2021-12-30 10:57:51 -06:00
} while ( sCurrentCmd - > type = = LEVEL_CMD_SKIPPABLE_NOP ) ;
2019-08-25 00:46:40 -04:00
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_skippable_nop ( void ) {
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_call ( void ) {
2019-11-03 14:36:27 -05:00
typedef s32 ( * Func ) ( s16 , s32 ) ;
Func func = CMD_GET ( Func , 4 ) ;
2019-08-25 00:46:40 -04:00
sRegister = func ( CMD_GET ( s16 , 2 ) , sRegister ) ;
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_call_loop ( void ) {
2019-11-03 14:36:27 -05:00
typedef s32 ( * Func ) ( s16 , s32 ) ;
Func func = CMD_GET ( Func , 4 ) ;
2019-08-25 00:46:40 -04:00
sRegister = func ( CMD_GET ( s16 , 2 ) , sRegister ) ;
if ( sRegister = = 0 ) {
sScriptStatus = SCRIPT_PAUSED ;
} else {
sScriptStatus = SCRIPT_RUNNING ;
sCurrentCmd = CMD_NEXT ;
}
}
static void level_cmd_set_register ( void ) {
sRegister = CMD_GET ( s16 , 2 ) ;
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_push_pool_state ( void ) {
main_pool_push_state ( ) ;
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_pop_pool_state ( void ) {
main_pool_pop_state ( ) ;
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_load_to_fixed_address ( void ) {
2019-11-03 14:36:27 -05:00
load_to_fixed_pool_addr ( CMD_GET ( void * , 4 ) , CMD_GET ( void * , 8 ) , CMD_GET ( void * , 12 ) ) ;
2019-08-25 00:46:40 -04:00
sCurrentCmd = CMD_NEXT ;
}
2019-10-05 15:08:05 -04:00
static void level_cmd_load_raw ( void ) {
2019-11-03 14:36:27 -05:00
load_segment ( CMD_GET ( s16 , 2 ) , CMD_GET ( void * , 4 ) , CMD_GET ( void * , 8 ) ,
2021-08-22 13:39:47 +01:00
MEMORY_POOL_LEFT , CMD_GET ( void * , 12 ) , CMD_GET ( void * , 16 ) ) ;
2019-08-25 00:46:40 -04:00
sCurrentCmd = CMD_NEXT ;
}
2020-12-03 20:19:03 -05:00
static void level_cmd_load_yay0 ( void ) {
2019-11-03 14:36:27 -05:00
load_segment_decompress ( CMD_GET ( s16 , 2 ) , CMD_GET ( void * , 4 ) , CMD_GET ( void * , 8 ) ) ;
2019-08-25 00:46:40 -04:00
sCurrentCmd = CMD_NEXT ;
}
2019-10-05 15:08:05 -04:00
static void level_cmd_load_mario_head ( void ) {
2021-05-26 14:55:59 +01:00
# ifdef KEEP_MARIO_HEAD
2021-03-28 20:54:54 -04:00
// TODO: Fix these hardcoded sizes
void * addr = main_pool_alloc ( DOUBLE_SIZE_ON_64_BIT ( 0xE1000 ) , MEMORY_POOL_LEFT ) ;
if ( addr ! = NULL ) {
gdm_init ( addr , DOUBLE_SIZE_ON_64_BIT ( 0xE1000 ) ) ;
gd_add_to_heap ( gZBuffer , sizeof ( gZBuffer ) ) ; // 0x25800
2021-12-30 10:57:51 -06:00
gd_add_to_heap ( gFramebuffer0 , 3 * sizeof ( gFramebuffer0 ) ) ; // 0x70800
2021-03-28 20:54:54 -04:00
gdm_setup ( ) ;
gdm_maketestdl ( CMD_GET ( s16 , 2 ) ) ;
}
# endif
2019-08-25 00:46:40 -04:00
sCurrentCmd = CMD_NEXT ;
}
2020-12-03 20:19:03 -05:00
static void level_cmd_load_yay0_texture ( void ) {
2023-08-29 13:55:21 +01:00
load_segment_decompress ( CMD_GET ( s16 , 2 ) , CMD_GET ( void * , 4 ) , CMD_GET ( void * , 8 ) ) ;
2019-08-25 00:46:40 -04:00
sCurrentCmd = CMD_NEXT ;
}
2021-09-11 10:58:54 -07:00
static void level_cmd_change_area_skybox ( void ) {
2021-09-04 20:27:21 -04:00
u8 areaCheck = CMD_GET ( s16 , 2 ) ;
gAreaSkyboxStart [ areaCheck - 1 ] = CMD_GET ( void * , 4 ) ;
gAreaSkyboxEnd [ areaCheck - 1 ] = CMD_GET ( void * , 8 ) ;
sCurrentCmd = CMD_NEXT ;
}
2019-08-25 00:46:40 -04:00
static void level_cmd_init_level ( void ) {
init_graph_node_start ( NULL , ( struct GraphNodeStart * ) & gObjParentGraphNode ) ;
clear_objects ( ) ;
clear_areas ( ) ;
main_pool_push_state ( ) ;
2021-09-05 11:35:35 -04:00
for ( u8 clearPointers = 0 ; clearPointers < AREA_COUNT ; clearPointers + + ) {
2021-09-05 11:00:11 -04:00
gAreaSkyboxStart [ clearPointers ] = 0 ;
gAreaSkyboxEnd [ clearPointers ] = 0 ;
}
2019-08-25 00:46:40 -04:00
sCurrentCmd = CMD_NEXT ;
}
2021-08-22 13:39:47 +01:00
extern s32 gTlbEntries ;
2021-12-30 10:57:51 -06:00
extern u8 gTlbSegments [ NUM_TLB_SEGMENTS ] ;
2021-08-22 13:39:47 +01:00
2021-12-30 10:57:51 -06:00
// This clears all the temporary bank TLB maps. group0, common1 and behavourdata are always loaded,
// and they're also loaded first, so that means we just leave the first 3 indexes mapped.
void unmap_tlbs ( void ) {
2021-08-23 14:06:27 +01:00
s32 i ;
2021-12-30 10:57:51 -06:00
for ( i = 0 ; i < NUM_TLB_SEGMENTS ; i + + ) {
if ( gTlbSegments [ i ] ) {
if ( i ! = SEGMENT_GROUP0_GEO & & i ! = SEGMENT_COMMON1_GEO & & i ! = SEGMENT_BEHAVIOR_DATA ) {
while ( gTlbSegments [ i ] > 0 ) {
osUnmapTLB ( gTlbEntries ) ;
gTlbSegments [ i ] - - ;
gTlbEntries - - ;
2023-03-12 16:29:08 +00:00
# ifdef PUPPYPRINT_DEBUG
set_segment_memory_printout ( i , 0 ) ;
# endif
2021-12-30 10:57:51 -06:00
}
} else {
gTlbEntries - = gTlbSegments [ i ] ;
gTlbSegments [ i ] = 0 ;
2021-08-23 18:38:43 +01:00
}
2021-08-23 14:06:27 +01:00
}
2021-08-23 12:10:03 +01:00
}
}
2019-08-25 00:46:40 -04:00
static void level_cmd_clear_level ( void ) {
clear_objects ( ) ;
2020-03-01 22:42:52 -05:00
clear_area_graph_nodes ( ) ;
2019-08-25 00:46:40 -04:00
clear_areas ( ) ;
main_pool_pop_state ( ) ;
2022-07-19 23:24:16 +12:00
// the game does a push on level load and a pop on level unload, we need to add another push to store state after the level has been loaded, so one more pop is needed
main_pool_pop_state ( ) ;
2021-08-23 12:10:03 +01:00
unmap_tlbs ( ) ;
2019-08-25 00:46:40 -04:00
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_alloc_level_pool ( void ) {
if ( sLevelPool = = NULL ) {
sLevelPool = alloc_only_pool_init ( main_pool_available ( ) - sizeof ( struct AllocOnlyPool ) ,
MEMORY_POOL_LEFT ) ;
}
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_free_level_pool ( void ) {
s32 i ;
alloc_only_pool_resize ( sLevelPool , sLevelPool - > usedSpace ) ;
sLevelPool = NULL ;
2021-09-08 20:34:24 +01:00
for ( i = 0 ; i < AREA_COUNT ; i + + ) {
2019-08-25 00:46:40 -04:00
if ( gAreaData [ i ] . terrainData ! = NULL ) {
alloc_surface_pools ( ) ;
break ;
}
}
2022-07-19 23:24:16 +12:00
main_pool_push_state ( ) ;
2019-08-25 00:46:40 -04:00
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_begin_area ( void ) {
u8 areaIndex = CMD_GET ( u8 , 2 ) ;
void * geoLayoutAddr = CMD_GET ( void * , 4 ) ;
2021-09-08 20:34:24 +01:00
if ( areaIndex < AREA_COUNT ) {
2019-08-25 00:46:40 -04:00
struct GraphNodeRoot * screenArea =
( struct GraphNodeRoot * ) process_geo_layout ( sLevelPool , geoLayoutAddr ) ;
struct GraphNodeCamera * node = ( struct GraphNodeCamera * ) screenArea - > views [ 0 ] ;
sCurrAreaIndex = areaIndex ;
screenArea - > areaIndex = areaIndex ;
2021-09-20 16:25:58 -07:00
gAreas [ areaIndex ] . graphNode = screenArea ;
2019-08-25 00:46:40 -04:00
2019-09-01 15:50:50 -04:00
if ( node ! = NULL ) {
2020-01-03 10:38:57 -05:00
gAreas [ areaIndex ] . camera = ( struct Camera * ) node - > config . camera ;
2019-09-01 15:50:50 -04:00
} else {
2019-08-25 00:46:40 -04:00
gAreas [ areaIndex ] . camera = NULL ;
2019-09-01 15:50:50 -04:00
}
2019-08-25 00:46:40 -04:00
}
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_end_area ( void ) {
sCurrAreaIndex = - 1 ;
sCurrentCmd = CMD_NEXT ;
}
2019-10-05 15:08:05 -04:00
static void level_cmd_load_model_from_dl ( void ) {
2021-09-27 16:41:43 -07:00
ModelID16 model = CMD_GET ( ModelID16 , 0xA ) ;
2021-05-27 13:43:46 -04:00
s16 layer = CMD_GET ( u16 , 0x8 ) ;
2021-05-26 17:52:15 -04:00
void * dl_ptr = CMD_GET ( void * , 4 ) ;
2019-08-25 00:46:40 -04:00
2021-05-27 01:21:05 -04:00
if ( model < MODEL_ID_COUNT ) {
2021-05-26 17:52:15 -04:00
gLoadedGraphNodes [ model ] =
( struct GraphNode * ) init_graph_node_display_list ( sLevelPool , 0 , layer , dl_ptr ) ;
2019-09-01 15:50:50 -04:00
}
2019-08-25 00:46:40 -04:00
sCurrentCmd = CMD_NEXT ;
}
2019-10-05 15:08:05 -04:00
static void level_cmd_load_model_from_geo ( void ) {
2021-09-27 16:41:43 -07:00
ModelID16 model = CMD_GET ( ModelID16 , 2 ) ;
2021-05-27 00:15:06 -04:00
void * geo = CMD_GET ( void * , 4 ) ;
2019-08-25 00:46:40 -04:00
2021-05-27 01:21:05 -04:00
if ( model < MODEL_ID_COUNT ) {
2021-05-27 00:15:06 -04:00
gLoadedGraphNodes [ model ] = process_geo_layout ( sLevelPool , geo ) ;
2019-09-01 15:50:50 -04:00
}
2019-08-25 00:46:40 -04:00
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_23 ( void ) {
2021-12-30 10:57:51 -06:00
ModelID16 model = ( CMD_GET ( ModelID16 , 2 ) & 0x0FFF ) ;
s16 layer = ( ( ( u16 ) CMD_GET ( s16 , 2 ) ) > > 12 ) ;
void * dl = CMD_GET ( void * , 4 ) ;
s32 scale = CMD_GET ( s32 , 8 ) ;
2019-08-25 00:46:40 -04:00
2021-05-27 01:21:05 -04:00
if ( model < MODEL_ID_COUNT ) {
2019-08-25 00:46:40 -04:00
// GraphNodeScale has a GraphNode at the top. This
// is being stored to the array, so cast the pointer.
gLoadedGraphNodes [ model ] =
2021-12-30 10:57:51 -06:00
( struct GraphNode * ) init_graph_node_scale ( sLevelPool , 0 , layer , dl , scale ) ;
2019-09-01 15:50:50 -04:00
}
2019-08-25 00:46:40 -04:00
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_init_mario ( void ) {
2021-09-28 17:33:18 -07:00
vec3_zero ( gMarioSpawnInfo - > startPos ) ;
vec3_zero ( gMarioSpawnInfo - > startAngle ) ;
2019-08-25 00:46:40 -04:00
gMarioSpawnInfo - > activeAreaIndex = - 1 ;
gMarioSpawnInfo - > areaIndex = 0 ;
gMarioSpawnInfo - > behaviorArg = CMD_GET ( u32 , 4 ) ;
gMarioSpawnInfo - > behaviorScript = CMD_GET ( void * , 8 ) ;
2021-12-30 10:57:51 -06:00
gMarioSpawnInfo - > model = gLoadedGraphNodes [ CMD_GET ( ModelID16 , 0x2 ) ] ; // u8, 3?
2019-08-25 00:46:40 -04:00
gMarioSpawnInfo - > next = NULL ;
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_place_object ( void ) {
2021-12-30 10:57:51 -06:00
if (
sCurrAreaIndex ! = - 1
2022-12-10 15:25:53 -05:00
& & ( CMD_GET ( u8 , 2 ) & ( 1 < < ( gCurrActNum - 1 ) ) )
2021-12-30 10:57:51 -06:00
) {
ModelID16 model = CMD_GET ( u32 , 0x18 ) ;
struct SpawnInfo * spawnInfo = alloc_only_pool_alloc ( sLevelPool , sizeof ( struct SpawnInfo ) ) ;
2019-08-25 00:46:40 -04:00
2021-12-30 10:57:51 -06:00
vec3s_set ( spawnInfo - > startPos , CMD_GET ( s16 , 4 ) ,
CMD_GET ( s16 , 6 ) ,
CMD_GET ( s16 , 8 ) ) ;
2019-08-25 00:46:40 -04:00
2021-12-30 10:57:51 -06:00
vec3s_set ( spawnInfo - > startAngle , DEGREES ( CMD_GET ( s16 , 10 ) ) ,
DEGREES ( CMD_GET ( s16 , 12 ) ) ,
DEGREES ( CMD_GET ( s16 , 14 ) ) ) ;
2019-08-25 00:46:40 -04:00
spawnInfo - > areaIndex = sCurrAreaIndex ;
spawnInfo - > activeAreaIndex = sCurrAreaIndex ;
spawnInfo - > behaviorArg = CMD_GET ( u32 , 16 ) ;
spawnInfo - > behaviorScript = CMD_GET ( void * , 20 ) ;
2021-12-30 10:57:51 -06:00
spawnInfo - > model = gLoadedGraphNodes [ model ] ;
2019-08-25 00:46:40 -04:00
spawnInfo - > next = gAreas [ sCurrAreaIndex ] . objectSpawnInfos ;
gAreas [ sCurrAreaIndex ] . objectSpawnInfos = spawnInfo ;
}
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_create_warp_node ( void ) {
if ( sCurrAreaIndex ! = - 1 ) {
struct ObjectWarpNode * warpNode =
alloc_only_pool_alloc ( sLevelPool , sizeof ( struct ObjectWarpNode ) ) ;
warpNode - > node . id = CMD_GET ( u8 , 2 ) ;
warpNode - > node . destLevel = CMD_GET ( u8 , 3 ) + CMD_GET ( u8 , 6 ) ;
warpNode - > node . destArea = CMD_GET ( u8 , 4 ) ;
warpNode - > node . destNode = CMD_GET ( u8 , 5 ) ;
warpNode - > object = NULL ;
warpNode - > next = gAreas [ sCurrAreaIndex ] . warpNodes ;
gAreas [ sCurrAreaIndex ] . warpNodes = warpNode ;
}
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_create_instant_warp ( void ) {
s32 i ;
struct InstantWarp * warp ;
if ( sCurrAreaIndex ! = - 1 ) {
if ( gAreas [ sCurrAreaIndex ] . instantWarps = = NULL ) {
gAreas [ sCurrAreaIndex ] . instantWarps =
2021-12-30 10:57:51 -06:00
alloc_only_pool_alloc ( sLevelPool , INSTANT_WARP_INDEX_STOP * sizeof ( struct InstantWarp ) ) ;
2019-08-25 00:46:40 -04:00
2019-09-01 15:50:50 -04:00
for ( i = INSTANT_WARP_INDEX_START ; i < INSTANT_WARP_INDEX_STOP ; i + + ) {
2019-08-25 00:46:40 -04:00
gAreas [ sCurrAreaIndex ] . instantWarps [ i ] . id = 0 ;
2019-09-01 15:50:50 -04:00
}
2019-08-25 00:46:40 -04:00
}
warp = gAreas [ sCurrAreaIndex ] . instantWarps + CMD_GET ( u8 , 2 ) ;
2022-09-30 18:41:58 -04:00
warp [ 0 ] . id = SURFACE_INSTANT_WARP_1B + CMD_GET ( u8 , 2 ) ;
2019-08-25 00:46:40 -04:00
warp [ 0 ] . area = CMD_GET ( u8 , 3 ) ;
2022-09-30 18:41:58 -04:00
warp [ 0 ] . displacement [ 0 ] = CMD_GET ( s32 , 4 ) ;
warp [ 0 ] . displacement [ 1 ] = CMD_GET ( s32 , 8 ) ;
warp [ 0 ] . displacement [ 2 ] = CMD_GET ( s32 , 12 ) ;
2019-08-25 00:46:40 -04:00
}
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_set_terrain_type ( void ) {
2019-09-01 15:50:50 -04:00
if ( sCurrAreaIndex ! = - 1 ) {
2019-08-25 00:46:40 -04:00
gAreas [ sCurrAreaIndex ] . terrainType | = CMD_GET ( s16 , 2 ) ;
2019-09-01 15:50:50 -04:00
}
2019-08-25 00:46:40 -04:00
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_create_painting_warp_node ( void ) {
s32 i ;
struct WarpNode * node ;
if ( sCurrAreaIndex ! = - 1 ) {
if ( gAreas [ sCurrAreaIndex ] . paintingWarpNodes = = NULL ) {
gAreas [ sCurrAreaIndex ] . paintingWarpNodes =
2021-12-30 10:57:51 -06:00
alloc_only_pool_alloc ( sLevelPool , NUM_PAINTINGS * sizeof ( struct WarpNode ) ) ;
2019-08-25 00:46:40 -04:00
2021-12-30 10:57:51 -06:00
for ( i = 0 ; i < NUM_PAINTINGS ; i + + ) {
2019-08-25 00:46:40 -04:00
gAreas [ sCurrAreaIndex ] . paintingWarpNodes [ i ] . id = 0 ;
2019-09-01 15:50:50 -04:00
}
2019-08-25 00:46:40 -04:00
}
node = & gAreas [ sCurrAreaIndex ] . paintingWarpNodes [ CMD_GET ( u8 , 2 ) ] ;
node - > id = 1 ;
node - > destLevel = CMD_GET ( u8 , 3 ) + CMD_GET ( u8 , 6 ) ;
node - > destArea = CMD_GET ( u8 , 4 ) ;
node - > destNode = CMD_GET ( u8 , 5 ) ;
}
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_3A ( void ) {
struct UnusedArea28 * val4 ;
if ( sCurrAreaIndex ! = - 1 ) {
2021-12-30 10:57:51 -06:00
if ( ( val4 = gAreas [ sCurrAreaIndex ] . unused ) = = NULL ) {
val4 = gAreas [ sCurrAreaIndex ] . unused =
2019-08-25 00:46:40 -04:00
alloc_only_pool_alloc ( sLevelPool , sizeof ( struct UnusedArea28 ) ) ;
2019-09-01 15:50:50 -04:00
}
2019-08-25 00:46:40 -04:00
val4 - > unk00 = CMD_GET ( s16 , 2 ) ;
val4 - > unk02 = CMD_GET ( s16 , 4 ) ;
val4 - > unk04 = CMD_GET ( s16 , 6 ) ;
val4 - > unk06 = CMD_GET ( s16 , 8 ) ;
val4 - > unk08 = CMD_GET ( s16 , 10 ) ;
}
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_create_whirlpool ( void ) {
struct Whirlpool * whirlpool ;
s32 index = CMD_GET ( u8 , 2 ) ;
2022-12-10 15:25:53 -05:00
if (
sCurrAreaIndex ! = - 1
& & index < ARRAY_COUNT ( gAreas [ sCurrAreaIndex ] . whirlpools )
& & ( CMD_GET ( u8 , 3 ) & ( 1 < < ( gCurrActNum - 1 ) ) )
) {
if ( ( whirlpool = gAreas [ sCurrAreaIndex ] . whirlpools [ index ] ) = = NULL ) {
whirlpool = alloc_only_pool_alloc ( sLevelPool , sizeof ( struct Whirlpool ) ) ;
gAreas [ sCurrAreaIndex ] . whirlpools [ index ] = whirlpool ;
2019-08-25 00:46:40 -04:00
}
2022-12-10 15:25:53 -05:00
vec3s_set ( whirlpool - > pos , CMD_GET ( s16 , 4 ) , CMD_GET ( s16 , 6 ) , CMD_GET ( s16 , 8 ) ) ;
whirlpool - > strength = CMD_GET ( s16 , 10 ) ;
2019-08-25 00:46:40 -04:00
}
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_set_blackout ( void ) {
osViBlack ( CMD_GET ( u8 , 2 ) ) ;
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_set_gamma ( void ) {
osViSetSpecialFeatures ( CMD_GET ( u8 , 2 ) = = 0 ? OS_VI_GAMMA_OFF : OS_VI_GAMMA_ON ) ;
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_set_terrain_data ( void ) {
2019-09-01 15:50:50 -04:00
if ( sCurrAreaIndex ! = - 1 ) {
2020-06-02 12:44:34 -04:00
# ifndef NO_SEGMENTED_MEMORY
2019-08-25 00:46:40 -04:00
gAreas [ sCurrAreaIndex ] . terrainData = segmented_to_virtual ( CMD_GET ( void * , 4 ) ) ;
2020-06-02 12:44:34 -04:00
# else
// The game modifies the terrain data and must be reset upon level reload.
2021-12-30 10:57:51 -06:00
Collision * data = segmented_to_virtual ( CMD_GET ( void * , 4 ) ) ;
u32 size = get_area_terrain_size ( data ) * sizeof ( Collision ) ;
2020-06-02 12:44:34 -04:00
gAreas [ sCurrAreaIndex ] . terrainData = alloc_only_pool_alloc ( sLevelPool , size ) ;
memcpy ( gAreas [ sCurrAreaIndex ] . terrainData , data , size ) ;
# endif
2019-09-01 15:50:50 -04:00
}
2019-08-25 00:46:40 -04:00
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_set_rooms ( void ) {
2019-09-01 15:50:50 -04:00
if ( sCurrAreaIndex ! = - 1 ) {
2019-08-25 00:46:40 -04:00
gAreas [ sCurrAreaIndex ] . surfaceRooms = segmented_to_virtual ( CMD_GET ( void * , 4 ) ) ;
2019-09-01 15:50:50 -04:00
}
2019-08-25 00:46:40 -04:00
sCurrentCmd = CMD_NEXT ;
}
2019-10-05 15:08:05 -04:00
static void level_cmd_set_macro_objects ( void ) {
2019-09-01 15:50:50 -04:00
if ( sCurrAreaIndex ! = - 1 ) {
2020-06-02 12:44:34 -04:00
# ifndef NO_SEGMENTED_MEMORY
2019-08-25 00:46:40 -04:00
gAreas [ sCurrAreaIndex ] . macroObjects = segmented_to_virtual ( CMD_GET ( void * , 4 ) ) ;
2020-06-02 12:44:34 -04:00
# else
// The game modifies the macro object data (for example marking coins as taken),
// so it must be reset when the level reloads.
MacroObject * data = segmented_to_virtual ( CMD_GET ( void * , 4 ) ) ;
s32 len = 0 ;
while ( data [ len + + ] ! = MACRO_OBJECT_END ( ) ) {
len + = 4 ;
}
gAreas [ sCurrAreaIndex ] . macroObjects = alloc_only_pool_alloc ( sLevelPool , len * sizeof ( MacroObject ) ) ;
memcpy ( gAreas [ sCurrAreaIndex ] . macroObjects , data , len * sizeof ( MacroObject ) ) ;
# endif
2019-09-01 15:50:50 -04:00
}
2019-08-25 00:46:40 -04:00
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_load_area ( void ) {
s16 areaIndex = CMD_GET ( u8 , 2 ) ;
2020-12-03 14:26:38 -05:00
stop_sounds_in_continuous_banks ( ) ;
2019-08-25 00:46:40 -04:00
load_area ( areaIndex ) ;
sCurrentCmd = CMD_NEXT ;
}
2020-03-01 22:42:52 -05:00
static void level_cmd_unload_area ( void ) {
unload_area ( ) ;
2019-08-25 00:46:40 -04:00
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_set_mario_start_pos ( void ) {
gMarioSpawnInfo - > areaIndex = CMD_GET ( u8 , 2 ) ;
2019-11-03 14:36:27 -05:00
# if IS_64_BIT
vec3s_set ( gMarioSpawnInfo - > startPos , CMD_GET ( s16 , 6 ) , CMD_GET ( s16 , 8 ) , CMD_GET ( s16 , 10 ) ) ;
# else
2019-08-25 00:46:40 -04:00
vec3s_copy ( gMarioSpawnInfo - > startPos , CMD_GET ( Vec3s , 6 ) ) ;
2019-11-03 14:36:27 -05:00
# endif
2019-08-25 00:46:40 -04:00
vec3s_set ( gMarioSpawnInfo - > startAngle , 0 , CMD_GET ( s16 , 4 ) * 0x8000 / 180 , 0 ) ;
sCurrentCmd = CMD_NEXT ;
}
2021-12-30 10:57:51 -06:00
static void level_cmd_unload_mario_area ( void ) {
2020-03-01 22:42:52 -05:00
unload_mario_area ( ) ;
2019-08-25 00:46:40 -04:00
sCurrentCmd = CMD_NEXT ;
}
2021-12-30 10:57:51 -06:00
static void level_cmd_update_objects ( void ) {
2019-08-25 00:46:40 -04:00
area_update_objects ( ) ;
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_set_transition ( void ) {
2019-09-01 15:50:50 -04:00
if ( gCurrentArea ! = NULL ) {
2019-08-25 00:46:40 -04:00
play_transition ( CMD_GET ( u8 , 2 ) , CMD_GET ( u8 , 3 ) , CMD_GET ( u8 , 4 ) , CMD_GET ( u8 , 5 ) , CMD_GET ( u8 , 6 ) ) ;
2019-09-01 15:50:50 -04:00
}
2019-08-25 00:46:40 -04:00
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_nop ( void ) {
sCurrentCmd = CMD_NEXT ;
}
2019-10-05 15:08:05 -04:00
static void level_cmd_show_dialog ( void ) {
2019-08-25 00:46:40 -04:00
if ( sCurrAreaIndex ! = - 1 ) {
2019-09-01 15:50:50 -04:00
if ( CMD_GET ( u8 , 2 ) < 2 ) {
2019-08-25 00:46:40 -04:00
gAreas [ sCurrAreaIndex ] . dialog [ CMD_GET ( u8 , 2 ) ] = CMD_GET ( u8 , 3 ) ;
2019-09-01 15:50:50 -04:00
}
2019-08-25 00:46:40 -04:00
}
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_set_music ( void ) {
if ( sCurrAreaIndex ! = - 1 ) {
gAreas [ sCurrAreaIndex ] . musicParam = CMD_GET ( s16 , 2 ) ;
2023-01-24 09:22:49 -05:00
# ifdef BETTER_REVERB
2023-08-28 18:03:26 -04:00
if ( gEmulator & EMU_CONSOLE )
2023-01-24 09:22:49 -05:00
gAreas [ sCurrAreaIndex ] . betterReverbPreset = CMD_GET ( u8 , 4 ) ;
else
gAreas [ sCurrAreaIndex ] . betterReverbPreset = CMD_GET ( u8 , 5 ) ;
# endif
gAreas [ sCurrAreaIndex ] . musicParam2 = CMD_GET ( s16 , 6 ) ;
2019-08-25 00:46:40 -04:00
}
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_set_menu_music ( void ) {
2023-01-24 09:22:49 -05:00
# ifdef BETTER_REVERB
// Must come before set_background_music()
2023-08-28 18:03:26 -04:00
if ( gEmulator & EMU_CONSOLE )
2023-06-28 15:15:38 -04:00
gBetterReverbPresetValue = CMD_GET ( u8 , 4 ) ;
2023-01-24 09:22:49 -05:00
else
2023-06-28 15:15:38 -04:00
gBetterReverbPresetValue = CMD_GET ( u8 , 5 ) ;
2023-01-24 09:22:49 -05:00
# endif
2019-08-25 00:46:40 -04:00
set_background_music ( 0 , CMD_GET ( s16 , 2 ) , 0 ) ;
sCurrentCmd = CMD_NEXT ;
}
2021-12-30 10:57:51 -06:00
static void level_cmd_fadeout_music ( void ) {
2023-01-24 09:22:49 -05:00
s16 dur = CMD_GET ( s16 , 2 ) ;
if ( sCurrAreaIndex ! = - 1 & & dur = = 0 ) {
// Allow persistent block overrides for SET_BACKGROUND_MUSIC_WITH_REVERB
gAreas [ sCurrAreaIndex ] . musicParam = 0x00 ;
gAreas [ sCurrAreaIndex ] . musicParam2 = 0x00 ;
# ifdef BETTER_REVERB
gAreas [ sCurrAreaIndex ] . betterReverbPreset = 0x00 ;
# endif
} else {
if ( dur < 0 )
dur = 0 ;
fadeout_music ( dur ) ;
}
2019-08-25 00:46:40 -04:00
sCurrentCmd = CMD_NEXT ;
}
static void level_cmd_get_or_set_var ( void ) {
2021-09-23 17:37:05 -07:00
if ( CMD_GET ( u8 , 2 ) = = OP_SET ) {
2019-08-25 00:46:40 -04:00
switch ( CMD_GET ( u8 , 3 ) ) {
2021-09-23 17:37:05 -07:00
case VAR_CURR_SAVE_FILE_NUM :
2019-08-25 00:46:40 -04:00
gCurrSaveFileNum = sRegister ;
break ;
2021-09-23 17:37:05 -07:00
case VAR_CURR_COURSE_NUM :
2019-08-25 00:46:40 -04:00
gCurrCourseNum = sRegister ;
break ;
2021-09-23 17:37:05 -07:00
case VAR_CURR_ACT_NUM :
2019-08-25 00:46:40 -04:00
gCurrActNum = sRegister ;
break ;
2021-09-23 17:37:05 -07:00
case VAR_CURR_LEVEL_NUM :
2019-08-25 00:46:40 -04:00
gCurrLevelNum = sRegister ;
break ;
2021-09-23 17:37:05 -07:00
case VAR_CURR_AREA_INDEX :
2019-08-25 00:46:40 -04:00
gCurrAreaIndex = sRegister ;
break ;
}
} else {
switch ( CMD_GET ( u8 , 3 ) ) {
2021-09-23 17:37:05 -07:00
case VAR_CURR_SAVE_FILE_NUM :
2019-08-25 00:46:40 -04:00
sRegister = gCurrSaveFileNum ;
break ;
2021-09-23 17:37:05 -07:00
case VAR_CURR_COURSE_NUM :
2019-08-25 00:46:40 -04:00
sRegister = gCurrCourseNum ;
break ;
2021-09-23 17:37:05 -07:00
case VAR_CURR_ACT_NUM :
2019-08-25 00:46:40 -04:00
sRegister = gCurrActNum ;
break ;
2021-09-23 17:37:05 -07:00
case VAR_CURR_LEVEL_NUM :
2019-08-25 00:46:40 -04:00
sRegister = gCurrLevelNum ;
break ;
2021-09-23 17:37:05 -07:00
case VAR_CURR_AREA_INDEX :
2019-08-25 00:46:40 -04:00
sRegister = gCurrAreaIndex ;
break ;
}
}
sCurrentCmd = CMD_NEXT ;
}
2021-12-30 10:57:51 -06:00
static void level_cmd_puppyvolume ( void ) {
2021-09-05 11:14:15 -04:00
# ifdef PUPPYCAM
2021-12-30 10:57:51 -06:00
if ( ( sPuppyVolumeStack [ gPuppyVolumeCount ] = mem_pool_alloc ( gPuppyMemoryPool , sizeof ( struct sPuppyVolume ) ) ) = = NULL ) {
2021-08-10 21:53:43 +01:00
sCurrentCmd = CMD_NEXT ;
gPuppyError | = PUPPY_ERROR_POOL_FULL ;
2021-09-07 12:13:40 +01:00
append_puppyprint_log ( " Puppycamera volume allocation failed. " ) ;
2021-08-10 21:53:43 +01:00
return ;
}
2021-12-30 10:57:51 -06:00
vec3s_set ( sPuppyVolumeStack [ gPuppyVolumeCount ] - > pos , CMD_GET ( s16 , 2 ) ,
CMD_GET ( s16 , 4 ) ,
CMD_GET ( s16 , 6 ) ) ;
2021-08-10 21:53:43 +01:00
2021-12-30 10:57:51 -06:00
vec3s_set ( sPuppyVolumeStack [ gPuppyVolumeCount ] - > radius , CMD_GET ( s16 , 8 ) ,
CMD_GET ( s16 , 10 ) ,
CMD_GET ( s16 , 12 ) ) ;
2021-08-10 21:53:43 +01:00
sPuppyVolumeStack [ gPuppyVolumeCount ] - > rot = CMD_GET ( s16 , 14 ) ;
2021-12-30 10:57:51 -06:00
sPuppyVolumeStack [ gPuppyVolumeCount ] - > func = CMD_GET ( void * , 16 ) ;
2021-08-10 21:53:43 +01:00
sPuppyVolumeStack [ gPuppyVolumeCount ] - > angles = segmented_to_virtual ( CMD_GET ( void * , 20 ) ) ;
2021-12-30 10:57:51 -06:00
sPuppyVolumeStack [ gPuppyVolumeCount ] - > flagsAdd = CMD_GET ( s32 , 24 ) ;
2021-08-10 21:53:43 +01:00
sPuppyVolumeStack [ gPuppyVolumeCount ] - > flagsRemove = CMD_GET ( s32 , 28 ) ;
sPuppyVolumeStack [ gPuppyVolumeCount ] - > flagPersistance = CMD_GET ( u8 , 32 ) ;
2021-12-30 10:57:51 -06:00
sPuppyVolumeStack [ gPuppyVolumeCount ] - > shape = CMD_GET ( u8 , 33 ) ;
sPuppyVolumeStack [ gPuppyVolumeCount ] - > room = CMD_GET ( s16 , 34 ) ;
sPuppyVolumeStack [ gPuppyVolumeCount ] - > fov = CMD_GET ( u8 , 36 ) ;
sPuppyVolumeStack [ gPuppyVolumeCount ] - > area = sCurrAreaIndex ;
2021-08-10 21:53:43 +01:00
gPuppyVolumeCount + + ;
2021-09-05 11:14:15 -04:00
# endif
2021-08-10 21:53:43 +01:00
sCurrentCmd = CMD_NEXT ;
}
2021-09-05 11:14:15 -04:00
2021-12-30 10:57:51 -06:00
static void level_cmd_puppylight_environment ( void ) {
2021-09-07 12:13:40 +01:00
# ifdef PUPPYLIGHTS
2021-12-30 10:57:51 -06:00
Lights1 temp = gdSPDefLights1 ( CMD_GET ( u8 , 2 ) , CMD_GET ( u8 , 3 ) , CMD_GET ( u8 , 4 ) ,
CMD_GET ( u8 , 5 ) , CMD_GET ( u8 , 6 ) , CMD_GET ( u8 , 7 ) ,
CMD_GET ( u8 , 8 ) , CMD_GET ( u8 , 9 ) , CMD_GET ( u8 , 10 ) ) ;
2021-09-07 12:13:40 +01:00
memcpy ( & gLevelLight , & temp , sizeof ( Lights1 ) ) ;
levelAmbient = TRUE ;
# endif
sCurrentCmd = CMD_NEXT ;
}
2021-12-30 10:57:51 -06:00
static void level_cmd_puppylight_node ( void ) {
2021-09-07 12:13:40 +01:00
# ifdef PUPPYLIGHTS
2021-12-30 10:57:51 -06:00
gPuppyLights [ gNumLights ] = mem_pool_alloc ( gLightsPool , sizeof ( struct PuppyLight ) ) ;
if ( gPuppyLights [ gNumLights ] = = NULL ) {
2021-09-07 12:13:40 +01:00
append_puppyprint_log ( " Puppylight allocation failed. " ) ;
sCurrentCmd = CMD_NEXT ;
return ;
}
2021-12-30 10:57:51 -06:00
vec4_set ( gPuppyLights [ gNumLights ] - > rgba , CMD_GET ( u8 , 2 ) ,
CMD_GET ( u8 , 3 ) ,
CMD_GET ( u8 , 4 ) ,
CMD_GET ( u8 , 5 ) ) ;
2021-09-07 12:13:40 +01:00
2021-12-30 10:57:51 -06:00
vec3s_set ( gPuppyLights [ gNumLights ] - > pos [ 0 ] , CMD_GET ( s16 , 6 ) ,
CMD_GET ( s16 , 8 ) ,
CMD_GET ( s16 , 10 ) ) ;
2021-09-07 12:13:40 +01:00
2021-12-30 10:57:51 -06:00
vec3s_set ( gPuppyLights [ gNumLights ] - > pos [ 1 ] , CMD_GET ( s16 , 12 ) ,
CMD_GET ( s16 , 14 ) ,
CMD_GET ( s16 , 16 ) ) ;
gPuppyLights [ gNumLights ] - > yaw = CMD_GET ( s16 , 18 ) ;
gPuppyLights [ gNumLights ] - > epicentre = CMD_GET ( u8 , 20 ) ;
gPuppyLights [ gNumLights ] - > flags = CMD_GET ( u8 , 21 ) ;
gPuppyLights [ gNumLights ] - > active = TRUE ;
gPuppyLights [ gNumLights ] - > area = sCurrAreaIndex ;
gPuppyLights [ gNumLights ] - > room = CMD_GET ( s16 , 22 ) ;
2021-09-07 12:13:40 +01:00
gNumLights + + ;
# endif
sCurrentCmd = CMD_NEXT ;
}
2021-08-10 21:53:43 +01:00
2023-06-28 15:15:38 -04:00
static void level_cmd_set_echo ( void ) {
if ( sCurrAreaIndex > = 0 & & sCurrAreaIndex < AREA_COUNT ) {
gAreaData [ sCurrAreaIndex ] . useEchoOverride = TRUE ;
2023-08-28 18:03:26 -04:00
if ( gEmulator & EMU_CONSOLE )
2023-06-28 15:15:38 -04:00
gAreaData [ sCurrAreaIndex ] . echoOverride = CMD_GET ( s8 , 2 ) ;
else
gAreaData [ sCurrAreaIndex ] . echoOverride = CMD_GET ( s8 , 3 ) ;
}
sCurrentCmd = CMD_NEXT ;
}
2019-08-25 00:46:40 -04:00
static void ( * LevelScriptJumpTable [ ] ) ( void ) = {
2021-12-30 10:57:51 -06:00
/*LEVEL_CMD_LOAD_AND_EXECUTE */ level_cmd_load_and_execute ,
/*LEVEL_CMD_EXIT_AND_EXECUTE */ level_cmd_exit_and_execute ,
/*LEVEL_CMD_EXIT */ level_cmd_exit ,
/*LEVEL_CMD_SLEEP */ level_cmd_sleep ,
/*LEVEL_CMD_SLEEP2 */ level_cmd_sleep2 ,
/*LEVEL_CMD_JUMP */ level_cmd_jump ,
/*LEVEL_CMD_JUMP_AND_LINK */ level_cmd_jump_and_link ,
/*LEVEL_CMD_RETURN */ level_cmd_return ,
/*LEVEL_CMD_JUMP_AND_LINK_PUSH_ARG */ level_cmd_jump_and_link_push_arg ,
/*LEVEL_CMD_JUMP_REPEAT */ level_cmd_jump_repeat ,
/*LEVEL_CMD_LOOP_BEGIN */ level_cmd_loop_begin ,
/*LEVEL_CMD_LOOP_UNTIL */ level_cmd_loop_until ,
/*LEVEL_CMD_JUMP_IF */ level_cmd_jump_if ,
/*LEVEL_CMD_JUMP_AND_LINK_IF */ level_cmd_jump_and_link_if ,
/*LEVEL_CMD_SKIP_IF */ level_cmd_skip_if ,
/*LEVEL_CMD_SKIP */ level_cmd_skip ,
/*LEVEL_CMD_SKIPPABLE_NOP */ level_cmd_skippable_nop ,
/*LEVEL_CMD_CALL */ level_cmd_call ,
/*LEVEL_CMD_CALL_LOOP */ level_cmd_call_loop ,
/*LEVEL_CMD_SET_REGISTER */ level_cmd_set_register ,
/*LEVEL_CMD_PUSH_POOL_STATE */ level_cmd_push_pool_state ,
/*LEVEL_CMD_POP_POOL_STATE */ level_cmd_pop_pool_state ,
/*LEVEL_CMD_LOAD_TO_FIXED_ADDRESS */ level_cmd_load_to_fixed_address ,
/*LEVEL_CMD_LOAD_RAW */ level_cmd_load_raw ,
/*LEVEL_CMD_LOAD_YAY0 */ level_cmd_load_yay0 ,
/*LEVEL_CMD_LOAD_MARIO_HEAD */ level_cmd_load_mario_head ,
/*LEVEL_CMD_LOAD_YAY0_TEXTURE */ level_cmd_load_yay0_texture ,
/*LEVEL_CMD_INIT_LEVEL */ level_cmd_init_level ,
/*LEVEL_CMD_CLEAR_LEVEL */ level_cmd_clear_level ,
/*LEVEL_CMD_ALLOC_LEVEL_POOL */ level_cmd_alloc_level_pool ,
/*LEVEL_CMD_FREE_LEVEL_POOL */ level_cmd_free_level_pool ,
/*LEVEL_CMD_BEGIN_AREA */ level_cmd_begin_area ,
/*LEVEL_CMD_END_AREA */ level_cmd_end_area ,
/*LEVEL_CMD_LOAD_MODEL_FROM_DL */ level_cmd_load_model_from_dl ,
/*LEVEL_CMD_LOAD_MODEL_FROM_GEO */ level_cmd_load_model_from_geo ,
/*LEVEL_CMD_23 */ level_cmd_23 ,
/*LEVEL_CMD_PLACE_OBJECT */ level_cmd_place_object ,
/*LEVEL_CMD_INIT_MARIO */ level_cmd_init_mario ,
/*LEVEL_CMD_CREATE_WARP_NODE */ level_cmd_create_warp_node ,
/*LEVEL_CMD_CREATE_PAINTING_WARP_NODE */ level_cmd_create_painting_warp_node ,
/*LEVEL_CMD_CREATE_INSTANT_WARP */ level_cmd_create_instant_warp ,
/*LEVEL_CMD_LOAD_AREA */ level_cmd_load_area ,
/*LEVEL_CMD_UNLOAD_AREA */ level_cmd_unload_area ,
/*LEVEL_CMD_SET_MARIO_START_POS */ level_cmd_set_mario_start_pos ,
/*LEVEL_CMD_UNLOAD_MARIO_AREA */ level_cmd_unload_mario_area ,
/*LEVEL_CMD_UPDATE_OBJECTS */ level_cmd_update_objects ,
/*LEVEL_CMD_SET_TERRAIN_DATA */ level_cmd_set_terrain_data ,
/*LEVEL_CMD_SET_ROOMS */ level_cmd_set_rooms ,
/*LEVEL_CMD_SHOW_DIALOG */ level_cmd_show_dialog ,
/*LEVEL_CMD_SET_TERRAIN_TYPE */ level_cmd_set_terrain_type ,
/*LEVEL_CMD_NOP */ level_cmd_nop ,
/*LEVEL_CMD_SET_TRANSITION */ level_cmd_set_transition ,
/*LEVEL_CMD_SET_BLACKOUT */ level_cmd_set_blackout ,
/*LEVEL_CMD_SET_GAMMA */ level_cmd_set_gamma ,
/*LEVEL_CMD_SET_MUSIC */ level_cmd_set_music ,
/*LEVEL_CMD_SET_MENU_MUSIC */ level_cmd_set_menu_music ,
/*LEVEL_CMD_FADEOUT_MUSIC */ level_cmd_fadeout_music ,
/*LEVEL_CMD_SET_MACRO_OBJECTS */ level_cmd_set_macro_objects ,
/*LEVEL_CMD_3A */ level_cmd_3A ,
/*LEVEL_CMD_CREATE_WHIRLPOOL */ level_cmd_create_whirlpool ,
/*LEVEL_CMD_GET_OR_SET_VAR */ level_cmd_get_or_set_var ,
/*LEVEL_CMD_PUPPYVOLUME */ level_cmd_puppyvolume ,
/*LEVEL_CMD_CHANGE_AREA_SKYBOX */ level_cmd_change_area_skybox ,
/*LEVEL_CMD_PUPPYLIGHT_ENVIRONMENT */ level_cmd_puppylight_environment ,
/*LEVEL_CMD_PUPPYLIGHT_NODE */ level_cmd_puppylight_node ,
2023-06-28 15:15:38 -04:00
/*LEVEL_CMD_SET_ECHO */ level_cmd_set_echo ,
2019-08-25 00:46:40 -04:00
} ;
struct LevelCommand * level_script_execute ( struct LevelCommand * cmd ) {
sScriptStatus = SCRIPT_RUNNING ;
sCurrentCmd = cmd ;
2019-09-01 15:50:50 -04:00
while ( sScriptStatus = = SCRIPT_RUNNING ) {
2019-08-25 00:46:40 -04:00
LevelScriptJumpTable [ sCurrentCmd - > type ] ( ) ;
2019-09-01 15:50:50 -04:00
}
2019-08-25 00:46:40 -04:00
2021-09-16 23:14:53 +01:00
init_rcp ( CLEAR_ZBUFFER ) ;
2019-08-25 00:46:40 -04:00
render_game ( ) ;
end_master_display_list ( ) ;
alloc_display_list ( 0 ) ;
return sCurrentCmd ;
}