Ignore:
Timestamp:
Mar 9, 2021, 9:19:49 AM (4 years ago)
Author:
chronos
Message:
  • Modified: Synced code with current trunk version.
Location:
branches/highdpi/LocalPlayer
Files:
1 added
14 edited

Legend:

Unmodified
Added
Removed
  • branches/highdpi/LocalPlayer/CityScreen.pas

    r246 r303  
    216216  Template := TDpiBitmap.Create;
    217217  Template.PixelFormat := pf24bit;
    218   LoadGraphicFile(Template, GetGraphicsDir + DirectorySeparator + 'City.png', gfNoGamma);
     218  LoadGraphicFile(Template, GetGraphicsDir + DirectorySeparator + 'City.png',
     219    [gfNoGamma]);
    219220  CityMapTemplate := TDpiBitmap.Create;
    220221  CityMapTemplate.PixelFormat := pf24bit;
    221   LoadGraphicFile(CityMapTemplate, GetGraphicsDir + DirectorySeparator + 'BigCityMap.png', gfNoGamma);
     222  LoadGraphicFile(CityMapTemplate, GetGraphicsDir + DirectorySeparator + 'BigCityMap.png',
     223    [gfNoGamma]);
    222224  SmallCityMapTemplate := TDpiBitmap.Create;
    223225  SmallCityMapTemplate.PixelFormat := pf24bit;
    224226  LoadGraphicFile(SmallCityMapTemplate, GetGraphicsDir + DirectorySeparator + 'SmallCityMap.png',
    225     gfNoGamma);
     227    [gfNoGamma]);
    226228  SmallCityMap := TDpiBitmap.Create;
    227229  SmallCityMap.PixelFormat := pf24bit;
     
    13971399
    13981400procedure TCityDlg.ChooseProject;
    1399 const
    1400   ptSelect = 0;
    1401   ptTrGoods = 1;
    1402   ptUn = 2;
    1403   ptCaravan = 3;
    1404   ptImp = 4;
    1405   ptWonder = 6;
    1406   ptShip = 7;
    1407   ptInvalid = 8;
    1408 
    1409   function ProjectType(Project: integer): integer;
     1401type
     1402  TProjectType = (
     1403    ptSelect = 0,
     1404    ptTrGoods = 1,
     1405    ptUn = 2,
     1406    ptCaravan = 3,
     1407    ptImp = 4,
     1408    ptWonder = 6,
     1409    ptShip = 7,
     1410    ptInvalid = 8
     1411  );
     1412
     1413  function ProjectType(Project: integer): TProjectType;
    14101414  begin
    14111415    if Project and cpCompleted <> 0 then
    1412       result := ptSelect
     1416      Result := ptSelect
    14131417    else if Project and (cpImp + cpIndex) = cpImp + imTrGoods then
    1414       result := ptTrGoods
    1415     else if Project and cpImp = 0 then
     1418      Result := ptTrGoods
     1419    else if Project and cpImp = 0 then begin
    14161420      if MyModel[Project and cpIndex].Kind = mkCaravan then
    1417         result := ptCaravan
    1418       else
    1419         result := ptUn
     1421        Result := ptCaravan
     1422      else Result := ptUn;
     1423    end
    14201424    else if Project and cpIndex >= nImp then
    1421       result := ptInvalid
     1425      Result := ptInvalid
    14221426    else if Imp[Project and cpIndex].Kind = ikWonder then
    1423       result := ptWonder
     1427      Result := ptWonder
    14241428    else if Imp[Project and cpIndex].Kind = ikShipPart then
    1425       result := ptShip
    1426     else
    1427       result := ptImp
     1429      Result := ptShip
     1430    else
     1431      Result := ptImp;
    14281432  end;
    14291433
    14301434var
    1431   NewProject, OldMoney, pt0, pt1, cix1: integer;
     1435  NewProject, OldMoney, cix1: integer;
     1436  pt0, pt1: TProjectType;
    14321437  QueryOk: boolean;
    14331438begin
    1434   assert(not supervising);
     1439  Assert(not supervising);
    14351440  ModalSelectDlg.ShowNewContent_CityProject(wmModal, cix);
    14361441  if ModalSelectDlg.result <> -1 then
     
    14441449    else
    14451450    begin
    1446       NewProject := ModalSelectDlg.result;
    1447       QueryOk := true;
     1451      NewProject := ModalSelectDlg.Result;
     1452      QueryOk := True;
    14481453      if (NewProject and cpImp <> 0) and (NewProject and cpIndex >= 28) and
    14491454        (MyRO.NatBuilt[NewProject and cpIndex] > 0) then
     
    14531458          while (cix1 >= 0) and
    14541459            (MyCity[cix1].Built[NewProject and cpIndex] = 0) do
    1455             dec(cix1);
     1460            Dec(cix1);
    14561461          MessgText := Format(Phrases.Lookup('DOUBLESTATEIMP'),
    14571462            [Phrases.Lookup('IMPROVEMENTS', NewProject and cpIndex),
     
    14651470        end;
    14661471      if not QueryOk then
    1467         exit;
     1472        Exit;
    14681473
    14691474      if (MyCity[cix].Prod > 0) then
     
    14761481            (cpImp or cpIndex) then
    14771482          begin // loss of material -- do query
     1483            DpiApplication.ProcessMessages; // TODO: Needed for Gtk2, Lazarus gtk2 bug?
    14781484            if (pt1 = ptTrGoods) or (pt1 = ptShip) or (pt1 <> pt0) and
    1479               (pt0 <> ptCaravan) then
     1485              (pt0 <> ptCaravan) then begin
    14801486              QueryOk := SimpleQuery(mkOkCancel,
    14811487                Format(Phrases.Lookup('LOSEMAT'), [MyCity[cix].Prod0,
    14821488                MyCity[cix].Prod0]), 'MSG_DEFAULT') = mrOK
    1483             else if MyCity[cix].Project and (cpImp or cpIndex) = MyCity[cix]
    1484               .Project0 and (cpImp or cpIndex) then
    1485               QueryOk := SimpleQuery(mkOkCancel, Phrases.Lookup('LOSEMAT3'),
    1486                 'MSG_DEFAULT') = mrOK
     1489            end else
     1490            if MyCity[cix].Project and (cpImp or cpIndex) = MyCity[cix]
     1491              .Project0 and (cpImp or cpIndex) then begin
     1492                QueryOk := SimpleQuery(mkOkCancel, Phrases.Lookup('LOSEMAT3'),
     1493                  'MSG_DEFAULT') = mrOK;
     1494            end;
    14871495          end;
    14881496        end;
    14891497      end;
    14901498      if not QueryOk then
    1491         exit;
     1499        Exit;
    14921500
    14931501      OldMoney := MyRO.Money;
  • branches/highdpi/LocalPlayer/ClientTools.pas

    r210 r303  
    1313
    1414type
    15   TImpOrder = array [0 .. (nImp + 4) div 4 * 4 - 1] of ShortInt;
    16   TEnhancementJobs = array [0 .. 11, 0 .. 7] of Byte;
     15  TImpOrder = array [0 .. (nImp + 4) div 4 * 4 - 1] of shortint;
     16  TEnhancementJobs = array [0 .. 11, 0 .. 7] of byte;
    1717  JobResultSet = set of 0 .. 39;
    1818
     
    4242function CutCityFoodSurplus(FoodSurplus: integer; IsCityAlive: boolean;
    4343  gov, size: integer): integer;
    44 function CityTaxBalance(cix: integer; const CityReport: TCityReportNew)
    45   : integer;
     44function CityTaxBalance(cix: integer; const CityReport: TCityReportNew): integer;
    4645procedure SumCities(var TaxSum, ScienceSum: integer);
    4746function JobTest(uix, Job: integer; IgnoreResults: JobResultSet = []): boolean;
     
    5049function UnitExhausted(uix: integer): boolean;
    5150function ModelHash(const ModelInfo: TModelInfo): integer;
    52 function ProcessEnhancement(uix: integer; const Jobs: TEnhancementJobs)
    53   : integer;
     51function ProcessEnhancement(uix: integer; const Jobs: TEnhancementJobs): integer;
    5452function AutoBuild(cix: integer; const ImpOrder: TImpOrder): boolean;
    5553procedure DebugMessage(Level: integer; Text: string);
     
    6260procedure CityOptimizer_EndOfTurn;
    6361
     62
    6463implementation
    6564
     
    7271begin
    7372  y0 := (Loc + G.lx * 1024) div G.lx - 1024;
    74   result := (Loc + (dx + y0 and 1 + G.lx * 1024) shr 1) mod G.lx + G.lx
    75     * (y0 + dy)
     73  Result := (Loc + (dx + y0 and 1 + G.lx * 1024) shr 1) mod G.lx + G.lx * (y0 + dy);
    7674end;
    7775
     
    8078  dx, dy: integer;
    8179begin
    82   inc(Loc0, G.lx * 1024);
    83   inc(Loc1, G.lx * 1024);
    84   dx := abs(((Loc1 mod G.lx * 2 + Loc1 div G.lx and 1) - (Loc0 mod G.lx * 2 +
    85     Loc0 div G.lx and 1) + 3 * G.lx) mod (2 * G.lx) - G.lx);
     80  Inc(Loc0, G.lx * 1024);
     81  Inc(Loc1, G.lx * 1024);
     82  dx := abs(((Loc1 mod G.lx * 2 + Loc1 div G.lx and 1) -
     83    (Loc0 mod G.lx * 2 + Loc0 div G.lx and 1) + 3 * G.lx) mod (2 * G.lx) - G.lx);
    8684  dy := abs(Loc1 div G.lx - Loc0 div G.lx);
    87   result := dx + dy + abs(dx - dy) shr 1;
     85  Result := dx + dy + abs(dx - dy) shr 1;
    8886end;
    8987
     
    9290  uix1: integer;
    9391begin
    94   result := false;
     92  Result := False;
    9593  if MyModel[MyUn[uix].mix].Flags and mdCivil = 0 then
    9694    case MyRO.Government of
    9795      gRepublic, gFuture:
    98         result := (MyRO.Territory[Loc] >= 0) and (MyRO.Territory[Loc] <> me) and
     96        Result := (MyRO.Territory[Loc] >= 0) and (MyRO.Territory[Loc] <> me) and
    9997          (MyRO.Treaty[MyRO.Territory[Loc]] < trAlliance);
    10098      gDemocracy:
    101         result := (MyRO.Territory[Loc] < 0) or (MyRO.Territory[Loc] <> me) and
     99        Result := (MyRO.Territory[Loc] < 0) or (MyRO.Territory[Loc] <> me) and
    102100          (MyRO.Treaty[MyRO.Territory[Loc]] < trAlliance);
    103101    end;
     
    106104      for uix1 := 0 to MyRO.nUn - 1 do // check transported units too
    107105        if (MyUn[uix1].Loc >= 0) and (MyUn[uix1].Master = uix) then
    108           result := result or UnrestAtLoc(uix1, Loc);
     106          Result := Result or UnrestAtLoc(uix1, Loc);
    109107end;
    110108
     
    124122      MoveAdviceData.MoreTurns := 999;
    125123      MoveAdviceData.MaxHostile_MovementLeft := MyUn[uix].Health - MinEndHealth;
    126       result := Server(sGetMoveAdvice, me, uix, MoveAdviceData);
    127       if (MinEndHealth <= 1) or (result <> eNoWay) then
     124      Result := Server(sGetMoveAdvice, me, uix, MoveAdviceData);
     125      if (MinEndHealth <= 1) or (Result <> eNoWay) then
    128126        exit;
    129127    end;
     
    135133      25:
    136134        MinEndHealth := 12;
     135      else
     136        MinEndHealth := 1
     137    end;
     138  until False;
     139end;
     140
     141function ColorOfHealth(Health: integer): integer;
     142var
     143  red, green: integer;
     144begin
     145  green := 400 * Health div 100;
     146  if green > 200 then
     147    green := 200;
     148  red := 510 * (100 - Health) div 100;
     149  if red > 255 then
     150    red := 255;
     151  Result := green shl 8 + red;
     152end;
     153
     154function IsMultiPlayerGame: boolean;
     155var
     156  p1: integer;
     157begin
     158  Result := False;
     159  for p1 := 1 to nPl - 1 do
     160    if G.RO[p1] <> nil then
     161      Result := True;
     162end;
     163
     164procedure ItsMeAgain(p: integer);
     165begin
     166  if G.RO[p] <> nil then
     167    MyRO := pointer(G.RO[p])
     168  else if G.SuperVisorRO[p] <> nil then
     169    MyRO := pointer(G.SuperVisorRO[p])
     170  else
     171    exit;
     172  me := p;
     173  MyMap := pointer(MyRO.Map);
     174  MyUn := pointer(MyRO.Un);
     175  MyCity := pointer(MyRO.City);
     176  MyModel := pointer(MyRO.Model);
     177end;
     178
     179function GetAge(p: integer): integer;
     180var
     181  i: integer;
     182begin
     183  if p = me then
     184  begin
     185    Result := 0;
     186    for i := 1 to 3 do
     187      if MyRO.Tech[AgePreq[i]] >= tsApplicable then
     188        Result := i;
     189  end
     190  else
     191  begin
     192    Result := 0;
     193    for i := 1 to 3 do
     194      if MyRO.EnemyReport[p].Tech[AgePreq[i]] >= tsApplicable then
     195        Result := i;
     196  end;
     197end;
     198
     199function IsCivilReportNew(Enemy: integer): boolean;
     200var
     201  i: integer;
     202begin
     203  assert(Enemy <> me);
     204  i := MyRO.EnemyReport[Enemy].TurnOfCivilReport;
     205  Result := (i = MyRO.Turn) or (i = MyRO.Turn - 1) and (Enemy > me);
     206end;
     207
     208function IsMilReportNew(Enemy: integer): boolean;
     209var
     210  i: integer;
     211begin
     212  assert(Enemy <> me);
     213  i := MyRO.EnemyReport[Enemy].TurnOfMilReport;
     214  Result := (i = MyRO.Turn) or (i = MyRO.Turn - 1) and (Enemy > me);
     215end;
     216
     217function CutCityFoodSurplus(FoodSurplus: integer; IsCityAlive: boolean;
     218  gov, size: integer): integer;
     219begin
     220  Result := FoodSurplus;
     221  if not IsCityAlive or (Result > 0) and ((gov = gFuture) or
     222    (size >= NeedAqueductSize) and (Result < 2)) then
     223    Result := 0; { no growth }
     224end;
     225
     226function CityTaxBalance(cix: integer; const CityReport: TCityReportNew): integer;
     227var
     228  i: integer;
     229begin
     230  Result := 0;
     231  if (CityReport.HappinessBalance >= 0) { no disorder } and
     232    (MyCity[cix].Flags and chCaptured = 0) then // not captured
     233  begin
     234    Inc(Result, CityReport.Tax);
     235    if (MyCity[cix].Project and (cpImp + cpIndex) = cpImp + imTrGoods) and
     236      (CityReport.Production > 0) then
     237      Inc(Result, CityReport.Production);
     238    if ((MyRO.Government = gFuture) or (MyCity[cix].size >=
     239      NeedAqueductSize) and (CityReport.FoodSurplus < 2)) and
     240      (CityReport.FoodSurplus > 0) then
     241      Inc(Result, CityReport.FoodSurplus);
     242  end;
     243  for i := 28 to nImp - 1 do
     244    if MyCity[cix].Built[i] > 0 then
     245      Dec(Result, Imp[i].Maint);
     246end;
     247
     248procedure SumCities(var TaxSum, ScienceSum: integer);
     249var
     250  cix: integer;
     251  CityReport: TCityReportNew;
     252begin
     253  TaxSum := MyRO.OracleIncome;
     254  ScienceSum := 0;
     255  if MyRO.Government = gAnarchy then
     256    exit;
     257  for cix := 0 to MyRO.nCity - 1 do
     258    if MyCity[cix].Loc >= 0 then
     259    begin
     260      CityReport.HypoTiles := -1;
     261      CityReport.HypoTaxRate := -1;
     262      CityReport.HypoLuxuryRate := -1;
     263      Server(sGetCityReportNew, me, cix, CityReport);
     264      if (CityReport.HappinessBalance >= 0) { no disorder } and
     265        (MyCity[cix].Flags and chCaptured = 0) then // not captured
     266        ScienceSum := ScienceSum + CityReport.Science;
     267      TaxSum := TaxSum + CityTaxBalance(cix, CityReport);
     268    end;
     269end;
     270
     271function JobTest(uix, Job: integer; IgnoreResults: JobResultSet): boolean;
     272var
     273  Test: integer;
     274begin
     275  Test := Server(sStartJob + Job shl 4 - sExecute, me, uix, nil^);
     276  Result := (Test >= rExecuted) or (Test in IgnoreResults);
     277end;
     278
     279procedure GetUnitInfo(Loc: integer; var uix: integer; var UnitInfo: TUnitInfo);
     280var
     281  i, Cnt: integer;
     282begin
     283  if MyMap[Loc] and fOwned <> 0 then
     284  begin
     285    Server(sGetDefender, me, Loc, uix);
     286    Cnt := 0;
     287    for i := 0 to MyRO.nUn - 1 do
     288      if MyUn[i].Loc = Loc then
     289        Inc(Cnt);
     290    MakeUnitInfo(me, MyUn[uix], UnitInfo);
     291    if Cnt > 1 then
     292      UnitInfo.Flags := UnitInfo.Flags or unMulti;
     293  end
     294  else
     295  begin
     296    uix := MyRO.nEnemyUn - 1;
     297    while (uix >= 0) and (MyRO.EnemyUn[uix].Loc <> Loc) do
     298      Dec(uix);
     299    UnitInfo := MyRO.EnemyUn[uix];
     300  end;
     301end; { GetUnitInfo }
     302
     303procedure GetCityInfo(Loc: integer; var cix: integer; var CityInfo: TCityInfo);
     304begin
     305  if MyMap[Loc] and fOwned <> 0 then
     306  begin
     307    CityInfo.Loc := Loc;
     308    cix := MyRO.nCity - 1;
     309    while (cix >= 0) and (MyCity[cix].Loc <> Loc) do
     310      Dec(cix);
     311    with CityInfo do
     312    begin
     313      Owner := me;
     314      ID := MyCity[cix].ID;
     315      size := MyCity[cix].size;
     316      Flags := 0;
     317      if MyCity[cix].Built[imPalace] > 0 then
     318        Inc(Flags, ciCapital);
     319      if (MyCity[cix].Built[imWalls] > 0) or
     320        (MyMap[MyCity[cix].Loc] and fGrWall <> 0) then
     321        Inc(Flags, ciWalled);
     322      if MyCity[cix].Built[imCoastalFort] > 0 then
     323        Inc(Flags, ciCoastalFort);
     324      if MyCity[cix].Built[imMissileBat] > 0 then
     325        Inc(Flags, ciMissileBat);
     326      if MyCity[cix].Built[imBunker] > 0 then
     327        Inc(Flags, ciBunker);
     328      if MyCity[cix].Built[imSpacePort] > 0 then
     329        Inc(Flags, ciSpacePort);
     330    end;
     331  end
     332  else
     333  begin
     334    cix := MyRO.nEnemyCity - 1;
     335    while (cix >= 0) and (MyRO.EnemyCity[cix].Loc <> Loc) do
     336      Dec(cix);
     337    CityInfo := MyRO.EnemyCity[cix];
     338  end;
     339end;
     340
     341function UnitExhausted(uix: integer): boolean;
     342  // check if another move of this unit is still possible
     343var
     344  dx, dy: integer;
     345begin
     346  Result := True;
     347  if (MyUn[uix].Movement > 0) or
     348    (MyRO.Wonder[woShinkansen].EffectiveOwner = me) then
     349    if (MyUn[uix].Movement >= 100) or
     350      ((MyModel[MyUn[uix].mix].Kind = mkCaravan) and
     351      (MyMap[MyUn[uix].Loc] and fCity <> 0)) then
     352      Result := False
    137353    else
    138       MinEndHealth := 1
    139     end;
    140   until false end;
    141 
    142   function ColorOfHealth(Health: integer): integer;
    143   var
    144     red, green: integer;
    145   begin
    146     green := 400 * Health div 100;
    147     if green > 200 then
    148       green := 200;
    149     red := 510 * (100 - Health) div 100;
    150     if red > 255 then
    151       red := 255;
    152     result := green shl 8 + red
    153   end;
    154 
    155   function IsMultiPlayerGame: boolean;
    156   var
    157     p1: integer;
    158   begin
    159     result := false;
    160     for p1 := 1 to nPl - 1 do
    161       if G.RO[p1] <> nil then
    162         result := true;
    163   end;
    164 
    165   procedure ItsMeAgain(p: integer);
    166   begin
    167     if G.RO[p] <> nil then
    168       MyRO := pointer(G.RO[p])
    169     else if G.SuperVisorRO[p] <> nil then
    170       MyRO := pointer(G.SuperVisorRO[p])
    171     else
    172       exit;
    173     me := p;
    174     MyMap := pointer(MyRO.Map);
    175     MyUn := pointer(MyRO.Un);
    176     MyCity := pointer(MyRO.City);
    177     MyModel := pointer(MyRO.Model);
    178   end;
    179 
    180   function GetAge(p: integer): integer;
    181   var
    182     i: integer;
    183   begin
    184     if p = me then
    185     begin
    186       result := 0;
    187       for i := 1 to 3 do
    188         if MyRO.Tech[AgePreq[i]] >= tsApplicable then
    189           result := i;
    190     end
     354      for dx := -2 to 2 do
     355        for dy := -2 to 2 do
     356          if abs(dx) + abs(dy) = 2 then
     357            if Server(sMoveUnit - sExecute + dx and 7 shl 4 + dy and
     358              7 shl 7, me, uix, nil^) >= rExecuted then
     359              Result := False;
     360end;
     361
     362function ModelHash(const ModelInfo: TModelInfo): integer;
     363var
     364  i, FeatureCode, Hash1, Hash2, Hash2r, d: cardinal;
     365begin
     366  with ModelInfo do
     367    if Kind > mkEnemyDeveloped then
     368      Result := integer($C0000000 + Speed div 50 + Kind shl 8)
    191369    else
    192370    begin
    193       result := 0;
    194       for i := 1 to 3 do
    195         if MyRO.EnemyReport[p].Tech[AgePreq[i]] >= tsApplicable then
    196           result := i;
    197     end
    198   end;
    199 
    200   function IsCivilReportNew(Enemy: integer): boolean;
    201   var
    202     i: integer;
    203   begin
    204     assert(Enemy <> me);
    205     i := MyRO.EnemyReport[Enemy].TurnOfCivilReport;
    206     result := (i = MyRO.Turn) or (i = MyRO.Turn - 1) and (Enemy > me);
    207   end;
    208 
    209   function IsMilReportNew(Enemy: integer): boolean;
    210   var
    211     i: integer;
    212   begin
    213     assert(Enemy <> me);
    214     i := MyRO.EnemyReport[Enemy].TurnOfMilReport;
    215     result := (i = MyRO.Turn) or (i = MyRO.Turn - 1) and (Enemy > me);
    216   end;
    217 
    218   function CutCityFoodSurplus(FoodSurplus: integer; IsCityAlive: boolean;
    219     gov, size: integer): integer;
    220   begin
    221     result := FoodSurplus;
    222     if not IsCityAlive or (result > 0) and
    223       ((gov = gFuture) or (size >= NeedAqueductSize) and (result < 2)) then
    224       result := 0; { no growth }
    225   end;
    226 
    227   function CityTaxBalance(cix: integer;
    228     const CityReport: TCityReportNew): integer;
    229   var
    230     i: integer;
    231   begin
    232     result := 0;
    233     if (CityReport.HappinessBalance >= 0) { no disorder }
    234       and (MyCity[cix].Flags and chCaptured = 0) then // not captured
    235     begin
    236       inc(result, CityReport.Tax);
    237       if (MyCity[cix].Project and (cpImp + cpIndex) = cpImp + imTrGoods) and
    238         (CityReport.Production > 0) then
    239         inc(result, CityReport.Production);
    240       if ((MyRO.Government = gFuture) or (MyCity[cix].size >= NeedAqueductSize)
    241         and (CityReport.FoodSurplus < 2)) and (CityReport.FoodSurplus > 0) then
    242         inc(result, CityReport.FoodSurplus);
     371      FeatureCode := 0;
     372      for i := mcFirstNonCap to nFeature - 1 do
     373        if 1 shl Domain and Feature[i].Domains <> 0 then
     374        begin
     375          FeatureCode := FeatureCode * 2;
     376          if 1 shl (i - mcFirstNonCap) <> 0 then
     377            Inc(FeatureCode);
     378        end;
     379      case Domain of
     380        dGround:
     381        begin
     382          assert(FeatureCode < 1 shl 8);
     383          assert(Attack < 5113);
     384          assert(Defense < 2273);
     385          assert(Cost < 1611);
     386          Hash1 := (Attack * 2273 + Defense) * 9 + (Speed - 150) div 50;
     387          Hash2 := FeatureCode * 1611 + Cost;
     388        end;
     389        dSea:
     390        begin
     391          assert(FeatureCode < 1 shl 9);
     392          assert(Attack < 12193);
     393          assert(Defense < 6097);
     394          assert(Cost < 4381);
     395          Hash1 := ((Attack * 6097 + Defense) * 5 +
     396            (Speed - 350) div 100) * 2;
     397          if Weight >= 6 then
     398            Inc(Hash1);
     399          Hash2 := ((TTrans * 17 + ATrans_Fuel) shl 9 + FeatureCode) *
     400            4381 + Cost;
     401        end;
     402        dAir:
     403        begin
     404          assert(FeatureCode < 1 shl 5);
     405          assert(Attack < 2407);
     406          assert(Defense < 1605);
     407          assert(Bombs < 4813);
     408          assert(Cost < 2089);
     409          Hash1 := (Attack * 1605 + Defense) shl 5 + FeatureCode;
     410          Hash2 := ((Bombs * 7 + ATrans_Fuel) * 4 + TTrans) * 2089 + Cost;
     411        end;
     412      end;
     413      Hash2r := 0;
     414      for i := 0 to 7 do
     415      begin
     416        Hash2r := Hash2r * 13;
     417        d := Hash2 div 13;
     418        Inc(Hash2r, Hash2 - d * 13);
     419        Hash2 := d;
     420      end;
     421      Result := integer(Domain shl 30 + Hash1 xor Hash2r);
    243422    end;
    244     for i := 28 to nImp - 1 do
    245       if MyCity[cix].Built[i] > 0 then
    246         dec(result, Imp[i].Maint);
    247   end;
    248 
    249   procedure SumCities(var TaxSum, ScienceSum: integer);
    250   var
    251     cix: integer;
    252     CityReport: TCityReportNew;
    253   begin
    254     TaxSum := MyRO.OracleIncome;
    255     ScienceSum := 0;
    256     if MyRO.Government = gAnarchy then
    257       exit;
    258     for cix := 0 to MyRO.nCity - 1 do
    259       if MyCity[cix].Loc >= 0 then
    260       begin
    261         CityReport.HypoTiles := -1;
    262         CityReport.HypoTaxRate := -1;
    263         CityReport.HypoLuxuryRate := -1;
    264         Server(sGetCityReportNew, me, cix, CityReport);
    265         if (CityReport.HappinessBalance >= 0) { no disorder }
    266           and (MyCity[cix].Flags and chCaptured = 0) then // not captured
    267           ScienceSum := ScienceSum + CityReport.Science;
    268         TaxSum := TaxSum + CityTaxBalance(cix, CityReport);
    269       end;
    270   end;
    271 
    272   function JobTest(uix, Job: integer; IgnoreResults: JobResultSet): boolean;
    273   var
    274     Test: integer;
    275   begin
    276     Test := Server(sStartJob + Job shl 4 - sExecute, me, uix, nil^);
    277     result := (Test >= rExecuted) or (Test in IgnoreResults);
    278   end;
    279 
    280   procedure GetUnitInfo(Loc: integer; var uix: integer;
    281     var UnitInfo: TUnitInfo);
    282   var
    283     i, Cnt: integer;
    284   begin
    285     if MyMap[Loc] and fOwned <> 0 then
    286     begin
    287       Server(sGetDefender, me, Loc, uix);
    288       Cnt := 0;
    289       for i := 0 to MyRO.nUn - 1 do
    290         if MyUn[i].Loc = Loc then
    291           inc(Cnt);
    292       MakeUnitInfo(me, MyUn[uix], UnitInfo);
    293       if Cnt > 1 then
    294         UnitInfo.Flags := UnitInfo.Flags or unMulti;
    295     end
    296     else
    297     begin
    298       uix := MyRO.nEnemyUn - 1;
    299       while (uix >= 0) and (MyRO.EnemyUn[uix].Loc <> Loc) do
    300         dec(uix);
    301       UnitInfo := MyRO.EnemyUn[uix];
    302     end
    303   end; { GetUnitInfo }
    304 
    305   procedure GetCityInfo(Loc: integer; var cix: integer;
    306     var CityInfo: TCityInfo);
    307   begin
    308     if MyMap[Loc] and fOwned <> 0 then
    309     begin
    310       CityInfo.Loc := Loc;
    311       cix := MyRO.nCity - 1;
    312       while (cix >= 0) and (MyCity[cix].Loc <> Loc) do
    313         dec(cix);
    314       with CityInfo do
    315       begin
    316         Owner := me;
    317         ID := MyCity[cix].ID;
    318         size := MyCity[cix].size;
    319         Flags := 0;
    320         if MyCity[cix].Built[imPalace] > 0 then
    321           inc(Flags, ciCapital);
    322         if (MyCity[cix].Built[imWalls] > 0) or
    323           (MyMap[MyCity[cix].Loc] and fGrWall <> 0) then
    324           inc(Flags, ciWalled);
    325         if MyCity[cix].Built[imCoastalFort] > 0 then
    326           inc(Flags, ciCoastalFort);
    327         if MyCity[cix].Built[imMissileBat] > 0 then
    328           inc(Flags, ciMissileBat);
    329         if MyCity[cix].Built[imBunker] > 0 then
    330           inc(Flags, ciBunker);
    331         if MyCity[cix].Built[imSpacePort] > 0 then
    332           inc(Flags, ciSpacePort);
    333       end
    334     end
    335     else
    336     begin
    337       cix := MyRO.nEnemyCity - 1;
    338       while (cix >= 0) and (MyRO.EnemyCity[cix].Loc <> Loc) do
    339         dec(cix);
    340       CityInfo := MyRO.EnemyCity[cix];
    341     end
    342   end;
    343 
    344   function UnitExhausted(uix: integer): boolean;
    345   // check if another move of this unit is still possible
    346   var
    347     dx, dy: integer;
    348   begin
    349     result := true;
    350     if (MyUn[uix].Movement > 0) or
    351       (MyRO.Wonder[woShinkansen].EffectiveOwner = me) then
    352       if (MyUn[uix].Movement >= 100) or
    353         ((MyModel[MyUn[uix].mix].Kind = mkCaravan) and
    354         (MyMap[MyUn[uix].Loc] and fCity <> 0)) then
    355         result := false
    356       else
    357         for dx := -2 to 2 do
    358           for dy := -2 to 2 do
    359             if abs(dx) + abs(dy) = 2 then
    360               if Server(sMoveUnit - sExecute + dx and 7 shl 4 + dy and 7 shl 7,
    361                 me, uix, nil^) >= rExecuted then
    362                 result := false;
    363   end;
    364 
    365   function ModelHash(const ModelInfo: TModelInfo): integer;
    366   var
    367     i, FeatureCode, Hash1, Hash2, Hash2r, d: cardinal;
    368   begin
    369     with ModelInfo do
    370       if Kind > mkEnemyDeveloped then
    371         result := integer($C0000000 + Speed div 50 + Kind shl 8)
    372       else
    373       begin
    374         FeatureCode := 0;
    375         for i := mcFirstNonCap to nFeature - 1 do
    376           if 1 shl Domain and Feature[i].Domains <> 0 then
    377           begin
    378             FeatureCode := FeatureCode * 2;
    379             if 1 shl (i - mcFirstNonCap) <> 0 then
    380               inc(FeatureCode);
    381           end;
    382         case Domain of
    383           dGround:
    384             begin
    385               assert(FeatureCode < 1 shl 8);
    386               assert(Attack < 5113);
    387               assert(Defense < 2273);
    388               assert(Cost < 1611);
    389               Hash1 := (Attack * 2273 + Defense) * 9 + (Speed - 150) div 50;
    390               Hash2 := FeatureCode * 1611 + Cost;
    391             end;
    392           dSea:
    393             begin
    394               assert(FeatureCode < 1 shl 9);
    395               assert(Attack < 12193);
    396               assert(Defense < 6097);
    397               assert(Cost < 4381);
    398               Hash1 := ((Attack * 6097 + Defense) * 5 + (Speed - 350)
    399                 div 100) * 2;
    400               if Weight >= 6 then
    401                 inc(Hash1);
    402               Hash2 := ((TTrans * 17 + ATrans_Fuel) shl 9 + FeatureCode) *
    403                 4381 + Cost;
    404             end;
    405           dAir:
    406             begin
    407               assert(FeatureCode < 1 shl 5);
    408               assert(Attack < 2407);
    409               assert(Defense < 1605);
    410               assert(Bombs < 4813);
    411               assert(Cost < 2089);
    412               Hash1 := (Attack * 1605 + Defense) shl 5 + FeatureCode;
    413               Hash2 := ((Bombs * 7 + ATrans_Fuel) * 4 + TTrans) * 2089 + Cost;
    414             end;
    415         end;
    416         Hash2r := 0;
    417         for i := 0 to 7 do
    418         begin
    419           Hash2r := Hash2r * 13;
    420           d := Hash2 div 13;
    421           inc(Hash2r, Hash2 - d * 13);
    422           Hash2 := d
    423         end;
    424         result := integer(Domain shl 30 + Hash1 xor Hash2r)
    425       end
    426   end;
    427 
    428   function ProcessEnhancement(uix: integer;
    429     const Jobs: TEnhancementJobs): integer;
     423end;
     424
     425function ProcessEnhancement(uix: integer; const Jobs: TEnhancementJobs): integer;
    430426  { return values:
    431427    eJobDone - all applicable jobs done
    432428    eOK - enhancement not complete
    433429    eDied - job done and died (thurst) }
    434   var
    435     stage, NextJob, Tile: integer;
    436     Done: Set of jNone .. jPoll;
    437   begin
    438     Done := [];
    439     Tile := MyMap[MyUn[uix].Loc];
    440     if Tile and fRoad <> 0 then
    441       include(Done, jRoad);
    442     if Tile and fRR <> 0 then
    443       include(Done, jRR);
    444     if (Tile and fTerImp = tiIrrigation) or (Tile and fTerImp = tiFarm) then
    445       include(Done, jIrr);
    446     if Tile and fTerImp = tiFarm then
    447       include(Done, jFarm);
    448     if Tile and fTerImp = tiMine then
    449       include(Done, jMine);
    450     if Tile and fPoll = 0 then
    451       include(Done, jPoll);
    452 
    453     if MyUn[uix].Job = jNone then
    454       result := eJobDone
    455     else
    456       result := eOK;
    457     while (result <> eOK) and (result <> eDied) do
     430var
     431  stage, NextJob, Tile: integer;
     432  Done: set of jNone .. jPoll;
     433begin
     434  Done := [];
     435  Tile := MyMap[MyUn[uix].Loc];
     436  if Tile and fRoad <> 0 then
     437    include(Done, jRoad);
     438  if Tile and fRR <> 0 then
     439    include(Done, jRR);
     440  if (Tile and fTerImp = tiIrrigation) or (Tile and fTerImp = tiFarm) then
     441    include(Done, jIrr);
     442  if Tile and fTerImp = tiFarm then
     443    include(Done, jFarm);
     444  if Tile and fTerImp = tiMine then
     445    include(Done, jMine);
     446  if Tile and fPoll = 0 then
     447    include(Done, jPoll);
     448
     449  if MyUn[uix].Job = jNone then
     450    Result := eJobDone
     451  else
     452    Result := eOK;
     453  while (Result <> eOK) and (Result <> eDied) do
     454  begin
     455    stage := -1;
     456    repeat
     457      if stage = -1 then
     458        NextJob := jPoll
     459      else
     460        NextJob := Jobs[Tile and fTerrain, stage];
     461      if (NextJob = jNone) or not (NextJob in Done) then
     462        Break;
     463      Inc(stage);
     464    until stage = 5;
     465    if (stage = 5) or (NextJob = jNone) then
    458466    begin
    459       stage := -1;
    460       repeat
    461         if stage = -1 then
    462           NextJob := jPoll
    463         else
    464           NextJob := Jobs[Tile and fTerrain, stage];
    465         if (NextJob = jNone) or not(NextJob in Done) then
    466           Break;
    467         inc(stage);
    468       until stage = 5;
    469       if (stage = 5) or (NextJob = jNone) then
     467      Result := eJobDone;
     468      Break;
     469    end; // tile enhancement complete
     470    Result := Server(sStartJob + NextJob shl 4, me, uix, nil^);
     471    include(Done, NextJob);
     472  end;
     473end;
     474
     475function AutoBuild(cix: integer; const ImpOrder: TImpOrder): boolean;
     476var
     477  i, NewProject: integer;
     478begin
     479  Result := False;
     480  if (MyCity[cix].Project and (cpImp + cpIndex) = cpImp + imTrGoods) or
     481    (MyCity[cix].Flags and chProduction <> 0) then
     482  begin
     483    i := 0;
     484    repeat
     485      while (ImpOrder[i] >= 0) and (MyCity[cix].Built[ImpOrder[i]] > 0) do
     486        Inc(i);
     487      if ImpOrder[i] < 0 then
     488        Break;
     489      assert(i < nImp);
     490      NewProject := cpImp + ImpOrder[i];
     491      if Server(sSetCityProject, me, cix, NewProject) >= rExecuted then
    470492      begin
    471         result := eJobDone;
     493        Result := True;
     494        CityOptimizer_CityChange(cix);
    472495        Break;
    473       end; // tile enhancement complete
    474       result := Server(sStartJob + NextJob shl 4, me, uix, nil^);
    475       include(Done, NextJob)
     496      end;
     497      Inc(i);
     498    until False;
     499  end;
     500end;
     501
     502procedure CalculateAdvValues;
     503var
     504  i, j: integer;
     505  known: array [0 .. nAdv - 1] of integer;
     506
     507  procedure MarkPreqs(i: integer);
     508  begin
     509    if known[i] = 0 then
     510    begin
     511      known[i] := 1;
     512      if (i <> adScience) and (i <> adMassProduction) then
     513      begin
     514        if (AdvPreq[i, 0] >= 0) then
     515          MarkPreqs(AdvPreq[i, 0]);
     516        if (AdvPreq[i, 1] >= 0) then
     517          MarkPreqs(AdvPreq[i, 1]);
     518      end;
    476519    end;
    477520  end;
    478521
    479   function AutoBuild(cix: integer; const ImpOrder: TImpOrder): boolean;
    480   var
    481     i, NewProject: integer;
    482   begin
    483     result := false;
    484     if (MyCity[cix].Project and (cpImp + cpIndex) = cpImp + imTrGoods) or
    485       (MyCity[cix].Flags and chProduction <> 0) then
     522begin
     523  FillChar(AdvValue, SizeOf(AdvValue), 0);
     524  for i := 0 to nAdv - 1 do
     525  begin
     526    FillChar(known, SizeOf(known), 0);
     527    MarkPreqs(i);
     528    for j := 0 to nAdv - 1 do
     529      if known[j] > 0 then
     530        Inc(AdvValue[i]);
     531    if i in FutureTech then
     532      Inc(AdvValue[i], 3000)
     533    else if known[adMassProduction] > 0 then
     534      Inc(AdvValue[i], 2000)
     535    else if known[adScience] > 0 then
     536      Inc(AdvValue[i], 1000);
     537  end;
     538end;
     539
     540procedure DebugMessage(Level: integer; Text: string);
     541begin
     542  Server(sMessage, me, Level, PChar(Text)^);
     543end;
     544
     545function MarkCitiesAround(Loc, cixExcept: integer): boolean;
     546  // return whether a city was marked
     547var
     548  cix: integer;
     549begin
     550  Result := False;
     551  for cix := 0 to MyRO.nCity - 1 do
     552    if (cix <> cixExcept) and (MyCity[cix].Loc >= 0) and
     553      (MyCity[cix].Flags and chCaptured = 0) and
     554      (Distance(MyCity[cix].Loc, Loc) <= 5) then
    486555    begin
    487       i := 0;
    488       repeat
    489         while (ImpOrder[i] >= 0) and (MyCity[cix].Built[ImpOrder[i]] > 0) do
    490           inc(i);
    491         if ImpOrder[i] < 0 then
    492           Break;
    493         assert(i < nImp);
    494         NewProject := cpImp + ImpOrder[i];
    495         if Server(sSetCityProject, me, cix, NewProject) >= rExecuted then
     556      CityNeedsOptimize[cix] := True;
     557      Result := True;
     558    end;
     559end;
     560
     561procedure OptimizeCities(CheckOnly: boolean);
     562var
     563  cix, fix, dx, dy, Loc1, OptiType: integer;
     564  Done: boolean;
     565  Advice: TCityTileAdviceData;
     566begin
     567  repeat
     568    Done := True;
     569    for cix := 0 to MyRO.nCity - 1 do
     570      if CityNeedsOptimize[cix] then
     571      begin
     572        OptiType := (MyCity[cix].Status shr 4) and $0F;
     573        if OptiType <> 0 then
    496574        begin
    497           result := true;
    498           CityOptimizer_CityChange(cix);
    499           Break;
     575          Advice.ResourceWeights := OfferedResourceWeights[OptiType];
     576          Server(sGetCityTileAdvice, me, cix, Advice);
     577          if Advice.Tiles <> MyCity[cix].Tiles then
     578            if CheckOnly then
     579            begin
     580              // TODO: What is this assert for?
     581              // Need to optimize city tiles but CheckOnly true?
     582              //assert(false)
     583            end
     584            else
     585            begin
     586              for fix := 1 to 26 do
     587                if MyCity[cix].Tiles and not Advice.Tiles and
     588                  (1 shl fix) <> 0 then
     589                begin // tile no longer used by this city -- check using it by another
     590                  dy := fix shr 2 - 3;
     591                  dx := fix and 3 shl 1 - 3 + (dy + 3) and 1;
     592                  Loc1 := dLoc(MyCity[cix].Loc, dx, dy);
     593                  if MarkCitiesAround(Loc1, cix) then
     594                    Done := False;
     595                end;
     596              Server(sSetCityTiles, me, cix, Advice.Tiles);
     597            end;
    500598        end;
    501         inc(i);
    502       until false end end;
    503 
    504       procedure CalculateAdvValues;
    505       var
    506         i, j: integer;
    507         known: array [0 .. nAdv - 1] of integer;
    508 
    509         procedure MarkPreqs(i: integer);
    510         begin
    511           if known[i] = 0 then
    512           begin
    513             known[i] := 1;
    514             if (i <> adScience) and (i <> adMassProduction) then
    515             begin
    516               if (AdvPreq[i, 0] >= 0) then
    517                 MarkPreqs(AdvPreq[i, 0]);
    518               if (AdvPreq[i, 1] >= 0) then
    519                 MarkPreqs(AdvPreq[i, 1]);
    520             end
    521           end
    522         end;
    523 
     599        CityNeedsOptimize[cix] := False;
     600      end;
     601  until Done;
     602end;
     603
     604procedure CityOptimizer_BeginOfTurn;
     605var
     606  cix: integer;
     607begin
     608  FillChar(CityNeedsOptimize, MyRO.nCity - 1, 0); // false
     609  if MyRO.Government <> gAnarchy then
     610  begin
     611    for cix := 0 to MyRO.nCity - 1 do
     612      if (MyCity[cix].Loc >= 0) and (MyCity[cix].Flags and chCaptured = 0)
     613      then
     614        CityNeedsOptimize[cix] := True;
     615    OptimizeCities(False); // optimize all cities
     616  end;
     617end;
     618
     619procedure CityOptimizer_CityChange(cix: integer);
     620begin
     621  if (MyRO.Government <> gAnarchy) and (MyCity[cix].Flags and
     622    chCaptured = 0) then
     623  begin
     624    CityNeedsOptimize[cix] := True;
     625    OptimizeCities(False);
     626  end;
     627end;
     628
     629procedure CityOptimizer_TileBecomesAvailable(Loc: integer);
     630begin
     631  if (MyRO.Government <> gAnarchy) and MarkCitiesAround(Loc, -1) then
     632    OptimizeCities(False);
     633end;
     634
     635procedure CityOptimizer_ReleaseCityTiles(cix, ReleasedTiles: integer);
     636var
     637  fix, dx, dy, Loc1: integer;
     638  Done: boolean;
     639begin
     640  if (MyRO.Government <> gAnarchy) and (ReleasedTiles <> 0) then
     641  begin
     642    Done := True;
     643    for fix := 1 to 26 do
     644      if ReleasedTiles and (1 shl fix) <> 0 then
    524645      begin
    525         FillChar(AdvValue, SizeOf(AdvValue), 0);
    526         for i := 0 to nAdv - 1 do
    527         begin
    528           FillChar(known, SizeOf(known), 0);
    529           MarkPreqs(i);
    530           for j := 0 to nAdv - 1 do
    531             if known[j] > 0 then
    532               inc(AdvValue[i]);
    533           if i in FutureTech then
    534             inc(AdvValue[i], 3000)
    535           else if known[adMassProduction] > 0 then
    536             inc(AdvValue[i], 2000)
    537           else if known[adScience] > 0 then
    538             inc(AdvValue[i], 1000)
    539         end;
     646        dy := fix shr 2 - 3;
     647        dx := fix and 3 shl 1 - 3 + (dy + 3) and 1;
     648        Loc1 := dLoc(MyCity[cix].Loc, dx, dy);
     649        if MarkCitiesAround(Loc1, cix) then
     650          Done := False;
    540651      end;
    541 
    542       procedure DebugMessage(Level: integer; Text: string);
    543       begin
    544         Server(sMessage, me, Level, pchar(Text)^)
    545       end;
    546 
    547       function MarkCitiesAround(Loc, cixExcept: integer): boolean;
    548       // return whether a city was marked
    549       var
    550         cix: integer;
    551       begin
    552         result := false;
    553         for cix := 0 to MyRO.nCity - 1 do
    554           if (cix <> cixExcept) and (MyCity[cix].Loc >= 0) and
    555             (MyCity[cix].Flags and chCaptured = 0) and
    556             (Distance(MyCity[cix].Loc, Loc) <= 5) then
    557           begin
    558             CityNeedsOptimize[cix] := true;
    559             result := true;
    560           end
    561       end;
    562 
    563       procedure OptimizeCities(CheckOnly: boolean);
    564       var
    565         cix, fix, dx, dy, Loc1, OptiType: integer;
    566         Done: boolean;
    567         Advice: TCityTileAdviceData;
    568       begin
    569         repeat
    570           Done := true;
    571           for cix := 0 to MyRO.nCity - 1 do
    572             if CityNeedsOptimize[cix] then begin
    573               OptiType := (MyCity[cix].Status shr 4) and $0F;
    574               if OptiType <> 0 then begin
    575                 Advice.ResourceWeights := OfferedResourceWeights[OptiType];
    576                 Server(sGetCityTileAdvice, me, cix, Advice);
    577                 if Advice.Tiles <> MyCity[cix].Tiles then
    578                   if CheckOnly then begin
    579                     // TODO: What is this assert for?
    580                     // Need to optimize city tiles but CheckOnly true?
    581                     //assert(false)
    582                   end else begin
    583                     for fix := 1 to 26 do
    584                       if MyCity[cix].Tiles and not Advice.Tiles and
    585                         (1 shl fix) <> 0 then
    586                       begin // tile no longer used by this city -- check using it by another
    587                         dy := fix shr 2 - 3;
    588                         dx := fix and 3 shl 1 - 3 + (dy + 3) and 1;
    589                         Loc1 := dLoc(MyCity[cix].Loc, dx, dy);
    590                         if MarkCitiesAround(Loc1, cix) then
    591                           Done := false;
    592                       end;
    593                     Server(sSetCityTiles, me, cix, Advice.Tiles);
    594                   end;
    595               end;
    596               CityNeedsOptimize[cix] := false;
    597             end;
    598         until Done;
    599       end;
    600 
    601       procedure CityOptimizer_BeginOfTurn;
    602       var
    603         cix: integer;
    604       begin
    605         FillChar(CityNeedsOptimize, MyRO.nCity - 1, 0); // false
    606         if MyRO.Government <> gAnarchy then
    607         begin
    608           for cix := 0 to MyRO.nCity - 1 do
    609             if (MyCity[cix].Loc >= 0) and (MyCity[cix].Flags and chCaptured = 0)
    610             then
    611               CityNeedsOptimize[cix] := true;
    612           OptimizeCities(false); // optimize all cities
    613         end
    614       end;
    615 
    616       procedure CityOptimizer_CityChange(cix: integer);
    617       begin
    618         if (MyRO.Government <> gAnarchy) and
    619           (MyCity[cix].Flags and chCaptured = 0) then
    620         begin
    621           CityNeedsOptimize[cix] := true;
    622           OptimizeCities(false);
    623         end
    624       end;
    625 
    626       procedure CityOptimizer_TileBecomesAvailable(Loc: integer);
    627       begin
    628         if (MyRO.Government <> gAnarchy) and MarkCitiesAround(Loc, -1) then
    629           OptimizeCities(false);
    630       end;
    631 
    632       procedure CityOptimizer_ReleaseCityTiles(cix, ReleasedTiles: integer);
    633       var
    634         fix, dx, dy, Loc1: integer;
    635         Done: boolean;
    636       begin
    637         if (MyRO.Government <> gAnarchy) and (ReleasedTiles <> 0) then
    638         begin
    639           Done := true;
    640           for fix := 1 to 26 do
    641             if ReleasedTiles and (1 shl fix) <> 0 then
    642             begin
    643               dy := fix shr 2 - 3;
    644               dx := fix and 3 shl 1 - 3 + (dy + 3) and 1;
    645               Loc1 := dLoc(MyCity[cix].Loc, dx, dy);
    646               if MarkCitiesAround(Loc1, cix) then
    647                 Done := false;
    648             end;
    649           if not Done then
    650             OptimizeCities(false);
    651         end
    652       end;
    653 
    654       procedure CityOptimizer_BeforeRemoveUnit(uix: integer);
    655       var
    656         uix1: integer;
    657       begin
    658         if MyRO.Government <> gAnarchy then
    659         begin
    660           if MyUn[uix].Home >= 0 then
    661             CityNeedsOptimize[MyUn[uix].Home] := true;
    662 
    663           // transported units are also removed
    664           for uix1 := 0 to MyRO.nUn - 1 do
    665             if (MyUn[uix1].Loc >= 0) and (MyUn[uix1].Master = uix) and
    666               (MyUn[uix1].Home >= 0) then
    667               CityNeedsOptimize[MyUn[uix1].Home] := true;
    668         end
    669       end;
    670 
    671       procedure CityOptimizer_AfterRemoveUnit;
    672       begin
    673         if MyRO.Government <> gAnarchy then
    674           OptimizeCities(false);
    675       end;
    676 
    677       procedure CityOptimizer_EndOfTurn;
    678       // all cities should already be optimized here -- only check this
    679       var
    680         cix: integer;
    681       begin
     652    if not Done then
     653      OptimizeCities(False);
     654  end;
     655end;
     656
     657procedure CityOptimizer_BeforeRemoveUnit(uix: integer);
     658var
     659  uix1: integer;
     660begin
     661  if MyRO.Government <> gAnarchy then
     662  begin
     663    if MyUn[uix].Home >= 0 then
     664      CityNeedsOptimize[MyUn[uix].Home] := True;
     665
     666    // transported units are also removed
     667    for uix1 := 0 to MyRO.nUn - 1 do
     668      if (MyUn[uix1].Loc >= 0) and (MyUn[uix1].Master = uix) and
     669        (MyUn[uix1].Home >= 0) then
     670        CityNeedsOptimize[MyUn[uix1].Home] := True;
     671  end;
     672end;
     673
     674procedure CityOptimizer_AfterRemoveUnit;
     675begin
     676  if MyRO.Government <> gAnarchy then
     677    OptimizeCities(False);
     678end;
     679
     680procedure CityOptimizer_EndOfTurn;
     681// all cities should already be optimized here -- only check this
     682var
     683  cix: integer;
     684begin
    682685{$IFOPT O-}
    683         if MyRO.Government <> gAnarchy then
    684         begin
    685           FillChar(CityNeedsOptimize, MyRO.nCity - 1, 0); // false
    686           for cix := 0 to MyRO.nCity - 1 do
    687             if (MyCity[cix].Loc >= 0) and (MyCity[cix].Flags and chCaptured = 0)
    688             then
    689               CityNeedsOptimize[cix] := true;
    690           OptimizeCities(true); // check all cities
    691         end;
     686  if MyRO.Government <> gAnarchy then
     687  begin
     688    FillChar(CityNeedsOptimize, MyRO.nCity - 1, 0); // false
     689    for cix := 0 to MyRO.nCity - 1 do
     690      if (MyCity[cix].Loc >= 0) and (MyCity[cix].Flags and chCaptured = 0)
     691      then
     692        CityNeedsOptimize[cix] := True;
     693    OptimizeCities(True); // check all cities
     694  end;
    692695{$ENDIF}
    693       end;
     696end;
    694697
    695698initialization
    696699
    697 Assert(nImp < 128);
    698 CalculateAdvValues;
     700  Assert(nImp < 128);
     701  CalculateAdvValues;
    699702
    700703end.
  • branches/highdpi/LocalPlayer/Draft.pas

    r210 r303  
    9292  Template := TDpiBitmap.Create;
    9393  Template.PixelFormat := pf24bit;
    94   LoadGraphicFile(Template, GetGraphicsDir + DirectorySeparator + 'MiliRes.png', gfNoGamma);
     94  LoadGraphicFile(Template, GetGraphicsDir + DirectorySeparator + 'MiliRes.png',
     95    [gfNoGamma]);
    9596end;
    9697
  • branches/highdpi/LocalPlayer/Enhance.pas

    r244 r303  
    366366  Shift: TShiftState);
    367367begin
    368   if Key = VK_ESCAPE then
    369     Close
    370   else if Key = VK_F1 then
     368  if Key = VK_F1 then
    371369    HelpDlg.ShowNewContent(FWindowMode or wmPersistent, hkText,
    372370      HelpDlg.TextIndex('MACRO'))
  • branches/highdpi/LocalPlayer/Help.pas

    r265 r303  
    127127
    128128uses
    129   Directories, ClientTools, Term, Tribes, Inp, Messg, UPixelPointer, Global;
     129  Directories, ClientTools, Term, Tribes, Inp, Messg, UPixelPointer, Global,
     130  UKeyBindings;
    130131
    131132{$R *.lfm}
     
    207208destructor THyperText.Destroy;
    208209begin
    209   inherited Destroy;
     210  inherited;
    210211end;
    211212
     
    12421243      until FindNext(sr) <> 0;
    12431244    FindClose(sr);
    1244     Plus.Free;
     1245    FreeAndNil(Plus);
    12451246
    12461247    List.Sort;
     
    12591260      MainText.AddLine(s);
    12601261    end;
    1261     List.Free;
     1262    FreeAndNil(List);
    12621263  end;
    12631264
     
    12771278      MainText.AddLine(s);
    12781279    end;
    1279     List.Free;
     1280    FreeAndNil(List);
    12801281  end;
    12811282
     
    14391440            AppendList(List);
    14401441          end;
    1441           List.Free;
     1442          FreeAndNil(List);
    14421443        end
    14431444        else // single advance
     
    15381539          List.Sort;
    15391540          AppendList(List);
    1540           List.Free;
     1541          FreeAndNil(List);
    15411542        end
    15421543        else if no = 201 then
     
    18271828            AppendList(List);
    18281829          end;
    1829           List.Free;
     1830          FreeAndNil(List);
    18301831        end
    18311832        else
     
    19881989    OffscreenPaint;
    19891990    Invalidate;
    1990     HistItem.Free;
     1991    FreeAndNil(HistItem);
    19911992  end;
    19921993end;
     
    20162017  Shift: TShiftState);
    20172018begin
    2018   if Key = VK_F1 then // my key
     2019  if KeyToShortCut(Key, Shift) = BHelp.ShortCut then // my key
    20192020  else
    2020     inherited
     2021    inherited;
    20212022end;
    20222023
  • branches/highdpi/LocalPlayer/IsoEngine.pas

    r265 r303  
    133133  OnInitEnemyModel := InitEnemyModelHandler;
    134134  if NoMap <> nil then
    135     NoMap.Free;
     135    FreeAndNil(NoMap);
    136136  NoMap := TIsoMap.Create;
    137137end;
     
    168168  { prepare dithered ground tiles }
    169169  if LandPatch <> nil then
    170     LandPatch.Free;
     170    FreeAndNil(LandPatch);
    171171  LandPatch := TDpiBitmap.Create;
    172172  LandPatch.PixelFormat := pf24bit;
     
    175175  LandPatch.Canvas.FillRect(0, 0, LandPatch.Width, LandPatch.Height);
    176176  if OceanPatch <> nil then
    177     OceanPatch.Free;
     177    FreeAndNil(OceanPatch);
    178178  OceanPatch := TDpiBitmap.Create;
    179179  OceanPatch.PixelFormat := pf24bit;
     
    363363      DitherMask.Canvas, 0, 0, SRCAND);
    364364
    365   LandMore.Free;
    366   OceanMore.Free;
    367   DitherMask.Free;
     365  FreeAndNil(LandMore);
     366  FreeAndNil(OceanMore);
     367  FreeAndNil(DitherMask);
    368368
    369369  // reduce size of terrain icons
     
    417417  end;
    418418  Mask24.EndUpdate;
    419   Mask24.Free;
     419  FreeAndNil(Mask24);
    420420
    421421  if Borders <> nil then
    422     Borders.Free;
     422    FreeAndNil(Borders);
    423423  Borders := TDpiBitmap.Create;
    424424  Borders.PixelFormat := pf24bit;
     
    702702    end;
    703703    Textout(xShield + 2, yShield - 1, LabelTextColor, s);
    704   end
     704  end;
    705705end; { PaintCity }
    706706
     
    10781078  if not(FoW and (Tile and fObserved = 0)) then
    10791079    PaintBorder;
     1080
    10801081  if (Loc >= 0) and (Loc < G.lx * G.ly) and (Loc = FAdviceLoc) then
    10811082    TSprite(x, y, spPlain);
     
    12871288  i: integer;
    12881289begin
    1289   FOutput.Canvas.pen.Color := $000000; // $FF shl (8*random(3));
    12901290  FOutput.Canvas.pen.Color := $000000; // $FF shl (8*random(3));
    12911291  for i := 0 to nx div 2 do
  • branches/highdpi/LocalPlayer/MessgEx.pas

    r253 r303  
    218218  end
    219219  else
    220     result := inherited ShowModal;
     220    result := inherited;
    221221end;
    222222
  • branches/highdpi/LocalPlayer/NatStat.pas

    r244 r303  
    9393  Template := TDpiBitmap.Create;
    9494  Template.PixelFormat := pf24bit;
    95   LoadGraphicFile(Template, GetGraphicsDir + DirectorySeparator + 'Nation.png', gfNoGamma);
     95  LoadGraphicFile(Template, GetGraphicsDir + DirectorySeparator + 'Nation.png',
     96    [gfNoGamma]);
    9697end;
    9798
    9899procedure TNatStatDlg.FormDestroy(Sender: TObject);
    99100begin
    100   ReportText.Free;
     101  FreeAndNil(ReportText);
    101102  FreeMem(SelfReport);
    102   Template.Free;
    103   Back.Free;
     103  FreeAndNil(Template);
     104  FreeAndNil(Back);
    104105end;
    105106
  • branches/highdpi/LocalPlayer/Select.pas

    r273 r303  
    16051605  CaptionRight := CloseBtn.Left;
    16061606  { TODO:
    1607   SetWindowPos(sb.ScrollBar.Handle, 0, SideFrame + InnerWidth - GetSystemMetrics(SM_CXVSCROLL),
     1607  SetWindowPos(sb.ScrollBar.Handle, 0, SideFrame + InnerWidth - DpiGetSystemMetrics(SM_CXVSCROLL),
    16081608    TitleHeight, DpiGetSystemMetrics(SM_CXVSCROLL), LineDistance * DispLines + 48,
    16091609    SWP_NOZORDER or SWP_NOREDRAW);
  • branches/highdpi/LocalPlayer/TechTree.pas

    r246 r303  
    2323      Shift: TShiftState; X, Y: Integer);
    2424    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    25     procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    2625    procedure CloseBtnClick(Sender: TObject);
    2726  private
     
    133132  NewHeight: Integer;
    134133const
    135   TransparentColor = $7F007F;
     134  TransparentColor: Cardinal = $7F007F;
    136135begin
    137136  if Image = nil then begin
    138137    Image := TDpiBitmap.Create;
    139138    Image.PixelFormat := pf24bit;
    140     LoadGraphicFile(Image, HomeDir + 'Help' + DirectorySeparator + 'AdvTree.png', gfNoGamma);
     139    LoadGraphicFile(Image, HomeDir + 'Help' + DirectorySeparator + 'AdvTree.png',
     140      [gfNoGamma]);
    141141
    142142    with Image.Canvas do begin
     
    228228end;
    229229
    230 procedure TTechTreeDlg.FormKeyDown(Sender: TObject; var Key: Word;
    231   Shift: TShiftState);
    232 begin
    233   if Key = VK_ESCAPE then
    234     Close;
    235 end;
    236 
    237230procedure TTechTreeDlg.CloseBtnClick(Sender: TObject);
    238231begin
  • branches/highdpi/LocalPlayer/Term.pas

    r265 r303  
    235235    Closable, RepaintOnResize, Tracking, TurnComplete, Edited, GoOnPhase,
    236236      HaveStrategyAdvice, FirstMovieTurn: boolean;
     237    PrevWindowState: TWindowState;
     238    CurrentWindowState: TWindowState;
    237239    function ChooseUnusedTribe: integer;
    238240    procedure GetTribeList;
     
    283285    procedure OnEOT(var Msg: TMessage); message WM_EOT;
    284286    procedure SoundPreload(Check: integer);
     287    procedure UpdateKeyShortcuts;
     288    procedure SetFullScreen(Active: Boolean);
    285289  public
    286290    UsedOffscreenWidth, UsedOffscreenHeight: integer;
     
    307311    FileName: ShortString;
    308312  end;
    309 
    310313  TCityNameInfo = record
    311314    ID: integer;
    312     NewName: ShortString end;
    313     TModelNameInfo = record mix: integer;
    314     NewName: ShortString end;
    315     TPriceSet = Set of $00 .. $FF;
     315    NewName: ShortString;
     316  end;
     317  TModelNameInfo = record
     318    mix: integer;
     319    NewName: ShortString;
     320  end;
     321  TPriceSet = Set of $00 .. $FF;
    316322
    317323const
     
    481487  Directories, IsoEngine, CityScreen, Draft, MessgEx, Select, CityType, Help,
    482488  UnitStat, Log, Diagram, NatStat, Wonders, Enhance, Nego, UPixelPointer, Sound,
    483   Battle, Rates, TechTree, Registry, Global;
     489  Battle, Rates, TechTree, Registry, Global, UKeyBindings;
    484490
    485491{$R *.lfm}
     
    531537  SmallScreen, GameOK, MapValid, skipped, idle: boolean;
    532538
    533   SaveOption: array [0 .. nSaveOption - 1] of integer;
    534   MiniColors: array [0 .. $1f, 0 .. 1] of TColor;
     539  SaveOption: array [0..nSaveOption - 1] of integer;
     540  MiniColors: array [0..11, 0..1] of TColor;
    535541  MainMap: TIsoMap;
    536542  CurrentMoveInfo: record AfterMovePaintRadius, AfterAttackExpeller: integer;
     
    551557procedure InitSmallImp;
    552558const
    553   cut = 4;
     559  Cut = 4;
    554560  Sharpen = 80;
    555561type
     
    742748    ChooseModelPicture(Owner, mix, ModelCode(MyRO.EnemyModel[emix]),
    743749      ModelHash(MyRO.EnemyModel[emix]), MyRO.Turn, false, true);
    744   result := true
     750  result := true;
    745751end;
    746752
     
    786792function CreateTribe(p: integer; FileName: string; Original: boolean): boolean;
    787793begin
    788   if not FileExists(LocalizedFilePath('Tribes' + DirectorySeparator + FileName +
    789     '.tribe.txt')) then
    790   begin
    791     result := false;
    792     exit
     794  FileName := LocalizedFilePath('Tribes' + DirectorySeparator + FileName +
     795    CevoTribeExt);
     796  if not FileExists(FileName) then
     797  begin
     798    Result := False;
     799    Exit;
    793800  end;
    794801
     
    879886            MyModel[mix].Status := MyModel[mix].Status or msObsolete;
    880887      end;
    881       inc(MyData.ToldModels)
     888      inc(MyData.ToldModels);
    882889    end;
    883890end;
     
    11231130      if UnitStatDlg.Visible then
    11241131        UnitStatDlg.Close;
    1125     end
    1126   end
     1132    end;
     1133  end;
    11271134end;
    11281135
     
    11511158      if UnitStatDlg.Visible then
    11521159        UnitStatDlg.Close;
    1153     end
    1154   end
     1160    end;
     1161  end;
    11551162end;
    11561163
     
    11751182        UnFocus := -1;
    11761183        PaintLoc(Loc0);
    1177       end
     1184      end;
    11781185    end;
    11791186    UnFocus := uix;
     
    12201227    MovieSpeed3Btn.Visible := false;
    12211228    MovieSpeed4Btn.Visible := false;
    1222   end
     1229  end;
    12231230end;
    12241231
     
    12481255    if AILogo[p] <> nil then
    12491256    begin
    1250       AILogo[p].free;
    1251       AILogo[p] := nil
    1252     end
     1257      FreeAndNil(AILogo[p]);
     1258    end;
    12531259  end
    12541260  else
     
    12561262    if AILogo[p] = nil then
    12571263      AILogo[p] := TDpiBitmap.Create;
    1258     if not LoadGraphicFile(AILogo[p], HomeDir + Name + '.png', gfNoError) then
    1259     begin
    1260       AILogo[p].free;
    1261       AILogo[p] := nil
    1262     end
    1263   end
     1264    if not LoadGraphicFile(AILogo[p], HomeDir + Name + '.png', [gfNoError]) then
     1265    begin
     1266      FreeAndNil(AILogo[p]);
     1267    end;
     1268  end;
    12641269end;
    12651270
     
    12961301      MapValid := false;
    12971302      PaintAllMaps;
    1298     end
    1299   end
     1303    end;
     1304  end;
    13001305end;
    13011306
     
    14151420begin
    14161421  UnusedTribeFiles.Clear;
    1417   ok := FindFirst(LocalizedFilePath('Tribes') + DirectorySeparator + '*.tribe.txt',
     1422  ok := FindFirst(LocalizedFilePath('Tribes') + DirectorySeparator + '*' + CevoTribeExt,
    14181423    faArchive + faReadOnly, SearchRec) = 0;
    14191424  if not ok then
    14201425  begin
    14211426    FindClose(SearchRec);
    1422     ok := FindFirst(LocalizedFilePath('Tribes' + DirectorySeparator + '*.tribe.txt'),
     1427    ok := FindFirst(LocalizedFilePath('Tribes' + DirectorySeparator + '*' + CevoTribeExt),
    14231428      faArchive + faReadOnly, SearchRec) = 0;
    14241429  end;
    14251430  if ok then
    14261431    repeat
    1427       SearchRec.Name := Copy(SearchRec.Name, 1, Length(SearchRec.Name) - 10);
     1432      SearchRec.Name := Copy(SearchRec.Name, 1, Length(SearchRec.Name) - Length(CevoTribeExt));
    14281433      if GetTribeInfo(SearchRec.Name, Name, Color) then
    14291434        UnusedTribeFiles.AddObject(SearchRec.Name, TObject(Color));
     
    14341439function TMainScreen.ChooseUnusedTribe: integer;
    14351440var
    1436   i, j, ColorDistance, BestColorDistance, TestColorDistance,
    1437     CountBest: integer;
     1441  i: Integer;
     1442  j: Integer;
     1443  ColorDistance: Integer;
     1444  BestColorDistance: Integer;
     1445  TestColorDistance: Integer;
     1446  CountBest: Integer;
    14381447begin
    14391448  assert(UnusedTribeFiles.Count > 0);
     
    14651474      if DelphiRandom(CountBest) = 0 then
    14661475        result := j
    1467     end
     1476    end;
    14681477  end;
    14691478end;
     
    15231532          IconKind := mikShip;
    15241533          IconIndex := Ship2Owner;
    1525         end
     1534        end;
    15261535    end;
    15271536
     
    15361545          MostCost := TestCost;
    15371546          IconIndex := imShipComp + i
    1538         end
     1547        end;
    15391548      end;
    15401549    end;
     
    16191628  sb := TPVScrollbar.Create(Self);
    16201629  sb.OnUpdate := ScrollBarUpdate;
    1621 end; { InitModule }
     1630end;
    16221631
    16231632procedure TMainScreen.InitTurn(NewPlayer: integer);
     
    22372246                    Flags and CityRepMask);
    22382247                  UpdatePanel := true;
    2239                 end
     2248                end;
    22402249              end
    22412250              else { if mRepList.Checked then }
     
    22432252                if Flags and CityRepMask <> 0 then
    22442253                  ShowCityList := true
    2245               end
    2246             end
     2254              end;
     2255            end;
    22472256          end; { city loop }
    22482257  end; // ClientMode=cTurn
     
    22632272          Play('REVOLUTION');
    22642273          Server(sRevolution, me, 0, nil^);
    2265         end
     2274        end;
    22662275      end;
    22672276  end; // ClientMode=cTurn
     
    23822391                else
    23832392                  Status := Status and not usWaiting;
    2384             end
     2393            end;
    23852394          end;
    23862395  end; // ClientMode=cTurn
     
    24802489              opAllModel:
    24812490                s := s + 'All models';
    2482             end
     2491            end;
    24832492          end;
    24842493          LogDlg.Add(NewPlayer, G.RO[0].Turn, pchar(s));
     
    24882497          s := s + '--- ACCEPTED! ---';
    24892498          LogDlg.Add(NewPlayer, G.RO[0].Turn, pchar(s));
    2490         end
     2499        end;
    24912500      end;
    24922501
     
    25022511    cReleaseModule:
    25032512      begin
    2504         SmallImp.free;
    2505         UnusedTribeFiles.free;
    2506         TribeNames.free;
    2507         MainMap.free;
     2513        FreeAndNil(SmallImp);
     2514        FreeAndNil(UnusedTribeFiles);
     2515        FreeAndNil(TribeNames);
     2516        FreeAndNil(MainMap);
    25082517        IsoEngine.Done;
    25092518        // AdvisorDlg.DeInit;
     
    27032712        for p1 := 0 to nPl - 1 do
    27042713          if Tribe[p1] <> nil then
    2705             Tribe[p1].free;
     2714            FreeAndNil(Tribe[p1]);
    27062715        Tribes.Done;
    27072716        RepaintOnResize := false;
     
    28442853          // this break will ensure speed of fast forward does not depend on cpu speed
    28452854          DpiApplication.ProcessMessages;
    2846         end
     2855        end;
    28472856      end;
    28482857
     
    29232932              DipCall(scReject);
    29242933              EndNego
    2925             end
    2926           end
     2934            end;
     2935          end;
    29272936        end;
    29282937      end;
     
    34103419  i, j: integer;
    34113420begin
     3421  KeyBindings.LoadFromRegistry(HKEY_CURRENT_USER, AppRegistryKey + '\KeyBindings');
     3422  UpdateKeyShortcuts;
     3423
    34123424  MainFormKeyDown := FormKeyDown;
    34133425  BaseWin.CreateOffscreen(Offscreen);
     
    35123524  I: Integer;
    35133525begin
     3526  KeyBindings.SaveToRegistry(HKEY_CURRENT_USER, AppRegistryKey + '\KeyBindings');
    35143527  MainFormKeyDown := nil;
    35153528  FreeAndNil(sb);
     
    36153628    RectInvalidate(0, TopBarHeight, ClientWidth, TopBarHeight + MapHeight);
    36163629    MapValid := false;
    3617     PaintAll
    3618   end
     3630    PaintAll;
     3631  end;
    36193632end;
    36203633
     
    36233636  CanClose := Closable;
    36243637  if not Closable and idle and (me = 0) and (ClientMode < scContact) then
    3625     MenuClick(mResign)
     3638    MenuClick(mResign);
    36263639end;
    36273640
     
    40614074var
    40624075  uix, cix, x, y, Loc, i, hw, xm, cm, cmPolOcean, cmPolNone: integer;
    4063   PrevMiniPixel, MiniPixel: TPixelPointer;
     4076  PrevMiniPixel: TPixelPointer;
     4077  MiniPixel: TPixelPointer;
     4078  TerrainTile: Cardinal;
    40644079begin
    40654080  cmPolOcean := GrExt[HGrSystem].Data.Canvas.Pixels[101, 67];
     
    40854100            ScaleToNative(G.lx) * 5) mod (ScaleToNative(G.lx) * 2);
    40864101          MiniPixel.SetXY(xm, y);
    4087           cm := MiniColors[MyMap[Loc] and fTerrain, i];
     4102          TerrainTile := MyMap[Loc] and fTerrain;
     4103          if TerrainTile > 11 then TerrainTile := 0;
     4104          cm := MiniColors[TerrainTile, i];
    40884105          if ClientMode = cEditMap then
    40894106          begin
     
    64226439    MapValid := false;
    64236440    PaintAllMaps;
    6424   end
     6441  end;
     6442end;
     6443
     6444procedure TMainScreen.UpdateKeyShortcuts;
     6445begin
     6446  mHelp.ShortCut := BHelp.ShortCut;
     6447  mUnitStat.ShortCut := BUnitStat.ShortCut;
     6448  mCityStat.ShortCut := BCityStat.ShortCut;
     6449  mScienceStat.ShortCut := BScienceStat.ShortCut;
     6450  mEUnitStat.ShortCut := BEUnitStat.ShortCut;;
     6451  mDiagram.ShortCut := BDiagram.ShortCut;
     6452  mWonders.ShortCut := BWonders.ShortCut;
     6453  mShips.ShortCut := BShips.ShortCut;
     6454  mNations.ShortCut := BNations.ShortCut;
     6455  mEmpire.ShortCut := BEmpire.ShortCut;
     6456  mResign.ShortCut := BResign.ShortCut;
     6457  mRandomMap.ShortCut := BRandomMap.ShortCut;
     6458  mDisband.ShortCut := BDisbandUnit.ShortCut;
     6459  mFort.ShortCut := BFortify.ShortCut;
     6460  mCentre.ShortCut := BCenterUnit.ShortCut;
     6461  mStay.ShortCut := BStay.ShortCut;
     6462  mNoOrders.ShortCut := BNoOrders.ShortCut;
     6463  mCancel.ShortCut := BCancel.ShortCut;
     6464  mPillage.ShortCut := BPillage.ShortCut;
     6465  mTechTree.ShortCut := BTechTree.ShortCut;
     6466  mWait.ShortCut := BWait.ShortCut;
     6467  mJump.ShortCut := BJump.ShortCut;;
     6468  mDebugMap.ShortCut := BDebugMap.ShortCut;
     6469  mLocCodes.ShortCut := BLocCodes.ShortCut;
     6470  mNames.ShortCut := BNames.ShortCut;
     6471  mRun.ShortCut := BRun.ShortCut;
     6472  mAirBase.ShortCut := BAirBase.ShortCut;
     6473  mCity.ShortCut := BBuildCity.ShortCut;
     6474  mEnhance.ShortCut := BEnhance.ShortCut;
     6475  mGoOn.ShortCut := BGoOn.ShortCut;
     6476  mHome.ShortCut := BHome.ShortCut;
     6477  mFarm.ShortCut := BFarmClearIrrigation.ShortCut;
     6478  mClear.ShortCut := BFarmClearIrrigation.ShortCut;
     6479  mIrrigation.ShortCut := BFarmClearIrrigation.ShortCut;
     6480  mLoad.ShortCut := BLoad.ShortCut;
     6481  mAfforest.ShortCut := BAfforestMine.ShortCut;
     6482  mMine.ShortCut := BAfforestMine.ShortCut;
     6483  mCanal.ShortCut := BCanal.ShortCut;
     6484  MTrans.ShortCut := BTrans.ShortCut;
     6485  mPollution.ShortCut := BPollution.ShortCut;
     6486  mRR.ShortCut := BRailRoad.ShortCut;
     6487  mRoad.ShortCut := BRailRoad.ShortCut;
     6488  mUnload.ShortCut := BUnload.ShortCut;
     6489  mRecover.ShortCut := BRecover.ShortCut;
     6490  mUtilize.ShortCut := BUtilize.ShortCut;
     6491end;
     6492
     6493procedure TMainScreen.SetFullScreen(Active: Boolean);
     6494begin
     6495    if Active and (CurrentWindowState <> wsFullScreen) then begin
     6496      PrevWindowState := WindowState;
     6497      CurrentWindowState := wsFullScreen;
     6498      WindowState := CurrentWindowState;
     6499      {$IFDEF WINDOWS}
     6500      BorderStyle := bsNone;
     6501      {$ENDIF}
     6502      BorderIcons := [];
     6503    end else
     6504    if not Active and (CurrentWindowState = wsFullScreen) then begin
     6505      if PrevWindowState = wsMaximized then begin
     6506        CurrentWindowState := wsMaximized;
     6507        WindowState := CurrentWindowState;
     6508      end else begin
     6509        CurrentWindowState := wsNormal;
     6510        WindowState := CurrentWindowState;
     6511        WindowState := wsFullScreen;
     6512        WindowState := CurrentWindowState;
     6513      end;
     6514      {$IFDEF WINDOWS}
     6515      BorderStyle := bsSizeable;
     6516      {$ENDIF}
     6517      BorderIcons := [biSystemMenu, biMinimize, biMaximize];
     6518    end;
    64256519end;
    64266520
     
    64356529  end;
    64366530
     6531  procedure SetViewpointMe(p: Integer);
     6532  begin
     6533    if p = me then SetViewpoint(p)
     6534      else SetViewpoint(p);
     6535  end;
     6536
     6537  procedure DoMoveUnit(X, Y: Integer);
     6538  begin
     6539    DestinationMarkON := False;
     6540    PaintDestination;
     6541    MyUn[UnFocus].Status := MyUn[UnFocus].Status and
     6542      ($FFFF - usStay - usRecover - usGoto - usEnhance) or usWaiting;
     6543    MoveUnit(X, Y, muAutoNext);
     6544  end;
     6545
    64376546var
    6438   dx, dy: integer;
    6439   time0, time1: TDateTime;
    6440 begin
    6441   if GameMode = cMovie then
    6442   begin
    6443     case Key of
    6444       VK_F4:
    6445         MenuClick_Check(StatPopup, mScienceStat);
    6446       VK_F6:
    6447         MenuClick_Check(StatPopup, mDiagram);
    6448       VK_F7:
    6449         MenuClick_Check(StatPopup, mWonders);
    6450       VK_F8:
    6451         MenuClick_Check(StatPopup, mShips);
    6452     end;
    6453     exit;
    6454   end;
    6455 
    6456   if not idle then
    6457     exit;
    6458 
    6459   if ClientMode = cEditMap then
    6460   begin
    6461     if Shift = [ssCtrl] then
     6547  Time0, Time1: TDateTime;
     6548  ShortCut: TShortCut;
     6549begin
     6550  ShortCut := KeyToShortCut(Key, Shift);
     6551
     6552  if GameMode = cMovie then begin
     6553    if BScienceStat.Test(ShortCut) then MenuClick_Check(StatPopup, mScienceStat)
     6554    else if BDiagram.Test(ShortCut) then MenuClick_Check(StatPopup, mDiagram)
     6555    else if BWonders.Test(ShortCut) then MenuClick_Check(StatPopup, mWonders)
     6556    else if BShips.Test(ShortCut) then MenuClick_Check(StatPopup, mShips);
     6557    Exit;
     6558  end;
     6559
     6560  if not Idle then Exit;
     6561
     6562  if ClientMode = cEditMap then begin
     6563    if BResign.Test(ShortCut) then MenuClick(mResign)
     6564    else if BRandomMap.Test(ShortCut) then MenuClick(mRandomMap)
     6565    else if BHelp.Test(ShortCut) then MenuClick(mHelp);
     6566    (*if Shift = [ssCtrl] then
    64626567      case char(Key) of
    6463         (* 'A':
     6568        'A':
    64646569          begin // auto symmetry
    64656570          Server($7F0,me,0,nil^);
     
    64736578          if MyMap[dx] and fTerrain>=fGrass then inc(dy);
    64746579          dy:=dy
    6475           end; *)
    6476         'Q':
    6477           MenuClick(mResign);
    6478         'R':
    6479           MenuClick(mRandomMap);
    6480       end
    6481     else if Shift = [] then
    6482       case char(Key) of
    6483         char(VK_F1):
    6484           MenuClick(mHelp);
     6580          end;
    64856581      end;
    6486     exit;
    6487   end;
    6488 
    6489   if Shift = [ssAlt] then
    6490     case char(Key) of
    6491       '0':
    6492         SetDebugMap(-1);
    6493       '1' .. '9':
    6494         SetDebugMap(ord(Key) - 48);
     6582    *)
     6583    Exit;
     6584  end;
     6585
     6586  if BEndTurn.Test(ShortCut) then EndTurn
     6587  else if BFullScreen.Test(ShortCut) then begin
     6588    FullScreen := not FullScreen;
     6589    SetFullScreen(FullScreen);
     6590  end
     6591  else if BHelp.Test(ShortCut) then MenuClick(mHelp)
     6592  else if BUnitStat.Test(ShortCut) then MenuClick_Check(StatPopup, mUnitStat)
     6593  else if BCityStat.Test(ShortCut) then MenuClick_Check(StatPopup, mCityStat)
     6594  else if BScienceStat.Test(ShortCut) then MenuClick_Check(StatPopup, mScienceStat)
     6595  else if BEUnitStat.Test(ShortCut) then MenuClick_Check(StatPopup, mEUnitStat)
     6596  else if BDiagram.Test(ShortCut) then MenuClick_Check(StatPopup, mDiagram)
     6597  else if BWonders.Test(ShortCut) then MenuClick_Check(StatPopup, mWonders)
     6598  else if BShips.Test(ShortCut) then MenuClick_Check(StatPopup, mShips)
     6599  else if BNations.Test(ShortCut) then MenuClick_Check(StatPopup, mNations)
     6600  else if BEmpire.Test(ShortCut) then MenuClick_Check(StatPopup, mEmpire)
     6601
     6602  else if BSetDebugMap0.Test(ShortCut) then SetDebugMap(-1)
     6603  else if BSetDebugMap1.Test(ShortCut) then SetDebugMap(1)
     6604  else if BSetDebugMap2.Test(ShortCut) then SetDebugMap(2)
     6605  else if BSetDebugMap3.Test(ShortCut) then SetDebugMap(3)
     6606  else if BSetDebugMap4.Test(ShortCut) then SetDebugMap(4)
     6607  else if BSetDebugMap5.Test(ShortCut) then SetDebugMap(5)
     6608  else if BSetDebugMap6.Test(ShortCut) then SetDebugMap(6)
     6609  else if BSetDebugMap7.Test(ShortCut) then SetDebugMap(7)
     6610  else if BSetDebugMap8.Test(ShortCut) then SetDebugMap(8)
     6611  else if BSetDebugMap9.Test(ShortCut) then SetDebugMap(9)
     6612
     6613  else if BJump.Test(ShortCut) then MenuClick(mJump)
     6614  else if BDebugMap.Test(ShortCut) then mShowClick(mDebugMap)
     6615  else if BLocCodes.Test(ShortCut) then mShowClick(mLocCodes)
     6616  else if BLogDlg.Test(ShortCut) then begin
     6617    if LogDlg.Visible then LogDlg.Close
     6618      else LogDlg.Show;
     6619  end
     6620  else if BNames.Test(ShortCut) then mNamesClick(mNames)
     6621  else if BResign.Test(ShortCut) then MenuClick_Check(GamePopup, mResign)
     6622  else if BRun.Test(ShortCut) then MenuClick(mRun)
     6623  else if BTestMapRepaint.Test(ShortCut) then begin // test map repaint time
     6624    Time0 := NowPrecise;
     6625    MapValid := False;
     6626    MainOffscreenPaint;
     6627    Time1 := NowPrecise;
     6628    SimpleMessage(Format('Map repaint time: %.3f ms',
     6629      [(Time1 - Time0) / OneMillisecond]));
     6630  end
     6631  else if BSetViewpoint0.Test(ShortCut) then SetViewpointMe(0)
     6632  else if BSetViewpoint1.Test(ShortCut) then SetViewpointMe(1)
     6633  else if BSetViewpoint2.Test(ShortCut) then SetViewpointMe(2)
     6634  else if BSetViewpoint3.Test(ShortCut) then SetViewpointMe(3)
     6635  else if BSetViewpoint4.Test(ShortCut) then SetViewpointMe(4)
     6636  else if BSetViewpoint5.Test(ShortCut) then SetViewpointMe(5)
     6637  else if BSetViewpoint6.Test(ShortCut) then SetViewpointMe(6)
     6638  else if BSetViewpoint7.Test(ShortCut) then SetViewpointMe(7)
     6639  else if BSetViewpoint8.Test(ShortCut) then SetViewpointMe(8)
     6640  else if BSetViewpoint9.Test(ShortCut) then SetViewpointMe(9)
     6641
     6642  else if BMapBtn0.Test(ShortCut) then MapBtnClick(MapBtn0)
     6643  else if BMapBtn1.Test(ShortCut) then MapBtnClick(MapBtn1)
     6644  else if BMapBtn4.Test(ShortCut) then MapBtnClick(MapBtn4)
     6645  else if BMapBtn5.Test(ShortCut) then MapBtnClick(MapBtn5)
     6646  else if BMapBtn6.Test(ShortCut) then MapBtnClick(MapBtn6)
     6647  else if BTechTree.Test(ShortCut) then MenuClick(mTechTree)
     6648  else if BWait.Test(ShortCut) then MenuClick(mWait);
     6649
     6650  if UnFocus >= 0 then begin
     6651    if BDisbandUnit.Test(ShortCut) then MenuClick(mDisband)
     6652    else if BFortify.Test(ShortCut) then MenuClick_Check(TerrainPopup, mFort)
     6653    else if BCenterUnit.Test(ShortCut) then MenuClick(mCentre)
     6654    else if BStay.Test(ShortCut) then MenuClick(mStay)
     6655    else if BNoOrders.Test(ShortCut) then MenuClick(mNoOrders)
     6656    else if BCancel.Test(ShortCut) then MenuClick_Check(UnitPopup, mCancel)
     6657    else if BPillage.Test(ShortCut) then MenuClick_Check(UnitPopup, mPillage)
     6658    else if BSelectTransport.Test(ShortCut) then MenuClick_Check(UnitPopup, mSelectTransport)
     6659    else if BAirBase.Test(ShortCut) then MenuClick_Check(TerrainPopup, mAirBase)
     6660    else if BBuildCity.Test(ShortCut) then MenuClick_Check(UnitPopup, mCity)
     6661    else if BEnhance.Test(ShortCut) then begin
     6662      InitPopup(TerrainPopup);
     6663      if mEnhance.Visible and mEnhance.Enabled then MenuClick(mEnhance)
     6664        else MenuClick(mEnhanceDef)
    64956665    end
    6496   else if Shift = [ssCtrl] then
    6497     case char(Key) of
    6498       'J':
    6499         MenuClick(mJump);
    6500       'K':
    6501         mShowClick(mDebugMap);
    6502       'L':
    6503         mShowClick(mLocCodes);
    6504       'M':
    6505         if LogDlg.Visible then
    6506           LogDlg.Close
    6507         else
    6508           LogDlg.Show;
    6509       'N':
    6510         mNamesClick(mNames);
    6511       'Q':
    6512         MenuClick_Check(GamePopup, mResign);
    6513       'R':
    6514         MenuClick(mRun);
    6515       '0' .. '9':
    6516         begin
    6517           if ord(Key) - 48 = me then
    6518             SetViewpoint(0)
    6519           else
    6520             SetViewpoint(ord(Key) - 48);
    6521         end;
    6522       ' ':
    6523         begin // test map repaint time
    6524           time0 := NowPrecise;
    6525           MapValid := false;
    6526           MainOffscreenPaint;
    6527           time1 := NowPrecise;
    6528           SimpleMessage(Format('Map repaint time: %.3f ms',
    6529             [(time1 - time0) / OneMillisecond]));
    6530         end
     6666    else if BGoOn.Test(ShortCut) then MenuClick_Check(UnitPopup, mGoOn)
     6667    else if BHome.Test(ShortCut) then MenuClick_Check(UnitPopup, mHome)
     6668    else if BFarmClearIrrigation.Test(ShortCut) then begin
     6669      if JobTest(UnFocus, jFarm, [eTreaty]) then
     6670        MenuClick(mFarm)
     6671      else if JobTest(UnFocus, jClear, [eTreaty]) then
     6672        MenuClick(mClear)
     6673      else MenuClick_Check(TerrainPopup, mIrrigation);
    65316674    end
    6532   else if Shift = [] then
    6533     case char(Key) of
    6534       char(VK_F1):
    6535         MenuClick(mHelp);
    6536       char(VK_F2):
    6537         MenuClick_Check(StatPopup, mUnitStat);
    6538       char(VK_F3):
    6539         MenuClick_Check(StatPopup, mCityStat);
    6540       char(VK_F4):
    6541         MenuClick_Check(StatPopup, mScienceStat);
    6542       char(VK_F5):
    6543         MenuClick_Check(StatPopup, mEUnitStat);
    6544       char(VK_F6):
    6545         MenuClick_Check(StatPopup, mDiagram);
    6546       char(VK_F7):
    6547         MenuClick_Check(StatPopup, mWonders);
    6548       char(VK_F8):
    6549         MenuClick_Check(StatPopup, mShips);
    6550       char(VK_F9):
    6551         MenuClick_Check(StatPopup, mNations);
    6552       char(VK_F10):
    6553         MenuClick_Check(StatPopup, mEmpire);
    6554       char(VK_ADD):
    6555         EndTurn;
    6556       '1':
    6557         MapBtnClick(MapBtn0);
    6558       '2':
    6559         MapBtnClick(MapBtn1);
    6560       '3':
    6561         MapBtnClick(MapBtn4);
    6562       '4':
    6563         MapBtnClick(MapBtn5);
    6564       '5':
    6565         MapBtnClick(MapBtn6);
    6566       'T':
    6567         MenuClick(mTechTree);
    6568       'W':
    6569         MenuClick(mWait);
    6570     end;
    6571 
    6572   if UnFocus >= 0 then
    6573     if Shift = [ssCtrl] then
    6574       case char(Key) of
    6575         'C':
    6576           MenuClick_Check(UnitPopup, mCancel);
    6577         'D':
    6578           MenuClick(mDisband);
    6579         'P':
    6580           MenuClick_Check(UnitPopup, mPillage);
    6581         'T':
    6582           MenuClick_Check(UnitPopup, mSelectTransport);
    6583       end
    6584     else if Shift = [] then
    6585       case char(Key) of
    6586         ' ':
    6587           MenuClick(mNoOrders);
    6588         'A':
    6589           MenuClick_Check(TerrainPopup, mAirBase);
    6590         'B':
    6591           MenuClick_Check(UnitPopup, mCity);
    6592         'C':
    6593           MenuClick(mCentre);
    6594         'E':
    6595           begin
    6596             InitPopup(TerrainPopup);
    6597             if mEnhance.Visible and mEnhance.Enabled then
    6598               MenuClick(mEnhance)
    6599             else
    6600               MenuClick(mEnhanceDef)
    6601           end;
    6602         'F':
    6603           MenuClick_Check(TerrainPopup, mFort);
    6604         'G':
    6605           MenuClick_Check(UnitPopup, mGoOn);
    6606         'H':
    6607           MenuClick_Check(UnitPopup, mHome);
    6608         'I':
    6609           if JobTest(UnFocus, jFarm, [eTreaty]) then
    6610             MenuClick(mFarm)
    6611           else if JobTest(UnFocus, jClear, [eTreaty]) then
    6612             MenuClick(mClear)
    6613           else
    6614             MenuClick_Check(TerrainPopup, mIrrigation);
    6615         'L':
    6616           MenuClick_Check(UnitPopup, mLoad);
    6617         'M':
    6618           if JobTest(UnFocus, jAfforest, [eTreaty]) then
    6619             MenuClick(mAfforest)
    6620           else
    6621             MenuClick_Check(TerrainPopup, mMine);
    6622         'N':
    6623           MenuClick_Check(TerrainPopup, mCanal);
    6624         'O':
    6625           MenuClick_Check(TerrainPopup, MTrans);
    6626         'P':
    6627           MenuClick_Check(TerrainPopup, mPollution);
    6628         'R':
    6629           if JobTest(UnFocus, jRR, [eTreaty]) then
    6630             MenuClick(mRR)
    6631           else
    6632             MenuClick_Check(TerrainPopup, mRoad);
    6633         'S':
    6634           MenuClick(mStay);
    6635         'U':
    6636           MenuClick_Check(UnitPopup, mUnload);
    6637         'V':
    6638           MenuClick_Check(UnitPopup, mRecover);
    6639         'Z':
    6640           MenuClick_Check(UnitPopup, mUtilize);
    6641         #33 .. #40, #97 .. #100, #102 .. #105:
    6642           begin { arrow keys }
    6643             DestinationMarkON := false;
    6644             PaintDestination;
    6645             MyUn[UnFocus].Status := MyUn[UnFocus].Status and
    6646               ($FFFF - usStay - usRecover - usGoto - usEnhance) or usWaiting;
    6647             case Key of
    6648               VK_NUMPAD1, VK_END:
    6649                 begin
    6650                   dx := -1;
    6651                   dy := 1
    6652                 end;
    6653               VK_NUMPAD2, VK_DOWN:
    6654                 begin
    6655                   dx := 0;
    6656                   dy := 2
    6657                 end;
    6658               VK_NUMPAD3, VK_NEXT:
    6659                 begin
    6660                   dx := 1;
    6661                   dy := 1
    6662                 end;
    6663               VK_NUMPAD4, VK_LEFT:
    6664                 begin
    6665                   dx := -2;
    6666                   dy := 0
    6667                 end;
    6668               VK_NUMPAD6, VK_RIGHT:
    6669                 begin
    6670                   dx := 2;
    6671                   dy := 0
    6672                 end;
    6673               VK_NUMPAD7, VK_HOME:
    6674                 begin
    6675                   dx := -1;
    6676                   dy := -1
    6677                 end;
    6678               VK_NUMPAD8, VK_UP:
    6679                 begin
    6680                   dx := 0;
    6681                   dy := -2
    6682                 end;
    6683               VK_NUMPAD9, VK_PRIOR:
    6684                 begin
    6685                   dx := 1;
    6686                   dy := -1
    6687                 end;
    6688             end;
    6689             MoveUnit(dx, dy, muAutoNext)
    6690           end;
    6691       end
     6675    else if BLoad.Test(ShortCut) then MenuClick_Check(UnitPopup, mLoad)
     6676    else if BAfforestMine.Test(ShortCut) then begin
     6677      if JobTest(UnFocus, jAfforest, [eTreaty]) then MenuClick(mAfforest)
     6678        else MenuClick_Check(TerrainPopup, mMine);
     6679    end
     6680    else if BCanal.Test(ShortCut) then MenuClick_Check(TerrainPopup, mCanal)
     6681    else if BTrans.Test(ShortCut) then MenuClick_Check(TerrainPopup, MTrans)
     6682    else if BPollution.Test(ShortCut) then MenuClick_Check(TerrainPopup, mPollution)
     6683    else if BRailRoad.Test(ShortCut) then begin
     6684      if JobTest(UnFocus, jRR, [eTreaty]) then MenuClick(mRR)
     6685        else MenuClick_Check(TerrainPopup, mRoad);
     6686    end
     6687    else if BUnload.Test(ShortCut) then MenuClick_Check(UnitPopup, mUnload)
     6688    else if BRecover.Test(ShortCut) then MenuClick_Check(UnitPopup, mRecover)
     6689    else if BUtilize.Test(ShortCut) then MenuClick_Check(UnitPopup, mUtilize)
     6690    else if BMoveLeftDown.Test(ShortCut) then DoMoveUnit(-1, 1)
     6691    else if BMoveDown.Test(ShortCut) then DoMoveUnit(0, 2)
     6692    else if BMoveRightDown.Test(ShortCut) then DoMoveUnit(1, 1)
     6693    else if BMoveLeft.Test(ShortCut) then DoMoveUnit(-2, 0)
     6694    else if BMoveRight.Test(ShortCut) then DoMoveUnit(2, 0)
     6695    else if BMoveLeftUp.Test(ShortCut) then DoMoveUnit(-1, -1)
     6696    else if BMoveUp.Test(ShortCut) then  DoMoveUnit(0, -2)
     6697    else if BMoveRightUp.Test(ShortCut) then DoMoveUnit(1, -1);
     6698  end;
    66926699end;
    66936700
     
    71527159            SetTroopLoc(Loc);
    71537160            PanelPaint
    7154           end
     7161          end;
    71557162        end
    71567163      else if Sender = mSelectTransport then
     
    71717178    begin
    71727179      HaveCities := true;
    7173       Break
     7180      Break;
    71747181    end;
    71757182  if Popup = GamePopup then
     
    72717278            m.Checked := true;
    72727279          mDebugMap.Add(m);
    7273         end
     7280        end;
    72747281    end;
    72757282    mSmallTiles.Checked := xxt = 33;
     
    74557462  begin
    74567463    SetTroopLoc(-1);
    7457     PanelPaint
     7464    PanelPaint;
    74587465  end
    74597466  else
     
    74747481      SetTroopLoc(-1);
    74757482      PanelPaint
    7476     end
    7477   end
     7483    end;
     7484  end;
    74787485end;
    74797486
     
    75237530        2 + G.ly);
    75247531      Update;
    7525     end
     7532    end;
    75267533  end
    75277534  else
     
    75397546    MiniPaint;
    75407547    PanelPaint;
    7541   end
     7548  end;
    75427549end;
    75437550
     
    75917598begin
    75927599  result := (y >= TopBarHeight + MapHeight) or (y >= ClientHeight - PanelHeight)
    7593     and ((x < xMidPanel) or (x >= xRightPanel))
     7600    and ((x < xMidPanel) or (x >= xRightPanel));
    75947601end;
    75957602
     
    76087615          GamePopup.Popup(Left + 4, Top + DpiGetSystemMetrics(SM_CYCAPTION) + 4 +
    76097616            TopBarHeight - 1);
    7610       end
     7617      end;
    76117618    end
    76127619    else if IsPanelPixel(x, y) then
     
    77717778      CityRepMask := CityRepMask or (1 shl (Tag shr 8))
    77727779    else
    7773       CityRepMask := CityRepMask and not(1 shl (Tag shr 8))
    7774   end
     7780      CityRepMask := CityRepMask and not(1 shl (Tag shr 8));
     7781  end;
    77757782end;
    77767783
     
    77827789procedure TMainScreen.FormShow(Sender: TObject);
    77837790begin
    7784   if FullScreen then begin
    7785     WindowState := wsFullScreen;
    7786     BorderStyle := bsNone;
    7787     BorderIcons := [];
    7788   end else begin
    7789     WindowState := wsMaximized;
    7790     BorderStyle := bsSizeable;
    7791     BorderIcons := [biSystemMenu, biMinimize, biMaximize];
    7792   end;
     7791  SetFullScreen(FullScreen);
    77937792  Timer1.Enabled := True;
    77947793end;
     
    78277826      else if Flag = tfAllTechs then
    78287827        TellNewModels
    7829     end
    7830   end
     7828    end;
     7829  end;
    78317830end;
    78327831
     
    78987897      GamePopup.Popup(Left + 4, Top + DpiGetSystemMetrics(SM_CYCAPTION) + 4 +
    78997898        TopBarHeight - 1);
    7900     exit
    7901   end // windows menu button calls game menu
     7899    exit;
     7900  end; // windows menu button calls game menu
    79027901end;
    79037902
  • branches/highdpi/LocalPlayer/Tribes.pas

    r210 r303  
    55
    66uses
    7   Protocol, ScreenTools, LazFileUtils,
    8   Classes, Graphics, SysUtils;
     7  Protocol, ScreenTools, LazFileUtils, Classes, Graphics, SysUtils, Global;
    98
    109type
    1110  TCityPicture = record
    12     xShield, yShield: integer;
     11    xShield: Integer;
     12    yShield: Integer;
    1313  end;
    1414
    1515  TModelPicture = record
    16     HGr, pix, xShield, yShield: integer;
     16    HGr: Integer;
     17    pix: Integer;
     18    xShield: Integer;
     19    yShield: Integer;
    1720  end;
    1821
    1922  TModelPictureInfo = record
    20     trix, mix, pix, Hash: integer;
     23    trix: Integer;
     24    mix: Integer;
     25    pix: Integer;
     26    Hash: Integer;
    2127    GrName: ShortString;
    2228  end;
    2329
    2430  TTribe = class
    25     symHGr, sympix, faceHGr, facepix, cHGr, cpix,
     31    symHGr: Integer;
     32    sympix: Integer;
     33    faceHGr: Integer;
     34    facepix: Integer;
     35    cHGr: Integer;
     36    cpix: Integer;
    2637    // symbol and city graphics
    27     cAge, mixSlaves: integer;
     38    cAge: Integer;
     39    mixSlaves: Integer;
    2840    Color: TColor;
    29     NumberName: integer;
     41    NumberName: Integer;
    3042    CityPicture: array [0 .. 3] of TCityPicture;
    3143    ModelPicture: array [-1 .. 256] of TModelPicture; // -1 is building site
     
    3345    constructor Create(FileName: string);
    3446    destructor Destroy; override;
    35     function GetCityName(i: integer): string;
    36 {$IFNDEF SCR} procedure SetCityName(i: integer; NewName: string); {$ENDIF}
     47    function GetCityName(i: Integer): string;
     48{$IFNDEF SCR} procedure SetCityName(i: Integer; NewName: string); {$ENDIF}
    3749{$IFNDEF SCR} function TString(Template: string): string;
    3850    function TPhrase(Item: string): string; {$ENDIF}
    39     procedure SetModelPicture(const Info: TModelPictureInfo; IsNew: boolean);
     51    procedure SetModelPicture(const Info: TModelPictureInfo; IsNew: Boolean);
    4052    function ChooseModelPicture(var Picture: TModelPictureInfo;
    41       code, Turn: integer; ForceNew: boolean): boolean;
    42     procedure InitAge(Age: integer);
     53      Code, Turn: Integer; ForceNew: Boolean): Boolean;
     54    procedure InitAge(Age: Integer);
    4355  protected
    44     CityLine0, nCityLines: integer;
     56    CityLine0: Integer;
     57    nCityLines: Integer;
    4558    Name: array ['a' .. 'z'] of string;
    46     Script: tstringlist;
     59    Script: TStringList;
    4760  end;
    4861
    4962var
    5063  Tribe: array [0 .. nPl - 1] of TTribe;
    51   HGrStdUnits: integer;
     64  HGrStdUnits: Integer;
    5265
    5366procedure Init;
    5467procedure Done;
    55 function CityName(Founder: integer): string;
    56 function ModelCode(const ModelInfo: TModelInfo): integer;
    57 procedure FindStdModelPicture(code: integer; var pix: integer;
    58   var Name: string);
    59 function GetTribeInfo(FileName: string; var Name: string;
    60   var Color: TColor): boolean;
    61 procedure FindPosition(HGr, x, y, xmax, ymax: integer; Mark: TColor;
    62   var xp, yp: integer);
     68function CityName(Founder: Integer): string;
     69function ModelCode(const ModelInfo: TModelInfo): Integer;
     70procedure FindStdModelPicture(Code: Integer; var pix: Integer; var Name: string);
     71function GetTribeInfo(FileName: string; var Name: string; var Color: TColor): Boolean;
     72procedure FindPosition(HGr, x, y, xmax, ymax: Integer; Mark: TColor;
     73  var xp, yp: Integer);
     74
    6375
    6476implementation
     
    6981type
    7082  TChosenModelPictureInfo = record
    71     Hash, HGr, pix: integer;
    72     ModelName: ShortString end;
    73 
    74     TPictureList = array [0 .. 99999] of TChosenModelPictureInfo;
    75 
    76   var
    77     StdUnitScript: tstringlist;
    78     PictureList: ^TPictureList;
    79     nPictureList: integer;
    80 
    81     procedure Init;
    82     begin
    83       StdUnitScript := tstringlist.Create;
    84       StdUnitScript.LoadFromFile(LocalizedFilePath('Tribes' + DirectorySeparator + 'StdUnits.txt'));
    85       nPictureList := 0;
    86       PictureList := nil;
     83    Hash: Integer;
     84    HGr: Integer;
     85    pix: Integer;
     86    ModelName: ShortString;
     87  end;
     88
     89  TPictureList = array [0 .. 99999] of TChosenModelPictureInfo;
     90
     91var
     92  StdUnitScript: TStringList;
     93  PictureList: ^TPictureList;
     94  nPictureList: Integer;
     95
     96procedure Init;
     97begin
     98  StdUnitScript := TStringList.Create;
     99  StdUnitScript.LoadFromFile(LocalizedFilePath('Tribes' +
     100    DirectorySeparator + 'StdUnits.txt'));
     101  nPictureList := 0;
     102  PictureList := nil;
     103end;
     104
     105procedure Done;
     106begin
     107  ReallocMem(PictureList, 0);
     108  FreeAndNil(StdUnitScript);
     109end;
     110
     111function CityName(Founder: Integer): string;
     112begin
     113  if not GenerateNames then
     114    Result := Format('%d.%d', [Founder shr 12, Founder and $FFF])
     115  else
     116    Result := Tribe[Founder shr 12].GetCityName(Founder and $FFF);
     117end;
     118
     119function ModelCode(const ModelInfo: TModelInfo): Integer;
     120begin
     121  with ModelInfo do
     122  begin
     123    case Kind of
     124      mkSelfDeveloped, mkEnemyDeveloped:
     125        case Domain of { age determination }
     126          dGround:
     127            if (Attack >= Defense * 4) or (Attack > 0) and
     128              (MaxUpgrade < 10) and
     129              (Cap and (1 shl (mcArtillery - mcFirstNonCap)) <> 0) then
     130            begin
     131              Result := 170;
     132              if MaxUpgrade >= 12 then
     133                Inc(Result, 3)
     134              else if (MaxUpgrade >= 10) or (Weight > 7) then
     135                Inc(Result, 2)
     136              else if MaxUpgrade >= 4 then
     137                Inc(Result, 1);
     138            end
     139            else
     140            begin
     141              Result := 100;
     142              if MaxUpgrade >= 12 then
     143                Inc(Result, 6)
     144              else if (MaxUpgrade >= 10) or (Weight > 7) then
     145                Inc(Result, 5)
     146              else if MaxUpgrade >= 6 then
     147                Inc(Result, 4)
     148              else if MaxUpgrade >= 4 then
     149                Inc(Result, 3)
     150              else if MaxUpgrade >= 2 then
     151                Inc(Result, 2)
     152              else if MaxUpgrade >= 1 then
     153                Inc(Result, 1);
     154              if Speed >= 250 then
     155                if (Result >= 105) and (Attack <= Defense) then
     156                  Result := 110
     157                else
     158                  Inc(Result, 30);
     159            end;
     160          dSea:
     161          begin
     162            Result := 200;
     163            if MaxUpgrade >= 8 then
     164              Inc(Result, 3)
     165            else if MaxUpgrade >= 6 then
     166              Inc(Result, 2)
     167            else if MaxUpgrade >= 3 then
     168              Inc(Result, 1);
     169            if Cap and (1 shl (mcSub - mcFirstNonCap)) <> 0 then
     170              Result := 240
     171            else if ATrans_Fuel > 0 then
     172              Result := 220
     173            else if (Result >= 202) and (Attack = 0) and (TTrans > 0) then
     174              Result := 210;
     175          end;
     176          dAir:
     177          begin
     178            Result := 300;
     179            if (Bombs > 0) or (TTrans > 0) then
     180              Inc(Result, 10);
     181            if Speed > 850 then
     182              Inc(Result, 1);
     183          end;
     184        end;
     185      mkSpecial_TownGuard:
     186        Result := 41;
     187      mkSpecial_Boat:
     188        Result := 64;
     189      mkSpecial_SubCabin:
     190        Result := 71;
     191      mkSpecial_Glider:
     192        Result := 73;
     193      mkSlaves:
     194        Result := 74;
     195      mkSettler:
     196        if Speed > 150 then
     197          Result := 11
     198        else
     199          Result := 10;
     200      mkDiplomat:
     201        Result := 21;
     202      mkCaravan:
     203        Result := 30;
    87204    end;
    88 
    89     procedure Done;
    90     begin
    91       ReallocMem(PictureList, 0);
    92       StdUnitScript.Free;
     205  end;
     206end;
     207
     208var
     209  Input: string;
     210
     211function Get: string;
     212var
     213  p: Integer;
     214begin
     215  while (Input <> '') and ((Input[1] = ' ') or (Input[1] = #9)) do
     216    Delete(Input, 1, 1);
     217  p := Pos(',', Input);
     218  if p = 0 then
     219    p := Length(Input) + 1;
     220  Result := Copy(Input, 1, p - 1);
     221  Delete(Input, 1, p);
     222end;
     223
     224function GetNum: Integer;
     225var
     226  i: Integer;
     227begin
     228  Val(Get, Result, i);
     229  if i <> 0 then
     230    Result := 0;
     231end;
     232
     233procedure FindStdModelPicture(Code: Integer; var pix: Integer; var Name: string);
     234var
     235  i: Integer;
     236begin
     237  for i := 0 to StdUnitScript.Count - 1 do
     238  begin // look through StdUnits
     239    Input := StdUnitScript[i];
     240    pix := GetNum;
     241    if Code = GetNum then
     242    begin
     243      Name := Get;
     244      Exit;
    93245    end;
    94 
    95     function CityName(Founder: integer): string;
    96     begin
    97       if not GenerateNames then
    98         result := Format('%d.%d', [Founder shr 12, Founder and $FFF])
     246  end;
     247  pix := -1;
     248end;
     249
     250function GetTribeInfo(FileName: string; var Name: string;
     251  var Color: TColor): Boolean;
     252var
     253  Found: Integer;
     254  TribeScript: TextFile;
     255begin
     256  Name := '';
     257  Color := $FFFFFF;
     258  Found := 0;
     259  AssignFile(TribeScript, LocalizedFilePath('Tribes' + DirectorySeparator +
     260    FileName + CevoTribeExt));
     261  Reset(TribeScript);
     262  while not EOF(TribeScript) do
     263  begin
     264    ReadLn(TribeScript, Input);
     265    if Copy(Input, 1, 7) = '#CHOOSE' then
     266    begin
     267      Name := Copy(Input, 9, 255);
     268      Found := Found or 1;
     269      if Found = 3 then
     270        Break;
     271    end
     272    else if Copy(Input, 1, 6) = '#COLOR' then
     273    begin
     274      Color := HexStringToColor(Copy(Input, 7, 255));
     275      Found := Found or 2;
     276      if Found = 3 then
     277        Break;
     278    end;
     279  end;
     280  CloseFile(TribeScript);
     281  Result := Found = 3;
     282end;
     283
     284constructor TTribe.Create(FileName: string);
     285var
     286  Line: Integer;
     287  Variant: Char;
     288  Item: string;
     289begin
     290  inherited Create;
     291  for Variant := 'a' to 'z' do
     292    Name[Variant] := '';
     293  Script := TStringList.Create;
     294  Script.LoadFromFile(FileName);
     295  CityLine0 := 0;
     296  nCityLines := 0;
     297  for Line := 0 to Script.Count - 1 do
     298  begin
     299    Input := Script[Line];
     300    if (CityLine0 > 0) and (nCityLines = 0) and
     301      ((Input = '') or (Input[1] = '#')) then
     302      nCityLines := Line - CityLine0;
     303    if (Length(Input) >= 3) and (Input[1] = '#') and
     304      (Input[2] in ['a' .. 'z']) and (Input[3] = ' ') then
     305      Name[Input[2]] := Copy(Input, 4, 255)
     306    else if Copy(Input, 1, 6) = '#COLOR' then
     307      Color := HexStringToColor(Copy(Input, 7, 255))
     308    else if Copy(Input, 1, 7) = '#CITIES' then
     309      CityLine0 := Line + 1
     310    else if Copy(Input, 1, 8) = '#SYMBOLS' then
     311    begin
     312      Delete(Input, 1, 9);
     313      Item := Get;
     314      sympix := GetNum;
     315      symHGr := LoadGraphicSet(Item + '.png');
     316    end;
     317  end;
     318  FillChar(ModelPicture, SizeOf(ModelPicture), 0);
     319  NumberName := -1;
     320  cAge := -1;
     321  mixSlaves := -1;
     322end;
     323
     324destructor TTribe.Destroy;
     325begin
     326  FreeAndNil(Script);
     327  inherited;
     328end;
     329
     330procedure FindPosition(HGr, x, y, xmax, ymax: Integer; Mark: TColor;
     331  var xp, yp: Integer);
     332begin
     333  xp := 0;
     334  while (xp < xmax) and (GrExt[HGr].Data.Canvas.Pixels[x + 1 + xp, y] <> Mark) do
     335    Inc(xp);
     336  yp := 0;
     337  while (yp < ymax) and (GrExt[HGr].Data.Canvas.Pixels[x, y + 1 + yp] <> Mark) do
     338    Inc(yp);
     339end;
     340
     341function TTribe.GetCityName(i: Integer): string;
     342begin
     343  Result := '';
     344  if nCityLines > i then
     345  begin
     346    Result := Script[CityLine0 + i];
     347    while (Result <> '') and ((Result[1] = ' ') or (Result[1] = #9)) do
     348      Delete(Result, 1, 1);
     349  end
     350{$IFNDEF SCR}
     351  else
     352    Result := Format(TPhrase('GENCITY'), [i + 1]);
     353{$ENDIF}
     354end;
     355
     356{$IFNDEF SCR}
     357procedure TTribe.SetCityName(i: Integer; NewName: string);
     358begin
     359  while nCityLines <= i do
     360  begin
     361    Script.Insert(CityLine0 + nCityLines, Format(TPhrase('GENCITY'),
     362      [nCityLines + 1]));
     363    Inc(nCityLines);
     364  end;
     365  Script[CityLine0 + i] := NewName;
     366end;
     367
     368function TTribe.TString(Template: string): string;
     369var
     370  p: Integer;
     371  Variant: Char;
     372  CaseUp: Boolean;
     373begin
     374  repeat
     375    p := pos('#', Template);
     376    if (p = 0) or (p = Length(Template)) then
     377      Break;
     378    Variant := Template[p + 1];
     379    CaseUp := Variant in ['A' .. 'Z'];
     380    if CaseUp then
     381      Inc(Variant, 32);
     382    Delete(Template, p, 2);
     383    if Variant in ['a' .. 'z'] then
     384    begin
     385      if NumberName < 0 then
     386        Insert(Name[Variant], Template, p)
    99387      else
    100         result := Tribe[Founder shr 12].GetCityName(Founder and $FFF);
    101     end;
    102 
    103     function ModelCode(const ModelInfo: TModelInfo): integer;
    104     begin
    105       with ModelInfo do
    106       begin
    107         case Kind of
    108           mkSelfDeveloped, mkEnemyDeveloped:
    109             case Domain of { age determination }
    110               dGround:
    111                 if (Attack >= Defense * 4) or (Attack > 0) and (MaxUpgrade < 10)
    112                   and (Cap and (1 shl (mcArtillery - mcFirstNonCap)) <> 0) then
    113                 begin
    114                   result := 170;
    115                   if MaxUpgrade >= 12 then
    116                     inc(result, 3)
    117                   else if (MaxUpgrade >= 10) or (Weight > 7) then
    118                     inc(result, 2)
    119                   else if MaxUpgrade >= 4 then
    120                     inc(result, 1)
    121                 end
    122                 else
    123                 begin
    124                   result := 100;
    125                   if MaxUpgrade >= 12 then
    126                     inc(result, 6)
    127                   else if (MaxUpgrade >= 10) or (Weight > 7) then
    128                     inc(result, 5)
    129                   else if MaxUpgrade >= 6 then
    130                     inc(result, 4)
    131                   else if MaxUpgrade >= 4 then
    132                     inc(result, 3)
    133                   else if MaxUpgrade >= 2 then
    134                     inc(result, 2)
    135                   else if MaxUpgrade >= 1 then
    136                     inc(result, 1);
    137                   if Speed >= 250 then
    138                     if (result >= 105) and (Attack <= Defense) then
    139                       result := 110
    140                     else
    141                       inc(result, 30)
    142                 end;
    143               dSea:
    144                 begin
    145                   result := 200;
    146                   if MaxUpgrade >= 8 then
    147                     inc(result, 3)
    148                   else if MaxUpgrade >= 6 then
    149                     inc(result, 2)
    150                   else if MaxUpgrade >= 3 then
    151                     inc(result, 1);
    152                   if Cap and (1 shl (mcSub - mcFirstNonCap)) <> 0 then
    153                     result := 240
    154                   else if ATrans_Fuel > 0 then
    155                     result := 220
    156                   else if (result >= 202) and (Attack = 0) and (TTrans > 0) then
    157                     result := 210;
    158                 end;
    159               dAir:
    160                 begin
    161                   result := 300;
    162                   if (Bombs > 0) or (TTrans > 0) then
    163                     inc(result, 10);
    164                   if Speed > 850 then
    165                     inc(result, 1)
    166                 end;
    167             end;
    168           mkSpecial_TownGuard:
    169             result := 41;
    170           mkSpecial_Boat:
    171             result := 64;
    172           mkSpecial_SubCabin:
    173             result := 71;
    174           mkSpecial_Glider:
    175             result := 73;
    176           mkSlaves:
    177             result := 74;
    178           mkSettler:
    179             if Speed > 150 then
    180               result := 11
    181             else
    182               result := 10;
    183           mkDiplomat:
    184             result := 21;
    185           mkCaravan:
    186             result := 30;
    187         end;
    188       end;
    189     end;
    190 
    191   var
    192     Input: string;
    193 
    194     function Get: string;
    195 
    196   var
    197     p: integer;
    198   begin
    199     while (Input <> '') and ((Input[1] = ' ') or (Input[1] = #9)) do
    200       Delete(Input, 1, 1);
    201     p := pos(',', Input);
    202     if p = 0 then
    203       p := Length(Input) + 1;
    204     result := Copy(Input, 1, p - 1);
    205     Delete(Input, 1, p)
    206   end;
    207 
    208   function GetNum: integer;
    209 
    210   var
    211     i: integer;
    212   begin
    213     val(Get, result, i);
    214     if i <> 0 then
    215       result := 0
    216   end;
    217 
    218   procedure FindStdModelPicture(code: integer; var pix: integer;
    219     var Name: string);
    220 
    221   var
    222     i: integer;
    223   begin
    224     for i := 0 to StdUnitScript.Count - 1 do
    225     begin // look through StdUnits
    226       Input := StdUnitScript[i];
    227       pix := GetNum;
    228       if code = GetNum then
    229       begin
    230         Name := Get;
    231         exit;
    232       end
    233     end;
    234     pix := -1
    235   end;
    236 
    237   function GetTribeInfo(FileName: string; var Name: string;
    238     var Color: TColor): boolean;
    239 
    240   var
    241     found: integer;
    242     TribeScript: TextFile;
    243   begin
    244     Name := '';
    245     Color := $FFFFFF;
    246     found := 0;
    247     AssignFile(TribeScript, LocalizedFilePath('Tribes' + DirectorySeparator + FileName +
    248       '.tribe.txt'));
    249     Reset(TribeScript);
    250     while not EOF(TribeScript) do
    251     begin
    252       ReadLn(TribeScript, Input);
    253       if Copy(Input, 1, 7) = '#CHOOSE' then
    254       begin
    255         Name := Copy(Input, 9, 255);
    256         found := found or 1;
    257         if found = 3 then
    258           break
    259       end
    260       else if Copy(Input, 1, 6) = '#COLOR' then
    261       begin
    262         Color := HexStringToColor(Copy(Input, 7, 255));
    263         found := found or 2;
    264         if found = 3 then
    265           break
    266       end
    267     end;
    268     CloseFile(TribeScript);
    269     result := found = 3;
    270   end;
    271 
    272   constructor TTribe.Create(FileName: string);
    273 
    274   var
    275     line: integer;
    276     variant: char;
    277     Item: string;
    278   begin
    279     inherited Create;
    280     for variant := 'a' to 'z' do
    281       Name[variant] := '';
    282     Script := tstringlist.Create;
    283     Script.LoadFromFile(LocalizedFilePath('Tribes' + DirectorySeparator + FileName + '.tribe.txt'));
    284     CityLine0 := 0;
    285     nCityLines := 0;
    286     for line := 0 to Script.Count - 1 do
    287     begin
    288       Input := Script[line];
    289       if (CityLine0 > 0) and (nCityLines = 0) and
    290         ((Input = '') or (Input[1] = '#')) then
    291         nCityLines := line - CityLine0;
    292       if (Length(Input) >= 3) and (Input[1] = '#') and (Input[2] in ['a' .. 'z']
    293         ) and (Input[3] = ' ') then
    294         Name[Input[2]] := Copy(Input, 4, 255)
    295       else if Copy(Input, 1, 6) = '#COLOR' then
    296         Color := HexStringToColor(Copy(Input, 7, 255))
    297       else if Copy(Input, 1, 7) = '#CITIES' then
    298         CityLine0 := line + 1
    299       else if Copy(Input, 1, 8) = '#SYMBOLS' then
    300       begin
    301         Delete(Input, 1, 9);
    302         Item := Get;
    303         sympix := GetNum;
    304         symHGr := LoadGraphicSet(Item + '.png');
    305       end
    306     end;
    307     FillChar(ModelPicture, SizeOf(ModelPicture), 0);
    308     NumberName := -1;
    309     cAge := -1;
    310     mixSlaves := -1;
    311   end;
    312 
    313   destructor TTribe.Destroy;
    314   begin
    315     Script.Free;
    316     inherited Destroy;
    317   end;
    318 
    319   procedure FindPosition(HGr, x, y, xmax, ymax: integer; Mark: TColor;
    320     var xp, yp: integer);
    321   begin
    322     xp := 0;
    323     while (xp < xmax) and (GrExt[HGr].Data.Canvas.Pixels[x + 1 + xp, y]
    324       <> Mark) do
    325       inc(xp);
    326     yp := 0;
    327     while (yp < ymax) and (GrExt[HGr].Data.Canvas.Pixels[x, y + 1 + yp]
    328       <> Mark) do
    329       inc(yp);
    330   end;
    331 
    332   function TTribe.GetCityName(i: integer): string;
    333   begin
    334     result := '';
    335     if nCityLines > i then
    336     begin
    337       result := Script[CityLine0 + i];
    338       while (result <> '') and ((result[1] = ' ') or (result[1] = #9)) do
    339         Delete(result, 1, 1);
     388        Insert(Format('P%d', [NumberName]), Template, p);
     389      if CaseUp and (Length(Template) >= p) and
     390        (Template[p] in ['a' .. 'z', #$E0 .. #$FF]) then
     391        Dec(Template[p], 32);
    340392    end
    341 {$IFNDEF SCR} else
    342       result := Format(TPhrase('GENCITY'), [i + 1]){$ENDIF}
    343   end;
    344 
    345 {$IFNDEF SCR}
    346   procedure TTribe.SetCityName(i: integer; NewName: string);
    347   begin
    348     while nCityLines <= i do
    349     begin
    350       Script.Insert(CityLine0 + nCityLines, Format(TPhrase('GENCITY'),
    351         [nCityLines + 1]));
    352       inc(nCityLines);
    353     end;
    354     Script[CityLine0 + i] := NewName;
    355   end;
    356 
    357   function TTribe.TString(Template: string): string;
    358 
    359   var
    360     p: integer;
    361     variant: char;
    362     CaseUp: boolean;
    363   begin
    364     repeat
    365       p := pos('#', Template);
    366       if (p = 0) or (p = Length(Template)) then
    367         break;
    368       variant := Template[p + 1];
    369       CaseUp := variant in ['A' .. 'Z'];
    370       if CaseUp then
    371         inc(variant, 32);
    372       Delete(Template, p, 2);
    373       if variant in ['a' .. 'z'] then
    374       begin
    375         if NumberName < 0 then
    376           Insert(Name[variant], Template, p)
    377         else
    378           Insert(Format('P%d', [NumberName]), Template, p);
    379         if CaseUp and (Length(Template) >= p) and
    380           (Template[p] in ['a' .. 'z', #$E0 .. #$FF]) then
    381           dec(Template[p], 32);
    382       end
    383       until false;
    384       result := Template;
    385     end;
    386 
    387     function TTribe.TPhrase(Item: string): string;
    388     begin
    389       result := TString(Phrases.Lookup(Item));
    390     end;
     393  until False;
     394  Result := Template;
     395end;
     396
     397function TTribe.TPhrase(Item: string): string;
     398begin
     399  Result := TString(Phrases.Lookup(Item));
     400end;
     401
    391402{$ENDIF}
    392403
    393     procedure TTribe.InitAge(Age: integer);
    394     type
    395       TLine = array [0 .. 649, 0 .. 2] of Byte;
    396     var
    397       i, x, gray: integer;
    398       Item: string;
    399     begin
    400       if Age = cAge then
    401         exit;
    402       cAge := Age;
    403       with Script do
    404       begin
    405         i := 0;
    406         while (i < Count) and
    407           (Copy(Strings[i], 1, 6) <> '#AGE' + char(48 + Age) + ' ') do
    408           inc(i);
    409         if i < Count then
    410         begin
    411           Input := Strings[i];
    412           system.Delete(Input, 1, 6);
    413           Item := Get;
    414           cpix := GetNum;
    415           // init city graphics
    416           if Age < 2 then
    417           begin
    418             if CompareText(Item, 'stdcities') = 0 then
    419               case cpix of
    420                 3:
    421                   cpix := 0;
    422                 6:
    423                   begin
    424                     cpix := 0;
    425                     Item := 'Nation2';
    426                   end
    427               end;
    428             cHGr := LoadGraphicSet(Item + '.png');
    429             for x := 0 to 3 do
    430               with CityPicture[x] do
    431               begin
    432                 FindPosition(cHGr, x * 65, cpix * 49, 63, 47, $00FFFF,
    433                   xShield, yShield);
    434                 // FindPosition(cHGr,x*65,cpix*49,$FFFFFF,xf,yf);
    435               end
    436           end
    437           else
    438             cHGr := -1;
    439 
    440 {$IFNDEF SCR}
    441           Get;
    442           GetNum;
    443           Item := Get;
    444           if Item = '' then
    445             faceHGr := -1
    446           else
    447           begin
    448             faceHGr := LoadGraphicSet(Item + '.png');
    449             facepix := GetNum;
    450             if GrExt[faceHGr].Data.Canvas.Pixels[facepix mod 10 * 65,
    451               facepix div 10 * 49 + 48] = $00FFFF then
    452             begin // generate shield picture
    453               GrExt[faceHGr].Data.Canvas.Pixels[facepix mod 10 * 65,
    454                 facepix div 10 * 49 + 48] := $000000;
    455               gray := $B8B8B8;
    456               ImageOp_BCC(GrExt[faceHGr].Data, Templates,
    457                 facepix mod 10 * 65 + 1, facepix div 10 * 49 + 1, 1, 25, 64, 48,
    458                 gray, Color);
     404procedure TTribe.InitAge(Age: Integer);
     405type
     406  TLine = array [0 .. 649, 0 .. 2] of Byte;
     407var
     408  i, x, Gray: Integer;
     409  Item: string;
     410begin
     411  if Age = cAge then
     412    Exit;
     413  cAge := Age;
     414  with Script do
     415  begin
     416    i := 0;
     417    while (i < Count) and (Copy(Strings[i], 1, 6) <>
     418        '#AGE' + char(48 + Age) + ' ') do
     419      Inc(i);
     420    if i < Count then
     421    begin
     422      Input := Strings[i];
     423      system.Delete(Input, 1, 6);
     424      Item := Get;
     425      cpix := GetNum;
     426      // init city graphics
     427      if Age < 2 then
     428      begin
     429        if CompareText(Item, 'stdcities') = 0 then
     430          case cpix of
     431            3:
     432              cpix := 0;
     433            6:
     434            begin
     435              cpix := 0;
     436              Item := 'Nation2';
    459437            end
    460438          end;
     439        cHGr := LoadGraphicSet(Item + '.png');
     440        for x := 0 to 3 do
     441          with CityPicture[x] do
     442          begin
     443            FindPosition(cHGr, x * 65, cpix * 49, 63, 47, $00FFFF,
     444              xShield, yShield);
     445            // FindPosition(cHGr,x*65,cpix*49,$FFFFFF,xf,yf);
     446          end;
     447      end
     448      else
     449        cHGr := -1;
     450
     451{$IFNDEF SCR}
     452      Get;
     453      GetNum;
     454      Item := Get;
     455      if Item = '' then
     456        faceHGr := -1
     457      else
     458      begin
     459        faceHGr := LoadGraphicSet(Item + '.png');
     460        facepix := GetNum;
     461        if GrExt[faceHGr].Data.Canvas.Pixels[facepix mod 10 * 65,
     462          facepix div 10 * 49 + 48] = $00FFFF then
     463        begin // generate shield picture
     464          GrExt[faceHGr].Data.Canvas.Pixels[facepix mod 10 * 65,
     465            facepix div 10 * 49 + 48] := $000000;
     466          Gray := $B8B8B8;
     467          ImageOp_BCC(GrExt[faceHGr].Data, Templates,
     468            facepix mod 10 * 65 + 1, facepix div 10 * 49 + 1, 1, 25, 64, 48,
     469            Gray, Color);
     470        end;
     471      end;
    461472{$ENDIF}
    462         end
    463       end
    464473    end;
    465 
    466     procedure TTribe.SetModelPicture(const Info: TModelPictureInfo;
    467       IsNew: boolean);
    468     var
    469       i: integer;
    470       ok: boolean;
    471     begin
    472       with Info do
    473       begin
    474         if not IsNew then
     474  end;
     475end;
     476
     477procedure TTribe.SetModelPicture(const Info: TModelPictureInfo; IsNew: Boolean);
     478var
     479  i: Integer;
     480  ok: Boolean;
     481begin
     482  with Info do
     483  begin
     484    if not IsNew then
     485    begin
     486      i := nPictureList - 1;
     487      while (i >= 0) and (PictureList[i].Hash <> Info.Hash) do
     488        Dec(i);
     489      assert(i >= 0);
     490      assert(PictureList[i].HGr = LoadGraphicSet(GrName));
     491      assert(PictureList[i].pix = pix);
     492      ModelPicture[mix].HGr := PictureList[i].HGr;
     493      ModelPicture[mix].pix := PictureList[i].pix;
     494      ModelName[mix] := PictureList[i].ModelName;
     495    end
     496    else
     497    begin
     498      with ModelPicture[mix] do
     499      begin
     500        HGr := LoadGraphicSet(GrName);
     501        pix := Info.pix;
     502        Inc(GrExt[HGr].pixUsed[pix]);
     503      end;
     504      ModelName[mix] := '';
     505
     506      // read model name from tribe script
     507      ok := False;
     508      for i := 0 to Script.Count - 1 do
     509      begin
     510        Input := Script[i];
     511        if Input = '#UNITS ' + ExtractFileNameOnly(GrName) then
     512          ok := True
     513        else if (Input <> '') and (Input[1] = '#') then
     514          ok := False
     515        else if ok and (GetNum = pix) then
    475516        begin
    476           i := nPictureList - 1;
    477           while (i >= 0) and (PictureList[i].Hash <> Info.Hash) do
    478             dec(i);
    479           assert(i >= 0);
    480           assert(PictureList[i].HGr = LoadGraphicSet(GrName));
    481           assert(PictureList[i].pix = pix);
    482           ModelPicture[mix].HGr := PictureList[i].HGr;
    483           ModelPicture[mix].pix := PictureList[i].pix;
    484           ModelName[mix] := PictureList[i].ModelName;
    485         end
    486         else
     517          Get;
     518          ModelName[mix] := Get;
     519        end;
     520      end;
     521
     522      if ModelName[mix] = '' then
     523      begin // read model name from StdUnits.txt
     524        for i := 0 to StdUnitScript.Count - 1 do
    487525        begin
    488           with ModelPicture[mix] do
     526          Input := StdUnitScript[i];
     527          if GetNum = pix then
    489528          begin
    490             HGr := LoadGraphicSet(GrName);
    491             pix := Info.pix;
    492             inc(GrExt[HGr].pixUsed[pix]);
     529            Get;
     530            ModelName[mix] := Get;
    493531          end;
    494           ModelName[mix] := '';
    495 
    496           // read model name from tribe script
    497           ok := false;
    498           for i := 0 to Script.Count - 1 do
    499           begin
    500             Input := Script[i];
    501             if Input = '#UNITS ' + ExtractFileNameOnly(GrName) then
    502               ok := true
    503             else if (Input <> '') and (Input[1] = '#') then
    504               ok := false
    505             else if ok and (GetNum = pix) then
    506             begin
    507               Get;
    508               ModelName[mix] := Get
    509             end
    510           end;
    511 
    512           if ModelName[mix] = '' then
    513           begin // read model name from StdUnits.txt
    514             for i := 0 to StdUnitScript.Count - 1 do
    515             begin
    516               Input := StdUnitScript[i];
    517               if GetNum = pix then
    518               begin
    519                 Get;
    520                 ModelName[mix] := Get
    521               end
    522             end
    523           end;
    524 
    525           if Hash <> 0 then
    526           begin
    527             if nPictureList = 0 then
    528               ReallocMem(PictureList, 64 * SizeOf(TChosenModelPictureInfo))
    529             else if (nPictureList >= 64) and
    530               (nPictureList and (nPictureList - 1) = 0) then
    531               ReallocMem(PictureList,
    532                 nPictureList * (2 * SizeOf(TChosenModelPictureInfo)));
    533             PictureList[nPictureList].Hash := Info.Hash;
    534             PictureList[nPictureList].HGr := ModelPicture[mix].HGr;
    535             PictureList[nPictureList].pix := Info.pix;
    536             PictureList[nPictureList].ModelName := ModelName[mix];
    537             inc(nPictureList);
    538           end
    539532        end;
    540 
    541         with ModelPicture[mix] do
    542           FindPosition(HGr, pix mod 10 * 65, pix div 10 * 49, 63, 47, $FFFFFF,
    543             xShield, yShield);
     533      end;
     534
     535      if Hash <> 0 then
     536      begin
     537        if nPictureList = 0 then
     538          ReallocMem(PictureList, 64 * SizeOf(TChosenModelPictureInfo))
     539        else if (nPictureList >= 64) and (nPictureList and
     540          (nPictureList - 1) = 0) then
     541          ReallocMem(PictureList,
     542            nPictureList * (2 * SizeOf(TChosenModelPictureInfo)));
     543        PictureList[nPictureList].Hash := Info.Hash;
     544        PictureList[nPictureList].HGr := ModelPicture[mix].HGr;
     545        PictureList[nPictureList].pix := Info.pix;
     546        PictureList[nPictureList].ModelName := ModelName[mix];
     547        Inc(nPictureList);
    544548      end;
    545549    end;
    546550
    547     function TTribe.ChooseModelPicture(var Picture: TModelPictureInfo;
    548       code, Turn: integer; ForceNew: boolean): boolean;
    549     var
    550       i, Cnt, HGr, used, LeastUsed: integer;
    551       TestPic: TModelPictureInfo;
    552       ok: boolean;
    553 
    554       procedure check;
    555       begin
    556         TestPic.pix := GetNum;
    557         if code = GetNum then
    558         begin
    559           if ForceNew or (HGr < 0) then
    560             used := 0
    561           else
    562           begin
    563             used := 4 * GrExt[HGr].pixUsed[TestPic.pix];
    564             if HGr = HGrStdUnits then
    565               inc(used, 2); // prefer units not from StdUnits
    566           end;
    567           if used < LeastUsed then
    568           begin
    569             Cnt := 0;
    570             LeastUsed := used
    571           end;
    572           if used = LeastUsed then
    573           begin
    574             inc(Cnt);
    575             if Turn mod Cnt = 0 then
    576               Picture := TestPic
    577           end;
    578         end
    579       end;
    580 
    581     begin
    582       // look for identical model to assign same picture again
    583       if not ForceNew and (Picture.Hash > 0) then
    584       begin
    585         for i := 0 to nPictureList - 1 do
    586           if PictureList[i].Hash = Picture.Hash then
    587           begin
    588             Picture.GrName := GrExt[PictureList[i].HGr].Name;
    589             Picture.pix := PictureList[i].pix;
    590             result := false;
    591             exit;
    592           end
    593       end;
    594 
    595       Picture.pix := 0;
    596       TestPic := Picture;
    597       LeastUsed := MaxInt;
    598 
    599       TestPic.GrName := 'StdUnits.png';
    600       HGr := HGrStdUnits;
    601       for i := 0 to StdUnitScript.Count - 1 do
    602       begin // look through StdUnits
    603         Input := StdUnitScript[i];
    604         check;
    605       end;
    606 
    607       ok := false;
    608       for i := 0 to Script.Count - 1 do
    609       begin // look through units defined in tribe script
    610         Input := Script[i];
    611         if Copy(Input, 1, 6) = '#UNITS' then
    612         begin
    613           ok := true;
    614           TestPic.GrName := Copy(Input, 8, 255) + '.png';
    615           HGr := nGrExt - 1;
    616           while (HGr >= 0) and (GrExt[HGr].Name <> TestPic.GrName) do
    617             dec(HGr);
    618         end
    619         else if (Input <> '') and (Input[1] = '#') then
    620           ok := false
    621         else if ok then
    622           check;
    623       end;
    624       result := true;
     551    with ModelPicture[mix] do
     552      FindPosition(HGr, pix mod 10 * 65, pix div 10 * 49, 63, 47, $FFFFFF,
     553        xShield, yShield);
     554  end;
     555end;
     556
     557function TTribe.ChooseModelPicture(var Picture: TModelPictureInfo;
     558  Code, Turn: Integer; ForceNew: Boolean): Boolean;
     559var
     560  i, Cnt, HGr, Used, LeastUsed: Integer;
     561  TestPic: TModelPictureInfo;
     562  ok: Boolean;
     563
     564  procedure Check;
     565  begin
     566    TestPic.pix := GetNum;
     567    if Code = GetNum then
     568    begin
     569      if ForceNew or (HGr < 0) then
     570        Used := 0
     571      else
     572      begin
     573        Used := 4 * GrExt[HGr].pixUsed[TestPic.pix];
     574        if HGr = HGrStdUnits then
     575          Inc(Used, 2); // prefer units not from StdUnits
     576      end;
     577      if Used < LeastUsed then
     578      begin
     579        Cnt := 0;
     580        LeastUsed := Used;
     581      end;
     582      if Used = LeastUsed then
     583      begin
     584        Inc(Cnt);
     585        if Turn mod Cnt = 0 then
     586          Picture := TestPic;
     587      end;
    625588    end;
     589  end;
     590
     591begin
     592  // look for identical model to assign same picture again
     593  if not ForceNew and (Picture.Hash > 0) then
     594  begin
     595    for i := 0 to nPictureList - 1 do
     596      if PictureList[i].Hash = Picture.Hash then
     597      begin
     598        Picture.GrName := GrExt[PictureList[i].HGr].Name;
     599        Picture.pix := PictureList[i].pix;
     600        Result := False;
     601        Exit;
     602      end;
     603  end;
     604
     605  Picture.pix := 0;
     606  TestPic := Picture;
     607  LeastUsed := MaxInt;
     608
     609  TestPic.GrName := 'StdUnits.png';
     610  HGr := HGrStdUnits;
     611  for i := 0 to StdUnitScript.Count - 1 do
     612  begin // look through StdUnits
     613    Input := StdUnitScript[i];
     614    Check;
     615  end;
     616
     617  ok := False;
     618  for i := 0 to Script.Count - 1 do
     619  begin // look through units defined in tribe script
     620    Input := Script[i];
     621    if Copy(Input, 1, 6) = '#UNITS' then
     622    begin
     623      ok := True;
     624      TestPic.GrName := Copy(Input, 8, 255) + '.png';
     625      HGr := nGrExt - 1;
     626      while (HGr >= 0) and (GrExt[HGr].Name <> TestPic.GrName) do
     627        Dec(HGr);
     628    end
     629    else if (Input <> '') and (Input[1] = '#') then
     630      ok := False
     631    else if ok then
     632      Check;
     633  end;
     634  Result := True;
     635end;
    626636
    627637end.
  • branches/highdpi/LocalPlayer/UnitStat.pas

    r210 r303  
    8383  Template := TDpiBitmap.Create;
    8484  Template.PixelFormat := pf24bit;
    85   LoadGraphicFile(Template, GetGraphicsDir + DirectorySeparator + 'Unit.png', gfNoGamma);
     85  LoadGraphicFile(Template, GetGraphicsDir + DirectorySeparator + 'Unit.png',
     86    [gfNoGamma]);
    8687end;
    8788
    8889procedure TUnitStatDlg.FormDestroy(Sender: TObject);
    8990begin
    90   Template.Free;
    91   Back.Free;
     91  FreeAndNil(Template);
     92  FreeAndNil(Back);
    9293end;
    9394
     
    276277procedure TUnitStatDlg.CloseBtnClick(Sender: TObject);
    277278begin
    278   Close
     279  Close;
    279280end;
    280281
     
    363364            inc(dx, 15)
    364365          end;
    365         end
    366       end
     366        end;
     367      end;
    367368  end; { featurebar }
    368369
Note: See TracChangeset for help on using the changeset viewer.