- Added optional highlight for (un)walkable tiles

- Fixed lightmanager to draw in the correct color
- Fixed TMapBlock and TStaticBlock to correctly initialize itself as "unchanged"
- Cleanup in the server project
This commit is contained in:
Andreas Schneider 2009-12-24 15:49:15 +01:00
parent f2764e928e
commit d461774816
9 changed files with 2396 additions and 2253 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,376 +1,378 @@
(* (*
* CDDL HEADER START * CDDL HEADER START
* *
* The contents of this file are subject to the terms of the * The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only * Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance * (the "License"). You may not use this file except in compliance
* with the License. * with the License.
* *
* You can obtain a copy of the license at * You can obtain a copy of the license at
* http://www.opensource.org/licenses/cddl1.php. * http://www.opensource.org/licenses/cddl1.php.
* See the License for the specific language governing permissions * See the License for the specific language governing permissions
* and limitations under the License. * and limitations under the License.
* *
* When distributing Covered Code, include this CDDL HEADER in each * When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at * file and include the License file at
* http://www.opensource.org/licenses/cddl1.php. If applicable, * http://www.opensource.org/licenses/cddl1.php. If applicable,
* add the following below this CDDL HEADER, with the fields enclosed * add the following below this CDDL HEADER, with the fields enclosed
* by brackets "[]" replaced with your own identifying * information: * by brackets "[]" replaced with your own identifying * information:
* Portions Copyright [yyyy] [name of copyright owner] * Portions Copyright [yyyy] [name of copyright owner]
* *
* CDDL HEADER END * CDDL HEADER END
* *
* *
* Portions Copyright 2009 Andreas Schneider * Portions Copyright 2009 Andreas Schneider
*) *)
unit ULightManager; unit ULightManager;
{$mode objfpc}{$H+} {$mode objfpc}{$H+}
interface interface
uses uses
Classes, SysUtils, Imaging, ImagingTypes, ImagingClasses, ImagingCanvases, Classes, SysUtils, Imaging, ImagingTypes, ImagingClasses, ImagingCanvases,
ImagingOpenGL, GL, GLu, GLext, fgl, ULandscape, UWorldItem, UCacheManager; ImagingOpenGL, GL, GLu, GLext, fgl, ULandscape, UWorldItem, UCacheManager;
type type
TCalculateOffset = procedure(AX, AY: Integer; out DrawX, DrawY: Integer) of object; TCalculateOffset = procedure(AX, AY: Integer; out DrawX, DrawY: Integer) of object;
{ TLightMaterial } { TLightMaterial }
TLightMaterial = class(TSimpleMaterial) TLightMaterial = class(TSimpleMaterial)
constructor Create(AGraphic: TBaseImage); constructor Create(AGraphic: TBaseImage);
destructor Destroy; override; destructor Destroy; override;
protected protected
FCanvas: TFastARGB32Canvas; FCanvas: TFastARGB32Canvas;
public public
property Canvas: TFastARGB32Canvas read FCanvas; property Canvas: TFastARGB32Canvas read FCanvas;
end; end;
TLightCache = specialize TCacheManager<TLightMaterial>; TLightCache = specialize TCacheManager<TLightMaterial>;
TLightManager = class; TLightManager = class;
{ TLightSource } { TLightSource }
TLightSource = class TLightSource = class
constructor Create(AManager: TLightManager; AWorldItem: TWorldItem); constructor Create(AManager: TLightManager; AWorldItem: TWorldItem);
destructor Destroy; override; destructor Destroy; override;
protected protected
FX: Integer; FX: Integer;
FY: Integer; FY: Integer;
FZ: SmallInt; FZ: SmallInt;
FMaterial: TLightMaterial; FMaterial: TLightMaterial;
public public
property X: Integer read FX; property X: Integer read FX;
property Y: Integer read FY; property Y: Integer read FY;
property Z: SmallInt read FZ; property Z: SmallInt read FZ;
property Material: TLightMaterial read FMaterial; property Material: TLightMaterial read FMaterial;
end; end;
TLightSources = specialize TFPGObjectList<TLightSource>; TLightSources = specialize TFPGObjectList<TLightSource>;
{ TLightManager } { TLightManager }
TLightManager = class TLightManager = class
constructor Create(ACalculateOffset: TCalculateOffset); constructor Create(ACalculateOffset: TCalculateOffset);
destructor Destroy; override; destructor Destroy; override;
protected protected
FLightSources: TLightSources; FLightSources: TLightSources;
FOverlay: TSingleImage; FOverlay: TSingleImage;
FOverlayTexture: GLuint; FOverlayTexture: GLuint;
FLightLevel: Byte; FLightLevel: Byte;
FValid: Boolean; FValid: Boolean;
FCalculateOffset: TCalculateOffset; FCalculateOffset: TCalculateOffset;
FLightCache: TLightCache; FLightCache: TLightCache;
FUseFBO: Boolean; FUseFBO: Boolean;
FInitialized: Boolean; FInitialized: Boolean;
function GetLight(AID: Integer): TLightMaterial; function GetLight(AID: Integer): TLightMaterial;
procedure SetLightLevel(AValue: Byte); procedure SetLightLevel(AValue: Byte);
procedure UpdateOverlay(AScreenRect: TRect); procedure UpdateOverlay(AScreenRect: TRect);
public public
property LightLevel: Byte read FLightLevel write SetLightLevel; property LightLevel: Byte read FLightLevel write SetLightLevel;
procedure InitGL; procedure InitGL;
procedure UpdateLightMap(ALeft, AWidth, ATop, AHeight: Integer; procedure UpdateLightMap(ALeft, AWidth, ATop, AHeight: Integer;
AScreenBuffer: TScreenBuffer); AScreenBuffer: TScreenBuffer);
procedure Draw(AScreenRect: TRect); procedure Draw(AScreenRect: TRect);
end; end;
implementation implementation
uses uses
UGameResources, UTiledata, UStatics, UMap, ULight, Logging; UGameResources, UTiledata, UStatics, UMap, ULight, Logging;
{ TLightManager } { TLightManager }
constructor TLightManager.Create(ACalculateOffset: TCalculateOffset); constructor TLightManager.Create(ACalculateOffset: TCalculateOffset);
begin begin
FCalculateOffset := ACalculateOffset; FCalculateOffset := ACalculateOffset;
FLightSources := TLightSources.Create(True); FLightSources := TLightSources.Create(True);
FLightLevel := 0; FLightLevel := 0;
FLightCache := TLightCache.Create(32); FLightCache := TLightCache.Create(32);
FInitialized := False; FInitialized := False;
end; end;
destructor TLightManager.Destroy; destructor TLightManager.Destroy;
begin begin
FreeAndNil(FLightSources); FreeAndNil(FLightSources);
FreeAndNil(FOverlay); FreeAndNil(FOverlay);
FreeAndNil(FLightCache); FreeAndNil(FLightCache);
glDeleteTextures(1, @FOverlayTexture); glDeleteTextures(1, @FOverlayTexture);
inherited Destroy; inherited Destroy;
end; end;
function TLightManager.GetLight(AID: Integer): TLightMaterial; function TLightManager.GetLight(AID: Integer): TLightMaterial;
var var
light: TLight; light: TLight;
begin begin
Result := nil; Result := nil;
if not FLightCache.QueryID(AID, Result) then if not FLightCache.QueryID(AID, Result) then
begin begin
if ResMan.Lights.Exists(AID) then if ResMan.Lights.Exists(AID) then
begin begin
light := ResMan.Lights.GetLight(AID); light := ResMan.Lights.GetLight(AID);
Result := TLightMaterial.Create(light.Graphic); Result := TLightMaterial.Create(light.Graphic);
FLightCache.StoreID(AID, Result); FLightCache.StoreID(AID, Result);
light.Free; light.Free;
end; end;
end; end;
end; end;
procedure TLightManager.SetLightLevel(AValue: Byte); procedure TLightManager.SetLightLevel(AValue: Byte);
begin begin
FLightLevel := AValue; FLightLevel := AValue;
FValid := False; FValid := False;
end; end;
procedure TLightManager.UpdateOverlay(AScreenRect: TRect); procedure TLightManager.UpdateOverlay(AScreenRect: TRect);
var var
canvas: TFastARGB32Canvas; canvas: TFastARGB32Canvas;
color: TColor32Rec; color: TColor32Rec;
i: Integer; i: Integer;
lightMaterial: TLightMaterial; lightMaterial: TLightMaterial;
colorGL: GLclampf; colorGL: GLclampf;
fbo: GLuint; fbo: GLuint;
begin begin
glDeleteTextures(1, @FOverlayTexture); glDeleteTextures(1, @FOverlayTexture);
if FUseFBO then if FUseFBO then
begin begin
glGenTextures(1, @FOverlayTexture); glGenTextures(1, @FOverlayTexture);
glBindTexture(GL_TEXTURE_2D, FOverlayTexture); glBindTexture(GL_TEXTURE_2D, FOverlayTexture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, AScreenRect.Right, glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, AScreenRect.Right,
AScreenRect.Bottom, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil); AScreenRect.Bottom, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
glGenFramebuffersEXT(1, @fbo); glGenFramebuffersEXT(1, @fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, FOverlayTexture, 0); GL_TEXTURE_2D, FOverlayTexture, 0);
colorGL :=(32 - lightLevel) / 32; colorGL :=(32 - lightLevel) / 32;
glClearColor(colorGL, colorGL, colorGL, 1); glClearColor(colorGL, colorGL, colorGL, 1);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
glBlendFunc(GL_ONE, GL_ONE); glBlendFunc(GL_ONE, GL_ONE);
for i := 0 to FLightSources.Count - 1 do for i := 0 to FLightSources.Count - 1 do
begin begin
lightMaterial := FLightSources[i].Material; lightMaterial := FLightSources[i].Material;
if lightMaterial <> nil then if lightMaterial <> nil then
begin begin
glBindTexture(GL_TEXTURE_2D, lightMaterial.Texture); glBindTexture(GL_TEXTURE_2D, lightMaterial.Texture);
glBegin(GL_QUADS); glBegin(GL_QUADS);
glTexCoord2i(0, 0); glTexCoord2i(0, 0);
glVertex2i(FLightSources[i].FX - lightMaterial.RealWidth div 2, glVertex2i(FLightSources[i].FX - lightMaterial.RealWidth div 2,
FLightSources[i].FY - lightMaterial.RealHeight div 2); FLightSources[i].FY - lightMaterial.RealHeight div 2);
glTexCoord2i(0, 1); glTexCoord2i(0, 1);
glVertex2i(FLightSources[i].FX - lightMaterial.RealWidth div 2, glVertex2i(FLightSources[i].FX - lightMaterial.RealWidth div 2,
FLightSources[i].FY - lightMaterial.RealHeight div 2 + FLightSources[i].FY - lightMaterial.RealHeight div 2 +
lightMaterial.Height); lightMaterial.Height);
glTexCoord2i(1, 1); glTexCoord2i(1, 1);
glVertex2i(FLightSources[i].FX - lightMaterial.RealWidth div 2 + glVertex2i(FLightSources[i].FX - lightMaterial.RealWidth div 2 +
lightMaterial.Width, FLightSources[i].FY - lightMaterial.Width, FLightSources[i].FY -
lightMaterial.RealHeight div 2 + lightMaterial.Height); lightMaterial.RealHeight div 2 + lightMaterial.Height);
glTexCoord2i(1, 0); glTexCoord2i(1, 0);
glVertex2i(FLightSources[i].FX - lightMaterial.RealWidth div 2 + glVertex2i(FLightSources[i].FX - lightMaterial.RealWidth div 2 +
lightMaterial.Width, lightMaterial.Width,
FLightSources[i].FY - lightMaterial.RealHeight div 2); FLightSources[i].FY - lightMaterial.RealHeight div 2);
glEnd; glEnd;
end; end;
end; end;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glDeleteFramebuffersEXT(1, @fbo); glDeleteFramebuffersEXT(1, @fbo);
end else end else
begin begin
FOverlay.Free; FOverlay.Free;
color.A := $FF; color.A := $FF;
color.R := ((32 - FLightLevel) * 255) div 32; color.R := ((32 - FLightLevel) * 255) div 32;
color.G := color.R; color.G := color.R;
color.B := color.R; color.B := color.R;
FOverlay := TSingleImage.CreateFromParams(AScreenRect.Right, FOverlay := TSingleImage.CreateFromParams(AScreenRect.Right,
AScreenRect.Bottom, ifA8R8G8B8); AScreenRect.Bottom, ifA8R8G8B8);
canvas := TFastARGB32Canvas.CreateForImage(FOverlay); canvas := TFastARGB32Canvas.CreateForImage(FOverlay);
try try
canvas.FillColor32 := color.Color; canvas.FillColor32 := color.Color;
canvas.FillRect(AScreenRect); canvas.FillRect(AScreenRect);
for i := 0 to FLightSources.Count - 1 do for i := 0 to FLightSources.Count - 1 do
begin begin
lightMaterial := FLightSources[i].Material; lightMaterial := FLightSources[i].Material;
if lightMaterial <> nil then if lightMaterial <> nil then
begin begin
lightMaterial.Canvas.DrawAdd(lightMaterial.Canvas.ClipRect, canvas, lightMaterial.Canvas.DrawAdd(lightMaterial.Canvas.ClipRect, canvas,
FLightSources[i].FX - lightMaterial.RealWidth div 2, FLightSources[i].FX - lightMaterial.RealWidth div 2,
FLightSources[i].FY - lightMaterial.RealHeight div 2); FLightSources[i].FY - lightMaterial.RealHeight div 2);
end; end;
end; end;
finally finally
canvas.Free; canvas.Free;
end; end;
FOverlayTexture := CreateGLTextureFromImage(FOverlay.ImageDataPointer^); FOverlayTexture := CreateGLTextureFromImage(FOverlay.ImageDataPointer^);
end; end;
FValid := True; FValid := True;
end; end;
procedure TLightManager.InitGL; procedure TLightManager.InitGL;
begin begin
FUseFBO := Load_GL_EXT_framebuffer_object; FUseFBO := Load_GL_EXT_framebuffer_object;
end; end;
procedure TLightManager.UpdateLightMap(ALeft, AWidth, ATop, AHeight: Integer; procedure TLightManager.UpdateLightMap(ALeft, AWidth, ATop, AHeight: Integer;
AScreenBuffer: TScreenBuffer); AScreenBuffer: TScreenBuffer);
var var
blockInfo: PBlockInfo; blockInfo: PBlockInfo;
lights: TWorldItemList; lights: TWorldItemList;
i, x, y, tileID: Integer; i, x, y, tileID: Integer;
tileData: TTiledata; tileData: TTiledata;
tileMap: array of array of TWorldItem; tileMap: array of array of TWorldItem;
begin begin
//Logger.EnterMethod([lcClient, lcDebug], 'UpdateLightMap'); //Logger.EnterMethod([lcClient, lcDebug], 'UpdateLightMap');
FLightSources.Clear; FLightSources.Clear;
{Logger.Send([lcClient, lcDebug], 'AWidth', AWidth); {Logger.Send([lcClient, lcDebug], 'AWidth', AWidth);
Logger.Send([lcClient, lcDebug], 'AHeight', AHeight);} Logger.Send([lcClient, lcDebug], 'AHeight', AHeight);}
lights := TWorldItemList.Create(False); lights := TWorldItemList.Create(False);
SetLength(tileMap, AWidth, AHeight); SetLength(tileMap, AWidth, AHeight);
for x := 0 to AWidth - 1 do for x := 0 to AWidth - 1 do
for y := 0 to AHeight - 1 do for y := 0 to AHeight - 1 do
tileMap[x,y] := nil; tileMap[x,y] := nil;
blockInfo := nil; blockInfo := nil;
while AScreenBuffer.Iterate(blockInfo) do while AScreenBuffer.Iterate(blockInfo) do
begin begin
if blockInfo^.State = ssNormal then if blockInfo^.State = ssNormal then
begin begin
if blockInfo^.Item is TStaticItem then if blockInfo^.Item is TStaticItem then
tileID := blockInfo^.Item.TileID + $4000 tileID := blockInfo^.Item.TileID + $4000
else else
tileID := blockInfo^.Item.TileID; tileID := blockInfo^.Item.TileID;
tileData := ResMan.Tiledata.TileData[tileID]; tileData := ResMan.Tiledata.TileData[tileID];
if tdfLightSource in tileData.Flags then if tdfLightSource in tileData.Flags then
lights.Add(blockInfo^.Item) lights.Add(blockInfo^.Item)
else else
tileMap[blockInfo^.Item.X - ALeft, blockInfo^.Item.Y - ATop] := tileMap[blockInfo^.Item.X - ALeft, blockInfo^.Item.Y - ATop] :=
blockInfo^.Item; blockInfo^.Item;
end; end;
end; end;
for i := 0 to lights.Count - 1 do for i := 0 to lights.Count - 1 do
begin begin
x := lights[i].X + 1 - ALeft; x := lights[i].X + 1 - ALeft;
y := lights[i].Y + 1 - ATop; y := lights[i].Y + 1 - ATop;
if (x = AWidth) or (y = AHeight) or (tileMap[x,y] = nil) or if (x = AWidth) or (y = AHeight) or (tileMap[x,y] = nil) or
(tileMap[x,y].Z < lights[i].Z + 5) then (tileMap[x,y].Z < lights[i].Z + 5) then
FLightSources.Add(TLightSource.Create(Self, lights[i])); FLightSources.Add(TLightSource.Create(Self, lights[i]));
end; end;
lights.Free; lights.Free;
FValid := False; FValid := False;
//Logger.ExitMethod([lcClient, lcDebug], 'UpdateLightMap'); //Logger.ExitMethod([lcClient, lcDebug], 'UpdateLightMap');
end; end;
procedure TLightManager.Draw(AScreenRect: TRect); procedure TLightManager.Draw(AScreenRect: TRect);
begin begin
if not FInitialized then if not FInitialized then
InitGL; InitGL;
if not FValid then glColor4f(1, 1, 1, 1);
UpdateOverlay(AScreenRect);
if not FValid then
glBindTexture(GL_TEXTURE_2D, FOverlayTexture); UpdateOverlay(AScreenRect);
glBlendFunc(GL_ZERO, GL_SRC_COLOR);
glBegin(GL_QUADS); glBindTexture(GL_TEXTURE_2D, FOverlayTexture);
if FUseFBO then glBlendFunc(GL_ZERO, GL_SRC_COLOR);
begin glBegin(GL_QUADS);
glTexCoord2i(0, 1); if FUseFBO then
glVertex2i(AScreenRect.Left, AScreenRect.Top); begin
glTexCoord2i(0, 0); glTexCoord2i(0, 1);
glVertex2i(AScreenRect.Left, AScreenRect.Bottom); glVertex2i(AScreenRect.Left, AScreenRect.Top);
glTexCoord2i(1, 0); glTexCoord2i(0, 0);
glVertex2i(AScreenRect.Right, AScreenRect.Bottom); glVertex2i(AScreenRect.Left, AScreenRect.Bottom);
glTexCoord2i(1, 1); glTexCoord2i(1, 0);
glVertex2i(AScreenRect.Right, AScreenRect.Top); glVertex2i(AScreenRect.Right, AScreenRect.Bottom);
end else glTexCoord2i(1, 1);
begin glVertex2i(AScreenRect.Right, AScreenRect.Top);
glTexCoord2i(0, 0); end else
glVertex2i(AScreenRect.Left, AScreenRect.Top); begin
glTexCoord2i(0, 1); glTexCoord2i(0, 0);
glVertex2i(AScreenRect.Left, AScreenRect.Bottom); glVertex2i(AScreenRect.Left, AScreenRect.Top);
glTexCoord2i(1, 1); glTexCoord2i(0, 1);
glVertex2i(AScreenRect.Right, AScreenRect.Bottom); glVertex2i(AScreenRect.Left, AScreenRect.Bottom);
glTexCoord2i(1, 0); glTexCoord2i(1, 1);
glVertex2i(AScreenRect.Right, AScreenRect.Top); glVertex2i(AScreenRect.Right, AScreenRect.Bottom);
end; glTexCoord2i(1, 0);
glEnd; glVertex2i(AScreenRect.Right, AScreenRect.Top);
end; end;
glEnd;
{ TLightSource } end;
constructor TLightSource.Create(AManager: TLightManager; AWorldItem: TWorldItem); { TLightSource }
var
lightID: Byte; constructor TLightSource.Create(AManager: TLightManager; AWorldItem: TWorldItem);
begin var
lightID := ResMan.Tiledata.StaticTiles[AWorldItem.TileID].Quality; lightID: Byte;
FMaterial := AManager.GetLight(lightID); begin
if FMaterial <> nil then lightID := ResMan.Tiledata.StaticTiles[AWorldItem.TileID].Quality;
begin FMaterial := AManager.GetLight(lightID);
AManager.FCalculateOffset(AWorldItem.X, AWorldItem.Y, FX, FY); if FMaterial <> nil then
FZ := AWorldItem.Z * 4; begin
FY := FY + 22 - FZ; AManager.FCalculateOffset(AWorldItem.X, AWorldItem.Y, FX, FY);
FMaterial.AddRef; FZ := AWorldItem.Z * 4;
end; FY := FY + 22 - FZ;
end; FMaterial.AddRef;
end;
destructor TLightSource.Destroy; end;
begin
if FMaterial <> nil then destructor TLightSource.Destroy;
FMaterial.DelRef; begin
inherited Destroy; if FMaterial <> nil then
end; FMaterial.DelRef;
inherited Destroy;
{ TLightMaterial } end;
constructor TLightMaterial.Create(AGraphic: TBaseImage); { TLightMaterial }
begin
inherited Create(AGraphic); constructor TLightMaterial.Create(AGraphic: TBaseImage);
FCanvas := TFastARGB32Canvas.CreateForImage(FGraphic); begin
end; inherited Create(AGraphic);
FCanvas := TFastARGB32Canvas.CreateForImage(FGraphic);
destructor TLightMaterial.Destroy; end;
begin
FreeAndNil(FCanvas); destructor TLightMaterial.Destroy;
inherited Destroy; begin
end; FreeAndNil(FCanvas);
inherited Destroy;
end. end;
end.

View File

@ -967,14 +967,14 @@ object frmMain: TfrmMain
OnClick = tbStaticsClick OnClick = tbStaticsClick
end end
object tbSeparator5: TToolButton object tbSeparator5: TToolButton
Left = 438 Left = 461
Top = 2 Top = 2
Width = 17 Width = 17
Caption = 'tbSeparator5' Caption = 'tbSeparator5'
Style = tbsDivider Style = tbsDivider
end end
object tbRadarMap: TToolButton object tbRadarMap: TToolButton
Left = 455 Left = 478
Hint = 'Radar Map' Hint = 'Radar Map'
Top = 2 Top = 2
Caption = 'Radar Map' Caption = 'Radar Map'
@ -996,7 +996,7 @@ object frmMain: TfrmMain
OnMouseMove = tbFilterMouseMove OnMouseMove = tbFilterMouseMove
end end
object tbFlat: TToolButton object tbFlat: TToolButton
Left = 403 Left = 426
Top = 2 Top = 2
Action = acFlat Action = acFlat
DropdownMenu = pmFlatViewSettings DropdownMenu = pmFlatViewSettings
@ -1020,11 +1020,17 @@ object frmMain: TfrmMain
Top = 2 Top = 2
Action = acUndo Action = acUndo
end end
object ToolButton1: TToolButton object tbLightlevel: TToolButton
Left = 380 Left = 403
Top = 2 Top = 2
Action = acLightlevel Action = acLightlevel
end end
object tbWalkable: TToolButton
Left = 380
Top = 2
Action = acWalkable
Style = tbsCheck
end
end end
object pnlChatHeader: TPanel object pnlChatHeader: TPanel
AnchorSideLeft.Control = pnlChat AnchorSideLeft.Control = pnlChat
@ -1465,7 +1471,7 @@ object frmMain: TfrmMain
left = 264 left = 264
top = 32 top = 32
Bitmap = { Bitmap = {
4C69160000001000000010000000000000000000000000000000000000000000 4C69170000001000000010000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000
0000D9A781FFD39E76FF00000000000000000000000000000000000000000000 0000D9A781FFD39E76FF00000000000000000000000000000000000000000000
0000000000000000000000000000ECBEA1FFE7BB9DFFE4B697FFE0B292FFDAAE 0000000000000000000000000000ECBEA1FFE7BB9DFFE4B697FFE0B292FFDAAE
@ -2169,7 +2175,39 @@ object frmMain: TfrmMain
FF0088A7BB5D485055F5444545FE3F4141FE3F474AF67D9CB16AFFFFFF00FFFF FF0088A7BB5D485055F5444545FE3F4141FE3F474AF67D9CB16AFFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00 FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF006D9CD4896A9AD2FB6697CFEEFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00709ED6DB6D9C
D4FF85B1DAFF5A91B9FF6093CBEAFFFFFF00FFFFFF00808080FF7E7E7EFF7C7C
7CFF7A7A7AFF777777FF757575FF727272FF719ED4FF6F9ED6FF87B2DCFFABD3
E8FFA9D0E6FF5890B8FF598EC6EAFFFFFF00FFFFFF007D7D7DFF999999FF9999
99FF9A9A9AFF9A9A9AFF9B9B9BFF9B9B9BFF6F9DD3FFAAD1E7FFABD1E7FF98C7
E1FF91C2DEFF568FB7FF5289C1EAFFFFFF00FFFFFF007A7A7AFF999999FF5291
59FF999A99FF9B9B9BFF9C9C9CFF9C9C9CFF6C9AD0FFA7CEE5FF8FC1DFFF89BD
DCFF8BBDDCFF538DB6FF4B84BCEAFFFFFF00FFFFFF00777777FF9A9A9AFF3D8A
45FF498A4FFF9C9C9CFF9D9D9DFF9D9D9DFF6696CCFFA2CBE3FF89BDDCFF83B9
DAFF84B9DAFF518BB5FF437EB6EA44944DFF42914BFF3F8D48FF3D8945FF5DA4
65FF5AA061FF45834BFF9E9E9EFF9E9E9EFF6092C9FF9EC7E2FF83B8DAFF7DB4
D7FF7EB3D7FF4F89B4FF3B79B1EA41904AFF94D29FFF91D09AFF8DCD96FF89CB
92FF84C88DFF519858FF417C46FF9F9F9FFF5A8EC4FF98C3E0FF7CB3D7FF74AF
D6FF5EC4EDFF4B88B3FF3473ABEA3E8B46FF8FCE99FF7DC687FF78C381FF73C0
7CFF74C07CFF79C281FF49904FFF547F57FF5489BFFF94BFDDFF75ADD4FF63B8
E1FF4BD4FFFF428BB8FF2C6EA6EA3B8742FF89CB92FF84C88DFF80C688FF7BC3
83FF77C17FFF478F4DFF3B743FFFA1A1A1FF4C84BAFF8DBBDBFF6EA8D1FF66A6
D1FF5FB4DFFF4785B1FF2569A1EA37823EFF347E3BFF317937FF2E7534FF4991
50FF468F4CFF39733DFFA1A1A1FFA2A2A2FF457EB4FF88B7D9FF67A3CFFF619E
CCFF639FCCFF4583B1FF1F649CEAFFFFFF00FFFFFF00606060FFA0A0A0FF3D76
41FF367139FFA2A2A2FFA2A2A2FFA3A3A3FF3D79B0FF82B3D7FF629FCCFF5A9A
C9FF5E9BCAFF4381AFFF196098EAFFFFFF00FFFFFF005C5C5CFFA1A1A1FF3C73
40FFA0A1A1FFA3A3A3FFA3A3A3FFA4A4A4FF3674AAFF7DAFD4FF5B9AC9FF5495
C7FF5896C8FF4180AEFF135C94EAFFFFFF00FFFFFF00585858FFA2A2A2FFA2A2
A2FFA3A3A3FFA4A4A4FFA4A4A4FFA5A5A5FF2F6FA5FF78ABD2FF78ABD3FF73A7
D1FF69A0CDFF407FAEFF0F5991EA999999FF717171FF545454FF515151FF4F4F
4FFF4C4C4CFF4A4A4AFF474747FF454545FF25679DFF3274A8FF3D7CAFFF4784
B5FF4E8ABAFF3E7EADFF0C578FEAFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001D639B1619609839145D9562105A
92880D5890A4135C92FC0C578FED
} }
end end
object pmTileList: TPopupMenu object pmTileList: TPopupMenu
@ -2657,6 +2695,15 @@ object frmMain: TfrmMain
ImageIndex = 21 ImageIndex = 21
OnExecute = acLightlevelExecute OnExecute = acLightlevelExecute
end end
object acWalkable: TAction
Category = 'Settings'
AutoCheck = True
Caption = 'Walkable'
Hint = 'Highlight (un)walkable surfaces'
ImageIndex = 22
OnExecute = acWalkableExecute
ShortCut = 16471
end
end end
object tmGrabTileInfo: TTimer object tmGrabTileInfo: TTimer
Enabled = False Enabled = False

View File

@ -69,6 +69,7 @@ type
acFlat: TAction; acFlat: TAction;
acNoDraw: TAction; acNoDraw: TAction;
acLightlevel: TAction; acLightlevel: TAction;
acWalkable: TAction;
acUndo: TAction; acUndo: TAction;
acVirtualLayer: TAction; acVirtualLayer: TAction;
ActionList1: TActionList; ActionList1: TActionList;
@ -149,7 +150,8 @@ type
tbNoDraw: TToolButton; tbNoDraw: TToolButton;
tbSeparator2: TToolButton; tbSeparator2: TToolButton;
tbUndo: TToolButton; tbUndo: TToolButton;
ToolButton1: TToolButton; tbLightlevel: TToolButton;
tbWalkable: TToolButton;
tsLocations: TTabSheet; tsLocations: TTabSheet;
tbSetHue: TToolButton; tbSetHue: TToolButton;
tmGrabTileInfo: TTimer; tmGrabTileInfo: TTimer;
@ -190,6 +192,7 @@ type
procedure acSelectExecute(Sender: TObject); procedure acSelectExecute(Sender: TObject);
procedure acUndoExecute(Sender: TObject); procedure acUndoExecute(Sender: TObject);
procedure acVirtualLayerExecute(Sender: TObject); procedure acVirtualLayerExecute(Sender: TObject);
procedure acWalkableExecute(Sender: TObject);
procedure ApplicationProperties1Idle(Sender: TObject; var Done: Boolean); procedure ApplicationProperties1Idle(Sender: TObject; var Done: Boolean);
procedure ApplicationProperties1ShowHint(var HintStr: string; procedure ApplicationProperties1ShowHint(var HintStr: string;
var CanShow: Boolean; var HintInfo: THintInfo); var CanShow: Boolean; var HintInfo: THintInfo);
@ -525,6 +528,9 @@ end;
procedure TfrmMain.oglGameWindowKeyDown(Sender: TObject; var Key: Word; procedure TfrmMain.oglGameWindowKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState); Shift: TShiftState);
begin begin
if Shift <> [] then
Exit;
case Key of case Key of
VK_W, VK_NUMPAD8, VK_UP: VK_W, VK_NUMPAD8, VK_UP:
MoveBy(-8, -8); MoveBy(-8, -8);
@ -1125,6 +1131,12 @@ begin
frmVirtualLayer.Show; frmVirtualLayer.Show;
end; end;
procedure TfrmMain.acWalkableExecute(Sender: TObject);
begin
InvalidateFilter;
FRepaintNeeded := True;
end;
procedure TfrmMain.acDrawExecute(Sender: TObject); procedure TfrmMain.acDrawExecute(Sender: TObject);
begin begin
acDraw.Checked := True; acDraw.Checked := True;
@ -2311,7 +2323,7 @@ end;
procedure TfrmMain.Render; procedure TfrmMain.Render;
var var
highlight: Boolean; highlight: Boolean;
intensity: GLfloat; intensity, red, green, blue: GLfloat;
blockInfo: PBlockInfo; blockInfo: PBlockInfo;
item: TWorldItem; item: TWorldItem;
begin begin
@ -2345,10 +2357,31 @@ begin
SetDarkLights; SetDarkLights;
end; end;
case blockInfo^.WalkRestriction of
wrNone:
begin
red := 1;
green := 1;
blue := 1;
end;
wrCanWalk:
begin
red := 0.5;
green := 1;
blue := 0.5;
end;
wrCannotWalk:
begin
red := 1;
green := 0.5;
blue := 0.5;
end;
end;
if blockInfo^.Translucent then if blockInfo^.Translucent then
glColor4f(intensity, intensity, intensity, 0.8) glColor4f(intensity * red, intensity * green, intensity * blue, 0.8)
else else
glColor4f(intensity, intensity, intensity, 1.0); glColor4f(intensity * red, intensity * green, intensity * blue, 1.0);
highlight := blockInfo^.Highlighted and item.CanBeEdited; highlight := blockInfo^.Highlighted and item.CanBeEdited;
@ -2362,7 +2395,7 @@ begin
begin begin
glBindTexture(GL_TEXTURE_2D, blockInfo^.HighRes.Texture); glBindTexture(GL_TEXTURE_2D, blockInfo^.HighRes.Texture);
if not highlight then if not highlight and (blockInfo^.WalkRestriction = wrNone) then
glEnable(GL_LIGHTING); glEnable(GL_LIGHTING);
glBegin(GL_QUADS); glBegin(GL_QUADS);
@ -2376,7 +2409,7 @@ begin
glTexCoord2i(1, 0); glVertex2iv(@blockInfo^.DrawQuad[1]); glTexCoord2i(1, 0); glVertex2iv(@blockInfo^.DrawQuad[1]);
glEnd; glEnd;
if not highlight then if not highlight and (blockInfo^.WalkRestriction = wrNone) then
glDisable(GL_LIGHTING); glDisable(GL_LIGHTING);
end else end else
begin begin
@ -2722,8 +2755,13 @@ end;
procedure TfrmMain.UpdateFilter; procedure TfrmMain.UpdateFilter;
var var
blockInfo: PBlockInfo; blockInfo: PBlockInfo;
tileData: TTiledata;
staticTileData: TStaticTileData;
lastSurface: PBlockInfo;
surfaceTop: Integer;
begin begin
blockInfo := nil; blockInfo := nil;
lastSurface := nil;
while FScreenBuffer.Iterate(blockInfo) do while FScreenBuffer.Iterate(blockInfo) do
begin begin
if blockInfo^.State in [ssNormal, ssFiltered] then if blockInfo^.State in [ssNormal, ssFiltered] then
@ -2739,8 +2777,56 @@ begin
begin begin
blockInfo^.State := ssFiltered; blockInfo^.State := ssFiltered;
end; end;
blockInfo^.WalkRestriction := wrNone;
if acWalkable.Checked then
begin
if blockInfo^.Item is TMapCell then
begin
tileData := ResMan.Tiledata.LandTiles[blockInfo^.Item.TileID];
if tdfImpassable in tileData.Flags then
begin
blockInfo^.WalkRestriction := wrCannotWalk;
lastSurface := nil;
end else
begin
blockInfo^.WalkRestriction := wrCanWalk;
lastSurface := blockInfo;
surfaceTop := blockInfo^.Item.Z;
end;
end else
begin
staticTileData := ResMan.Tiledata.StaticTiles[blockInfo^.Item.TileID];
if (lastSurface <> nil) and (lastSurface^.WalkRestriction = wrCanWalk) and
(lastSurface^.Item.X = blockInfo^.Item.X) and
(lastSurface^.Item.Y = blockInfo^.Item.Y) and ([tdfSurface,
tdfImpassable] * staticTileData.Flags <> []) then
begin
if (blockInfo^.Item.Z < surfaceTop + 16) and
((blockInfo^.Item.Z > lastSurface^.Item.Z + 2) or
not (tdfSurface in staticTileData.Flags)) then
lastSurface^.WalkRestriction := wrCannotWalk;
end;
if tdfSurface in staticTileData.Flags then
begin
if tdfImpassable in staticTileData.Flags then
begin
blockInfo^.WalkRestriction := wrCannotWalk;
lastSurface := nil;
end else
begin
blockInfo^.WalkRestriction := wrCanWalk;
lastSurface := blockInfo;
surfaceTop := blockInfo^.Item.Z + staticTileData.Height;
end;
end;
end;
end; //acWalkable.Checked
end; end;
end; end;
Include(FScreenBufferState, sbsFiltered); Include(FScreenBufferState, sbsFiltered);
if (FLightManager.LightLevel > 0) and not acFlat.Checked then if (FLightManager.LightLevel > 0) and not acFlat.Checked then

View File

@ -30,7 +30,7 @@ unit ULandscape;
interface interface
uses uses
SysUtils, Classes, math, UGenericIndex, UMap, UStatics, UWorldItem, UMulBlock, SysUtils, Classes, math, UGenericIndex, UMap, UStatics, UWorldItem,
UTileDataProvider, URadarMap, UTileDataProvider, URadarMap,
UCacheManager, ULinkedList, UBufferedStreams, UCacheManager, ULinkedList, UBufferedStreams,
UEnhancedMemoryStream, UPacketHandlers, UPackets, UNetState, UEnums; UEnhancedMemoryStream, UPacketHandlers, UPackets, UNetState, UEnums;
@ -207,6 +207,7 @@ begin
end; end;
block.Free; block.Free;
end; end;
FChanged := False;
end; end;
constructor TSeperatedStaticBlock.Create(AData: TStream; AIndex: TGenericIndex); constructor TSeperatedStaticBlock.Create(AData: TStream; AIndex: TGenericIndex);
@ -558,7 +559,7 @@ end;
procedure TLandscape.SaveBlock(AWorldBlock: TWorldBlock); procedure TLandscape.SaveBlock(AWorldBlock: TWorldBlock);
var var
i, j, size: Integer; size: Integer;
index: TGenericIndex; index: TGenericIndex;
begin begin
if AWorldBlock is TMapBlock then if AWorldBlock is TMapBlock then

View File

@ -42,7 +42,7 @@
<PackageName Value="lnetbase"/> <PackageName Value="lnetbase"/>
</Item2> </Item2>
</RequiredPackages> </RequiredPackages>
<Units Count="15"> <Units Count="16">
<Unit0> <Unit0>
<Filename Value="cedserver.lpr"/> <Filename Value="cedserver.lpr"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
@ -118,6 +118,11 @@
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
<UnitName Value="UStatics"/> <UnitName Value="UStatics"/>
</Unit14> </Unit14>
<Unit15>
<Filename Value="../UOLib/UMap.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="UMap"/>
</Unit15>
</Units> </Units>
</ProjectOptions> </ProjectOptions>
<CompilerOptions> <CompilerOptions>

View File

@ -1,76 +1,74 @@
(* (*
* CDDL HEADER START * CDDL HEADER START
* *
* The contents of this file are subject to the terms of the * The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only * Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance * (the "License"). You may not use this file except in compliance
* with the License. * with the License.
* *
* You can obtain a copy of the license at * You can obtain a copy of the license at
* http://www.opensource.org/licenses/cddl1.php. * http://www.opensource.org/licenses/cddl1.php.
* See the License for the specific language governing permissions * See the License for the specific language governing permissions
* and limitations under the License. * and limitations under the License.
* *
* When distributing Covered Code, include this CDDL HEADER in each * When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at * file and include the License file at
* http://www.opensource.org/licenses/cddl1.php. If applicable, * http://www.opensource.org/licenses/cddl1.php. If applicable,
* add the following below this CDDL HEADER, with the fields enclosed * add the following below this CDDL HEADER, with the fields enclosed
* by brackets "[]" replaced with your own identifying * information: * by brackets "[]" replaced with your own identifying * information:
* Portions Copyright [yyyy] [name of copyright owner] * Portions Copyright [yyyy] [name of copyright owner]
* *
* CDDL HEADER END * CDDL HEADER END
* *
* *
* Portions Copyright 2008 Andreas Schneider * Portions Copyright 2008 Andreas Schneider
*) *)
program cedserver; program cedserver;
{$mode objfpc}{$H+} {$mode objfpc}{$H+}
uses uses
{$IFDEF UNIX}{$IFDEF UseCThreads} {$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads, cthreads,
{$ENDIF}{$ENDIF} {$ENDIF}{$ENDIF}
SysUtils, Classes, lnetbase, UConfig, UCEDServer, URadarMap, SysUtils, UConfig, UCEDServer;
ULargeScaleOperations, UPackets, UAdminHandling, UClientHandling, ULandscape,
UPacketHandlers, URegions, UStatics, Logging; {$I version.inc}
{$I version.inc} {$IFDEF WINDOWS}{$R cedserver.rc}{$ENDIF}
{$IFDEF WINDOWS}{$R cedserver.rc}{$ENDIF} begin
Writeln('');
begin Writeln('CentrED Server Version ', ProductVersion);
Writeln(''); Writeln('Copyright ', Copyright);
Writeln('CentrED Server Version ', ProductVersion); //Writeln('================================');
Writeln('Copyright ', Copyright); Writeln('');
//Writeln('================================');
Writeln(''); {$IFDEF Windows}
if FileExists(ConfigFile) then
{$IFDEF Windows} Config := TConfig.Create(ConfigFile)
if FileExists(ConfigFile) then else
Config := TConfig.Create(ConfigFile) Config := TConfig.Init(ConfigFile);
else {$ELSE}
Config := TConfig.Init(ConfigFile); if ParamStr(1) = '--init' then
{$ELSE} Config := TConfig.Init(ConfigFile)
if ParamStr(1) = '--init' then else if FileExists(ConfigFile) then
Config := TConfig.Init(ConfigFile) Config := TConfig.Create(ConfigFile)
else if FileExists(ConfigFile) then else begin
Config := TConfig.Create(ConfigFile) Writeln('No valid config file was found. Use --init to create one.');
else begin Halt;
Writeln('No valid config file was found. Use --init to create one.'); end;
Halt; {$ENDIF}
end;
{$ENDIF} Writeln(TimeStamp, 'Initialization started');
Randomize;
Writeln(TimeStamp, 'Initialization started'); CEDServerInstance := TCEDServer.Create;
Randomize; Writeln(TimeStamp, 'Initialization done');
CEDServerInstance := TCEDServer.Create; CEDServerInstance.Run;
Writeln(TimeStamp, 'Initialization done'); Write(TimeStamp, 'Shutting down ... ');
CEDServerInstance.Run; FreeAndNil(CEDServerInstance);
Write(TimeStamp, 'Shutting down ... '); Config.Flush;
FreeAndNil(CEDServerInstance); FreeAndNil(Config);
Config.Flush; Writeln('done');
FreeAndNil(Config); end.
Writeln('done');
end.

View File

@ -173,8 +173,9 @@ begin
for iX := 0 to 7 do for iX := 0 to 7 do
Cells[iY * 8 + iX] := TMapCell.Create(Self, buffer, AX * 8 + iX, AY * 8 + iY); Cells[iY * 8 + iX] := TMapCell.Create(Self, buffer, AX * 8 + iX, AY * 8 + iY);
finally finally
if Assigned(buffer) then FreeAndNil(buffer); buffer.Free;
end; end;
FChanged := False;
end; end;
constructor TMapBlock.Create(AData: TStream); constructor TMapBlock.Create(AData: TStream);

View File

@ -189,6 +189,7 @@ begin
FItems.Add(TStaticItem.Create(Self, block, AX, AY)); FItems.Add(TStaticItem.Create(Self, block, AX, AY));
block.Free; block.Free;
end; end;
FChanged := False;
end; end;
constructor TStaticBlock.Create(AData: TStream; AIndex: TGenericIndex); constructor TStaticBlock.Create(AData: TStream; AIndex: TGenericIndex);