579 lines
15 KiB
ObjectPascal
579 lines
15 KiB
ObjectPascal
|
|
unit arena_m;
|
||
|
|
|
||
|
|
interface
|
||
|
|
|
||
|
|
uses creature_m, trace_m;
|
||
|
|
|
||
|
|
const
|
||
|
|
ArenaH = 33;
|
||
|
|
ArenaW = 41;
|
||
|
|
TotalCells = ArenaW * ArenaH;
|
||
|
|
RandomCutThreshold = 25;
|
||
|
|
|
||
|
|
type
|
||
|
|
arenaMatrix = array [1..ArenaH, 1..ArenaW] of boolean;
|
||
|
|
|
||
|
|
arena = record
|
||
|
|
captured, borders: arenaMatrix;
|
||
|
|
end;
|
||
|
|
|
||
|
|
function ArenaSplited(var h: creature; var t: tracePtr; var a: arena): boolean;
|
||
|
|
function
|
||
|
|
HamsterStepPossible(var h: creature; var t: tracePtr; var a: arena): boolean;
|
||
|
|
function IsOnEdge(var cr: creature): boolean;
|
||
|
|
function IsOnEdge(x, y: integer): boolean;
|
||
|
|
procedure ArenaCutPart(var hamster: creature; var t: tracePtr;
|
||
|
|
var cutOff: integer; var a: arena);
|
||
|
|
procedure InitArena(var a: arena);
|
||
|
|
procedure KillCapturedEnemies(var a: arena; var e: creatureList);
|
||
|
|
procedure EraseEnemies(var a: arena; var e: creatureList);
|
||
|
|
procedure MakeEnemySteps(var a: arena; var h: creature;
|
||
|
|
t: tracePtr; var e: creatureList);
|
||
|
|
procedure MakeHamsterStep(var h: creature; var t: tracePtr; var a: arena);
|
||
|
|
procedure SetArenaBorder(var t: tracePtr; var a: arena);
|
||
|
|
procedure TurnStubbornEnemies(var a: arena; var e: creatureList);
|
||
|
|
procedure MakeStep(var a: arena; var cr: creature);
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
implementation
|
||
|
|
|
||
|
|
uses arena_graphics_m, cell_m, crt, graphics_m, math_m, Math;
|
||
|
|
|
||
|
|
const
|
||
|
|
MaxTurnAttempts = 3;
|
||
|
|
TotalProcent = 100;
|
||
|
|
|
||
|
|
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 <> ArenaW + 1) and
|
||
|
|
(y <> 0) and (y <> ArenaH + 1) and
|
||
|
|
not a.captured[y][x] and not a.borders[y][x]
|
||
|
|
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^.y][cell^.x] := 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.y][cell.x] then
|
||
|
|
continue;
|
||
|
|
result := result + 1;
|
||
|
|
a.captured[cell.y][cell.x] := 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.y][cell.x] then
|
||
|
|
continue;
|
||
|
|
cutOff := cutOff + 1;
|
||
|
|
a.captured[cell.y][cell.x] := true;
|
||
|
|
DrawArenaCell(cell.x, cell.y, a);
|
||
|
|
AddAvailableNeighbours(captureQ, cell, a)
|
||
|
|
end
|
||
|
|
end;
|
||
|
|
|
||
|
|
function OnEdgeX(x: integer): boolean;
|
||
|
|
begin
|
||
|
|
OnEdgeX := (x = 1) or (x = ArenaW)
|
||
|
|
end;
|
||
|
|
|
||
|
|
function OnEdgeY(y: integer): boolean;
|
||
|
|
begin
|
||
|
|
OnEdgeY := (y = 1) or (y = ArenaH)
|
||
|
|
end;
|
||
|
|
|
||
|
|
function IsOnEdge(x, y: integer): boolean;
|
||
|
|
begin
|
||
|
|
IsOnEdge := (OnEdgeX(x) or OnEdgeY(y))
|
||
|
|
end;
|
||
|
|
|
||
|
|
function YNeighboursCaptured(x, y: integer; var a: arena): boolean;
|
||
|
|
begin
|
||
|
|
YNeighboursCaptured :=
|
||
|
|
not OnEdgeY(y) and a.captured[y + 1][x] and a.captured[y - 1][x]
|
||
|
|
end;
|
||
|
|
|
||
|
|
function XNeighboursCaptured(x, y: integer; var a: arena): boolean;
|
||
|
|
begin
|
||
|
|
XNeighboursCaptured :=
|
||
|
|
not OnEdgeX(x) and a.captured[y][x + 1] and a.captured[y][x - 1]
|
||
|
|
end;
|
||
|
|
|
||
|
|
function DiagonalNeighboursCaptured(x, y: integer; var a: arena): boolean;
|
||
|
|
begin
|
||
|
|
DiagonalNeighboursCaptured :=
|
||
|
|
not IsOnEdge(x, y) and
|
||
|
|
a.captured[y - 1][x - 1] and a.captured[y + 1][x - 1] and
|
||
|
|
a.captured[y - 1][x + 1] and a.captured[y + 1][x + 1]
|
||
|
|
end;
|
||
|
|
|
||
|
|
function ArenaCellCaptured(x, y: integer; var a: arena): boolean;
|
||
|
|
begin
|
||
|
|
ArenaCellCaptured :=
|
||
|
|
XNeighboursCaptured(x, y, a) or YNeighboursCaptured(x, y, a) or
|
||
|
|
DiagonalNeighboursCaptured(x, y, a)
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure CaptureArenaBorder(x, y: integer; var a: arena);
|
||
|
|
begin
|
||
|
|
a.borders[y][x] := false;
|
||
|
|
a.captured[y][x] := true;
|
||
|
|
DrawFieldCell(x, y, CaptureSymbol)
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure CaptureCutBorders(var a: arena; var cutOff: integer); {rename, slow}
|
||
|
|
var
|
||
|
|
i, j: integer;
|
||
|
|
begin
|
||
|
|
for i := 1 to ArenaH do
|
||
|
|
for j := 1 to ArenaW do
|
||
|
|
if a.borders[i][j] 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
|
||
|
|
exit;
|
||
|
|
a.borders[t^.y][t^.x] := true;
|
||
|
|
SetArenaBorder(t^.prev, a)
|
||
|
|
end;
|
||
|
|
|
||
|
|
function IsOnEdge(var cr: creature): boolean;
|
||
|
|
begin
|
||
|
|
IsOnEdge :=
|
||
|
|
(cr.curX = 1) or (cr.curX = ArenaW) or (cr.curY = 1) or
|
||
|
|
(cr.curY = ArenaH)
|
||
|
|
end;
|
||
|
|
|
||
|
|
function IsOnBorder(var x, y: integer; var a: arena): boolean;
|
||
|
|
begin
|
||
|
|
IsOnBorder :=
|
||
|
|
a.borders[y][x] and (
|
||
|
|
a.captured[y + 1][x - 1] or
|
||
|
|
a.captured[y - 1][x - 1] or
|
||
|
|
a.captured[y + 1][x + 1] or
|
||
|
|
a.captured[y - 1][x + 1]
|
||
|
|
)
|
||
|
|
end;
|
||
|
|
|
||
|
|
function IsOnBorder(var cr: creature; var a: arena): boolean;
|
||
|
|
begin
|
||
|
|
IsOnBorder :=
|
||
|
|
a.borders[cr.curY][cr.curX] and (
|
||
|
|
a.captured[cr.curY + 1][cr.curX - 1] or
|
||
|
|
a.captured[cr.curY - 1][cr.curX - 1] or
|
||
|
|
a.captured[cr.curY + 1][cr.curX + 1] or
|
||
|
|
a.captured[cr.curY - 1][cr.curX + 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 / TotalProcent;
|
||
|
|
LowerToBiggerRatio := Round(TotalProcent - 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, ArenaW);
|
||
|
|
nextY := Clamp(hamster.curY + hamster.dY, 1, ArenaH);
|
||
|
|
idx := FindIndex(t, nextX, nextY, 1);
|
||
|
|
StepOnTrace := idx > PreviousTraceIdx
|
||
|
|
end;
|
||
|
|
|
||
|
|
function StepBeyondEdgeX(var cr: creature): boolean;
|
||
|
|
begin
|
||
|
|
StepBeyondEdgeX :=
|
||
|
|
(cr.dX > 0) and (cr.curX = ArenaW) or
|
||
|
|
(cr.dX < 0) and (cr.curX = 1)
|
||
|
|
end;
|
||
|
|
|
||
|
|
function StepBeyondEdgeY(var cr: creature): boolean;
|
||
|
|
begin
|
||
|
|
StepBeyondEdgeY :=
|
||
|
|
(cr.dY > 0) and (cr.curY = ArenaH) or
|
||
|
|
(cr.dY < 0) and (cr.curY = 1)
|
||
|
|
end;
|
||
|
|
|
||
|
|
function StepBeyondEdge(var cr: creature): boolean;
|
||
|
|
begin
|
||
|
|
StepBeyondEdge := StepBeyondEdgeX(cr) or StepBeyondEdgeY(cr)
|
||
|
|
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 ArenaCutPart(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, ArenaW);
|
||
|
|
nextY := Clamp(h.curY + h.dY, 1, ArenaH);
|
||
|
|
midX := Clamp(h.curX + (h.dX div 2), 1, ArenaW);
|
||
|
|
midY := Clamp(h.curY + (h.dY div 2), 1, ArenaH);
|
||
|
|
HamsterStepPossible :=
|
||
|
|
not StepOnTrace(h, t)
|
||
|
|
and (not a.captured[midY][midX] or IsOnEdge(nextX, nextY))
|
||
|
|
and not StepBeyondEdge(h)
|
||
|
|
and not (
|
||
|
|
not IsOnEdge(h) and a.borders[h.curY][h.curX] and
|
||
|
|
a.captured[midY][midX]
|
||
|
|
);
|
||
|
|
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[midY][midX] and
|
||
|
|
not a.borders[hamster.curY][hamster.curX] 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.curY][hamster.curX] and
|
||
|
|
not a.borders[midY][midX]
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure MakeHamsterStep(var h: creature; var t: tracePtr; var a: arena);
|
||
|
|
begin
|
||
|
|
h.curX := Clamp(h.curX + h.dX, 1, ArenaW);
|
||
|
|
h.curY := Clamp(h.curY + h.dY, 1, ArenaH);
|
||
|
|
if FieldToEdge(h, t, a) or IsOnField(h, t, a) then
|
||
|
|
ChangeHamsterTrace(h, t);
|
||
|
|
DrawAfterHamsterStep(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 := StepBeyondEdge(g) or
|
||
|
|
a.borders[g.curY][g.curX] and a.captured[nextY][nextX]
|
||
|
|
end;
|
||
|
|
|
||
|
|
function SunShouldTurn(var g: creature; var a: arena): boolean;
|
||
|
|
begin
|
||
|
|
SunShouldTurn := true
|
||
|
|
end;
|
||
|
|
|
||
|
|
function VerticalBorder(nextX, nextY: integer; var a: arena): boolean;
|
||
|
|
begin
|
||
|
|
VerticalBorder :=
|
||
|
|
a.borders[nextY][nextX] and
|
||
|
|
(a.borders[nextY - 1][nextX] or a.borders[nextY + 1][nextX])
|
||
|
|
end;
|
||
|
|
|
||
|
|
function HorizontalBorder(nextX, nextY: integer; var a: arena): boolean;
|
||
|
|
begin
|
||
|
|
HorizontalBorder :=
|
||
|
|
a.borders[nextY][nextX] and
|
||
|
|
(a.borders[nextY][nextX - 1] or a.borders[nextY][nextX + 1])
|
||
|
|
end;
|
||
|
|
|
||
|
|
function IsCorner(x, y: integer; var a: arena): boolean;
|
||
|
|
begin
|
||
|
|
IsCorner := HorizontalBorder(x, y, a) and VerticalBorder(x, y, a)
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure TurnGhost(var g: creature; var a: arena);
|
||
|
|
begin
|
||
|
|
if (OnEdgeX(g.curX) or VerticalBorder(g.curX, g.curY, a)) then
|
||
|
|
g.dX := g.dX * -1;
|
||
|
|
if (OnEdgeY(g.curY) or HorizontalBorder(g.curX, g.curY, a)) then
|
||
|
|
g.dY := g.dY * -1
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure TurnSun(var g: creature; var a: arena);
|
||
|
|
begin
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure MakeEnemyStep(var a: arena; var e, h: creature; t: tracePtr);
|
||
|
|
var
|
||
|
|
prevX, prevY: integer;
|
||
|
|
begin
|
||
|
|
prevX := e.curX;
|
||
|
|
prevY := e.curY;
|
||
|
|
MakeStep(a, e);
|
||
|
|
if TraceCrossed(prevX, prevY, e, t) then
|
||
|
|
h.alive := false
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure KillCapturedEnemies(var a: arena; var e: creatureList);
|
||
|
|
var
|
||
|
|
tmp: creatureItemPtr;
|
||
|
|
begin
|
||
|
|
tmp := e.first;
|
||
|
|
while tmp <> nil do
|
||
|
|
begin
|
||
|
|
if tmp^.cr^.alive and a.captured[tmp^.cr^.curY][tmp^.cr^.curX] then
|
||
|
|
KillCreature(tmp^.cr^);
|
||
|
|
tmp := tmp^.next
|
||
|
|
end
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure TurnEnemy(var cr: creature; var a: arena);
|
||
|
|
begin
|
||
|
|
case cr.t of
|
||
|
|
creatureGhost:
|
||
|
|
TurnGhost(cr, a);
|
||
|
|
creatureSun:
|
||
|
|
TurnGhost(cr, a)
|
||
|
|
end
|
||
|
|
end;
|
||
|
|
|
||
|
|
function EnemyShouldTurn(var cr: creature; var a: arena): boolean;
|
||
|
|
begin
|
||
|
|
case cr.t of
|
||
|
|
creatureGhost:
|
||
|
|
EnemyShouldTurn := GhostShouldTurn(cr, a);
|
||
|
|
creatureSun:
|
||
|
|
EnemyShouldTurn := GhostShouldTurn(cr, a)
|
||
|
|
end
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure TurnStubbornEnemies(var a: arena; var e: creatureList);
|
||
|
|
var
|
||
|
|
turnCnt: integer = 0;
|
||
|
|
tmp: creatureItemPtr;
|
||
|
|
begin
|
||
|
|
tmp := e.first;
|
||
|
|
while tmp <> nil do
|
||
|
|
begin
|
||
|
|
while tmp^.cr^.alive and EnemyShouldTurn(tmp^.cr^, a) and
|
||
|
|
(turnCnt < MaxTurnAttempts) do
|
||
|
|
begin
|
||
|
|
TurnEnemy(tmp^.cr^, a);
|
||
|
|
turnCnt := turnCnt + 1
|
||
|
|
end;
|
||
|
|
turnCnt := 0;
|
||
|
|
tmp := tmp^.next
|
||
|
|
end
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure EraseEnemies(var a: arena; var e: creatureList);
|
||
|
|
var
|
||
|
|
tmp: creatureItemPtr;
|
||
|
|
begin
|
||
|
|
tmp := e.first;
|
||
|
|
while tmp <> nil do
|
||
|
|
begin
|
||
|
|
if tmp^.cr^.alive and not EnemyShouldTurn(tmp^.cr^, a) then
|
||
|
|
RedrawArea(a, tmp^.cr^.curX, tmp^.cr^.curY, tmp^.cr^.t);
|
||
|
|
tmp := tmp^.next
|
||
|
|
end
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure MakeEnemySteps(var a: arena; var h: creature;
|
||
|
|
t: tracePtr; var e: creatureList);
|
||
|
|
var
|
||
|
|
tmp: creatureItemPtr;
|
||
|
|
begin
|
||
|
|
tmp := e.first;
|
||
|
|
while tmp <> nil do
|
||
|
|
begin
|
||
|
|
if tmp^.cr^.alive and not EnemyShouldTurn(tmp^.cr^, a) then
|
||
|
|
MakeEnemyStep(a, tmp^.cr^, h, t);
|
||
|
|
tmp := tmp^.next
|
||
|
|
end
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure MakeStep(var a: arena; var cr: creature);
|
||
|
|
var
|
||
|
|
absDx, absDy, maxD, stepX, stepY, i, nX, nY: integer;
|
||
|
|
begin
|
||
|
|
absDx := Abs(cr.dX);
|
||
|
|
absDy := Abs(cr.dY);
|
||
|
|
maxD := Max(absDx, absDy);
|
||
|
|
stepX := Signum(cr.dX, 0);
|
||
|
|
stepY := Signum(cr.dY, 0);
|
||
|
|
for i := 1 to maxD do
|
||
|
|
begin
|
||
|
|
nX := cr.curX + stepX;
|
||
|
|
nY := cr.curY + stepY;
|
||
|
|
if a.captured[nY][nX] or (nX < 1) or (nX > ArenaW) or
|
||
|
|
(nY < 1) or (nY > ArenaH) then
|
||
|
|
begin
|
||
|
|
break
|
||
|
|
end
|
||
|
|
else
|
||
|
|
begin
|
||
|
|
cr.curX := nX;
|
||
|
|
cr.curY := nY
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end;
|
||
|
|
|
||
|
|
end.
|