If you appreciate the work done within the wiki, please consider supporting The Cutting Room Floor on Patreon. Thanks for all your support!

LEGO Star Wars III: The Clone Wars (Nintendo DS)

From The Cutting Room Floor
Jump to navigation Jump to search

Title Screen

LEGO Star Wars III: The Clone Wars

Developer: TT Fusion
Publisher: LucasArts
Platform: Nintendo DS
Released in US: March 22, 2011
Released in EU: March 25, 2011
Released in AU: March 30, 2011


CharacterIcon.png This game has unused playable characters.
SourceIcon.png This game has uncompiled source code.
GraphicsIcon.png This game has unused graphics.


LEGO! Star Wars! Clone Wars.

fedora.nbfc

LEGOSW3 fedora icon.png

The data directory contains the icon from LEGO Indiana Jones: The Original Adventures.

Unused Character

LEGO Star Wars DS character.png

The man behind the counter in the HUB area can be switched to by using a moon-jump cheat to get behind the counter. He's basically a Clone Trooper without a helmet, except he doesn't have a gun and uses Obi-Wan's icon. He can also use The Force, unlike the other Clone Troopers.

Uncompiled Source Code

In the same data directory contains a file named test.txt which seems to be for a knife-throwing game for the Wii.


#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include "fnaDevice.h"
#include "fnaMatrix.h"
#include "fnaPrimitive.h"
#include "fnaTexture.h"
#include "fnaDebug.h"
#include "fnaLight.h"
#include "fnaController.h"

#include "fnFont.h"
#include "fnMaths.h"
#include "fnMemory.h"
#include "fnCollision.h"
#include "fnRender.h"
#include "fnAnimBones.h"

#include "geGameobject.h"

#include "..\Games.h"
#include "..\Controls.h"
#include "..\GameLoop.h"
#include "..\Players.h"
#include "..\ViewPorts.h"
#include "..\SoundFX.h"
#include "..\GOFlasher.h"
#include "..\Hud.h"
#include "..\Gestures.h"


//-----------------------------------------------------------------------------------------------------------------------------
fnOBJECT *Game058_FindChild(fnOBJECT *parentObject, const char *ChildName);


//-----------------------------------------------------------------------------------------------------------------------------
// Constants
const u32 GAME058_DURATION = 6000000;//6000;

const u32 NUM_KNIVES = 50;
const u32 NUM_THROW_TICKS = 35;


static u8 SoundFX[] = {
	SFX_WHISTLE,
	SFX_CAMERA,
	SFX_CROWDBOO,
	SFX_CROWDOOH,
	SFX_CROWDCHEER,
	SFX_CROWDLOOP,
	SFX_COUNTDOWN,
	GESOUND_NONE
};

//-----------------------------------------------------------------------------------------------------------------------------
// Enums
enum GAME058PLAYERSTATE {
	GAME058PLAYERSTATE_PLAYING,
	GAME058PLAYERSTATE_FINISHED,
};

enum GAME058KNIFESTATE {
	GAME058KNIFESTATE_FREE,
	GAME058KNIFESTATE_THROWING,
	GAME058KNIFESTATE_FALLING,
	GAME058KNIFESTATE_ON_FLOOR,
	GAME058KNIFESTATE_STUCK,
};


//-----------------------------------------------------------------------------------------------------------------------------
// Structs and classes
class Game058 : public Game {
public:
	Game058();
	void GameLoad();
	void GameExit();
	void GameUpdate(u32 tick, u32 player, fnINPUTDEVICE *joypad);
	void GameUpdateAll(u32 tick);
	void GameRender();
};


struct GAME058KNIFE
{
	GEGAMEOBJECT		*pKnife;
	GAME058KNIFESTATE	State;
	x32mat4				KnifeMat;
	x32mat4				StartMat;
	x32mat4				TargetMat;

	u32					StartTick;
	u32					EndTick;
};


struct GAME058PLAYER {
	GAME058PLAYERSTATE State;
	CONTROLPOINTER* pPointer;
	x32mat4			CameraMatrix;
	x32vec2			ScreenPos;
	fnCACHEITEM		*pPointerTexture;
	GEGAMEOBJECT	*GOCharacter;
	GEUIITEM*		_clogBar;

	u32				NumLaunched;
	GAME058KNIFE	Knives[NUM_KNIVES];

	GEGAMEOBJECT	*GOKnifeThrowing;
	GEGAMEOBJECT	*GOWheel;
//	fnOBJECT		*GOWheel;
	x32				WheelAngle;
};

struct GAME058DATA
{
	GAME058PLAYER		Players[4];
	GEGAMEOBJECT		*pKnife;
	u32					TicksTaken;
	bool				HadGameStart;
	GESOUNDBANK			*SoundBank;

#ifdef _DEBUG
	fnFONT * pDebugFont;
	char DebugMsgBuffer[256];
#endif

};



//-----------------------------------------------------------------------------------------------------------------------------
// Globals
Game058 Game058Module;
Game *Game058Ptr = &Game058Module;
static x32vec2  UVTopLeft, UVTopRight, UVBottomRight, UVBottomLeft;
static GAME058DATA *pData;



//-----------------------------------------------------------------------------------------------------------------------------
// Functions
Game058::Game058() {
	levelname = "Game058KnifeThrowing";
	GameTextName = TXT_GAMETEXTWII_GAMENAME_026;
}

//-----------------------------------------------------------------------------------------------------------------------------
void Game058_InitPlayer(u32 playerIndex) {
	GAME058PLAYER* pPlayer	= &pData->Players[playerIndex];

	char buf[64];
	sprintf(buf, "Sprites/HandPoint%d.tga", playerIndex + 1);
	pPlayer->pPointerTexture = fnCache_Load(buf, fnCACHELOADTYPE_FOREGROUND);

	x32vec4 v4startEndPos;
	fnaMatrix_v4make(&v4startEndPos, fnFixedx32(-60.f), fnFixedx32(100.f), fnFixedx32(10.f), fnFixedx32(100.f));

	sprintf(buf, "Player%d", playerIndex+1);
	pPlayer->GOCharacter = geGameobject_FindGameobject(buf);

	pData->Players[playerIndex].pPointer = &Player_Get(playerIndex)->currentPointer;

	pPlayer->GOKnifeThrowing = geGameobject_FindGameobject("KnifeThrowing");
	fnaAssert( pPlayer->GOKnifeThrowing, "Game058_InitPlayer: Unable to find object KnifeThrowing" );

	pPlayer->GOWheel = geGameobject_FindGameobject("Wheel");
	fnaAssert( pPlayer->GOWheel, "Game058_InitPlayer: Unable to find object Wheel" );

//	pPlayer->GOWheel = Game058_FindChild(pPlayer->GOKnifeThrowing->object, "Wheel");
//	fnaAssert( pPlayer->GOWheel, "Game058_InitPlayer: Unable to find object Wheel" );

	for (u32 n=0; n<NUM_KNIVES; n++)
	{
		sprintf(buf, "Knife%02d", n + 1);
		pPlayer->Knives[n].State = GAME058KNIFESTATE_FREE;
		pPlayer->Knives[n].pKnife = (GEGAMEOBJECT*) geGameobject_FindGameobject(buf);
		fnaAssert( pPlayer->Knives[n].pKnife, fnaDebug_String("Game058_InitPlayer: Unable to find object %s", buf) );
	}
}

//-----------------------------------------------------------------------------------------------------------------------------
void Game058::GameLoad() {
	pData = (GAME058DATA*) fnMem_Alloc(sizeof(GAME058DATA));

	pData->pKnife = (GEGAMEOBJECT*) geGameobject_FindGameobject("Knife");

	pData->TicksTaken			= 0;
	pData->HadGameStart			= false;


	x32vec2 range = {fnFixedx32(0), fnFixedx32(115)};
	x32vec4 StartEndPos;
	switch(Player_Count)
	{
	case 1:
		fnaMatrix_v4make(&StartEndPos, -fnFixedx32(10), fnFixedx32(160), fnFixedx32(10), fnFixedx32(160));
		pData->Players[0]._clogBar = Hud_PercentCreate("sprites/EggandSpoonBar.tga", NULL, "sprites/EggandSpoonBarBit.tga", &range, &StartEndPos);
		break;
	case 2:
		fnaMatrix_v4make(&StartEndPos, -fnFixedx32(10), fnFixedx32(70), fnFixedx32(10), fnFixedx32(70));
		pData->Players[0]._clogBar = Hud_PercentCreate("sprites/EggandSpoonBar.tga", NULL, "sprites/EggandSpoonBarBit.tga", &range, &StartEndPos);

		fnaMatrix_v4make(&StartEndPos, fnFixedx32(660) * Hud_WideScreenScale, fnFixedx32(70), fnFixedx32(590) * Hud_WideScreenScale, fnFixedx32(70));
		pData->Players[1]._clogBar = Hud_PercentCreate("sprites/EggandSpoonBar.tga", NULL, "sprites/EggandSpoonBarBit.tga", &range, &StartEndPos);
		break;
	case 3:
		fnaMatrix_v4make(&StartEndPos, -fnFixedx32(10), fnFixedx32(70), fnFixedx32(10), fnFixedx32(70));
		pData->Players[0]._clogBar = Hud_PercentCreate("sprites/EggandSpoonBar.tga", NULL, "sprites/EggandSpoonBarBit.tga", &range, &StartEndPos);

		fnaMatrix_v4make(&StartEndPos, fnFixedx32(660) * Hud_WideScreenScale, fnFixedx32(70), fnFixedx32(590) * Hud_WideScreenScale, fnFixedx32(70));
		pData->Players[1]._clogBar = Hud_PercentCreate("sprites/EggandSpoonBar.tga", NULL, "sprites/EggandSpoonBarBit.tga", &range, &StartEndPos);

		fnaMatrix_v4make(&StartEndPos, -fnFixedx32(10), fnFixedx32(300), fnFixedx32(10), fnFixedx32(300));
		pData->Players[2]._clogBar = Hud_PercentCreate("sprites/EggandSpoonBar.tga", NULL, "sprites/EggandSpoonBarBit.tga", &range, &StartEndPos);
		break;
	case 4:
		fnaMatrix_v4make(&StartEndPos, -fnFixedx32(10), fnFixedx32(70), fnFixedx32(10), fnFixedx32(70));
		pData->Players[0]._clogBar = Hud_PercentCreate("sprites/EggandSpoonBar.tga", NULL, "sprites/EggandSpoonBarBit.tga", &range, &StartEndPos);

		fnaMatrix_v4make(&StartEndPos, fnFixedx32(660) * Hud_WideScreenScale, fnFixedx32(70), fnFixedx32(590) * Hud_WideScreenScale, fnFixedx32(70));
		pData->Players[1]._clogBar = Hud_PercentCreate("sprites/EggandSpoonBar.tga", NULL, "sprites/EggandSpoonBarBit.tga", &range, &StartEndPos);

		fnaMatrix_v4make(&StartEndPos, -fnFixedx32(10), fnFixedx32(300), fnFixedx32(10), fnFixedx32(300));
		pData->Players[2]._clogBar = Hud_PercentCreate("sprites/EggandSpoonBar.tga", NULL, "sprites/EggandSpoonBarBit.tga", &range, &StartEndPos);

		fnaMatrix_v4make(&StartEndPos, fnFixedx32(660) * Hud_WideScreenScale, fnFixedx32(300), fnFixedx32(590) * Hud_WideScreenScale, fnFixedx32(300));
		pData->Players[3]._clogBar = Hud_PercentCreate("sprites/EggandSpoonBar.tga", NULL, "sprites/EggandSpoonBarBit.tga", &range, &StartEndPos);
		break;
	}

	// The intro/countdown stages trash the camera1 settings, so save them for later
	fnaMatrix_v2make(&UVBottomRight,	fnFixedx32_Zero,	fnFixedx32_Zero);
	fnaMatrix_v2make(&UVBottomLeft,	fnFixedx32_One,		fnFixedx32_Zero);
	fnaMatrix_v2make(&UVTopLeft,		fnFixedx32_One,		fnFixedx32_One);
	fnaMatrix_v2make(&UVTopRight,		fnFixedx32_Zero,	fnFixedx32_One);

	pData->SoundBank = geSoundBank_Load(SoundFX_Files, SoundFX);

#ifndef FNTARGET_PC
	//geSound_PlaySound(pGameData->SoundBank, SFX_CROWDLOOP, 0);
#endif
	fnaFile_SetDirectory("models/textures/");
	
	ViewPorts_Set(VIEWPORT_FULL, VIEWPORT_FULL, VIEWPORT_FULL, VIEWPORTFLAG_COUNTER);

	for (u32 playerIndex = 0; playerIndex < Player_Count; ++playerIndex)
	{
		Game058_InitPlayer(playerIndex);

		fnaMatrix_m4copy( &pData->Players[playerIndex].CameraMatrix, fnObject_GetMatrixPtr( geGameobject_FindGameobject( "Camera1" )->object ) );
	}

#ifdef _DEBUG
	pData->pDebugFont	= fnFont_Load( "Fonts/Tahoma10", FNFONTTYPE_3D );
	fnFont_SetColour( pData->pDebugFont, 0xffffffff);
	fnFont_SetAlphaBlend( pData->pDebugFont, FNALPHABLEND_SRCALPHA, FNALPHABLEND_INVSRCALPHA );
	fnFont_SetFormat( pData->pDebugFont, FNFONTPRINT_XJUSTLEFT, FNFONTPRINT_YJUSTTOP, false, false );
	fnFont_SetFont( pData->pDebugFont );
#endif // _DEBUG

}

//-----------------------------------------------------------------------------------------------------------------------------

void Game058::GameExit()
{
	geSoundBank_Destroy(pData->SoundBank);

	for (u8 playerIndex = 0; playerIndex < Player_Count; ++playerIndex) {
		GAME058PLAYER* pPlayer = &pData->Players[playerIndex];

		fnCache_Unload(pPlayer->pPointerTexture);

		if(pPlayer->_clogBar) {
			Hud_DestroyItem(pPlayer->_clogBar);
		}
	}

#ifdef _DEBUG
	fnFont_Destroy( pData->pDebugFont );
#endif

	fnMem_Free(pData);
}

//-----------------------------------------------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------------------------------------------


fnOBJECT *Game058_FindChild(fnOBJECT *parentObject, const char *ChildName)
{

	fnOBJECT * pChildObj	= NULL;
	fnOBJECT * pRoot		= NULL;

	pRoot = fnObject_Find( parentObject, "root" );

	fnaAssert( pRoot, "Game058_FindChild: Unable to find object root" );

	for ( pChildObj = pRoot->firstchild; pChildObj != NULL; pChildObj = pChildObj->nextchild )
	{
		if ( strncmp( pChildObj->name, ChildName, strlen(ChildName) ) == 0 )
		{
			return pChildObj;
		}
	}

	return NULL;
}



x32mat4 *game058_CalcKnifePos(u32 player)
{
	GAME058PLAYER * pPlayer = &pData->Players[player];

	x32vec2 pointer = { pPlayer->ScreenPos.x, pPlayer->ScreenPos.y };

	x32vec3 rayEnd;
	fnCamera_ScreenToWorld(GameLoop_Camera[player], &pointer, 900.0f, &rayEnd);

	x32mat4 *pKnifeMat;
	pKnifeMat = fnObject_GetMatrixPtr(pData->pKnife->object);

	pKnifeMat->loc.x = rayEnd.x;
	pKnifeMat->loc.y = rayEnd.y;
	pKnifeMat->loc.z = rayEnd.z;

	fnObject_SetMatrix(pData->pKnife->object, pKnifeMat);

	return pKnifeMat;
}

GAME058KNIFE *Game058_FindFreeKnife(u32 player)
{
	GAME058PLAYER * pPlayer = &pData->Players[player];
	GAME058KNIFE *knife = NULL;

	for (u32 n=0; n<NUM_KNIVES; n++)
	{
		if (knife == NULL && pPlayer->Knives[n].State == GAME058KNIFESTATE_FREE)
			knife = &pPlayer->Knives[n];
	}

	return knife;
}

void Game058_ThrowKnife(u32 player, u32 tick)
{
	GAME058PLAYER * pPlayer = &pData->Players[player];

	GAME058KNIFE *knife = Game058_FindFreeKnife(player);
	if (knife)
	{
		knife->State = GAME058KNIFESTATE_THROWING;
		pPlayer->NumLaunched++;
		knife->StartTick = tick;
		knife->EndTick = tick + NUM_THROW_TICKS;

		fnaAssert( knife, "No free knives!" );

		x32mat4 *pPlayerMat;
		pPlayerMat = fnObject_GetMatrixPtr(pPlayer->GOCharacter->object);




		// need to get a proper launch point here
//		fnObject_SetMatrix(knife->pKnife->object, pPlayerMat);


		if ((pPlayer->NumLaunched&1)==0)
			knife->StartMat.loc.x = pPlayerMat->loc.x + fnFixedx32(36.0f) /* + fnFixedx32(pPlayer->NumLaunched * 2)*/;
		else
			knife->StartMat.loc.x = pPlayerMat->loc.x - fnFixedx32(36.0f) /* + fnFixedx32(pPlayer->NumLaunched * 2)*/;

		knife->StartMat.loc.y = pPlayerMat->loc.y + fnFixedx32(70.0f) /* + fnFixedx32(pPlayer->NumLaunched * 2)*/;
		knife->StartMat.loc.z = fnFixedx32(250.0f);

		fnaMatrix_m4copy(&knife->KnifeMat, pPlayerMat);

		sprintf( pData->DebugMsgBuffer, "num: %d  x: %f  y: %f  z: %f",pPlayer->NumLaunched, knife->StartMat.loc.x, knife->StartMat.loc.y, knife->StartMat.loc.z  );


		x32mat4 *pTargetMat;
		pTargetMat = game058_CalcKnifePos(player);
		fnaMatrix_m4copy(&knife->TargetMat, pTargetMat);

	}
}


void Game058_UpdateKnives(u32 player, u32 tick)
{
	GAME058PLAYER * pPlayer = &pData->Players[player];
	GAME058KNIFE *knife = NULL;
	u32 currtime;
	x32 lerp;

	for (u32 n=0; n<NUM_KNIVES; n++)
	{
		knife = &pPlayer->Knives[n];
		if (knife)
		{
			switch (knife->State)
			{
				case GAME058KNIFESTATE_THROWING:
					currtime = tick-knife->StartTick;
					lerp = fnFixedx32(currtime) / fnFixedx32(NUM_THROW_TICKS);

					if (lerp >= fnFixedx32(1.0f))
					{
						lerp = fnFixedx32(1.0f);
						knife->State = GAME058KNIFESTATE_STUCK;
						fnObject_Unlink(knife->pKnife->object->parent, knife->pKnife->object);
						fnObject_Attach( pPlayer->GOWheel->object, knife->pKnife->object );
					}

					x32mat4 posMatrix;
					fnaMatrix_m4unit(&posMatrix);
					fnaMatrix_v3lerpd(&posMatrix.loc.vec3, &knife->StartMat.loc.vec3, &knife->TargetMat.loc.vec3, lerp);

					x32mat4 cameraMatrix;
					fnaMatrix_m4unit( &cameraMatrix );
					fnaMatrix_m3vec_to_matrix( &cameraMatrix, &knife->StartMat.loc.vec3, &knife->TargetMat.loc.vec3, fnFixedx32_Zero );

					x32mat4 tmpMatrix;
					fnaMatrix_m4prodd(&tmpMatrix, &cameraMatrix, &posMatrix);
					fnaMatrix_m4copy(&knife->KnifeMat, &tmpMatrix);
					fnObject_SetMatrix(knife->pKnife->object, &knife->KnifeMat);
					break;

				case GAME058KNIFESTATE_STUCK:
					break;
			}
		}
	}
}

void Game058_RotateWheel(u32 player)
{
	GAME058PLAYER * pPlayer = &pData->Players[player];
	pPlayer->WheelAngle += fnFixedx32(2.0f);
	GEGAMEOBJECT *wheel = pPlayer->GOWheel;

	x32mat4 rotZ;
	fnaMatrix_m4unit(&rotZ);
	fnaMatrix_m3rotz(&rotZ, fnMaths_DegreeToRad(pPlayer->WheelAngle));

	x32mat4 *pWheelMat = fnObject_GetMatrixPtr(wheel->object);
	fnaMatrix_m3copy(pWheelMat, &rotZ);
	fnObject_SetMatrix(wheel->object, pWheelMat);

}


//-----------------------------------------------------------------------------------------------------------------------------
void Game058_UpdatePlaying(u32 tick, u32 player, fnINPUTDEVICE* joypad) {
//	GAME058PLAYER * pPlayer = &pData->Players[player];


#ifdef FNTARGET_PC
	if (Controls_Mouse->buttons[FNINPUTMOUSE_BUTTON1].clicked)
#else
	if (joypad->buttons[CONTROLS_A].clicked)
//	if (Game054_UpdateNunchuck(player, joypad) > 2.0f)
#endif
	{
		Game058_ThrowKnife(player, tick);
	}

	Game058_RotateWheel(player);
	Game058_UpdateKnives(player, tick);
	game058_CalcKnifePos(player);

//	sprintf( pData->DebugMsgBuffer, "Num: %d", pPlayer->NumLaunched  );

}

//-----------------------------------------------------------------------------------------------------------------------------
void Game058_UpdateFinished(u32 tick, u32 player, fnINPUTDEVICE * joypad) {
	fnaController_StopMotor(joypad, 0);
}

//-----------------------------------------------------------------------------------------------------------------------------
void Game058_UpdateCursor(u32 player) {	
	GAME058PLAYER * pPlayer = &pData->Players[player];
//#ifdef FNTARGET_PC
//	pPlayer->pPointer->screenloc.x = Controls_Mouse->buttons[FNINPUTMOUSE_MOUSEX].value;
//	pPlayer->pPointer->screenloc.y = Controls_Mouse->buttons[FNINPUTMOUSE_MOUSEY].value;
//#endif
	pPlayer->ScreenPos.x = pPlayer->pPointer->screenloc.x;
	pPlayer->ScreenPos.y = pPlayer->pPointer->screenloc.y;

	if (pPlayer->ScreenPos.x < 0) 
		pPlayer->ScreenPos.x = 0;
	else if (pPlayer->ScreenPos.x > fusionInit.width) 
		pPlayer->ScreenPos.x = fusionInit.width;

	if (pPlayer->ScreenPos.y < 0) 
		pPlayer->ScreenPos.y = 0;
	else if (pPlayer->ScreenPos.y > fusionInit.height) 
		pPlayer->ScreenPos.y = fusionInit.height;	
}

//-----------------------------------------------------------------------------------------------------------------------------

void Game058::GameUpdate(u32 tick, u32 player, fnINPUTDEVICE *joypad) {
	Game058_UpdateCursor(player);

	switch (pData->Players[player].State)
	{
	case GAME058PLAYERSTATE_PLAYING:
		Game058_UpdatePlaying(tick, player, joypad);
		break;

	case GAME058PLAYERSTATE_FINISHED:
		Game058_UpdateFinished(tick, player, joypad);
		break;
	}
	pData->TicksTaken++;
}

//-----------------------------------------------------------------------------------------------------------------------------
void Game058::GameUpdateAll(u32 tick) {
	switch(GameLoop_CurrentStage)
	{
	case GAMELOOPSTAGE_INTRO:
		break;

	case GAMELOOPSTAGE_COUNTDOWN:
		if (GameLoop_CountDownTimer == 400) {
//			fnCamera_SetParallel(GameLoop_Camera[0], 100.0f);
//			x32vec3 org = geGameobject_FindGameobject("fleeceOrigin")->object->worldmatrix.loc.vec3;
//			fnCamera_WorldToScreen(GameLoop_Camera[0], &org, &pData->_fleeceOrigin);
		}

		for (u8 i = 0; i < Player_Count; ++i) {
			geUIItem_Show(pData->Players[i]._clogBar, 0);
		}

		if (GameLoop_CountDownTimer == geMain_UpdateFPS * 2)
			ViewPorts_ShowHud();

		if(!((GameLoop_CountDownTimer+1) % geMain_UpdateFPS))
			geSound_PlaySound(pData->SoundBank, SFX_COUNTDOWN, 0);

		if(GameLoop_CountDownTimer == geMain_UpdateFPS)
		{
			geSound_PlaySound(pData->SoundBank, SFX_WHISTLE, 0);
			geSound_PlaySound(pData->SoundBank, SFX_CROWDCHEER, 0);
			GOFlasher_RateIncrease();
		}

		for (u32 playerIndex = 0; playerIndex < Player_Count; ++playerIndex)
		{
			Game058_UpdateCursor(playerIndex);
		}

		if (!pData->HadGameStart)
		{
			GEGAMEOBJECT * cam = geGameobject_FindGameobject("Camera1");
			fnObject_SetMatrix(GameLoop_Camera[0], &cam->object->worldmatrix);
		}
		pData->HadGameStart = true;
		break;


	case GAMELOOPSTAGE_GAME:
		if (pData->TicksTaken >= GAME058_DURATION) {
			for (u8 player = 0; player < Player_Count; ++player) {
				pData->Players[player].State = GAME058PLAYERSTATE_FINISHED;
				fnaController_StopMotor(&Player_Get(player)->currentInput, 0);
			}
			
			GameLoop_CurrentStage = GAMELOOPSTAGE_OUTRO;
		}
		break;

	case GAMELOOPSTAGE_OUTRO:
		break;

	case GAMELOOPSTAGE_OUTRORECORDS:
		break;

	default:
		fnaFail("Game058::GameUpdateAll: Hit default case.");
		break;
	}
}

//-----------------------------------------------------------------------------------------------------------------------------
void Game058::GameRender() {
	fnaLight_ResetAll();

	for (u32 i = 0; i < Player_Count; ++i)
	{
		ViewPorts_Render(i, fnFixedx32(pData->TicksTaken) / fnFixedx32(geMain_UpdateFPS));

		GAME058PLAYER* pPlayer = &pData->Players[i];

		if (GameLoop_CurrentStage == GAMELOOPSTAGE_GAME || GameLoop_CurrentStage == GAMELOOPSTAGE_COUNTDOWN)
		{
			x32vec3 v3ScreenPos;

			v3ScreenPos.x = pPlayer->ScreenPos.x - 32;
			v3ScreenPos.y = pPlayer->ScreenPos.y - 32;
			v3ScreenPos.z = 0.f;

			u32 colour;
			switch (i)
			{
				case 0: colour = 0xffffffff; break;
				case 1: colour = 0xffff0000; break;
				case 2: colour = 0xff00ff00; break;
				case 3: colour = 0xff00ffff; break;
				default: colour = 0xffffffff; break;
			}

			geUISprite_Render(pPlayer->pPointerTexture, &v3ScreenPos, colour, true);
		}

//		Hud_SetPercentBar(pPlayer->_clogBar, displayedClipClog);
	}

#ifdef _DEBUG
	fnFont_SetFont( pData->pDebugFont );
	fnFont_SetLocation( 20, 5);
	fnFont_PrintString( pData->DebugMsgBuffer );
#endif // _DEBUG

}

Menu Cheats

There are six cheats that can be used in the main menu of the game before loading a save. When a code is entered successfully an explosion sound can be heard. Two of the cheats are labeled as 'cash1' and 'cash2' in the game code but the actual effect is currently unknown.

Input Description
Down, Up, Left, Left, Right, Right, Right, Down, L, R, L, R, Up, Up, Select Cash1 (unknown Effect)
Up, Down, Right, Right, Up, Up, L, R, L, R, L, L, R, R, Select Cash2 (unknown Effect)
Down, Down, Left, Right, L, L, R, R, Down, Down, R, R, L, L, Select Unlock all Characters
L, R, L, L, Right, Right, Left, Left, Up, Down, R, L, L, R, Select Unlock all Levels
Down, Up, Up, Up, Down, Up, L, R, R, L, Down, Down, Left, Right, Select Unlock all Extras
Up, Down, Up, Up, Down, Down, L, L, L, L, Right, Right, Left, Right, Select Unlock all Minikits
(Source: SporyTike (RetroAchievements.org))