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 = 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.Create(aType: TKMHandEntityType; aUID: Integer; aOwner: TKMHandID); begin inherited Create(aType, aUID, aOwner); fPointerCount := 0; end; constructor TKMHandEntityPointer.Load(LoadStream: TKMemoryStream); begin inherited; LoadStream.Read(fPointerCount); end; function TKMHandEntityPointer.ObjToString(const aSeparator: String = '|'): String; begin Result := inherited ObjToString(aSeparator) + Format('%sPointerCnt = %d', [aSeparator, fPointerCount]); end; procedure TKMHandEntityPointer.Save(SaveStream: TKMemoryStream); begin inherited; SaveStream.Write(fPointerCount); end; // Returns self and adds on to the pointer counter function TKMHandEntityPointer.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.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.