{$MODE OBJFPC} { -*- delphi -*- } {$INCLUDE settings.inc} unit factory; interface uses basenetwork, systems, serverstream, materials, techtree, messageport, region, time, systemdynasty; type TFactoryFeatureClass = class(TFeatureClass) private FMaxRate: TRate; strict protected function GetFeatureNodeClass(): FeatureNodeReference; override; public constructor CreateFromTechnologyTree(Reader: TTechTreeReader); override; function InitFeatureNode(ASystem: TSystem): TFeatureNode; override; end; TFactoryFeatureNode = class(TFeatureNode, IRefinery) strict private FFeatureClass: TFactoryFeatureClass; FRegion: TRegionFeatureNode; FDisabledReasons: TDisabledReasons; FPoweredMaxRate: TRate; // FFeatureClass.FMaxRate * RateLimit FConfiguredMaxRate: TRate; FLocalDisabledReason: TFactoryDisabledReason; // if set, actual rate is currently zero private // IFactory function GetFactoryInputs(): TMaterialQuantityArray; function GetFactoryOutputs(): TMaterialQuantityArray; function GetFactoryRate(): TRate; // instances per second, min of FPoweredMaxRate and FConfiguredMaxRate procedure SetFactoryRegion(Region: TRegionFeatureNode); procedure StartFactory(); procedure StallFactory(Reason: TFactoryDisabledReason); procedure DisconnectFactory(); function GetDynasty(): TDynasty; protected constructor CreateFromJournal(Journal: TJournalReader; AFeatureClass: TFeatureClass; ASystem: TSystem); override; procedure HandleChanges(); override; procedure ResetDynastyNotes(OldDynasties: TDynastyIndexHashTable; NewDynasties: TDynasty.TArray); override; procedure ResetVisibility(); override; procedure HandleKnowledge(const DynastyIndex: Cardinal; const Sensors: ISensorsProvider); override; procedure Serialize(DynastyIndex: Cardinal; Writer: TServerStreamWriter); override; public constructor Create(ASystem: TSystem; AFeatureClass: TFactoryFeatureClass); destructor Destroy(); override; procedure UpdateJournal(Journal: TJournalWriter); override; procedure ApplyJournal(Journal: TJournalReader); override; end; // TODO: handle our ancestor chain changing implementation uses exceptions, sysutils, isdprotocol, knowledge, typedump, commonbuses; constructor TFactoryFeatureClass.CreateFromTechnologyTree(Reader: TTechTreeReader); var Material: TMaterial; begin inherited Create(); Reader.Tokens.ReadIdentifier('for'); Material := ReadMaterial(Reader); if ((Material.ID < Low(TOres)) or (Material.ID > High(TOres))) then Reader.Tokens.Error('Material "%s" is not an ore', [Material.Name]); FOre := Material.ID; // $R- Reader.Tokens.ReadComma(); Reader.Tokens.ReadIdentifier('max'); Reader.Tokens.ReadIdentifier('throughput'); FBandwidth := ReadMassPerTime(Reader.Tokens); end; function TFactoryFeatureClass.GetFeatureNodeClass(): FeatureNodeReference; begin Result := TFactoryFeatureNode; end; function TFactoryFeatureClass.InitFeatureNode(ASystem: TSystem): TFeatureNode; begin Result := TFactoryFeatureNode.Create(ASystem, Self); end; constructor TFactoryFeatureNode.Create(ASystem: TSystem; AFeatureClass: TFactoryFeatureClass); begin inherited Create(ASystem); FFeatureClass := AFeatureClass; end; constructor TFactoryFeatureNode.CreateFromJournal(Journal: TJournalReader; AFeatureClass: TFeatureClass; ASystem: TSystem); begin Assert(Assigned(AFeatureClass)); FFeatureClass := AFeatureClass as TFactoryFeatureClass; inherited; end; destructor TFactoryFeatureNode.Destroy(); begin if (FStatus.Connected) then FStatus.Region.RemoveRefinery(Self); inherited; end; function TFactoryFeatureNode.GetRefineryOre(): TOres; begin Result := FFeatureClass.FOre; end; function TFactoryFeatureNode.GetRefineryMaxRate(): TRate; // kg per second begin Result := FFeatureClass.FBandwidth * FStatus.RateLimit; end; function TFactoryFeatureNode.GetRefineryCurrentRate(): TRate; // kg per second begin Result := FStatus.Rate; end; procedure TFactoryFeatureNode.SetRefineryRegion(Region: TRegionFeatureNode); begin FStatus.SetRegion(Region); end; procedure TFactoryFeatureNode.StartRefinery(Rate: TRate; SourceLimiting, TargetLimiting: Boolean); // kg per second begin Assert(Assigned(FStatus.Region)); if (FStatus.Update(Rate, SourceLimiting, TargetLimiting)) then MarkAsDirty([dkUpdateClients]); end; procedure TFactoryFeatureNode.DisconnectRefinery(); begin FStatus.Reset(); MarkAsDirty([dkUpdateClients, dkNeedsHandleChanges]); end; function TFactoryFeatureNode.GetDynasty(): TDynasty; begin Result := Parent.Owner; end; procedure TFactoryFeatureNode.HandleChanges(); var DisabledReasons: TDisabledReasons; Message: TRegisterRefineryBusMessage; RateLimit: Double; begin DisabledReasons := CheckDisabled(Parent, RateLimit); if ((RateLimit = 0.0) and (FStatus.Connected)) then FStatus.Region.RemoveRefinery(Self); if ((DisabledReasons <> FStatus.DisabledReasons) or (RateLimit <> FStatus.RateLimit)) then begin if (DisabledReasons <> FStatus.DisabledReasons) then MarkAsDirty([dkUpdateClients]); FStatus.SetDisabledReasons(DisabledReasons, RateLimit); end; if (FStatus.NeedsConnection) then begin Message := TRegisterRefineryBusMessage.Create(Self); if (InjectBusMessage(Message) <> irHandled) then FStatus.SetNoRegion(); FreeAndNil(Message); end; inherited; end; procedure TFactoryFeatureNode.Serialize(DynastyIndex: Cardinal; Writer: TServerStreamWriter); var Visibility: TVisibility; Flags: Byte; begin Visibility := Parent.ReadVisibilityFor(DynastyIndex); if ((dmDetectable * Visibility <> []) and (dmClassKnown in Visibility)) then begin Writer.WriteCardinal(fcFactory); if (FOreKnowledge.GetEntry(DynastyIndex)) then begin Writer.WriteCardinal(FFeatureClass.FOre); end else begin Writer.WriteCardinal(0); end; Writer.WriteDouble(FFeatureClass.FBandwidth.AsDouble); Writer.WriteCardinal(Cardinal(FStatus.DisabledReasons)); Flags := $00; if (FStatus.SourceLimiting) then Flags := Flags or $01; // $R- if (FStatus.TargetLimiting) then Flags := Flags or $02; // $R- Writer.WriteByte(Flags); Writer.WriteDouble(FStatus.Rate.AsDouble); end; end; procedure TFactoryFeatureNode.ResetDynastyNotes(OldDynasties: TDynastyIndexHashTable; NewDynasties: TDynasty.TArray); begin FOreKnowledge.Init(Length(NewDynasties)); // $R- end; procedure TFactoryFeatureNode.ResetVisibility(); begin FOreKnowledge.Reset(); end; procedure TFactoryFeatureNode.HandleKnowledge(const DynastyIndex: Cardinal; const Sensors: ISensorsProvider); begin FOreKnowledge.SetEntry(DynastyIndex, Sensors.Knows(System.Encyclopedia.Materials[FFeatureClass.FOre])); end; procedure TFactoryFeatureNode.UpdateJournal(Journal: TJournalWriter); begin end; procedure TFactoryFeatureNode.ApplyJournal(Journal: TJournalReader); begin end; initialization RegisterFeatureClass(TFactoryFeatureClass); end.