This commit is contained in:
1 parent
f1b253e842
commit
039dcaa381
3 files changed
+300
-1
No files matched your search
@@ -0,0 +1,297 @@
|
||||
unit KM_ResInterpolation;
|
||||
{$I KaM_Remake.inc}
|
||||
interface
|
||||
uses
|
||||
Classes, SysUtils, Math,
|
||||
KM_Defaults, KM_Points, KM_ResTypes, KM_ResMapElements, KM_ResHouses;
|
||||
|
||||
const
|
||||
INTERP_LEVEL = 8;
|
||||
|
||||
type
|
||||
TKMInterpolation = array[1..30, 0..INTERP_LEVEL-1] of Integer;
|
||||
TKMUnitActionInterp = array[UNIT_MIN..UNIT_MAX, UNIT_ACT_MIN..UNIT_ACT_MAX, dirN..dirNW] of TKMInterpolation;
|
||||
TKMSerfCarryInterp = array[WARE_MIN..WARE_MAX, dirN..dirNW] of TKMInterpolation;
|
||||
TKMUnitThoughtInterp = array[TKMUnitThought] of TKMInterpolation;
|
||||
TKMTreeInterp = array[0..OBJECTS_CNT] of TKMInterpolation;
|
||||
TKMHouseInterp = array[HOUSE_MIN..HOUSE_MAX, TKMHouseActionType] of TKMInterpolation;
|
||||
TKMBeastInterp = array[1..3,1..5,1..3] of TKMInterpolation;
|
||||
|
||||
TKMResInterpolation = class
|
||||
private
|
||||
fUnitActions: TKMUnitActionInterp;
|
||||
fSerfCarry: TKMSerfCarryInterp;
|
||||
fUnitThoughts: TKMUnitThoughtInterp;
|
||||
fTrees: TKMTreeInterp;
|
||||
fHouses: TKMHouseInterp;
|
||||
fBeasts: TKMBeastInterp;
|
||||
fInterpolationDataEligible: Boolean;
|
||||
public
|
||||
procedure LoadFromFile(const FileName: string);
|
||||
|
||||
function UnitAction(aUnit: TKMUnitType; aAct: TKMUnitActionType; aDir: TKMDirection; aStep: Integer; aStepFrac: Single): Integer;
|
||||
function UnitActionByPercent(aUnit: TKMUnitType; aAct: TKMUnitActionType; aDir: TKMDirection; aPercent: Single): Integer;
|
||||
function SerfCarry(aWare: TKMWareType; aDir: TKMDirection; aStep: Integer; aStepFrac: Single): Integer;
|
||||
function UnitThought(aTh: TKMUnitThought; aStep: Integer; aStepFrac: Single): Integer;
|
||||
function Tree(aObject: Integer; aStep: Integer; aStepFrac: Single; aLoop: Boolean): Integer;
|
||||
function House(aHT: TKMHouseType; aAct: TKMHouseActionType; aStep: Integer; aStepFrac: Single): Integer;
|
||||
function Beast(aHT: TKMHouseType; BeastId, BeastAge, aStep: Integer; aStepFrac: Single): Integer;
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
uses
|
||||
KM_CommonClasses, KM_Resource, KM_CommonTypes, KM_Pics, KM_ResUnits, KM_GameSettings,
|
||||
KaMResourceInput;
|
||||
|
||||
|
||||
type
|
||||
EInterpolationDataFormatError = class(Exception);
|
||||
|
||||
TInterpolationStaging = record
|
||||
UnitActions: TKMUnitActionInterp;
|
||||
SerfCarry: TKMSerfCarryInterp;
|
||||
UnitThoughts: TKMUnitThoughtInterp;
|
||||
Trees: TKMTreeInterp;
|
||||
Houses: TKMHouseInterp;
|
||||
Beasts: TKMBeastInterp;
|
||||
end;
|
||||
PInterpolationStaging = ^TInterpolationStaging;
|
||||
|
||||
|
||||
procedure CheckInterpolationMarker(aStream: TKMemoryStreamBinary; const aExpected: string);
|
||||
var
|
||||
markerLength: Word;
|
||||
markerBytes: array[0..13] of Byte;
|
||||
i: Integer;
|
||||
begin
|
||||
aStream.ReadBuffer(markerLength, SizeOf(Word));
|
||||
if markerLength <> Length(aExpected) then
|
||||
raise EInterpolationDataFormatError.Create('Invalid interpolation data marker');
|
||||
|
||||
aStream.ReadBuffer(markerBytes[0], markerLength);
|
||||
for i := 1 to Length(aExpected) do
|
||||
if markerBytes[i - 1] <> Ord(aExpected[i]) then
|
||||
raise EInterpolationDataFormatError.Create('Invalid interpolation data marker');
|
||||
end;
|
||||
|
||||
|
||||
{ TKMResInterpolation }
|
||||
procedure TKMResInterpolation.LoadFromFile(const FileName: string);
|
||||
var
|
||||
S: TKMemoryStreamBinary;
|
||||
stagingPtr: PInterpolationStaging;
|
||||
effectiveReference: string;
|
||||
begin
|
||||
fInterpolationDataEligible := False;
|
||||
|
||||
if FileName = ExeDir + 'data' + PathDelim + 'defines' + PathDelim + 'interp.dat' then
|
||||
effectiveReference := KaMResolvePackagedResource('data/defines/interp.dat')
|
||||
else
|
||||
effectiveReference := FileName;
|
||||
|
||||
S := TKMemoryStreamBinary.Create;
|
||||
try
|
||||
S.LoadFromFile(effectiveReference);
|
||||
New(stagingPtr);
|
||||
try
|
||||
CheckInterpolationMarker(S, 'UnitAction');
|
||||
S.ReadBuffer(stagingPtr^.UnitActions, SizeOf(TKMUnitActionInterp));
|
||||
|
||||
CheckInterpolationMarker(S, 'SerfCarry ');
|
||||
S.ReadBuffer(stagingPtr^.SerfCarry, SizeOf(TKMSerfCarryInterp));
|
||||
|
||||
CheckInterpolationMarker(S, 'UnitThoughts ');
|
||||
S.ReadBuffer(stagingPtr^.UnitThoughts, SizeOf(TKMUnitThoughtInterp));
|
||||
|
||||
CheckInterpolationMarker(S, 'Trees ');
|
||||
S.ReadBuffer(stagingPtr^.Trees, SizeOf(TKMTreeInterp));
|
||||
|
||||
CheckInterpolationMarker(S, 'Houses');
|
||||
S.ReadBuffer(stagingPtr^.Houses, SizeOf(TKMHouseInterp));
|
||||
|
||||
CheckInterpolationMarker(S, 'Beasts');
|
||||
S.ReadBuffer(stagingPtr^.Beasts, SizeOf(TKMBeastInterp));
|
||||
|
||||
System.Move(stagingPtr^.UnitActions, fUnitActions, SizeOf(TKMUnitActionInterp));
|
||||
System.Move(stagingPtr^.SerfCarry, fSerfCarry, SizeOf(TKMSerfCarryInterp));
|
||||
System.Move(stagingPtr^.UnitThoughts, fUnitThoughts, SizeOf(TKMUnitThoughtInterp));
|
||||
System.Move(stagingPtr^.Trees, fTrees, SizeOf(TKMTreeInterp));
|
||||
System.Move(stagingPtr^.Houses, fHouses, SizeOf(TKMHouseInterp));
|
||||
System.Move(stagingPtr^.Beasts, fBeasts, SizeOf(TKMBeastInterp));
|
||||
fInterpolationDataEligible := True;
|
||||
finally
|
||||
Dispose(stagingPtr);
|
||||
end;
|
||||
finally
|
||||
S.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function TKMResInterpolation.UnitAction(aUnit: TKMUnitType; aAct: TKMUnitActionType; aDir: TKMDirection; aStep: Integer;
|
||||
aStepFrac: Single): Integer;
|
||||
var
|
||||
A: TKMAnimLoop;
|
||||
step, subStep, baseFrame, candidate: Integer;
|
||||
begin
|
||||
A := gRes.Units[aUnit].UnitAnim[aAct, aDir];
|
||||
|
||||
step := aStep mod Byte(A.Count) + 1;
|
||||
subStep := EnsureRange(Floor(INTERP_LEVEL*aStepFrac), 0, INTERP_LEVEL-1);
|
||||
baseFrame := A.Step[step] + 1;
|
||||
|
||||
if not fInterpolationDataEligible then
|
||||
Exit(baseFrame);
|
||||
if not gGameSettings.GFX.InterpolatedAnimations then
|
||||
Exit(baseFrame);
|
||||
|
||||
candidate := fUnitActions[aUnit, aAct, aDir, step, subStep];
|
||||
if candidate <= 0 then Exit(baseFrame);
|
||||
if candidate > gRes.Sprites[rxUnits].RXData.Count then Exit(baseFrame);
|
||||
if gRes.Sprites[rxUnits].RXData.Size[candidate].X = 0 then Exit(baseFrame);
|
||||
Result := candidate;
|
||||
end;
|
||||
|
||||
|
||||
function TKMResInterpolation.UnitActionByPercent(aUnit: TKMUnitType; aAct: TKMUnitActionType; aDir: TKMDirection; aPercent: Single): Integer;
|
||||
var
|
||||
count: Integer;
|
||||
fracStep: Single;
|
||||
begin
|
||||
count := gRes.Units[aUnit].UnitAnim[aAct, aDir].Count;
|
||||
fracStep := Min(aPercent, 1.0) * (count-1);
|
||||
Result := UnitAction(aUnit, aAct, aDir, Trunc(fracStep), Frac(fracStep));
|
||||
end;
|
||||
|
||||
|
||||
function TKMResInterpolation.UnitThought(aTh: TKMUnitThought; aStep: Integer; aStepFrac: Single): Integer;
|
||||
var
|
||||
animCount, step, subStep: Integer;
|
||||
baseFrame, candidate: Integer;
|
||||
begin
|
||||
animCount := UNIT_THOUGHT_BOUNDS[aTh, 2] - UNIT_THOUGHT_BOUNDS[aTh, 1];
|
||||
step := aStep mod Byte(animCount) + 1;
|
||||
subStep := EnsureRange(Floor(INTERP_LEVEL*aStepFrac), 0, INTERP_LEVEL-1);
|
||||
baseFrame := UNIT_THOUGHT_BOUNDS[aTh, 2] + 1 - step;
|
||||
|
||||
if not fInterpolationDataEligible then
|
||||
Exit(baseFrame);
|
||||
if not gGameSettings.GFX.InterpolatedAnimations then
|
||||
Exit(baseFrame);
|
||||
|
||||
candidate := fUnitThoughts[aTh, step, subStep];
|
||||
if candidate <= 0 then Exit(baseFrame);
|
||||
if candidate > gRes.Sprites[rxUnits].RXData.Count then Exit(baseFrame);
|
||||
if gRes.Sprites[rxUnits].RXData.Size[candidate].X = 0 then Exit(baseFrame);
|
||||
Result := candidate;
|
||||
end;
|
||||
|
||||
|
||||
function TKMResInterpolation.SerfCarry(aWare: TKMWareType; aDir: TKMDirection; aStep: Integer; aStepFrac: Single): Integer;
|
||||
var
|
||||
A: TKMAnimLoop;
|
||||
step, subStep, baseFrame, candidate: Integer;
|
||||
begin
|
||||
A := gRes.Units.SerfCarry[aWare, aDir];
|
||||
|
||||
step := aStep mod Byte(A.Count) + 1;
|
||||
subStep := EnsureRange(Floor(INTERP_LEVEL*aStepFrac), 0, INTERP_LEVEL-1);
|
||||
baseFrame := A.Step[step] + 1;
|
||||
|
||||
if not fInterpolationDataEligible then
|
||||
Exit(baseFrame);
|
||||
if not gGameSettings.GFX.InterpolatedAnimations then
|
||||
Exit(baseFrame);
|
||||
|
||||
candidate := fSerfCarry[aWare, aDir, step, subStep];
|
||||
if candidate <= 0 then Exit(baseFrame);
|
||||
if candidate > gRes.Sprites[rxUnits].RXData.Count then Exit(baseFrame);
|
||||
if gRes.Sprites[rxUnits].RXData.Size[candidate].X = 0 then Exit(baseFrame);
|
||||
Result := candidate;
|
||||
end;
|
||||
|
||||
|
||||
function TKMResInterpolation.Tree(aObject, aStep: Integer; aStepFrac: Single; aLoop: Boolean): Integer;
|
||||
var
|
||||
A: TKMAnimLoop;
|
||||
step, subStep, baseFrame, candidate: Integer;
|
||||
begin
|
||||
A := gMapElements[aObject].Anim;
|
||||
|
||||
step := aStep mod Byte(A.Count) + 1;
|
||||
|
||||
if aLoop or (step < A.Count) then
|
||||
subStep := EnsureRange(Floor(INTERP_LEVEL*aStepFrac), 0, INTERP_LEVEL-1)
|
||||
else
|
||||
subStep := 0;
|
||||
baseFrame := A.Step[step] + 1;
|
||||
|
||||
if not fInterpolationDataEligible then
|
||||
Exit(baseFrame);
|
||||
if not gGameSettings.GFX.InterpolatedAnimations then
|
||||
Exit(baseFrame);
|
||||
|
||||
candidate := fTrees[aObject, step, subStep];
|
||||
if candidate <= 0 then Exit(baseFrame);
|
||||
if candidate > gRes.Sprites[rxTrees].RXData.Count then Exit(baseFrame);
|
||||
if gRes.Sprites[rxTrees].RXData.Size[candidate].X = 0 then Exit(baseFrame);
|
||||
Result := candidate;
|
||||
end;
|
||||
|
||||
|
||||
function TKMResInterpolation.House(aHT: TKMHouseType; aAct: TKMHouseActionType; aStep: Integer; aStepFrac: Single): Integer;
|
||||
var
|
||||
A: TKMAnimLoop;
|
||||
step, subStep, baseFrame, candidate: Integer;
|
||||
begin
|
||||
A := gRes.Houses[aHT].Anim[aAct];
|
||||
|
||||
step := aStep mod Byte(A.Count) + 1;
|
||||
subStep := EnsureRange(Floor(INTERP_LEVEL*aStepFrac), 0, INTERP_LEVEL-1);
|
||||
baseFrame := A.Step[step] + 1;
|
||||
|
||||
if not fInterpolationDataEligible then
|
||||
Exit(baseFrame);
|
||||
if not gGameSettings.GFX.InterpolatedAnimations then
|
||||
Exit(baseFrame);
|
||||
|
||||
candidate := fHouses[aHT, aAct, step, subStep];
|
||||
if candidate <= 0 then Exit(baseFrame);
|
||||
if candidate > gRes.Sprites[rxHouses].RXData.Count then Exit(baseFrame);
|
||||
if gRes.Sprites[rxHouses].RXData.Size[candidate].X = 0 then Exit(baseFrame);
|
||||
Result := candidate;
|
||||
end;
|
||||
|
||||
|
||||
function TKMResInterpolation.Beast(aHT: TKMHouseType; BeastId, BeastAge, aStep: Integer; aStepFrac: Single): Integer;
|
||||
var
|
||||
A: TKMAnimLoop;
|
||||
step, subStep, baseFrame, candidate: Integer;
|
||||
begin
|
||||
A := gRes.Houses.BeastAnim[aHT, BeastId, BeastAge];
|
||||
|
||||
step := aStep mod Byte(A.Count) + 1;
|
||||
subStep := EnsureRange(Floor(INTERP_LEVEL*aStepFrac), 0, INTERP_LEVEL-1);
|
||||
baseFrame := A.Step[step] + 1;
|
||||
|
||||
if not fInterpolationDataEligible then
|
||||
Exit(baseFrame);
|
||||
if not gGameSettings.GFX.InterpolatedAnimations then
|
||||
Exit(baseFrame);
|
||||
|
||||
case aHT of
|
||||
htSwine: candidate := fBeasts[1, BeastId, BeastAge, step, subStep];
|
||||
htStables: candidate := fBeasts[2, BeastId, BeastAge, step, subStep];
|
||||
htMarket: candidate := fBeasts[3, BeastId, 1, step, subStep];
|
||||
else candidate := -1;
|
||||
end;
|
||||
|
||||
if candidate <= 0 then Exit(baseFrame);
|
||||
if candidate > gRes.Sprites[rxHouses].RXData.Count then Exit(baseFrame);
|
||||
if gRes.Sprites[rxHouses].RXData.Size[candidate].X = 0 then Exit(baseFrame);
|
||||
Result := candidate;
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
Reference in new issue
Block a user