mirror of
https://github.com/nebiun/ledHeadWii.git
synced 2024-11-25 12:06:53 +01:00
453 lines
9.5 KiB
C
453 lines
9.5 KiB
C
/*
|
|
|
|
LEDhead
|
|
Copyright 2001, Peter Hirschberg
|
|
Author: Peter Hirschberg
|
|
|
|
The current version of this SOURCE CODE as well as the official
|
|
versions of the LEDHEAD APPLICATION are available from my website
|
|
at: http://www.peterhirschberg.com
|
|
|
|
Based on the handheld electronic games by Mattel Electronics.
|
|
All trademarks copyrighted by their respective owners. This
|
|
program is not affiliated or endorsed by Mattel Electronics.
|
|
|
|
License agreement:
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program (license.txt); if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
Email : peter@peterhirschberg.com
|
|
Website : http://www.peterhirschberg.com
|
|
|
|
*/
|
|
|
|
#include "AutoRace.h"
|
|
#include "Games.h"
|
|
|
|
// constants
|
|
|
|
#define TIMER_CARADVANCE 10
|
|
|
|
typedef int BLIP;
|
|
|
|
static BLIP Blips[AUTORACE_BLIP_COLUMNS][AUTORACE_BLIP_ROWS];
|
|
|
|
typedef struct ONCOMINGCAR{
|
|
int nRow;
|
|
int nColumn;
|
|
BOOL bActive;
|
|
}ONCOMINGCAR;
|
|
|
|
static ONCOMINGCAR sOncomingCarA, sOncomingCarB;
|
|
|
|
|
|
// game variables
|
|
static int nLaneSelector;
|
|
static int nGear;
|
|
static int nCarRow;
|
|
static int nGameTimer;
|
|
static int nLaps;
|
|
static BOOL bGameEnd; // 1 = loose, 2 = win
|
|
static BOOL bInFrame = FALSE;
|
|
static BOOL bPower;
|
|
static int nCarAdvanceTimer;
|
|
static int nGearCounter;
|
|
|
|
static void fsmPlayStartWait();
|
|
static void fsmInPlay();
|
|
static void fsmCrash();
|
|
static void fsmEndLap();
|
|
static void fsmEndGame();
|
|
|
|
static enum FSM {
|
|
FSM_PLAYSTARTWAIT=0,
|
|
FSM_INPLAY,
|
|
FSM_CRASH,
|
|
FSM_ENDLAP,
|
|
FSM_ENDGAME
|
|
}fsm;
|
|
|
|
typedef void (*FSMFCN)();
|
|
|
|
static FSMFCN fsmfcn[] = {
|
|
fsmPlayStartWait,
|
|
fsmInPlay,
|
|
fsmCrash,
|
|
fsmEndLap,
|
|
fsmEndGame
|
|
};
|
|
|
|
static void InitGame();
|
|
static void UpdateOurCar();
|
|
static void UpdateOncomingCars();
|
|
static void DoHitTest();
|
|
static void UpdateBlips();
|
|
static void StartSecondCar();
|
|
|
|
BOOL AutoRace_GetPower()
|
|
{
|
|
return (bPower ? TRUE : FALSE);
|
|
}
|
|
|
|
void AutoRace_PowerOn()
|
|
{
|
|
InitGame();
|
|
bPower = TRUE;
|
|
}
|
|
|
|
void AutoRace_PowerOff()
|
|
{
|
|
bPower = FALSE;
|
|
AutoRace_StopSound();
|
|
AutoRace_StopEngineSound();
|
|
}
|
|
|
|
int AutoRace_GetSkill()
|
|
{
|
|
return nGear;
|
|
}
|
|
|
|
void AutoRace_SetSkill(int i)
|
|
{
|
|
if (i > 3) {
|
|
i = 3;
|
|
}
|
|
else if (i < 0) {
|
|
i = 0;
|
|
}
|
|
nGear = i;
|
|
}
|
|
|
|
void InitGame()
|
|
{
|
|
// set our car's position
|
|
nLaneSelector = 1;
|
|
nCarRow = AUTORACE_BLIP_ROWS - 1;
|
|
|
|
// init the other cars
|
|
sOncomingCarA.bActive = FALSE;
|
|
sOncomingCarB.bActive = FALSE;
|
|
|
|
nGameTimer = 0;
|
|
bGameEnd = 0;
|
|
nLaps = 0;
|
|
|
|
nCarAdvanceTimer = TIMER_CARADVANCE;
|
|
nGearCounter = 999;
|
|
fsm = FSM_PLAYSTARTWAIT;
|
|
}
|
|
|
|
void AutoRace_Run(int tu)
|
|
{
|
|
int x, y;
|
|
|
|
// prevent reentrancy
|
|
if (bInFrame){ return; }
|
|
bInFrame = TRUE;
|
|
|
|
// init the blips field
|
|
for (y = 0; y < AUTORACE_BLIP_ROWS; y++){
|
|
for (x = 0; x < AUTORACE_BLIP_COLUMNS; x++){
|
|
Blips[x][y] = BLIP_OFF;
|
|
}
|
|
}
|
|
if (!bPower){
|
|
fsm = FSM_PLAYSTARTWAIT;
|
|
}
|
|
Platform_StartDraw();
|
|
|
|
(fsmfcn[fsm])();
|
|
|
|
UpdateBlips();
|
|
|
|
// draw the blips field
|
|
for (int y = 0; y < AUTORACE_BLIP_ROWS; y++){
|
|
for (int x = 0; x < AUTORACE_BLIP_COLUMNS; x++){
|
|
AutoRace_DrawBlip(Blips[x][y], x, y);
|
|
}
|
|
}
|
|
|
|
// draw the score
|
|
AutoRace_DrawTime(nGameTimer);
|
|
|
|
Platform_EndDraw();
|
|
|
|
bInFrame = FALSE;
|
|
}
|
|
|
|
void fsmInPlay()
|
|
{
|
|
BOOL bMoveCars = FALSE;
|
|
|
|
if (Platform_IsNewSecond()){
|
|
// update the game timer
|
|
++nGameTimer;
|
|
if (nGameTimer == 99){
|
|
// time's up -- game over!
|
|
bGameEnd = 1;
|
|
fsm = FSM_ENDGAME;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// get the current stick position
|
|
nLaneSelector = AutoRace_GetInputSTICK();
|
|
|
|
// check for gear changes
|
|
nGear = AutoRace_GetInputGEAR(NULL);
|
|
|
|
// move the cars at the correct speed per gear selection
|
|
AutoRace_PlayEngineSound();
|
|
|
|
switch(nGear){
|
|
case 0:
|
|
if (nGearCounter > 3){
|
|
nGearCounter = 0;
|
|
bMoveCars = TRUE;
|
|
}
|
|
break;
|
|
case 1:
|
|
if (nGearCounter > 2){
|
|
nGearCounter = 0;
|
|
bMoveCars = TRUE;
|
|
}
|
|
break;
|
|
case 2:
|
|
if (nGearCounter > 1){
|
|
nGearCounter = 0;
|
|
bMoveCars = TRUE;
|
|
}
|
|
break;
|
|
case 3:
|
|
// move every frame
|
|
bMoveCars = TRUE;
|
|
nGearCounter = 0;
|
|
break;
|
|
}
|
|
++nGearCounter;
|
|
|
|
if (bMoveCars){
|
|
UpdateOncomingCars();
|
|
DoHitTest();
|
|
UpdateOurCar();
|
|
DoHitTest();
|
|
}
|
|
}
|
|
|
|
void UpdateOurCar()
|
|
{
|
|
if (nCarAdvanceTimer){
|
|
--nCarAdvanceTimer;
|
|
}
|
|
if (nCarAdvanceTimer == 0){
|
|
|
|
// move our car up
|
|
--nCarRow;
|
|
if (nCarRow <= 0){
|
|
// lap completed!
|
|
fsm = FSM_ENDLAP;
|
|
}
|
|
nCarAdvanceTimer = TIMER_CARADVANCE;
|
|
}
|
|
}
|
|
|
|
void UpdateOncomingCars()
|
|
{
|
|
|
|
// move the oncoming cars down
|
|
for (int i=0; i<2; i++){
|
|
|
|
ONCOMINGCAR *pOncomingCar = i ? &sOncomingCarB : &sOncomingCarA;
|
|
|
|
if (pOncomingCar->bActive){
|
|
pOncomingCar->nRow++;
|
|
if (pOncomingCar->nRow >= AUTORACE_BLIP_ROWS){
|
|
// car has left the screen
|
|
pOncomingCar->bActive = FALSE;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// count the number of oncoming cars
|
|
// should be at least 1 car at all times
|
|
// maximum 2 oncoming cars at any given time
|
|
|
|
if (!sOncomingCarA.bActive && !sOncomingCarB.bActive){
|
|
|
|
// no cars are approaching, start at least one
|
|
sOncomingCarA.bActive = TRUE;
|
|
sOncomingCarA.nRow = -2;
|
|
sOncomingCarA.nColumn = Platform_Random(3);
|
|
|
|
// and perhaps start a second car
|
|
if (Platform_Random(5) == 0){
|
|
StartSecondCar();
|
|
}
|
|
|
|
}
|
|
|
|
if (!sOncomingCarA.bActive || !sOncomingCarB.bActive){
|
|
// only 1 car is active -- randomly try to start a second car
|
|
if (Platform_Random(10) == 0){
|
|
StartSecondCar();
|
|
}
|
|
}
|
|
}
|
|
|
|
void StartSecondCar()
|
|
{
|
|
if (sOncomingCarA.bActive && sOncomingCarB.bActive){
|
|
// both cars are already active
|
|
return;
|
|
}
|
|
|
|
ONCOMINGCAR *pNewOncomingCar, *pOtherOncomingCar;
|
|
if (sOncomingCarA.bActive){
|
|
pNewOncomingCar = &sOncomingCarB;
|
|
pOtherOncomingCar = &sOncomingCarA;
|
|
} else {
|
|
pNewOncomingCar = &sOncomingCarA;
|
|
pOtherOncomingCar = &sOncomingCarB;
|
|
}
|
|
|
|
pNewOncomingCar->bActive = TRUE;
|
|
pNewOncomingCar->nRow = -2;
|
|
pNewOncomingCar->nColumn = Platform_Random(3);
|
|
|
|
if ((pNewOncomingCar->nColumn == pOtherOncomingCar->nColumn)
|
|
&& (pNewOncomingCar->nRow == pOtherOncomingCar->nRow)
|
|
&& pOtherOncomingCar->bActive){
|
|
// car is on top of other car -- reposition the car behind the other car
|
|
pNewOncomingCar->nRow = pNewOncomingCar->nRow-1;
|
|
}
|
|
|
|
}
|
|
|
|
void DoHitTest()
|
|
{
|
|
for (int i=0; i<2; i++){
|
|
ONCOMINGCAR *pOncomingCar = i ? &sOncomingCarB : &sOncomingCarA;
|
|
|
|
if (pOncomingCar->bActive){
|
|
if ((pOncomingCar->nRow == nCarRow)
|
|
&& (pOncomingCar->nColumn == nLaneSelector)){
|
|
|
|
// hit an oncoming car!
|
|
fsm = FSM_CRASH;
|
|
if (nCarRow < (AUTORACE_BLIP_ROWS - 1)){
|
|
++nCarRow;
|
|
}
|
|
else {
|
|
// if oncoming car is in the last row and hits us
|
|
// delete it to keep it from hitting us every frame
|
|
// (since our car can't be moved out of the way)
|
|
pOncomingCar->bActive = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void UpdateBlips()
|
|
{
|
|
// draw the oncoming car blips
|
|
for (int i=0; i<2; i++){
|
|
ONCOMINGCAR *pOncomingCar = i ? &sOncomingCarB : &sOncomingCarA;
|
|
if (pOncomingCar->bActive){
|
|
if ((pOncomingCar->nColumn >= 0) && (pOncomingCar->nColumn < AUTORACE_BLIP_COLUMNS)
|
|
&& (pOncomingCar->nRow >= 0) && (pOncomingCar->nRow < AUTORACE_BLIP_ROWS)){
|
|
Blips[pOncomingCar->nColumn][pOncomingCar->nRow] = (fsm == FSM_CRASH) ? BLIP_BRIGHT : BLIP_DIM;
|
|
}
|
|
else if ((pOncomingCar->nColumn >= 0) && (pOncomingCar->nColumn < AUTORACE_BLIP_COLUMNS)
|
|
&& (pOncomingCar->nRow == -1)){
|
|
// oncoming car blips display on-screen for an extra frame when they first appear
|
|
// (to give you a better chance of avoiding them when our car is near the top)
|
|
// put them on-screen even if they are just off-screen
|
|
Blips[pOncomingCar->nColumn][0] = (fsm == FSM_CRASH) ? BLIP_BRIGHT : BLIP_DIM;
|
|
}
|
|
}
|
|
}
|
|
|
|
// draw the player's car blip
|
|
if ((nCarRow <= (AUTORACE_BLIP_ROWS - 1))
|
|
&& (nCarRow >= 0)){
|
|
Blips[nLaneSelector][nCarRow] = BLIP_BRIGHT;
|
|
}
|
|
|
|
}
|
|
|
|
void fsmPlayStartWait()
|
|
{
|
|
nLaneSelector = AutoRace_GetInputSTICK();
|
|
|
|
// check for gear changes
|
|
nGear = AutoRace_GetInputGEAR(NULL);
|
|
|
|
if (bPower){
|
|
Blips[nLaneSelector][nCarRow] = BLIP_BRIGHT;
|
|
}
|
|
else {
|
|
AutoRace_ClearScreen();
|
|
}
|
|
|
|
// wait for 1st gear before starting
|
|
if (nGear == 0){
|
|
Platform_IsNewSecond();
|
|
fsm = FSM_INPLAY;
|
|
}
|
|
}
|
|
|
|
void fsmCrash()
|
|
{
|
|
AutoRace_PlaySound(AUTORACE_SOUND_HIT, PLAYSOUNDFLAGS_PRIORITY);
|
|
fsm = FSM_INPLAY;
|
|
}
|
|
|
|
void fsmEndLap()
|
|
{
|
|
// lap completed!
|
|
AutoRace_StopEngineSound();
|
|
Platform_Pause(300);
|
|
nCarRow = AUTORACE_BLIP_ROWS - 1;
|
|
++nLaps;
|
|
if (nLaps >= 4){
|
|
// finished race -- game over!
|
|
bGameEnd = 2;
|
|
fsm = FSM_ENDGAME;
|
|
}
|
|
else {
|
|
AutoRace_PlayEngineSound();
|
|
fsm = FSM_INPLAY;
|
|
}
|
|
}
|
|
|
|
void fsmEndGame()
|
|
{
|
|
AutoRace_ClearScreen();
|
|
AutoRace_StopEngineSound();
|
|
|
|
switch(bGameEnd) {
|
|
case 1:
|
|
AutoRace_PlaySound(AUTORACE_SOUND_TIME, PLAYSOUNDFLAGS_PRIORITY);
|
|
break;
|
|
case 2:
|
|
AutoRace_PlaySound(AUTORACE_SOUND_WIN, PLAYSOUNDFLAGS_PRIORITY);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
bGameEnd = 0;
|
|
} |