608 lines
16 KiB
ObjectPascal
608 lines
16 KiB
ObjectPascal
unit arena_graphics_m;
|
|
|
|
interface
|
|
|
|
uses arena_m, creature_m, trace_m, level_m, _banners_m;
|
|
|
|
const
|
|
ArenaSymbol = ' ';
|
|
CaptureSymbol = '.';
|
|
|
|
procedure DrawAfterHamsterStep(var h: creature; var t: tracePtr; var a: arena);
|
|
procedure DrawAliveEnemies(var e: creatureList);
|
|
procedure RedrawArea(var a: arena; arenaX, arenaY: integer; t: creatureType);
|
|
procedure DrawArenaBorders(var a: arena);
|
|
procedure DrawCreature(var cr: creature);
|
|
procedure DrawFieldCell(arenaX, arenaY: integer; symbol: char);
|
|
procedure DrawArenaEdges;
|
|
procedure DrawPause;
|
|
procedure DrawTrace(a: tracePtr);
|
|
procedure DrawHamster(var h: creature);
|
|
procedure FillCellsCapture(var a: arena);
|
|
procedure FillCompleteBar(s: integer);
|
|
procedure DrawArenaCell(x, y: integer; var a: arena);
|
|
procedure DrawLevel(var level: levelState; life, score: integer);
|
|
procedure DrawLevelUnpause(var level: levelState);
|
|
procedure DrawLifesNumber(n: integer);
|
|
procedure DrawScore(s: integer);
|
|
procedure EraseStepTrace(var hamster: creature; a: tracePtr);
|
|
procedure EraseLifesNumber(n: integer);
|
|
procedure EraseTrace(tp: tracePtr; var a: arena);
|
|
|
|
implementation
|
|
|
|
uses ascii_arts_m, crt, math_m, hamster_m, graphics_m;
|
|
const
|
|
ArenaPauseLowerMarginY = 14;
|
|
ArenaPauseMarginX = 9;
|
|
ArenaPauseUpperMarginY = 7;
|
|
InterfaceBarH = ScreenH - ArenaH * CellSize + BorderSize; { 14 }
|
|
InterfaceCellW = ScreenW div 3;
|
|
InterfaceMarginX = InterfaceCellW div 4;
|
|
InterfaceMarginY = InterfaceBarH div 4 + BorderSize + 1;
|
|
CompleteBarMarginY = 4;
|
|
CompleteBarMarginX = 5;
|
|
CompleteBarX = (
|
|
InterfaceCellW * WidthCoefficient + BorderSize + CompleteBarMarginX
|
|
);
|
|
CompleteBarY = BorderSize + CompleteBarMarginY + 1;
|
|
TotalProcent = 100;
|
|
CompleteBarH = InterfaceBarH - BorderSize * 2 - CompleteBarMarginY * 2;
|
|
CompleteBarW = (
|
|
InterfaceCellW * WidthCoefficient - CompleteBarMarginX * 2
|
|
);
|
|
BarWinX = CompleteBarW * LevelCompleteThreshold div TotalProcent;
|
|
LifeBarX = 17;
|
|
LifeNumberX = 27;
|
|
MidCellDelimiter = '_';
|
|
HamsterLifeY = 5;
|
|
DecimalBase = 10;
|
|
PauseXPadding = 3 * WidthCoefficient;
|
|
PauseX = (ScreenW * WidthCoefficient - PauseWidth) div 2;
|
|
PauseYPadding = 1;
|
|
PauseY = (ScreenH - PauseHeight) div 2;
|
|
InterfaceArenaCellX1 = 15;
|
|
InterfaceArenaCellX2 = 29;
|
|
|
|
type
|
|
redrawAreaBox = record
|
|
lX, lY, rX, rY: integer
|
|
end;
|
|
|
|
const
|
|
RedrawAreas: array[creatureType] of redrawAreaBox = (
|
|
(
|
|
lX: -HamsterWidth div CellSize div WidthCoefficient;
|
|
lY: -HamsterHeight div CellSize; rX: 0; rY: 0
|
|
),
|
|
(
|
|
lX: -GhostWidth div CellSize div WidthCoefficient;
|
|
lY: 0; rX: 0; rY: GhostHeight div CellSize
|
|
),
|
|
(
|
|
lX: 0; lY: 0; rX: 0; rY: 0
|
|
),
|
|
(
|
|
lX: 0; lY: 0; rX: 0; rY: 0
|
|
),
|
|
(
|
|
lX: 0; lY: 0; rX: 0; rY: 0
|
|
)
|
|
);
|
|
|
|
procedure DrawCompleteBar;
|
|
begin
|
|
FillRectangle(CompleteBarX, CompleteBarY, CompleteBarW, CompleteBarH, '-');
|
|
FillRectangle(CompleteBarX + BarWinX, CompleteBarY,
|
|
1, CompleteBarH, '|')
|
|
end;
|
|
|
|
procedure FillCompleteBar(s: integer);
|
|
var
|
|
cutedProcent: integer = 0;
|
|
fillW: integer;
|
|
begin
|
|
if s <> 0 then
|
|
cutedProcent := round(s / (TotalCells / TotalProcent));
|
|
fillW := round(CompleteBarW / TotalProcent * cutedProcent);
|
|
FillRectangle(CompleteBarX, CompleteBarY, fillW, CompleteBarH, '+')
|
|
end;
|
|
|
|
procedure DrawAliveEnemies(var e: creatureList);
|
|
var
|
|
tmp: creatureItemPtr;
|
|
begin
|
|
tmp := e.first;
|
|
while tmp <> nil do
|
|
begin
|
|
if tmp^.cr^.alive then
|
|
DrawCreature(tmp^.cr^);
|
|
tmp := tmp^.next
|
|
end
|
|
end;
|
|
|
|
procedure DrawFieldAscii(arenaX, arenaY, h, w: integer; var a: CreatureImage);
|
|
var
|
|
screenX, screenY: integer;
|
|
begin
|
|
screenX := BorderSize + (arenaX - 1) * CellSize * WidthCoefficient;
|
|
screenY := InterfaceBarH + (arenaY - 1) * CellSize;
|
|
DrawCreatureImage(screenX, screenY, h, a)
|
|
end;
|
|
|
|
procedure DrawStepTrace(a: tracePtr; hamsterDelta: integer);
|
|
var
|
|
i: integer;
|
|
t: tracePtr;
|
|
begin
|
|
t := a;
|
|
for i := 1 to HamsterDelta + 2 do
|
|
begin
|
|
t := t^.prev;
|
|
if t = nil then
|
|
break;
|
|
DrawFieldCell(t^.x, t^.y, TraceSymbol)
|
|
end
|
|
end;
|
|
|
|
procedure DrawPreviousCell(var cr: creature; var a: arena);
|
|
var
|
|
prevX, prevY: integer;
|
|
begin
|
|
prevX := cr.curX - cr.dX;
|
|
prevY := cr.curY - cr.dY;
|
|
DrawArenaCell(prevX, prevY, a)
|
|
end;
|
|
|
|
procedure EraseStepTrace(var hamster: creature; a: tracePtr);
|
|
var
|
|
i: integer;
|
|
t: tracePtr;
|
|
begin
|
|
t := a;
|
|
for i := 1 to hamster.movespeed do
|
|
begin
|
|
DrawFieldCell(t^.x, t^.y, ArenaSymbol);
|
|
t := t^.prev
|
|
end;
|
|
if GetLength(t) = 1 then
|
|
begin
|
|
if IsOnEdge(hamster) then
|
|
DrawFieldCell(t^.x, t^.y, ArenaSymbol)
|
|
else
|
|
DrawFieldCell(t^.x, t^.y, BorderSymbol)
|
|
end
|
|
end;
|
|
|
|
procedure EraseHamsterInterface(x: integer);
|
|
begin
|
|
if x <= 0 then
|
|
exit;
|
|
DrawFieldCell(x, 0, ' ');
|
|
DrawFieldCell(x, -1, ' ');
|
|
DrawFieldCell(x - 1, 0, ' ');
|
|
DrawFieldCell(x - 1, -1, ' ')
|
|
end;
|
|
|
|
procedure RedrawInterfaceArea(x: integer);
|
|
begin
|
|
EraseHamsterInterface(x);
|
|
if (x = 1) or (x = 2) then
|
|
DrawLineY(1, InterfaceBarH - HamsterHeight,
|
|
HamsterHeight, BorderSymbol)
|
|
else
|
|
if x = InterfaceArenaCellX1 then
|
|
DrawLineY(InterfaceCellW * WidthCoefficient,
|
|
InterfaceBarH - HamsterHeight, HamsterHeight, BorderSymbol)
|
|
else
|
|
if x = InterfaceArenaCellX2 then
|
|
DrawLineY(InterfaceCellW * 2 * WidthCoefficient + 1,
|
|
InterfaceBarH - HamsterHeight, HamsterHeight, BorderSymbol)
|
|
else
|
|
if x = ArenaW then
|
|
DrawLineY(ArenaW * CellSize * WidthCoefficient,
|
|
InterfaceBarH - HamsterHeight, HamsterHeight, BorderSymbol)
|
|
end;
|
|
|
|
procedure RedrawArea(var a: arena; arenaX, arenaY: integer; t: creatureType);
|
|
var
|
|
i, j: integer;
|
|
r: redrawAreaBox;
|
|
begin
|
|
r := RedrawAreas[t];
|
|
for i := r.lY to r.rY do
|
|
begin
|
|
for j := r.lX to r.rX do
|
|
begin
|
|
if (arenaX + j > 0) and (arenaX + j < ArenaW + 1) and
|
|
(arenaY + i > 0) and (arenaY + i < ArenaH + 1) then
|
|
begin
|
|
if (t = creatureHamster) and (arenaY + i = 1) then
|
|
RedrawInterfaceArea(arenaX + j);
|
|
DrawArenaCell(arenaX + j, arenaY + i, a)
|
|
end
|
|
end
|
|
end
|
|
end;
|
|
|
|
procedure DrawAfterHamsterStep(var h: creature; var t: tracePtr; var a: arena);
|
|
var
|
|
arenaX, arenaY: integer;
|
|
begin
|
|
{Later move to erase hamster}
|
|
arenaX := h.curX - h.dX;
|
|
arenaY := h.curY - h.dY;
|
|
RedrawArea(a, arenaX, arenaY, h.t);
|
|
if t <> nil then
|
|
DrawTrace(t);
|
|
if t = nil then
|
|
DrawPreviousCell(h, a)
|
|
end;
|
|
|
|
procedure FillCells(var a: arena; x1, y1, x2, y2: integer);
|
|
var
|
|
i, j: integer;
|
|
begin
|
|
for i := y1 to y2 do
|
|
for j := x1 to x2 do
|
|
if a.borders[i][j] then
|
|
DrawFieldCell(j, i, BorderSymbol)
|
|
else
|
|
if a.captured[i][j] then
|
|
DrawFieldCell(j, i, CaptureSymbol)
|
|
end;
|
|
|
|
procedure FillCellsUnpause(var a: arena);
|
|
begin
|
|
FillCells(a, 1 + ArenaPauseMarginX, ArenaPauseUpperMarginY,
|
|
ArenaW - ArenaPauseMarginX, ArenaH - ArenaPauseLowerMarginY)
|
|
end;
|
|
|
|
procedure DrawPause;
|
|
begin
|
|
EraseRectangle(PauseX - PauseXPadding,
|
|
PauseY - PauseYPadding,
|
|
PauseWidth + PauseXPadding * 2,
|
|
PauseHeight + PauseYPadding * 2 + 1);
|
|
DrawRectangle(PauseX - PauseXPadding,
|
|
PauseY - PauseYPadding,
|
|
PauseHeight + PauseYPadding * 2 + 1,
|
|
PauseWidth + PauseXPadding * 2,
|
|
BorderSymbol);
|
|
DrawBannerImage(PauseX, PauseY, PauseHeight, PauseAscii)
|
|
end;
|
|
|
|
procedure DrawTrace(a: tracePtr);
|
|
var
|
|
t: tracePtr;
|
|
begin
|
|
if a = nil then
|
|
exit;
|
|
t := a^.prev;
|
|
while t <> nil do
|
|
begin
|
|
DrawFieldCell(t^.x, t^.y, TraceSymbol);
|
|
t := t^.prev
|
|
end
|
|
end;
|
|
|
|
procedure EraseInterfaceNumber(interfaceX: integer; num: longint);
|
|
var
|
|
cnt: integer = 0;
|
|
x, w, s: integer;
|
|
begin
|
|
s := num;
|
|
while s <> 0 do
|
|
begin
|
|
s := s div DecimalBase;
|
|
cnt += 1
|
|
end;
|
|
x := interfaceX + InterfaceMarginX;
|
|
w := (DigitWidth + DigitSpaceWidth) * cnt;
|
|
EraseRectangle(x, InterfaceMarginY, w, DigitHeight)
|
|
end;
|
|
|
|
procedure DrawInterfaceNumber(interfaceX: integer; n: longint);
|
|
begin
|
|
DrawNumber(interfaceX + InterfaceMarginX, InterfaceMarginY, n)
|
|
end;
|
|
|
|
procedure DrawScore(s: integer);
|
|
var
|
|
scoreX: integer = InterfaceCellW * 2 * WidthCoefficient + BorderSize;
|
|
begin
|
|
DrawInterfaceNumber(scoreX, s)
|
|
end;
|
|
|
|
procedure EraseLifesNumber(n: integer);
|
|
begin
|
|
EraseInterfaceNumber(LifeNumberX, n)
|
|
end;
|
|
|
|
procedure DrawLifesNumber(n: integer);
|
|
begin
|
|
DrawInterfaceNumber(LifeNumberX, n)
|
|
end;
|
|
|
|
procedure DrawLifes(n: integer);
|
|
begin
|
|
DrawCreatureImage(LifeBarX, HamsterLifeY,
|
|
HamsterHeight, HamsterLifesAscii);
|
|
DrawInterfaceNumber(LifeNumberX, n)
|
|
end;
|
|
|
|
procedure DrawInterface;
|
|
begin
|
|
DrawLineX(1, InterfaceBarH, ScreenW * WidthCoefficient, BorderSymbol);
|
|
DrawLineY(InterfaceCellW * WidthCoefficient, 1,
|
|
InterfaceBarH, BorderSymbol);
|
|
DrawLineY(InterfaceCellW * 2 * WidthCoefficient + 1, 1,
|
|
InterfaceBarH, BorderSymbol)
|
|
end;
|
|
|
|
procedure DrawLevel(var level: levelState; life, score: integer);
|
|
begin
|
|
DrawInterface;
|
|
FillCells(level.a, 1, 1, ArenaW, ArenaH);
|
|
DrawArenaEdges;
|
|
DrawTrace(level.t);
|
|
DrawCreature(level.h);
|
|
DrawAliveEnemies(level.enemyList);
|
|
DrawLifes(life);
|
|
DrawCompleteBar;
|
|
FillCompleteBar(level.cut);
|
|
DrawScore(score)
|
|
end;
|
|
|
|
procedure ErasePause;
|
|
begin
|
|
EraseRectangle(PauseX - PauseXPadding,
|
|
PauseY - PauseYPadding,
|
|
PauseWidth + PauseXPadding * 2,
|
|
PauseHeight + PauseYPadding * 2 + 1)
|
|
end;
|
|
|
|
procedure DrawLevelUnpause(var level: levelState);
|
|
begin
|
|
ErasePause;
|
|
FillCellsUnpause(level.a);
|
|
DrawTrace(level.t);
|
|
DrawAliveEnemies(level.enemyList);
|
|
DrawCreature(level.h)
|
|
end;
|
|
|
|
procedure DrawFieldCell(arenaX, arenaY: integer; symbol: char);
|
|
var
|
|
i, j, screenX, screenY: integer;
|
|
begin
|
|
screenX := BorderSize + (arenaX - 1) * CellSize * WidthCoefficient;
|
|
screenY := InterfaceBarH + (arenaY - 1) * CellSize;
|
|
for i := 1 to CellSize do
|
|
begin
|
|
GotoXY(screenX, screenY + i - 1);
|
|
for j := 1 to CellSize * WidthCoefficient do
|
|
begin
|
|
if (screenX + j - 1 >= 1) and
|
|
(screenX + j - 1 <= ScreenW * WidthCoefficient) then
|
|
begin
|
|
write(symbol)
|
|
end
|
|
end
|
|
end;
|
|
GotoXY(1, 1)
|
|
end;
|
|
|
|
procedure DrawArenaEdges;
|
|
begin
|
|
DrawRectangle(1, InterfaceBarH,
|
|
ScreenH - InterfaceBarH + 1, ScreenW * WidthCoefficient,
|
|
BorderSymbol)
|
|
end;
|
|
|
|
procedure DrawLeftEdge(y: integer);
|
|
var
|
|
terminalY, clampedY: integer;
|
|
begin
|
|
clampedY := Clamp(y, 1, ArenaH);
|
|
terminalY := InterfaceBarH + (clampedY - 1) * CellSize;
|
|
DrawLineY(1, terminalY, CellSize, BorderSymbol)
|
|
end;
|
|
|
|
procedure DrawRightEdge(y: integer);
|
|
var
|
|
terminalY, clampedY: integer;
|
|
begin
|
|
clampedY := Clamp(y, 1, ArenaH);
|
|
terminalY := InterfaceBarH + (clampedY - 1) * CellSize;
|
|
DrawLineY(ScreenW * WidthCoefficient, terminalY, CellSize, BorderSymbol)
|
|
end;
|
|
|
|
procedure DrawUpperEdge(x: integer);
|
|
var
|
|
terminalX, sizeX, clampedX: integer;
|
|
begin
|
|
clampedX := Clamp(x, 1, ArenaW);
|
|
terminalX := (clampedX - 1) * CellSize * WidthCoefficient + 1;
|
|
sizeX := CellSize * WidthCoefficient;
|
|
DrawLineX(terminalX, InterfaceBarH, sizeX, BorderSymbol)
|
|
end;
|
|
|
|
procedure DrawLowerEdge(x: integer);
|
|
var
|
|
terminalX, sizeX, clampedX: integer;
|
|
begin
|
|
clampedX := Clamp(x, 1, ArenaW);
|
|
terminalX := (clampedX - 1) * CellSize * WidthCoefficient + 1;
|
|
sizeX := CellSize * WidthCoefficient;
|
|
DrawLineX(terminalX, InterfaceBarH + ArenaH * CellSize - 1,
|
|
sizeX, BorderSymbol)
|
|
end;
|
|
|
|
procedure DrawArenaBorders(var a: arena);
|
|
var
|
|
i, j: integer;
|
|
begin
|
|
for i := 1 to ArenaH do
|
|
for j := 1 to ArenaW do
|
|
if a.borders[i][j] then
|
|
DrawFieldCell(j, i, BorderSymbol)
|
|
end;
|
|
|
|
procedure DrawEdge(x, y: integer);
|
|
begin
|
|
if x = 1 then
|
|
DrawLeftEdge(y)
|
|
else
|
|
if x = ArenaW then
|
|
DrawRightEdge(y);
|
|
|
|
if y = 1 then
|
|
DrawUpperEdge(x)
|
|
else
|
|
if y = ArenaH then
|
|
DrawLowerEdge(x)
|
|
end;
|
|
|
|
procedure DrawArenaCell(x, y: integer; var a: arena);
|
|
begin
|
|
if a.captured[y][x] then
|
|
DrawFieldCell(x, y, CaptureSymbol)
|
|
else
|
|
if a.borders[y][x] then
|
|
DrawFieldCell(x, y, BorderSymbol)
|
|
else
|
|
DrawFieldCell(x, y, ArenaSymbol);
|
|
if IsOnEdge(x, y) then
|
|
DrawEdge(x, y)
|
|
end;
|
|
|
|
procedure DrawCapturedCell(x, y: integer);
|
|
begin
|
|
DrawFieldCell(x, y, CaptureSymbol);
|
|
if IsOnEdge(x, y) then
|
|
DrawEdge(x, y)
|
|
end;
|
|
|
|
procedure EraseTrace(tp: tracePtr; var a: arena);
|
|
var
|
|
t: tracePtr;
|
|
begin
|
|
if tp = nil then
|
|
exit;
|
|
t := tp;
|
|
while t <> nil do
|
|
begin
|
|
if t^.prev = nil then
|
|
DrawArenaCell(t^.x, t^.y, a)
|
|
else
|
|
DrawFieldCell(t^.x, t^.y, ArenaSymbol);
|
|
t := t^.prev
|
|
end
|
|
end;
|
|
|
|
procedure FillCellsCapture(var a: arena);
|
|
var
|
|
i, j: integer;
|
|
begin
|
|
for i := 1 to ArenaH do
|
|
for j := 1 to ArenaW do
|
|
begin
|
|
if not a.captured[i][j] then
|
|
DrawCapturedCell(j, i)
|
|
end
|
|
end;
|
|
|
|
procedure DrawHamsterRunX(var h: creature);
|
|
var
|
|
xIdx: integer;
|
|
img: ^CreatureImage;
|
|
begin
|
|
if h.dX = 0 then
|
|
exit;
|
|
xIdx := h.curX div h.moveSpeed mod HamsterRunNX + 1;
|
|
if h.dX > 0 then
|
|
img := @(HamsterRightAscii[xIdx])
|
|
else
|
|
img := @(HamsterLeftAscii[xIdx]);
|
|
DrawFieldAscii(h.curX - HamsterWidth div WidthCoefficient div 2,
|
|
h.curY - HamsterHeight div 2,
|
|
HamsterHeight, HamsterWidth, img^);
|
|
end;
|
|
|
|
procedure DrawHamsterRunY(var h: creature);
|
|
var
|
|
yIdx: integer;
|
|
img: ^CreatureImage;
|
|
begin
|
|
if h.dY = 0 then
|
|
exit;
|
|
yIdx := h.curY div h.moveSpeed mod HamsterRunNY + 1;
|
|
if h.dY > 0 then
|
|
img := @(HamsterDownAscii[yIdx])
|
|
else
|
|
img := @(HamsterUpAscii[yIdx]);
|
|
DrawFieldAscii(h.curX - HamsterWidth div WidthCoefficient div 2,
|
|
h.curY - HamsterHeight div 2,
|
|
HamsterHeight, HamsterWidth, img^)
|
|
end;
|
|
|
|
procedure DrawHamster(var h: creature);
|
|
begin
|
|
if (h.dX = 0) and (h.dY = 0) then
|
|
DrawFieldAscii(h.curX - HamsterWidth div WidthCoefficient div 2,
|
|
h.curY - HamsterHeight div 2,
|
|
HamsterHeight, HamsterWidth,
|
|
HamsterStayAscii)
|
|
else
|
|
if h.dX <> 0 then
|
|
DrawHamsterRunX(h)
|
|
else
|
|
if h.dY <> 0 then
|
|
DrawHamsterRunY(h)
|
|
end;
|
|
|
|
procedure DrawGhost(var g: creature);
|
|
var
|
|
asciiIdx: integer;
|
|
begin
|
|
asciiIdx := g.curX div g.moveSpeed mod GhostRunN + 1;
|
|
DrawFieldAscii(g.curX - GhostWidth div WidthCoefficient div 2,
|
|
g.curY - GhostHeight div 2 + 1,
|
|
GhostHeight, GhostWidth, GhostAscii[asciiIdx])
|
|
|
|
end;
|
|
|
|
procedure DrawSun(var g: creature);
|
|
var
|
|
asciiIdx: integer;
|
|
begin
|
|
asciiIdx := g.curX div g.moveSpeed mod SunRunN + 1;
|
|
DrawFieldAscii(g.curX - SunWidth div WidthCoefficient div 2,
|
|
g.curY - SunHeight div 2 + 1,
|
|
SunHeight, SunWidth, SunAscii[asciiIdx])
|
|
|
|
end;
|
|
|
|
{
|
|
procedure DrawEnemy(var e: creature);
|
|
var
|
|
asciiIdx: integer;
|
|
begin
|
|
asciiIdx := e.curX div e.moveSpeed mod;
|
|
end;
|
|
}
|
|
|
|
procedure DrawCreature(var cr: creature);
|
|
begin
|
|
case cr.t of
|
|
creatureHamster:
|
|
DrawHamster(cr);
|
|
creatureGhost:
|
|
DrawGhost(cr);
|
|
creatureSun:
|
|
DrawSun(cr)
|
|
end
|
|
end;
|
|
|
|
end.
|