691 lines
28 KiB
ObjectPascal
691 lines
28 KiB
ObjectPascal
unit KM_UnitWorkPlan;
|
|
{$I KaM_Remake.inc}
|
|
interface
|
|
uses
|
|
KM_Defaults, KM_CommonClasses, KM_Points, KM_TerrainTypes, KM_Units,
|
|
KM_ResTypes;
|
|
|
|
|
|
const
|
|
MAX_WORKPLAN = 24;
|
|
|
|
type
|
|
TKMWorkPlanAllowedEvent = function(aProduct: TKMWareType): Boolean of object;
|
|
|
|
TKMUnitWorkPlan = class
|
|
private
|
|
fHome: TKMHouseType;
|
|
fIssued: Boolean;
|
|
function ChooseTree(const aLoc, aAvoid: TKMPoint; aRadius: Integer; aPlantAct: TKMPlantAct; aUnit: TKMUnit;
|
|
out Tree: TKMPointDir; out PlantAct: TKMPlantAct): Boolean;
|
|
procedure Clear;
|
|
procedure WalkStyle(const aLoc2: TKMPointDir; aTo, aWork: TKMUnitActionType; aCycles, aDelay: Byte; aFrom: TKMUnitActionType; aScript: TKMGatheringScript);
|
|
procedure SubActAdd(aAct: TKMHouseActionType; aCycles: Single);
|
|
procedure ResourcePlan(Res1: TKMWareType; Qty1: Byte; Res2: TKMWareType; Qty2: Byte; Prod1: TKMWareType; Prod2: TKMWareType = wtNone);
|
|
public
|
|
HasToWalk: Boolean;
|
|
Loc: TKMPoint;
|
|
ActionWalkTo: TKMUnitActionType;
|
|
ActionWorkType: TKMUnitActionType;
|
|
WorkCyc: Integer;
|
|
WorkDir: TKMDirection;
|
|
GatheringScript: TKMGatheringScript;
|
|
AfterWorkDelay: Integer;
|
|
ActionWalkFrom: TKMUnitActionType;
|
|
Resource1: TKMWareType; Count1: Byte;
|
|
Resource2: TKMWareType; Count2: Byte;
|
|
ActCount: Byte;
|
|
HouseAct: array [0..MAX_WORKPLAN - 1] of record
|
|
Act: TKMHouseActionType;
|
|
TimeToWork: Word;
|
|
end;
|
|
Product1: TKMWareType; ProdCount1: Byte;
|
|
Product2: TKMWareType; ProdCount2: Byte;
|
|
AfterWorkIdle: Integer;
|
|
ResourceDepleted: Boolean;
|
|
public
|
|
procedure FindPlan(aUnit: TKMUnit; aHome: TKMHouseType; aProduct: TKMWareType;
|
|
aLoc: TKMPoint; aPlantAct: TKMPlantAct);
|
|
function FindDifferentResource(aUnit: TKMUnit; aLoc: TKMPoint; const aAvoidLoc: TKMPoint): Boolean;
|
|
property IsIssued: Boolean read fIssued;
|
|
procedure Save(SaveStream: TKMemoryStream);
|
|
procedure Load(LoadStream: TKMemoryStream);
|
|
end;
|
|
|
|
|
|
implementation
|
|
uses
|
|
SysUtils,
|
|
KM_ResUnits, KM_Houses, KM_HouseWoodcutters,
|
|
KM_ResHouses,
|
|
KM_Terrain,
|
|
KM_Resource, KM_CommonUtils;
|
|
|
|
|
|
{Houses are only a place on map, they should not issue or perform tasks (except Training)
|
|
Everything should be issued by units
|
|
Where to go, which walking style, what to do on location, for how long
|
|
How to go back in case success, incase bad luck
|
|
What to take from supply, how much, take2, much2
|
|
What to do, Work/Cycles, What resource to add to Output, how much
|
|
E.g. CoalMine: Miner arrives at home and Idles for 5sec, then takes a work task (depending on ResOut count)
|
|
Since Loc is 0,0 he immidietely skips to Phase X where he switches house to Work1 (and self busy for same framecount)
|
|
Then Work2 and Work3 same way. Then adds resource to out and everything to Idle for 5sec.
|
|
E.g. Farmer arrives at home and Idles for 5sec, then takes a work task (depending on ResOut count, HouseType and Need to sow corn)
|
|
...... then switches house to Work1 (and self busy for same framecount)
|
|
Then Work2 and Work3 same way. Then adds resource to out and everything to Idle for 5sec.}
|
|
procedure TKMUnitWorkPlan.Clear;
|
|
begin
|
|
fIssued := False;
|
|
HasToWalk := False;
|
|
Loc := KMPOINT_ZERO;
|
|
ActionWalkTo := uaWalk;
|
|
ActionWorkType := uaWork;
|
|
WorkCyc := 0;
|
|
WorkDir := dirNA;
|
|
GatheringScript := gsNone;
|
|
AfterWorkDelay := 0;
|
|
ActionWalkFrom := uaWalk;
|
|
Resource1 := wtNone;
|
|
Count1 := 0;
|
|
Resource2 := wtNone;
|
|
Count2 := 0;
|
|
ActCount := 0;
|
|
Product1 := wtNone;
|
|
ProdCount1 := 0;
|
|
Product2 := wtNone;
|
|
ProdCount2 := 0;
|
|
AfterWorkIdle := 0;
|
|
ResourceDepleted := False;
|
|
end;
|
|
|
|
|
|
procedure TKMUnitWorkPlan.WalkStyle(const aLoc2: TKMPointDir; aTo, aWork: TKMUnitActionType; aCycles,aDelay: Byte; aFrom: TKMUnitActionType; aScript: TKMGatheringScript);
|
|
begin
|
|
Loc := aLoc2.Loc;
|
|
HasToWalk := True;
|
|
ActionWalkTo := aTo;
|
|
ActionWorkType := aWork;
|
|
WorkCyc := aCycles;
|
|
AfterWorkDelay := aDelay;
|
|
GatheringScript := aScript;
|
|
ActionWalkFrom := aFrom;
|
|
WorkDir := aLoc2.Dir;
|
|
end;
|
|
|
|
|
|
procedure TKMUnitWorkPlan.SubActAdd(aAct: TKMHouseActionType; aCycles: Single);
|
|
begin
|
|
HouseAct[ActCount].Act := aAct;
|
|
HouseAct[ActCount].TimeToWork := Round(gRes.Houses[fHome].Anim[aAct].Count * aCycles);
|
|
Inc(ActCount);
|
|
end;
|
|
|
|
|
|
procedure TKMUnitWorkPlan.ResourcePlan(Res1: TKMWareType; Qty1: Byte; Res2: TKMWareType; Qty2: Byte; Prod1: TKMWareType; Prod2: TKMWareType = wtNone);
|
|
begin
|
|
Resource1 := Res1; Count1 := Qty1;
|
|
Resource2 := Res2; Count2 := Qty2;
|
|
Product1 := Prod1; ProdCount1 := gRes.Houses[fHome].ResProductionX;
|
|
if Prod2=wtNone then exit;
|
|
Product2 := Prod2; ProdCount2 := gRes.Houses[fHome].ResProductionX;
|
|
end;
|
|
|
|
|
|
function TKMUnitWorkPlan.FindDifferentResource(aUnit: TKMUnit; aLoc: TKMPoint; const aAvoidLoc: TKMPoint): Boolean;
|
|
var
|
|
NewLoc: TKMPointDir;
|
|
PlantAct: TKMPlantAct;
|
|
Found: boolean;
|
|
HW: TKMHouseWoodcutters;
|
|
begin
|
|
if (GatheringScript = gsWoodCutterCut) or (GatheringScript = gsWoodCutterPlant) then
|
|
begin
|
|
HW := TKMHouseWoodcutters(aUnit.Home);
|
|
HW.ValidateFlagPoint; //Validate Cutting point. It will be set to a valid one if needed.
|
|
|
|
if HW.IsFlagPointSet then
|
|
aLoc := HW.FlagPoint;
|
|
end;
|
|
|
|
with gTerrain do
|
|
case GatheringScript of
|
|
gsStoneCutter: Found := FindStone(aLoc, gRes.Units[aUnit.UnitType].MiningRange, aAvoidLoc, False, NewLoc);
|
|
gsFarmerSow: Found := FindCornField(aLoc, gRes.Units[aUnit.UnitType].MiningRange, aAvoidLoc, taPlant, PlantAct, NewLoc);
|
|
gsFarmerCorn: begin
|
|
Found := FindCornField(aLoc, gRes.Units[aUnit.UnitType].MiningRange, aAvoidLoc, taAny, PlantAct, NewLoc);
|
|
if PlantAct = taPlant then
|
|
begin
|
|
GatheringScript := gsFarmerSow; //Switch to sowing corn rather than cutting
|
|
ActionWalkFrom := uaWalkTool; //Carry our scythe back (without the corn) as the player saw us take it out
|
|
ActionWorkType := uaWork1;
|
|
WorkCyc := 10;
|
|
Product1 := wtNone; //Don't produce corn
|
|
ProdCount1 := 0;
|
|
end;
|
|
end;
|
|
gsFarmerWine: begin
|
|
Found := FindWineField(aLoc, gRes.Units[aUnit.UnitType].MiningRange, aAvoidLoc, NewLoc);
|
|
NewLoc.Dir := dirN; //The animation for picking grapes is only defined for facing north
|
|
end;
|
|
gsFisherCatch: Found := FindFishWater(aLoc, gRes.Units[aUnit.UnitType].MiningRange, aAvoidLoc, False, NewLoc);
|
|
gsWoodCutterCut: Found := ChooseTree(aLoc, KMGetVertexTile(aAvoidLoc, WorkDir), gRes.Units[aUnit.UnitType].MiningRange, taCut, aUnit, NewLoc, PlantAct);
|
|
gsWoodCutterPlant: Found := ChooseTree(aLoc, aAvoidLoc, gRes.Units[aUnit.UnitType].MiningRange, taPlant, aUnit, NewLoc, PlantAct);
|
|
else
|
|
Found := False; //Can find a new resource for an unknown gathering script, so return with False
|
|
end;
|
|
|
|
if Found then
|
|
begin
|
|
Loc := NewLoc.Loc;
|
|
WorkDir := NewLoc.Dir;
|
|
Result := True;
|
|
end
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
|
|
function TKMUnitWorkPlan.ChooseTree(const aLoc, aAvoid: TKMPoint; aRadius: Integer; aPlantAct: TKMPlantAct; aUnit: TKMUnit; out Tree: TKMPointDir; out PlantAct: TKMPlantAct): Boolean;
|
|
var
|
|
I: Integer;
|
|
T: TKMPoint;
|
|
treeList: TKMPointDirCenteredList;
|
|
bestToPlant, secondBestToPlant: TKMPointCenteredList;
|
|
begin
|
|
treeList := TKMPointDirCenteredList.Create(aLoc);
|
|
bestToPlant := TKMPointCenteredList.Create(aLoc);
|
|
secondBestToPlant := TKMPointCenteredList.Create(aLoc);
|
|
|
|
gTerrain.FindTree(aLoc, aRadius, aAvoid, aPlantAct, treeList, bestToPlant, secondBestToPlant);
|
|
|
|
//Convert taAny to either a Tree or a Spot
|
|
if (aPlantAct in [taCut, taAny])
|
|
and ((treeList.Count > 8) //Always chop the tree if there are many
|
|
or (bestToPlant.Count + secondBestToPlant.Count = 0)
|
|
or ((treeList.Count > 0) and (KaMRandom({$IFDEF DBG_RNG_SPY}'TKMUnitWorkPlan.ChooseTree'{$ENDIF}) < treeList.Count / (treeList.Count + (bestToPlant.Count + secondBestToPlant.Count)/15)))
|
|
) then
|
|
begin
|
|
PlantAct := taCut;
|
|
Result := treeList.GetWeightedRandom(Tree);
|
|
end
|
|
else
|
|
begin
|
|
PlantAct := taPlant;
|
|
//First try stumps list
|
|
for I := bestToPlant.Count - 1 downto 0 do
|
|
if not TKMUnitCitizen(aUnit).CanWorkAt(bestToPlant[I], gsWoodCutterPlant) then
|
|
bestToPlant.Delete(I);
|
|
Result := bestToPlant.GetWeightedRandom(T);
|
|
//Trees must always be planted facing north as that is the direction the animation uses
|
|
if Result then
|
|
Tree := KMPointDir(T, dirN)
|
|
else
|
|
begin
|
|
//Try empty places list
|
|
for I := secondBestToPlant.Count - 1 downto 0 do
|
|
if not TKMUnitCitizen(aUnit).CanWorkAt(secondBestToPlant[I], gsWoodCutterPlant) then
|
|
secondBestToPlant.Delete(I);
|
|
Result := secondBestToPlant.GetWeightedRandom(T);
|
|
//Trees must always be planted facing north as that is the direction the animation uses
|
|
if Result then
|
|
Tree := KMPointDir(T, dirN);
|
|
end;
|
|
end;
|
|
|
|
treeList.Free;
|
|
bestToPlant.Free;
|
|
secondBestToPlant.Free;
|
|
end;
|
|
|
|
|
|
procedure TKMUnitWorkPlan.FindPlan(aUnit: TKMUnit; aHome: TKMHouseType; aProduct: TKMWareType; aLoc: TKMPoint; aPlantAct: TKMPlantAct);
|
|
var
|
|
I: Integer;
|
|
tmp: TKMPointDir;
|
|
plantAct: TKMPlantAct;
|
|
HW: TKMHouseWoodcutters;
|
|
begin
|
|
Clear;
|
|
|
|
fHome := aHome;
|
|
AfterWorkIdle := gRes.Houses[aHome].WorkerRest * 10;
|
|
|
|
//Now we need to fill only specific properties
|
|
case aUnit.UnitType of
|
|
utWoodcutter: if aHome = htWoodcutters then
|
|
begin
|
|
HW := TKMHouseWoodcutters(aUnit.Home);
|
|
HW.ValidateFlagPoint; //Validate Cutting point. It will be set to a valid one if needed.
|
|
|
|
if HW.IsFlagPointSet then
|
|
aLoc := HW.FlagPoint;
|
|
|
|
fIssued := ChooseTree(aLoc, KMPOINT_ZERO, gRes.Units[aUnit.UnitType].MiningRange, aPlantAct, aUnit, tmp, plantAct);
|
|
if fIssued then
|
|
begin
|
|
case plantAct of
|
|
taCut: begin //Cutting uses DirNW,DirSW,DirSE,DirNE (1,3,5,7) of uaWork
|
|
ResourcePlan(wtNone,0,wtNone,0,wtTrunk);
|
|
WalkStyle(tmp, uaWalkBooty,uaWork,15,20,uaWalkTool2,gsWoodCutterCut);
|
|
end;
|
|
taPlant: begin //Planting uses DirN (0) of uaWork
|
|
WalkStyle(tmp, uaWalkTool,uaWork,12,0,uaWalk,gsWoodCutterPlant);
|
|
end;
|
|
else fIssued := False;
|
|
end;
|
|
end
|
|
else
|
|
case plantAct of
|
|
taCut: if not gTerrain.CanFindTree(aLoc, gRes.Units[aUnit.UnitType].MiningRange) then
|
|
ResourceDepleted := True; //No more trees to cut
|
|
taPlant: if HW.WoodcutterMode = wmPlant then
|
|
ResourceDepleted := True; //No place for trees to plant
|
|
end;
|
|
end;
|
|
utMiner: if aHome = htCoalMine then
|
|
begin
|
|
fIssued := gTerrain.FindOre(aLoc, wtCoal, tmp.Loc);
|
|
if fIssued then
|
|
begin
|
|
Loc := tmp.Loc;
|
|
ResourcePlan(wtNone,0,wtNone,0,wtCoal);
|
|
GatheringScript := gsCoalMiner;
|
|
SubActAdd(haWork1,1);
|
|
SubActAdd(haWork2,23);
|
|
SubActAdd(haWork5,1);
|
|
end else
|
|
ResourceDepleted := True;
|
|
end else
|
|
if aHome = htIronMine then
|
|
begin
|
|
fIssued := gTerrain.FindOre(aLoc, wtIronOre, tmp.Loc);
|
|
if fIssued then
|
|
begin
|
|
Loc := tmp.Loc;
|
|
ResourcePlan(wtNone,0,wtNone,0,wtIronOre);
|
|
GatheringScript := gsIronMiner;
|
|
SubActAdd(haWork1,1);
|
|
SubActAdd(haWork2,24);
|
|
SubActAdd(haWork5,1);
|
|
end else
|
|
ResourceDepleted := True;
|
|
end else
|
|
if aHome = htGoldMine then
|
|
begin
|
|
fIssued := gTerrain.FindOre(aLoc, wtGoldOre, tmp.Loc);
|
|
if fIssued then
|
|
begin
|
|
Loc := tmp.Loc;
|
|
ResourcePlan(wtNone,0,wtNone,0,wtGoldOre);
|
|
GatheringScript := gsGoldMiner;
|
|
SubActAdd(haWork1,1);
|
|
SubActAdd(haWork2,24);
|
|
SubActAdd(haWork5,1);
|
|
end else
|
|
ResourceDepleted := True;
|
|
end;
|
|
utAnimalBreeder: if aHome = htSwine then
|
|
begin
|
|
ResourcePlan(wtCorn,1,wtNone,0,wtPig,wtSkin);
|
|
GatheringScript := gsSwineBreeder;
|
|
for I := 0 to 3 do
|
|
begin
|
|
SubActAdd(haWork2,1);
|
|
SubActAdd(haWork3,1);
|
|
end;
|
|
SubActAdd(haWork2,1);
|
|
fIssued := True;
|
|
end else
|
|
|
|
if aHome = htStables then
|
|
begin
|
|
ResourcePlan(wtCorn,1,wtNone,0,wtHorse);
|
|
GatheringScript := gsHorseBreeder;
|
|
SubActAdd(haWork1,1);
|
|
SubActAdd(haWork2,1);
|
|
SubActAdd(haWork3,1);
|
|
SubActAdd(haWork4,1);
|
|
SubActAdd(haWork5,1);
|
|
fIssued := True;
|
|
end;
|
|
utFarmer: if aHome = htFarm then
|
|
begin
|
|
fIssued := gTerrain.FindCornField(aLoc, gRes.Units[aUnit.UnitType].MiningRange, KMPOINT_ZERO, aPlantAct, plantAct, tmp);
|
|
if fIssued then
|
|
case plantAct of
|
|
taCut: begin
|
|
ResourcePlan(wtNone,0,wtNone,0,wtCorn);
|
|
WalkStyle(tmp, uaWalkTool,uaWork,6,0,uaWalkBooty,gsFarmerCorn);
|
|
end;
|
|
taPlant: WalkStyle(tmp, uaWalk,uaWork1,10,0,uaWalk,gsFarmerSow);
|
|
else fIssued := False;
|
|
end;
|
|
end else
|
|
|
|
if aHome = htVineyard then
|
|
begin
|
|
fIssued := gTerrain.FindWineField(aLoc, gRes.Units[aUnit.UnitType].MiningRange, KMPOINT_ZERO, tmp);
|
|
if fIssued then
|
|
begin
|
|
ResourcePlan(wtNone,0,wtNone,0,wtWine);
|
|
WalkStyle(KMPointDir(tmp.Loc,dirN), uaWalkTool2,uaWork2,5,0,uaWalkBooty2,gsFarmerWine); //The animation for picking grapes is only defined for facing north
|
|
SubActAdd(haWork1,1);
|
|
SubActAdd(haWork2,11);
|
|
SubActAdd(haWork5,1);
|
|
end;
|
|
end;
|
|
utCarpenter: if aHome = htSawmill then
|
|
begin
|
|
ResourcePlan(wtTrunk,1,wtNone,0,wtTimber);
|
|
SubActAdd(haWork1,1);
|
|
SubActAdd(haWork2,25);
|
|
SubActAdd(haWork5,1);
|
|
fIssued := True;
|
|
end else
|
|
|
|
if (aHome = htArmorWorkshop) and (aProduct = wtLeatherArmor) then
|
|
begin
|
|
ResourcePlan(wtLeather,1,wtNone,0,wtLeatherArmor);
|
|
for I := 0 to 3 do
|
|
begin
|
|
SubActAdd(haWork2,1);
|
|
SubActAdd(haWork3,1);
|
|
SubActAdd(haWork4,1);
|
|
end;
|
|
SubActAdd(haWork2,0.25);
|
|
fIssued := True;
|
|
end else
|
|
|
|
if (aHome = htArmorWorkshop) and (aProduct = wtWoodenShield) then
|
|
begin
|
|
ResourcePlan(wtTimber,1,wtNone,0,wtWoodenShield);
|
|
for I := 0 to 3 do
|
|
begin
|
|
SubActAdd(haWork2,1);
|
|
SubActAdd(haWork3,1);
|
|
SubActAdd(haWork4,1);
|
|
end;
|
|
SubActAdd(haWork2,0.25);
|
|
fIssued := True;
|
|
end else
|
|
|
|
if (aHome = htWeaponWorkshop) and (aProduct = wtAxe) then
|
|
begin
|
|
ResourcePlan(wtTimber,2,wtNone,0,wtAxe);
|
|
SubActAdd(haWork1,1);
|
|
for I := 0 to 2 do
|
|
begin
|
|
SubActAdd(haWork2,1);
|
|
SubActAdd(haWork3,1);
|
|
SubActAdd(haWork4,1);
|
|
end;
|
|
SubActAdd(haWork5,1);
|
|
fIssued := True;
|
|
end else
|
|
|
|
if (aHome = htWeaponWorkshop) and (aProduct = wtLance) then
|
|
begin
|
|
ResourcePlan(wtTimber,2,wtNone,0,wtLance);
|
|
SubActAdd(haWork1,1);
|
|
for I := 0 to 2 do
|
|
begin
|
|
SubActAdd(haWork2,1);
|
|
SubActAdd(haWork3,1);
|
|
SubActAdd(haWork4,1);
|
|
end;
|
|
SubActAdd(haWork5,1);
|
|
fIssued := True;
|
|
end else
|
|
|
|
if (aHome = htWeaponWorkshop) and (aProduct = wtBow) then
|
|
begin
|
|
ResourcePlan(wtTimber,2,wtNone,0,wtBow);
|
|
SubActAdd(haWork1,1);
|
|
for I := 0 to 2 do
|
|
begin
|
|
SubActAdd(haWork2,1);
|
|
SubActAdd(haWork3,1);
|
|
SubActAdd(haWork4,1);
|
|
end;
|
|
SubActAdd(haWork5,1);
|
|
fIssued := True;
|
|
end;
|
|
utBaker: if aHome = htMill then
|
|
begin
|
|
ResourcePlan(wtCorn,1,wtNone,0,wtFlour);
|
|
SubActAdd(haWork2,47);
|
|
fIssued := True;
|
|
end else
|
|
|
|
if aHome = htBakery then
|
|
begin
|
|
ResourcePlan(wtFlour,1,wtNone,0,wtBread);
|
|
for I := 0 to 6 do
|
|
begin
|
|
SubActAdd(haWork2,1);
|
|
SubActAdd(haWork3,1);
|
|
end;
|
|
fIssued := True;
|
|
end;
|
|
utButcher: if aHome = htTannery then
|
|
begin
|
|
ResourcePlan(wtSkin,1,wtNone,0,wtLeather);
|
|
SubActAdd(haWork1,1);
|
|
SubActAdd(haWork2,29);
|
|
fIssued := True;
|
|
end else
|
|
|
|
if aHome = htButchers then
|
|
begin
|
|
ResourcePlan(wtPig,1,wtNone,0,wtSausage);
|
|
SubActAdd(haWork1,1);
|
|
for I := 0 to 5 do
|
|
begin
|
|
SubActAdd(haWork2,1);
|
|
SubActAdd(haWork4,1);
|
|
SubActAdd(haWork3,1);
|
|
end;
|
|
fIssued := True;
|
|
end;
|
|
utFisher: if aHome = htFishermans then
|
|
begin
|
|
fIssued := gTerrain.FindFishWater(aLoc, gRes.Units[aUnit.UnitType].MiningRange, KMPOINT_ZERO, False, tmp);
|
|
if fIssued then
|
|
begin
|
|
ResourcePlan(wtNone,0,wtNone,0,wtFish);
|
|
WalkStyle(tmp,uaWalk,uaWork2,10,0,uaWalkTool,gsFisherCatch);
|
|
end else
|
|
//We must check again this time ignoring working units since they don't indicate the resource is depleted
|
|
ResourceDepleted := not gTerrain.FindFishWater(aLoc, gRes.Units[aUnit.UnitType].MiningRange, KMPOINT_ZERO, True, tmp);
|
|
end;
|
|
utStonemason: if aHome = htQuarry then
|
|
begin
|
|
fIssued := gTerrain.FindStone(aLoc, gRes.Units[aUnit.UnitType].MiningRange, KMPOINT_ZERO, False, tmp);
|
|
if fIssued then
|
|
begin
|
|
ResourcePlan(wtNone,0,wtNone,0,wtStone);
|
|
WalkStyle(tmp, uaWalk,uaWork,8,0,uaWalkTool,gsStoneCutter);
|
|
SubActAdd(haWork1,1);
|
|
SubActAdd(haWork2,9);
|
|
SubActAdd(haWork5,1);
|
|
end else
|
|
//We must check again this time ignoring working units since they don't indicate the resource is depleted
|
|
ResourceDepleted := not gTerrain.FindStone(aLoc, gRes.Units[aUnit.UnitType].MiningRange, KMPOINT_ZERO, True, tmp);
|
|
end;
|
|
utSmith: if (aHome = htArmorSmithy) and (aProduct = wtIronShield) then
|
|
begin
|
|
ResourcePlan(wtIron,1,wtCoal,1,wtIronShield);
|
|
for I := 0 to 3 do
|
|
begin
|
|
SubActAdd(haWork2,1);
|
|
SubActAdd(haWork3,1);
|
|
SubActAdd(haWork4,1);
|
|
end;
|
|
SubActAdd(haWork2,1);
|
|
SubActAdd(haWork5,1);
|
|
fIssued := True;
|
|
end else
|
|
|
|
if (aHome = htArmorSmithy) and (aProduct = wtIronArmor) then
|
|
begin
|
|
ResourcePlan(wtIron,1,wtCoal,1,wtIronArmor);
|
|
for I := 0 to 3 do
|
|
begin
|
|
SubActAdd(haWork2,1);
|
|
SubActAdd(haWork3,1);
|
|
SubActAdd(haWork4,1);
|
|
end;
|
|
SubActAdd(haWork2,1);
|
|
SubActAdd(haWork5,1);
|
|
fIssued := True;
|
|
end else
|
|
|
|
if (aHome = htWeaponSmithy) and (aProduct = wtSword) then
|
|
begin
|
|
ResourcePlan(wtIron,1,wtCoal,1,wtSword);
|
|
SubActAdd(haWork1,1);
|
|
for I := 0 to 2 do
|
|
begin
|
|
SubActAdd(haWork2,1);
|
|
SubActAdd(haWork3,1);
|
|
SubActAdd(haWork4,1);
|
|
end;
|
|
SubActAdd(haWork5,1);
|
|
fIssued := True;
|
|
end else
|
|
|
|
if (aHome = htWeaponSmithy) and (aProduct = wtPike) then
|
|
begin
|
|
ResourcePlan(wtIron,1,wtCoal,1,wtPike);
|
|
SubActAdd(haWork1,1);
|
|
for I := 0 to 2 do
|
|
begin
|
|
SubActAdd(haWork2,1);
|
|
SubActAdd(haWork3,1);
|
|
SubActAdd(haWork4,1);
|
|
end;
|
|
SubActAdd(haWork5,1);
|
|
fIssued := True;
|
|
end else
|
|
|
|
if (aHome = htWeaponSmithy) and (aProduct = wtCrossbow) then
|
|
begin
|
|
ResourcePlan(wtIron,1,wtCoal,1,wtCrossbow);
|
|
SubActAdd(haWork1,1);
|
|
for I := 0 to 2 do
|
|
begin
|
|
SubActAdd(haWork2,1);
|
|
SubActAdd(haWork3,1);
|
|
SubActAdd(haWork4,1);
|
|
end;
|
|
SubActAdd(haWork5,1);
|
|
fIssued := True;
|
|
end;
|
|
utMetallurgist: if aHome = htIronSmithy then
|
|
begin
|
|
ResourcePlan(wtIronOre,1,wtCoal,1,wtIron);
|
|
for I := 0 to 3 do
|
|
begin
|
|
SubActAdd(haWork2,1);
|
|
SubActAdd(haWork3,1);
|
|
end;
|
|
SubActAdd(haWork2,1);
|
|
SubActAdd(haWork3,0.25);
|
|
fIssued := True;
|
|
end else
|
|
if aHome = htMetallurgists then
|
|
begin
|
|
ResourcePlan(wtGoldOre,1,wtCoal,1,wtGold);
|
|
for I := 0 to 3 do
|
|
begin
|
|
SubActAdd(haWork2,1);
|
|
SubActAdd(haWork3,1);
|
|
SubActAdd(haWork4,1);
|
|
end;
|
|
SubActAdd(haWork2,1);
|
|
SubActAdd(haWork3,0.1);
|
|
fIssued := True;
|
|
end;
|
|
else
|
|
raise Exception.Create('No work plan for ' +
|
|
gRes.Units[aUnit.UnitType].GUIName + ' in ' +
|
|
gRes.Houses[aHome].HouseName);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TKMUnitWorkPlan.Load(LoadStream: TKMemoryStream);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
LoadStream.CheckMarker('WorkPlan');
|
|
LoadStream.Read(fHome, SizeOf(fHome));
|
|
LoadStream.Read(fIssued);
|
|
//public
|
|
LoadStream.Read(HasToWalk);
|
|
LoadStream.Read(Loc);
|
|
LoadStream.Read(ActionWalkTo, SizeOf(ActionWalkTo));
|
|
LoadStream.Read(ActionWorkType, SizeOf(ActionWorkType));
|
|
LoadStream.Read(WorkCyc);
|
|
LoadStream.Read(WorkDir);
|
|
LoadStream.Read(GatheringScript, SizeOf(GatheringScript));
|
|
LoadStream.Read(AfterWorkDelay);
|
|
LoadStream.Read(ActionWalkFrom, SizeOf(ActionWalkFrom));
|
|
LoadStream.Read(Resource1, SizeOf(Resource1));
|
|
LoadStream.Read(Count1);
|
|
LoadStream.Read(Resource2, SizeOf(Resource2));
|
|
LoadStream.Read(Count2);
|
|
LoadStream.Read(ActCount);
|
|
for I := 0 to ActCount - 1 do //Write only assigned
|
|
begin
|
|
LoadStream.Read(HouseAct[I].Act, SizeOf(HouseAct[I].Act));
|
|
LoadStream.Read(HouseAct[I].TimeToWork);
|
|
end;
|
|
LoadStream.Read(Product1, SizeOf(Product1));
|
|
LoadStream.Read(ProdCount1);
|
|
LoadStream.Read(Product2, SizeOf(Product2));
|
|
LoadStream.Read(ProdCount2);
|
|
LoadStream.Read(AfterWorkIdle);
|
|
LoadStream.Read(ResourceDepleted);
|
|
end;
|
|
|
|
|
|
procedure TKMUnitWorkPlan.Save(SaveStream: TKMemoryStream);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
SaveStream.PlaceMarker('WorkPlan');
|
|
SaveStream.Write(fHome, SizeOf(fHome));
|
|
SaveStream.Write(fIssued);
|
|
//public
|
|
SaveStream.Write(HasToWalk);
|
|
SaveStream.Write(Loc);
|
|
SaveStream.Write(ActionWalkTo, SizeOf(ActionWalkTo));
|
|
SaveStream.Write(ActionWorkType, SizeOf(ActionWorkType));
|
|
SaveStream.Write(WorkCyc);
|
|
SaveStream.Write(WorkDir);
|
|
SaveStream.Write(GatheringScript, SizeOf(GatheringScript));
|
|
SaveStream.Write(AfterWorkDelay);
|
|
SaveStream.Write(ActionWalkFrom, SizeOf(ActionWalkFrom));
|
|
SaveStream.Write(Resource1, SizeOf(Resource1));
|
|
SaveStream.Write(Count1);
|
|
SaveStream.Write(Resource2, SizeOf(Resource2));
|
|
SaveStream.Write(Count2);
|
|
SaveStream.Write(ActCount);
|
|
for I := 0 to ActCount - 1 do //Write only assigned
|
|
begin
|
|
SaveStream.Write(HouseAct[I].Act, SizeOf(HouseAct[I].Act));
|
|
SaveStream.Write(HouseAct[I].TimeToWork);
|
|
end;
|
|
SaveStream.Write(Product1, SizeOf(Product1));
|
|
SaveStream.Write(ProdCount1);
|
|
SaveStream.Write(Product2, SizeOf(Product2));
|
|
SaveStream.Write(ProdCount2);
|
|
SaveStream.Write(AfterWorkIdle);
|
|
SaveStream.Write(ResourceDepleted);
|
|
end;
|
|
|
|
|
|
end.
|