Blame |
Last modification |
View Log
| RSS feed
unit app_game_main;
interface
uses sux_constant, sux_object, app_constant,
app_game_player, resource_list, app_entity_main, app_game_highscore,
app_particle_main, Bass;
type
TSState = record
state: SXState;
timer: SXFloat;
nextballdirection: SXFloat;
soundtimer: SXFloat;
nextpoweruptimer: SXFloat;
paused: SXBool;
end;
TSMenu = record
selection: SXInt;
joypadrepresstimer: SXFloat;
end;
TSHelpScreen = record
comefromstate: SXState;
end;
TSHighScore = record
name: SXStringL;
cursorpos: SXInt;
playerindex: SXInt;
score: SXInt;
end;
TSEffects = record
pixel: SXFloat;
flowers: SXFloat;
slowmotion: SXFloat;
createcrystals: SXInt;
concave: SXFloat;
end;
TSMusic = record
timer: SXFloat;
length: SXFloat;
end;
TSettings = record
player1, player2: SAGPlayer;
game: SXState;
state: TSState;
menu: TSMenu;
helpscreen: TSHelpScreen;
highscore: TSHighScore;
effects: TSEffects;
music: TSMusic;
end;
SAGame=class(SUXObject)
settings: TSettings;
entities: SRList;
particlesystems: SRList;
highscore: SAGHighScore;
procedure setGameState(state: SXState);
function getGameTimer:SXFloat;
function isGameInProgress:SXBool;
function getPlayer1:SAGPlayer;
function getPlayer2:SAGPlayer;
function getPlayer(player:SXInt):SAGPlayer;
function createEntity(typus:SXState):SAEntity;
function getEntity(index:SXInt):SAEntity;
procedure deleteEntity(entity:SAEntity);
function createParticleSystem(const typus: SXState): SAParticle;
function getParticleSystem(const index: SXInt): SAParticle;
procedure deleteParticleSystem(const particlesystem: SAParticle);
procedure restartGame;
procedure playerGainsScore(player:SXInt;typeofscore:SXState);
procedure startSingePlayerGame;
procedure startLocalMultiPlayerGame;
procedure startNetworkGameAsServer;
procedure startNetworkGameAsClient;
procedure endCurrentGame;
procedure openHelpScreen;
procedure openHintScreen;
procedure openEnterHighScore;
procedure playerEnterHighScore(const playerindex: SXInt; const score: SXInt);
procedure getKeyPressed(const key: Char);
procedure onTimerMusic;
procedure onTimerSpawnPowerUp;
procedure onTimerEffects;
procedure onTimerEntities;
procedure onTimerParticleSystems;
procedure onTimerPlay;
procedure onTimerWaitForBall;
procedure onTimerMenu;
procedure onTimerHelpScreen;
procedure onTimerViewHighScore;
procedure onTimerEnterHighScore;
procedure onTimer;
procedure initialize(const startimmediately: SXBool);
constructor Create(parent:TObject);
destructor Destroy; override;
end;
implementation
uses main, app_entity_paddle, app_entity_ball, app_entity_impact,
app_entity_trail, app_entity_warp, app_entity_crystal, app_entity_powerup,
app_particle_ballsparks, app_particle_crystalshards,
app_particle_powerupappears, app_particle_flowers;
// --- SAGame
procedure SAGame.setGameState(state: SXState);
begin
if (state = SX_GAME_STATE_HELPSCREEN) or (state = SX_GAME_STATE_HINTSCREEN) then
settings.helpscreen.comefromstate := settings.state.state;
settings.state.state:=state;
settings.state.timer:=0;
settings.menu.joypadrepresstimer := 0;
if (state = SX_GAME_STATE_MENU) then app.scene.flash.displayMenuFlash;
end;
function SAGame.getGameTimer:SXFloat;
begin
result:=settings.state.timer;
end;
function SAGame.isGameInProgress:SXBool;
begin
result:=(settings.game<>SX_NONE);
end;
function SAGame.getPlayer1:SAGPlayer;
begin
result:=settings.player1;
end;
function SAGame.getPlayer2:SAGPlayer;
begin
result:=settings.player2;
end;
function SAGame.getPlayer(player:SXInt):SAGPlayer;
begin
case player of
1 : result:=settings.player1;
2 : result:=settings.player2;
else
result:=nil;
end;
end;
function SAGame.createEntity(typus:SXState):SAEntity;
var entity:SAEntity;
begin
case typus of
SX_ENTITY_PADDLE : entity := SAEPaddle.Create(self);
SX_ENTITY_BALL : entity := SAEBall.Create(self);
SX_ENTITY_IMPACT : entity := SAEImpact.Create(self);
SX_ENTITY_TRAIL : entity := SAETrail.Create(self);
SX_ENTITY_WARP : entity := SAEWarp.Create(self);
SX_ENTITY_CRYSTAL : entity := SAECrystal.Create(self);
SX_ENTITY_POWERUP : entity := SAEPowerUp.Create(self);
else
entity:=SAEntity.Create(self);
end;
entity.settings.typus:=typus;
entities.addObject(entity);
result:=entity;
end;
function SAGame.getEntity(index:SXInt):SAEntity;
begin
result:=SAEntity(entities.getObject(index));
end;
procedure SAGame.deleteEntity(entity:SAEntity);
begin
entities.deleteObject(entity);
end;
function SAGame.createParticleSystem(const typus: SXState): SAParticle;
var particle: SAParticle;
begin
case typus of
SX_PARTICLESYSTEM_BALLSPARKS : particle := SAPBallSparks.Create(self);
SX_PARTICLESYSTEM_CRYSTALSHARDS : particle := SAPCrystalShards.Create(self);
SX_PARTICLESYSTEM_POWERUPAPPEARS : particle := SAPPowerUpAppears.Create(self);
SX_PARTICLESYSTEM_FLOWERS : particle := SAPFlowers.Create(self);
else
particle := SAParticle.Create(self);
end;
particle.settings.typus := typus;
particlesystems.addObject(particle);
result := particle;
end;
function SAGame.getParticleSystem(const index: SXInt): SAParticle;
begin
result := SAParticle(particlesystems.getObject(index));
end;
procedure SAGame.deleteParticleSystem(const particlesystem: SAParticle);
begin
particlesystems.deleteObject(particlesystem);
end;
procedure SAGame.restartGame;
var paddle:SAEPaddle;
begin
// Delete all previous entities
entities.deleteAllObjects;
particlesystems.deleteAllObjects;
// Create new entities for the players
paddle:=SAEPaddle(createEntity(SX_ENTITY_PADDLE));
paddle.connectToPlayer(1);
paddle:=SAEPaddle(createEntity(SX_ENTITY_PADDLE));
paddle.connectToPlayer(2);
// The two players wait for a ball
setGameState(SX_GAME_STATE_WAITFORBALL);
settings.state.nextballdirection:=270;
settings.effects.pixel := 0;
settings.effects.flowers := 0;
settings.effects.slowmotion := 0;
settings.effects.createcrystals := 0;
settings.effects.concave := 0;
settings.state.paused := false;
end;
procedure SAGame.playerGainsScore(player:SXInt;typeofscore:SXState);
begin
getPlayer(player).gainScore;
setGameState(SX_GAME_STATE_WAITFORBALL);
app.scene.flash.displayGainScore(typeofscore);
inc(app.settings.score);
if (player=1) then settings.state.nextballdirection:=90;
if (player=2) then settings.state.nextballdirection:=270;
end;
procedure SAGame.startSingePlayerGame;
begin
endCurrentGame;
settings.game:=SX_GAME_SINGLEPLAYER;
settings.player1:=SAGPlayer.Create(self, 1, SX_PLAYER_CONTROL_CPU);
settings.player2:=SAGPlayer.Create(self, 2, SX_PLAYER_CONTROL_CPU);
restartGame;
settings.state.nextpoweruptimer := 0;
end;
procedure SAGame.startLocalMultiPlayerGame;
begin
endCurrentGame;
settings.game:=SX_GAME_LOCALMULTIPLAYER;
settings.player1:=SAGPlayer.Create(self, 1, SX_PLAYER_CONTROL_LOCAL);
settings.player2:=SAGPlayer.Create(self, 2, SX_PLAYER_CONTROL_LOCAL);
restartGame;
end;
procedure SAGame.startNetworkGameAsServer;
begin
endCurrentGame;
settings.game:=SX_GAME_NETWORK;
settings.player1:=SAGPlayer.Create(self, 1, SX_PLAYER_CONTROL_LOCAL);
settings.player2:=SAGPlayer.Create(self, 2, SX_PLAYER_CONTROL_NETWORK);
restartGame;
end;
procedure SAGame.startNetworkGameAsClient;
begin
endCurrentGame;
settings.game:=SX_GAME_NETWORK;
settings.player1:=SAGPlayer.Create(self, 1, SX_PLAYER_CONTROL_NETWORK);
settings.player2:=SAGPlayer.Create(self, 2, SX_PLAYER_CONTROL_LOCAL);
restartGame;
end;
procedure SAGame.endCurrentGame;
begin
entities.deleteAllObjects;
particlesystems.deleteAllObjects;
if (settings.player1<>nil) then settings.player1.Free;
if (settings.player2<>nil) then settings.player2.Free;
settings.player1:=nil;
settings.player2:=nil;
if (settings.game<>SX_NONE) then settings.game:=SX_NONE;
end;
procedure SAGame.openHelpScreen;
begin
setGameState(SX_GAME_STATE_HELPSCREEN);
end;
procedure SAGame.openHintScreen;
begin
setGameState(SX_GAME_STATE_HINTSCREEN);
end;
procedure SAGame.openEnterHighScore;
var position, score: SXInt;
begin
if (settings.player1 <> nil) then
if (settings.player1.isHumanPlayer) then
begin
score := settings.player1.settings.score;
position := highscore.getPositionForScore(score);
settings.player1.Free;
settings.player1 := nil;
if (position <> SX_NONE) then
begin
playerEnterHighScore(1, score);
exit;
end;
end;
if (settings.player2 <> nil) then
if (settings.player2.isHumanPlayer) then
begin
score := settings.player2.settings.score;
position := highscore.getPositionForScore(score);
settings.player2.Free;
settings.player2 := nil;
if (position <> SX_NONE) then
begin
playerEnterHighScore(2, score);
exit;
end;
end;
if (settings.state.state <> SX_GAME_STATE_ENTERHIGHSCORE) then
begin
setGameState(SX_GAME_STATE_MENU);
end else setGameState(SX_GAME_STATE_VIEWHIGHSCORE);
end;
procedure SAGame.playerEnterHighScore(const playerindex: SXInt; const score: SXInt);
begin
settings.highscore.name := '';
settings.highscore.cursorpos := 0;
settings.highscore.playerindex := playerindex;
settings.highscore.score := score;
setGameState(SX_GAME_STATE_ENTERHIGHSCORE);
end;
procedure SAGame.getKeyPressed(const key: Char);
begin
if (settings.state.state = SX_GAME_STATE_ENTERHIGHSCORE) then
begin
if (key = #13) then
begin
if (settings.highscore.cursorpos = 0) then settings.highscore.name := 'brak';
highscore.addEntry(settings.highscore.name, settings.highscore.score);
openEnterHighScore;
exit;
end;
if (key = #27) then
begin
setGameState(SX_GAME_STATE_MENU);
exit;
end;
// Backspace
if (key = #8) then
begin
if (settings.highscore.cursorpos > 0) then
begin
settings.highscore.name := sx.math.strings.deleteFromString(settings.highscore.name,
settings.highscore.cursorpos, settings.highscore.cursorpos);
dec(settings.highscore.cursorpos);
end;
exit;
end;
// Add letter to name
if (settings.highscore.cursorpos < 25) then
begin
inc(settings.highscore.cursorpos);
settings.highscore.name := sx.math.strings.insertSubString(
settings.highscore.name, key, settings.highscore.cursorpos);
end;
end;
end;
procedure SAGame.onTimerMusic;
var sam: BASS_SAMPLE;
backgroundmusic: SXBASSSample;
begin
if (not app.ini.settings.sound.backgroundmusic) then exit;
sx.timer.incTimer(settings.music.timer);
if (settings.music.timer > settings.music.length) then
begin
settings.music.timer := 0;
backgroundmusic := app.sound.getSound('sounds\hydrotopos').sound.index;
app.sound.playSample2D('sounds\hydrotopos');
BASS_SampleGetInfo(backgroundmusic, sam);
sam.volume := 50;
BASS_SampleSetInfo(backgroundmusic, sam);
settings.music.length := sam.length / sam.freq;
end;
end;
procedure SAGame.onTimerSpawnPowerUp;
var e: SXInt;
powerupspresent: SXInt;
begin
sx.timer.incTimer(settings.state.nextpoweruptimer);
if (settings.state.nextpoweruptimer > app.ini.settings.gameplay.poweruptimer) then
begin
settings.state.nextpoweruptimer := 0;
// Not more than 3 power ups may be present at the same time.
powerupspresent := 0;
for e := 0 to entities.getMax do
if (entities.getObject(e) is SAEPowerUp) then inc(powerupspresent);
if (powerupspresent >= app.ini.settings.gameplay.maximumpowerupspresent) then exit;
createEntity(SX_ENTITY_POWERUP);
end;
end;
procedure SAGame.onTimerEffects;
begin
sx.timer.decTimer(settings.effects.pixel);
sx.timer.decTimer(settings.effects.flowers);
sx.timer.decTimer(settings.effects.slowmotion);
sx.timer.decTimer(settings.effects.concave);
end;
procedure SAGame.onTimerEntities;
var e:SXInt;
begin
for e := entities.getMax downto 0 do
if (e <= entities.getMax) then
begin
getEntity(e).onTimer;
end;
end;
procedure SAGame.onTimerParticleSystems;
var p: SXInt;
begin
for p := particlesystems.getMax downto 0 do
if (p <= particlesystems.getMax) then
begin
getParticleSystem(p).onTimer;
end;
end;
procedure SAGame.onTimerPlay;
begin
if (not settings.state.paused) then
begin
if (settings.effects.slowmotion > 0) then sx.timer.setGameSpeed(0.5);
onTimerSpawnPowerUp;
onTimerEffects;
onTimerEntities;
onTimerParticleSystems;
end;
if (app.ini.settings.menu.candisplaymenu) then
begin
if (app.input.isPressedNow('Pause','Menu')) then settings.state.paused := not settings.state.paused;
if (app.input.isPressedNow('Quit','Menu')) then
begin
if (app.ini.settings.menu.canquit) then settings.menu.selection := SX_MENU_SELECTION_QUIT
else settings.menu.selection := SX_MENU_SELECTION_STARTGAME;
openEnterHighScore;
end;
// Enter help screen
if (app.input.isPressedNow('Help','Menu')) then openHelpScreen;
if (app.input.isPressedNow('Hint','Menu')) then openHintScreen;
end;
end;
procedure SAGame.onTimerWaitForBall;
var ball:SAEBall;
warp:SAEWarp;
begin
if (not settings.state.paused) then
begin
if (settings.effects.slowmotion > 0) then sx.timer.setGameSpeed(0.5);
onTimerSpawnPowerUp;
onTimerEffects;
onTimerEntities;
onTimerParticleSystems;
if (getGameTimer>=2.0) then
begin
// Spawn a ball
setGameState(SX_GAME_STATE_PLAY);
ball:=createEntity(SX_ENTITY_BALL) as SAEBall;
ball.setRotation(settings.state.nextballdirection);
ball.setSpeed(app.ini.settings.gameplay.ballstartspeed);
app.scene.flash.displayNewBall;
warp:=createEntity(SX_ENTITY_WARP) as SAEWarp;
warp.setSize(10,0.8);
warp:=createEntity(SX_ENTITY_WARP) as SAEWarp;
warp.setSize(20,0.6);
warp:=createEntity(SX_ENTITY_WARP) as SAEWarp;
warp.setSize(30,0.4);
warp:=createEntity(SX_ENTITY_WARP) as SAEWarp;
warp.setSize(40,0.2);
end;
end;
if (app.ini.settings.menu.candisplaymenu) then
begin
if (app.input.isPressedNow('Pause','Menu')) then settings.state.paused := not settings.state.paused;
if (app.input.isPressedNow('Quit','Menu')) then
begin
if (app.ini.settings.menu.canquit) then settings.menu.selection := SX_MENU_SELECTION_QUIT
else settings.menu.selection := SX_MENU_SELECTION_STARTGAME;
openEnterHighScore;
end;
// Enter help screen
if (app.input.isPressedNow('Help','Menu')) then openHelpScreen;
if (app.input.isPressedNow('Hint', 'Menu')) then openHintScreen;
end;
end;
procedure SAGame.onTimerMenu;
var pressedup, presseddown, pressedaccept: SXBool;
movement1, movement2: SXFloat;
joyindex: SXInt;
begin
sx.timer.decTimer(settings.menu.joypadrepresstimer);
if (sx.timer.exceedTimerValue(getGameTimer,0.1)) then app.sound.playSample2D('sounds\menuopen');
if (getGameTimer < 0.2) then exit;
// Navigate through the menu
movement1 := 0;
movement2 := 0;
pressedaccept := false;
pressedup := false;
presseddown := false;
if (app.input.isRePressed('Up','Menu'))
or (app.input.isRePressed('Up','Player1'))
or (app.input.isRePressed('Up','Player2')) then pressedup := true;
if (app.input.isRePressed('Down','Menu'))
or (app.input.isRePressed('Down','Player1'))
or (app.input.isRePressed('Down','Player2')) then presseddown := true;
if (app.input.isPressedNow('Accept','Menu')) then pressedaccept := true;
joyindex := app.ini.settings.player1.joypad - 1;
if (joyindex > SX_NONE) and (app.input.joysticks.maxjoystick >= joyindex) then
begin
movement1 := app.input.getJoystick(joyindex).getMovementY;
if (settings.menu.joypadrepresstimer <= 0) then
begin
if (movement1 < 0) then pressedup := true;
if (movement1 > 0) then presseddown := true;
if (movement1 <> 0) then settings.menu.joypadrepresstimer := 0.3;
end;
if (app.input.getJoystick(joyindex).getButtonPressed(SX_INPUT_JOYSTICK_BUTTON_0)) then pressedaccept := true;
end;
joyindex := app.ini.settings.player2.joypad - 1;
if (joyindex > SX_NONE) and (app.input.joysticks.maxjoystick >= joyindex) then
begin
movement2 := app.input.getJoystick(joyindex).getMovementY;
if (settings.menu.joypadrepresstimer <= 0) then
begin
if (movement2 < 0) then pressedup := true;
if (movement2 > 0) then presseddown := true;
if (movement2 <> 0) then settings.menu.joypadrepresstimer := 0.3;
end;
if (app.input.getJoystick(joyindex).getButtonPressed(SX_INPUT_JOYSTICK_BUTTON_0)) then pressedaccept := true;
end;
if (movement1 = 0) and (movement2 = 0) then settings.menu.joypadrepresstimer := 0;
if (pressedup) then
if (settings.menu.selection > 0) then
begin
app.sound.playSample2D('sounds\menumove');
dec(settings.menu.selection);
end;
if (presseddown) then
if (settings.menu.selection < 2) or ((app.ini.settings.menu.canquit) and (settings.menu.selection < 3)) then
begin
app.sound.playSample2D('sounds\menumove');
inc(settings.menu.selection);
end;
// Enter help screen
if (app.input.isPressedNow('Help','Menu')) then openHelpScreen;
if (app.input.isPressedNow('Hint', 'Menu')) then openHintScreen;
// Quit game
if (app.ini.settings.menu.canquit) then
if (app.input.isPressedNow('Quit','Menu')) then app.settings.close:=true;
// Select a menu option
if (pressedaccept) then
begin
app.sound.playSample2D('sounds\menuselect');
case settings.menu.selection of
SX_MENU_SELECTION_STARTGAME : startSingePlayerGame;
SX_MENU_SELECTION_HIGHSCORE : setGameState(SX_GAME_STATE_VIEWHIGHSCORE);
SX_MENU_SELECTION_HELP : openHelpScreen;
SX_MENU_SELECTION_QUIT : app.settings.close:=true;
end;
end;
end;
procedure SAGame.onTimerHelpScreen;
begin
if (sx.timer.exceedTimerValue(getGameTimer,0.1)) then app.sound.playSample2D('sounds\menuopen');
if (getGameTimer < 0.2) then exit;
// Go back to previous game state
if (app.input.isPressedNow('Help','Menu')) or (app.input.isPressedNow('Hint','Menu')) then
begin
app.sound.playSample2D('sounds\menuselect');
setGameState(settings.helpscreen.comefromstate);
end;
if (app.input.isPressedNow('Accept','Menu'))
or (app.input.isPressedNow('Quit','Menu')) then
begin
app.sound.playSample2D('sounds\menuselect');
setGameState(settings.helpscreen.comefromstate);
end;
end;
procedure SAGame.onTimerViewHighScore;
begin
if (sx.timer.exceedTimerValue(getGameTimer,0.1)) then app.sound.playSample2D('sounds\menuopen');
if (getGameTimer < 0.2) then exit;
// Go back to previous game state
if (app.input.isPressedNow('Accept','Menu'))
or (app.input.isPressedNow('Quit','Menu')) then
begin
app.sound.playSample2D('sounds\menuselect');
setGameState(SX_GAME_STATE_MENU);
end;
end;
procedure SAGame.onTimerEnterHighScore;
begin
if (sx.timer.exceedTimerValue(getGameTimer,0.1)) then app.sound.playSample2D('sounds\menuopen');
end;
procedure SAGame.onTimer;
begin
sx.timer.setGameSpeed(1);
if (settings.state.state > SX_GAME_STATE_WAITFORBALL) or (not settings.state.paused) then
begin
sx.timer.incTimer(settings.state.timer);
end;
case settings.state.state of
SX_GAME_STATE_PLAY : onTimerPlay;
SX_GAME_STATE_WAITFORBALL : onTimerWaitForBall;
SX_GAME_STATE_MENU : onTimerMenu;
SX_GAME_STATE_HELPSCREEN,
SX_GAME_STATE_HINTSCREEN : onTimerHelpScreen;
SX_GAME_STATE_VIEWHIGHSCORE : onTimerViewHighScore;
SX_GAME_STATE_ENTERHIGHSCORE : onTimerEnterHighScore;
end;
sx.timer.setGameSpeed(1);
onTimerMusic;
end;
procedure SAGame.initialize(const startimmediately: SXBool);
begin
highscore.initialize;
if (startimmediately) then
begin
startSingePlayerGame;
end else
begin
setGameState(SX_GAME_STATE_MENU);
end;
end;
constructor SAGame.Create(parent:TObject);
begin
inherited Create(parent,'Game');
settings.player1:=nil;
settings.player2:=nil;
settings.game:=SX_NONE;
settings.menu.selection:=0;
particlesystems := SRList.Create(self, false, true, true);
entities := SRList.Create(self, false, true, true);
setGameState(SX_NONE);
settings.state.soundtimer:=0;
settings.state.paused := false;
highscore := SAGHighScore.Create(self);
settings.music.timer := 0;
settings.music.length := -1;
end;
destructor SAGame.Destroy;
begin
endCurrentGame;
entities.Free;
particlesystems.Free;
highscore.Free;
inherited;
end;
end.