init
This commit is contained in:
commit
c6f50b0e6e
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
*.swp
|
||||||
|
*.o
|
||||||
|
*.ppu
|
||||||
|
|
||||||
14
Makefile
Normal file
14
Makefile
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
compile:
|
||||||
|
fpc src/go
|
||||||
|
|
||||||
|
play:
|
||||||
|
./src/go
|
||||||
|
|
||||||
|
# After that you can use in VIM Ctrl-] and Ctrl-^ on functions and procedures
|
||||||
|
tags:
|
||||||
|
ctags src/*
|
||||||
|
cd src/ && ctags *
|
||||||
|
|
||||||
|
wc:
|
||||||
|
cat src/*.pas | wc -l
|
||||||
|
|
||||||
23
README.md
Normal file
23
README.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Go Hamster
|
||||||
|
|
||||||
|
Это калька на игру с телефона Samsung SGH-S500 под названием Go! Hamster,
|
||||||
|
играл в неё в далёком детстве :). Решил реализовать в качестве этюда.
|
||||||
|
Инструментом для реализации выбрал Object Pascal, пишу под терминал UNIX-like
|
||||||
|
системы. С небольшой правкой в исходниках можно компилить и под Windows, но
|
||||||
|
библиотека crt слишком медленно там работает, так что ставьте Linux^W^W^W^W^W.
|
||||||
|
После завершения разработки игры опубликую куда-нибудь в opensource, олды
|
||||||
|
вспомнят... Для завершения этюда требуется ещё ~10-15 часов работы.
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
q: Pascal???
|
||||||
|
a: Антихайп.
|
||||||
|
|
||||||
|
## Сборка
|
||||||
|
```bash
|
||||||
|
fpc src/go.pas
|
||||||
|
```
|
||||||
|
|
||||||
|
## Запуск:
|
||||||
|
```bash
|
||||||
|
./src/go
|
||||||
|
```
|
||||||
178
src/arena_graphics_m.pas
Normal file
178
src/arena_graphics_m.pas
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
unit arena_graphics_m;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses arena_m, creature_m;
|
||||||
|
|
||||||
|
const
|
||||||
|
ArenaSymbol = ' ';
|
||||||
|
BorderSize = 1;
|
||||||
|
BorderSymbol = '|';
|
||||||
|
BorderSymbolX = '|';
|
||||||
|
MidCellDelimiter = '_';
|
||||||
|
BorderSymbolY = '|';
|
||||||
|
CaptureSymbol = '.';
|
||||||
|
CellSize = 2;
|
||||||
|
InterfaceH = 6;
|
||||||
|
ScreenH = (ArenaW + InterfaceH) * CellSize + BorderSize;
|
||||||
|
ScreenW = (ArenaH - 1) * CellSize + BorderSize * 2; { 82 }
|
||||||
|
InterfaceBarH = ScreenW - ArenaW * CellSize - BorderSize * 2; { 14 }
|
||||||
|
InterfaceCellW = ScreenW div 3;
|
||||||
|
LifeBarX = 33;
|
||||||
|
WidthCoefficient = 2;
|
||||||
|
|
||||||
|
procedure DrawArenaBorders(var a: arena);
|
||||||
|
procedure DrawArenaCell(arenaX, arenaY: integer; symbol: char);
|
||||||
|
procedure DrawArenaEdges;
|
||||||
|
procedure DrawEdge(x, y: integer; var a: arena);
|
||||||
|
procedure DrawLevelInterface;
|
||||||
|
procedure DrawRectangle(x0, y0, h, w: integer);
|
||||||
|
procedure DrawInterface;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses crt, math_m;
|
||||||
|
|
||||||
|
procedure DrawLineX(x, y, len: integer; ch: char);
|
||||||
|
var
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
GotoXY(x, y);
|
||||||
|
for i := 1 to len do
|
||||||
|
write(ch);
|
||||||
|
GotoXY(1, 1)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawLineY(x, y, len: integer);
|
||||||
|
var
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
for i := 1 to len do
|
||||||
|
begin
|
||||||
|
GotoXY(x, y + i - 1);
|
||||||
|
write(BorderSymbolY)
|
||||||
|
end;
|
||||||
|
GotoXY(1, 1)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawRectangle(x0, y0, h, w: integer);
|
||||||
|
var
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
DrawLineX(x0, y0, w, BorderSymbolX);
|
||||||
|
for i := 1 to h - 2 do
|
||||||
|
begin
|
||||||
|
GotoXY(x0, y0 + i);
|
||||||
|
write(BorderSymbolY);
|
||||||
|
GotoXY(x0 + w - 1, y0 + i);
|
||||||
|
write(BorderSymbolY)
|
||||||
|
end;
|
||||||
|
DrawLineX(x0, y0 + h - 1, w, BorderSymbolX);
|
||||||
|
GotoXY(1, 1)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawInterface;
|
||||||
|
begin
|
||||||
|
DrawLineX(1, InterfaceBarH, ScreenW * WidthCoefficient, BorderSymbolX);
|
||||||
|
|
||||||
|
DrawLineX(InterfaceCellW * WidthCoefficient,
|
||||||
|
InterfaceBarH div 2,
|
||||||
|
InterfaceCellW * WidthCoefficient + 1, MidCellDelimiter);
|
||||||
|
DrawLineY(InterfaceCellW * WidthCoefficient, 1, InterfaceBarH);
|
||||||
|
DrawLineY(InterfaceCellW * 2 * WidthCoefficient + 1, 1, InterfaceBarH)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawArenaCell(arenaX, arenaY: integer; symbol: char);
|
||||||
|
var
|
||||||
|
i, screenX, screenY: integer;
|
||||||
|
begin
|
||||||
|
screenX := BorderSize + (arenaX - 1) * CellSize * WidthCoefficient;
|
||||||
|
screenY := InterfaceBarH + (arenaY - 1) * CellSize;
|
||||||
|
GotoXY(screenX, screenY);
|
||||||
|
for i := 1 to CellSize * WidthCoefficient do
|
||||||
|
write(symbol);
|
||||||
|
GotoXY(screenX, screenY + 1); { later change to nested for }
|
||||||
|
for i := 1 to CellSize * WidthCoefficient do
|
||||||
|
write(symbol);
|
||||||
|
GotoXY(1, 1)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawArenaEdges;
|
||||||
|
begin
|
||||||
|
DrawRectangle(1, InterfaceBarH,
|
||||||
|
ScreenH - InterfaceBarH + 1, ScreenW * WidthCoefficient)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawLeftEdge(y: integer);
|
||||||
|
var
|
||||||
|
terminalY: integer;
|
||||||
|
begin
|
||||||
|
y := Clamp(y, 1, ArenaW);
|
||||||
|
terminalY := InterfaceBarH + (y - 1) * CellSize;
|
||||||
|
DrawLineY(1, terminalY, CellSize)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawRightEdge(y: integer);
|
||||||
|
var
|
||||||
|
terminalY: integer;
|
||||||
|
begin
|
||||||
|
y := Clamp(y, 1, ArenaW);
|
||||||
|
terminalY := InterfaceBarH + (y - 1) * CellSize;
|
||||||
|
DrawLineY(ScreenW * WidthCoefficient, terminalY, CellSize)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawUpperEdge(x: integer);
|
||||||
|
var
|
||||||
|
terminalX, sizeX: integer;
|
||||||
|
begin
|
||||||
|
x := Clamp(x, 1, ArenaH);
|
||||||
|
terminalX := (x - 1) * CellSize * WidthCoefficient + 1;
|
||||||
|
sizeX := CellSize * WidthCoefficient;
|
||||||
|
DrawLineX(terminalX, InterfaceBarH, sizeX, BorderSymbolX)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawLowerEdge(x: integer);
|
||||||
|
var
|
||||||
|
terminalX, sizeX: integer;
|
||||||
|
begin
|
||||||
|
x := Clamp(x, 1, ArenaH);
|
||||||
|
terminalX := (x - 1) * CellSize * WidthCoefficient + 1;
|
||||||
|
sizeX := CellSize * WidthCoefficient;
|
||||||
|
DrawLineX(terminalX, InterfaceBarH + ArenaW * CellSize - 1,
|
||||||
|
sizeX, BorderSymbolX)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawArenaBorders(var a: arena);
|
||||||
|
var
|
||||||
|
i, j: integer;
|
||||||
|
begin
|
||||||
|
for i := 1 to ArenaW do
|
||||||
|
for j := 1 to ArenaH do
|
||||||
|
if a.borders[j][i] then
|
||||||
|
DrawArenaCell(j, i, BorderSymbol)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawEdge(x, y: integer; var a: arena);
|
||||||
|
begin
|
||||||
|
if a.captured[x][y] then
|
||||||
|
DrawArenaCell(x, y, CaptureSymbol)
|
||||||
|
else
|
||||||
|
DrawArenaCell(x, y, ArenaSymbol);
|
||||||
|
if x = 1 then
|
||||||
|
DrawLeftEdge(y);
|
||||||
|
if x = ArenaH then
|
||||||
|
DrawRightEdge(y);
|
||||||
|
if y = 1 then
|
||||||
|
DrawUpperEdge(x);
|
||||||
|
if y = ArenaW then
|
||||||
|
DrawLowerEdge(x)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawLevelInterface;
|
||||||
|
begin
|
||||||
|
clrscr;
|
||||||
|
DrawRectangle(1, 1, ScreenH, ScreenW * WidthCoefficient);
|
||||||
|
DrawInterface
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
512
src/arena_m.pas
Normal file
512
src/arena_m.pas
Normal file
@ -0,0 +1,512 @@
|
|||||||
|
unit arena_m;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses creature_m, trace_m;
|
||||||
|
|
||||||
|
const
|
||||||
|
ArenaW = 33;
|
||||||
|
ArenaH = 41;
|
||||||
|
RandomCutThreshold = 20;
|
||||||
|
RandomOneToOne = 2;
|
||||||
|
|
||||||
|
type
|
||||||
|
arenaMatrix = array [1..ArenaH, 1..ArenaW] of boolean;
|
||||||
|
|
||||||
|
arena = record
|
||||||
|
captured, borders: arenaMatrix;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ArenaCellCaptured(x, y: integer; var a: arena): boolean;
|
||||||
|
function ArenaSplited(var h: creature; var t: tracePtr; var a: arena): boolean;
|
||||||
|
function GhostShouldTurn(var g: creature; var a: arena): boolean;
|
||||||
|
function
|
||||||
|
HamsterStepPossible(var h: creature; var t: tracePtr; var a: arena): boolean;
|
||||||
|
function IsOnBorder(var x, y: integer; var a: arena): boolean;
|
||||||
|
function IsOnEdge(var cr: creature): boolean;
|
||||||
|
function IsOnEdge(x, y: integer): boolean;
|
||||||
|
procedure CutPart(var hamster: creature; var t: tracePtr;
|
||||||
|
var cutOff: integer; var a: arena);
|
||||||
|
procedure InitArena(var a: arena);
|
||||||
|
procedure MakeEnemyStep(var e, h: creature; t: tracePtr; var a: arena);
|
||||||
|
procedure MakeHamsterStep(var h: creature; var t: tracePtr; var a: arena);
|
||||||
|
procedure SetArenaBorder(var t: tracePtr; var a: arena);
|
||||||
|
procedure TurnGhost(var g: creature; var a: arena);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses arena_graphics_m, cell_m, crt, graphics_m, math_m;
|
||||||
|
|
||||||
|
procedure Fill(var m: arenaMatrix; val: boolean);
|
||||||
|
var
|
||||||
|
i, j: integer;
|
||||||
|
begin
|
||||||
|
for i := 1 to ArenaH do
|
||||||
|
for j := 1 to ArenaW do
|
||||||
|
m[i][j] := val
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure InitArena(var a: arena);
|
||||||
|
begin
|
||||||
|
Fill(a.captured, false);
|
||||||
|
Fill(a.borders, false)
|
||||||
|
end;
|
||||||
|
|
||||||
|
function IsCellFree(x, y: integer; var a: arena): boolean;
|
||||||
|
begin
|
||||||
|
IsCellFree :=
|
||||||
|
(x <> 0) and (x <> ArenaH + 1) and
|
||||||
|
(y <> 0) and (y <> ArenaW + 1) and
|
||||||
|
not a.captured[x][y] and not a.borders[x][y]
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ReleaseArenaCells(var q: QCell; var a: arena);
|
||||||
|
var
|
||||||
|
cell: cellItemPtr;
|
||||||
|
begin
|
||||||
|
while not QCellIsEmpty(q) do
|
||||||
|
begin
|
||||||
|
cell := QCellGet(q);
|
||||||
|
a.captured[cell^.x][cell^.y] := false;
|
||||||
|
QCellPop(q)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TryAddCell(x, y: integer; var q: QCell; var a: arena);
|
||||||
|
var
|
||||||
|
cell: cellItem;
|
||||||
|
begin
|
||||||
|
if IsCellFree(x, y, a) then
|
||||||
|
begin
|
||||||
|
InitCell(cell, x, y);
|
||||||
|
QCellPush(q, cell)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ bfs algo iteration }
|
||||||
|
procedure AddAvailableNeighbours(var q: QCell; var curCell: cellItem;
|
||||||
|
var a: arena);
|
||||||
|
var
|
||||||
|
x, y: integer;
|
||||||
|
begin
|
||||||
|
x := curCell.x;
|
||||||
|
y := curCell.y;
|
||||||
|
TryAddCell(x - 1, y, q, a);
|
||||||
|
TryAddCell(x + 1, y, q, a);
|
||||||
|
TryAddCell(x, y - 1, q, a);
|
||||||
|
TryAddCell(x, y + 1, q, a)
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Kind of bfs algorithm. }
|
||||||
|
function GetFigureArea(var partCell: cellItem; var a: arena): integer;
|
||||||
|
var
|
||||||
|
cellPtr: cellItemPtr;
|
||||||
|
cell: cellItem;
|
||||||
|
captureQ, releaseQ: QCell;
|
||||||
|
result: integer = 0;
|
||||||
|
begin
|
||||||
|
QCellInit(captureQ);
|
||||||
|
QCellInit(releaseQ);
|
||||||
|
QCellPush(captureQ, partCell);
|
||||||
|
while not QCellIsEmpty(captureQ) do
|
||||||
|
begin
|
||||||
|
cellPtr := QCellGet(captureQ);
|
||||||
|
InitCell(cell, cellPtr^.x, cellPtr^.y);
|
||||||
|
QCellPop(captureQ);
|
||||||
|
if a.captured[cell.x][cell.y] then
|
||||||
|
continue;
|
||||||
|
result := result + 1;
|
||||||
|
a.captured[cell.x][cell.y] := true;
|
||||||
|
AddAvailableNeighbours(captureQ, cell, a);
|
||||||
|
QCellPush(releaseQ, cell)
|
||||||
|
end;
|
||||||
|
ReleaseArenaCells(releaseQ, a);
|
||||||
|
GetFigureArea := result
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure
|
||||||
|
CutChosenPart(var partCell: cellItem; var a: arena; var cutOff: integer);
|
||||||
|
var
|
||||||
|
cellPtr: cellItemPtr;
|
||||||
|
cell: cellItem;
|
||||||
|
captureQ: QCell;
|
||||||
|
begin
|
||||||
|
QCellInit(captureQ);
|
||||||
|
QCellPush(captureQ, partCell);
|
||||||
|
while not QCellIsEmpty(captureQ) do
|
||||||
|
begin
|
||||||
|
cellPtr := QCellGet(captureQ);
|
||||||
|
InitCell(cell, cellPtr^.x, cellPtr^.y);
|
||||||
|
QCellPop(captureQ);
|
||||||
|
if a.captured[cell.x][cell.y] then
|
||||||
|
continue;
|
||||||
|
cutOff := cutOff + 1;
|
||||||
|
a.captured[cell.x][cell.y] := true;
|
||||||
|
DrawArenaCell(cell.x, cell.y, CaptureSymbol);
|
||||||
|
AddAvailableNeighbours(captureQ, cell, a)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
function OnEdgeX(x: integer): boolean;
|
||||||
|
begin
|
||||||
|
OnEdgeX := (x = 1) or (x = ArenaH)
|
||||||
|
end;
|
||||||
|
|
||||||
|
function OnEdgeY(y: integer): boolean;
|
||||||
|
begin
|
||||||
|
OnEdgeY := (y = 1) or (y = ArenaW)
|
||||||
|
end;
|
||||||
|
|
||||||
|
function IsOnEdge(x, y: integer): boolean;
|
||||||
|
begin
|
||||||
|
IsOnEdge := (OnEdgeX(x) or OnEdgeY(y))
|
||||||
|
end;
|
||||||
|
|
||||||
|
function YNeighborsCaptured(x, y: integer; var a: arena): boolean;
|
||||||
|
begin
|
||||||
|
YNeighborsCaptured :=
|
||||||
|
not OnEdgeY(y) and a.captured[x][y - 1] and a.captured[x][y + 1]
|
||||||
|
end;
|
||||||
|
|
||||||
|
function XNeighborsCaptured(x, y: integer; var a: arena): boolean;
|
||||||
|
begin
|
||||||
|
XNeighborsCaptured :=
|
||||||
|
not OnEdgeX(x) and a.captured[x + 1][y] and a.captured[x - 1][y]
|
||||||
|
end;
|
||||||
|
|
||||||
|
function DiagonalNeighborsCaptured(x, y: integer; var a: arena): boolean;
|
||||||
|
begin
|
||||||
|
DiagonalNeighborsCaptured :=
|
||||||
|
not IsOnEdge(x, y) and
|
||||||
|
a.captured[x - 1][y - 1] and a.captured[x - 1][y + 1] and
|
||||||
|
a.captured[x + 1][y - 1] and a.captured[x + 1][y + 1]
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ArenaCellCaptured(x, y: integer; var a: arena): boolean;
|
||||||
|
begin
|
||||||
|
ArenaCellCaptured :=
|
||||||
|
XNeighborsCaptured(x, y, a) or YNeighborsCaptured(x, y, a) or
|
||||||
|
DiagonalNeighborsCaptured(x, y, a)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure CaptureArenaBorder(x, y: integer; var a: arena);
|
||||||
|
begin
|
||||||
|
a.borders[x][y] := false;
|
||||||
|
a.captured[x][y] := true;
|
||||||
|
DrawArenaCell(x, y, CaptureSymbol)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure CaptureCutBorders(var a: arena; var cutOff: integer); {rename, slow}
|
||||||
|
var
|
||||||
|
i, j: integer;
|
||||||
|
begin
|
||||||
|
for i := 1 to ArenaW do
|
||||||
|
for j := 1 to ArenaH do
|
||||||
|
if a.borders[j][i] and ArenaCellCaptured(j, i, a) then
|
||||||
|
begin
|
||||||
|
cutOff := cutOff + 1;
|
||||||
|
CaptureArenaBorder(j, i, a)
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure SetArenaBorder(var t: tracePtr; var a: arena);
|
||||||
|
begin
|
||||||
|
if t <> nil then
|
||||||
|
begin
|
||||||
|
a.borders[t^.x][t^.y] := true;
|
||||||
|
SetArenaBorder(t^.prev, a)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
function IsOnEdge(var cr: creature): boolean;
|
||||||
|
begin
|
||||||
|
IsOnEdge :=
|
||||||
|
(cr.curX = 1) or (cr.curX = ArenaH) or (cr.curY = 1) or
|
||||||
|
(cr.curY = ArenaW)
|
||||||
|
end;
|
||||||
|
|
||||||
|
function IsOnBorder(var x, y: integer; var a: arena): boolean;
|
||||||
|
begin
|
||||||
|
IsOnBorder :=
|
||||||
|
a.borders[x][y] and (
|
||||||
|
a.captured[x - 1][y + 1] or
|
||||||
|
a.captured[x - 1][y - 1] or
|
||||||
|
a.captured[x + 1][y + 1] or
|
||||||
|
a.captured[x + 1][y - 1]
|
||||||
|
)
|
||||||
|
end;
|
||||||
|
|
||||||
|
function IsOnBorder(var cr: creature; var a: arena): boolean;
|
||||||
|
begin
|
||||||
|
IsOnBorder :=
|
||||||
|
a.borders[cr.curX][cr.curY] and (
|
||||||
|
a.captured[cr.curX - 1][cr.curY + 1] or
|
||||||
|
a.captured[cr.curX - 1][cr.curY - 1] or
|
||||||
|
a.captured[cr.curX + 1][cr.curY + 1] or
|
||||||
|
a.captured[cr.curX + 1][cr.curY - 1]
|
||||||
|
)
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ArenaSplited(var h: creature; var t: tracePtr; var a: arena): boolean;
|
||||||
|
begin
|
||||||
|
ArenaSplited :=
|
||||||
|
(t <> nil) and (IsOnBorder(h, a) or IsOnEdge(h)) and (t^.prev <> nil)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure GetPartsCells(var t: tracePtr; var part1, part2: cellItem;
|
||||||
|
var a: arena);
|
||||||
|
var
|
||||||
|
prevTrace: tracePtr;
|
||||||
|
begin
|
||||||
|
prevTrace := t^.prev;
|
||||||
|
if t^.y = prevTrace^.y then
|
||||||
|
begin
|
||||||
|
InitCell(part1, prevTrace^.x, prevTrace^.y - 1);
|
||||||
|
InitCell(part2, prevTrace^.x, prevTrace^.y + 1)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
InitCell(part1, prevTrace^.x - 1, prevTrace^.y);
|
||||||
|
InitCell(part2, prevTrace^.x + 1, prevTrace^.y)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
function LowerToBiggerRatio(val1, val2: integer): integer;
|
||||||
|
var
|
||||||
|
v1, v2, tmp, biggerProcent: real;
|
||||||
|
begin
|
||||||
|
v1 := val1;
|
||||||
|
v2 := val2;
|
||||||
|
|
||||||
|
if v1 > v2 then
|
||||||
|
begin
|
||||||
|
tmp := v1;
|
||||||
|
v1 := v2;
|
||||||
|
v2 := tmp
|
||||||
|
end;
|
||||||
|
biggerProcent := v2 / 100;
|
||||||
|
LowerToBiggerRatio := Round(100 - v1 / biggerProcent)
|
||||||
|
end;
|
||||||
|
|
||||||
|
function StepOnTrace(var hamster: creature; var t: tracePtr): boolean;
|
||||||
|
var
|
||||||
|
nextX, nextY, idx: integer;
|
||||||
|
begin
|
||||||
|
nextX := Clamp(hamster.curX + hamster.dX, 1, ArenaH);
|
||||||
|
nextY := Clamp(hamster.curY + hamster.dY, 1, ArenaW);
|
||||||
|
idx := FindIndex(t, nextX, nextY, 1);
|
||||||
|
StepOnTrace := idx > PreviousTraceIdx
|
||||||
|
end;
|
||||||
|
|
||||||
|
function StepBeyondEdge(var cr: creature): boolean;
|
||||||
|
begin
|
||||||
|
StepBeyondEdge :=
|
||||||
|
(cr.dX > 0) and (cr.curX = ArenaH) or
|
||||||
|
(cr.dX < 0) and (cr.curX = 1) or
|
||||||
|
(cr.dY > 0) and (cr.curY = ArenaW) or
|
||||||
|
(cr.dY < 0) and (cr.curY = 1)
|
||||||
|
end;
|
||||||
|
|
||||||
|
function RandomBool: boolean;
|
||||||
|
begin
|
||||||
|
if Random(RandomOneToOne) = 1 then
|
||||||
|
RandomBool := true
|
||||||
|
else
|
||||||
|
RandomBool := false
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ChooseRandomCell(p1, p2: cellItem): cellItem;
|
||||||
|
var
|
||||||
|
rb: boolean;
|
||||||
|
begin
|
||||||
|
rb := RandomBool;
|
||||||
|
if rb then
|
||||||
|
ChooseRandomCell := p1
|
||||||
|
else
|
||||||
|
ChooseRandomCell := p2
|
||||||
|
end;
|
||||||
|
|
||||||
|
{refactor? pass just level later}
|
||||||
|
procedure CutPart(var hamster: creature; var t: tracePtr;
|
||||||
|
var cutOff: integer; var a: arena);
|
||||||
|
var
|
||||||
|
area1, area2, diffProcent: integer;
|
||||||
|
part1, part2, cutFigure: cellItem;
|
||||||
|
begin
|
||||||
|
GetPartsCells(t, part1, part2, a);
|
||||||
|
|
||||||
|
area1 := GetFigureArea(part1, a);
|
||||||
|
area2 := GetFigureArea(part2, a);
|
||||||
|
|
||||||
|
diffProcent := LowerToBiggerRatio(area1, area2);
|
||||||
|
if diffProcent <= RandomCutThreshold then
|
||||||
|
cutFigure := ChooseRandomCell(part1, part2)
|
||||||
|
else
|
||||||
|
if area1 <= area2 then
|
||||||
|
cutFigure := part1
|
||||||
|
else
|
||||||
|
cutFigure := part2;
|
||||||
|
CutChosenPart(cutFigure, a, cutOff);
|
||||||
|
CaptureCutBorders(a, cutOff);
|
||||||
|
DrawArenaBorders(a);
|
||||||
|
DrawArenaEdges;
|
||||||
|
DrawCreature(hamster);
|
||||||
|
DeleteTrace(t)
|
||||||
|
end;
|
||||||
|
|
||||||
|
function
|
||||||
|
HamsterStepPossible(var h: creature; var t: tracePtr; var a: arena): boolean;
|
||||||
|
var
|
||||||
|
nextX, nextY, midX, midY: integer;
|
||||||
|
begin
|
||||||
|
nextX := Clamp(h.curX + h.dX, 1, ArenaH);
|
||||||
|
nextY := Clamp(h.curY + h.dY, 1, ArenaW);
|
||||||
|
midX := Clamp(h.curX + (h.dX div 2), 1, ArenaH);
|
||||||
|
midY := Clamp(h.curY + (h.dY div 2), 1, ArenaW);
|
||||||
|
HamsterStepPossible :=
|
||||||
|
not StepOnTrace(h, t)
|
||||||
|
and (not a.captured[midX][midY] or IsOnEdge(nextX, nextY))
|
||||||
|
and not StepBeyondEdge(h)
|
||||||
|
and not (
|
||||||
|
not IsOnEdge(h) and a.borders[h.curX][h.curY] and
|
||||||
|
a.captured[midX][midY]
|
||||||
|
)
|
||||||
|
end;
|
||||||
|
|
||||||
|
function
|
||||||
|
FieldToEdge(var hamster: creature; var t: tracePtr; var a: arena): boolean;
|
||||||
|
var
|
||||||
|
midX, midY: integer;
|
||||||
|
begin
|
||||||
|
midX := hamster.curX - (hamster.dX div 2);
|
||||||
|
midY := hamster.curY - (hamster.dY div 2);
|
||||||
|
FieldToEdge :=
|
||||||
|
IsOnEdge(hamster) and (t = nil) and not a.captured[midX][midY] and
|
||||||
|
not a.borders[hamster.curX][hamster.curY] and
|
||||||
|
not (IsOnEdge(midX, midY))
|
||||||
|
end;
|
||||||
|
|
||||||
|
function
|
||||||
|
IsOnField(var hamster: creature; var t: tracePtr; var a: arena): boolean;
|
||||||
|
var
|
||||||
|
midX, midY: integer;
|
||||||
|
begin
|
||||||
|
midX := hamster.curX - (hamster.dX div 2);
|
||||||
|
midY := hamster.curY - (hamster.dY div 2);
|
||||||
|
IsOnField :=
|
||||||
|
not (IsOnEdge(hamster) and (t = nil)) and
|
||||||
|
not a.captured[hamster.curX][hamster.curY] and
|
||||||
|
not a.borders[midX][midY]
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure MakeHamsterStep(var h: creature; var t: tracePtr; var a: arena);
|
||||||
|
begin
|
||||||
|
MakeStep(h);
|
||||||
|
if FieldToEdge(h, t, a) or IsOnField(h, t, a) then
|
||||||
|
ChangeHamsterTrace(h, t);
|
||||||
|
DrawAfterStep(h, t, a)
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GhostShouldTurn(var g: creature; var a: arena): boolean;
|
||||||
|
var
|
||||||
|
nextX, nextY: integer;
|
||||||
|
begin
|
||||||
|
nextX := g.curX + g.dX;
|
||||||
|
nextY := g.curY + g.dY;
|
||||||
|
GhostShouldTurn := IsOnEdge(nextX, nextY) or a.borders[nextX][nextY]
|
||||||
|
end;
|
||||||
|
|
||||||
|
function BorderY(nextX, nextY: integer; var a: arena): boolean;
|
||||||
|
begin
|
||||||
|
BorderY :=
|
||||||
|
a.borders[nextX][nextY] and
|
||||||
|
(a.borders[nextX][nextY - 1] or a.borders[nextX][nextY + 1])
|
||||||
|
end;
|
||||||
|
|
||||||
|
function BorderX(nextX, nextY: integer; var a: arena): boolean;
|
||||||
|
begin
|
||||||
|
BorderX :=
|
||||||
|
a.borders[nextX][nextY] and
|
||||||
|
(a.borders[nextX - 1][nextY] or a.borders[nextX + 1][nextY])
|
||||||
|
end;
|
||||||
|
|
||||||
|
function IsCorner(x, y: integer; var a: arena): boolean;
|
||||||
|
begin
|
||||||
|
IsCorner := BorderX(x, y, a) and BorderY(x, y, a)
|
||||||
|
end;
|
||||||
|
|
||||||
|
function IsConcaveCorner(x, y: integer; var a: arena): boolean;
|
||||||
|
begin
|
||||||
|
IsConcaveCorner :=
|
||||||
|
a.borders[x - 1][y] and a.borders[x][y + 1] or
|
||||||
|
a.borders[x - 1][y] and a.borders[x][y - 1] or
|
||||||
|
a.borders[x + 1][y] and a.borders[x][y + 1] or
|
||||||
|
a.borders[x + 1][y] and a.borders[x][y - 1]
|
||||||
|
end;
|
||||||
|
|
||||||
|
function IsConvexCorner(var cr: creature; var a: arena): boolean;
|
||||||
|
var
|
||||||
|
x, y, nextX, nextY: integer;
|
||||||
|
begin
|
||||||
|
x := cr.curX;
|
||||||
|
y := cr.curY;
|
||||||
|
nextX := x + cr.dX;
|
||||||
|
nextY := y + cr.dY;
|
||||||
|
IsConvexCorner :=
|
||||||
|
IsCorner(nextX, nextY, a) and
|
||||||
|
not IsOnEdge(nextX, nextY) and
|
||||||
|
not IsConcaveCorner(x, y, a)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure CornerTurn(var cr: creature; var a: arena);
|
||||||
|
var
|
||||||
|
x, y, nextX, nextY: integer;
|
||||||
|
begin
|
||||||
|
x := cr.curX;
|
||||||
|
y := cr.curY;
|
||||||
|
nextX := x + cr.dX;
|
||||||
|
nextY := y + cr.dY;
|
||||||
|
if not a.borders[nextX][y] and not a.borders[x][nextY] then
|
||||||
|
begin
|
||||||
|
cr.dX := cr.dX * -1;
|
||||||
|
cr.dY := cr.dY * -1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if a.borders[nextX][y] then
|
||||||
|
cr.dX := cr.dX * -1
|
||||||
|
else
|
||||||
|
cr.dY := cr.dY * -1
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TurnGhost(var g: creature; var a: arena);
|
||||||
|
var
|
||||||
|
nextX, nextY: integer;
|
||||||
|
begin
|
||||||
|
nextX := g.curX + g.dX;
|
||||||
|
nextY := g.curY + g.dY;
|
||||||
|
if IsConvexCorner(g, a) then
|
||||||
|
begin
|
||||||
|
CornerTurn(g, a)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if OnEdgeX(nextX) or BorderY(nextX, nextY, a) then
|
||||||
|
g.dX := g.dX * -1;
|
||||||
|
if OnEdgeY(nextY) or BorderX(nextX, nextY, a) then
|
||||||
|
g.dY := g.dY * -1
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure MakeEnemyStep(var e, h: creature; t: tracePtr; var a: arena);
|
||||||
|
var
|
||||||
|
prevX, prevY: integer;
|
||||||
|
begin
|
||||||
|
prevX := e.curX;
|
||||||
|
prevY := e.curY;
|
||||||
|
MakeStep(e);
|
||||||
|
DrawAfterStep(e, a);
|
||||||
|
if TraceCrossed(prevX, prevY, e, t) then
|
||||||
|
h.alive := false
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
309
src/ascii_arts_m.pas
Normal file
309
src/ascii_arts_m.pas
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
unit ascii_arts_m;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
const
|
||||||
|
DigitHeight = 5;
|
||||||
|
DigitWidth = 5;
|
||||||
|
DigitsAscii: array[0..9] of array[1..DigitHeight] of string = (
|
||||||
|
(
|
||||||
|
'@@@@@',
|
||||||
|
'@ @',
|
||||||
|
'@ @',
|
||||||
|
'@ @',
|
||||||
|
'@@@@@'
|
||||||
|
),
|
||||||
|
(
|
||||||
|
' @ ',
|
||||||
|
' @@ ',
|
||||||
|
'@ @ ',
|
||||||
|
' @ ',
|
||||||
|
'@@@@@'
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'@@@@@',
|
||||||
|
' @',
|
||||||
|
'@@@@@',
|
||||||
|
'@ ',
|
||||||
|
'@@@@@'
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'@@@@@',
|
||||||
|
' @',
|
||||||
|
'@@@@@',
|
||||||
|
' @',
|
||||||
|
'@@@@@'
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'@ @',
|
||||||
|
'@ @',
|
||||||
|
'@@@@@',
|
||||||
|
' @',
|
||||||
|
' @'
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'@@@@@',
|
||||||
|
'@ ',
|
||||||
|
'@@@@@',
|
||||||
|
' @',
|
||||||
|
'@@@@@'
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'@@@@@',
|
||||||
|
'@ ',
|
||||||
|
'@@@@@',
|
||||||
|
'@ @',
|
||||||
|
'@@@@@'
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'@@@@@',
|
||||||
|
' @',
|
||||||
|
' @',
|
||||||
|
' @',
|
||||||
|
' @'
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'@@@@@',
|
||||||
|
'@ @',
|
||||||
|
'@@@@@',
|
||||||
|
'@ @',
|
||||||
|
'@@@@@'
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'@@@@@',
|
||||||
|
'@ @',
|
||||||
|
'@@@@@',
|
||||||
|
' @',
|
||||||
|
'@@@@@'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
GameNameHeight = 6;
|
||||||
|
GameNameWidth = 58;
|
||||||
|
GameNameAscii: array[1..GameNameHeight] of string = (
|
||||||
|
' _____ _ _ _ _',
|
||||||
|
' / ____| | | | | | | | |',
|
||||||
|
'| | __ ___ | | | |__| | __ _ _ __ ___ ___| |_ ___ _ __',
|
||||||
|
'| | |_ |/ _ \| | | __ |/ _` | ''_ ` _ \/ __| __/ _ \ ''__|',
|
||||||
|
'| |__| | (_) |_| | | | | (_| | | | | | \__ \ || __/ |',
|
||||||
|
' \_____|\___/(_) |_| |_|\__,_|_| |_| |_|___/\__\___|_|'
|
||||||
|
);
|
||||||
|
NewGameHeight = 6;
|
||||||
|
NewGameAscii: array[1..NewGameHeight] of string = (
|
||||||
|
' _ _ _____',
|
||||||
|
'| \ | | / ____|',
|
||||||
|
'| \| | _____ __ | | __ __ _ _ __ ___ ___',
|
||||||
|
'| . ` |/ _ \ \ /\ / / | | |_ |/ _` | ''_ ` _ \ / _ \',
|
||||||
|
'| |\ | __/\ V V / | |__| | (_| | | | | | | __/',
|
||||||
|
'|_| \_|\___| \_/\_/ \_____|\__,_|_| |_| |_|\___|'
|
||||||
|
);
|
||||||
|
HighScoreHeight = 8;
|
||||||
|
HighScoreAscii: array[1..HighScoreHeight] of string = (
|
||||||
|
' _ _ _ _ _____',
|
||||||
|
'| | | (_) | | / ____|',
|
||||||
|
'| |__| |_ __ _| |__ | (___ ___ ___ _ __ ___',
|
||||||
|
'| __ | |/ _` | ''_ \ \___ \ / __/ _ \| ''__/ _ \',
|
||||||
|
'| | | | | (_| | | | | ____) | (_| (_) | | | __/',
|
||||||
|
'|_| |_|_|\__, |_| |_| |_____/ \___\___/|_| \___|',
|
||||||
|
' __/ |',
|
||||||
|
' |___/'
|
||||||
|
);
|
||||||
|
|
||||||
|
MenuInfoHeight = 8;
|
||||||
|
KeyInfoAscii: array[1..MenuInfoHeight] of string = (
|
||||||
|
' _ __ _____ __',
|
||||||
|
'| |/ / |_ _| / _|',
|
||||||
|
'| '' / ___ _ _ | | _ __ | |_ ___',
|
||||||
|
'| < / _ \ | | | | | | ''_ \| _/ _ \',
|
||||||
|
'| . \ __/ |_| | _| |_| | | | || (_) |',
|
||||||
|
'|_|\_\___|\__, | |_____|_| |_|_| \___/',
|
||||||
|
' __/ |',
|
||||||
|
' |___/'
|
||||||
|
);
|
||||||
|
|
||||||
|
ContinueHeight = 6;
|
||||||
|
ContinueWidth = 41;
|
||||||
|
ContinueAscii: array[1..ContinueHeight] of string = (
|
||||||
|
' _____ _ _ ',
|
||||||
|
' / ____| | | (_) ',
|
||||||
|
'| | ___ _ __ | |_ _ _ __ _ _ ___ ',
|
||||||
|
'| | / _ \| ''_ \| __| | ''_ \| | | |/ _ \',
|
||||||
|
'| |___| (_) | | | | |_| | | | | |_| | __/',
|
||||||
|
' \_____\___/|_| |_|\__|_|_| |_|\__,_|\___|'
|
||||||
|
);
|
||||||
|
|
||||||
|
ExitHeight = 8;
|
||||||
|
ExitWidth = 70;
|
||||||
|
ExitAscii: array[1..ExitHeight] of string = (
|
||||||
|
' ______ _ _ _ _ ___',
|
||||||
|
'| ____| (_) | | | | | |__ \',
|
||||||
|
'| |__ __ ___| |_ | |_| |__ ___ __ _ __ _ _ __ ___ ___ ) |',
|
||||||
|
'| __| \ \/ / | __| | __| ''_ \ / _ \ / _` |/ _` | ''_ ` _ \ / _ \/ /',
|
||||||
|
'| |____ > <| | |_ | |_| | | | __/ | (_| | (_| | | | | | | __/_|',
|
||||||
|
'|______/_/\_\_|\__| \__|_| |_|\___| \__, |\__,_|_| |_| |_|\___(_)',
|
||||||
|
' __/ |',
|
||||||
|
' |___/'
|
||||||
|
);
|
||||||
|
|
||||||
|
PauseHeight = 22;
|
||||||
|
PauseWidth = 76;
|
||||||
|
|
||||||
|
{ Too long strings :(, lets following linux styleguide }
|
||||||
|
PauseAscii: array[1..PauseHeight] of string = (
|
||||||
|
' _',
|
||||||
|
' | |',
|
||||||
|
' _ __ __ _ _ _ ___ ___ __| |',
|
||||||
|
' | ''_ \ / _` | | | / __|/ _ \/ _` |',
|
||||||
|
' | |_) | (_| | |_| \__ \ __/ (_| |',
|
||||||
|
' | .__/ \__,_|\__,_|___/\___|\__,_| ',
|
||||||
|
' | | ',
|
||||||
|
' |_| _ _',
|
||||||
|
' | | (_)',
|
||||||
|
' ___ _ __ __ _ __ ___ ___ ___ _ __ | |_ _ _ __ _ _ ___',
|
||||||
|
'/ __| ''_ \ / _` |/ __/ _ \ ______ / __/ _ \| ''_ \| __| | ''_ \| | | |/ _ \',
|
||||||
|
'\__ \ |_) | (_| | (_| __/ |______| | (_| (_) | | | | |_| | | | | |_| | __/',
|
||||||
|
'|___/ .__/ \__,_|\___\___| \___\___/|_| |_|\__|_|_| |_|\__,_|\___|',
|
||||||
|
'====| |===================',
|
||||||
|
' |_| _ _ _',
|
||||||
|
' (_) | | |',
|
||||||
|
' __ _ __ _ _ _ _| |_ | |_ ___ _ __ ___ ___ _ __ _ _',
|
||||||
|
' / _` | ______ / _` | | | | | __| | __/ _ \ | ''_ ` _ \ / _ \ ''_ \| | | |',
|
||||||
|
'| (_| | |______| | (_| | |_| | | |_ | || (_) | | | | | | | __/ | | | |_| |',
|
||||||
|
' \__, | \__, |\__,_|_|\__| \__\___/ |_| |_| |_|\___|_| |_|\__,_|',
|
||||||
|
'====| |= | |',
|
||||||
|
' |_| |_|'
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
YesHeight = 6;
|
||||||
|
YesAscii: array[1..YesHeight] of string = (
|
||||||
|
' _ _ ___ ___',
|
||||||
|
'| | | |/ _ \/ __|',
|
||||||
|
'| |_| | __/\__ \',
|
||||||
|
' \__, |\___||___/',
|
||||||
|
' __/ |',
|
||||||
|
' |___/'
|
||||||
|
);
|
||||||
|
|
||||||
|
NoHeight = 4;
|
||||||
|
NoWidth = 13;
|
||||||
|
NoAscii: array[1..NoHeight] of string = (
|
||||||
|
' _ __ ___',
|
||||||
|
'| ''_ \ / _ \',
|
||||||
|
'| | | | (_) |',
|
||||||
|
'|_| |_|\___/'
|
||||||
|
);
|
||||||
|
|
||||||
|
HamsterHeight = 5;
|
||||||
|
HamsterWidth = 7;
|
||||||
|
HamsterStayAscii: array[1..HamsterHeight] of string = (
|
||||||
|
' (\_/)',
|
||||||
|
'( 0_0 )',
|
||||||
|
'/-----\',
|
||||||
|
' |___|',
|
||||||
|
' / \'
|
||||||
|
);
|
||||||
|
HamsterGGAscii: array[1..HamsterHeight] of string = (
|
||||||
|
' (\_/)',
|
||||||
|
'( G_G )',
|
||||||
|
'/-----\',
|
||||||
|
' |___|',
|
||||||
|
' / \'
|
||||||
|
);
|
||||||
|
|
||||||
|
GameOverHeight = 40;
|
||||||
|
GameOverWidth = 62;
|
||||||
|
GameOverScreen: array[1..GameOverHeight] of string = (
|
||||||
|
' _____ __ __ ______ ',
|
||||||
|
' / ____| /\ | \/ | ____| ',
|
||||||
|
' | | __ / \ | \ / | |__ ',
|
||||||
|
' | | |_ | / /\ \ | |\/| | __| ',
|
||||||
|
' | |__| |/ ____ \| | | | |____ ',
|
||||||
|
' \_____/_/ \_\_| |_|______| ',
|
||||||
|
' ______ ________ _____ ',
|
||||||
|
' / __ \ \ / / ____| __ \ ',
|
||||||
|
' | | | \ \ / /| |__ | |__) | ',
|
||||||
|
' | | | |\ \/ / | __| | _ / ',
|
||||||
|
' | |__| | \ / | |____| | \ \ ',
|
||||||
|
' \____/ \/ |______|_| \_\ ',
|
||||||
|
' ',
|
||||||
|
' ____ ____ ',
|
||||||
|
' / o@@\ /@@o \ ',
|
||||||
|
' / /``\@\ __,-==-,__ /@/``\ \ ',
|
||||||
|
' / /` `||//\______/ \||` `\ \ ',
|
||||||
|
' | |` // __ __ \\ `| | ',
|
||||||
|
' \ \` (/ /;g\ /g;\ \) `/ | ',
|
||||||
|
' \_\__(( " .. " )____/_/ ',
|
||||||
|
' \ " __ " / ',
|
||||||
|
' @@@@@@(||)@@@@`@@`@@@@(||)@@@@@@@ ',
|
||||||
|
' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ',
|
||||||
|
' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ',
|
||||||
|
' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ',
|
||||||
|
' ',
|
||||||
|
' _ _ ___ ',
|
||||||
|
' | | (_) |__ \ ',
|
||||||
|
' ___ ___ _ __ | |_ _ _ __ _ _ ___ ) | ',
|
||||||
|
' / __/ _ \| ''_ \| __| | ''_ \| | | |/ _ \ / / ',
|
||||||
|
' | (_| (_) | | | | |_| | | | | |_| | __/ |_| ',
|
||||||
|
' \___\___/|_| |_|\__|_|_| |_|\__,_|\___| (_) ',
|
||||||
|
' ___ ___ __ ___ ___',
|
||||||
|
'| _| |_ | \ \ | _| |_ |',
|
||||||
|
'| | _ _ | | ___ ___ \ \ | | _ __ | | ___',
|
||||||
|
'| | | | | | | |/ _ \/ __| \ \ | | | ''_ \ | |/ _ \',
|
||||||
|
'| | | |_| | | | __/\__ \ \ \ | | | | | | | | (_) |',
|
||||||
|
'| |_ \__, | _| |\___||___/ \ \ | |_ |_| |_| _| |\___/',
|
||||||
|
'|___|=====/ |=|___| \_\ |___|=========|___|',
|
||||||
|
' |___/'
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
KeyInfoHeight = 42;
|
||||||
|
KeyInfoWidth = 98;
|
||||||
|
KeyInfoScreen: array[1..KeyInfoHeight] of string = (
|
||||||
|
' _',
|
||||||
|
' | |',
|
||||||
|
' _ __ ___ _____ _____ | | _____ _ _ ___ _',
|
||||||
|
' | ''_ ` _ \ / _ \ \ / / _ \ | |/ / _ \ | | / __| (_)',
|
||||||
|
' | | | | | | (_) \ V / __/ | < __/ |_| \__ \ _',
|
||||||
|
' |_| |_| |_|\___/ \_/ \___| |_|\_\___|\__, |___/ (_)',
|
||||||
|
' __/ |',
|
||||||
|
' _ |___/',
|
||||||
|
' / \',
|
||||||
|
' / . \',
|
||||||
|
' / / \ \',
|
||||||
|
' /_/| |\_\',
|
||||||
|
' | |',
|
||||||
|
' |_|',
|
||||||
|
' __ ========= __',
|
||||||
|
' / / (\_/) \ \',
|
||||||
|
' / /_____ ( 0_0 ) ______\ \ ',
|
||||||
|
' { ______| /-----\ |_______ }',
|
||||||
|
' \ \ |___| / /',
|
||||||
|
' \_\ / \ /_/',
|
||||||
|
' ========== _ ===========',
|
||||||
|
' | |',
|
||||||
|
' _ | | _ ',
|
||||||
|
' \ \| |/ /',
|
||||||
|
' \ \ / / ',
|
||||||
|
' \ ` / ',
|
||||||
|
' \_/',
|
||||||
|
' =========',
|
||||||
|
' _ _ _ ',
|
||||||
|
' | | | | | |',
|
||||||
|
' ___ _ __ __ _ ___ ___ ___| |_ ___ _ __ | |__ __ _ _ __ ___ ___| |_ ___ _ __',
|
||||||
|
' / __| ''_ \ / _` |/ __/ _ \ ______ / __| __/ _ \| ''_ \ | ''_ \ / _` | ''_ ` _ \/ __| __/ _ \ ''__|',
|
||||||
|
' \__ \ |_) | (_| | (_| __/ |______| \__ \ || (_) | |_) | | | | | (_| | | | | | \__ \ || __/ |',
|
||||||
|
' |___/ .__/ \__,_|\___\___| |___/\__\___/| .__/ |_| |_|\__,_|_| |_| |_|___/\__\___|_|',
|
||||||
|
' ====| |=================== | |',
|
||||||
|
' |_| |_|',
|
||||||
|
' ___ ___ ___ _ __ __ _ _ _ ___ ___',
|
||||||
|
' / _ \/ __|/ __| ______ | ''_ \ / _` | | | / __|/ _ \',
|
||||||
|
'| __/\__ \ (__ |______| | |_) | (_| | |_| \__ \ __/',
|
||||||
|
' \___||___/\___| | .__/ \__,_|\__,_|___/\___|',
|
||||||
|
'================ | |',
|
||||||
|
' |_|'
|
||||||
|
);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
end.
|
||||||
|
|
||||||
80
src/cell_m.pas
Normal file
80
src/cell_m.pas
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
unit cell_m;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
type
|
||||||
|
cellItemPtr = ^cellItem;
|
||||||
|
|
||||||
|
cellItem = record
|
||||||
|
x, y: integer;
|
||||||
|
next: cellItemPtr
|
||||||
|
end;
|
||||||
|
|
||||||
|
QCell = record
|
||||||
|
first, last: cellItemPtr
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure InitCell(var c: cellItem; x, y: integer);
|
||||||
|
procedure QCellInit(var q: QCell);
|
||||||
|
procedure QCellPush(var q: QCell; var c: cellItem);
|
||||||
|
function QCellIsEmpty(var q: QCell): boolean;
|
||||||
|
function QCellGet(var q: QCell): cellItemPtr;
|
||||||
|
procedure QCellPop(var q: QCell);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
procedure InitCell(var c: cellItem; x, y: integer);
|
||||||
|
begin
|
||||||
|
c.x := x;
|
||||||
|
c.y := y;
|
||||||
|
c.next := nil
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure QCellInit(var q: QCell);
|
||||||
|
begin
|
||||||
|
q.first := nil;
|
||||||
|
q.last := nil
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure QCellPush(var q: QCell; var c: cellItem);
|
||||||
|
var
|
||||||
|
tmp: cellItemPtr;
|
||||||
|
begin
|
||||||
|
new(tmp);
|
||||||
|
tmp^.x := c.x;
|
||||||
|
tmp^.y := c.y;
|
||||||
|
tmp^.next := nil;
|
||||||
|
if q.last = nil then
|
||||||
|
begin
|
||||||
|
q.first := tmp;
|
||||||
|
q.last := q.first
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
q.last^.next := tmp;
|
||||||
|
q.last := q.last^.next
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
function QCellIsEmpty(var q: QCell): boolean;
|
||||||
|
begin
|
||||||
|
QCellIsEmpty := (q.last = nil)
|
||||||
|
end;
|
||||||
|
|
||||||
|
function QCellGet(var q: QCell): cellItemPtr;
|
||||||
|
begin
|
||||||
|
QCellGet := q.first
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure QCellPop(var q: QCell);
|
||||||
|
var
|
||||||
|
removeItem: cellItemPtr;
|
||||||
|
begin
|
||||||
|
removeItem := QCellGet(q);
|
||||||
|
q.first := removeItem^.next;
|
||||||
|
if q.first = nil then
|
||||||
|
q.last := q.first;
|
||||||
|
dispose(removeItem)
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
52
src/creature_m.pas
Normal file
52
src/creature_m.pas
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
unit creature_m;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
type
|
||||||
|
creature = record
|
||||||
|
curX, curY, dX, dY, moveSpeed: integer;
|
||||||
|
symbol: char;
|
||||||
|
alive: boolean
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure
|
||||||
|
InitCreature(var cr: creature; curX, curY, movespeed: integer; symbol: char);
|
||||||
|
procedure KillCreature(var cr: creature);
|
||||||
|
procedure StopCreature(var cr: creature);
|
||||||
|
procedure MakeStep(var cr: creature);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses arena_graphics_m, arena_m, math_m;
|
||||||
|
|
||||||
|
procedure
|
||||||
|
InitCreature(var cr: creature; curX, curY, movespeed: integer; symbol: char);
|
||||||
|
begin
|
||||||
|
cr.curX := curX;
|
||||||
|
cr.curY := curY;
|
||||||
|
cr.dX := 0;
|
||||||
|
cr.dY := 0;
|
||||||
|
cr.movespeed := moveSpeed;
|
||||||
|
cr.alive := true;
|
||||||
|
cr.symbol := symbol
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure StopCreature(var cr: creature);
|
||||||
|
begin
|
||||||
|
cr.dX := 0;
|
||||||
|
cr.dY := 0
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure MakeStep(var cr: creature);
|
||||||
|
begin
|
||||||
|
cr.curX := Clamp(cr.curX + cr.dX, 1, ArenaH);
|
||||||
|
cr.curY := Clamp(cr.curY + cr.dY, 1, ArenaW)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure KillCreature(var cr: creature);
|
||||||
|
begin
|
||||||
|
cr.alive := false;
|
||||||
|
DrawArenaCell(cr.curX, cr.curY, CaptureSymbol)
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
64
src/debug_m.pas
Normal file
64
src/debug_m.pas
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
unit debug_m;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses arena_m, cell_m, creature_m;
|
||||||
|
|
||||||
|
procedure Debug;
|
||||||
|
procedure DebugCell(cell: cellItemPtr);
|
||||||
|
procedure Print(var m: arenaMatrix);
|
||||||
|
|
||||||
|
procedure PrintCreatureDebug(var cr: creature);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses crt;
|
||||||
|
|
||||||
|
const
|
||||||
|
DebugMsg = '===============DEBUG===============';
|
||||||
|
|
||||||
|
var
|
||||||
|
DebugTmp: integer = 2;
|
||||||
|
|
||||||
|
procedure Debug;
|
||||||
|
begin
|
||||||
|
GotoXY(2, DebugTmp);
|
||||||
|
writeln(DebugMsg);
|
||||||
|
DebugTmp := DebugTmp + 1
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DebugCell(cell: cellItemPtr);
|
||||||
|
begin
|
||||||
|
GotoXY(2, DebugTmp);
|
||||||
|
writeln('Cur X: ', cell^.x, ' Cur Y: ', cell^.y);
|
||||||
|
DebugTmp := DebugTmp + 1
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure Print(var m: arenaMatrix);
|
||||||
|
var
|
||||||
|
i, j: integer;
|
||||||
|
begin
|
||||||
|
for i := 1 to ArenaW do
|
||||||
|
begin
|
||||||
|
for j := 1 to ArenaH do
|
||||||
|
if m[j][i] then
|
||||||
|
write(1, ' ')
|
||||||
|
else
|
||||||
|
write(0, ' ');
|
||||||
|
writeln
|
||||||
|
end;
|
||||||
|
GotoXY(1, 1)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure PrintCreatureDebug(var cr: creature);
|
||||||
|
var
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
GotoXY(2, 2);
|
||||||
|
for i := 1 to 20 do
|
||||||
|
write(' ');
|
||||||
|
GotoXY(2, 2);
|
||||||
|
writeln(cr.curX, ' ', cr.curY, ' ', cr.dX, ' ', cr.dY)
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
247
src/game_m.pas
Normal file
247
src/game_m.pas
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
{ MainLoop -- main loop }
|
||||||
|
unit game_m;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses level_m;
|
||||||
|
|
||||||
|
type
|
||||||
|
state = (gameExit, gameMenu, gameStartLevel, gameScore, gameKeyInfo,
|
||||||
|
gamePause, gameContinueLevel, gameOver);
|
||||||
|
menuState = (menuNewGame, menuHighScore, menuKeyInfo, menuContinue);
|
||||||
|
exitState = (exitYes, exitNo);
|
||||||
|
gameState = record
|
||||||
|
curExit: exitState;
|
||||||
|
curMenu: menuState;
|
||||||
|
curState: state;
|
||||||
|
level: integer;
|
||||||
|
shutdown, continueAllowed: boolean;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DecreaseLife(var level: levelState);
|
||||||
|
procedure RunGameOver(var g: gameState; var level: levelState);
|
||||||
|
procedure InitGame(var g: gameState);
|
||||||
|
procedure NextExitState(var g: gameState);
|
||||||
|
procedure PreviousExitState(var g: gameState);
|
||||||
|
procedure RunExit(var g: gameState);
|
||||||
|
procedure MainLoop(var g: gameState);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses arena_m, arena_graphics_m, crt, creature_m, ghost_m, graphics_m,
|
||||||
|
hamster_m, keys_m, trace_m;
|
||||||
|
|
||||||
|
const
|
||||||
|
KeyDelayMs = 25;
|
||||||
|
LevelDelayMs = 100;
|
||||||
|
|
||||||
|
procedure DecreaseLife(var level: levelState);
|
||||||
|
begin
|
||||||
|
level.life := level.life - 1;
|
||||||
|
DrawLifes(level.life)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure InitGame(var g: gameState);
|
||||||
|
begin
|
||||||
|
g.continueAllowed := false;
|
||||||
|
g.curMenu := menuNewGame;
|
||||||
|
g.curState := gameMenu;
|
||||||
|
g.level := 1;
|
||||||
|
g.shutdown := false;
|
||||||
|
{
|
||||||
|
g.slowBonus := StartSlowBonus;
|
||||||
|
g.speedBonus := StartSpeedBonus
|
||||||
|
}
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure RunExit(var g: gameState);
|
||||||
|
begin
|
||||||
|
DrawExit(g);
|
||||||
|
while g.curState = gameExit do
|
||||||
|
begin
|
||||||
|
delay(KeyDelayMs);
|
||||||
|
if keypressed then
|
||||||
|
HandleExitKey(g)
|
||||||
|
end;
|
||||||
|
EraseExit
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure RunScore(var g: gameState);
|
||||||
|
begin
|
||||||
|
{DrawHighScore;}
|
||||||
|
while g.curState = gameScore do
|
||||||
|
begin
|
||||||
|
delay(KeyDelayMs);
|
||||||
|
if keypressed then
|
||||||
|
HandleScoreKey(g)
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure RunKeyInfo(var g: gameState);
|
||||||
|
begin
|
||||||
|
DrawKeyInfo;
|
||||||
|
while g.curState = gameKeyInfo do
|
||||||
|
begin
|
||||||
|
delay(KeyDelayMs);
|
||||||
|
if keypressed then
|
||||||
|
HandleInfoKey(g)
|
||||||
|
end;
|
||||||
|
EraseKeyInfo
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure RunPause(var g: gameState);
|
||||||
|
begin
|
||||||
|
DrawPause(g);
|
||||||
|
while g.curState = gamePause do
|
||||||
|
begin
|
||||||
|
delay(KeyDelayMs);
|
||||||
|
if keypressed then
|
||||||
|
HandlePauseKey(g)
|
||||||
|
end;
|
||||||
|
if g.curState = gameMenu then
|
||||||
|
EraseLevel;
|
||||||
|
if g.curState = gameContinueLevel then
|
||||||
|
ErasePause(g)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure RunGameOver(var g: gameState; var level: levelState);
|
||||||
|
begin
|
||||||
|
DrawGameOver;
|
||||||
|
while g.curState = gameOver do
|
||||||
|
begin
|
||||||
|
delay(KeyDelayMs);
|
||||||
|
if keypressed then
|
||||||
|
HandleGameOverKey(g)
|
||||||
|
end;
|
||||||
|
EraseGameOver;
|
||||||
|
if g.curState = gameContinueLevel then
|
||||||
|
InitLevel(level)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure LevelLoop(var g: gameState; var level: levelState);
|
||||||
|
begin
|
||||||
|
while level.continueLevel do
|
||||||
|
begin
|
||||||
|
delay(LevelDelayMs);
|
||||||
|
if ArenaSplited(level.h, level.t, level.a) then
|
||||||
|
begin
|
||||||
|
SetArenaBorder(level.t, level.a);
|
||||||
|
CutPart(level.h, level.t, level.score, level.a);
|
||||||
|
DrawScore(level.score)
|
||||||
|
end;
|
||||||
|
if level.g.alive then
|
||||||
|
MakeEnemyStep(level.g, level.h, level.t, level.a);
|
||||||
|
while level.g.alive and GhostShouldTurn(level.g, level.a) do
|
||||||
|
TurnGhost(level.g, level.a);
|
||||||
|
if not level.h.alive then
|
||||||
|
begin
|
||||||
|
if level.life <= 0 then
|
||||||
|
begin
|
||||||
|
g.curState := gameOver;
|
||||||
|
EraseLevel;
|
||||||
|
break
|
||||||
|
end;
|
||||||
|
DecreaseLife(level);
|
||||||
|
KillHamster(level.h, level.t, level.a);
|
||||||
|
level.h.alive := true
|
||||||
|
end;
|
||||||
|
if keypressed then
|
||||||
|
HandleLevelKey(level.h, level.a, level.t, g);
|
||||||
|
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);
|
||||||
|
if level.g.alive and
|
||||||
|
level.a.captured[level.g.curX][level.g.curY] then
|
||||||
|
begin
|
||||||
|
KillCreature(level.g)
|
||||||
|
end;
|
||||||
|
if g.curState = gamePause then
|
||||||
|
break
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure StartLevel(var g: gameState; var level: levelState);
|
||||||
|
begin
|
||||||
|
InitLevel(level);
|
||||||
|
DrawLevel(level);
|
||||||
|
LevelLoop(g, level)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ContinueLevel(var g: gameState; var level: levelState);
|
||||||
|
begin
|
||||||
|
DrawLevel(level);
|
||||||
|
LevelLoop(g, level)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure RunMenu(var g: gameState);
|
||||||
|
var
|
||||||
|
prevMenu: boolean = false;
|
||||||
|
begin
|
||||||
|
g.curState := gameMenu;
|
||||||
|
while g.curState = gameMenu do
|
||||||
|
begin
|
||||||
|
if (g.curState = gameMenu) and not prevMenu then
|
||||||
|
begin
|
||||||
|
DrawMenu(g);
|
||||||
|
prevMenu := true
|
||||||
|
end;
|
||||||
|
delay(KeyDelayMs);
|
||||||
|
if keypressed then
|
||||||
|
HandleMenuKey(g);
|
||||||
|
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 MainLoop(var g: gameState);
|
||||||
|
var
|
||||||
|
level: levelState;
|
||||||
|
begin
|
||||||
|
while not g.shutdown do
|
||||||
|
begin
|
||||||
|
case g.curState of
|
||||||
|
gameExit:
|
||||||
|
RunExit(g);
|
||||||
|
gameScore:
|
||||||
|
RunScore(g);
|
||||||
|
gameKeyInfo:
|
||||||
|
RunKeyInfo(g);
|
||||||
|
gamePause:
|
||||||
|
RunPause(g);
|
||||||
|
gameStartLevel:
|
||||||
|
StartLevel(g, level);
|
||||||
|
gameContinueLevel: {Maybe here should be gameStartLevel}
|
||||||
|
ContinueLevel(g, level);
|
||||||
|
gameOver:
|
||||||
|
RunGameOver(g, level);
|
||||||
|
gameMenu:
|
||||||
|
RunMenu(g)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
EraseAll
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure NextExitState(var g: gameState);
|
||||||
|
begin
|
||||||
|
if g.curExit = exitNo then
|
||||||
|
g.curExit := exitYes
|
||||||
|
else
|
||||||
|
g.curExit := succ(g.curExit)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure PreviousExitState(var g: gameState);
|
||||||
|
begin
|
||||||
|
if g.curExit = exitYes then
|
||||||
|
g.curExit := exitNo
|
||||||
|
else
|
||||||
|
g.curExit := pred(g.curExit)
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
26
src/ghost_m.pas
Normal file
26
src/ghost_m.pas
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
unit ghost_m;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses creature_m;
|
||||||
|
|
||||||
|
const
|
||||||
|
GhostStartX = 5;
|
||||||
|
GhostStartY = 5;
|
||||||
|
GhostMovespeed = 1;
|
||||||
|
GhostStartDX = GhostMovespeed;
|
||||||
|
GhostStartDY = GhostMovespeed;
|
||||||
|
GhostSymbol = 'g';
|
||||||
|
|
||||||
|
procedure InitGhost(var g: creature);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
procedure InitGhost(var g: creature);
|
||||||
|
begin
|
||||||
|
InitCreature(g, GhostStartX, GhostStartY, GhostMovespeed, GhostSymbol);
|
||||||
|
g.dX := GhostStartDX;
|
||||||
|
g.dY := GhostStartDY
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
36
src/go.pas
Normal file
36
src/go.pas
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
program go_hamster;
|
||||||
|
uses crt, keys_m, arena_graphics_m, graphics_m, game_m, debug_m;
|
||||||
|
|
||||||
|
function IsTerminalValid: boolean;
|
||||||
|
begin
|
||||||
|
IsTerminalValid := (ScreenWidth >= ScreenW) and (ScreenHeight >= ScreenH)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure PrintTerminalHelp;
|
||||||
|
begin
|
||||||
|
writeln('Increase your terminal size and try again.');
|
||||||
|
if ScreenWidth < ScreenW then
|
||||||
|
begin
|
||||||
|
writeln('Your terminal width: ', ScreenWidth,
|
||||||
|
'. Required: ', ScreenW, '.')
|
||||||
|
end;
|
||||||
|
if ScreenHeight < ScreenH then
|
||||||
|
begin
|
||||||
|
writeln('Your terminal height: ', ScreenHeight,
|
||||||
|
'. Required: ', ScreenH, '.')
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
g: gameState;
|
||||||
|
begin
|
||||||
|
if not IsTerminalValid then
|
||||||
|
begin
|
||||||
|
PrintTerminalHelp;
|
||||||
|
exit
|
||||||
|
end;
|
||||||
|
InitGame(g);
|
||||||
|
EraseAll;
|
||||||
|
MainLoop(g)
|
||||||
|
end.
|
||||||
|
|
||||||
474
src/graphics_m.pas
Normal file
474
src/graphics_m.pas
Normal file
@ -0,0 +1,474 @@
|
|||||||
|
unit graphics_m;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses arena_graphics_m, arena_m, creature_m, hamster_m, trace_m, game_m, level_m;
|
||||||
|
|
||||||
|
procedure DrawAfterStep(var cr: creature; var a: arena);
|
||||||
|
procedure DrawAfterStep(var hamster: creature; var t: tracePtr; var a: arena);
|
||||||
|
procedure DrawCreature(var cr: creature);
|
||||||
|
procedure DrawExitState(s: exitState);
|
||||||
|
procedure DrawExit(var g: gameState);
|
||||||
|
procedure DrawGameOver;
|
||||||
|
procedure DrawKeyInfo;
|
||||||
|
procedure DrawLevel(var level: levelState);
|
||||||
|
procedure DrawLifes(n: integer);
|
||||||
|
procedure DrawMenuState(s: menuState);
|
||||||
|
procedure DrawMenu(var g: gameState);
|
||||||
|
procedure DrawPause(var g: gameState);
|
||||||
|
procedure DrawScore(s: integer);
|
||||||
|
procedure EraseAll;
|
||||||
|
procedure EraseExit;
|
||||||
|
procedure EraseExitState(s: exitState);
|
||||||
|
procedure EraseGameOver;
|
||||||
|
procedure EraseKeyInfo;
|
||||||
|
procedure EraseLevel;
|
||||||
|
procedure EraseMenu;
|
||||||
|
procedure EraseMenuState(s: menuState);
|
||||||
|
procedure ErasePause(var g: gameState);
|
||||||
|
procedure EraseStepTrace(var hamster: creature; t: tracePtr);
|
||||||
|
procedure EraseTrace(t: tracePtr; var a: arena);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses crt, math_m, ascii_arts_m;
|
||||||
|
|
||||||
|
const
|
||||||
|
BigLetterWidth = 8;
|
||||||
|
DigitWidth = 6;
|
||||||
|
BorderN = 2;
|
||||||
|
GameNameX = ScreenW * WidthCoefficient div 3 + 4;
|
||||||
|
GameNameY = 12;
|
||||||
|
GameOverX = ScreenW * WidthCoefficient div 2 - GameNameWidth div 2;
|
||||||
|
GameOverY = ScreenH div 2 - GameOverHeight div 2;
|
||||||
|
NameHeightPadding = 8;
|
||||||
|
MenuHeightPadding = 2;
|
||||||
|
MenuWidthPadding = 4;
|
||||||
|
MenuHamsterX = GameNameX - HamsterWidth - MenuWidthPadding;
|
||||||
|
NewGameY = GameNameY + GameNameHeight + NameHeightPadding;
|
||||||
|
HighScoreY = NewGameY + NewGameHeight + MenuHeightPadding;
|
||||||
|
MenuInfoY = HighScoreY + HighScoreHeight;
|
||||||
|
|
||||||
|
KeyInfoX = ScreenW * WidthCoefficient div 2 - KeyInfoWidth div 2;
|
||||||
|
KeyInfoY = ScreenH div 2 - KeyInfoHeight div 2 - 1;
|
||||||
|
|
||||||
|
ContinueY = MenuInfoY + MenuInfoHeight;
|
||||||
|
InterfaceMarginX = InterfaceCellW div 4;
|
||||||
|
InterfaceMarginY = InterfaceBarH div 4 + BorderSize + 1;
|
||||||
|
LetterWidth = 5;
|
||||||
|
Notation = 10;
|
||||||
|
PunctuationWidth = 3;
|
||||||
|
SpaceWidth = 1;
|
||||||
|
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;
|
||||||
|
PauseXPadding = 3 * WidthCoefficient;
|
||||||
|
PauseYPadding = 1;
|
||||||
|
PauseX = (ScreenW * WidthCoefficient - PauseWidth) div 2;
|
||||||
|
PauseY = (ScreenH - PauseHeight) div 2;
|
||||||
|
|
||||||
|
ArenaPauseUpperMarginY = 7;
|
||||||
|
ArenaPauseLowerMarginY = 14;
|
||||||
|
ArenaPauseMarginX = 9;
|
||||||
|
var
|
||||||
|
firstMenuDraw: boolean = true;
|
||||||
|
|
||||||
|
procedure EraseTrace(t: tracePtr; var a: arena);
|
||||||
|
begin
|
||||||
|
while t <> nil do
|
||||||
|
begin
|
||||||
|
if t^.prev = nil then
|
||||||
|
DrawEdge(t^.x, t^.y, a)
|
||||||
|
else
|
||||||
|
DrawArenaCell(t^.x, t^.y, ArenaSymbol);
|
||||||
|
t := t^.prev
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure EraseStepTrace(var hamster: creature; t: tracePtr);
|
||||||
|
var
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
for i := 1 to hamster.movespeed do
|
||||||
|
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;
|
||||||
|
|
||||||
|
procedure DrawStepTrace(t: tracePtr; hamsterDelta: integer);
|
||||||
|
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
|
||||||
|
DrawStepTrace(t, hamster.movespeed);
|
||||||
|
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;
|
||||||
|
|
||||||
|
procedure FillRectangle(x, y, w, h: integer; ch: char);
|
||||||
|
var
|
||||||
|
i, j: integer;
|
||||||
|
begin
|
||||||
|
for i := 0 to h - 1 do
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
procedure DrawDigit(x, y, digit: integer);
|
||||||
|
begin
|
||||||
|
DrawAscii(x, y, DigitHeight, DigitsAscii[digit])
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawNumber(interfaceX: integer; s: longint);
|
||||||
|
var
|
||||||
|
x, y: integer;
|
||||||
|
i: integer = 0;
|
||||||
|
st: StackInt;
|
||||||
|
begin
|
||||||
|
StackIntInit(st);
|
||||||
|
if s = 0 then
|
||||||
|
StackPush(st, 0);
|
||||||
|
while s <> 0 do
|
||||||
|
begin
|
||||||
|
StackPush(st, s mod Notation);
|
||||||
|
s := s div Notation
|
||||||
|
end;
|
||||||
|
x := interfaceX + InterfaceMarginX;
|
||||||
|
y := InterfaceMarginY;
|
||||||
|
while st.top <> nil do
|
||||||
|
begin
|
||||||
|
DrawDigit(x + (DigitWidth + SpaceWidth) * i, y, st.top^.val);
|
||||||
|
StackPop(st);
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawLifes(n: integer);
|
||||||
|
begin
|
||||||
|
DrawNumber(LifeBarX, n)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawScore(s: integer);
|
||||||
|
var
|
||||||
|
killBarX: integer = InterfaceCellW * 2 * WidthCoefficient + BorderSize;
|
||||||
|
begin
|
||||||
|
DrawNumber(killBarX, s)
|
||||||
|
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, MenuInfoY + 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, MenuInfoY, MenuInfoHeight, KeyInfoAscii);
|
||||||
|
DrawAscii(GameNameX, ContinueY, ContinueHeight, ContinueAscii);
|
||||||
|
if not g.continueAllowed then
|
||||||
|
FillRectangle(GameNameX, ContinueY + ContinueHeight div 2,
|
||||||
|
ContinueWidth, 1, '-');
|
||||||
|
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, MenuInfoY + 1,
|
||||||
|
HamsterWidth, HamsterHeight);
|
||||||
|
menuContinue:
|
||||||
|
EraseRectangle(MenuHamsterX, ContinueY + 1,
|
||||||
|
HamsterWidth, HamsterHeight)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure EraseAll;
|
||||||
|
begin
|
||||||
|
EraseRectangle(1, 1, ScreenW * WidthCoefficient, ScreenH)
|
||||||
|
end;
|
||||||
|
|
||||||
|
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,
|
||||||
|
HamsterHeight, HamsterGGAscii);
|
||||||
|
exitNo:
|
||||||
|
DrawAscii(HamsterNoX, ExitHamsterY,
|
||||||
|
HamsterHeight, HamsterStayAscii)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawPause(var g: gameState);
|
||||||
|
begin
|
||||||
|
EraseRectangle(PauseX - PauseXPadding,
|
||||||
|
PauseY - PauseYPadding,
|
||||||
|
PauseWidth + PauseXPadding * 2 - 1,
|
||||||
|
PauseHeight + PauseYPadding * 2 + 1);
|
||||||
|
DrawRectangle(PauseX - PauseXPadding,
|
||||||
|
PauseY - PauseYPadding,
|
||||||
|
PauseHeight + PauseYPadding * 2 + 1,
|
||||||
|
PauseWidth + PauseXPadding * 2);
|
||||||
|
DrawAscii(PauseX, PauseY, PauseHeight, PauseAscii)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ErasePause(var g: gameState);
|
||||||
|
begin
|
||||||
|
EraseRectangle(PauseX - PauseXPadding,
|
||||||
|
PauseY - PauseYPadding,
|
||||||
|
PauseWidth + PauseXPadding * 2 - 1,
|
||||||
|
PauseHeight + PauseYPadding * 2 + 1)
|
||||||
|
end;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
procedure EraseKeyInfo;
|
||||||
|
begin
|
||||||
|
EraseRectangle(KeyInfoX, KeyInfoY, KeyInfoWidth, KeyInfoHeight)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawKeyInfo;
|
||||||
|
begin
|
||||||
|
DrawAscii(KeyInfoX, KeyInfoY, KeyInfoHeight, KeyInfoScreen)
|
||||||
|
end;
|
||||||
|
|
||||||
|
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)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawTrace(t: tracePtr);
|
||||||
|
begin
|
||||||
|
if t <> nil then
|
||||||
|
t := t^.prev;
|
||||||
|
while t <> nil do
|
||||||
|
begin
|
||||||
|
DrawArenaCell(t^.x, t^.y, TraceSymbol);
|
||||||
|
t := t^.prev
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure FillPauseCells(var a: arena);
|
||||||
|
var
|
||||||
|
i, j: integer;
|
||||||
|
begin
|
||||||
|
for i := ArenaPauseUpperMarginY to (ArenaW - ArenaPauseLowerMarginY) do
|
||||||
|
for j := (1 + ArenaPauseMarginX) to (ArenaH - ArenaPauseMarginX) do
|
||||||
|
if a.borders[j][i] then
|
||||||
|
DrawArenaCell(j, i, BorderSymbol)
|
||||||
|
else
|
||||||
|
if a.captured[j][i] then
|
||||||
|
DrawArenaCell(j, i, CaptureSymbol)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawLevel(var level: levelState);
|
||||||
|
begin
|
||||||
|
DrawInterface;
|
||||||
|
FillPauseCells(level.a);
|
||||||
|
DrawTrace(level.t);
|
||||||
|
DrawCreature(level.h);
|
||||||
|
DrawCreature(level.g);
|
||||||
|
DrawScore(level.score);
|
||||||
|
DrawLifes(level.life)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure EraseLevel;
|
||||||
|
begin
|
||||||
|
EraseRectangle(2, 2,
|
||||||
|
ScreenW * WidthCoefficient - BorderSize * BorderN,
|
||||||
|
ScreenH - BorderSize * BorderN);
|
||||||
|
DrawRectangle(1, 1, ScreenH, ScreenW * WidthCoefficient)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure EraseGameOver;
|
||||||
|
begin
|
||||||
|
EraseRectangle(GameOverX, GameOverY, GameOverWidth, GameOverHeight)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawGameOver;
|
||||||
|
begin
|
||||||
|
DrawAscii(GameOverX, GameOverY, GameOverHeight, GameOverScreen)
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
50
src/hamster_m.pas
Normal file
50
src/hamster_m.pas
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
unit hamster_m;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses arena_graphics_m, arena_m, creature_m, trace_m;
|
||||||
|
|
||||||
|
const
|
||||||
|
HamsterStartX = 5;
|
||||||
|
HamsterStartY = 1;
|
||||||
|
HamsterStartDX = 0;
|
||||||
|
HamsterStartDY = 0;
|
||||||
|
HamsterMovespeed = 2;
|
||||||
|
HamsterSymbol = 'h';
|
||||||
|
|
||||||
|
procedure InitHamster(var h: creature);
|
||||||
|
procedure KillHamster(var h: creature; var t: tracePtr; var a: arena);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses graphics_m;
|
||||||
|
|
||||||
|
procedure InitHamster(var h: creature);
|
||||||
|
begin
|
||||||
|
InitCreature(h, HamsterStartX, HamsterStartY,
|
||||||
|
HamsterMovespeed, HamsterSymbol);
|
||||||
|
h.dX := HamsterStartDX;
|
||||||
|
h.dY := HamsterStartDY
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure KillHamster(var h: creature; var t: tracePtr; var a: arena);
|
||||||
|
var
|
||||||
|
traceStart: tracePtr;
|
||||||
|
begin
|
||||||
|
DrawArenaCell(h.curX, h.curY, ArenaSymbol);
|
||||||
|
EraseTrace(t, a);
|
||||||
|
if IsOnEdge(h) then
|
||||||
|
DrawEdge(h.curX, h.curY, a)
|
||||||
|
else
|
||||||
|
if a.borders[h.curX][h.curY] then
|
||||||
|
DrawArenaCell(h.curX, h.curY, BorderSymbol);
|
||||||
|
GetStart(traceStart, t);
|
||||||
|
h.curX := traceStart^.x;
|
||||||
|
h.curY := traceStart^.y;
|
||||||
|
h.dX := HamsterStartDX;
|
||||||
|
h.dY := HamsterStartDY;
|
||||||
|
DeleteTrace(t);
|
||||||
|
DrawCreature(h)
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
282
src/keys_m.pas
Normal file
282
src/keys_m.pas
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
unit keys_m;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses crt, creature_m, arena_m, game_m, trace_m, hamster_m, debug_m;
|
||||||
|
|
||||||
|
const
|
||||||
|
ArrowDownOrd = -80;
|
||||||
|
ArrowLeftOrd = -75;
|
||||||
|
ArrowRightOrd = -77;
|
||||||
|
ArrowUpOrd = -72;
|
||||||
|
CtrlCOrd = 3;
|
||||||
|
EnterOrd = 13;
|
||||||
|
EscOrd = 27;
|
||||||
|
LowerNOrd = 110;
|
||||||
|
LowerYOrd = 121;
|
||||||
|
SpaceOrd = 32;
|
||||||
|
UpperNOrd = 78;
|
||||||
|
UpperYOrd = 89;
|
||||||
|
|
||||||
|
OneOrd = 49;
|
||||||
|
TwoOrd = 50;
|
||||||
|
ThreeOrd = 51;
|
||||||
|
FourOrd = 52;
|
||||||
|
UpperQOrd = 81;
|
||||||
|
LowerQOrd = 113;
|
||||||
|
|
||||||
|
{ Debug }
|
||||||
|
BOrd = 98;
|
||||||
|
COrd = 99;
|
||||||
|
LOrd = 108;
|
||||||
|
{ Debug }
|
||||||
|
|
||||||
|
procedure GetKey(var keyCode: integer);
|
||||||
|
procedure HandleExitKey(var g: gameState);
|
||||||
|
procedure HandleLevelKey(var h: creature; var a: arena;
|
||||||
|
var t: tracePtr; var g: gameState);
|
||||||
|
procedure HandleMenuKey(var g: gameState);
|
||||||
|
procedure HandleInfoKey(var g: gameState);
|
||||||
|
procedure HandleGameOverKey(var g: gameState);
|
||||||
|
procedure HandleScoreKey(var g: gameState);
|
||||||
|
procedure HandlePauseKey(var g: gameState);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses graphics_m;
|
||||||
|
|
||||||
|
procedure GetKey(var keyCode: integer);
|
||||||
|
var
|
||||||
|
c: char;
|
||||||
|
begin
|
||||||
|
c := ReadKey;
|
||||||
|
if c = #0 then
|
||||||
|
begin
|
||||||
|
c := ReadKey;
|
||||||
|
keyCode := -ord(c)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
keyCode := ord(c)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ChangeHamsterDelta(k: integer; var h: creature);
|
||||||
|
begin
|
||||||
|
h.dX := 0;
|
||||||
|
h.dY := 0;
|
||||||
|
case k of
|
||||||
|
ArrowLeftOrd:
|
||||||
|
h.dX := -h.movespeed;
|
||||||
|
ArrowRightOrd:
|
||||||
|
h.dX := h.movespeed;
|
||||||
|
ArrowUpOrd:
|
||||||
|
h.dY := -h.movespeed;
|
||||||
|
ArrowDownOrd:
|
||||||
|
h.dY := h.movespeed;
|
||||||
|
SpaceOrd:
|
||||||
|
StopCreature(h)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure HandleLevelKey(var h: creature; var a: arena;
|
||||||
|
var t: tracePtr; var g: gameState);
|
||||||
|
var
|
||||||
|
k: integer;
|
||||||
|
begin
|
||||||
|
GetKey(k);
|
||||||
|
{DEBUG}
|
||||||
|
if k = BOrd then
|
||||||
|
Print(a.borders);
|
||||||
|
if k = COrd then
|
||||||
|
Print(a.captured);
|
||||||
|
if k = LOrd then
|
||||||
|
begin
|
||||||
|
GotoXY(2, 60);
|
||||||
|
write(' ');
|
||||||
|
GotoXY(2, 60);
|
||||||
|
writeln(GetLength(t));
|
||||||
|
GotoXY(1, 1)
|
||||||
|
end;
|
||||||
|
{DEBUG}
|
||||||
|
if (k = ArrowLeftOrd) or (k = ArrowRightOrd) or (k = ArrowUpOrd) or
|
||||||
|
(k = ArrowDownOrd) or (k = SpaceOrd) then
|
||||||
|
begin
|
||||||
|
ChangeHamsterDelta(k, h)
|
||||||
|
end;
|
||||||
|
if k = EscOrd then
|
||||||
|
g.curState := gamePause
|
||||||
|
{
|
||||||
|
if k = CtrlCOrd then
|
||||||
|
continueLevel := false
|
||||||
|
}
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure PreviousMenuState(var g: gameState);
|
||||||
|
begin
|
||||||
|
if (g.curMenu = menuNewGame) and not g.continueAllowed then
|
||||||
|
g.curMenu := menuKeyInfo
|
||||||
|
else
|
||||||
|
if g.curMenu = menuNewGame then
|
||||||
|
g.curMenu := menuContinue
|
||||||
|
else
|
||||||
|
g.curMenu := pred(g.curMenu)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure NextMenuState(var g: gameState);
|
||||||
|
begin
|
||||||
|
if (g.curMenu = menuKeyInfo) and not g.continueAllowed or
|
||||||
|
(g.curMenu = menuContinue) then
|
||||||
|
begin
|
||||||
|
g.curMenu := menuNewGame
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
g.curMenu := succ(g.curMenu)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ChangeMenuState(k: integer; var g: gameState);
|
||||||
|
begin
|
||||||
|
case k of
|
||||||
|
ArrowUpOrd:
|
||||||
|
PreviousMenuState(g);
|
||||||
|
ArrowDownOrd:
|
||||||
|
NextMenuState(g)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ChooseMenuNum(k: integer; var g: gameState);
|
||||||
|
begin
|
||||||
|
if (k = FourOrd) and not g.continueAllowed then
|
||||||
|
exit;
|
||||||
|
case k of
|
||||||
|
OneOrd:
|
||||||
|
g.curState := gameStartLevel;
|
||||||
|
TwoOrd:
|
||||||
|
g.curState := gameScore;
|
||||||
|
ThreeOrd:
|
||||||
|
g.curState := gameKeyInfo;
|
||||||
|
FourOrd:
|
||||||
|
g.curState := gameContinueLevel
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ChooseMenuMarked(var g: gameState);
|
||||||
|
begin
|
||||||
|
case g.curMenu of
|
||||||
|
menuNewGame:
|
||||||
|
g.curState := gameStartLevel;
|
||||||
|
menuHighScore:
|
||||||
|
g.curState := gameScore;
|
||||||
|
menuKeyInfo:
|
||||||
|
g.curState := gameKeyInfo;
|
||||||
|
menuContinue:
|
||||||
|
g.curState := gameContinueLevel
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure HandleMenuKey(var g: gameState);
|
||||||
|
var
|
||||||
|
k: integer;
|
||||||
|
begin
|
||||||
|
GetKey(k);
|
||||||
|
if (k = ArrowUpOrd) or (k = ArrowDownOrd) then
|
||||||
|
begin
|
||||||
|
EraseMenuState(g.curMenu);
|
||||||
|
ChangeMenuState(k, g);
|
||||||
|
DrawMenuState(g.curMenu)
|
||||||
|
end;
|
||||||
|
if (k = OneOrd) or (k = TwoOrd) or (k = ThreeOrd) or (k = FourOrd) then
|
||||||
|
ChooseMenuNum(k, g);
|
||||||
|
if (k = EscOrd) or (k = UpperQOrd) or (k = LowerQOrd) then
|
||||||
|
g.curState := gameExit;
|
||||||
|
if (k = EnterOrd) or (k = SpaceOrd) then
|
||||||
|
ChooseMenuMarked(g);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure HandleGameOverKey(var g: gameState);
|
||||||
|
var
|
||||||
|
k: integer;
|
||||||
|
begin
|
||||||
|
GetKey(k);
|
||||||
|
case k of
|
||||||
|
UpperYOrd, LowerYOrd:
|
||||||
|
g.curState := gameContinueLevel;
|
||||||
|
UpperNOrd, LowerNOrd:
|
||||||
|
g.curState := gameMenu;
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ChangeExitState(k: integer; var g: gameState);
|
||||||
|
begin
|
||||||
|
case k of
|
||||||
|
ArrowRightOrd:
|
||||||
|
NextExitState(g);
|
||||||
|
ArrowLeftOrd:
|
||||||
|
PreviousExitState(g)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure HandleExitKey(var g: gameState);
|
||||||
|
var
|
||||||
|
k: integer;
|
||||||
|
begin
|
||||||
|
GetKey(k);
|
||||||
|
if (k = ArrowLeftOrd) or (k = ArrowRightOrd) then
|
||||||
|
begin
|
||||||
|
EraseExitState(g.curExit);
|
||||||
|
ChangeExitState(k, g);
|
||||||
|
DrawExitState(g.curExit);
|
||||||
|
exit
|
||||||
|
end;
|
||||||
|
if (k = EnterOrd) or (k = SpaceOrd) then
|
||||||
|
begin
|
||||||
|
if g.curExit = exitYes then
|
||||||
|
g.shutdown := true
|
||||||
|
else
|
||||||
|
g.curExit := exitYes;
|
||||||
|
end;
|
||||||
|
if (k = UpperYOrd) or (k = LowerYOrd) or (k = OneOrd) then
|
||||||
|
g.shutdown := true;
|
||||||
|
if (k = UpperNOrd) or (k = LowerNOrd) or (k = EscOrd) or (k = TwoOrd) then
|
||||||
|
g.curExit := exitYes;
|
||||||
|
g.curState := gameMenu
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure HandlePauseKey(var g: gameState);
|
||||||
|
var
|
||||||
|
k: integer;
|
||||||
|
begin
|
||||||
|
GetKey(k);
|
||||||
|
if (k = EscOrd) or (k = SpaceOrd) then
|
||||||
|
g.curState := gameContinueLevel;
|
||||||
|
if (k = UpperQOrd) or (k = LowerQOrd) then
|
||||||
|
g.curState := gameMenu;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure HandleInfoKey(var g: gameState);
|
||||||
|
var
|
||||||
|
k: integer;
|
||||||
|
begin
|
||||||
|
GetKey(k);
|
||||||
|
if (k = EscOrd) or (k = SpaceOrd) or (k = EnterOrd) or
|
||||||
|
(k = UpperQOrd) or (k = LowerQOrd) then
|
||||||
|
begin
|
||||||
|
g.curState := gameMenu;
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure HandleScoreKey(var g: gameState);
|
||||||
|
var
|
||||||
|
k: integer;
|
||||||
|
begin
|
||||||
|
GetKey(k);
|
||||||
|
if (k = EscOrd) or (k = SpaceOrd) or (k = EnterOrd) or
|
||||||
|
(k = UpperQOrd) or (k = LowerQOrd) then
|
||||||
|
begin
|
||||||
|
g.curState := gameMenu;
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
43
src/level_m.pas
Normal file
43
src/level_m.pas
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
unit level_m;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses arena_m, trace_m, creature_m;
|
||||||
|
|
||||||
|
type
|
||||||
|
levelState = record
|
||||||
|
a: arena;
|
||||||
|
t: tracePtr;
|
||||||
|
levelStarted, continueLevel, hamsterAlive: boolean;
|
||||||
|
h, g: creature;
|
||||||
|
life, score: integer
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure InitLevel(var level: levelState);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
uses hamster_m, ghost_m;
|
||||||
|
|
||||||
|
const
|
||||||
|
StartScore = 0;
|
||||||
|
StartLifes = 3;
|
||||||
|
{
|
||||||
|
BonusTurns = 45;
|
||||||
|
StartSpeedBonus = 0;
|
||||||
|
StartSlowBonus = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
procedure InitLevel(var level: levelState);
|
||||||
|
begin
|
||||||
|
InitArena(level.a);
|
||||||
|
InitHamster(level.h);
|
||||||
|
InitGhost(level.g);
|
||||||
|
level.levelStarted := true;
|
||||||
|
level.continueLevel := true;
|
||||||
|
level.hamsterAlive := true;
|
||||||
|
level.t := nil;
|
||||||
|
level.life := StartLifes;
|
||||||
|
level.score := StartScore
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
36
src/math_m.pas
Normal file
36
src/math_m.pas
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
unit math_m;
|
||||||
|
interface
|
||||||
|
|
||||||
|
function Clamp(val, min, max: integer): integer;
|
||||||
|
function Signum(a, b: integer): integer;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
function Clamp(val, min, max: integer): integer;
|
||||||
|
begin
|
||||||
|
Clamp := val;
|
||||||
|
if val < min then
|
||||||
|
Clamp := min;
|
||||||
|
if val > max then
|
||||||
|
Clamp := max
|
||||||
|
end;
|
||||||
|
|
||||||
|
function Signum(a, b: integer): integer;
|
||||||
|
begin
|
||||||
|
if a < b then
|
||||||
|
Signum := -1
|
||||||
|
else
|
||||||
|
if a > b then
|
||||||
|
Signum := 1
|
||||||
|
else
|
||||||
|
Signum := 0
|
||||||
|
end;
|
||||||
|
|
||||||
|
function Abs(val: integer): integer;
|
||||||
|
begin
|
||||||
|
if val < 0 then
|
||||||
|
val := val * -1;
|
||||||
|
Abs := val
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
188
src/trace_m.pas
Normal file
188
src/trace_m.pas
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
unit trace_m;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses creature_m, math_m;
|
||||||
|
|
||||||
|
const
|
||||||
|
PreviousTraceIdx = 3;
|
||||||
|
TraceSymbol = '+';
|
||||||
|
|
||||||
|
type
|
||||||
|
tracePtr = ^trace;
|
||||||
|
|
||||||
|
trace = record
|
||||||
|
x, y: integer;
|
||||||
|
prev: tracePtr
|
||||||
|
end;
|
||||||
|
|
||||||
|
function FindIndex(var t: tracePtr; x, y, curIdx: integer): integer;
|
||||||
|
function GetLength(var t: tracePtr): integer;
|
||||||
|
function IsOnTrace(var cr: creature; t: tracePtr): boolean;
|
||||||
|
function IsOnTrace(x, y: integer; t: tracePtr): boolean;
|
||||||
|
function
|
||||||
|
TraceCrossed(prevX, prevY: integer; var cr: creature; t: tracePtr): boolean;
|
||||||
|
procedure ChangeHamsterTrace(var h: creature; var t: tracePtr);
|
||||||
|
procedure DecreaseTrace(var hamster: creature; var t: tracePtr);
|
||||||
|
procedure DeleteTrace(var t: tracePtr);
|
||||||
|
procedure GetStart(var traceStart: tracePtr; t: tracePtr);
|
||||||
|
procedure IncreaseTrace(var hamster: creature; var t: tracePtr);
|
||||||
|
procedure Pop(var t: tracePtr);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses graphics_m;
|
||||||
|
|
||||||
|
function GetLength(var t: tracePtr): integer;
|
||||||
|
begin
|
||||||
|
if t = nil then
|
||||||
|
GetLength := 0
|
||||||
|
else
|
||||||
|
GetLength := 1 + GetLength(t^.prev)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure GetStart(var traceStart: tracePtr; t: tracePtr);
|
||||||
|
begin
|
||||||
|
while t <> nil do
|
||||||
|
begin
|
||||||
|
if t^.prev = nil then
|
||||||
|
traceStart := t;
|
||||||
|
t := t^.prev
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DeleteTrace(var t: tracePtr);
|
||||||
|
var
|
||||||
|
tmpT: tracePtr;
|
||||||
|
begin
|
||||||
|
while t <> nil do
|
||||||
|
begin
|
||||||
|
tmpT := t^.prev;
|
||||||
|
dispose(t);
|
||||||
|
t := tmpT
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
function FindIndex(var t: tracePtr; x, y, curIdx: integer): integer;
|
||||||
|
begin
|
||||||
|
if t = nil then
|
||||||
|
FindIndex := -1
|
||||||
|
else
|
||||||
|
if (t^.x = x) and (t^.y = y) then
|
||||||
|
FindIndex := curIdx
|
||||||
|
else
|
||||||
|
FindIndex := FindIndex(t^.prev, x, y, curIdx + 1)
|
||||||
|
end;
|
||||||
|
|
||||||
|
function IsOnTrace(x, y: integer; t: tracePtr): boolean;
|
||||||
|
begin
|
||||||
|
if t = nil then
|
||||||
|
IsOnTrace := false
|
||||||
|
else
|
||||||
|
if (t^.x = x) and (t^.y = y) then
|
||||||
|
IsOnTrace := true
|
||||||
|
else
|
||||||
|
IsOnTrace := IsOnTrace(x, y, t^.prev)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure Add(var t: tracePtr; x, y: integer);
|
||||||
|
var
|
||||||
|
nextTrace: tracePtr;
|
||||||
|
begin
|
||||||
|
new(nextTrace);
|
||||||
|
nextTrace^.x := x;
|
||||||
|
nextTrace^.y := y;
|
||||||
|
nextTrace^.prev := t;
|
||||||
|
t := nextTrace
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure Pop(var t: tracePtr);
|
||||||
|
var
|
||||||
|
tmpPrev: tracePtr;
|
||||||
|
begin
|
||||||
|
tmpPrev := t^.prev;
|
||||||
|
dispose(t);
|
||||||
|
t := tmpPrev
|
||||||
|
end;
|
||||||
|
|
||||||
|
function IsOnTrace(var cr: creature; t: tracePtr): boolean;
|
||||||
|
begin
|
||||||
|
IsOnTrace := IsOnTrace(cr.curX, cr.curY, t)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure AddStepTrace(var h: creature; var t: tracePtr);
|
||||||
|
var
|
||||||
|
nextX, nextY, dX, dY: integer;
|
||||||
|
begin
|
||||||
|
dX := Signum(h.curX, t^.x);
|
||||||
|
dY := Signum(h.curY, t^.y);
|
||||||
|
nextX := t^.x + dX;
|
||||||
|
nextY := t^.y + dY;
|
||||||
|
Add(t, nextX, nextY)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure AddFirstTrace(var hamster: creature; var t: tracePtr);
|
||||||
|
var
|
||||||
|
traceX, traceY, dX, dY: integer;
|
||||||
|
begin
|
||||||
|
dX := Signum(hamster.curX - hamster.dX, hamster.curX) * hamster.movespeed;
|
||||||
|
dY := Signum(hamster.curY - hamster.dY, hamster.curY) * hamster.movespeed;
|
||||||
|
traceX := hamster.curX + dX;
|
||||||
|
traceY := hamster.curY + dY;
|
||||||
|
Add(t, traceX, traceY)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure IncreaseTrace(var hamster: creature; var t: tracePtr);
|
||||||
|
var
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
if t = nil then
|
||||||
|
AddFirstTrace(hamster, t);
|
||||||
|
for i := 1 to hamster.movespeed do
|
||||||
|
AddStepTrace(hamster, t)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DecreaseTrace(var hamster: creature; var t: tracePtr);
|
||||||
|
var
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
for i := 1 to hamster.movespeed do
|
||||||
|
Pop(t);
|
||||||
|
if GetLength(t) = 1 then
|
||||||
|
Pop(t)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ChangeHamsterTrace(var h: creature; var t: tracePtr);
|
||||||
|
begin
|
||||||
|
if IsOnTrace(h, t) then
|
||||||
|
begin
|
||||||
|
EraseStepTrace(h, t);
|
||||||
|
DecreaseTrace(h, t)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
IncreaseTrace(h, t)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
function
|
||||||
|
TraceCrossed(prevX, prevY: integer; var cr: creature; t: tracePtr): boolean;
|
||||||
|
var
|
||||||
|
dX, dY: integer;
|
||||||
|
begin
|
||||||
|
dX := Signum(cr.curX, prevX);
|
||||||
|
dY := Signum(cr.curY, prevY);
|
||||||
|
while (prevX <> cr.curX) and (prevY <> cr.curY) do
|
||||||
|
begin
|
||||||
|
if IsOnTrace(prevX, prevY, t) then
|
||||||
|
begin
|
||||||
|
TraceCrossed := true;
|
||||||
|
exit
|
||||||
|
end;
|
||||||
|
prevX := prevX + dX;
|
||||||
|
prevY := prevY + dY
|
||||||
|
end;
|
||||||
|
TraceCrossed := false
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
Loading…
Reference in New Issue
Block a user