2026-02-28 10:57:08 +00:00
|
|
|
unit graphics_m;
|
|
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
2026-02-28 11:14:58 +00:00
|
|
|
uses arena_graphics_m, arena_m, creature_m, hamster_m, trace_m, game_m;
|
2026-02-28 10:57:08 +00:00
|
|
|
|
|
|
|
|
procedure DrawAfterStep(var cr: creature; var a: arena);
|
2026-02-28 11:05:48 +00:00
|
|
|
procedure DrawAfterStep(var hamster: creature; var t: tracePtr; var a: arena);
|
2026-02-28 10:57:08 +00:00
|
|
|
procedure DrawCreature(var cr: creature);
|
2026-02-28 11:25:06 +00:00
|
|
|
procedure DrawExitState(s: exitState);
|
|
|
|
|
procedure DrawExit(var g: gameState);
|
2026-02-28 11:28:22 +00:00
|
|
|
procedure DrawPause(var g: gameState);
|
|
|
|
|
procedure DrawInfo;
|
2026-02-28 11:25:06 +00:00
|
|
|
procedure DrawLifes(var g: GameState);
|
|
|
|
|
procedure DrawMenuState(s: menuState);
|
|
|
|
|
procedure DrawMenu(var g: gameState);
|
|
|
|
|
procedure DrawScore(var g: GameState);
|
2026-02-28 11:28:22 +00:00
|
|
|
procedure EraseAll;
|
2026-02-28 11:25:06 +00:00
|
|
|
procedure EraseExit;
|
|
|
|
|
procedure EraseExitState(s: exitState);
|
|
|
|
|
procedure EraseMenu;
|
|
|
|
|
procedure EraseMenuState(s: menuState);
|
2026-02-28 11:14:58 +00:00
|
|
|
procedure EraseStepTrace(var hamster: creature; t: tracePtr);
|
|
|
|
|
procedure EraseTrace(t: tracePtr; var a: arena);
|
2026-02-28 10:57:08 +00:00
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
|
2026-02-28 11:25:06 +00:00
|
|
|
uses crt, math_m, ascii_arts_m;
|
2026-02-28 10:57:08 +00:00
|
|
|
|
|
|
|
|
const
|
2026-02-28 11:25:06 +00:00
|
|
|
BigLetterWidth = 8;
|
|
|
|
|
DigitWidth = 6;
|
|
|
|
|
GameNameX = ScreenW * WidthCoefficient div 3 + 4;
|
|
|
|
|
GameNameY = 12;
|
|
|
|
|
NameHeightPadding = 8;
|
|
|
|
|
MenuHeightPadding = 2;
|
|
|
|
|
MenuWidthPadding = 4;
|
|
|
|
|
MenuHamsterX = GameNameX - HamsterWidth - MenuWidthPadding;
|
|
|
|
|
NewGameY = GameNameY + GameNameHeight + NameHeightPadding;
|
|
|
|
|
HighScoreY = NewGameY + NewGameHeight + MenuHeightPadding;
|
|
|
|
|
KeyInfoY = HighScoreY + HighScoreHeight;
|
|
|
|
|
ContinueY = KeyInfoY + KeyInfoHeight;
|
2026-02-28 11:14:58 +00:00
|
|
|
InterfaceMarginX = InterfaceCellW div 4;
|
2026-02-28 11:25:06 +00:00
|
|
|
InterfaceMarginY = InterfaceBarH div 4 + BorderSize + 1;
|
|
|
|
|
LetterWidth = 5;
|
|
|
|
|
Notation = 10;
|
|
|
|
|
PunctuationWidth = 3;
|
|
|
|
|
SpaceWidth = 3;
|
|
|
|
|
ExitGameY = ScreenH div 2 - ExitHeight - MenuHeightPadding;
|
|
|
|
|
ExitYesX = MenuHamsterX;
|
|
|
|
|
ExitYesY = ExitGameY + ExitHeight + MenuHeightPadding;
|
|
|
|
|
ExitNoX = ScreenW * WidthCoefficient - ExitYesX - NoWidth;
|
|
|
|
|
ExitHamsterY = ExitYesY;
|
|
|
|
|
HamsterYesX = ExitYesX - HamsterWidth - MenuWidthPadding;
|
|
|
|
|
HamsterNoX = ExitNoX - HamsterWidth - MenuWidthPadding;
|
2026-02-28 11:28:22 +00:00
|
|
|
PauseXMargin = 3 * WidthCoefficient;
|
|
|
|
|
PauseYMargin = 1;
|
2026-02-28 11:25:06 +00:00
|
|
|
var
|
|
|
|
|
firstMenuDraw: boolean = true;
|
2026-02-28 10:57:08 +00:00
|
|
|
|
2026-02-28 11:14:58 +00:00
|
|
|
procedure EraseTrace(t: tracePtr; var a: arena);
|
2026-02-28 10:57:08 +00:00
|
|
|
begin
|
2026-02-28 11:14:58 +00:00
|
|
|
while t <> nil do
|
2026-02-28 10:57:08 +00:00
|
|
|
begin
|
2026-02-28 11:14:58 +00:00
|
|
|
if t^.prev = nil then
|
|
|
|
|
DrawEdge(t^.x, t^.y, a)
|
|
|
|
|
else
|
|
|
|
|
DrawArenaCell(t^.x, t^.y, ArenaSymbol);
|
|
|
|
|
t := t^.prev
|
|
|
|
|
end
|
2026-02-28 10:57:08 +00:00
|
|
|
end;
|
|
|
|
|
|
2026-02-28 11:14:58 +00:00
|
|
|
procedure EraseStepTrace(var hamster: creature; t: tracePtr);
|
2026-02-28 10:57:08 +00:00
|
|
|
var
|
|
|
|
|
i: integer;
|
|
|
|
|
begin
|
2026-02-28 11:14:58 +00:00
|
|
|
for i := 1 to hamster.movespeed do
|
2026-02-28 10:57:08 +00:00
|
|
|
begin
|
|
|
|
|
DrawArenaCell(t^.x, t^.y, ArenaSymbol);
|
|
|
|
|
t := t^.prev
|
|
|
|
|
end;
|
|
|
|
|
if GetLength(t) = 1 then
|
|
|
|
|
begin
|
|
|
|
|
if IsOnEdge(hamster) then
|
|
|
|
|
DrawArenaCell(t^.x, t^.y, ArenaSymbol)
|
|
|
|
|
else
|
|
|
|
|
DrawArenaCell(t^.x, t^.y, BorderSymbol)
|
|
|
|
|
end
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure DrawCreature(var cr: creature);
|
|
|
|
|
begin
|
|
|
|
|
DrawArenaCell(cr.curX, cr.curY, cr.symbol)
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure
|
|
|
|
|
DrawPreviousCell(var hamster: creature; var t: tracePtr; var a: arena);
|
|
|
|
|
var
|
|
|
|
|
prevX, prevY: integer;
|
|
|
|
|
begin
|
|
|
|
|
prevX := hamster.curX - hamster.dX;
|
|
|
|
|
prevY := hamster.curY - hamster.dY;
|
|
|
|
|
if t = nil then
|
|
|
|
|
DrawEdge(prevX, prevY, a);
|
|
|
|
|
if (a.borders[prevX][prevY]) and (t = nil) then
|
|
|
|
|
DrawArenaCell(prevX, prevY, BorderSymbol)
|
|
|
|
|
end;
|
|
|
|
|
|
2026-02-28 11:14:58 +00:00
|
|
|
procedure DrawStepTrace(t: tracePtr; hamsterDelta: integer);
|
2026-02-28 10:57:08 +00:00
|
|
|
var
|
|
|
|
|
i: integer;
|
|
|
|
|
begin
|
|
|
|
|
for i := 1 to HamsterDelta do
|
|
|
|
|
begin
|
|
|
|
|
t := t^.prev;
|
|
|
|
|
DrawArenaCell(t^.x, t^.y, TraceSymbol)
|
|
|
|
|
end
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure DrawAfterStep(var hamster: creature; var t: tracePtr; var a: arena);
|
|
|
|
|
var
|
|
|
|
|
prevX, prevY: integer;
|
|
|
|
|
begin
|
|
|
|
|
prevX := hamster.curX - hamster.dX;
|
|
|
|
|
prevY := hamster.curY - hamster.dY;
|
|
|
|
|
if IsOnEdge(prevX, prevY) and a.captured[prevX][prevY] then
|
|
|
|
|
DrawArenaCell(prevX, prevY, CaptureSymbol)
|
|
|
|
|
else
|
|
|
|
|
if IsOnBorder(prevX, prevY, a) then
|
|
|
|
|
DrawArenaCell(prevX, prevY, BorderSymbol)
|
|
|
|
|
else
|
|
|
|
|
DrawArenaCell(prevX, prevY, ArenaSymbol);
|
|
|
|
|
if t <> nil then
|
2026-02-28 11:14:58 +00:00
|
|
|
DrawStepTrace(t, hamster.movespeed);
|
2026-02-28 10:57:08 +00:00
|
|
|
DrawCreature(hamster);
|
|
|
|
|
DrawPreviousCell(hamster, t, a)
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure DrawAfterStep(var cr: creature; var a: arena);
|
|
|
|
|
var
|
|
|
|
|
prevX, prevY: integer;
|
|
|
|
|
begin
|
|
|
|
|
prevX := cr.curX - cr.dX;
|
|
|
|
|
prevY := cr.curY - cr.dY;
|
|
|
|
|
if IsOnEdge(prevX, prevY) and a.captured[prevX][prevY] then
|
|
|
|
|
DrawArenaCell(prevX, prevY, CaptureSymbol)
|
|
|
|
|
else
|
|
|
|
|
if IsOnBorder(prevX, prevY, a) then
|
|
|
|
|
DrawArenaCell(prevX, prevY, BorderSymbol)
|
|
|
|
|
else
|
|
|
|
|
DrawArenaCell(prevX, prevY, ArenaSymbol);
|
|
|
|
|
DrawCreature(cr)
|
|
|
|
|
end;
|
|
|
|
|
|
2026-02-28 11:05:48 +00:00
|
|
|
procedure FillRectangle(x, y, w, h: integer; ch: char);
|
|
|
|
|
var
|
|
|
|
|
i, j: integer;
|
|
|
|
|
begin
|
2026-02-28 11:25:06 +00:00
|
|
|
for i := 0 to h - 1 do
|
2026-02-28 11:05:48 +00:00
|
|
|
begin
|
|
|
|
|
GotoXY(x, y + i);
|
|
|
|
|
for j := 0 to w do
|
|
|
|
|
write(ch)
|
|
|
|
|
end;
|
|
|
|
|
GotoXY(1, 1)
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
type
|
|
|
|
|
stackIntPtr = ^stackIntItem;
|
|
|
|
|
|
|
|
|
|
stackIntItem = record
|
|
|
|
|
val: integer;
|
|
|
|
|
next: stackIntPtr
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
StackInt = record
|
|
|
|
|
top: stackIntPtr
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure StackIntInit(var s: StackInt);
|
|
|
|
|
begin
|
|
|
|
|
s.top := nil
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure StackPush(var st: StackInt; val: integer);
|
|
|
|
|
var
|
|
|
|
|
tmp: stackIntPtr;
|
|
|
|
|
begin
|
|
|
|
|
new(tmp);
|
|
|
|
|
tmp^.val := val;
|
|
|
|
|
tmp^.next := st.top;
|
|
|
|
|
st.top := tmp
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure StackPop(var st: StackInt);
|
|
|
|
|
var
|
|
|
|
|
tmp: stackIntPtr;
|
|
|
|
|
begin
|
|
|
|
|
tmp := st.top;
|
|
|
|
|
st.top := st.top^.next;
|
|
|
|
|
dispose(tmp)
|
|
|
|
|
end;
|
|
|
|
|
|
2026-02-28 11:25:06 +00:00
|
|
|
procedure DrawAscii(x, y, h: integer; var a: array of string);
|
|
|
|
|
var
|
|
|
|
|
i: integer;
|
|
|
|
|
begin
|
|
|
|
|
for i := 1 to h do
|
|
|
|
|
begin
|
|
|
|
|
GotoXY(x, y + i - 1);
|
|
|
|
|
write(a[i - 1])
|
|
|
|
|
end;
|
|
|
|
|
GotoXY(1, 1)
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure EraseRectangle(x, y, w, h: integer);
|
|
|
|
|
begin
|
|
|
|
|
FillRectangle(x, y, w, h, ' ')
|
|
|
|
|
end;
|
|
|
|
|
|
2026-02-28 11:05:48 +00:00
|
|
|
procedure DrawDigit(x, y, digit: integer);
|
|
|
|
|
begin
|
2026-02-28 11:25:06 +00:00
|
|
|
DrawAscii(x, y, DigitHeight, DigitsAscii[digit])
|
2026-02-28 11:05:48 +00:00
|
|
|
end;
|
|
|
|
|
|
2026-02-28 11:14:58 +00:00
|
|
|
procedure DrawNumber(interfaceX: integer; s: longint);
|
2026-02-28 11:05:48 +00:00
|
|
|
var
|
|
|
|
|
x, y: integer;
|
|
|
|
|
i: integer = 0;
|
|
|
|
|
st: StackInt;
|
|
|
|
|
begin
|
|
|
|
|
StackIntInit(st);
|
|
|
|
|
if s = 0 then
|
|
|
|
|
StackPush(st, 0);
|
|
|
|
|
while s <> 0 do
|
|
|
|
|
begin
|
2026-02-28 11:14:58 +00:00
|
|
|
StackPush(st, s mod Notation);
|
|
|
|
|
s := s div Notation
|
2026-02-28 11:05:48 +00:00
|
|
|
end;
|
2026-02-28 11:14:58 +00:00
|
|
|
x := interfaceX + InterfaceMarginX;
|
|
|
|
|
y := InterfaceMarginY;
|
2026-02-28 11:05:48 +00:00
|
|
|
while st.top <> nil do
|
|
|
|
|
begin
|
2026-02-28 11:25:06 +00:00
|
|
|
DrawDigit(x + (DigitWidth + SpaceWidth) * i, y, st.top^.val);
|
2026-02-28 11:05:48 +00:00
|
|
|
StackPop(st);
|
|
|
|
|
i := i + 1
|
|
|
|
|
end
|
|
|
|
|
end;
|
|
|
|
|
|
2026-02-28 11:25:06 +00:00
|
|
|
procedure DrawLifes(var g: GameState);
|
2026-02-28 11:14:58 +00:00
|
|
|
begin
|
2026-02-28 11:25:06 +00:00
|
|
|
DrawNumber(LifeBarX, g.life)
|
2026-02-28 11:14:58 +00:00
|
|
|
end;
|
|
|
|
|
|
2026-02-28 11:25:06 +00:00
|
|
|
procedure DrawScore(var g: GameState);
|
2026-02-28 11:14:58 +00:00
|
|
|
var
|
|
|
|
|
killBarX: integer = InterfaceCellW * 2 * WidthCoefficient + BorderSize;
|
|
|
|
|
begin
|
2026-02-28 11:25:06 +00:00
|
|
|
DrawNumber(killBarX, g.score)
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure DrawMenuState(s: menuState);
|
|
|
|
|
begin
|
|
|
|
|
case s of
|
|
|
|
|
menuNewGame:
|
|
|
|
|
DrawAscii(MenuHamsterX, NewGameY + 1,
|
|
|
|
|
HamsterHeight, HamsterStayAscii);
|
|
|
|
|
menuHighScore:
|
|
|
|
|
DrawAscii(MenuHamsterX, HighScoreY + 1,
|
|
|
|
|
HamsterHeight, HamsterStayAscii);
|
|
|
|
|
menuKeyInfo:
|
|
|
|
|
DrawAscii(MenuHamsterX, KeyInfoY + 1,
|
|
|
|
|
HamsterHeight, HamsterStayAscii);
|
|
|
|
|
menuContinue:
|
|
|
|
|
DrawAscii(MenuHamsterX, ContinueY + 1,
|
|
|
|
|
HamsterHeight, HamsterStayAscii)
|
|
|
|
|
end
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure DrawMenu(var g: gameState);
|
|
|
|
|
var
|
|
|
|
|
y: integer = GameNameY;
|
|
|
|
|
begin
|
|
|
|
|
if firstMenuDraw then
|
|
|
|
|
begin
|
|
|
|
|
DrawRectangle(1, 1, ScreenH, ScreenW * WidthCoefficient);
|
|
|
|
|
firstMenuDraw := not firstMenuDraw
|
|
|
|
|
end;
|
|
|
|
|
DrawAscii(GameNameX, y, GameNameHeight, GameNameAscii);
|
|
|
|
|
DrawAscii(GameNameX, NewGameY, NewGameHeight, NewGameAscii);
|
|
|
|
|
DrawAscii(GameNameX, HighScoreY, HighScoreHeight, HighScoreAscii);
|
|
|
|
|
DrawAscii(GameNameX, KeyInfoY, KeyInfoHeight, KeyInfoAscii);
|
|
|
|
|
DrawAscii(GameNameX, ContinueY, ContinueHeight, ContinueAscii);
|
2026-02-28 11:28:22 +00:00
|
|
|
if not g.continueAllowed then
|
|
|
|
|
FillRectangle(GameNameX, ContinueY + ContinueHeight div 2,
|
|
|
|
|
ContinueWidth, 1, '-');
|
2026-02-28 11:25:06 +00:00
|
|
|
DrawMenuState(g.curMenu)
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure EraseMenuState(s: menuState);
|
|
|
|
|
begin
|
|
|
|
|
case s of
|
|
|
|
|
menuNewGame:
|
|
|
|
|
EraseRectangle(MenuHamsterX, NewGameY + 1,
|
|
|
|
|
HamsterWidth, HamsterHeight);
|
|
|
|
|
menuHighScore:
|
|
|
|
|
EraseRectangle(MenuHamsterX, HighScoreY + 1,
|
|
|
|
|
HamsterWidth, HamsterHeight);
|
|
|
|
|
menuKeyInfo:
|
|
|
|
|
EraseRectangle(MenuHamsterX, KeyInfoY + 1,
|
|
|
|
|
HamsterWidth, HamsterHeight);
|
|
|
|
|
menuContinue:
|
|
|
|
|
EraseRectangle(MenuHamsterX, ContinueY + 1,
|
|
|
|
|
HamsterWidth, HamsterHeight)
|
|
|
|
|
end
|
|
|
|
|
end;
|
|
|
|
|
|
2026-02-28 11:28:22 +00:00
|
|
|
procedure EraseAll;
|
|
|
|
|
begin
|
|
|
|
|
EraseRectangle(1, 1, ScreenW * WidthCoefficient, ScreenH)
|
|
|
|
|
end;
|
|
|
|
|
|
2026-02-28 11:25:06 +00:00
|
|
|
procedure EraseMenu;
|
|
|
|
|
begin
|
|
|
|
|
EraseRectangle(MenuHamsterX, GameNameY,
|
|
|
|
|
GameNameWidth + HamsterWidth + MenuWidthPadding,
|
|
|
|
|
ScreenH - GameNameY * 2)
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure DrawExitState(s: exitState);
|
|
|
|
|
begin
|
|
|
|
|
case s of
|
|
|
|
|
exitYes:
|
|
|
|
|
DrawAscii(HamsterYesX, ExitHamsterY,
|
2026-02-28 11:28:22 +00:00
|
|
|
HamsterHeight, HamsterGGAscii);
|
2026-02-28 11:25:06 +00:00
|
|
|
exitNo:
|
|
|
|
|
DrawAscii(HamsterNoX, ExitHamsterY,
|
|
|
|
|
HamsterHeight, HamsterStayAscii)
|
|
|
|
|
end
|
|
|
|
|
end;
|
|
|
|
|
|
2026-02-28 11:28:22 +00:00
|
|
|
procedure DrawPause(var g: gameState);
|
|
|
|
|
var
|
|
|
|
|
pauseX: integer = (ScreenW * WidthCoefficient - PauseWidth) div 2;
|
|
|
|
|
pauseY: integer = (ScreenH - PauseHeight) div 2;
|
|
|
|
|
begin
|
|
|
|
|
EraseRectangle(pauseX - PauseXMargin,
|
|
|
|
|
pauseY - PauseYMargin,
|
|
|
|
|
PauseWidth + PauseXMargin * 2 - 1,
|
|
|
|
|
PauseHeight + PauseYMargin * 2 + 1);
|
|
|
|
|
DrawRectangle(pauseX - PauseXMargin,
|
|
|
|
|
pauseY - PauseYMargin,
|
|
|
|
|
PauseHeight + PauseYMargin * 2 + 1,
|
|
|
|
|
PauseWidth + PauseXMargin * 2);
|
|
|
|
|
DrawAscii(pauseX, pauseY, PauseHeight, PauseAscii)
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure ErasePause(var g: gameState);
|
|
|
|
|
begin
|
|
|
|
|
end;
|
|
|
|
|
|
2026-02-28 11:25:06 +00:00
|
|
|
procedure DrawExit(var g: gameState);
|
|
|
|
|
var
|
|
|
|
|
realX: integer = ScreenW * WidthCoefficient;
|
|
|
|
|
begin
|
|
|
|
|
DrawAscii((realX - ExitWidth) div 2, ExitGameY, ExitHeight, ExitAscii);
|
|
|
|
|
DrawAscii(ExitYesX, ExitYesY, YesHeight, YesAscii);
|
|
|
|
|
DrawAscii(ExitNoX, ExitYesY, NoHeight, NoAscii);
|
|
|
|
|
DrawExitState(g.curExit)
|
|
|
|
|
end;
|
|
|
|
|
|
2026-02-28 11:28:22 +00:00
|
|
|
procedure DrawInfo;
|
|
|
|
|
begin
|
|
|
|
|
end;
|
|
|
|
|
|
2026-02-28 11:25:06 +00:00
|
|
|
procedure EraseExitState(s: exitState);
|
|
|
|
|
begin
|
|
|
|
|
case s of
|
|
|
|
|
exitYes:
|
|
|
|
|
EraseRectangle(HamsterYesX, ExitHamsterY,
|
|
|
|
|
HamsterWidth, HamsterHeight);
|
|
|
|
|
exitNo:
|
|
|
|
|
EraseRectangle(HamsterNoX, ExitHamsterY,
|
|
|
|
|
HamsterWidth, HamsterHeight)
|
|
|
|
|
end
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure EraseExit;
|
|
|
|
|
begin
|
|
|
|
|
EraseRectangle(HamsterYesX, ExitGameY,
|
|
|
|
|
ExitWidth + HamsterWidth + MenuWidthPadding,
|
|
|
|
|
ExitHeight + MenuHeightPadding + YesHeight)
|
2026-02-28 11:14:58 +00:00
|
|
|
end;
|
|
|
|
|
|
2026-02-28 10:57:08 +00:00
|
|
|
end.
|