sync: restore source from Google Drive
Sync changed files to Google Drive / sync (push) Successful in 1h45m13s
Sync changed files to Google Drive / sync (push) Successful in 1h45m13s
This commit is contained in:
1 parent
e2d8247e91
commit
7063d1b1c9
993 files changed
+949976
No files matched your search
+2319
File diff suppressed because it is too large.
Load diff
+1445
File diff suppressed because it is too large.
Load diff
+306
@@ -0,0 +1,306 @@
|
||||
unit KM_HandEntity;
|
||||
{$I KaM_Remake.inc}
|
||||
interface
|
||||
uses
|
||||
KM_Defaults, KM_Points, KM_CommonClasses, KM_HandTypes, KM_Entity, KromOGLUtils;
|
||||
|
||||
type
|
||||
// Common class for TKMUnit / TKMHouse / TKMUnitGroup
|
||||
// "class abstract" disallows anyone from creating an instance of it (can create only child classes)
|
||||
TKMHandEntity = class abstract(TKMEntity)
|
||||
private
|
||||
fType: TKMHandEntityType;
|
||||
fOwner: TKMHandID;
|
||||
fAllowAllyToSelect: Boolean; // Allow ally to select entity
|
||||
function GetOwner: TKMHandID; inline;
|
||||
function GetType: TKMHandEntityType;
|
||||
protected
|
||||
function GetPositionForDisplayF: TKMPointF; virtual; abstract;
|
||||
|
||||
procedure SetOwner(const aOwner: TKMHandID); virtual;
|
||||
function GetAllowAllyToSelect: Boolean; virtual;
|
||||
procedure SetAllowAllyToSelect(aAllow: Boolean); virtual;
|
||||
|
||||
function GetIsSelectable: Boolean; virtual; abstract;
|
||||
public
|
||||
constructor Create(aType: TKMHandEntityType; aUID: Integer; aOwner: TKMHandID);
|
||||
constructor Load(LoadStream: TKMemoryStream); override;
|
||||
procedure Save(SaveStream: TKMemoryStream); override;
|
||||
|
||||
property EntityType: TKMHandEntityType read GetType;
|
||||
property Owner: TKMHandID read GetOwner write SetOwner;
|
||||
|
||||
property PositionForDisplayF: TKMPointF read GetPositionForDisplayF;
|
||||
|
||||
property AllowAllyToSelect: Boolean read GetAllowAllyToSelect write SetAllowAllyToSelect;
|
||||
|
||||
property IsSelectable: Boolean read GetIsSelectable;
|
||||
|
||||
function IsUnit: Boolean;
|
||||
function IsGroup: Boolean;
|
||||
function IsHouse: Boolean;
|
||||
|
||||
function ObjToStringBasic(const aSeparator: String = '|'): String;
|
||||
function ObjToString(const aSeparator: String = '|'): String; override;
|
||||
function ObjToStringShort(const aSeparator: String = '|'): String; override;
|
||||
end;
|
||||
|
||||
TKMHandEntityPointer<T> = class abstract(TKMHandEntity)
|
||||
private
|
||||
fPointerCount: Cardinal;
|
||||
protected
|
||||
function GetInstance: T; virtual; abstract;
|
||||
public
|
||||
constructor Create(aType: TKMHandEntityType; aUID: Integer; aOwner: TKMHandID);
|
||||
constructor Load(LoadStream: TKMemoryStream); override;
|
||||
procedure Save(SaveStream: TKMemoryStream); override;
|
||||
|
||||
function GetPointer: T; //Returns self and adds one to the pointer counter
|
||||
procedure ReleasePointer; //Decreases the pointer counter
|
||||
property PointerCount: Cardinal read fPointerCount;
|
||||
|
||||
function ObjToString(const aSeparator: String = '|'): String; override;
|
||||
end;
|
||||
|
||||
TKMHighlightEntity = record
|
||||
Entity: TKMHandEntity;
|
||||
Color: TColor4;
|
||||
constructor New(aEntity: TKMHandEntity); overload;
|
||||
constructor New(aEntity: TKMHandEntity; aColor: TColor4); overload;
|
||||
|
||||
procedure SetEntity(aEntity: TKMHandEntity);
|
||||
procedure SetColor(aColor: TColor4);
|
||||
|
||||
function IsSet: Boolean;
|
||||
procedure Reset;
|
||||
end;
|
||||
|
||||
const
|
||||
DEFAULT_HIGHLIGHT_COL = icCyan;
|
||||
|
||||
|
||||
implementation
|
||||
uses
|
||||
SysUtils, KM_GameParams,
|
||||
KM_CommonExceptions;
|
||||
|
||||
|
||||
{ TKMHandEntity }
|
||||
constructor TKMHandEntity.Create(aType: TKMHandEntityType; aUID: Integer; aOwner: TKMHandID);
|
||||
begin
|
||||
inherited Create(aUID);
|
||||
|
||||
fType := aType;
|
||||
fOwner := aOwner;
|
||||
fAllowAllyToSelect := False; // Entity view for allies is blocked by default
|
||||
end;
|
||||
|
||||
|
||||
constructor TKMHandEntity.Load(LoadStream: TKMemoryStream);
|
||||
begin
|
||||
inherited;
|
||||
|
||||
LoadStream.Read(fType, SizeOf(fType));
|
||||
LoadStream.Read(fOwner, SizeOf(fOwner));
|
||||
LoadStream.Read(fAllowAllyToSelect);
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMHandEntity.Save(SaveStream: TKMemoryStream);
|
||||
begin
|
||||
inherited;
|
||||
|
||||
SaveStream.Write(fType, SizeOf(fType));
|
||||
SaveStream.Write(fOwner, SizeOf(fOwner));
|
||||
SaveStream.Write(fAllowAllyToSelect);
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMHandEntity.SetAllowAllyToSelect(aAllow: Boolean);
|
||||
begin
|
||||
fAllowAllyToSelect := aAllow;
|
||||
end;
|
||||
|
||||
|
||||
function TKMHandEntity.GetAllowAllyToSelect: Boolean;
|
||||
begin
|
||||
Result := ALLOW_SELECT_ALLIES and fAllowAllyToSelect;
|
||||
end;
|
||||
|
||||
|
||||
function TKMHandEntity.GetOwner: TKMHandID;
|
||||
begin
|
||||
if Self = nil then Exit(HAND_NONE);
|
||||
|
||||
Result := fOwner;
|
||||
end;
|
||||
|
||||
|
||||
function TKMHandEntity.GetType: TKMHandEntityType;
|
||||
begin
|
||||
if Self = nil then Exit(etNone);
|
||||
|
||||
Result := fType;
|
||||
end;
|
||||
|
||||
|
||||
function TKMHandEntity.IsUnit: Boolean;
|
||||
begin
|
||||
if Self = nil then Exit(False);
|
||||
|
||||
Result := fType = etUnit;
|
||||
end;
|
||||
|
||||
|
||||
function TKMHandEntity.IsGroup: Boolean;
|
||||
begin
|
||||
if Self = nil then Exit(False);
|
||||
|
||||
Result := fType = etGroup;
|
||||
end;
|
||||
|
||||
|
||||
function TKMHandEntity.IsHouse: Boolean;
|
||||
begin
|
||||
if Self = nil then Exit(False);
|
||||
|
||||
Result := fType = etHouse;
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMHandEntity.SetOwner(const aOwner: TKMHandID);
|
||||
begin
|
||||
fOwner := aOwner;
|
||||
end;
|
||||
|
||||
|
||||
function TKMHandEntity.ObjToStringBasic(const aSeparator: String = '|'): String;
|
||||
begin
|
||||
Result := Format('UID = %d%sPos = %s', [UID, aSeparator, PositionForDisplayF.ToString]);
|
||||
end;
|
||||
|
||||
|
||||
function TKMHandEntity.ObjToStringShort(const aSeparator: String = '|'): String;
|
||||
begin
|
||||
Result := inherited ObjToStringShort(aSeparator) +
|
||||
Format('%sPos = %s', [aSeparator, PositionForDisplayF.ToString]);
|
||||
end;
|
||||
|
||||
|
||||
function TKMHandEntity.ObjToString(const aSeparator: String = '|'): String;
|
||||
begin
|
||||
Result := inherited ObjToString(aSeparator) +
|
||||
Format('%sOwner = %d%sPositionF = %s%sAllowAllyToSel = %s',
|
||||
[aSeparator,
|
||||
Owner, aSeparator,
|
||||
PositionForDisplayF.ToString, aSeparator,
|
||||
BoolToStr(AllowAllyToSelect, True)]);
|
||||
end;
|
||||
|
||||
|
||||
{ TKMHandEntityPointer }
|
||||
constructor TKMHandEntityPointer<T>.Create(aType: TKMHandEntityType; aUID: Integer; aOwner: TKMHandID);
|
||||
begin
|
||||
inherited Create(aType, aUID, aOwner);
|
||||
|
||||
fPointerCount := 0;
|
||||
end;
|
||||
|
||||
|
||||
constructor TKMHandEntityPointer<T>.Load(LoadStream: TKMemoryStream);
|
||||
begin
|
||||
inherited;
|
||||
|
||||
LoadStream.Read(fPointerCount);
|
||||
end;
|
||||
|
||||
|
||||
function TKMHandEntityPointer<T>.ObjToString(const aSeparator: String = '|'): String;
|
||||
begin
|
||||
Result := inherited ObjToString(aSeparator) + Format('%sPointerCnt = %d', [aSeparator, fPointerCount]);
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMHandEntityPointer<T>.Save(SaveStream: TKMemoryStream);
|
||||
begin
|
||||
inherited;
|
||||
|
||||
SaveStream.Write(fPointerCount);
|
||||
end;
|
||||
|
||||
|
||||
// Returns self and adds on to the pointer counter
|
||||
function TKMHandEntityPointer<T>.GetPointer: T;
|
||||
begin
|
||||
Assert(gGameParams.AllowPointerOperations, 'GetPointer is not allowed outside of game tick update procedure, it could cause game desync');
|
||||
|
||||
Inc(fPointerCount);
|
||||
Result := GetInstance;
|
||||
end;
|
||||
|
||||
|
||||
{Decreases the pointer counter}
|
||||
//Should be used only by gHands for clarity sake
|
||||
procedure TKMHandEntityPointer<T>.ReleasePointer;
|
||||
var
|
||||
ErrorMsg: UnicodeString;
|
||||
begin
|
||||
Assert(gGameParams.AllowPointerOperations, 'ReleasePointer is not allowed outside of game tick update procedure, it could cause game desync');
|
||||
|
||||
if fPointerCount < 1 then
|
||||
begin
|
||||
ErrorMsg := 'Unit remove pointer for U: ';
|
||||
try
|
||||
ErrorMsg := ErrorMsg + ObjToStringShort(',');
|
||||
except
|
||||
on E: Exception do
|
||||
ErrorMsg := ErrorMsg + IntToStr(UID) + ' Pos = ' + PositionForDisplayF.ToString;
|
||||
end;
|
||||
raise ELocError.Create(ErrorMsg, KMPointRound(PositionForDisplayF));
|
||||
end;
|
||||
|
||||
Dec(fPointerCount);
|
||||
end;
|
||||
|
||||
|
||||
{ TKMHighlightEntity }
|
||||
constructor TKMHighlightEntity.New(aEntity: TKMHandEntity; aColor: TColor4);
|
||||
begin
|
||||
Entity := aEntity;
|
||||
Color := aColor;
|
||||
end;
|
||||
|
||||
|
||||
constructor TKMHighlightEntity.New(aEntity: TKMHandEntity);
|
||||
begin
|
||||
Entity := aEntity;
|
||||
Color := DEFAULT_HIGHLIGHT_COL;
|
||||
end;
|
||||
|
||||
|
||||
function TKMHighlightEntity.IsSet: Boolean;
|
||||
begin
|
||||
Result := Entity <> nil;
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMHighlightEntity.Reset;
|
||||
begin
|
||||
Entity := nil;
|
||||
Color := DEFAULT_HIGHLIGHT_COL;
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMHighlightEntity.SetColor(aColor: TColor4);
|
||||
begin
|
||||
Color := aColor;
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMHighlightEntity.SetEntity(aEntity: TKMHandEntity);
|
||||
begin
|
||||
Entity := aEntity;
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
@@ -0,0 +1,64 @@
|
||||
unit KM_HandEntityHelper;
|
||||
{$I KaM_Remake.inc}
|
||||
interface
|
||||
uses
|
||||
KM_HandEntity, KM_Units, KM_UnitWarrior, KM_UnitGroup, KM_Houses;
|
||||
|
||||
type
|
||||
TKMHandEntityHelper = class helper for TKMHandEntity
|
||||
function AsUnit: TKMUnit;
|
||||
function AsUnitWarrior: TKMUnitWarrior;
|
||||
function AsGroup: TKMUnitGroup;
|
||||
function AsHouse: TKMHouse;
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
|
||||
{ TKMHandEntityHelper }
|
||||
function TKMHandEntityHelper.AsGroup: TKMUnitGroup;
|
||||
begin
|
||||
if (Self = nil)
|
||||
or not IsGroup
|
||||
or not (Self is TKMUnitGroup) then
|
||||
Exit(nil);
|
||||
|
||||
Result := TKMUnitGroup(Self);
|
||||
end;
|
||||
|
||||
|
||||
function TKMHandEntityHelper.AsHouse: TKMHouse;
|
||||
begin
|
||||
if (Self = nil)
|
||||
or not IsHouse
|
||||
or not (Self is TKMHouse) then
|
||||
Exit(nil);
|
||||
|
||||
Result := TKMHouse(Self);
|
||||
end;
|
||||
|
||||
|
||||
function TKMHandEntityHelper.AsUnit: TKMUnit;
|
||||
begin
|
||||
if (Self = nil)
|
||||
or not IsUnit
|
||||
or not (Self is TKMUnit) then
|
||||
Exit(nil);
|
||||
|
||||
Result := TKMUnit(Self);
|
||||
end;
|
||||
|
||||
|
||||
function TKMHandEntityHelper.AsUnitWarrior: TKMUnitWarrior;
|
||||
begin
|
||||
if (Self = nil)
|
||||
or not IsUnit
|
||||
or not (Self is TKMUnitWarrior) then
|
||||
Exit(nil);
|
||||
|
||||
Result := TKMUnitWarrior(Self);
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
unit KM_HandLocks;
|
||||
{$I KaM_Remake.inc}
|
||||
interface
|
||||
uses
|
||||
KM_ResHouses,
|
||||
KM_CommonClasses, KM_Defaults,
|
||||
KM_ResTypes, KM_HandTypes;
|
||||
|
||||
|
||||
type
|
||||
TKMBoolHouseType = array [TKMHouseType] of Boolean;
|
||||
|
||||
// Permissions to build, trade and train
|
||||
TKMHandLocks = class
|
||||
private
|
||||
fHouseUnlocked: array [TKMHouseType] of Boolean; //If building requirements performed
|
||||
fUnitBlocked: array [TKMUnitType] of Boolean; //Allowance derived from mission script
|
||||
|
||||
fHandHouseLock: array [TKMHouseType] of TKMHandHouseLock;
|
||||
procedure UpdateReqDone(aType: TKMHouseType);
|
||||
|
||||
function GetHouseBlocked(aHouseType: TKMHouseType): Boolean;
|
||||
function GetHouseGranted(aHouseType: TKMHouseType): Boolean;
|
||||
function GetHandHouseLock(aHouseType: TKMHouseType): TKMHandHouseLock;
|
||||
procedure SetHandHouseLock(aHouseType: TKMHouseType; const aValue: TKMHandHouseLock);
|
||||
public
|
||||
AllowToTrade: array [WARE_MIN..WARE_MAX] of Boolean; //Allowance derived from mission script
|
||||
constructor Create;
|
||||
|
||||
property HouseBlocked[aHouseType: TKMHouseType]: Boolean read GetHouseBlocked;
|
||||
property HouseGranted[aHouseType: TKMHouseType]: Boolean read GetHouseGranted;
|
||||
property HouseLock[aHouseType: TKMHouseType]: TKMHandHouseLock read GetHandHouseLock write SetHandHouseLock;
|
||||
|
||||
procedure HouseCreated(aType: TKMHouseType);
|
||||
function HouseCanBuild(aType: TKMHouseType): Boolean;
|
||||
|
||||
procedure SetUnitBlocked(aIsBlocked: Boolean; aUnitType: TKMUnitType; aInTownHall: Boolean = False);
|
||||
function GetUnitBlocked(aUnitType: TKMUnitType; aInTownHall: Boolean = False): Boolean;
|
||||
|
||||
procedure Save(SaveStream: TKMemoryStream);
|
||||
procedure Load(LoadStream: TKMemoryStream);
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
uses
|
||||
KM_Resource;
|
||||
|
||||
|
||||
{ TKMHandLocks }
|
||||
constructor TKMHandLocks.Create;
|
||||
var
|
||||
W: TKMWareType;
|
||||
HT: TKMHouseType;
|
||||
begin
|
||||
inherited;
|
||||
|
||||
for W := WARE_MIN to WARE_MAX do
|
||||
AllowToTrade[W] := True;
|
||||
|
||||
//Release Store at the start of the game by default
|
||||
fHouseUnlocked[htStore] := True;
|
||||
|
||||
for HT := Low(TKMHouseType) to High(TKMHouseType) do
|
||||
fHandHouseLock[HT] := hlDefault;
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMHandLocks.UpdateReqDone(aType: TKMHouseType);
|
||||
var
|
||||
H: TKMHouseType;
|
||||
begin
|
||||
for H := HOUSE_MIN to HOUSE_MAX do
|
||||
if gRes.Houses[H].ReleasedBy = aType then
|
||||
fHouseUnlocked[H] := True;
|
||||
end;
|
||||
|
||||
|
||||
// New house, either built by player or created by mission script
|
||||
procedure TKMHandLocks.HouseCreated(aType: TKMHouseType);
|
||||
begin
|
||||
UpdateReqDone(aType);
|
||||
end;
|
||||
|
||||
|
||||
// Get effective permission
|
||||
function TKMHandLocks.HouseCanBuild(aType: TKMHouseType): Boolean;
|
||||
begin
|
||||
Result := False;
|
||||
case fHandHouseLock[aType] of
|
||||
hlDefault: Result := fHouseUnlocked[aType];
|
||||
hlBlocked: Result := False;
|
||||
hlGranted: Result := True;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function TKMHandLocks.GetHouseBlocked(aHouseType: TKMHouseType): Boolean;
|
||||
begin
|
||||
Result := fHandHouseLock[aHouseType] = hlBlocked;
|
||||
end;
|
||||
|
||||
|
||||
function TKMHandLocks.GetHouseGranted(aHouseType: TKMHouseType): Boolean;
|
||||
begin
|
||||
Result := fHandHouseLock[aHouseType] = hlGranted;
|
||||
end;
|
||||
|
||||
|
||||
function TKMHandLocks.GetHandHouseLock(aHouseType: TKMHouseType): TKMHandHouseLock;
|
||||
begin
|
||||
Result := fHandHouseLock[aHouseType];
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMHandLocks.SetHandHouseLock(aHouseType: TKMHouseType; const aValue: TKMHandHouseLock);
|
||||
begin
|
||||
Assert(aValue <> hlNone, 'Can''t set hlNone Hand House Lock');
|
||||
fHandHouseLock[aHouseType] := aValue;
|
||||
end;
|
||||
|
||||
|
||||
//procedure TKMHandLocks.SetHouseBlocked(aHouseType: TKMHouseType; const aValue: Boolean);
|
||||
//begin
|
||||
// if aValue then
|
||||
// fPlayerHouseLock[aHouseType] := phlBlocked
|
||||
// else
|
||||
// fPlayerHouseLock[aHouseType] := phlDefault;
|
||||
//end;
|
||||
//
|
||||
//
|
||||
//procedure TKMHandLocks.SetHouseGranted(aHouseType: TKMHouseType; const aValue: Boolean);
|
||||
//begin
|
||||
// fPlayerHouseLock[aHouseType] := phlGranted;
|
||||
//end;
|
||||
|
||||
|
||||
function TKMHandLocks.GetUnitBlocked(aUnitType: TKMUnitType; aInTownHall: Boolean = False): Boolean;
|
||||
begin
|
||||
Result := fUnitBlocked[aUnitType];
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMHandLocks.SetUnitBlocked(aIsBlocked: Boolean; aUnitType: TKMUnitType; aInTownHall: Boolean = False);
|
||||
begin
|
||||
fUnitBlocked[aUnitType] := aIsBlocked;
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMHandLocks.Save(SaveStream: TKMemoryStream);
|
||||
begin
|
||||
SaveStream.PlaceMarker('HandLocks');
|
||||
SaveStream.Write(fHandHouseLock, SizeOf(fHandHouseLock));
|
||||
SaveStream.Write(fUnitBlocked, SizeOf(fUnitBlocked));
|
||||
SaveStream.Write(AllowToTrade, SizeOf(AllowToTrade));
|
||||
SaveStream.Write(fHouseUnlocked, SizeOf(fHouseUnlocked));
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMHandLocks.Load(LoadStream: TKMemoryStream);
|
||||
begin
|
||||
LoadStream.CheckMarker('HandLocks');
|
||||
LoadStream.Read(fHandHouseLock, SizeOf(fHandHouseLock));
|
||||
LoadStream.Read(fUnitBlocked, SizeOf(fUnitBlocked));
|
||||
LoadStream.Read(AllowToTrade, SizeOf(AllowToTrade));
|
||||
LoadStream.Read(fHouseUnlocked, SizeOf(fHouseUnlocked));
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
+3126
File diff suppressed because it is too large.
Load diff
+430
@@ -0,0 +1,430 @@
|
||||
unit KM_HandSpectator;
|
||||
{$I KaM_Remake.inc}
|
||||
interface
|
||||
uses
|
||||
KM_Hand, KM_FogOfWar,
|
||||
KM_CommonClasses, KM_Defaults,
|
||||
KM_HandEntity;
|
||||
|
||||
|
||||
type
|
||||
//Wrap to let choose FOW player sees (and let 1 player control several towns
|
||||
//or several players to control 1 town in future)
|
||||
TKMSpectator = class
|
||||
private
|
||||
fHandIndex: TKMHandID;
|
||||
fHighlight: TKMHighlightEntity; //Unit/House/Group that is shown highlighted to draw players attention
|
||||
fHighlightEnd: Cardinal; //Highlight has a short time to live
|
||||
fHighlightDebug: TKMHighlightEntity; //Unit/House/Group that is shown highlighted to draw players attention
|
||||
fHighlightDebug2: TKMHighlightEntity;
|
||||
fHighlightDebug3: TKMHighlightEntity;
|
||||
fHighlightRoute: TKMHighlightEntity;
|
||||
fSelected: TKMHandEntity;
|
||||
fLastSelected: TKMHandEntity;
|
||||
fIsSelectedMyObj: Boolean; // We can select ally's house/unit
|
||||
fLastSpecSelectedObjUID: array [0..MAX_HANDS-1] of Integer; //UIDs of last selected objects for each hand while spectating/watching replay
|
||||
fFOWIndex: TKMHandID; //Unit/House/Group selected by player and shown in UI
|
||||
fFogOfWarOpen: TKMFogOfWarOpen; //Stub for MapEd
|
||||
fFogOfWar: TKMFogOfWarCommon; //Pointer to current FOW view, updated by UpdateFogOfWarIndex
|
||||
procedure SetHighlight(Value: TKMHandEntity);
|
||||
procedure SetHighlightEntity(Value: TKMHighlightEntity);
|
||||
procedure SetSelected(Value: TKMHandEntity);
|
||||
function GetSelected: TKMHandEntity;
|
||||
procedure SetHandIndex(const Value: TKMHandID);
|
||||
procedure SetFOWIndex(const Value: TKMHandID);
|
||||
procedure UpdateFogOfWarIndex;
|
||||
function GetLastSpecSelectedEntity: TKMHandEntity;
|
||||
procedure UpdateNewSelected(var aNewSelected: TKMHandEntity); overload;
|
||||
function GetSelectedHandID: TKMHandID;
|
||||
function GetHighlight: TKMHandEntity;
|
||||
public
|
||||
constructor Create(aHandIndex: TKMHandID);
|
||||
destructor Destroy; override;
|
||||
property Highlight: TKMHandEntity read GetHighlight write SetHighlight;
|
||||
property HighlightEntity: TKMHighlightEntity read fHighlight write SetHighlightEntity;
|
||||
property HighlightDebug: TKMHighlightEntity read fHighlightDebug write fHighlightDebug;
|
||||
property HighlightDebug2: TKMHighlightEntity read fHighlightDebug2 write fHighlightDebug2;
|
||||
property HighlightDebug3: TKMHighlightEntity read fHighlightDebug3 write fHighlightDebug3;
|
||||
property HighlightRoute: TKMHighlightEntity read fHighlightRoute write fHighlightRoute;
|
||||
property Selected: TKMHandEntity read GetSelected write SetSelected;
|
||||
property LastSelected: TKMHandEntity read fLastSelected;
|
||||
procedure NilLastSelected;
|
||||
property IsSelectedMyObj: Boolean read fIsSelectedMyObj write fIsSelectedMyObj;
|
||||
function Hand: TKMHand;
|
||||
property HandID: TKMHandID read fHandIndex write SetHandIndex;
|
||||
property SelectedHandID: TKMHandID read GetSelectedHandID;
|
||||
property FOWIndex: TKMHandID read fFOWIndex write SetFOWIndex;
|
||||
property FogOfWar: TKMFogOfWarCommon read fFogOfWar;
|
||||
property LastSpecSelectedEntity: TKMHandEntity read GetLastSpecSelectedEntity;
|
||||
function HitTestCursor(aIncludeAnimals: Boolean = False): TKMHandEntity;
|
||||
function HitTestCursorWGroup(aIncludeAnimals: Boolean = False): TKMHandEntity;
|
||||
procedure UpdateNewSelected; overload;
|
||||
procedure UpdateSelect(aCheckUnderCursor: Boolean = True; aAllowAnimals: Boolean = False);
|
||||
procedure Load(LoadStream: TKMemoryStream);
|
||||
procedure Save(SaveStream: TKMemoryStream);
|
||||
procedure UpdateState(aTick: Cardinal);
|
||||
|
||||
procedure ResetHighlightDebug;
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
uses
|
||||
KM_Entity, KM_HandEntityHelper,
|
||||
KM_GameParams, KM_Cursor,
|
||||
KM_HandsCollection, KM_HandTypes,
|
||||
KM_Units, KM_UnitGroup, KM_UnitWarrior, KM_Houses,
|
||||
KM_CommonUtils,
|
||||
KM_GameTypes,
|
||||
KM_Main;
|
||||
|
||||
|
||||
{ TKMSpectator }
|
||||
constructor TKMSpectator.Create(aHandIndex: TKMHandID);
|
||||
var
|
||||
I: Integer;
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
fHandIndex := aHandIndex;
|
||||
|
||||
fHighlight.Color := DEFAULT_HIGHLIGHT_COL;
|
||||
fHighlightDebug.Color := DEFAULT_HIGHLIGHT_COL;
|
||||
fHighlightDebug2.Color := DEFAULT_HIGHLIGHT_COL;
|
||||
fHighlightRoute.Color := DEFAULT_HIGHLIGHT_COL;
|
||||
|
||||
//Stub that always returns REVEALED
|
||||
fFogOfWarOpen := TKMFogOfWarOpen.Create;
|
||||
UpdateFogOfWarIndex;
|
||||
|
||||
for I := Low(fLastSpecSelectedObjUID) to High(fLastSpecSelectedObjUID) do
|
||||
fLastSpecSelectedObjUID[I] := UID_NONE;
|
||||
end;
|
||||
|
||||
|
||||
destructor TKMSpectator.Destroy;
|
||||
begin
|
||||
Highlight := nil;
|
||||
Selected := nil;
|
||||
fFogOfWarOpen.Free;
|
||||
inherited;
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMSpectator.UpdateFogOfWarIndex;
|
||||
begin
|
||||
//fGame = nil in Tests
|
||||
if (gGameParams <> nil) and (gGameParams.Mode in [gmMultiSpectate, gmMapEd, gmReplaySingle, gmReplayMulti]) then
|
||||
if FOWIndex = -1 then
|
||||
fFogOfWar := fFogOfWarOpen
|
||||
else
|
||||
fFogOfWar := gHands[FOWIndex].FogOfWar
|
||||
else
|
||||
fFogOfWar := gHands[HandID].FogOfWar;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
function TKMSpectator.GetHighlight: TKMHandEntity;
|
||||
begin
|
||||
Result := fHighlight.Entity;
|
||||
end;
|
||||
|
||||
|
||||
//Return last seleted object for current chosen hand
|
||||
function TKMSpectator.GetLastSpecSelectedEntity: TKMHandEntity;
|
||||
var
|
||||
entity: TKMHandEntity;
|
||||
UID: Integer;
|
||||
begin
|
||||
Result := nil;
|
||||
UID := fLastSpecSelectedObjUID[fHandIndex];
|
||||
if UID <> UID_NONE then
|
||||
begin
|
||||
entity := gHands.GetObjectByUID(UID);
|
||||
if (entity <> nil) and entity.IsSelectable then
|
||||
Result := entity
|
||||
else
|
||||
fLastSpecSelectedObjUID[fHandIndex] := UID_NONE; // Last selected object is not valid anymore, so reset UID
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function TKMSpectator.GetSelected: TKMHandEntity;
|
||||
begin
|
||||
if Self = nil then Exit(nil);
|
||||
|
||||
Result := fSelected;
|
||||
end;
|
||||
|
||||
|
||||
function TKMSpectator.GetSelectedHandID: TKMHandID;
|
||||
begin
|
||||
Result := fHandIndex;
|
||||
if Self = nil then Exit;
|
||||
|
||||
if fSelected <> nil then
|
||||
Result := fSelected.Owner;
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMSpectator.Load(LoadStream: TKMemoryStream);
|
||||
begin
|
||||
LoadStream.CheckMarker('Spectator');
|
||||
LoadStream.Read(fHandIndex);
|
||||
UpdateFogOfWarIndex;
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMSpectator.Save(SaveStream: TKMemoryStream);
|
||||
begin
|
||||
SaveStream.PlaceMarker('Spectator');
|
||||
SaveStream.Write(fHandIndex);
|
||||
end;
|
||||
|
||||
|
||||
function TKMSpectator.Hand: TKMHand;
|
||||
begin
|
||||
if Self = nil then Exit(nil);
|
||||
|
||||
Result := gHands[fHandIndex];
|
||||
end;
|
||||
|
||||
|
||||
//Test if there's object below that player can interact with
|
||||
//Units and Houses, not Groups
|
||||
function TKMSpectator.HitTestCursor(aIncludeAnimals: Boolean = False): TKMHandEntity;
|
||||
begin
|
||||
Result := gHands.GetUnitByUID(gCursor.ObjectUID);
|
||||
if ((Result is TKMUnit) and TKMUnit(Result).IsDeadOrDying)
|
||||
or ((Result is TKMUnitAnimal) and not aIncludeAnimals) then
|
||||
Result := nil;
|
||||
|
||||
//If there's no unit try pick a house on the Cell below
|
||||
if Result = nil then
|
||||
begin
|
||||
Result := gHands.HousesHitTest(gCursor.Cell.X, gCursor.Cell.Y);
|
||||
if (Result is TKMHouse) and TKMHouse(Result).IsDestroyed then
|
||||
Result := nil;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
//Test if there's object below that player can interact with
|
||||
//Units and Houses and Groups
|
||||
function TKMSpectator.HitTestCursorWGroup(aIncludeAnimals: Boolean = False): TKMHandEntity;
|
||||
var
|
||||
G: TKMUnitGroup;
|
||||
begin
|
||||
Result := HitTestCursor(aIncludeAnimals);
|
||||
|
||||
if Result is TKMUnitWarrior then
|
||||
begin
|
||||
if gGameParams.Mode in [gmMultiSpectate, gmMapEd, gmReplaySingle, gmReplayMulti] then
|
||||
G := gHands.GetGroupByMember(TKMUnitWarrior(Result))
|
||||
else
|
||||
G := gHands[fHandIndex].UnitGroups.GetGroupByMember(TKMUnitWarrior(Result));
|
||||
|
||||
//Warrior might not be assigned to a group while walking out of the Barracks
|
||||
if G <> nil then
|
||||
Result := G
|
||||
else
|
||||
Result := nil; //Can't select warriors until they have been assigned a group
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMSpectator.UpdateNewSelected;
|
||||
var
|
||||
tmpSelected: TKMHandEntity;
|
||||
begin
|
||||
//We do not want to change Selected object actually, just update fIsSelectedMyObj field is good enough
|
||||
tmpSelected := Selected;
|
||||
UpdateNewSelected(tmpSelected);
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMSpectator.UpdateNewSelected(var aNewSelected: TKMHandEntity);
|
||||
begin
|
||||
if gGameParams.Mode in [gmMultiSpectate, gmMapEd, gmReplaySingle, gmReplayMulti] then
|
||||
Exit;
|
||||
|
||||
if aNewSelected.Owner <> -1 then
|
||||
begin
|
||||
if aNewSelected.Owner <> fHandIndex then // check if we selected our unit/ally's or enemy's
|
||||
begin
|
||||
if ALLOW_SELECT_ALL
|
||||
or (aNewSelected.AllowAllyToSelect and (Hand.Alliances[aNewSelected.Owner] = atAlly)) then
|
||||
fIsSelectedMyObj := False
|
||||
else
|
||||
aNewSelected := nil;
|
||||
end else
|
||||
fIsSelectedMyObj := True;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
//Select anything player CAN select below cursor
|
||||
procedure TKMSpectator.UpdateSelect(aCheckUnderCursor: Boolean = True; aAllowAnimals: Boolean = False);
|
||||
var
|
||||
newSelected: TKMHandEntity;
|
||||
UID: Integer;
|
||||
begin
|
||||
newSelected := nil;
|
||||
|
||||
if aCheckUnderCursor then
|
||||
begin
|
||||
newSelected := gHands.GetUnitByUID(gCursor.ObjectUID);
|
||||
|
||||
//In-game player can select only own and ally Units
|
||||
UpdateNewSelected(newSelected);
|
||||
|
||||
//Don't allow the player to select dead units
|
||||
if ((newSelected is TKMUnit) and TKMUnit(newSelected).IsDeadOrDying)
|
||||
or (not aAllowAnimals and (newSelected is TKMUnitAnimal)) then //...or animals
|
||||
newSelected := nil;
|
||||
|
||||
//If Id belongs to some Warrior, try to select his group instead
|
||||
if newSelected is TKMUnitWarrior then
|
||||
begin
|
||||
newSelected := gHands.GetGroupByMember(TKMUnitWarrior(newSelected));
|
||||
UpdateNewSelected(newSelected);
|
||||
end;
|
||||
|
||||
//Update selected groups selected unit
|
||||
if newSelected is TKMUnitGroup then
|
||||
TKMUnitGroup(newSelected).SelectedUnit := TKMUnitGroup(newSelected).MemberByUID(gCursor.ObjectUID);
|
||||
|
||||
//If there's no unit try pick a house on the Cell below
|
||||
if newSelected = nil then
|
||||
begin
|
||||
newSelected := gHands.HousesHitTest(gCursor.Cell.X, gCursor.Cell.Y);
|
||||
|
||||
//In-game player can select only own and ally Units
|
||||
if (newSelected is TKMHouse) then
|
||||
UpdateNewSelected(newSelected);
|
||||
|
||||
//Don't allow the player to select destroyed houses
|
||||
if (newSelected is TKMHouse) and TKMHouse(newSelected).IsDestroyed then
|
||||
newSelected := nil;
|
||||
end;
|
||||
|
||||
//Don't clear the old selection unless we found something new
|
||||
if newSelected <> nil then
|
||||
Selected := newSelected;
|
||||
end
|
||||
else
|
||||
begin
|
||||
newSelected := Selected; //To avoid nil-ing of fSelected
|
||||
//In-game player can select only own and ally Units
|
||||
UpdateNewSelected(newSelected); //Updates fIsSelectedMyObj
|
||||
end;
|
||||
|
||||
// In a replay we want in-game statistics (and other things) to be shown for the owner of the last select object
|
||||
if gGameParams.IsReplayOrSpectate then
|
||||
begin
|
||||
UID := UID_NONE;
|
||||
if Selected is TKMHouse then
|
||||
begin
|
||||
HandID := TKMHouse(Selected).Owner;
|
||||
UID := TKMHouse(Selected).UID;
|
||||
end;
|
||||
if Selected is TKMUnit then
|
||||
begin
|
||||
HandID := TKMUnit(Selected).Owner;
|
||||
UID := TKMUnit(Selected).UID;
|
||||
end;
|
||||
if Selected is TKMUnitGroup then
|
||||
begin
|
||||
HandID := TKMUnitGroup(Selected).Owner;
|
||||
UID := TKMUnitGroup(Selected).UID;
|
||||
end;
|
||||
if (Selected <> nil) and (UID <> UID_NONE) then
|
||||
fLastSpecSelectedObjUID[fHandIndex] := UID;
|
||||
end;
|
||||
|
||||
// Update F11 Debug panel UIDs
|
||||
if gMain <> nil then
|
||||
gMain.FormMain.SetEntitySelected(Selected.UID, Selected.AsGroup.SelectedUnit.UID);
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMSpectator.SetFOWIndex(const Value: TKMHandID);
|
||||
begin
|
||||
fFOWIndex := Value;
|
||||
UpdateFogOfWarIndex;
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMSpectator.SetHighlight(Value: TKMHandEntity);
|
||||
begin
|
||||
//We don't increase PointersCount of object because of savegames identicality over MP
|
||||
//Objects report on their destruction and set it to nil
|
||||
fHighlight.Entity := Value;
|
||||
fHighlight.Color := DEFAULT_HIGHLIGHT_COL;
|
||||
fHighlightEnd := TimeGet + 3000;
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMSpectator.SetHighlightEntity(Value: TKMHighlightEntity);
|
||||
begin
|
||||
fHighlight := Value;
|
||||
SetHighlight(Value.Entity);
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMSpectator.SetHandIndex(const Value: TKMHandID);
|
||||
begin
|
||||
Assert(MULTIPLAYER_CHEATS or (gGameParams.Mode <> gmMulti));
|
||||
fHandIndex := Value;
|
||||
|
||||
if not (gGameParams.Mode in [gmMultiSpectate, gmMapEd, gmReplaySingle, gmReplayMulti]) then
|
||||
Selected := nil;
|
||||
|
||||
UpdateFogOfWarIndex;
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMSpectator.SetSelected(Value: TKMHandEntity);
|
||||
begin
|
||||
if Self = nil then Exit;
|
||||
|
||||
fLastSelected := fSelected;
|
||||
|
||||
//We don't increase PointersCount of object because of savegames identicality over MP
|
||||
//Objects report on their destruction and set it to nil
|
||||
fSelected := Value;
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMSpectator.NilLastSelected;
|
||||
begin
|
||||
fLastSelected := nil;
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMSpectator.ResetHighlightDebug;
|
||||
begin
|
||||
if Self = nil then Exit;
|
||||
|
||||
fHighlightDebug.Reset;
|
||||
fHighlightDebug2.Reset;
|
||||
fHighlightDebug3.Reset;
|
||||
fHighlightRoute.Reset;
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMSpectator.UpdateState;
|
||||
begin
|
||||
//Hide the highlight
|
||||
if TimeGet > fHighlightEnd then
|
||||
fHighlight.Reset;
|
||||
//Units should be deselected when they go inside a house
|
||||
if Selected is TKMUnit then
|
||||
if not TKMUnit(Selected).Visible then
|
||||
Selected := nil;
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
|
||||
+1074
File diff suppressed because it is too large.
Load diff
+36
@@ -0,0 +1,36 @@
|
||||
unit KM_HandTypes;
|
||||
interface
|
||||
uses
|
||||
KM_ResFonts;
|
||||
|
||||
type
|
||||
TKMHandType = (
|
||||
hndHuman,
|
||||
hndComputer
|
||||
);
|
||||
|
||||
TKMHandEntityType = (etNone, etUnit, etGroup, etHouse);
|
||||
|
||||
//* House lock state
|
||||
TKMHandHouseLock = (
|
||||
hlNone,
|
||||
hlDefault,
|
||||
hlBlocked, // Never allowed
|
||||
hlGranted // Always allowed
|
||||
);
|
||||
|
||||
TKMOverlayTextSettings = record
|
||||
WordWrap: Boolean;
|
||||
Font: TKMFont;
|
||||
end;
|
||||
|
||||
const
|
||||
HAND_NONE = -1; //No player
|
||||
HAND_ANIMAL = -2; //animals
|
||||
|
||||
const
|
||||
DELIVERY_NO_ID = -1;
|
||||
|
||||
implementation
|
||||
|
||||
end.
|
||||
+1392
File diff suppressed because it is too large.
Load diff
+143
@@ -0,0 +1,143 @@
|
||||
unit KM_WareDistribution;
|
||||
{$I KaM_Remake.inc}
|
||||
interface
|
||||
uses
|
||||
KM_ResTypes,
|
||||
KM_CommonClasses;
|
||||
|
||||
|
||||
const
|
||||
// These have been adjusted slightly from the old KaM defaults.
|
||||
// The number means how many items should be in houses input max, and also affects delivery priority.
|
||||
DISTRIBUTION_DEFAULTS: array [1..4, 1..4] of Byte = (
|
||||
(5, 5, 0, 0),
|
||||
(3, 5, 3, 3),
|
||||
(2, 5, 0, 0),
|
||||
(4, 5, 3, 0)
|
||||
);
|
||||
|
||||
|
||||
type
|
||||
TKMWareDistribution = class
|
||||
private
|
||||
fWareDistribution: array [1..4, 1..4] of Byte;
|
||||
procedure SetWareDistribution(aWare: TKMWareType; aHouse: TKMHouseType; aValue: Byte);
|
||||
function GetWareDistribution(aWare: TKMWareType; aHouse: TKMHouseType): Byte;
|
||||
public
|
||||
constructor Create;
|
||||
property WareDistribution[aWare: TKMWareType; aHouse: TKMHouseType]: Byte read GetWareDistribution write SetWareDistribution; default;
|
||||
procedure LoadFromStr(aString: String);
|
||||
function PackToStr: String;
|
||||
|
||||
procedure Save(SaveStream: TKMemoryStream);
|
||||
procedure Load(LoadStream: TKMemoryStream);
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
uses
|
||||
SysUtils, Math;
|
||||
|
||||
{TKMWareDistribution}
|
||||
constructor TKMWareDistribution.Create;
|
||||
var
|
||||
I, K: Integer;
|
||||
begin
|
||||
for I := 1 to 4 do
|
||||
for K := 1 to 4 do
|
||||
fWareDistribution[I, K] := DISTRIBUTION_DEFAULTS[I, K]; // Load default ratios
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMWareDistribution.SetWareDistribution(aWare: TKMWareType; aHouse: TKMHouseType; aValue: Byte);
|
||||
begin
|
||||
case aWare of
|
||||
wtIron: if aHouse = htWeaponSmithy then fWareDistribution[1,1] := aValue else
|
||||
if aHouse = htArmorSmithy then fWareDistribution[1,2] := aValue;
|
||||
wtCoal: if aHouse = htIronSmithy then fWareDistribution[2,1] := aValue else
|
||||
if aHouse = htMetallurgists then fWareDistribution[2,2] := aValue else
|
||||
if aHouse = htWeaponSmithy then fWareDistribution[2,3] := aValue else
|
||||
if aHouse = htArmorSmithy then fWareDistribution[2,4] := aValue;
|
||||
wtTimber: if aHouse = htArmorWorkshop then fWareDistribution[3,1] := aValue else
|
||||
if aHouse = htWeaponWorkshop then fWareDistribution[3,2] := aValue;
|
||||
wtCorn: if aHouse = htMill then fWareDistribution[4,1] := aValue else
|
||||
if aHouse = htSwine then fWareDistribution[4,2] := aValue else
|
||||
if aHouse = htStables then fWareDistribution[4,3] := aValue;
|
||||
else raise Exception.Create('Unexpected resource at SetWareDistribution');
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function TKMWareDistribution.GetWareDistribution(aWare: TKMWareType; aHouse: TKMHouseType): Byte;
|
||||
begin
|
||||
Result := 5; //Default should be 5, for house/resource combinations that don't have a setting (on a side note this should be the only place the resourse limit is defined)
|
||||
case aWare of
|
||||
wtIron: if aHouse = htWeaponSmithy then Result := fWareDistribution[1,1] else
|
||||
if aHouse = htArmorSmithy then Result := fWareDistribution[1,2];
|
||||
wtCoal: if aHouse = htIronSmithy then Result := fWareDistribution[2,1] else
|
||||
if aHouse = htMetallurgists then Result := fWareDistribution[2,2] else
|
||||
if aHouse = htWeaponSmithy then Result := fWareDistribution[2,3] else
|
||||
if aHouse = htArmorSmithy then Result := fWareDistribution[2,4];
|
||||
wtTimber: if aHouse = htArmorWorkshop then Result := fWareDistribution[3,1] else
|
||||
if aHouse = htWeaponWorkshop then Result := fWareDistribution[3,2];
|
||||
wtCorn: if aHouse = htMill then Result := fWareDistribution[4,1] else
|
||||
if aHouse = htSwine then Result := fWareDistribution[4,2] else
|
||||
if aHouse = htStables then Result := fWareDistribution[4,3];
|
||||
else //Handled in 1st row to avoid repeating in if .. else lines
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMWareDistribution.LoadFromStr(aString: String);
|
||||
|
||||
function IsValid: Boolean;
|
||||
var
|
||||
I: Integer;
|
||||
begin
|
||||
Result := Length(aString) = 16; // Ware distribution string length should be equal to 16
|
||||
if Result then
|
||||
for I := 1 to 16 do
|
||||
Result := Result and InRange(Ord(aString[I]), 48, 53); //In ware distribution string only digits from 0 to 5 are allowed'
|
||||
end;
|
||||
|
||||
var
|
||||
I, J: Integer;
|
||||
begin
|
||||
aString := Trim(aString); // Trim possible spaces
|
||||
//Distribution format is string of 16 digits, each digit should be between 0 and 5
|
||||
if IsValid then
|
||||
for I := 1 to 16 do
|
||||
fWareDistribution[1+((I-1) div 4), 1+((I-1) mod 4)] := StrToInt(aString[I])
|
||||
else
|
||||
for I := 1 to 4 do
|
||||
for J := 1 to 4 do
|
||||
fWareDistribution[I, J] := DISTRIBUTION_DEFAULTS[I, J];
|
||||
end;
|
||||
|
||||
|
||||
function TKMWareDistribution.PackToStr: String;
|
||||
var
|
||||
I, J: Integer;
|
||||
begin
|
||||
Result := '';
|
||||
for I := 1 to 4 do
|
||||
for J := 1 to 4 do
|
||||
Result := Result + IntToStr(fWareDistribution[I, J]);
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMWareDistribution.Save(SaveStream: TKMemoryStream);
|
||||
begin
|
||||
SaveStream.PlaceMarker('WareDistribution');
|
||||
SaveStream.Write(fWareDistribution, SizeOf(fWareDistribution));
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMWareDistribution.Load(LoadStream: TKMemoryStream);
|
||||
begin
|
||||
LoadStream.CheckMarker('WareDistribution');
|
||||
LoadStream.Read(fWareDistribution, SizeOf(fWareDistribution));
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
Reference in new issue
Block a user