mirror of
https://github.com/nebiun/ledHeadWii.git
synced 2024-11-23 02:59:16 +01:00
1806 lines
39 KiB
C
1806 lines
39 KiB
C
/*
|
|
* LEDhead for Wii
|
|
* Copyright (C) 2017-2020 Nebiun
|
|
*
|
|
* 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.
|
|
*
|
|
* 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 3 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. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "Soccer2.h"
|
|
#include "Games.h"
|
|
|
|
// constants
|
|
|
|
#define NUM_DEFENSEPLAYERS 5
|
|
#define TIME_STATSDISPLAY 5
|
|
#define TIME_BALLMOVE 5
|
|
#define GAMETIME 45.9
|
|
#define TIME_TICKTIMER 10
|
|
#define BALL_LOWKICK (3 + Platform_Random(2))
|
|
#define BALL_HIGHKICK (5 + Platform_Random(4))
|
|
|
|
#define IS_GOALAREA() ((nSector == 1) || (nSector == 9))
|
|
#define IS_ATTACKAREA() ((nSector == 1 && bHomeTeam) || (nSector == 9 && !bHomeTeam))
|
|
|
|
typedef struct {
|
|
int state;
|
|
} BLIP;
|
|
|
|
typedef struct {
|
|
Coord_t player;
|
|
Coord_t receiver;
|
|
Coord_t defense[NUM_DEFENSEPLAYERS];
|
|
} SCHEME_t;
|
|
|
|
static BLIP Blips[SOCCER2_BLIP_COLUMNS][SOCCER2_BLIP_ROWS];
|
|
|
|
// debug
|
|
static int trc_debug;
|
|
|
|
// game variables
|
|
static BOOL bGameOver;
|
|
static BOOL bHomeTeam;
|
|
static BOOL bInFrame = FALSE;
|
|
static BOOL bPower;
|
|
static BOOL bBounce = FALSE;
|
|
static BOOL bTeamMate = FALSE;
|
|
static BOOL bTeamMateSet = FALSE;
|
|
static BOOL bKickKey = FALSE;
|
|
|
|
static int nLevel = -1;
|
|
static int nHScore;
|
|
static int nVScore;
|
|
static int fGameTime;
|
|
static int nHalf;
|
|
static int nTimerTickTimer;
|
|
static int nSector;
|
|
static int nBallDirectionX;
|
|
static int nBallDirectionY;
|
|
static int nTimerBallMove;
|
|
static int nStatsIndex;
|
|
static int nTimerStatsDisplay;
|
|
static int nBallStep;
|
|
static int nBallMax;
|
|
|
|
typedef struct {
|
|
int x;
|
|
int y;
|
|
int side;
|
|
}BALL_OUT;
|
|
static BALL_OUT ball_out;
|
|
|
|
typedef struct {
|
|
int nColumn;
|
|
int nRow;
|
|
int nBright;
|
|
int nColumnOld;
|
|
int nRowOld;
|
|
int nMoveNow;
|
|
}PLAYER;
|
|
|
|
static PLAYER ball;
|
|
static PLAYER player;
|
|
static PLAYER receiver;
|
|
static PLAYER goalkeeper;
|
|
static PLAYER defense[NUM_DEFENSEPLAYERS];
|
|
|
|
// macros for dealing with the players
|
|
|
|
#define SETPLAYERBRIGHTNESS(p,b) { \
|
|
(p)->nBright = b; \
|
|
}
|
|
|
|
#define NOTECURRENTPLAYERPOSITION(p) { \
|
|
(p)->nColumnOld = (p)->nColumn; \
|
|
(p)->nRowOld = (p)->nRow; \
|
|
}
|
|
|
|
#define SETPLAYER(p,x,y,b) { \
|
|
NOTECURRENTPLAYERPOSITION(p); \
|
|
if (x >= 0) { (p)->nColumn = (x) % SOCCER2_BLIP_COLUMNS; } \
|
|
if (y >= 0) { (p)->nRow = (y) % SOCCER2_BLIP_ROWS; } \
|
|
if (b >= 0) { (p)->nBright = b; }\
|
|
}
|
|
|
|
#define UNSETPLAYER(p) { \
|
|
(p)->nBright = BLIP_OFF; \
|
|
}
|
|
|
|
#define ISPLAYERMOVED(p) (((p)->nColumn != (p)->nColumnOld) || ((p)->nRow != (p)->nRowOld))
|
|
|
|
#define UNMOVEPLAYER(p) { \
|
|
(p)->nRow = (p)->nRowOld; \
|
|
(p)->nColumn = (p)->nColumnOld; \
|
|
}
|
|
|
|
#define ISPLAYEROFFSCREEN(p) (!VALID_COLUMN((p)->nColumn) || !VALID_ROW((p)->nRow))
|
|
|
|
#define ISPLAYERENABLED(p) \
|
|
((p)->nBright)
|
|
|
|
#define ISBALL(x,y) generic_check(&ball, x, y)
|
|
#define ISPLAYER(x,y) generic_check(&player, x, y)
|
|
#define ISRECEIVER(x,y) generic_check(&receiver, x, y)
|
|
#define ISGOALKEEPER(x,y) generic_check(&goalkeeper, x, y)
|
|
|
|
#define SET_BALLOUT(p) { ball_out.x = (p)->nColumnOld; ball_out.y = (p)->nRowOld; ball_out.side = Platform_Random(2); }
|
|
|
|
static BOOL generic_check(PLAYER *p, int x, int y)
|
|
{
|
|
if ((p->nColumn == x)
|
|
&& (p->nRow == y)
|
|
&& (p->nBright)){
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static BOOL ISDEFENSE(int x, int y)
|
|
{
|
|
for (int i=0; i<NUM_DEFENSEPLAYERS; i++){
|
|
if(generic_check(&defense[i],x,y) == TRUE) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static PLAYER *GETPLAYERAT(int x, int y)
|
|
{
|
|
if (generic_check(&ball, x, y))
|
|
return &ball;
|
|
|
|
if (generic_check(&player, x, y))
|
|
return &player;
|
|
|
|
if(generic_check(&receiver, x, y))
|
|
return &receiver;
|
|
|
|
if (generic_check(&goalkeeper, x, y))
|
|
return &goalkeeper;
|
|
|
|
for (int i=0; i<NUM_DEFENSEPLAYERS; i++) {
|
|
if(generic_check(&defense[i],x,y)) {
|
|
return &defense[i];
|
|
}
|
|
}
|
|
|
|
return (PLAYER *)NULL;
|
|
}
|
|
|
|
static BOOL ISOCCUPIED(int x, int y)
|
|
{
|
|
PLAYER *p;
|
|
|
|
p = GETPLAYERAT(x, y);
|
|
if( p == NULL || p == &ball)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
/* Not used (for now)
|
|
static int move_torow(PLAYER *p, int row, int flag)
|
|
{
|
|
int v = 0;
|
|
int c, rtn;
|
|
|
|
if(row == (p->nRow + 1)) {
|
|
v = 1;
|
|
}
|
|
else if(row == (p->nRow - 1)) {
|
|
v = -1;
|
|
}
|
|
else {
|
|
v = 0;
|
|
}
|
|
|
|
c = (flag) ? -1 : 1;
|
|
|
|
if(v != 0 && !ISOCCUPIED(p->nColumn,p->nRow+v)) {
|
|
rtn = p->nColumn;
|
|
}
|
|
else if(VALID_COLUMN(p->nColumn+c) && !ISOCCUPIED(p->nColumn+c,p->nRow+v)) {
|
|
rtn = p->nColumn+c;
|
|
}
|
|
else if(VALID_COLUMN(p->nColumn-c) && !ISOCCUPIED(p->nColumn-c,p->nRow+v)) {
|
|
rtn = p->nColumn-c;
|
|
}
|
|
else {
|
|
rtn = -1;
|
|
}
|
|
|
|
return rtn;
|
|
}
|
|
*/
|
|
static int move_tocol(PLAYER *p, int col, int flag)
|
|
{
|
|
int v = 0;
|
|
int r, rtn;
|
|
|
|
if(col == (p->nColumn + 1)) {
|
|
v = 1;
|
|
}
|
|
else if(col == (p->nColumn - 1)) {
|
|
v = -1;
|
|
}
|
|
else {
|
|
v = 0;
|
|
}
|
|
|
|
r = (flag) ? -1 : 1;
|
|
|
|
if(v != 0 && !ISOCCUPIED(p->nColumn+v,p->nRow)) {
|
|
rtn = p->nRow;
|
|
}
|
|
else if(VALID_ROW(p->nRow+r) && !ISOCCUPIED(p->nColumn+v,p->nRow+r)) {
|
|
rtn = p->nRow+r;
|
|
}
|
|
else if(VALID_ROW(p->nRow-r) && !ISOCCUPIED(p->nColumn+v,p->nRow-r)) {
|
|
rtn = p->nRow-r;
|
|
}
|
|
else {
|
|
rtn = -1;
|
|
}
|
|
return rtn;
|
|
}
|
|
|
|
static BOOL move_around(PLAYER *p)
|
|
{
|
|
int x, y;
|
|
int x1, y1;
|
|
|
|
for(x=0; x<SOCCER2_BLIP_COLUMNS; x++) {
|
|
x1 = (x + p->nColumn) % SOCCER2_BLIP_COLUMNS;
|
|
for(y=0; y<SOCCER2_BLIP_ROWS; y++) {
|
|
y1 = (y + p->nRow) % SOCCER2_BLIP_ROWS;
|
|
if(!ISOCCUPIED(x1,y1)) {
|
|
SETPLAYER(p, x1, y1, -1);
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static BOOL set_goalkeeper()
|
|
{
|
|
PLAYER *p;
|
|
int x;
|
|
|
|
if(nSector == 1 && bHomeTeam)
|
|
x = 0;
|
|
else if(nSector == 9 && !bHomeTeam)
|
|
x = 6;
|
|
else {
|
|
UNSETPLAYER(&goalkeeper);
|
|
return FALSE;
|
|
}
|
|
if( (p = GETPLAYERAT(x, 2)) != NULL ) {
|
|
move_around(p);
|
|
}
|
|
SETPLAYER(&goalkeeper,x, 2, BLIP_DIM);
|
|
return TRUE;
|
|
}
|
|
|
|
// finite state machine stuff
|
|
#define FSM_RUNNING(x) ((x == FSM_INPLAY) || (x == FSM_SHOOTING) || (x == FSM_GOAL) || (x == FSM_PASSING))
|
|
#define next_fsm(x) { if(FSM_RUNNING(x)) {fsm = x; nextFsm = FSM_INVALID; } else { fsm = FSM_WAITSCOREPRESS; nextFsm = x; } }
|
|
|
|
static void fsmKickoff();
|
|
static void fsmTurnover();
|
|
static void fsmThrowin();
|
|
static void fsmGoalKick();
|
|
static void fsmCornerKick();
|
|
static void fsmInPlay();
|
|
static void fsmPassing();
|
|
static void fsmShooting();
|
|
static void fsmGameOver();
|
|
static void fsmWaitScorePress();
|
|
static void fsmGoal();
|
|
|
|
enum FSM {
|
|
FSM_INVALID = -1,
|
|
FSM_KICKOFF = 0,
|
|
FSM_TURNOVER,
|
|
FSM_THROWIN,
|
|
FSM_GOALKICK,
|
|
FSM_CORNERKICK,
|
|
FSM_INPLAY,
|
|
FSM_PASSING,
|
|
FSM_SHOOTING,
|
|
FSM_GAMEOVER,
|
|
FSM_WAITSCOREPRESS,
|
|
FSM_GOAL
|
|
};
|
|
|
|
static enum FSM fsm, nextFsm;
|
|
|
|
typedef void (*FSMFCN)();
|
|
|
|
static FSMFCN fsmfcn[] = {
|
|
fsmKickoff,
|
|
fsmTurnover,
|
|
fsmThrowin,
|
|
fsmGoalKick,
|
|
fsmCornerKick,
|
|
fsmInPlay,
|
|
fsmPassing,
|
|
fsmShooting,
|
|
fsmGameOver,
|
|
fsmWaitScorePress,
|
|
fsmGoal
|
|
};
|
|
|
|
static int probability(int value)
|
|
{
|
|
int rtn;
|
|
|
|
rtn = (Platform_Random(100) <= ((value/4 * (nLevel + 1)) - Platform_Random(4 - nLevel))) ? 1 : 0;
|
|
|
|
return rtn;
|
|
}
|
|
|
|
static void lost_possession()
|
|
{
|
|
bHomeTeam = !bHomeTeam;
|
|
PlatformSetInput(bHomeTeam);
|
|
}
|
|
|
|
static void InitGame()
|
|
{
|
|
bHomeTeam = FALSE;
|
|
PlatformSetInput(bHomeTeam);
|
|
nHScore = 0;
|
|
nVScore = 0;
|
|
fGameTime = GAMETIME;
|
|
nHalf = 0;
|
|
bGameOver = FALSE;
|
|
nSector = 5;
|
|
bTeamMate = FALSE;
|
|
bTeamMateSet = FALSE;
|
|
bKickKey = FALSE;
|
|
|
|
next_fsm(FSM_INVALID);
|
|
}
|
|
|
|
static void DrawBlips()
|
|
{
|
|
static BOOL bBlink = FALSE;
|
|
int x, y, nBright;
|
|
|
|
for (int i=0; i<NUM_DEFENSEPLAYERS; i++){
|
|
if (defense[i].nBright != BLIP_OFF){
|
|
x = defense[i].nColumn;
|
|
y = defense[i].nRow;
|
|
nBright = defense[i].nBright;
|
|
Blips[x][y].state = nBright;
|
|
}
|
|
}
|
|
/* Player & receiver can overlap, then */
|
|
/* print receiver first, then player */
|
|
if (receiver.nBright != BLIP_OFF){
|
|
x = receiver.nColumn;
|
|
y = receiver.nRow;
|
|
nBright = receiver.nBright;
|
|
Blips[x][y].state = nBright;
|
|
}
|
|
if (player.nBright != BLIP_OFF){
|
|
x = player.nColumn;
|
|
y = player.nRow;
|
|
nBright = player.nBright;
|
|
Blips[x][y].state = nBright;
|
|
}
|
|
|
|
if (goalkeeper.nBright != BLIP_OFF){
|
|
x = goalkeeper.nColumn;
|
|
y = goalkeeper.nRow;
|
|
nBright = goalkeeper.nBright;
|
|
Blips[x][y].state = nBright;
|
|
}
|
|
/* Ball must be last */
|
|
if (ball.nBright != BLIP_OFF){
|
|
x = ball.nColumn;
|
|
y = ball.nRow;
|
|
nBright = ball.nBright;
|
|
Blips[x][y].state = nBright;
|
|
}
|
|
|
|
// draw the blips field
|
|
for (y = 0; y < SOCCER2_BLIP_ROWS; y++){
|
|
for (x = 0; x < SOCCER2_BLIP_COLUMNS; x++){
|
|
switch(Blips[x][y].state){
|
|
case BLIP_OFF:
|
|
case BLIP_DIM:
|
|
case BLIP_BRIGHT:
|
|
Soccer2_DrawBlip(Blips[x][y].state, x, y);
|
|
break;
|
|
case BLIP_DIMBLINK:
|
|
if (!bBlink){
|
|
Soccer2_DrawBlip(BLIP_DIM, x, y);
|
|
} else {
|
|
Soccer2_DrawBlip(BLIP_OFF, x, y);
|
|
}
|
|
break;
|
|
case BLIP_BRIGHTBLINK:
|
|
if (!bBlink){
|
|
Soccer2_DrawBlip(BLIP_BRIGHT, x, y);
|
|
} else {
|
|
Soccer2_DrawBlip(BLIP_OFF, x, y);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Soccer2_DrawGoalareaFlag(IS_GOALAREA() ? TRUE : FALSE);
|
|
|
|
bBlink = !bBlink;
|
|
}
|
|
|
|
static void EraseBlips()
|
|
{
|
|
int i;
|
|
|
|
// turn off all players
|
|
UNSETPLAYER(&ball);
|
|
UNSETPLAYER(&goalkeeper);
|
|
UNSETPLAYER(&player);
|
|
UNSETPLAYER(&receiver);
|
|
for(i=0; i<NUM_DEFENSEPLAYERS; i++)
|
|
UNSETPLAYER(&defense[i]);
|
|
}
|
|
|
|
static void swap_player(PLAYER *p1, PLAYER *p2)
|
|
{
|
|
PLAYER tmp;
|
|
|
|
tmp = *p1;
|
|
*p1 = *p2;
|
|
*p2 = tmp;
|
|
|
|
bTeamMate = FALSE;
|
|
bTeamMateSet = FALSE;
|
|
bKickKey = FALSE;
|
|
}
|
|
|
|
static void kickoff_scheme()
|
|
{
|
|
static SCHEME_t ko[2] = {
|
|
{ {3,2}, {3,3}, {{4,0}, {5,1}, {5,2}, {5,3}, {4,4}} },
|
|
{ {3,2}, {3,1}, {{2,0}, {1,1}, {1,2}, {1,3}, {2,4}} }
|
|
};
|
|
SCHEME_t *ps;
|
|
int i;
|
|
|
|
ps = &ko[bHomeTeam];
|
|
|
|
UNSETPLAYER(&ball);
|
|
UNSETPLAYER(&goalkeeper);
|
|
|
|
SETPLAYER(&player, ps->player.x, ps->player.y, BLIP_BRIGHT);
|
|
SETPLAYER(&receiver, ps->receiver.x, ps->receiver.y, BLIP_DIMBLINK);
|
|
for(i=0; i<NUM_DEFENSEPLAYERS; i++)
|
|
SETPLAYER(&defense[i], ps->defense[i].x, ps->defense[i].y, BLIP_DIM);
|
|
}
|
|
|
|
static void corner_scheme()
|
|
{
|
|
static SCHEME_t cl[2] = {
|
|
{ {6,0}, {6,1}, {{4,0}, {4,1}, {3,2}, {4,3}, {4,4}} },
|
|
{ {0,4}, {0,3}, {{2,0}, {2,1}, {3,2}, {2,3}, {2,4}} }
|
|
};
|
|
static SCHEME_t cr[2] = {
|
|
{ {6,4}, {6,3}, {{4,0}, {4,1}, {3,2}, {4,3}, {4,4}} },
|
|
{ {0,0}, {0,1}, {{2,0}, {2,1}, {3,2}, {2,3}, {2,4}} }
|
|
|
|
};
|
|
SCHEME_t *ps;
|
|
int i;
|
|
|
|
if(ball_out.x != 0 && ball_out.x != 6)
|
|
return;
|
|
|
|
if(ball_out.x == 0) {
|
|
if(ball_out.y < 3)
|
|
ps = &cr[1];
|
|
else if(ball_out.y > 3)
|
|
ps = &cl[1];
|
|
else
|
|
ps = ball_out.side ? &cr[1] : &cl[1];
|
|
}
|
|
else { /* x == 6 */
|
|
if(ball_out.y < 3)
|
|
ps = &cl[0];
|
|
else if(ball_out.y < 3)
|
|
ps = &cr[0];
|
|
else
|
|
ps = ball_out.side ? &cr[0] : &cl[0];
|
|
}
|
|
|
|
UNSETPLAYER(&ball);
|
|
|
|
SETPLAYER(&player, ps->player.x, ps->player.y, BLIP_BRIGHT);
|
|
SETPLAYER(&receiver, ps->receiver.x, ps->receiver.y, BLIP_DIMBLINK);
|
|
for(i=0; i<NUM_DEFENSEPLAYERS; i++)
|
|
SETPLAYER(&defense[i], ps->defense[i].x, ps->defense[i].y, BLIP_DIM);
|
|
|
|
set_goalkeeper();
|
|
}
|
|
|
|
static void throwin_scheme()
|
|
{
|
|
static SCHEME_t p[] = {
|
|
/* player receiver 0 1 2 3 4 */
|
|
{ {3,4}, {3,3}, {{1,3}, {2,2}, {3,2}, {4,2}, {5,3}} },
|
|
{ {2,4}, {2,3}, {{0,3}, {1,2}, {2,2}, {3,2}, {4,3}} },
|
|
{ {1,4}, {1,3}, {{0,2}, {1,2}, {2,2}, {3,3}, {3,4}} },
|
|
{ {0,4}, {0,3}, {{0,2}, {1,2}, {2,2}, {2,3}, {2,4}} },
|
|
{ {3,0}, {3,1}, {{1,1}, {2,2}, {3,2}, {4,2}, {5,1}} },
|
|
{ {2,0}, {2,1}, {{0,1}, {1,2}, {2,2}, {3,2}, {4,1}} },
|
|
{ {1,0}, {1,1}, {{0,2}, {1,2}, {2,2}, {3,1}, {3,0}} },
|
|
{ {0,0}, {0,1}, {{0,2}, {1,2}, {2,2}, {2,1}, {2,0}} },
|
|
{ {6,4}, {6,3}, {{6,2}, {5,2}, {4,2}, {4,3}, {4,4}} },
|
|
{ {5,4}, {5,3}, {{6,2}, {5,2}, {4,2}, {3,3}, {3,4}} },
|
|
{ {4,4}, {4,3}, {{6,3}, {5,2}, {4,2}, {3,2}, {2,3}} },
|
|
{ {6,0}, {6,1}, {{6,2}, {5,2}, {4,2}, {4,1}, {4,0}} },
|
|
{ {5,0}, {5,1}, {{6,2}, {5,2}, {4,2}, {3,1}, {3,0}} },
|
|
{ {4,0}, {4,1}, {{6,1}, {5,2}, {4,2}, {3,2}, {2,1}} },
|
|
};
|
|
int i;
|
|
|
|
UNSETPLAYER(&ball);
|
|
|
|
for(i=0; i<sizeof(p)/sizeof(*p); i++) {
|
|
if(p[i].player.x == ball_out.x && p[i].player.y == ball_out.y) {
|
|
int j;
|
|
|
|
SETPLAYER(&player, p[i].player.x, p[i].player.y, BLIP_BRIGHT);
|
|
SETPLAYER(&receiver,p[i].receiver.x , p[i].receiver.y, BLIP_DIMBLINK);
|
|
for(j=0; j<NUM_DEFENSEPLAYERS; j++)
|
|
SETPLAYER(&defense[j], p[i].defense[j].x, p[i].defense[j].y, BLIP_DIM);
|
|
|
|
set_goalkeeper();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void goalkick_scheme()
|
|
{
|
|
static SCHEME_t ko[2] = {
|
|
{ {0,2}, {2,2}, {{2,0}, {2,1}, {3,2}, {2,3}, {2,4}} },
|
|
{ {6,2}, {4,2}, {{4,0}, {4,1}, {3,2}, {4,3}, {4,4}} }
|
|
};
|
|
SCHEME_t *ps;
|
|
int i;
|
|
|
|
ps = &ko[bHomeTeam];
|
|
|
|
UNSETPLAYER(&ball);
|
|
UNSETPLAYER(&goalkeeper);
|
|
|
|
SETPLAYER(&player, ps->player.x, ps->player.y, BLIP_BRIGHT);
|
|
SETPLAYER(&receiver, ps->receiver.x, ps->receiver.y, BLIP_DIMBLINK);
|
|
for(i=0; i<NUM_DEFENSEPLAYERS; i++)
|
|
SETPLAYER(&defense[i], ps->defense[i].x, ps->defense[i].y, BLIP_DIM);
|
|
}
|
|
|
|
static void turnover_scheme()
|
|
{
|
|
int i;
|
|
|
|
UNSETPLAYER(&ball);
|
|
|
|
/* Swap blips specularly to middle line */
|
|
SETPLAYER(&player, SOCCER2_BLIP_COLUMNS - 1 - player.nColumn, player.nRow, BLIP_BRIGHT);
|
|
SETPLAYER(&receiver, SOCCER2_BLIP_COLUMNS - 1 - receiver.nColumn, receiver.nRow, BLIP_DIMBLINK);
|
|
for(i=0; i<NUM_DEFENSEPLAYERS; i++)
|
|
SETPLAYER(&defense[i], SOCCER2_BLIP_COLUMNS - 1 - defense[i].nColumn, defense[i].nRow, BLIP_DIM);
|
|
}
|
|
|
|
/* PLAYER *p; Player that make switch
|
|
* int x; Player column in the new scheme
|
|
* int y; Player line in the new scheme
|
|
*/
|
|
static void build_newsector(PLAYER *p, int x, int y)
|
|
{
|
|
if(IS_GOALAREA())
|
|
Soccer2_PlaySound(SOCCER2_SOUND_BEEP, PLAYSOUNDFLAGS_PRIORITY);
|
|
|
|
SETPLAYER(p, x, y, -1);
|
|
set_goalkeeper();
|
|
}
|
|
|
|
static BOOL MOVEAT(const PLAYER *p, int dx, int dy, int *nx, int *ny)
|
|
{
|
|
int x = 0;
|
|
int y = 0;
|
|
|
|
if(p->nColumn != dx) {
|
|
if(p->nColumn > dx && p->nColumn > 0)
|
|
x--;
|
|
else if(p->nColumn < dx && p->nColumn < SOCCER2_BLIP_COLUMNS-1)
|
|
x++;
|
|
}
|
|
|
|
if(p->nRow != dy) {
|
|
if(p->nRow > dy && p->nRow > 0)
|
|
y--;
|
|
else if(p->nRow < dy && p->nRow < SOCCER2_BLIP_ROWS-1)
|
|
y++;
|
|
}
|
|
|
|
*nx = p->nColumn + x;
|
|
*ny = p->nRow + y;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL IS_ALIGNED(const PLAYER *p1, const PLAYER *p2, int *dx, int *dy)
|
|
{
|
|
int x, y;
|
|
|
|
x = p2->nColumn - p1->nColumn;
|
|
y = p2->nRow - p1->nRow;
|
|
|
|
if(dx != NULL)
|
|
*dx = x;
|
|
if(dy != NULL)
|
|
*dy = y;
|
|
|
|
if((x == 0) || (y == 0) || (x == y))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static int moveCounterInit()
|
|
{
|
|
int rtn;
|
|
|
|
switch(nLevel) {
|
|
case LVL_ROOKIEFAST:
|
|
rtn = 8 + Platform_Random(12);
|
|
break;
|
|
case LVL_PROSLOW:
|
|
rtn = 4 + Platform_Random(8);
|
|
break;
|
|
case LVL_PROFAST:
|
|
rtn = Platform_Random(4);
|
|
break;
|
|
case LVL_ROOKIESLOW:
|
|
default:
|
|
rtn = 12 + Platform_Random(16);
|
|
break;
|
|
}
|
|
return rtn;
|
|
}
|
|
|
|
static enum FSM move_player(enum FSM curFsm)
|
|
{
|
|
enum FSM newFsm = FSM_INVALID;
|
|
BOOL bChange;
|
|
BOOL moved = FALSE;
|
|
BOOL newsect = FALSE;
|
|
int col, row;
|
|
PLAYER *p;
|
|
|
|
p = (bTeamMate || curFsm == FSM_PASSING) ? &receiver : &player;
|
|
|
|
NOTECURRENTPLAYERPOSITION(p);
|
|
col = p->nColumn;
|
|
row = p->nRow;
|
|
|
|
if (Soccer2_GetInputLEFTUP(&bChange)) {
|
|
if (bChange) {
|
|
col -= 1;
|
|
row -= 1;
|
|
moved = TRUE;
|
|
}
|
|
}
|
|
else if (Soccer2_GetInputLEFTDOWN(&bChange)) {
|
|
if (bChange) {
|
|
col -= 1;
|
|
row += 1;
|
|
moved = TRUE;
|
|
}
|
|
}
|
|
else if (Soccer2_GetInputRIGHTUP(&bChange)) {
|
|
if (bChange) {
|
|
col += 1;
|
|
row -= 1;
|
|
moved = TRUE;
|
|
}
|
|
}
|
|
else if (Soccer2_GetInputRIGHTDOWN(&bChange)) {
|
|
if (bChange) {
|
|
col += 1;
|
|
row += 1;
|
|
moved = TRUE;
|
|
}
|
|
}
|
|
else if (Soccer2_GetInputLEFT(&bChange)) {
|
|
if (bChange) {
|
|
col -= 1;
|
|
moved = TRUE;
|
|
}
|
|
}
|
|
else if (Soccer2_GetInputRIGHT(&bChange)) {
|
|
if (bChange) {
|
|
col += 1;
|
|
moved = TRUE;
|
|
}
|
|
}
|
|
else if (Soccer2_GetInputUP(&bChange)) {
|
|
if (bChange) {
|
|
row -= 1;
|
|
moved = TRUE;
|
|
}
|
|
}
|
|
else if (Soccer2_GetInputDOWN(&bChange)) {
|
|
if (bChange) {
|
|
row += 1;
|
|
moved = TRUE;
|
|
}
|
|
}
|
|
|
|
if(moved == FALSE)
|
|
return newFsm;
|
|
|
|
if(!VALID_COLUMN(col)) {
|
|
moved = FALSE;
|
|
|
|
/* Moves between sectors only if 'p' is the player and has the ball */
|
|
if (!ISPLAYERENABLED(&ball) && (p == &player)) {
|
|
if(col < 0) {
|
|
if(nSector == 1) {
|
|
SET_BALLOUT(p);
|
|
newFsm = (!bHomeTeam) ? FSM_CORNERKICK : FSM_GOALKICK;
|
|
lost_possession();
|
|
}
|
|
else if(nSector > 1) {
|
|
nSector--;
|
|
newsect = TRUE;
|
|
col = SOCCER2_BLIP_COLUMNS - 1;
|
|
moved = TRUE;
|
|
}
|
|
}
|
|
else if(col >= SOCCER2_BLIP_COLUMNS) {
|
|
if(nSector == 9) {
|
|
SET_BALLOUT(p);
|
|
newFsm = (!bHomeTeam) ? FSM_GOALKICK : FSM_CORNERKICK;
|
|
lost_possession();
|
|
}
|
|
else if(nSector < 9) {
|
|
nSector++;
|
|
newsect = TRUE;
|
|
col = 0;
|
|
moved = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!VALID_ROW(row)) {
|
|
moved = FALSE; /* Invalid move */
|
|
}
|
|
|
|
if(moved) {
|
|
if(newsect)
|
|
build_newsector(p, col, row);
|
|
else if(!ISOCCUPIED(col, row) ||
|
|
ISPLAYER(col,row) || ISRECEIVER(col,row)) {
|
|
SETPLAYER(p, col, row, -1);
|
|
if(bTeamMate) {
|
|
bTeamMateSet = TRUE;
|
|
}
|
|
}
|
|
else if(ISBALL(col,row)) {
|
|
UNSETPLAYER(&ball);
|
|
Soccer2_PlaySound(SOCCER2_SOUND_BOUNCE, PLAYSOUNDFLAGS_PRIORITY);
|
|
if(p == &receiver) {
|
|
swap_player(&player, &receiver);
|
|
}
|
|
SETPLAYER(&player, col, row, BLIP_BRIGHT);
|
|
SETPLAYERBRIGHTNESS(&receiver, BLIP_DIMBLINK);
|
|
}
|
|
newFsm = curFsm;
|
|
}
|
|
|
|
return newFsm;
|
|
}
|
|
|
|
static BOOL count_down()
|
|
{
|
|
// count down the clock
|
|
if (Platform_IsNewSecond()){
|
|
// check for end of quarter
|
|
if (fGameTime > 0.0){
|
|
fGameTime -= (int).1;
|
|
if (fGameTime < 0.1){
|
|
|
|
// end of quarter
|
|
++nHalf;
|
|
if (nHalf >= 2)
|
|
{
|
|
// game over
|
|
bGameOver = TRUE;
|
|
Soccer2_ClearScreen();
|
|
Soccer2_PlaySound(SOCCER2_SOUND_ENDGAME, PLAYSOUNDFLAGS_PRIORITY);
|
|
next_fsm(FSM_GAMEOVER);
|
|
return FALSE;
|
|
}
|
|
|
|
bHomeTeam = (nHalf % 2) ? FALSE : TRUE;
|
|
PlatformSetInput(bHomeTeam);
|
|
|
|
fGameTime = GAMETIME;
|
|
Soccer2_ClearScreen();
|
|
Soccer2_PlaySound(SOCCER2_SOUND_ENDHALF, PLAYSOUNDFLAGS_PRIORITY);
|
|
next_fsm(FSM_KICKOFF);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
Soccer2_DrawSect(nSector, bHomeTeam);
|
|
|
|
// make tick sounds
|
|
if (fGameTime >= .1){
|
|
if (--nTimerTickTimer <= 0){
|
|
Soccer2_PlaySound(SOCCER2_SOUND_TICK, PLAYSOUNDFLAGS_ASYNC);
|
|
nTimerTickTimer = TIME_TICKTIMER;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL move_receiver()
|
|
{
|
|
int x, y;
|
|
int dx, dy;
|
|
|
|
if(!ISPLAYERENABLED(&receiver)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if(bTeamMate || bTeamMateSet) {
|
|
return FALSE;
|
|
}
|
|
|
|
if(IS_ALIGNED(&receiver, &player, &dx, &dy)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if(receiver.nMoveNow-- > 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
x = receiver.nColumn;
|
|
y = receiver.nRow;
|
|
if(!bHomeTeam) {
|
|
if(dx < 0 && x < (SOCCER2_BLIP_COLUMNS - 1))
|
|
x++;
|
|
else if(x < (SOCCER2_BLIP_COLUMNS - 1))
|
|
x++;
|
|
}
|
|
else {
|
|
if(dx > 0 && x > 0)
|
|
x--;
|
|
else if(x > 0)
|
|
x--;
|
|
}
|
|
|
|
if(ISOCCUPIED(x, y)) {
|
|
int newy;
|
|
|
|
newy = move_tocol(&receiver, x, Platform_Random(2));
|
|
if(newy >= 0) {
|
|
y = newy;
|
|
}
|
|
else { /* Try move only on y axis */
|
|
x = receiver.nColumn;
|
|
newy = move_tocol(&receiver, x, Platform_Random(2));
|
|
if(newy >= 0) {
|
|
y = newy;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!ISOCCUPIED(x, y)) {
|
|
SETPLAYER(&receiver, x, y, BLIP_DIMBLINK);
|
|
receiver.nMoveNow = moveCounterInit();
|
|
return TRUE;
|
|
}
|
|
|
|
receiver.nMoveNow = 0; /* Try to move next time */
|
|
return FALSE;
|
|
}
|
|
|
|
static void initDefense()
|
|
{
|
|
int i;
|
|
|
|
for(i=0; i < NUM_DEFENSEPLAYERS; i++) {
|
|
defense[i].nMoveNow = moveCounterInit();
|
|
}
|
|
}
|
|
|
|
static BOOL passing()
|
|
{
|
|
int x, y;
|
|
|
|
if (ISPLAYERENABLED(&ball))
|
|
return FALSE;
|
|
|
|
Soccer2_PlaySound((bKickKey) ? SOCCER2_SOUND_LOWKICK : SOCCER2_SOUND_HIGHKICK, PLAYSOUNDFLAGS_PRIORITY);
|
|
|
|
y = player.nRow - receiver.nRow;
|
|
x = player.nColumn - receiver.nColumn;
|
|
|
|
if(abs(x) == abs(y)) {
|
|
if(y > 0)
|
|
nBallDirectionY = -1;
|
|
else if(y < 0)
|
|
nBallDirectionY = 1;
|
|
else
|
|
nBallDirectionY = 0;
|
|
|
|
if(x > 0)
|
|
nBallDirectionX = -1;
|
|
else if(x < 0)
|
|
nBallDirectionX = 1;
|
|
else
|
|
nBallDirectionX = 0;
|
|
}
|
|
else if(abs(x) > abs(y)) {
|
|
nBallDirectionY = 0;
|
|
if(x > 0)
|
|
nBallDirectionX = -1;
|
|
else if(x < 0)
|
|
nBallDirectionX = 1;
|
|
}
|
|
else {
|
|
nBallDirectionX = 0;
|
|
if(y > 0)
|
|
nBallDirectionY = -1;
|
|
else if(y < 0)
|
|
nBallDirectionY = 1;
|
|
}
|
|
|
|
SETPLAYER(&ball, player.nColumn, player.nRow, BLIP_BRIGHT);
|
|
UNSETPLAYER(&player);
|
|
|
|
nBallStep = 0;
|
|
nBallMax = (bKickKey) ? BALL_HIGHKICK : BALL_LOWKICK;
|
|
nTimerBallMove = TIME_BALLMOVE;
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL shooting()
|
|
{
|
|
if (ISPLAYERENABLED(&ball))
|
|
return FALSE;
|
|
|
|
Soccer2_PlaySound((bKickKey) ? SOCCER2_SOUND_LOWKICK : SOCCER2_SOUND_HIGHKICK, PLAYSOUNDFLAGS_PRIORITY);
|
|
|
|
nBallDirectionX = (!bHomeTeam) ? 1 : -1;
|
|
if(IS_ATTACKAREA()) {
|
|
if(player.nRow > 2)
|
|
nBallDirectionY = -1;
|
|
else if(player.nRow < 2)
|
|
nBallDirectionY = 1;
|
|
else
|
|
nBallDirectionY = 0;
|
|
}
|
|
else {
|
|
nBallDirectionY = 0;
|
|
}
|
|
|
|
SETPLAYER(&ball, player.nColumn, player.nRow, BLIP_BRIGHT);
|
|
|
|
UNSETPLAYER(&receiver);
|
|
SETPLAYERBRIGHTNESS(&player, BLIP_DIMBLINK);
|
|
|
|
nBallStep = 0;
|
|
nBallMax = (bKickKey) ? BALL_HIGHKICK : BALL_LOWKICK;
|
|
nTimerBallMove = TIME_BALLMOVE;
|
|
return TRUE;
|
|
}
|
|
|
|
static int bounce(enum FSM curFsm)
|
|
{
|
|
bBounce = TRUE;
|
|
|
|
/* On sector 1 or 9, on shoot or passage it can be corner kick */
|
|
if( IS_ATTACKAREA() ) {
|
|
if( (curFsm == FSM_SHOOTING) && probability(50) ) {
|
|
nBallDirectionX = (bHomeTeam) ? -1 : 1;
|
|
}
|
|
else if((curFsm == FSM_PASSING) && probability(25)) {
|
|
nBallDirectionX = (bHomeTeam) ? -1 : 1;
|
|
}
|
|
else {
|
|
nBallDirectionX = (bHomeTeam) ? 1 : -1;
|
|
}
|
|
}
|
|
else {
|
|
if((curFsm == FSM_PASSING) && probability(15))
|
|
nBallDirectionX = (bHomeTeam) ? -1 : 1;
|
|
else
|
|
nBallDirectionX = (bHomeTeam) ? 1 : -1;
|
|
}
|
|
|
|
if(probability(20))
|
|
nBallDirectionY = 0;
|
|
else if(probability(40))
|
|
nBallDirectionY = -1;
|
|
else if(probability(40))
|
|
nBallDirectionY = 1;
|
|
|
|
nBallStep = 0;
|
|
nBallMax = (Platform_Random(2)) ? BALL_HIGHKICK : BALL_LOWKICK;
|
|
Soccer2_PlaySound(SOCCER2_SOUND_BOUNCE, PLAYSOUNDFLAGS_PRIORITY);
|
|
|
|
SETPLAYERBRIGHTNESS(&player, BLIP_DIMBLINK);
|
|
SETPLAYERBRIGHTNESS(&receiver, BLIP_DIMBLINK);
|
|
nTimerBallMove = TIME_BALLMOVE;
|
|
return 0;
|
|
}
|
|
|
|
static enum FSM move_defense(enum FSM curFsm)
|
|
{
|
|
Coord_t gk = {0, 0};
|
|
Coord_t df[NUM_DEFENSEPLAYERS];
|
|
enum FSM newFsm = curFsm;
|
|
int i, nx, ny;
|
|
|
|
gk.x = goalkeeper.nColumn;
|
|
gk.y = goalkeeper.nRow;
|
|
for(i=0; i<NUM_DEFENSEPLAYERS; i++) {
|
|
df[i].x = defense[i].nColumn;
|
|
df[i].y = defense[i].nRow;
|
|
}
|
|
|
|
if (ISPLAYERENABLED(&ball)) {
|
|
if(ISPLAYERENABLED(&goalkeeper)) {
|
|
/* if the ball is near goalkeeper, he takes it */
|
|
if( ((!bHomeTeam && ball.nColumn == 6) || (bHomeTeam && ball.nColumn == 0)) &&
|
|
( ball.nRow > 0 && ball.nRow < 4)) {
|
|
gk.y = ball.nRow;
|
|
}
|
|
}
|
|
for(i=0; i<NUM_DEFENSEPLAYERS; i++) {
|
|
if(defense[i].nMoveNow-- <= 0) {
|
|
if(MOVEAT(&defense[i], ball.nColumn, ball.nRow, &nx, &ny) == TRUE) {
|
|
df[i].x = nx;
|
|
df[i].y = ny;
|
|
}
|
|
defense[i].nMoveNow = moveCounterInit();
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if(ISPLAYERENABLED(&goalkeeper)) {
|
|
if(goalkeeper.nMoveNow-- <= 0) {
|
|
goalkeeper.nMoveNow = moveCounterInit();
|
|
if((!bHomeTeam && player.nColumn == 6) || (bHomeTeam && player.nColumn == 0)) {
|
|
if(player.nRow < gk.y)
|
|
gk.y--;
|
|
else if(player.nRow > gk.y)
|
|
gk.y++;
|
|
}
|
|
else if(player.nRow > 0 && player.nRow < 4) {
|
|
if((!bHomeTeam && player.nColumn == 5) || (bHomeTeam && player.nColumn == 1)) {
|
|
gk.x = player.nColumn;
|
|
gk.y = player.nRow;
|
|
}
|
|
else {
|
|
gk.x = goalkeeper.nColumn;
|
|
gk.y = player.nRow;
|
|
}
|
|
}
|
|
else {
|
|
if(player.nRow == 2)
|
|
gk.y = 2;
|
|
else
|
|
gk.y = 2 + (player.nRow < 2) ? -1 : 1;
|
|
}
|
|
}
|
|
}
|
|
for(i=0; i<NUM_DEFENSEPLAYERS; i++) {
|
|
if(defense[i].nMoveNow-- <= 0) {
|
|
if(MOVEAT(&defense[i], player.nColumn, player.nRow, &nx, &ny) == TRUE) {
|
|
df[i].x = nx;
|
|
df[i].y = ny;
|
|
}
|
|
defense[i].nMoveNow = moveCounterInit();
|
|
}
|
|
}
|
|
}
|
|
|
|
if(ISPLAYERENABLED(&goalkeeper)) {
|
|
if(ISBALL(gk.x, gk.y)) {
|
|
SETPLAYER(&goalkeeper,gk.x, gk.y, BLIP_DIM);
|
|
if(probability(75)) {
|
|
UNSETPLAYER(&ball);
|
|
lost_possession();
|
|
newFsm = FSM_GOALKICK;
|
|
}
|
|
else {
|
|
bounce(curFsm);
|
|
newFsm = FSM_INPLAY;
|
|
}
|
|
}
|
|
else if(!ISPLAYERENABLED(&ball) && ISPLAYER(gk.x,gk.y)) {
|
|
if(probability(60)) {
|
|
lost_possession();
|
|
newFsm = FSM_GOALKICK;
|
|
}
|
|
}
|
|
if(!ISOCCUPIED(gk.x, gk.y)) {
|
|
SETPLAYER(&goalkeeper,gk.x, gk.y, BLIP_DIM);
|
|
}
|
|
}
|
|
|
|
for(i=0; i<NUM_DEFENSEPLAYERS; i++) {
|
|
if(ISBALL(df[i].x, df[i].y)) {
|
|
SETPLAYER(&defense[i], df[i].x, df[i].y, BLIP_DIM);
|
|
if(probability(75)) {
|
|
lost_possession();
|
|
newFsm = FSM_TURNOVER;
|
|
}
|
|
else {
|
|
bounce(curFsm);
|
|
newFsm = FSM_INPLAY;
|
|
}
|
|
}
|
|
/* a defensor can thieft the ball to the the captain? */
|
|
else if(IS_LVLPRO(nLevel) && !ISPLAYERENABLED(&ball) && ISPLAYER(df[i].x, df[i].y)) {
|
|
if(probability(40)) {
|
|
bounce(curFsm);
|
|
newFsm = FSM_INPLAY;
|
|
}
|
|
}
|
|
else if(!ISOCCUPIED(df[i].x, df[i].y))
|
|
SETPLAYER(&defense[i], df[i].x, df[i].y, BLIP_DIM);
|
|
}
|
|
|
|
return newFsm;
|
|
}
|
|
|
|
static enum FSM move_ball(enum FSM curFsm)
|
|
{
|
|
if (ISPLAYERENABLED(&ball)) {
|
|
if (--nTimerBallMove <= 0) {
|
|
Soccer2_PlaySound(SOCCER2_SOUND_LOOSEBALL, PLAYSOUNDFLAGS_ASYNC);
|
|
nTimerBallMove = TIME_BALLMOVE;
|
|
|
|
// ball stay
|
|
if(IS_LVLPRO(nLevel) && (nBallStep >= nBallMax)) {
|
|
SETPLAYERBRIGHTNESS(&player, BLIP_DIMBLINK);
|
|
SETPLAYERBRIGHTNESS(&receiver, BLIP_OFF);
|
|
bBounce = FALSE;
|
|
return FSM_INPLAY;
|
|
}
|
|
|
|
// move the ball
|
|
NOTECURRENTPLAYERPOSITION(&ball);
|
|
ball.nColumn += nBallDirectionX;
|
|
ball.nRow += nBallDirectionY;
|
|
nBallStep++;
|
|
|
|
/* Check if is off-screen */
|
|
if (ISPLAYEROFFSCREEN(&ball)) {
|
|
/* Choose throwin or goalkick */
|
|
if(!VALID_COLUMN(ball.nColumn)) {
|
|
if(nSector > 1 && nBallDirectionX < 0) {
|
|
if(nBallDirectionY == 0) {
|
|
nSector--;
|
|
build_newsector(&ball, SOCCER2_BLIP_COLUMNS - 1, ball.nRow);
|
|
}
|
|
else {
|
|
nBallStep = nBallMax;
|
|
ball.nColumn = 0;
|
|
ball.nRow = ball.nRowOld;
|
|
}
|
|
}
|
|
else if(nSector < 9 && nBallDirectionX > 0) {
|
|
if(nBallDirectionY == 0) {
|
|
nSector++;
|
|
build_newsector(&ball, 0, ball.nRow);
|
|
}
|
|
else {
|
|
nBallStep = nBallMax;
|
|
ball.nColumn = 6;
|
|
ball.nRow = ball.nRowOld;
|
|
}
|
|
}
|
|
else {
|
|
SET_BALLOUT(&ball);
|
|
UNSETPLAYER(&ball);
|
|
if(!bBounce) {
|
|
lost_possession();
|
|
return FSM_GOALKICK;
|
|
}
|
|
bBounce = FALSE;
|
|
return FSM_CORNERKICK;
|
|
}
|
|
}
|
|
if(!VALID_ROW(ball.nRow)) {
|
|
SET_BALLOUT(&ball);
|
|
UNSETPLAYER(&ball);
|
|
if(!bBounce) {
|
|
lost_possession();
|
|
}
|
|
else {
|
|
bBounce = FALSE;
|
|
}
|
|
return FSM_THROWIN;
|
|
}
|
|
}
|
|
/* Check if goal */
|
|
if(((fsm == FSM_SHOOTING) || (fsm == FSM_PASSING)) &&
|
|
((nSector == 1 && ball.nColumn == 0 && ball.nRow == 2) ||
|
|
(nSector == 9 && ball.nColumn == 6 && ball.nRow == 2))) {
|
|
bBounce = FALSE;
|
|
if(bKickKey == TRUE) {
|
|
if(ISGOALKEEPER(ball.nColumn,ball.nRow)) {
|
|
if(probability(70)) {
|
|
SET_BALLOUT(&ball);
|
|
lost_possession();
|
|
return FSM_GOALKICK;
|
|
}
|
|
}
|
|
else if(ISDEFENSE(ball.nColumn,ball.nRow)) {
|
|
if(probability(20)) {
|
|
bounce(curFsm);
|
|
return FSM_INPLAY;
|
|
}
|
|
return FSM_GOAL;
|
|
}
|
|
else if(probability(30)) {
|
|
SET_BALLOUT(&ball);
|
|
bBounce = FALSE;
|
|
lost_possession();
|
|
return FSM_GOALKICK;
|
|
}
|
|
return FSM_GOAL;
|
|
}
|
|
if (ISGOALKEEPER(ball.nColumn, ball.nRow)) {
|
|
lost_possession();
|
|
return FSM_GOALKICK;
|
|
}
|
|
return FSM_GOAL;
|
|
}
|
|
|
|
/* non goal */
|
|
if( (bKickKey == FALSE) ||
|
|
(bKickKey == TRUE && (nBallStep == 1 || nBallStep == nBallMax)) ) {
|
|
/* Check if bounced by defender or goalkeeper */
|
|
if (ISGOALKEEPER(ball.nColumn, ball.nRow)) {
|
|
if(curFsm == FSM_PASSING || probability(50)) {
|
|
SET_BALLOUT(&ball);
|
|
bBounce = FALSE;
|
|
lost_possession();
|
|
return FSM_GOALKICK;
|
|
}
|
|
bounce(curFsm);
|
|
return FSM_INPLAY;
|
|
}
|
|
if (ISDEFENSE(ball.nColumn, ball.nRow)) {
|
|
if(curFsm == FSM_PASSING) {
|
|
bounce(curFsm);
|
|
return FSM_INPLAY;
|
|
}
|
|
if(probability(50)) {
|
|
lost_possession();
|
|
return FSM_TURNOVER;
|
|
}
|
|
bounce(curFsm);
|
|
return FSM_INPLAY;
|
|
}
|
|
/* Check if receiver has gained possession */
|
|
if (ISRECEIVER(ball.nColumn, ball.nRow)) {
|
|
UNSETPLAYER(&ball);
|
|
bBounce = FALSE;
|
|
Soccer2_PlaySound(SOCCER2_SOUND_BOUNCE, PLAYSOUNDFLAGS_PRIORITY);
|
|
/* Swap player and receiver */
|
|
swap_player(&player, &receiver);
|
|
|
|
SETPLAYERBRIGHTNESS(&player, BLIP_BRIGHT);
|
|
SETPLAYERBRIGHTNESS(&receiver, BLIP_DIMBLINK);
|
|
return FSM_INPLAY;
|
|
}
|
|
}
|
|
|
|
/* Check if player has regained possession */
|
|
if (ISPLAYER(ball.nColumn, ball.nRow)) {
|
|
UNSETPLAYER(&ball);
|
|
bBounce = FALSE;
|
|
Soccer2_PlaySound(SOCCER2_SOUND_BOUNCE, PLAYSOUNDFLAGS_PRIORITY);
|
|
SETPLAYERBRIGHTNESS(&player, BLIP_BRIGHT);
|
|
SETPLAYERBRIGHTNESS(&receiver, BLIP_DIMBLINK);
|
|
return FSM_INPLAY;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
bBounce = FALSE;
|
|
}
|
|
return curFsm;
|
|
}
|
|
|
|
int Soccer2_GetPower()
|
|
{
|
|
return (bPower ? TRUE : FALSE);
|
|
}
|
|
|
|
void Soccer2_PowerOn()
|
|
{
|
|
if (!bPower)
|
|
{
|
|
InitGame();
|
|
bPower = TRUE;
|
|
}
|
|
}
|
|
|
|
void Soccer2_PowerOff()
|
|
{
|
|
bPower = FALSE;
|
|
Soccer2_StopSound();
|
|
}
|
|
|
|
void Soccer2_SetSkill(int i)
|
|
{
|
|
nLevel = i;
|
|
}
|
|
|
|
int Soccer2_GetSkill()
|
|
{
|
|
return nLevel;
|
|
}
|
|
|
|
void Soccer2_Run(int tu)
|
|
{
|
|
int x, y;
|
|
|
|
// prevent reentrancy
|
|
if (bInFrame){
|
|
return;
|
|
}
|
|
bInFrame = TRUE;
|
|
|
|
// turn off all blips
|
|
for (y = 0; y < SOCCER2_BLIP_ROWS; y++){
|
|
for (x = 0; x < SOCCER2_BLIP_COLUMNS; x++){
|
|
Blips[x][y].state = BLIP_OFF;
|
|
}
|
|
}
|
|
|
|
if (!bPower){
|
|
Soccer2_ClearScreen();
|
|
bInFrame = FALSE;
|
|
return;
|
|
}
|
|
|
|
Platform_StartDraw();
|
|
|
|
// run the game
|
|
(fsmfcn[fsm])();
|
|
|
|
DrawBlips();
|
|
|
|
Platform_EndDraw();
|
|
|
|
bInFrame = FALSE;
|
|
}
|
|
|
|
// FINITE STATE MACHINE STUFF
|
|
static void fsmWaitScorePress()
|
|
{
|
|
static BOOL pressed = FALSE;
|
|
BOOL bChange;
|
|
|
|
if(nextFsm == FSM_INVALID) {
|
|
kickoff_scheme();
|
|
nextFsm = FSM_KICKOFF;
|
|
}
|
|
|
|
if(pressed == FALSE) {
|
|
Soccer2_DrawSect(nSector, bHomeTeam);
|
|
if (Soccer2_GetInputSCORE(&bChange)) {
|
|
if (bChange) {
|
|
pressed = TRUE;
|
|
nStatsIndex = 0;
|
|
nTimerStatsDisplay = TIME_STATSDISPLAY;
|
|
if(nextFsm != FSM_KICKOFF)
|
|
EraseBlips();
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (--nTimerStatsDisplay <= 0)
|
|
{
|
|
++nStatsIndex;
|
|
nTimerStatsDisplay = TIME_STATSDISPLAY;
|
|
}
|
|
switch(nStatsIndex) {
|
|
case 0:
|
|
Soccer2_DrawStat(-1);
|
|
break;
|
|
case 1:
|
|
Soccer2_DrawStat(nVScore);
|
|
break;
|
|
case 2:
|
|
Soccer2_DrawStat(-1);
|
|
break;
|
|
case 3:
|
|
Soccer2_DrawStat(nHScore);
|
|
break;
|
|
case 4:
|
|
Soccer2_DrawStat(-1);
|
|
break;
|
|
case 5:
|
|
Soccer2_DrawStat((int)fGameTime);
|
|
break;
|
|
case 6:
|
|
Soccer2_DrawStat(-1);
|
|
break;
|
|
case 7:
|
|
Soccer2_DrawSect(nSector, bHomeTeam);
|
|
break;
|
|
default:
|
|
initDefense();
|
|
receiver.nMoveNow = moveCounterInit();
|
|
pressed = FALSE;
|
|
bTeamMate = FALSE;
|
|
bTeamMateSet = FALSE;
|
|
bKickKey = FALSE;
|
|
bBounce = FALSE;
|
|
fsm = nextFsm;
|
|
nextFsm = FSM_INVALID;
|
|
switch(fsm) {
|
|
case FSM_KICKOFF:
|
|
kickoff_scheme();
|
|
break;
|
|
case FSM_CORNERKICK:
|
|
corner_scheme();
|
|
break;
|
|
case FSM_GOALKICK:
|
|
goalkick_scheme();
|
|
break;
|
|
case FSM_THROWIN:
|
|
throwin_scheme();
|
|
break;
|
|
case FSM_TURNOVER:
|
|
turnover_scheme();
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void fsmKickoff()
|
|
{
|
|
BOOL bChange;
|
|
|
|
kickoff_scheme();
|
|
|
|
if(Soccer2_GetInputPASS(&bChange)) {
|
|
if (bChange) {
|
|
Platform_IsNewSecond();
|
|
if(passing() == TRUE) {
|
|
next_fsm(FSM_PASSING);
|
|
}
|
|
}
|
|
}
|
|
|
|
Soccer2_DrawSect(nSector, bHomeTeam);
|
|
}
|
|
|
|
static void fsmTurnover()
|
|
{
|
|
enum FSM newFsm;
|
|
|
|
newFsm = move_player(fsm);
|
|
if(newFsm != FSM_INVALID) {
|
|
Platform_IsNewSecond();
|
|
next_fsm(FSM_INPLAY);
|
|
}
|
|
}
|
|
|
|
static void fsmThrowin()
|
|
{
|
|
BOOL bChange;
|
|
|
|
if(Soccer2_GetInputPASS(&bChange)) {
|
|
if (bChange) {
|
|
Platform_IsNewSecond();
|
|
if(passing() == TRUE) {
|
|
next_fsm(FSM_PASSING);
|
|
}
|
|
}
|
|
}
|
|
if(IS_LVLPRO(nLevel)) {
|
|
if (Soccer2_GetInputTEAM(&bChange)) {
|
|
if (bChange) {
|
|
bTeamMate = !bTeamMate;
|
|
if(bTeamMate == TRUE)
|
|
Soccer2_PlaySound(SOCCER2_SOUND_BEEP, PLAYSOUNDFLAGS_PRIORITY);
|
|
}
|
|
}
|
|
if (Soccer2_GetInputSCORE(&bChange)) {
|
|
if (bChange) {
|
|
bTeamMateSet = FALSE;
|
|
}
|
|
}
|
|
/* Can move the receiver */
|
|
if(bTeamMate == TRUE) {
|
|
move_player(FSM_THROWIN);
|
|
}
|
|
}
|
|
Soccer2_DrawSect(nSector, bHomeTeam);
|
|
}
|
|
|
|
static void fsmGoalKick()
|
|
{
|
|
BOOL bChange;
|
|
|
|
if(Soccer2_GetInputPASS(&bChange)) {
|
|
if (bChange) {
|
|
Platform_IsNewSecond();
|
|
if(passing() == TRUE) {
|
|
next_fsm(FSM_PASSING);
|
|
}
|
|
}
|
|
}
|
|
|
|
Soccer2_DrawSect(nSector, bHomeTeam);
|
|
}
|
|
|
|
static void fsmCornerKick()
|
|
{
|
|
BOOL bChange;
|
|
|
|
if(Soccer2_GetInputPASS(&bChange)) {
|
|
if (bChange) {
|
|
Platform_IsNewSecond();
|
|
if(passing() == TRUE) {
|
|
next_fsm(FSM_PASSING);
|
|
}
|
|
}
|
|
}
|
|
if(IS_LVLPRO(nLevel)) {
|
|
if (Soccer2_GetInputTEAM(&bChange)) {
|
|
if (bChange) {
|
|
bTeamMate = !bTeamMate;
|
|
if(bTeamMate == TRUE)
|
|
Soccer2_PlaySound(SOCCER2_SOUND_BEEP, PLAYSOUNDFLAGS_PRIORITY);
|
|
}
|
|
}
|
|
if (Soccer2_GetInputSCORE(&bChange)) {
|
|
if (bChange) {
|
|
bTeamMateSet = FALSE;
|
|
}
|
|
}
|
|
/* Can move the receiver */
|
|
if(bTeamMate == TRUE) {
|
|
move_player(FSM_CORNERKICK);
|
|
}
|
|
}
|
|
|
|
Soccer2_DrawSect(nSector, bHomeTeam);
|
|
}
|
|
|
|
static void fsmInPlay()
|
|
{
|
|
enum FSM newFsm;
|
|
BOOL bChange;
|
|
|
|
newFsm = move_player(fsm);
|
|
if(newFsm == FSM_INVALID) {
|
|
if (Soccer2_GetInputSHOOT(&bChange)) {
|
|
if (bChange) {
|
|
if(shooting() == TRUE) {
|
|
next_fsm(FSM_SHOOTING);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Soccer2_GetInputPASS(&bChange)) {
|
|
if (bChange) {
|
|
if(passing() == TRUE) {
|
|
next_fsm(FSM_PASSING);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(IS_LVLPRO(nLevel)) {
|
|
if (Soccer2_GetInputTEAM(&bChange)) {
|
|
if (bChange) {
|
|
bTeamMate = !bTeamMate;
|
|
if(bTeamMate == TRUE)
|
|
Soccer2_PlaySound(SOCCER2_SOUND_BEEP, PLAYSOUNDFLAGS_PRIORITY);
|
|
}
|
|
}
|
|
if (Soccer2_GetInputSCORE(&bChange)) {
|
|
if (bChange) {
|
|
bTeamMateSet = FALSE;
|
|
}
|
|
}
|
|
if (Soccer2_GetInputKICK(&bChange)) {
|
|
if (bChange) {
|
|
bKickKey = !bKickKey;
|
|
Soccer2_PlaySound((bKickKey) ? SOCCER2_SOUND_LOWKICK : SOCCER2_SOUND_HIGHKICK, PLAYSOUNDFLAGS_PRIORITY);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(newFsm != FSM_INPLAY) {
|
|
if(!FSM_RUNNING(newFsm))
|
|
Soccer2_PlaySound(SOCCER2_SOUND_BALLOUT, PLAYSOUNDFLAGS_PRIORITY);
|
|
next_fsm(newFsm);
|
|
return;
|
|
}
|
|
|
|
// move the receiver
|
|
move_receiver();
|
|
|
|
// move defenders
|
|
newFsm = move_defense(fsm);
|
|
if(!FSM_RUNNING(newFsm))
|
|
Soccer2_PlaySound(SOCCER2_SOUND_BALLOUT, PLAYSOUNDFLAGS_PRIORITY);
|
|
next_fsm(newFsm);
|
|
|
|
// count down the clock
|
|
count_down();
|
|
}
|
|
|
|
static void fsmPassing()
|
|
{
|
|
enum FSM newFsm;
|
|
BOOL bChange;
|
|
|
|
newFsm = move_player(fsm);
|
|
if(newFsm == FSM_INVALID) {
|
|
if (Soccer2_GetInputKICK(&bChange) && IS_LVLPRO(nLevel)) {
|
|
if (bChange) {
|
|
bKickKey = !bKickKey;
|
|
Soccer2_PlaySound((bKickKey) ? SOCCER2_SOUND_LOWKICK : SOCCER2_SOUND_HIGHKICK, PLAYSOUNDFLAGS_PRIORITY);
|
|
}
|
|
}
|
|
}
|
|
else if(newFsm != FSM_PASSING) {
|
|
if(!FSM_RUNNING(newFsm))
|
|
Soccer2_PlaySound(SOCCER2_SOUND_BALLOUT, PLAYSOUNDFLAGS_PRIORITY);
|
|
next_fsm(newFsm);
|
|
return;
|
|
}
|
|
// move defenders
|
|
if(bKickKey) {
|
|
newFsm = move_defense(fsm);
|
|
if(!FSM_RUNNING(newFsm))
|
|
Soccer2_PlaySound(SOCCER2_SOUND_BALLOUT, PLAYSOUNDFLAGS_PRIORITY);
|
|
next_fsm(newFsm);
|
|
}
|
|
// move the ball
|
|
if(fsm == FSM_PASSING) {
|
|
newFsm = move_ball(fsm);
|
|
if(!FSM_RUNNING(newFsm))
|
|
Soccer2_PlaySound(SOCCER2_SOUND_BALLOUT, PLAYSOUNDFLAGS_PRIORITY);
|
|
next_fsm(newFsm);
|
|
}
|
|
|
|
// count down the clock
|
|
count_down();
|
|
}
|
|
|
|
static void fsmShooting()
|
|
{
|
|
enum FSM newFsm;
|
|
BOOL bChange;
|
|
|
|
newFsm = move_player(fsm);
|
|
if(newFsm == FSM_INVALID) {
|
|
if (Soccer2_GetInputKICK(&bChange) && IS_LVLPRO(nLevel)) {
|
|
if (bChange) {
|
|
bKickKey = !bKickKey;
|
|
Soccer2_PlaySound((bKickKey) ? SOCCER2_SOUND_LOWKICK : SOCCER2_SOUND_HIGHKICK, PLAYSOUNDFLAGS_PRIORITY);
|
|
}
|
|
}
|
|
}
|
|
else if(newFsm != FSM_SHOOTING) {
|
|
if(!FSM_RUNNING(newFsm))
|
|
Soccer2_PlaySound(SOCCER2_SOUND_BALLOUT, PLAYSOUNDFLAGS_PRIORITY);
|
|
next_fsm(newFsm);
|
|
return;
|
|
}
|
|
|
|
// move defenders
|
|
if(bKickKey) {
|
|
newFsm = move_defense(fsm);
|
|
if(!FSM_RUNNING(newFsm))
|
|
Soccer2_PlaySound(SOCCER2_SOUND_BALLOUT, PLAYSOUNDFLAGS_PRIORITY);
|
|
next_fsm(newFsm);
|
|
}
|
|
// move the ball
|
|
if(fsm == FSM_SHOOTING) {
|
|
newFsm = move_ball(fsm);
|
|
if(!FSM_RUNNING(newFsm))
|
|
Soccer2_PlaySound(SOCCER2_SOUND_BALLOUT, PLAYSOUNDFLAGS_PRIORITY);
|
|
next_fsm(newFsm);
|
|
}
|
|
|
|
// count down the clock
|
|
count_down();
|
|
}
|
|
|
|
static void fsmGameOver()
|
|
{
|
|
next_fsm(FSM_GAMEOVER);
|
|
}
|
|
|
|
static void fsmGoal()
|
|
{
|
|
Soccer2_PlaySound(SOCCER2_SOUND_GOAL, PLAYSOUNDFLAGS_PRIORITY);
|
|
if(!bHomeTeam)
|
|
nVScore++;
|
|
else
|
|
nHScore++;
|
|
nSector = 5;
|
|
lost_possession();
|
|
|
|
next_fsm(FSM_KICKOFF);
|
|
}
|
|
|
|
#define LINE_STEP 20
|
|
void Soccer2_Debug(int f)
|
|
{
|
|
int w, h;
|
|
int y = 0;
|
|
Soccer2_GetSize(&w, &h);
|
|
|
|
debugPrintf(realx(w)+10, realy(y), 0xFFFFFFFF, "level =%d", nLevel);
|
|
y += LINE_STEP;
|
|
debugPrintf(realx(w)+10, realy(y), 0xFFFFFFFF, "fsm =%d (%d)", fsm, FSM_RUNNING(fsm));
|
|
y += LINE_STEP;
|
|
debugPrintf(realx(w)+10, realy(y), 0xFFFFFFFF, "nx fsm =%d (%d)", nextFsm, FSM_RUNNING(nextFsm));
|
|
y += LINE_STEP;
|
|
debugPrintf(realx(w)+10, realy(y), 0xFFFFFFFF, "bnc=%d kk=%d",
|
|
bBounce, bKickKey);
|
|
y += LINE_STEP;
|
|
debugPrintf(realx(w)+10, realy(y), 0xFFFFFFFF, "tm=%d tms=%d",
|
|
bTeamMate, bTeamMateSet);
|
|
y += LINE_STEP;
|
|
debugPrintf(realx(w)+10, realy(y), 0xFFFFFFFF, "trc =%d", trc_debug);
|
|
y += LINE_STEP;
|
|
debugPrintf(realx(w)+10, realy(y), 0xFFFFFFFF, "ball =%d (%d,%d)(%d,%d)",
|
|
ball.nBright, ball.nColumn, ball.nRow, ball.nColumnOld, ball.nRowOld);
|
|
y += LINE_STEP;
|
|
debugPrintf(realx(w)+10, realy(y), 0xFFFFFFFF, "play =%d (%d,%d)(%d,%d)",
|
|
player.nBright, player.nColumn, player.nRow, player.nColumnOld, player.nRowOld);
|
|
y += LINE_STEP;
|
|
debugPrintf(realx(w)+10, realy(y), 0xFFFFFFFF, "recv =%d (%d,%d)(%d,%d)",
|
|
receiver.nBright, receiver.nColumn, receiver.nRow, receiver.nColumnOld, receiver.nRowOld);
|
|
y += LINE_STEP;
|
|
}
|