diff --git a/CLEAN.bat b/CLEAN.bat index 2551b71..bce4737 100644 --- a/CLEAN.bat +++ b/CLEAN.bat @@ -9,5 +9,6 @@ del /s *.otares del /s *.local del /s *.cfg del /s *.ddp -del /s *.o del /s *.a +del /S *.*proj.local +del /S *.tvsconfig diff --git a/README.md b/README.md index 596602e..2fc3404 100644 --- a/README.md +++ b/README.md @@ -2,31 +2,31 @@ Simple roguelike game based on Disciples. ## Screenshots -### Day 1 +### Day 1 [3.03.2018] ![screenshot](https://github.com/devapromix-roguelikes/disciplesrl/blob/master/screenshots/screenshot_day_1.png) - ### Day 2 + ### Day 2 [4.03.2018] ![screenshot](https://github.com/devapromix-roguelikes/disciplesrl/blob/master/screenshots/screenshot_day_2.png) - ### Day 3 + ### Day 3 [5.03.2018] ![screenshot](https://github.com/devapromix-roguelikes/disciplesrl/blob/master/screenshots/screenshot_day_3.png) - ### Day 4 + ### Day 4 [6.03.2018] ![screenshot](https://github.com/devapromix-roguelikes/disciplesrl/blob/master/screenshots/screenshot_day_4.png) -### Day 5 +### Day 5 [7.03.2018] ![screenshot](https://github.com/devapromix-roguelikes/disciplesrl/blob/master/screenshots/screenshot_day_5.png) -### Day 6 +### Day 6 [8.03.2018] ![screenshot](https://github.com/devapromix-roguelikes/disciplesrl/blob/master/screenshots/screenshot_day_6.png) -### Day 7 +### Day 7 [9.03.2018] ![screenshot](https://github.com/devapromix-roguelikes/disciplesrl/blob/master/screenshots/screenshot_day_7.png) diff --git a/resources/chest.png b/resources/chest.png index 3c7500f..bbf1339 100644 Binary files a/resources/chest.png and b/resources/chest.png differ diff --git a/resources/dirt.png b/resources/dirt.png new file mode 100644 index 0000000..505e11f Binary files /dev/null and b/resources/dirt.png differ diff --git a/resources/mountain.png b/resources/mountain.png new file mode 100644 index 0000000..c6808fa Binary files /dev/null and b/resources/mountain.png differ diff --git a/screenshots/screenshot_day_3.png b/screenshots/screenshot_day_3.png new file mode 100644 index 0000000..84668df Binary files /dev/null and b/screenshots/screenshot_day_3.png differ diff --git a/sources/DisciplesRL.City.pas b/sources/DisciplesRL.City.pas new file mode 100644 index 0000000..610de8c --- /dev/null +++ b/sources/DisciplesRL.City.pas @@ -0,0 +1,121 @@ +unit DisciplesRL.City; + +interface + +uses DisciplesRL.Party; + +type + TCity = record + X, Y: Integer; + CurLevel: Integer; + MaxLevel: Integer; + Owner: TRaceEnum; + end; + +var + City: array [0 .. 3] of TCity; + +procedure Init; +function GetCityIndex(const AX, AY: Integer): Integer; +procedure UpdateRadius(const AID: Integer); +procedure Gen; + +implementation + +uses System.Math, DisciplesRL.Map, DisciplesRL.Resources, DisciplesRL.Utils, DisciplesRL.Player; + +procedure Init; +var + I: Integer; +begin + for I := 0 to High(City) do + begin + City[I].X := 0; + City[I].Y := 0; + City[I].CurLevel := 0; + City[I].MaxLevel := 2; + City[I].Owner := reNeutrals; + end; +end; + +function GetCityIndex(const AX, AY: Integer): Integer; +var + I: Integer; +begin + Result := -1; + for I := 0 to High(City) do + if ((City[I].X = AX) and (City[I].Y = AY)) then + begin + Result := I; + Break; + end; +end; + +procedure UpdateRadius(const AID: Integer); +begin + DisciplesRL.Map.UpdateRadius(City[AID].X, City[AID].Y, City[AID].CurLevel, MapTile, reEmpireTerrain, + [reEmpireCity, reNeutralCity, reEmpireCapital]); + DisciplesRL.Map.UpdateRadius(City[AID].X, City[AID].Y, City[AID].CurLevel, MapDark, reNone); + City[AID].Owner := reTheEmpire; +end; + +function ChCity(N: Integer): Boolean; +var + I: Integer; +begin + Result := True; + if (N = 0) then + Exit; + for I := 0 to N - 1 do + begin + if (GetDist(City[I].X, City[I].Y, City[N].X, City[N].Y) <= 6) then + begin + Result := False; + Exit; + end; + end; +end; + +procedure ClearObj(const AX, AY: Integer); +var + X, Y: Integer; +begin + for X := AX - 2 to AX + 2 do + for Y := AY - 2 to AY + 2 do + if (X = AX - 2) or (X = AX + 2) or (Y = AY - 2) or (Y = AY + 2) then + begin + if (RandomRange(0, 5) = 0) then + MapObj[X, Y] := reNone + end + else + MapObj[X, Y] := reNone; +end; + +procedure Gen; +var + I, X, Y: Integer; +begin + for I := 0 to High(City) do + begin + repeat + City[I].X := RandomRange(3, MapWidth - 3); + City[I].Y := RandomRange(3, MapHeight - 3); + until ChCity(I); + // Capital + if (I = 0) then + begin + Player.X := City[I].X; + Player.Y := City[I].Y; + MapTile[City[I].X, City[I].Y] := reEmpireCapital; + ClearObj(City[I].X, City[I].Y); + UpdateRadius(I); + Continue; + end; + // City + MapTile[City[I].X, City[I].Y] := reNeutralCity; + ClearObj(City[I].X, City[I].Y); + MapObj[City[I].X, City[I].Y] := reEnemies; + end; +end; + +end. diff --git a/sources/DisciplesRL.MainForm.dfm b/sources/DisciplesRL.MainForm.dfm index c0aa830..ad1fde7 100644 --- a/sources/DisciplesRL.MainForm.dfm +++ b/sources/DisciplesRL.MainForm.dfm @@ -1,9 +1,11 @@ object MainForm: TMainForm Left = 0 Top = 0 + BorderIcons = [biSystemMenu, biMinimize] + BorderStyle = bsSingle Caption = 'DisciplesRL' - ClientHeight = 492 - ClientWidth = 1057 + ClientHeight = 596 + ClientWidth = 795 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText diff --git a/sources/DisciplesRL.MainForm.pas b/sources/DisciplesRL.MainForm.pas index ee1fd66..e665e34 100644 --- a/sources/DisciplesRL.MainForm.pas +++ b/sources/DisciplesRL.MainForm.pas @@ -33,13 +33,18 @@ implementation procedure TMainForm.FormCreate(Sender: TObject); begin + Top := 0; + Left := 0; Randomize; - DisciplesRL.Scenes.Init; // Test DisciplesRL.Resources.Init; DisciplesRL.Map.Init; DisciplesRL.Map.Gen; DisciplesRL.Player.Init; + // + ClientWidth := MapWidth * TileSize; + ClientHeight := MapHeight * TileSize; + DisciplesRL.Scenes.Init; end; procedure TMainForm.FormPaint(Sender: TObject); diff --git a/sources/DisciplesRL.Map.pas b/sources/DisciplesRL.Map.pas index 018c855..c311d29 100644 --- a/sources/DisciplesRL.Map.pas +++ b/sources/DisciplesRL.Map.pas @@ -5,28 +5,35 @@ interface uses DisciplesRL.Resources; var - MapWidth: Integer = 20; - MapHeight: Integer = 12; + MapWidth: Integer = 40; + MapHeight: Integer = 20; const TileSize = 32; type - TLayerEnum = (lTile, lPath, lDark); + TLayerEnum = (lrTile, lrPath, lrDark, lrObj); + +type + TMapLayer = array of array of TResEnum; + TIgnoreRes = set of TResEnum; var - MapTile: array of array of TResEnum; - MapPath: array of array of TResEnum; - MapDark: array of array of TResEnum; + MapTile: TMapLayer; + MapPath: TMapLayer; + MapDark: TMapLayer; + MapObj: TMapLayer; procedure Init; procedure Clear(const L: TLayerEnum); procedure Gen; function InMap(X, Y: Integer): Boolean; +procedure UpdateRadius(const AX, AY, AR: Integer; var MapLayer: TMapLayer; const AResEnum: TResEnum; + IgnoreRes: TIgnoreRes = []); implementation -uses System.Math, DisciplesRL.Player; +uses System.Math, DisciplesRL.Player, DisciplesRL.Utils, DisciplesRL.City, DisciplesRL.PathFind; procedure Init; var @@ -35,8 +42,10 @@ procedure Init; SetLength(MapTile, MapWidth, MapHeight); SetLength(MapPath, MapWidth, MapHeight); SetLength(MapDark, MapWidth, MapHeight); + SetLength(MapObj, MapWidth, MapHeight); for L := Low(TLayerEnum) to High(TLayerEnum) do Clear(L); + DisciplesRL.City.Init; end; procedure Clear(const L: TLayerEnum); @@ -46,34 +55,65 @@ procedure Clear(const L: TLayerEnum); for Y := 0 to MapHeight - 1 do for X := 0 to MapWidth - 1 do case L of - lTile: + lrTile: MapTile[X, Y] := reNone; - lPath: + lrPath: MapPath[X, Y] := reNone; - lDark: + lrDark: MapDark[X, Y] := reDark; + lrObj: + MapObj[X, Y] := reNone; end; end; +function ChTile(X, Y: Integer): Boolean; stdcall; +begin + Result := True; +end; + procedure Gen; var - X, Y: Integer; + X, Y, RX, RY, I: Integer; begin for Y := 0 to MapHeight - 1 do for X := 0 to MapWidth - 1 do - MapTile[X, Y] := reGrass; - for X := 0 to 7 do - MapTile[RandomRange(0, MapWidth), RandomRange(0, MapHeight)] := reEnemies; - for X := 0 to 5 do - MapTile[RandomRange(0, MapWidth), RandomRange(0, MapHeight)] := reBag; - for X := 0 to 3 do - MapTile[RandomRange(0, MapWidth), RandomRange(0, MapHeight)] := reCity; - // Player - X := RandomRange(0, MapWidth); - Y := RandomRange(0, MapHeight); - MapTile[X, Y] := reCapital; - Player.X := X; - Player.Y := Y; + begin + MapTile[X, Y] := reNeutral; + MapObj[X, Y] := reMountain; + end; + // Bags + // for X := 0 to 5 do + // MapObj[RandomRange(0, MapWidth), RandomRange(0, MapHeight)] := reBag; + // Capital and Cities + DisciplesRL.City.Gen; + X := City[0].X; + Y := City[0].Y; + for I := 1 to High(City) do + repeat + if PathFind(X, Y, City[I].X, City[I].Y, ChTile, RX, RY) then + begin + // if (RandomRange(0, 2) = 0) then + begin + X := RX + RandomRange(-1, 2); + Y := RY + RandomRange(-1, 2); + if MapObj[X, Y] = reMountain then + MapObj[X, Y] := reNone; + end; + X := RX; + Y := RY; + if MapObj[X, Y] = reMountain then + MapObj[X, Y] := reNone; + end; + until ((X = City[I].X) and (Y = City[I].Y)); + // Enemies + for I := 0 to High(City) do + begin + repeat + X := RandomRange(1, MapWidth - 1); + Y := RandomRange(1, MapHeight - 1); + until (MapObj[X, Y] = reNone); + MapObj[X, Y] := reEnemies; + end; end; function InMap(X, Y: Integer): Boolean; @@ -81,4 +121,18 @@ function InMap(X, Y: Integer): Boolean; Result := (X >= 0) and (X < MapWidth) and (Y >= 0) and (Y < MapHeight); end; +procedure UpdateRadius(const AX, AY, AR: Integer; var MapLayer: TMapLayer; const AResEnum: TResEnum; + IgnoreRes: TIgnoreRes = []); +var + X, Y: Integer; +begin + for Y := -AR to AR do + for X := -AR to AR do + if (GetDist(AX + X, AY + Y, AX, AY) <= AR) and DisciplesRL.Map.InMap(AX + X, AY + Y) then + if (MapLayer[AX + X, AY + Y] in IgnoreRes) then + Continue + else + MapLayer[AX + X, AY + Y] := AResEnum; +end; + end. diff --git a/sources/DisciplesRL.Party.pas b/sources/DisciplesRL.Party.pas index 60bf610..dd16262 100644 --- a/sources/DisciplesRL.Party.pas +++ b/sources/DisciplesRL.Party.pas @@ -5,7 +5,7 @@ interface uses DisciplesRL.Creatures; type - TRace = (rcTheEmpire, rcNeutrals); + TRaceEnum = (reTheEmpire, reNeutrals); type TPosition = 0 .. 5; @@ -13,7 +13,7 @@ interface type TParty = class(TObject) private - FOwner: TRace; + FOwner: TRaceEnum; FCreature: array [TPosition] of TCreature; procedure AddCreature(const ACreatureEnum: TCreatureEnum; const APosition: TPosition); function GetCreature(APosition: TPosition): TCreature; @@ -21,7 +21,7 @@ TParty = class(TObject) public constructor Create; destructor Destroy; override; - property Owner: TRace read FOwner write FOwner; + property Owner: TRaceEnum read FOwner write FOwner; property Creature[APosition: TPosition]: TCreature read GetCreature write SetCreature; procedure Clear; function Hire(const ACreatureEnum: TCreatureEnum; const APosition: TPosition): Boolean; @@ -52,7 +52,7 @@ procedure TParty.Clear; constructor TParty.Create; begin Self.Clear; - Owner := rcNeutrals; + Owner := reNeutrals; end; destructor TParty.Destroy; @@ -125,5 +125,4 @@ procedure TParty.UpdateHP(const AHitPoints: Integer; const APosition: TPosition) HitPoints := MaxHitPoints; end; - end. diff --git a/sources/DisciplesRL.PathFind.pas b/sources/DisciplesRL.PathFind.pas new file mode 100644 index 0000000..dc256a8 --- /dev/null +++ b/sources/DisciplesRL.PathFind.pas @@ -0,0 +1,217 @@ +unit DisciplesRL.PathFind; + +interface + +uses DisciplesRL.Map; + +type + TGetXYVal = function(X, Y: Integer): Boolean; stdcall; + +function PathFind(FromX, FromY, ToX, ToY: Integer; Callback: TGetXYVal; + var TargetX, TargetY: Integer): Boolean; + +implementation + +uses Math; + +const + MAXLEN = 1000; + KNORM = 10; + KDIAG = 12; + +type + TUIntPoint = record + X, Y: Word; + end; + +type + TPathFindBlock = record + CostWay: Integer; + Parent: TUIntPoint; + end; + +type + TOpenBlock = record + Cost, X, Y: Integer; + end; + + POpenBlock = ^TOpenBlock; + + TPathFindMap = array of TPathFindBlock; + +var + Cells: TPathFindMap; + FAULT: Integer; + SavedMapX, SavedMapY: Integer; + Open: array [0 .. MAXLEN] of POpenBlock; + OpenRaw: array [0 .. MAXLEN] of TOpenBlock; + +procedure InitCrap; +var + I: Integer; +begin + for I := 0 to MAXLEN do + Open[I] := @OpenRaw[I]; +end; + +function Heuristic(dx, dy: Integer): Integer; +begin + Result := KNORM * Max(dx, dy) + (KDIAG - KNORM) * Min(dx, dy); +end; + +var + NOpen: Integer = 0; + +function PathFind(FromX, FromY, ToX, ToY: Integer; Callback: TGetXYVal; + var TargetX, TargetY: Integer): Boolean; + + procedure HeapSwap(I, j: Integer); + var + tmp: POpenBlock; + begin + tmp := Open[I]; + Open[I] := Open[j]; + Open[j] := tmp; + end; + + procedure HeapAdd; + var + I, Parent: Integer; + begin + I := NOpen - 1; + Parent := (I - 1) div 2; + while (I > 0) and (Open[Parent].Cost > Open[I].Cost) do + begin + HeapSwap(I, Parent); + I := Parent; + Parent := (I - 1) div 2; + end; + end; + + procedure Heapify(I: Integer); + var + leftChild, rightChild, largestChild: Integer; + begin + repeat + leftChild := 2 * I + 1; + if leftChild >= NOpen then + exit; + rightChild := leftChild + 1; + largestChild := I; + if Open[leftChild].Cost < Open[largestChild].Cost then + largestChild := leftChild; + if (rightChild < NOpen) and (Open[rightChild].Cost < Open[largestChild].Cost) then + largestChild := rightChild; + if largestChild = I then + exit; + HeapSwap(I, largestChild); + I := largestChild; + until false; + end; + + procedure AddToOpen(X, Y, FrX, FrY, NewCost: Integer); + begin + if not InRange(X, 0, MapWidth - 1) then + exit; + if not InRange(Y, 0, MapHeight - 1) then + exit; + with Cells[X * MapHeight + Y] do + begin + if CostWay > 0 then // if OpenID > 0 then + begin + // if CostWay <= NewCost then + exit; + end; + if not Callback(X, Y) then + exit; + if NOpen >= MAXLEN then + exit; + Open[NOpen].X := X; + Open[NOpen].Y := Y; + // TODO?? + CostWay := NewCost; + Open[NOpen].Cost := CostWay + Heuristic(abs(X - FromX), abs(Y - FromY)); + Inc(NOpen); + HeapAdd; + Parent.X := FrX; + Parent.Y := FrY; + end; + end; + +var + CurX, CurY: Integer; +begin + Result := false; + if not InRange(ToX, 0, MapWidth - 1) then + exit; + if not InRange(ToY, 0, MapHeight - 1) then + exit; + if not Callback(ToX, ToY) then + exit; + // if not Callback(FromX, FromY) then exit; + if (FromX = ToX) and (FromY = ToY) then + begin + Result := True; + TargetX := ToX; + TargetY := ToY; + exit; + end; + + if (SavedMapX <> MapWidth) or (SavedMapY <> MapHeight) then + begin + SetLength(Cells, 0); + SetLength(Cells, MapWidth * MapHeight); + SavedMapX := MapWidth; + SavedMapY := MapHeight; + end + else + begin + FillChar(Pointer(Cells)^, MapWidth * MapHeight * Sizeof(Cells[0]), 0); + end; + // exit; + + NOpen := 0; + // FillChar(Cells, SizeOf(Cells), 0); + AddToOpen(ToX, ToY, -1, -1, 0); + repeat + CurX := Open[0].X; + CurY := Open[0].Y; + if (CurX = FromX) and (CurY = FromY) then + begin + Result := True; + // Inc(TOTAL, Open[0].Cost); + with Cells[CurX * MapHeight + CurY] do + begin + TargetX := Parent.X; + TargetY := Parent.Y; + end; + exit; + end; + with Cells[CurX * MapHeight + CurY] do + begin + // IsClosed := True; + // inc(CHECKED); + HeapSwap(0, NOpen - 1); + // Open[0] := Open[NOpen-1]; + Dec(NOpen); + Heapify(0); + AddToOpen(CurX - 1, CurY, CurX, CurY, CostWay + KNORM); + AddToOpen(CurX, CurY - 1, CurX, CurY, CostWay + KNORM); + AddToOpen(CurX, CurY + 1, CurX, CurY, CostWay + KNORM); + AddToOpen(CurX + 1, CurY, CurX, CurY, CostWay + KNORM); + AddToOpen(CurX - 1, CurY - 1, CurX, CurY, CostWay + KDIAG); + AddToOpen(CurX - 1, CurY + 1, CurX, CurY, CostWay + KDIAG); + AddToOpen(CurX + 1, CurY - 1, CurX, CurY, CostWay + KDIAG); + AddToOpen(CurX + 1, CurY + 1, CurX, CurY, CostWay + KDIAG); + if NOpen > FAULT then + FAULT := NOpen; + end; + until NOpen <= 0; + Result := false; +end; + +initialization + +InitCrap; + +end. diff --git a/sources/DisciplesRL.Player.pas b/sources/DisciplesRL.Player.pas index 435ed63..c24842c 100644 --- a/sources/DisciplesRL.Player.pas +++ b/sources/DisciplesRL.Player.pas @@ -5,34 +5,75 @@ interface type TPlayer = record X, Y: Integer; - Rad: Integer; + Radius: Integer; + Turn: Integer; end; var Player: TPlayer; procedure Init; -procedure RefreshRad; +procedure Move(const AX, AY: ShortInt); +procedure PutAt(const AX, AY: ShortInt); +procedure RefreshRadius; implementation -uses DisciplesRL.Map, DisciplesRL.Resources, DisciplesRL.Utils; +uses DisciplesRL.Map, DisciplesRL.Resources, DisciplesRL.Utils, DisciplesRL.City, DisciplesRL.Party; procedure Init; begin - Player.Rad := 2; - RefreshRad; + Player.Turn := 0; + Player.Radius := 41; + RefreshRadius; end; -procedure RefreshRad; +procedure Move(const AX, AY: ShortInt); +begin + PutAt(Player.X + AX, Player.Y + AY); +end; + +procedure PutAt(const AX, AY: ShortInt); var - X, Y: Integer; + X, Y, I: Integer; +begin + if not InMap(AX, AY) then Exit; + if (MapObj[AX, AY] = reMountain) then Exit; + Inc(Player.Turn); + for I := 0 to High(City) do + begin + if (City[I].Owner = reTheEmpire) then + if (City[I].CurLevel < City[I].MaxLevel) then + begin + Inc(City[I].CurLevel); + DisciplesRL.City.UpdateRadius(I); + end; + end; + Player.X := AX; + Player.Y := AY; + RefreshRadius; + case MapObj[Player.X, Player.Y] of + reBag: + begin + MapObj[Player.X, Player.Y] := reNone; + end; + reEnemies: + begin + MapObj[Player.X, Player.Y] := reNone; + end; + end; + case MapTile[Player.X, Player.Y] of + reNeutralCity: + begin + MapTile[Player.X, Player.Y] := reEmpireCity; + DisciplesRL.City.UpdateRadius(DisciplesRL.City.GetCityIndex(Player.X, Player.Y)); + end; + end; +end; + +procedure RefreshRadius; begin - for Y := -(Player.Rad + 2) to Player.Rad + 2 do - for X := -(Player.Rad + 2) to Player.Rad + 2 do - if (Utils.GetDist(Player.X + X, Player.Y + Y, Player.X, Player.Y) <= Player.Rad) and - DisciplesRL.Map.InMap(Player.X + X, Player.Y + Y) then - MapDark[Player.X + X, Player.Y + Y] := reNone; + DisciplesRL.Map.UpdateRadius(Player.X, Player.Y, Player.Radius, MapDark, reNone); end; end. diff --git a/sources/DisciplesRL.Resources.pas b/sources/DisciplesRL.Resources.pas index 3cde834..5f886ea 100644 --- a/sources/DisciplesRL.Resources.pas +++ b/sources/DisciplesRL.Resources.pas @@ -5,10 +5,12 @@ interface uses Vcl.Imaging.PNGImage; type - TResEnum = (reNone, reGrass, reUnk, reEnemies, reCursor, rePlayer, reDark, reBag, reCity, reCapital); + TResEnum = (reNone, reNeutral, reEmpireTerrain, reUnk, reEnemies, reCursor, + rePlayer, reDark, reBag, reNeutralCity, reEmpireCity, reEmpireCapital, reMountain); type - TResTypeEnum = (teNone, teTile, teGUI, tePath, teObject, teEnemy, teBag, teCapital, teCity, teRuin); + TResTypeEnum = (teNone, teTile, teGUI, tePath, teObject, teEnemy, teBag, + teCapital, teCity, teRuin); type TResBase = record @@ -20,7 +22,9 @@ TResBase = record ResBase: array [TResEnum] of TResBase = ( // None (FileName: ''; ResType: teNone;), - // Grass + // Neutral + (FileName: 'dirt.png'; ResType: teTile;), + // Empire terrain (FileName: 'grass.png'; ResType: teTile;), // Unknown (?) (FileName: 'unknown.png'; ResType: teGUI;), @@ -36,8 +40,12 @@ TResBase = record (FileName: 'chest.png'; ResType: teBag;), // City (FileName: 'city.png'; ResType: teCity;), + // City + (FileName: 'city.png'; ResType: teCity;), // Capital - (FileName: 'castle.png'; ResType: teCapital;) + (FileName: 'castle.png'; ResType: teCapital;), + // Mountain + (FileName: 'mountain.png'; ResType: teObject;) // ); @@ -59,7 +67,7 @@ procedure Init; begin ResImage[I] := TPNGImage.Create; if (ResBase[I].FileName <> '') then - ResImage[I].LoadFromFile(Utils.GetPath('resources') + ResBase[I].FileName); + ResImage[I].LoadFromFile(GetPath('resources') + ResBase[I].FileName); end; end; diff --git a/sources/DisciplesRL.Scene.Map.pas b/sources/DisciplesRL.Scene.Map.pas index 9946f47..818f4a0 100644 --- a/sources/DisciplesRL.Scene.Map.pas +++ b/sources/DisciplesRL.Scene.Map.pas @@ -18,6 +18,12 @@ implementation DisciplesRL.Player, DisciplesRL.Utils; +const + K_RIGHT = 39; + K_LEFT = 37; + K_DOWN = 40; + K_UP = 38; + var LastMousePos, MousePos: TPoint; @@ -41,19 +47,28 @@ procedure Render; begin if (MapDark[X, Y] = reDark) then Continue; - DrawImage(X, Y, ResImage[reGrass]); - F := (Utils.GetDist(X, Y, Player.X, Player.Y) > Player.Rad) and (MapDark[X, Y] = reNone); + case MapTile[X, Y] of + reEmpireTerrain, reEmpireCapital, reEmpireCity: + DrawImage(X, Y, ResImage[reEmpireTerrain]); + else + DrawImage(X, Y, ResImage[reNeutral]); + end; + F := (GetDist(X, Y, Player.X, Player.Y) > Player.Radius) and + not(MapTile[X, Y] in [reEmpireTerrain, reEmpireCapital, reEmpireCity]) and (MapDark[X, Y] = reNone); + // Capital and Cities + if (ResBase[MapTile[X, Y]].ResType in [teCapital, teCity]) then + DrawImage(X, Y, ResImage[MapTile[X, Y]]); // - if (ResBase[MapTile[X, Y]].ResType in [teEnemy, teBag]) then + if (ResBase[MapObj[X, Y]].ResType in [teEnemy, teBag]) then if F then DrawImage(X, Y, ResImage[reUnk]) else - DrawImage(X, Y, ResImage[MapTile[X, Y]]); - if (ResBase[MapTile[X, Y]].ResType in [teCapital, teCity, teObject]) then - DrawImage(X, Y, ResImage[MapTile[X, Y]]); - // Leader - if (X = Player.X) and (Y = Player.Y) then - DrawImage(X, Y, ResImage[rePlayer]); + DrawImage(X, Y, ResImage[MapObj[X, Y]]) + else if (MapObj[X, Y] <> reNone) then + DrawImage(X, Y, ResImage[MapObj[X, Y]]); + // Leader + if (X = Player.X) and (Y = Player.Y) then + DrawImage(X, Y, ResImage[rePlayer]); // Fog if F then DrawImage(X, Y, ResImage[reDark]); @@ -70,14 +85,7 @@ procedure Timer; procedure MouseClick; begin if DisciplesRL.Map.InMap(MousePos.X, MousePos.Y) then - begin - Player.X := MousePos.X; - Player.Y := MousePos.Y; - DisciplesRL.Player.RefreshRad; - if (MapTile[Player.X, Player.Y] in [reBag, reEnemies]) then - MapTile[Player.X, Player.Y] := reNone; - - end; + DisciplesRL.Player.PutAt(MousePos.X, MousePos.Y); end; procedure MouseMove(Shift: TShiftState; X, Y: Integer); @@ -93,7 +101,16 @@ procedure MouseMove(Shift: TShiftState; X, Y: Integer); procedure KeyDown(var Key: Word; Shift: TShiftState); begin - + case Key of + K_UP: + DisciplesRL.Player.Move(0, -1); + K_DOWN: + DisciplesRL.Player.Move(0, 1); + K_LEFT: + DisciplesRL.Player.Move(-1, 0); + K_RIGHT: + DisciplesRL.Player.Move(1, 0); + end; end; procedure Free; diff --git a/sources/DisciplesRL.Utils.pas b/sources/DisciplesRL.Utils.pas index 351619a..8b1292f 100644 --- a/sources/DisciplesRL.Utils.pas +++ b/sources/DisciplesRL.Utils.pas @@ -5,30 +5,26 @@ interface uses Forms; -type - Utils = class(TObject) - public - class function GetDist(X1, Y1, X2, Y2: Single): Word; - class function GetPath(SubDir: string): string; - class function ShowForm(const Form: TForm): Integer; - end; +function GetDist(X1, Y1, X2, Y2: Single): Word; +function GetPath(SubDir: string): string; +function ShowForm(const Form: TForm): Integer; implementation uses SysUtils; -class function Utils.GetDist(X1, Y1, X2, Y2: Single): Word; +function GetDist(X1, Y1, X2, Y2: Single): Word; begin Result := Round(Sqrt(Sqr(X2 - X1) + Sqr(Y2 - Y1))); end; -class function Utils.GetPath(SubDir: string): string; +function GetPath(SubDir: string): string; begin Result := ExtractFilePath(ParamStr(0)); Result := IncludeTrailingPathDelimiter(Result + SubDir); end; -class function Utils.ShowForm(const Form: TForm): Integer; +function ShowForm(const Form: TForm): Integer; begin with Form do begin diff --git a/sources/DisciplesRL.dpr b/sources/DisciplesRL.dpr index 2c7b50b..9b57e0b 100644 --- a/sources/DisciplesRL.dpr +++ b/sources/DisciplesRL.dpr @@ -10,7 +10,9 @@ uses DisciplesRL.Resources in 'DisciplesRL.Resources.pas', DisciplesRL.Player in 'DisciplesRL.Player.pas', DisciplesRL.Creatures in 'DisciplesRL.Creatures.pas', - DisciplesRL.Party in 'DisciplesRL.Party.pas'; + DisciplesRL.Party in 'DisciplesRL.Party.pas', + DisciplesRL.City in 'DisciplesRL.City.pas', + DisciplesRL.PathFind in 'DisciplesRL.PathFind.pas'; {$R *.res} diff --git a/sources/DisciplesRL.dproj b/sources/DisciplesRL.dproj index 6a10030..09e5c88 100644 --- a/sources/DisciplesRL.dproj +++ b/sources/DisciplesRL.dproj @@ -95,6 +95,8 @@ + + Cfg_2 Base