ledHeadWii/source/game/Baseball.c

927 lines
21 KiB
C
Raw Permalink Normal View History

2020-03-03 18:49:42 +01:00
/*
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.
2020-05-25 18:02:06 +02:00
Email : peter@peterhirschberg.com
Website : http://www.peterhirschberg.com
2020-03-03 18:49:42 +01:00
*/
2020-05-25 18:02:06 +02:00
#include <string.h>
#include <sys/time.h>
2020-03-03 18:49:42 +01:00
#include "Baseball.h"
#include "Games.h"
// constants
#define FIRSTBASE 3
#define SECONDBASE 6
#define THIRDBASE 9
#define HOMEPLATE 12
2020-05-25 18:02:06 +02:00
#define MAGIC_NUMBER 64 // emperically derived magic number
#define SPEED_BASE (1 + (MAGIC_NUMBER/16))
#define CENTER_FIELD 0
#define LEFT_FIELD 1
#define RIGHT_FIELD 2
2020-03-03 18:49:42 +01:00
// game variables
static BOOL bHomeTeam;
static BOOL bInFrame = FALSE;
static int nHRuns;
static int nVRuns;
static int nInnings;
static int nOuts;
static int nBalls;
static int nStrikes;
static int nTimerPitchWait;
static int nPitchSpeed;
static BOOL bCurveball;
2020-05-25 18:02:06 +02:00
static BOOL bStrike = FALSE;
2020-03-03 18:49:42 +01:00
static int nPitchIndex;
static int nPendingRuns;
static int nTimerEndPlayWait;
static int nTimerRunnerMove;
static int nRunnerSpeed;
static int nTimerFielding;
static int nCurrentRunnerIndex;
static int nDefenseBlip;
2020-05-25 18:02:06 +02:00
static int nBallBlip;
2020-03-03 18:49:42 +01:00
static BOOL bCaught;
2020-05-25 18:02:06 +02:00
static BOOL bDisplayOff;
2020-03-03 18:49:42 +01:00
static int fireWorks;
2020-05-25 18:02:06 +02:00
static int nSwingSlot;
2020-03-03 18:49:42 +01:00
// finite state machine stuff
static void fsmIdle(int tu);
static void fsmPitchWait(int tu);
static void fsmPitching(int tu);
static void fsmEndPlayWait(int tu);
static void fsmRun(int tu);
static void fsmWalk(int tu);
static void fsmOut(int tu);
static void fsmHomeRun(int tu);
static void fsmEndPossession(int tu);
static void fsmGameOver(int tu);
2020-05-25 18:02:06 +02:00
static void fsmGoOut(int tu);
2020-03-03 18:49:42 +01:00
2020-05-25 18:02:06 +02:00
enum FSM {
2020-03-03 18:49:42 +01:00
FSM_IDLE,
FSM_PITCHWAIT,
FSM_PITCHING,
FSM_ENDPLAYWAIT,
FSM_RUN,
FSM_WALK,
FSM_OUT,
FSM_HOMERUN,
FSM_ENDPOSSESSION,
2020-05-25 18:02:06 +02:00
FSM_GAMEOVER,
FSM_GOOUT
};
static enum FSM fsm;
2020-03-03 18:49:42 +01:00
typedef void (*FSMFCN)(int);
static FSMFCN fsmfcn[] = {
fsmIdle,
fsmPitchWait,
fsmPitching,
fsmEndPlayWait,
fsmRun,
fsmWalk,
fsmOut,
fsmHomeRun,
fsmEndPossession,
2020-05-25 18:02:06 +02:00
fsmGameOver,
fsmGoOut
2020-03-03 18:49:42 +01:00
};
2020-05-25 18:02:06 +02:00
typedef struct
2020-03-03 18:49:42 +01:00
{
int baseindex;
BOOL enabled;
2020-05-25 18:02:06 +02:00
} RUNNER;
2020-03-03 18:49:42 +01:00
#define MAX_RUNNERS 4
RUNNER runners[MAX_RUNNERS];
2020-05-25 18:02:06 +02:00
typedef struct {
int seq[3];
int n;
} fireworks_t;
static fireworks_t fw_frames[] = {
{ {DIAMOND(1)}, 1},
{ {DIAMOND(1), DIAMOND(2)}, 2},
{ {DIAMOND(1), DIAMOND(2), DEEP_1ST}, 3},
{ {DIAMOND(2), DEEP_1ST, DIAMOND(4)}, 3},
{ {DEEP_1ST, DIAMOND(4), DIAMOND(5)}, 3},
{ {DIAMOND(4), DIAMOND(5), DEEP_3RD}, 3},
{ {DIAMOND(5), DEEP_3RD, DIAMOND(8)}, 3},
{ {DEEP_3RD, DIAMOND(8), DIAMOND(7)}, 3},
{ {DIAMOND(8), DIAMOND(7), OUT_LEFT}, 3},
{ {DIAMOND(7), OUT_LEFT, OUT_CENTER}, 3},
{ {OUT_LEFT, OUT_CENTER, -1}, 3},
{ {OUT_CENTER, -1, DIAMOND(10)}, 3},
{ {-1, DIAMOND(10), DIAMOND(11)}, 3},
{ {DIAMOND(10), DIAMOND(11), NORMAL_BALL(8)}, 3},
{ {NORMAL_BALL(8), NORMAL_BALL(7)}, 2},
{ {NORMAL_BALL(8), NORMAL_BALL(7), NORMAL_BALL(6)}, 3},
{ {NORMAL_BALL(7), NORMAL_BALL(6), NORMAL_BALL(5)}, 3},
{ {NORMAL_BALL(6), NORMAL_BALL(5), CURVE_BALL(4)}, 3},
{ {NORMAL_BALL(5), CURVE_BALL(3), CURVE_BALL(2)}, 3},
{ {CURVE_BALL(3), CURVE_BALL(2), CURVE_BALL(1)}, 3},
{ {CURVE_BALL(2), CURVE_BALL(1), NORMAL_BALL(1)}, 3},
{ {CURVE_BALL(1), NORMAL_BALL(1), NORMAL_BALL(2)}, 3},
{ {NORMAL_BALL(1), NORMAL_BALL(2), NORMAL_BALL(3)}, 3},
{ {NORMAL_BALL(2), NORMAL_BALL(3), NORMAL_BALL(4)}, 3},
{ {NORMAL_BALL(3), NORMAL_BALL(4)}, 2},
{ {}, 0}
};
2020-03-03 18:49:42 +01:00
2020-05-25 18:02:06 +02:00
static void ClearBlips()
2020-03-03 18:49:42 +01:00
{
2020-05-25 18:02:06 +02:00
int i;
if(fireWorks) {
fireworks_t *fw=&fw_frames[fireWorks-1];
for(i=0; i<fw->n; i++) {
if(fw->seq[i] != -1)
Baseball_DrawBlip(FALSE,fw->seq[i]);
}
}
else {
if(nBallBlip != -1) {
Baseball_DrawBlip(FALSE, nBallBlip);
}
for (i=0; i<MAX_RUNNERS; i++) {
if (runners[i].enabled) {
Baseball_DrawBlip(FALSE, DIAMOND(runners[i].baseindex));
}
}
if (nDefenseBlip != -1) {
Baseball_DrawBlip(FALSE, nDefenseBlip);
}
}
2020-03-03 18:49:42 +01:00
}
2020-05-25 18:02:06 +02:00
static void DrawBlips()
2020-03-03 18:49:42 +01:00
{
2020-05-25 18:02:06 +02:00
int i;
if(fireWorks > 0) {
fireworks_t *fw=&fw_frames[fireWorks-1];
2020-03-03 18:49:42 +01:00
2020-05-25 18:02:06 +02:00
Baseball_DrawScore(-1, -1); // Clean fireworks
for(i=0; i<fw->n; i++) {
if(fw->seq[i] == -1)
Baseball_DrawFireWorks();
else
Baseball_DrawBlip(TRUE,fw->seq[i]);
}
}
2020-03-03 18:49:42 +01:00
else {
2020-05-25 18:02:06 +02:00
if(nBallBlip != -1) {
Baseball_DrawBlip(TRUE, nBallBlip);
}
for (i=0; i<MAX_RUNNERS; i++) {
if (runners[i].enabled) {
Baseball_DrawBlip(TRUE, DIAMOND(runners[i].baseindex));
}
}
if (nDefenseBlip != -1) {
if (bCaught) {
static BOOL blink=FALSE;
static int blinkcnt=0;
--blinkcnt;
if (blinkcnt<0) {
blinkcnt = 2;
blink = !blink;
}
if (blink) {
Baseball_DrawBlip(TRUE, nDefenseBlip);
}
}
else
Baseball_DrawBlip(TRUE, nDefenseBlip);
}
2020-03-03 18:49:42 +01:00
}
}
2020-05-25 18:02:06 +02:00
static void InitGame()
2020-03-03 18:49:42 +01:00
{
bHomeTeam = FALSE;
PlatformSetInput(bHomeTeam);
nHRuns = 0;
nVRuns = 0;
nInnings = 0;
nStrikes = 0;
nOuts = 0;
nBalls = 0;
2020-05-25 18:02:06 +02:00
nBallBlip = -1;
nDefenseBlip = -1;
for (int i=0; i<MAX_RUNNERS; i++) {
2020-03-03 18:49:42 +01:00
runners[i].enabled = FALSE;
}
fsm = FSM_IDLE;
}
void Baseball_Run(int tu)
{
// prevent reentrancy
2020-05-25 18:02:06 +02:00
if (bInFrame)
return;
2020-03-03 18:49:42 +01:00
bInFrame = TRUE;
2020-05-25 18:02:06 +02:00
if (Baseball_GetPower() == FALSE) {
InitGame();
2020-03-03 18:49:42 +01:00
// power is off
Platform_StartDraw();
Baseball_DrawScore(-1, -1);
Platform_EndDraw();
bInFrame = FALSE;
return;
}
Platform_StartDraw();
2020-05-25 18:02:06 +02:00
ClearBlips();
2020-03-03 18:49:42 +01:00
// run the game
(fsmfcn[fsm])(tu);
2020-05-25 18:02:06 +02:00
if(!bDisplayOff) {
DrawBlips();
2020-03-03 18:49:42 +01:00
}
2020-05-25 18:02:06 +02:00
else {
Baseball_DrawScore(-1, -1);
2020-03-03 18:49:42 +01:00
}
2020-05-25 18:02:06 +02:00
Platform_EndDraw();
2020-03-03 18:49:42 +01:00
2020-05-25 18:02:06 +02:00
bInFrame = FALSE;
2020-03-03 18:49:42 +01:00
}
static void InsertRunner()
{
2020-05-25 18:02:06 +02:00
for (int i=0; i<MAX_RUNNERS; i++) {
if (!runners[i].enabled) {
runners[i].baseindex = 0;
runners[i].enabled = TRUE;
2020-03-03 18:49:42 +01:00
nCurrentRunnerIndex = i;
return;
}
}
}
// returns TRUE if move resulted in a run
static BOOL MoveRunners()
{
BOOL bRun = FALSE;
2020-05-25 18:02:06 +02:00
for (int i=0; i<MAX_RUNNERS; i++) {
if (runners[i].enabled) {
2020-03-03 18:49:42 +01:00
runners[i].baseindex++;
2020-05-25 18:02:06 +02:00
if (runners[i].baseindex >= HOMEPLATE) {
2020-03-03 18:49:42 +01:00
// got a run
2020-05-25 18:02:06 +02:00
runners[i].baseindex = -1;
runners[i].enabled = FALSE;
if (i == nCurrentRunnerIndex) {
2020-03-03 18:49:42 +01:00
nCurrentRunnerIndex = -1;
}
bRun=TRUE;
}
}
}
return bRun;
}
static void ResetOffBaseRunners()
{
BOOL bOffBase = FALSE;
2020-05-25 18:02:06 +02:00
for (int i=0; i<MAX_RUNNERS; i++) {
if (runners[i].enabled) {
2020-03-03 18:49:42 +01:00
if ((runners[i].baseindex != FIRSTBASE)
&& (runners[i].baseindex != SECONDBASE)
&& (runners[i].baseindex != THIRDBASE)
2020-05-25 18:02:06 +02:00
&& (runners[i].baseindex != HOMEPLATE)) {
2020-03-03 18:49:42 +01:00
// yes, there is at least one runner and he is off-base
bOffBase = TRUE;
break;
}
}
}
2020-05-25 18:02:06 +02:00
if (bOffBase) {
2020-03-03 18:49:42 +01:00
//
// The ball has now been fielded and there are
// currently runners off-base -- figure out who
// is out.
//
// If the batter did not make it to first, he is out and
// the remaining runners all move back to the previous base.
// If the batter made it past first, the lead runner is out
// and the remaining runners move either to the next base or
// to the previous base, depending on how far they made it.
//
// see if the batter made it to first
BOOL bFirst=TRUE;
int i;
2020-05-25 18:02:06 +02:00
for (i=0; i<MAX_RUNNERS; i++) {
if (runners[i].enabled) {
if (runners[i].baseindex < FIRSTBASE) {
2020-03-03 18:49:42 +01:00
// the batter didn't make it to first - he's out
runners[i].enabled = FALSE;
bFirst = FALSE;
break;
}
}
}
2020-05-25 18:02:06 +02:00
if (bFirst) {
2020-03-03 18:49:42 +01:00
// look for the lead runner
int nRunnerOut = -1;
2020-05-25 18:02:06 +02:00
for (i=0; i<MAX_RUNNERS; i++) {
if (runners[i].enabled) {
if (nRunnerOut == -1) {
2020-03-03 18:49:42 +01:00
nRunnerOut = i;
}
2020-05-25 18:02:06 +02:00
else {
if (runners[i].baseindex > runners[nRunnerOut].baseindex) {
2020-03-03 18:49:42 +01:00
nRunnerOut = i;
}
}
}
}
// mark the lead runner out
2020-05-25 18:02:06 +02:00
if (nRunnerOut != -1) {
2020-03-03 18:49:42 +01:00
runners[nRunnerOut].enabled = FALSE;
}
// figure out if the remaining runners should go to the previous or next base
2020-05-25 18:02:06 +02:00
for (i=0; i<MAX_RUNNERS; i++) {
if (runners[i].enabled) {
2020-03-03 18:49:42 +01:00
int howfar = (runners[i].baseindex) % 3;
2020-05-25 18:02:06 +02:00
if (howfar <= 1) {
2020-03-03 18:49:42 +01:00
// go back
runners[i].baseindex--;
}
2020-05-25 18:02:06 +02:00
else {
2020-03-03 18:49:42 +01:00
// go forward
runners[i].baseindex++;
}
}
}
}
2020-05-25 18:02:06 +02:00
else {
2020-03-03 18:49:42 +01:00
// the batter is out
2020-05-25 18:02:06 +02:00
for (i=0; i<MAX_RUNNERS; i++) {
if (runners[i].enabled) {
if (runners[i].baseindex < FIRSTBASE) {
2020-03-03 18:49:42 +01:00
runners[i].enabled = FALSE;
break;
}
}
}
// move the remaining runners back to the previous base
2020-05-25 18:02:06 +02:00
for (i=0; i<MAX_RUNNERS; i++) {
if (runners[i].enabled) {
2020-03-03 18:49:42 +01:00
runners[i].baseindex -= (runners[i].baseindex) % 3;
}
}
}
}
}
2020-05-25 18:02:06 +02:00
static enum FSM HitBall()
2020-03-03 18:49:42 +01:00
{
2020-05-25 18:02:06 +02:00
// This routine was totally rewritten by Nebiun
2020-03-03 18:49:42 +01:00
//
// There are 3 positions where you can hit the ball:
// - right in front of the plate
// - directly over the plate
// - right behind the plate
//
2020-05-25 18:02:06 +02:00
// In addition, each position is sampled more times related
// to the ball speed (random and depending from game level)
2020-03-03 18:49:42 +01:00
//
// Finally, there are 5 catchers that can field the ball:
// - left and right infield
// - left, center and right outfield
//
// The ball will either be fielded normally or it will be
// a fly out and will be counted as an out. If the ball is
// fielded normally, we pick a random fielding time (1,2 or 3
// beeps), and a random runner speed.
2020-05-25 18:02:06 +02:00
int side, force;
if(nPitchIndex == 5) {
if(Platform_Random(10) == 0) // left-handed batter
side = RIGHT_FIELD;
else
side = LEFT_FIELD;
}
else if(nPitchIndex == 7) {
if(Platform_Random(10) == 0) // left-handed batter
side = LEFT_FIELD;
else
side = RIGHT_FIELD;
2020-03-03 18:49:42 +01:00
}
2020-05-25 18:02:06 +02:00
else {
switch(Platform_Random(5)) {
2020-03-03 18:49:42 +01:00
case 0:
2020-05-25 18:02:06 +02:00
side = LEFT_FIELD;
2020-03-03 18:49:42 +01:00
break;
case 1:
2020-05-25 18:02:06 +02:00
side = RIGHT_FIELD;
2020-03-03 18:49:42 +01:00
break;
default:
2020-05-25 18:02:06 +02:00
side = CENTER_FIELD;
2020-03-03 18:49:42 +01:00
break;
}
2020-05-25 18:02:06 +02:00
}
2020-03-03 18:49:42 +01:00
2020-05-25 18:02:06 +02:00
if((nPitchSpeed <= 1) || (nSwingSlot < nPitchSpeed)) {
force = 1;
}
else {
force = 0;
}
switch(side) {
case LEFT_FIELD:
if((force == 0) || (Platform_Random(5) == 0))
nDefenseBlip = DEEP_3RD;
2020-03-03 18:49:42 +01:00
else
2020-05-25 18:02:06 +02:00
nDefenseBlip = Platform_Random(2) ? DEEP_3RD : OUT_LEFT;
break;
case RIGHT_FIELD:
if((force == 0) || (Platform_Random(5) == 0))
nDefenseBlip = DEEP_1ST;
else
nDefenseBlip = Platform_Random(2) ? DEEP_1ST : OUT_RIGHT;
break;
default:
if((force == 0) || (Platform_Random(5) == 0))
nDefenseBlip = Platform_Random(2) ? OUT_LEFT : OUT_RIGHT;
else
nDefenseBlip = OUT_CENTER;
break;
}
// Out ?
if (Platform_Random(4) == 0) {
bCaught = TRUE;
return FSM_GOOUT;
}
2020-03-03 18:49:42 +01:00
2020-05-25 18:02:06 +02:00
// Homerun
if ((force == 1) &&
(((side == CENTER_FIELD) && (Platform_Random(4) == 0)) || (Platform_Random(25) == 0))) {
nDefenseBlip = -1;
fireWorks = 1;
return FSM_HOMERUN;
}
Baseball_DrawStats(-1, -1, nBalls, nStrikes, bHomeTeam);
// pick a random fielding speed and play
// the correct number of base tones
int level = Baseball_GetSkill();
int bases = Platform_Random(3)+1;
nTimerFielding = (MAGIC_NUMBER * bases) - (level * Platform_Random(10));
for (int i=0; i<bases; i++) {
Baseball_PlaySound(BASEBALL_SOUND_HIT, PLAYSOUNDFLAGS_PRIORITY);
Platform_Pause(200);
}
2020-03-03 18:49:42 +01:00
2020-05-25 18:02:06 +02:00
// pick a random runner speed:
// slow or medium or fast
nTimerRunnerMove = nRunnerSpeed = SPEED_BASE * (1 + Platform_Random(3));
// insert a runner
InsertRunner();
return FSM_RUN;
}
static long long Baseball_Clock(int f)
{
static struct timeval tv_start;
struct timeval tv, tv_delta;
long long rtn;
if(f == 1) {
gettimeofday(&tv_start, NULL);
return 0;
}
gettimeofday(&tv, NULL);
timersub(&tv, &tv_start, &tv_delta);
rtn = tv_delta.tv_sec * 1000000 + tv_delta.tv_usec;
return rtn;
}
2020-03-03 18:49:42 +01:00
2020-05-25 18:02:06 +02:00
static BOOL run()
{
if (--nTimerRunnerMove <= 0) {
nTimerRunnerMove = nRunnerSpeed;
if (MoveRunners()) {
// record runs
if (bHomeTeam) {
++nHRuns;
}
else {
++nVRuns;
}
// also note the run for later (for the sounds)
++nPendingRuns;
2020-03-03 18:49:42 +01:00
}
2020-05-25 18:02:06 +02:00
return TRUE;
2020-03-03 18:49:42 +01:00
}
2020-05-25 18:02:06 +02:00
return FALSE;
}
static void pendigRunNotify()
{
while(nPendingRuns > 0) {
Baseball_PlaySound(BASEBALL_SOUND_RUN, PLAYSOUNDFLAGS_PRIORITY);
Platform_Pause(200);
--nPendingRuns;
}
bDisplayOff = (nPendingRuns > 0) ? TRUE : FALSE;
}
// FINITE STATE MACHINE STUFF
static void fsmGoOut(int tu)
{
static int delay = 0;
if(delay == 0) {
delay = 1000 * 600;
bDisplayOff = TRUE;
Baseball_PlaySound(BASEBALL_SOUND_OUT, PLAYSOUNDFLAGS_ASYNC|PLAYSOUNDFLAGS_PRIORITY);
Baseball_Clock(1);
}
else if(Baseball_Clock(0) >= delay) {
delay = 0;
bDisplayOff = FALSE;
fsm = FSM_OUT;
}
2020-03-03 18:49:42 +01:00
}
static void fsmOut(int tu)
{
++nOuts;
2020-05-25 18:02:06 +02:00
if (nOuts == 3) {
2020-03-03 18:49:42 +01:00
// end of possession
// but first play any pending run sounds
2020-05-25 18:02:06 +02:00
if(nPendingRuns > 0)
pendigRunNotify();
2020-03-03 18:49:42 +01:00
nOuts = 0;
bHomeTeam = !bHomeTeam;
2020-05-25 18:02:06 +02:00
if (!bHomeTeam) {
2020-03-03 18:49:42 +01:00
++nInnings;
2020-05-25 18:02:06 +02:00
if (nInnings == 5) {
2020-03-03 18:49:42 +01:00
// ************************
// ****** GAME OVER *******
// ************************
Baseball_PlaySound(BASEBALL_SOUND_ENDGAME, PLAYSOUNDFLAGS_ASYNC|PLAYSOUNDFLAGS_PRIORITY);
fsm = FSM_GAMEOVER;
return;
}
}
PlatformSetInput(bHomeTeam);
2020-05-25 18:02:06 +02:00
Baseball_PlaySound(BASEBALL_SOUND_ENDPOSSESSION, PLAYSOUNDFLAGS_PRIORITY|PLAYSOUNDFLAGS_ASYNC);
2020-03-03 18:49:42 +01:00
Baseball_DrawStats(-1, -1, nBalls, nStrikes, bHomeTeam);
fsm = FSM_ENDPOSSESSION;
}
2020-05-25 18:02:06 +02:00
else {
2020-03-03 18:49:42 +01:00
Baseball_DrawStats(-1, -1, nBalls, nStrikes, bHomeTeam);
2020-05-25 18:02:06 +02:00
nStrikes = 0;
nBalls = 0;
nTimerEndPlayWait = (nDefenseBlip == -1) ? 1500 : 3000;
Baseball_Clock(1);
2020-03-03 18:49:42 +01:00
fsm = FSM_ENDPLAYWAIT;
}
}
static void fsmIdle(int tu)
{
// play the run sounds
2020-05-25 18:02:06 +02:00
if(nPendingRuns > 0)
pendigRunNotify();
2020-03-03 18:49:42 +01:00
nCurrentRunnerIndex = -1;
nDefenseBlip = -1;
bCaught = FALSE;
2020-05-25 18:02:06 +02:00
nBallBlip = -1;
if (Baseball_GetInputSCORE(NULL)) {
2020-03-03 18:49:42 +01:00
Baseball_DrawScore(nVRuns, nHRuns);
}
2020-05-25 18:02:06 +02:00
else {
2020-03-03 18:49:42 +01:00
Baseball_DrawStats(nInnings+1, nOuts, nBalls, nStrikes, bHomeTeam);
}
// wait for pitch button
2020-05-25 18:02:06 +02:00
if (Baseball_GetInputPITCH(NULL)) {
2020-03-03 18:49:42 +01:00
// delay from 1.5 to 2.5 seconds (according to manual)
// before pitching the ball
2020-05-25 18:02:06 +02:00
nTimerPitchWait = 1000 * (1500 + Platform_Random(1000)); // Microsecs
Baseball_Clock(1);
2020-03-03 18:49:42 +01:00
fsm = FSM_PITCHWAIT;
}
}
static void fsmPitchWait(int tu)
{
Baseball_DrawScore(-1, -1);
2020-05-25 18:02:06 +02:00
if (Baseball_Clock(0) >= nTimerPitchWait) {
int level = Baseball_GetSkill();
2020-03-03 18:49:42 +01:00
// pick a ball speed and throw style
// and pitch the ball
2020-05-25 18:02:06 +02:00
bCurveball = (Platform_Random(3 - level) == 0) ? TRUE : FALSE;
if (bCurveball) {
nPitchSpeed = (3 - level) + Platform_Random(2 - level); // curve balls are a little slower
2020-03-03 18:49:42 +01:00
}
2020-05-25 18:02:06 +02:00
else {
nPitchSpeed = (2 - level) + Platform_Random(3 - level);
2020-03-03 18:49:42 +01:00
}
2020-05-25 18:02:06 +02:00
nSwingSlot = nPitchSpeed;
nPitchIndex = 0;
nBallBlip = (bCurveball) ? CURVE_BALL(nPitchIndex) : NORMAL_BALL(nPitchIndex);
2020-03-03 18:49:42 +01:00
2020-05-25 18:02:06 +02:00
bStrike = FALSE;
2020-03-03 18:49:42 +01:00
fsm = FSM_PITCHING;
}
}
static void fsmPitching(int tu)
{
2020-05-25 18:02:06 +02:00
const int nMissChance = 5;
2020-03-03 18:49:42 +01:00
2020-05-25 18:02:06 +02:00
if(nPitchIndex <= 8) {
if(Baseball_GetInputHIT(NULL)) {
if((nPitchIndex >= 5) && (nPitchIndex <= 7) && (Platform_Random(nMissChance) != 0)) {
fsm = HitBall();
2020-03-03 18:49:42 +01:00
}
2020-05-25 18:02:06 +02:00
else {
bStrike = TRUE;
nPitchIndex = 9;
2020-03-03 18:49:42 +01:00
}
}
else {
2020-05-25 18:02:06 +02:00
if(--nSwingSlot <= 0) {
nSwingSlot = nPitchSpeed;
++nPitchIndex;
}
2020-03-03 18:49:42 +01:00
}
}
2020-05-25 18:02:06 +02:00
else {
2020-03-03 18:49:42 +01:00
// if player didn't swing, randomly pick strike or ball
2020-05-25 18:02:06 +02:00
if (Platform_Random(2) && !bStrike) {
2020-03-03 18:49:42 +01:00
++nBalls;
}
2020-05-25 18:02:06 +02:00
else {
2020-03-03 18:49:42 +01:00
++nStrikes;
}
2020-05-25 18:02:06 +02:00
if (nBalls == 4) {
2020-03-03 18:49:42 +01:00
// walk
Baseball_DrawStats(-1, -1, nBalls, nStrikes, bHomeTeam);
2020-05-25 18:02:06 +02:00
Baseball_PlaySound(BASEBALL_SOUND_STRIKE, PLAYSOUNDFLAGS_PRIORITY|PLAYSOUNDFLAGS_ASYNC);
nTimerRunnerMove = nRunnerSpeed = 2 * SPEED_BASE; // walk is always a fixed speed
2020-03-03 18:49:42 +01:00
InsertRunner();
fsm = FSM_WALK;
}
2020-05-25 18:02:06 +02:00
else if (nStrikes == 3) {
2020-03-03 18:49:42 +01:00
// struck out
2020-05-25 18:02:06 +02:00
fsm = FSM_GOOUT;
2020-03-03 18:49:42 +01:00
}
2020-05-25 18:02:06 +02:00
else {
2020-03-03 18:49:42 +01:00
Baseball_DrawStats(-1, -1, nBalls, nStrikes, bHomeTeam);
2020-05-25 18:02:06 +02:00
Baseball_PlaySound(BASEBALL_SOUND_STRIKE, PLAYSOUNDFLAGS_PRIORITY|PLAYSOUNDFLAGS_ASYNC);
nTimerEndPlayWait = 1500;
2020-03-03 18:49:42 +01:00
fsm = FSM_ENDPLAYWAIT;
}
}
2020-05-25 18:02:06 +02:00
if(nPitchIndex <= 8)
nBallBlip = (bCurveball) ? CURVE_BALL(nPitchIndex) : NORMAL_BALL(nPitchIndex);
2020-03-03 18:49:42 +01:00
}
static void fsmEndPlayWait(int tu)
{
2020-05-25 18:02:06 +02:00
static int delay = 0;
if(delay == 0) {
delay = 1000 * nTimerEndPlayWait;
Baseball_Clock(1);
2020-03-03 18:49:42 +01:00
}
2020-05-25 18:02:06 +02:00
else if(Baseball_Clock(0) >= delay) {
delay = 0;
2020-03-03 18:49:42 +01:00
// reset the runners
ResetOffBaseRunners();
fsm = FSM_IDLE;
}
}
static void fsmRun(int tu)
{
// RUN does not take effect until you release HIT
2020-05-25 18:02:06 +02:00
if (Baseball_GetInputRUN(NULL) && !Baseball_GetInputHIT(NULL)) {
run();
2020-03-03 18:49:42 +01:00
}
2020-05-25 18:02:06 +02:00
if (--nTimerFielding <= 0) {
2020-03-03 18:49:42 +01:00
// ball is finished being fielded
// ball has been fielded - see if any runners are off base
BOOL bOffBase = FALSE;
2020-05-25 18:02:06 +02:00
for (int i=0; i<MAX_RUNNERS; i++) {
if (runners[i].enabled) {
2020-03-03 18:49:42 +01:00
if ((runners[i].baseindex != FIRSTBASE)
&& (runners[i].baseindex != SECONDBASE)
&& (runners[i].baseindex != THIRDBASE)
2020-05-25 18:02:06 +02:00
&& (runners[i].baseindex != HOMEPLATE)) {
2020-03-03 18:49:42 +01:00
bOffBase = TRUE;
break;
}
}
}
2020-05-25 18:02:06 +02:00
if (bOffBase) {
2020-03-03 18:49:42 +01:00
// somebody is out -- go through the 'out' theatrics
2020-05-25 18:02:06 +02:00
fsm = FSM_GOOUT;
2020-03-03 18:49:42 +01:00
}
2020-05-25 18:02:06 +02:00
else {
2020-03-03 18:49:42 +01:00
// all runners are safe
Baseball_DrawStats(-1, -1, nBalls, nStrikes, bHomeTeam);
nBalls=0;
nStrikes=0;
2020-05-25 18:02:06 +02:00
nTimerEndPlayWait = 1500;
2020-03-03 18:49:42 +01:00
fsm = FSM_ENDPLAYWAIT;
}
}
}
static void fsmWalk(int tu)
{
2020-05-25 18:02:06 +02:00
if (Baseball_GetInputRUN(NULL)) {
if(run() == TRUE) {
2020-03-03 18:49:42 +01:00
// when the current runner gets on first, we're done
2020-05-25 18:02:06 +02:00
if (runners[nCurrentRunnerIndex].baseindex == FIRSTBASE) {
2020-03-03 18:49:42 +01:00
// got someone on first - all done
nStrikes = 0;
nBalls = 0;
2020-05-25 18:02:06 +02:00
nTimerEndPlayWait = 1500;
fsm = FSM_ENDPLAYWAIT;
2020-03-03 18:49:42 +01:00
}
}
}
}
static void fsmHomeRun(int tu)
{
static int loop = 0;
if(fireWorks > 0) {
//
// do fireworks display
2020-05-25 18:02:06 +02:00
//
2020-03-03 18:49:42 +01:00
2020-05-25 18:02:06 +02:00
if(fireWorks == 1)
2020-03-03 18:49:42 +01:00
Baseball_PlaySound(BASEBALL_SOUND_RUN, PLAYSOUNDFLAGS_PRIORITY|PLAYSOUNDFLAGS_ASYNC);
2020-05-25 18:02:06 +02:00
Platform_Pause(40);
2020-03-03 18:49:42 +01:00
fireWorks++;
if(fireWorks > 26) {
loop++;
if(loop == 4) {
loop = 0;
fireWorks = 0;
// insert a runner
InsertRunner();
2020-05-25 18:02:06 +02:00
nTimerRunnerMove = nRunnerSpeed = 2 * SPEED_BASE; // fixed run speed
2020-03-03 18:49:42 +01:00
}
else {
fireWorks = 1;
}
}
return;
}
2020-05-25 18:02:06 +02:00
if (Baseball_GetInputRUN(NULL)) {
if (run() == TRUE) {
// see if anyone is still running the bases
BOOL bManOnBase = FALSE;
for (int i=0; i<MAX_RUNNERS; i++) {
if (runners[i].enabled) {
bManOnBase = TRUE;
break;
2020-03-03 18:49:42 +01:00
}
}
2020-05-25 18:02:06 +02:00
if (!bManOnBase) {
// nobody on base - all done
nStrikes = 0;
nBalls = 0;
fsm = FSM_IDLE;
}
2020-03-03 18:49:42 +01:00
}
}
}
static void fsmEndPossession(int tu)
{
// wait for SCORE key
2020-05-25 18:02:06 +02:00
if (Baseball_GetInputSCORE(NULL)) {
2020-03-03 18:49:42 +01:00
nOuts = 0;
nStrikes = 0;
nBalls = 0;
// remove all runners
2020-05-25 18:02:06 +02:00
for (int i=0; i<MAX_RUNNERS; i++) {
2020-03-03 18:49:42 +01:00
runners[i].enabled = FALSE;
}
Baseball_DrawStats(nInnings+1, nOuts, nBalls, nStrikes, bHomeTeam);
fsm = FSM_IDLE;
}
}
static void fsmGameOver(int tu)
{
Baseball_DrawScore(nVRuns, nHRuns);
}
2020-05-25 18:02:06 +02:00
#define LINE_STEP 20
void Baseball_Debug(int f)
{
int w, h;
int y = 0;
Baseball_GetSize(&w, &h);
debugPrintf(realx(w)+10, realy(y), 0xFFFFFFFF, "fsm =%d", fsm);
y += LINE_STEP;
debugPrintf(realx(w)+10, realy(y), 0xFFFFFFFF, "pitch i=%d s=%d", nPitchIndex, nPitchSpeed);
y += LINE_STEP;
debugPrintf(realx(w)+10, realy(y), 0xFFFFFFFF, "pitch w=%d", nTimerPitchWait/1000);
y += LINE_STEP;
debugPrintf(realx(w)+10, realy(y), 0xFFFFFFFF, "curve =%d", bCurveball);
y += LINE_STEP;
debugPrintf(realx(w)+10, realy(y), 0xFFFFFFFF, "Play tim =%d", nTimerEndPlayWait);
y += LINE_STEP;
debugPrintf(realx(w)+10, realy(y), 0xFFFFFFFF, "Field tim =%d", nTimerFielding);
y += LINE_STEP;
debugPrintf(realx(w)+10, realy(y), 0xFFFFFFFF, "Swing =%d", nSwingSlot);
y += LINE_STEP;
debugPrintf(realx(w)+10, realy(y), 0xFFFFFFFF, "Speed =%d", nRunnerSpeed);
y += LINE_STEP;
}