gh/game_m.pas

394 lines
9.5 KiB
ObjectPascal
Raw Normal View History

2026-01-10 07:09:22 +00:00
{ MainLoop -- main loop }
unit game_m;
interface
uses level_m, enemy_packs_m;
type
state = (
gameLevelAnnounce, gameExit, gameMenu, gameStartLevel, gameKeyInfo,
gamePause, gameUnpauseLevel, gameOver, gameComplete,
gameLevelComplete, gameLevelLoop, gameContinueLevel
);
menuState = (menuNewGame, menuKeyInfo, menuContinue);
gameState = record
curExit: boolean;
curMenu: menuState;
curState: state;
level, score, life: integer;
enemyPack: enemyPackType;
shutdown, newGame, unpause, levelInited, skipScene: boolean;
end;
procedure InitGame(var g: gameState);
procedure MainLoop(var g: gameState);
procedure NextExitState(var g: gameState);
procedure PreviousExitState(var g: gameState);
implementation
uses arena_m, arena_graphics_m, crt, creature_m, graphics_m, hamster_m,
keys_m, debug_m;
const
KeyDelayMs = 25;
MoveDelayMs = 120;
EraseLifeThreshold = 10;
AnnounceDelayMs = 1500;
LevelCompleteDelayMs = 1500;
LevelCount = 2;
StartLifeN = 3;
procedure DecreaseLife(var life: integer);
begin
if life = EraseLifeThreshold then
EraseLifesNumber(life);
life := life - 1;
DrawLifesNumber(life)
end;
procedure InitGame(var g: gameState);
begin
g.curMenu := menuNewGame;
g.curState := gameMenu;
g.enemyPack := enemyPack1;
g.score := 0;
g.shutdown := false;
g.newGame := false;
g.skipScene := false;
g.life := StartLifeN
end;
procedure RunExitState(var g: gameState; var level: levelState);
begin
DrawExit(g);
while (g.curState = gameExit) and not g.shutdown do
begin
delay(KeyDelayMs);
if keypressed then
HandleKey(g, level)
end;
EraseExit
end;
procedure RunInfoState(var g: gameState; var level: levelState);
begin
DrawKeyInfo;
while (g.curState = gameKeyInfo) and not g.shutdown do
begin
delay(KeyDelayMs);
if keypressed then
HandleKey(g, level)
end;
EraseKeyInfo
end;
procedure RunPauseState(var g: gameState; var level: levelState);
begin
DrawPause;
while (g.curState = gamePause) and not g.shutdown do
begin
delay(KeyDelayMs);
if keypressed then
HandleKey(g, level)
end;
if g.curState = gameMenu then
EraseLevel;
if g.curState = gameUnpauseLevel then
begin
DrawLevelUnpause(level);
level.unpause := true
end
end;
procedure RunGameOverState(var g: gameState; var level: levelState);
begin
DrawGameOver;
DisposeCreatureList(level.enemyList);
g.score := 0;
g.life := StartLifeN;
while (g.curState = gameOver) and not g.shutdown do
begin
delay(KeyDelayMs);
if keypressed then
HandleKey(g, level)
end;
EraseGameOver;
if g.curState = gameLevelAnnounce then
begin
InitLevel(level, enemyPack1)
end
else
begin
g.levelInited := false;
DisposeCreatureList(level.enemyList)
end;
end;
procedure GameCutPart(var g: gameState; var level: levelState);
var
beforeCut: integer;
begin
beforeCut := level.cut;
SetArenaBorder(level.t, level.a);
ArenaCutPart(level.h, level.t, level.cut, level.a);
FillCompleteBar(level.cut);
g.score := g.score + (level.cut - beforeCut);
DrawScore(g.score)
end;
procedure GameNextLevel(var g: gameState; var level: levelState);
begin
g.level := g.level + 1;
DisposeCreatureList(level.enemyList);
if g.level > LevelCount then
begin
g.levelInited := false;
g.curState := gameComplete
end
else
begin
g.curState := gameLevelComplete
end
end;
procedure GameKillHamster(var g: gameState; var level: levelState);
begin
if g.life <= 0 then
begin
g.curState := gameOver;
Exit
end;
DecreaseLife(g.life);
KillHamster(level.h, level.t, level.a);
DrawAliveEnemies(level.enemyList);
level.h.alive := true
end;
procedure PollGameKeys(var g: gameState; var level: levelState);
var
i: integer;
begin
for i := 1 to (MoveDelayMs div KeyDelayMs) do
begin
delay(KeyDelayMs);
if keypressed then
HandleKey(g, level);
if g.curState = gamePause then
break
end
end;
procedure MakeEnemyTurnStages(var level: levelState);
begin
KillCapturedEnemies(level.a, level.enemyList);
TurnStubbornEnemies(level.a, level.enemyList);
EraseEnemies(level.a, level.enemyList);
MakeEnemySteps(level.a, level.h, level.t, level.enemyList);
UpdateEnemyStates(level.enemyList);
DrawAliveEnemies(level.enemyList)
end;
procedure MakeHamsterTurnStages(var g: gameState; var level: levelState);
begin
if not level.h.alive then
GameKillHamster(g, level);
if g.curState = gameOver then
exit;
if not HamsterStepPossible(level.h, level.t, level.a) then
StopCreature(level.h);
if not ((level.h.dX = 0) and (level.h.dY = 0)) then
MakeHamsterStep(level.h, level.t, level.a);
DrawCreature(level.h)
end;
procedure LevelLoop(var g: gameState; var level: levelState);
begin
while (g.curState = gameLevelLoop) and not g.shutdown do
begin
PollGameKeys(g, level);
if g.curState = gamePause then
break;
if ArenaSplited(level.h, level.t, level.a) then
GameCutPart(g, level);
if IsLevelComplete(level) then
begin
GameNextLevel(g, level);
if g.curState = gameComplete then
EraseLevel;
break
end;
MakeEnemyTurnStages(level);
MakeHamsterTurnStages(g, level);
if g.curState = gameOver then
begin
EraseLevel;
break
end
end
end;
procedure RunLevelState(var g: gameState; var level: levelState);
begin
if g.newGame then
begin
g.levelInited := true;
g.level := 1;
g.life := StartLifeN;
g.newGame := false;
g.score := 0
end;
g.curState := gameLevelLoop;
InitLevel(level, enemyPack1);
DrawLevel(level, g.life, g.score);
LevelLoop(g, level)
end;
procedure UnpauseLevel(var g: gameState; var level: levelState);
begin
if level.unpause then
level.unpause := false
else
DrawLevel(level, g.life, g.score);
g.curState := gameLevelLoop;
LevelLoop(g, level)
end;
procedure ContinueLevel(var g: gameState; var level: levelState);
begin
DrawLevel(level, g.life, g.score);
g.curState := gamePause
end;
procedure RunMenuState(var g: gameState; var level: levelState);
var
prevMenu: boolean = false;
begin
g.curState := gameMenu;
while (g.curState = gameMenu) and not g.shutdown do
begin
if (g.curState = gameMenu) and not prevMenu then
begin
DrawMenu(g);
prevMenu := true
end;
delay(KeyDelayMs);
if keypressed then
HandleKey(g, level);
if (g.curState <> gameMenu) and prevMenu then
begin
EraseMenu;
prevMenu := false
end;
if (g.curState <> gameMenu) then
if g.shutdown then
break
end
end;
procedure RunAnnounceState(var g: gameState; var level: levelState);
var
i: integer;
begin
DrawAnnounce(g.level);
for i := 1 to AnnounceDelayMs div KeyDelayMs do
begin
delay(KeyDelayMs);
if keypressed then
HandleKey(g, level);
if g.shutdown then
exit;
if g.skipScene then
break
end;
g.skipScene := false;
g.curState := gameStartLevel;
EraseAnnounce(g.level)
end;
procedure RunLevelCompleteState(var g: gameState; var level: levelState);
var
i: integer;
begin
FillCellsCapture(level.a);
DrawCreature(level.h);
for i := 1 to LevelCompleteDelayMs div KeyDelayMs do
begin
delay(KeyDelayMs);
if keypressed then
HandleKey(g, level);
if g.shutdown then
exit;
if g.skipScene then
break
end;
g.skipScene := false;
g.curState := gameLevelAnnounce;
EraseLevel
end;
procedure RunGameCompleteState(var g: gameState; var level: levelState);
begin
DrawGameComplete(g.score);
while (g.curState = gameComplete) and not g.shutdown do
begin
delay(KeyDelayMs);
if keypressed then
HandleKey(g, level)
end;
EraseLevel
end;
procedure MainLoop(var g: gameState);
var
level: levelState;
begin
while not g.shutdown do
case g.curState of
gameLevelAnnounce:
RunAnnounceState(g, level);
gameExit:
RunExitState(g, level);
gameKeyInfo:
RunInfoState(g, level);
gamePause:
RunPauseState(g, level);
gameStartLevel:
RunLevelState(g, level);
gameUnpauseLevel:
UnpauseLevel(g, level);
gameContinueLevel:
ContinueLevel(g, level);
gameOver:
RunGameOverState(g, level);
gameMenu:
RunMenuState(g, level);
gameLevelComplete:
RunLevelCompleteState(g, level);
gameComplete:
RunGameCompleteState(g, level)
end;
EraseAll
end;
procedure NextExitState(var g: gameState);
begin
if not g.curExit then
g.curExit := true
else
g.curExit := false
end;
procedure PreviousExitState(var g: gameState);
begin
if g.curExit then
g.curExit := false
else
g.curExit := true
end;
end.