Changeset 6 for trunk/UnitProcessing.pas
- Timestamp:
- Jan 7, 2017, 11:32:14 AM (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/UnitProcessing.pas
r2 r6 5 5 6 6 uses 7 Protocol, Database;7 Protocol, Database; 8 8 9 9 type 10 TMoveType = (mtInvalid, mtMove, mtCapture, mtSpyMission, mtAttack, mtBombard, mtExpel); 11 12 TMoveInfo=record 13 MoveType: TMoveType; 14 Cost, 15 ToMaster, 16 EndHealth, 17 Defender, 18 Dcix, 19 Duix, 20 EndHealthDef: integer; 21 MountainDelay: boolean; 10 TMoveType = (mtInvalid, mtMove, mtCapture, mtSpyMission, mtAttack, 11 mtBombard, mtExpel); 12 13 TMoveInfo = record 14 MoveType: TMoveType; 15 Cost, ToMaster, EndHealth, Defender, Dcix, Duix, EndHealthDef: integer; 16 MountainDelay: boolean; 22 17 end; 23 18 24 19 var 25 uixSelectedTransport: integer; 26 Worked: array[0..nPl-1] of integer; {settler work statistics} 27 28 29 //Moving/Combat 20 uixSelectedTransport: integer; 21 Worked: array [0 .. nPl - 1] of integer; { settler work statistics } 22 23 // Moving/Combat 30 24 function HostileDamage(p, mix, Loc, MP: integer): integer; 31 function CalculateMove(p, uix,ToLoc,MoveLength: integer; TestOnly: boolean;25 function CalculateMove(p, uix, ToLoc, MoveLength: integer; TestOnly: boolean; 32 26 var MoveInfo: TMoveInfo): integer; 33 27 function GetBattleForecast(Loc: integer; var BattleForecast: TBattleForecast; 34 var Duix,Dcix,AStr,DStr,ABaseDamage,DBaseDamage: integer): integer; 35 function LoadUnit(p,uix: integer; TestOnly: boolean): integer; 36 function UnloadUnit(p,uix: integer; TestOnly: boolean): integer; 37 procedure Recover(p,uix: integer); 38 function GetMoveAdvice(p,uix: integer; var a: TMoveAdviceData): integer; 39 function CanPlaneReturn(p,uix: integer; PlaneReturnData: TPlaneReturnData): boolean; 28 var Duix, Dcix, AStr, DStr, ABaseDamage, DBaseDamage: integer): integer; 29 function LoadUnit(p, uix: integer; TestOnly: boolean): integer; 30 function UnloadUnit(p, uix: integer; TestOnly: boolean): integer; 31 procedure Recover(p, uix: integer); 32 function GetMoveAdvice(p, uix: integer; var a: TMoveAdviceData): integer; 33 function CanPlaneReturn(p, uix: integer; 34 PlaneReturnData: TPlaneReturnData): boolean; 40 35 41 36 // Terrain Improvement 42 function StartJob(p,uix,NewJob: integer; TestOnly: boolean): integer; 43 function Work(p,uix: integer): boolean; 44 function GetJobProgress(p,Loc: integer; var JobProgressData: TJobProgressData): integer; 37 function StartJob(p, uix, NewJob: integer; TestOnly: boolean): integer; 38 function Work(p, uix: integer): boolean; 39 function GetJobProgress(p, Loc: integer; 40 var JobProgressData: TJobProgressData): integer; 45 41 46 42 // Start/End Game … … 48 44 procedure ReleaseGame; 49 45 50 51 46 implementation 52 47 53 48 uses 54 IPQ;49 IPQ; 55 50 56 51 const 57 eMountains=$6000FFFF; // additional return code for server internal use58 59 // tile control flags60 coKnown=$02; coTrue=$04;61 62 ContraJobs: array[0..nJob-1] of Set of 0..nJob-1= 63 ([], //jNone64 [jCity], //jRoad65 [jCity], //jRR66 [jCity,jTrans], //jClear67 [jCity,jFarm,jAfforest,jMine,jBase,jFort], //jIrr68 [jCity,jIrr,jAfforest,jMine,jBase,jFort], //jFarm69 [jCity,jIrr,jFarm,jTrans], //jAfforest70 [jCity,jTrans,jIrr,jFarm,jBase,jFort], //jMine71 [jCity,jTrans], //jCanal72 [jCity,jClear,jAfforest,jMine,jCanal], //jTrans73 [jCity,jIrr,jFarm,jMine,jBase], //jFort74 [jCity], //jPoll75 [jCity,jIrr,jFarm,jMine,jFort], //jBase76 [jCity], //jPillage77 [jRoad..jPillage]); //jCity52 eMountains = $6000FFFF; // additional return code for server internal use 53 54 // tile control flags 55 coKnown = $02; 56 coTrue = $04; 57 58 ContraJobs: array [0 .. nJob - 1] of Set of 0 .. nJob - 1 = ([], // jNone 59 [jCity], // jRoad 60 [jCity], // jRR 61 [jCity, jTrans], // jClear 62 [jCity, jFarm, jAfforest, jMine, jBase, jFort], // jIrr 63 [jCity, jIrr, jAfforest, jMine, jBase, jFort], // jFarm 64 [jCity, jIrr, jFarm, jTrans], // jAfforest 65 [jCity, jTrans, jIrr, jFarm, jBase, jFort], // jMine 66 [jCity, jTrans], // jCanal 67 [jCity, jClear, jAfforest, jMine, jCanal], // jTrans 68 [jCity, jIrr, jFarm, jMine, jBase], // jFort 69 [jCity], // jPoll 70 [jCity, jIrr, jFarm, jMine, jFort], // jBase 71 [jCity], // jPillage 72 [jRoad .. jPillage]); // jCity 78 73 79 74 type 80 TToWorkList = array[0..INFIN,0..nJob-1] of word; 81 82 var 83 ToWork: ^TToWorkList; {work left for each tile and job} 84 85 86 { 87 Moving/Combat 88 ____________________________________________________________________ 89 } 75 TToWorkList = array [0 .. INFIN, 0 .. nJob - 1] of word; 76 77 var 78 ToWork: ^TToWorkList; { work left for each tile and job } 79 80 { 81 Moving/Combat 82 ____________________________________________________________________ 83 } 90 84 function HostileDamage(p, mix, Loc, MP: integer): integer; 91 85 var 92 Tile: integer; 93 begin 94 Tile:=RealMap[Loc]; 95 if (RW[p].Model[mix].Domain>=dSea) 96 or (RW[p].Model[mix].Kind=mkSettler) and (RW[p].Model[mix].Speed>=200) 97 or (Tile and (fCity or fRiver or fCanal)<>0) 98 or (Tile and fTerImp=tiBase) 99 or (GWonder[woGardens].EffectiveOwner=p) then 100 result:=0 101 else if (Tile and fTerrain=fDesert) 102 and (Tile and fSpecial<>fSpecial1{Oasis}) then 103 begin 104 assert((Tile and fTerImp<>tiIrrigation) and (Tile and fTerImp<>tiFarm)); 105 result:=(DesertThurst*MP-1) div RW[p].Model[mix].Speed +1 86 Tile: integer; 87 begin 88 Tile := RealMap[Loc]; 89 if (RW[p].Model[mix].Domain >= dSea) or (RW[p].Model[mix].Kind = mkSettler) 90 and (RW[p].Model[mix].Speed >= 200) or 91 (Tile and (fCity or fRiver or fCanal) <> 0) or (Tile and fTerImp = tiBase) 92 or (GWonder[woGardens].EffectiveOwner = p) then 93 result := 0 94 else if (Tile and fTerrain = fDesert) and 95 (Tile and fSpecial <> fSpecial1 { Oasis } ) then 96 begin 97 assert((Tile and fTerImp <> tiIrrigation) and (Tile and fTerImp <> tiFarm)); 98 result := (DesertThurst * MP - 1) div RW[p].Model[mix].Speed + 1 106 99 end 107 else if Tile and fTerrain=fArctic then108 begin 109 assert((Tile and fTerImp<>tiIrrigation) and (Tile and fTerImp<>tiFarm));110 result:=(ArcticThurst*MP-1) div RW[p].Model[mix].Speed +1100 else if Tile and fTerrain = fArctic then 101 begin 102 assert((Tile and fTerImp <> tiIrrigation) and (Tile and fTerImp <> tiFarm)); 103 result := (ArcticThurst * MP - 1) div RW[p].Model[mix].Speed + 1 111 104 end 112 else result:=0 105 else 106 result := 0 113 107 end; 114 108 115 function Controlled(p,Loc: integer; IsDest: boolean): integer; 116 {whether tile at Loc is in control zone of enemy unit 117 returns combination of tile control flags} 118 var 119 Loc1,V8: integer; 120 Adjacent: TVicinity8Loc; 121 begin 122 result:=0; 123 if IsDest and (Occupant[Loc]=p) and (ZoCMap[Loc]>0) then exit; 109 function Controlled(p, Loc: integer; IsDest: boolean): integer; 110 { whether tile at Loc is in control zone of enemy unit 111 returns combination of tile control flags } 112 var 113 Loc1, V8: integer; 114 Adjacent: TVicinity8Loc; 115 begin 116 result := 0; 117 if IsDest and (Occupant[Loc] = p) and (ZoCMap[Loc] > 0) then 118 exit; 124 119 // destination tile, not controlled if already occupied 125 120 126 if (RealMap[Loc] and fCity=0) 127 or (integer(RealMap[Loc] shr 27)<>p) and (ServerVersion[p]>=$000EF0) then121 if (RealMap[Loc] and fCity = 0) or (integer(RealMap[Loc] shr 27) <> p) and 122 (ServerVersion[p] >= $000EF0) then 128 123 begin // not own city 129 V8_to_Loc(Loc,Adjacent); 130 for V8:=0 to 7 do 131 begin 132 Loc1:=Adjacent[V8]; 133 if (Loc1>=0) and (Loc1<MapSize) 134 and (ZoCMap[Loc1]>0) 135 and (Occupant[Loc1]>=0) and (Occupant[Loc1]<>p) 136 and (RW[p].Treaty[Occupant[Loc1]]<trAlliance) then 137 if ObserveLevel[Loc1] and (3 shl (p*2))>0 then 124 V8_to_Loc(Loc, Adjacent); 125 for V8 := 0 to 7 do 126 begin 127 Loc1 := Adjacent[V8]; 128 if (Loc1 >= 0) and (Loc1 < MapSize) and (ZoCMap[Loc1] > 0) and 129 (Occupant[Loc1] >= 0) and (Occupant[Loc1] <> p) and 130 (RW[p].Treaty[Occupant[Loc1]] < trAlliance) then 131 if ObserveLevel[Loc1] and (3 shl (p * 2)) > 0 then 138 132 begin // p observes tile 139 result:=coKnown or coTrue; 140 exit 141 end 142 else result:=coTrue; // p does not observe tile 133 result := coKnown or coTrue; 134 exit 135 end 136 else 137 result := coTrue; // p does not observe tile 143 138 end; 144 139 end 145 140 end; 146 141 147 function GetMoveCost(p,mix,FromLoc,ToLoc,MoveLength: integer; var MoveCost: integer): integer; 142 function GetMoveCost(p, mix, FromLoc, ToLoc, MoveLength: integer; 143 var MoveCost: integer): integer; 148 144 // MoveLength - 2 for short move, 3 for long move 149 145 var 150 FromTile,ToTile: integer; 151 begin 152 result:=eOK; 153 FromTile:=RealMap[FromLoc]; 154 ToTile:=RealMap[ToLoc]; 155 with RW[p].Model[mix] do 156 begin 157 case Domain of 158 dGround: 159 if (ToTile and fTerrain>=fGrass) then {domain ok} 160 // if (Flags and mdCivil<>0) and (ToTile and fDeadLands<>0) then result:=eEerie 161 // else 162 begin {valid move} 163 if (FromTile and (fRR or fCity)<>0) 164 and (ToTile and (fRR or fCity)<>0) then 165 if GWonder[woShinkansen].EffectiveOwner=p then MoveCost:=0 166 else MoveCost:=Speed*(4*1311) shr 17 //move along railroad 167 else if (FromTile and (fRoad or fRR or fCity)<>0) 168 and (ToTile and (fRoad or fRR or fCity)<>0) 169 or (FromTile and ToTile and (fRiver or fCanal)<>0) 170 or (Cap[mcAlpine]>0) then 171 //move along road, river or canal 172 if Cap[mcOver]>0 then MoveCost:=40 173 else MoveCost:=20 174 else if Cap[mcOver]>0 then result:=eNoRoad 175 else case Terrain[ToTile and fTerrain].MoveCost of 176 1: MoveCost:=50; // plain terrain 177 2: 178 begin 179 assert(Speed-150<=600); 180 MoveCost:=50+(Speed-150)*13 shr 7; // heavy terrain 181 end; 182 3: 183 begin 184 MoveCost:=Speed; 185 result:=eMountains; 186 exit 187 end; 146 FromTile, ToTile: integer; 147 begin 148 result := eOK; 149 FromTile := RealMap[FromLoc]; 150 ToTile := RealMap[ToLoc]; 151 with RW[p].Model[mix] do 152 begin 153 case Domain of 154 dGround: 155 if (ToTile and fTerrain >= fGrass) then { domain ok } 156 // if (Flags and mdCivil<>0) and (ToTile and fDeadLands<>0) then result:=eEerie 157 // else 158 begin { valid move } 159 if (FromTile and (fRR or fCity) <> 0) and 160 (ToTile and (fRR or fCity) <> 0) then 161 if GWonder[woShinkansen].EffectiveOwner = p then 162 MoveCost := 0 163 else 164 MoveCost := Speed * (4 * 1311) shr 17 // move along railroad 165 else if (FromTile and (fRoad or fRR or fCity) <> 0) and 166 (ToTile and (fRoad or fRR or fCity) <> 0) or 167 (FromTile and ToTile and (fRiver or fCanal) <> 0) or 168 (Cap[mcAlpine] > 0) then 169 // move along road, river or canal 170 if Cap[mcOver] > 0 then 171 MoveCost := 40 172 else 173 MoveCost := 20 174 else if Cap[mcOver] > 0 then 175 result := eNoRoad 176 else 177 case Terrain[ToTile and fTerrain].MoveCost of 178 1: 179 MoveCost := 50; // plain terrain 180 2: 181 begin 182 assert(Speed - 150 <= 600); 183 MoveCost := 50 + (Speed - 150) * 13 shr 7; // heavy terrain 184 end; 185 3: 186 begin 187 MoveCost := Speed; 188 result := eMountains; 189 exit 190 end; 188 191 end; 189 MoveCost:=MoveCost*MoveLength; 190 end 191 else result:=eDomainMismatch; 192 193 dSea: 194 if (ToTile and (fCity or fCanal)<>0) 195 or (ToTile and fTerrain<fGrass) then {domain ok} 196 if (ToTile and fTerrain<>fOcean) or (Cap[mcNav]>0) then 197 MoveCost:=50*MoveLength {valid move} 198 else result:=eNoNav {navigation required for open sea} 199 else result:=eDomainMismatch; 200 201 dAir: 202 MoveCost:=50*MoveLength; {always valid move} 192 MoveCost := MoveCost * MoveLength; 193 end 194 else 195 result := eDomainMismatch; 196 197 dSea: 198 if (ToTile and (fCity or fCanal) <> 0) or (ToTile and fTerrain < fGrass) 199 then { domain ok } 200 if (ToTile and fTerrain <> fOcean) or (Cap[mcNav] > 0) then 201 MoveCost := 50 * MoveLength { valid move } 202 else 203 result := eNoNav { navigation required for open sea } 204 else 205 result := eDomainMismatch; 206 207 dAir: 208 MoveCost := 50 * MoveLength; { always valid move } 203 209 end 204 210 end 205 211 end; 206 212 207 function CalculateMove(p, uix,ToLoc,MoveLength: integer; TestOnly: boolean;213 function CalculateMove(p, uix, ToLoc, MoveLength: integer; TestOnly: boolean; 208 214 var MoveInfo: TMoveInfo): integer; 209 215 var 210 uix1,p1,FromLoc,DestControlled,AStr,DStr,ABaseDamage,DBaseDamage: integer; 211 PModel: ^TModel; 212 BattleForecast: TBattleForecast; 213 begin 214 with RW[p],Un[uix] do 215 begin 216 PModel:=@Model[mix]; 217 FromLoc:=Loc; 218 219 BattleForecast.pAtt:=p; 220 BattleForecast.mixAtt:=mix; 221 BattleForecast.HealthAtt:=Health; 222 BattleForecast.ExpAtt:=Exp; 223 BattleForecast.FlagsAtt:=Flags; 224 BattleForecast.Movement:=Movement; 225 result:=GetBattleForecast(ToLoc,BattleForecast,MoveInfo.Duix,MoveInfo.Dcix,AStr,DStr,ABaseDamage,DBaseDamage); 226 227 if result=eHiddenUnit then 228 if TestOnly then result:=eOK // behave just like unit was moving 229 else if Mode>moLoading_Fast then 230 Map[ToLoc]:=Map[ToLoc] or fHiddenUnit; 231 if result=eStealthUnit then 232 if TestOnly then result:=eOK // behave just like unit was moving 233 else if Mode>moLoading_Fast then 234 Map[ToLoc]:=Map[ToLoc] or fStealthUnit; 235 if result<rExecuted then exit; 236 237 case result of 238 eOk: MoveInfo.MoveType:=mtMove; 239 eExpelled: MoveInfo.MoveType:=mtExpel; 240 else MoveInfo.MoveType:=mtAttack; 241 end; 242 243 if MoveInfo.MoveType=mtMove then 244 begin 245 if Mode=moPlaying then 246 begin 247 p1:=RealMap[ToLoc] shr 27; 248 if (p1<nPl) and (p1<>p) 249 and ((RealMap[Loc] shr 27<>Cardinal(p1)) 250 and (PModel.Kind<>mkDiplomat) 251 and (Treaty[p1]>=trPeace) and (Treaty[p1]<trAlliance) 252 or (RealMap[ToLoc] and fCity<>0) and (Treaty[p1]>=trPeace)) then 253 begin result:=eTreaty; exit end; // keep peace treaty! 216 uix1, p1, FromLoc, DestControlled, AStr, DStr, ABaseDamage, 217 DBaseDamage: integer; 218 PModel: ^TModel; 219 BattleForecast: TBattleForecast; 220 begin 221 with RW[p], Un[uix] do 222 begin 223 PModel := @Model[mix]; 224 FromLoc := Loc; 225 226 BattleForecast.pAtt := p; 227 BattleForecast.mixAtt := mix; 228 BattleForecast.HealthAtt := Health; 229 BattleForecast.ExpAtt := Exp; 230 BattleForecast.FlagsAtt := Flags; 231 BattleForecast.Movement := Movement; 232 result := GetBattleForecast(ToLoc, BattleForecast, MoveInfo.Duix, 233 MoveInfo.Dcix, AStr, DStr, ABaseDamage, DBaseDamage); 234 235 if result = eHiddenUnit then 236 if TestOnly then 237 result := eOK // behave just like unit was moving 238 else if Mode > moLoading_Fast then 239 Map[ToLoc] := Map[ToLoc] or fHiddenUnit; 240 if result = eStealthUnit then 241 if TestOnly then 242 result := eOK // behave just like unit was moving 243 else if Mode > moLoading_Fast then 244 Map[ToLoc] := Map[ToLoc] or fStealthUnit; 245 if result < rExecuted then 246 exit; 247 248 case result of 249 eOK: 250 MoveInfo.MoveType := mtMove; 251 eExpelled: 252 MoveInfo.MoveType := mtExpel; 253 else 254 MoveInfo.MoveType := mtAttack; 255 end; 256 257 if MoveInfo.MoveType = mtMove then 258 begin 259 if Mode = moPlaying then 260 begin 261 p1 := RealMap[ToLoc] shr 27; 262 if (p1 < nPl) and (p1 <> p) and 263 ((RealMap[Loc] shr 27 <> Cardinal(p1)) and (PModel.Kind <> mkDiplomat) 264 and (Treaty[p1] >= trPeace) and (Treaty[p1] < trAlliance) or 265 (RealMap[ToLoc] and fCity <> 0) and (Treaty[p1] >= trPeace)) then 266 begin 267 result := eTreaty; 268 exit 269 end; // keep peace treaty! 254 270 end; 255 if (RealMap[ToLoc] and fCity<>0) 256 and (RealMap[ToLoc] shr 27<>Cardinal(p)) then // empty enemy city 257 if PModel.Kind=mkDiplomat then 258 begin 259 MoveInfo.MoveType:=mtSpyMission; 260 end 261 else if PModel.Domain=dGround then 262 begin 263 if PModel.Flags and mdCivil<>0 then 264 begin result:=eNoCapturer; exit end; 265 MoveInfo.MoveType:=mtCapture; 266 end 271 if (RealMap[ToLoc] and fCity <> 0) and 272 (RealMap[ToLoc] shr 27 <> Cardinal(p)) then // empty enemy city 273 if PModel.Kind = mkDiplomat then 274 begin 275 MoveInfo.MoveType := mtSpyMission; 276 end 277 else if PModel.Domain = dGround then 278 begin 279 if PModel.Flags and mdCivil <> 0 then 280 begin 281 result := eNoCapturer; 282 exit 283 end; 284 MoveInfo.MoveType := mtCapture; 285 end 286 else 287 begin 288 if (PModel.Domain = dSea) and (PModel.Cap[mcArtillery] = 0) then 289 begin 290 result := eDomainMismatch; 291 exit 292 end 293 else if (PModel.Attack = 0) and 294 not((PModel.Cap[mcBombs] > 0) and (Flags and unBombsLoaded <> 0)) 295 then 296 begin 297 result := eNoBombarder; 298 exit 299 end 300 else if Movement < 100 then 301 begin 302 result := eNoTime_Bombard; 303 exit 304 end; 305 MoveInfo.MoveType := mtBombard; 306 result := eBombarded; 307 end 308 end; 309 310 MoveInfo.MountainDelay := false; 311 if MoveInfo.MoveType in [mtAttack, mtBombard, mtExpel] then 312 begin 313 if (Master >= 0) or (PModel.Domain = dSea) and 314 (RealMap[Loc] and fTerrain >= fGrass) or (PModel.Domain = dAir) and 315 ((RealMap[Loc] and fCity <> 0) or (RealMap[Loc] and fTerImp = tiBase)) 316 then 317 begin 318 result := eViolation; 319 exit 320 end; 321 if MoveInfo.MoveType = mtBombard then 322 begin 323 MoveInfo.EndHealth := Health; 324 MoveInfo.EndHealthDef := -1; 325 end 267 326 else 268 begin 269 if (PModel.Domain=dSea) and (PModel.Cap[mcArtillery]=0) then 270 begin result:=eDomainMismatch; exit end 271 else if (PModel.Attack=0) 272 and not ((PModel.Cap[mcBombs]>0) and (Flags and unBombsLoaded<>0)) then 273 begin result:=eNoBombarder; exit end 274 else if Movement<100 then 275 begin result:=eNoTime_Bombard; exit end; 276 MoveInfo.MoveType:=mtBombard; 277 result:=eBombarded; 278 end 279 end; 280 281 MoveInfo.MountainDelay:=false; 282 if MoveInfo.MoveType in [mtAttack,mtBombard,mtExpel] then 283 begin 284 if (Master>=0) 285 or (PModel.Domain=dSea) and (RealMap[Loc] and fTerrain>=fGrass) 286 or (PModel.Domain=dAir) and ((RealMap[Loc] and fCity<>0) 287 or (RealMap[Loc] and fTerImp=tiBase)) then 288 begin result:=eViolation; exit end; 289 if MoveInfo.MoveType=mtBombard then 290 begin 291 MoveInfo.EndHealth:=Health; 292 MoveInfo.EndHealthDef:=-1; 293 end 294 else 295 begin 296 MoveInfo.EndHealth:=BattleForecast.EndHealthAtt; 297 MoveInfo.EndHealthDef:=BattleForecast.EndHealthDef; 327 begin 328 MoveInfo.EndHealth := BattleForecast.EndHealthAtt; 329 MoveInfo.EndHealthDef := BattleForecast.EndHealthDef; 298 330 end 299 331 end 300 else // if MoveInfo.MoveType in [mtMove,mtCapture,mtSpyMission] then301 begin 302 if (Master>=0) and (PModel.Domain<dSea) then332 else // if MoveInfo.MoveType in [mtMove,mtCapture,mtSpyMission] then 333 begin 334 if (Master >= 0) and (PModel.Domain < dSea) then 303 335 begin // transport unload 304 MoveInfo.Cost:=PModel.Speed;305 if RealMap[ToLoc] and fTerrain<fGrass then306 result:=eDomainMismatch;336 MoveInfo.Cost := PModel.Speed; 337 if RealMap[ToLoc] and fTerrain < fGrass then 338 result := eDomainMismatch; 307 339 end 308 else 309 begin 310 result:=GetMoveCost(p,mix,FromLoc,ToLoc,MoveLength,MoveInfo.Cost); 311 if result=eMountains then 312 begin result:=eOk; MoveInfo.MountainDelay:=true end; 340 else 341 begin 342 result := GetMoveCost(p, mix, FromLoc, ToLoc, MoveLength, 343 MoveInfo.Cost); 344 if result = eMountains then 345 begin 346 result := eOK; 347 MoveInfo.MountainDelay := true 348 end; 313 349 end; 314 if (result>=rExecuted) and (MoveInfo.MoveType=mtSpyMission) then 315 result:=eMissionDone; 316 317 MoveInfo.ToMaster:=-1; 318 if (result=eDomainMismatch) and (PModel.Domain<dSea) 319 and (PModel.Cap[mcOver]=0) then 320 begin 321 for uix1:=0 to nUn-1 do with Un[uix1] do // check load to transport 322 if (Loc=ToLoc) 323 and (TroopLoad<Model[mix].MTrans*Model[mix].Cap[mcSeaTrans]) then 324 begin 325 result:=eLoaded; 326 MoveInfo.Cost:=PModel.Speed; 327 MoveInfo.ToMaster:=uix1; 328 if (uixSelectedTransport>=0) and (uix1=uixSelectedTransport) then 329 Break; 330 end; 350 if (result >= rExecuted) and (MoveInfo.MoveType = mtSpyMission) then 351 result := eMissionDone; 352 353 MoveInfo.ToMaster := -1; 354 if (result = eDomainMismatch) and (PModel.Domain < dSea) and 355 (PModel.Cap[mcOver] = 0) then 356 begin 357 for uix1 := 0 to nUn - 1 do 358 with Un[uix1] do // check load to transport 359 if (Loc = ToLoc) and 360 (TroopLoad < Model[mix].MTrans * Model[mix].Cap[mcSeaTrans]) then 361 begin 362 result := eLoaded; 363 MoveInfo.Cost := PModel.Speed; 364 MoveInfo.ToMaster := uix1; 365 if (uixSelectedTransport >= 0) and (uix1 = uixSelectedTransport) 366 then 367 Break; 368 end; 331 369 end 332 else if (PModel.Domain=dAir) and (PModel.Cap[mcAirTrans]=0) 333 and (RealMap[ToLoc] and fCity=0) and (RealMap[ToLoc] and fTerImp<>tiBase) then 334 begin 335 for uix1:=0 to nUn-1 do with Un[uix1] do 336 if (Loc=ToLoc) 337 and (AirLoad<Model[mix].MTrans*Model[mix].Cap[mcCarrier]) then 338 begin// load plane to ship 339 result:=eLoaded; 340 MoveInfo.ToMaster:=uix1; 341 if (uixSelectedTransport>=0) and (uix1=uixSelectedTransport) then 342 Break; 343 end 370 else if (PModel.Domain = dAir) and (PModel.Cap[mcAirTrans] = 0) and 371 (RealMap[ToLoc] and fCity = 0) and (RealMap[ToLoc] and fTerImp <> tiBase) 372 then 373 begin 374 for uix1 := 0 to nUn - 1 do 375 with Un[uix1] do 376 if (Loc = ToLoc) and 377 (AirLoad < Model[mix].MTrans * Model[mix].Cap[mcCarrier]) then 378 begin // load plane to ship 379 result := eLoaded; 380 MoveInfo.ToMaster := uix1; 381 if (uixSelectedTransport >= 0) and (uix1 = uixSelectedTransport) 382 then 383 Break; 384 end 344 385 end; 345 if result<rExecuted then exit; 346 347 if (Master<0) and (MoveInfo.ToMaster<0) then 348 MoveInfo.EndHealth:=Health-HostileDamage(p,mix,ToLoc,MoveInfo.Cost) 349 else MoveInfo.EndHealth:=Health; 350 351 if (Mode=moPlaying) 352 and (PModel.Flags and mdZOC<>0) 353 and (Master<0) and (MoveInfo.ToMaster<0) 354 and (Controlled(p,FromLoc,false)>=coTrue) then 355 begin 356 DestControlled:=Controlled(p,ToLoc,true); 357 if DestControlled>=coTrue+coKnown then 358 begin result:=eZOC; exit end 359 else if not TestOnly and (DestControlled>=coTrue) then 360 begin result:=eZOC_EnemySpotted; exit end 386 if result < rExecuted then 387 exit; 388 389 if (Master < 0) and (MoveInfo.ToMaster < 0) then 390 MoveInfo.EndHealth := Health - HostileDamage(p, mix, ToLoc, 391 MoveInfo.Cost) 392 else 393 MoveInfo.EndHealth := Health; 394 395 if (Mode = moPlaying) and (PModel.Flags and mdZOC <> 0) and (Master < 0) 396 and (MoveInfo.ToMaster < 0) and (Controlled(p, FromLoc, false) >= coTrue) 397 then 398 begin 399 DestControlled := Controlled(p, ToLoc, true); 400 if DestControlled >= coTrue + coKnown then 401 begin 402 result := eZOC; 403 exit 404 end 405 else if not TestOnly and (DestControlled >= coTrue) then 406 begin 407 result := eZOC_EnemySpotted; 408 exit 409 end 361 410 end; 362 if (Movement=0) and (ServerVersion[p]>=$0100F1) or (MoveInfo.Cost>Movement) then 363 if (Master>=0) or (MoveInfo.ToMaster>=0) then 364 begin result:=eNoTime_Load; exit end 365 else begin result:=eNoTime_Move; exit end; 366 if (MoveInfo.EndHealth<=0) or (MoveInfo.MoveType=mtSpyMission) then 367 result:=result or rUnitRemoved; // spy mission or victim of HostileDamage 411 if (Movement = 0) and (ServerVersion[p] >= $0100F1) or 412 (MoveInfo.Cost > Movement) then 413 if (Master >= 0) or (MoveInfo.ToMaster >= 0) then 414 begin 415 result := eNoTime_Load; 416 exit 417 end 418 else 419 begin 420 result := eNoTime_Move; 421 exit 422 end; 423 if (MoveInfo.EndHealth <= 0) or (MoveInfo.MoveType = mtSpyMission) then 424 result := result or rUnitRemoved; 425 // spy mission or victim of HostileDamage 368 426 369 427 end; // if MoveInfo.MoveType in [mtMove,mtCapture,mtSpyMission] 370 428 371 if MoveInfo.MoveType in [mtAttack,mtExpel] then372 MoveInfo.Defender:=Occupant[ToLoc]373 else if RealMap[ToLoc] and fCity<>0 then429 if MoveInfo.MoveType in [mtAttack, mtExpel] then 430 MoveInfo.Defender := Occupant[ToLoc] 431 else if RealMap[ToLoc] and fCity <> 0 then 374 432 begin // MoveInfo.Dcix not set yet 375 MoveInfo.Defender:=RealMap[ToLoc] shr 27;376 SearchCity(ToLoc,MoveInfo.Defender,MoveInfo.Dcix);433 MoveInfo.Defender := RealMap[ToLoc] shr 27; 434 SearchCity(ToLoc, MoveInfo.Defender, MoveInfo.Dcix); 377 435 end 378 436 end 379 end; // CalculateMove437 end; // CalculateMove 380 438 381 439 function GetBattleForecast(Loc: integer; var BattleForecast: TBattleForecast; 382 var Duix,Dcix,AStr,DStr,ABaseDamage,DBaseDamage: integer): integer; 383 var 384 Time,Defender,ABon,DBon,DCnt,MultiDamage: integer; 385 PModel,DModel: ^TModel; 386 begin 387 with BattleForecast do 388 begin 389 Defender:=Occupant[Loc]; 390 if (Defender<0) or (Defender=pAtt) then 391 begin result:=eOK; exit end; // no attack, simple move 392 393 PModel:=@RW[pAtt].Model[mixAtt]; 394 Strongest(Loc,Duix,DStr,DBon,DCnt); {get defense strength and bonus} 395 if (PModel.Kind=mkDiplomat) and (RealMap[Loc] and fCity<>0) then 440 var Duix, Dcix, AStr, DStr, ABaseDamage, DBaseDamage: integer): integer; 441 var 442 Time, Defender, ABon, DBon, DCnt, MultiDamage: integer; 443 PModel, DModel: ^TModel; 444 begin 445 with BattleForecast do 446 begin 447 Defender := Occupant[Loc]; 448 if (Defender < 0) or (Defender = pAtt) then 449 begin 450 result := eOK; 451 exit 452 end; // no attack, simple move 453 454 PModel := @RW[pAtt].Model[mixAtt]; 455 Strongest(Loc, Duix, DStr, DBon, DCnt); { get defense strength and bonus } 456 if (PModel.Kind = mkDiplomat) and (RealMap[Loc] and fCity <> 0) then 396 457 begin // spy mission -- return as if move was possible 397 EndHealthAtt:=HealthAtt; 398 EndHealthDef:=RW[Defender].Un[Duix].Health; 399 result:=eOk; 400 exit 401 end; 402 403 DModel:=@RW[Defender].Model[RW[Defender].Un[Duix].mix]; 404 if (RealMap[Loc] and fCity=0) and (RealMap[Loc] and fTerImp<>tiBase) then 405 begin 406 if (DModel.Cap[mcSub]>0) 407 and (RealMap[Loc] and fTerrain<fGrass) 408 and (ObserveLevel[Loc] shr (2*pAtt) and 3<lObserveAll) then 409 begin result:=eHiddenUnit; exit; end; //attacking submarine not allowed 410 if (DModel.Cap[mcStealth]>0) 411 and (ObserveLevel[Loc] shr (2*pAtt) and 3<>lObserveSuper) then 412 begin result:=eStealthUnit; exit; end; //attacking stealth aircraft not allowed 413 if (DModel.Domain=dAir) and (DModel.Kind<>mkSpecial_Glider) 414 and (PModel.Domain<>dAir) then 415 begin result:=eDomainMismatch; exit end; //can't attack plane 416 end; 417 if ((PModel.Cap[mcArtillery]=0) 418 or ((ServerVersion[pAtt]>=$010200) and (RealMap[Loc] and fTerrain<fGrass) 419 and (DModel.Cap[mcSub]>0))) // ground units can't attack submarines 420 and ((PModel.Domain=dGround) and (RealMap[Loc] and fTerrain<fGrass) 421 or (PModel.Domain=dSea) and (RealMap[Loc] and fTerrain>=fGrass)) then 422 begin result:=eDomainMismatch; exit end; 423 if (PModel.Attack=0) 424 and not ((PModel.Cap[mcBombs]>0) and (FlagsAtt and unBombsLoaded<>0) 425 and (DModel.Domain<dAir)) then 426 begin result:=eInvalid; exit end; 427 428 if Movement=0 then 429 begin result:=eNoTime_Attack; exit end; 430 431 {$IFOPT O-}assert(InvalidTreatyMap=0);{$ENDIF} 432 if RW[pAtt].Treaty[Defender]>=trPeace then 433 begin 434 if (PModel.Domain<>dAir) 435 and (PModel.Attack>0) and (integer(RealMap[Loc] shr 27)=pAtt) then 436 if Movement>=100 then 458 EndHealthAtt := HealthAtt; 459 EndHealthDef := RW[Defender].Un[Duix].Health; 460 result := eOK; 461 exit 462 end; 463 464 DModel := @RW[Defender].Model[RW[Defender].Un[Duix].mix]; 465 if (RealMap[Loc] and fCity = 0) and (RealMap[Loc] and fTerImp <> tiBase) 466 then 467 begin 468 if (DModel.Cap[mcSub] > 0) and (RealMap[Loc] and fTerrain < fGrass) and 469 (ObserveLevel[Loc] shr (2 * pAtt) and 3 < lObserveAll) then 470 begin 471 result := eHiddenUnit; 472 exit; 473 end; // attacking submarine not allowed 474 if (DModel.Cap[mcStealth] > 0) and 475 (ObserveLevel[Loc] shr (2 * pAtt) and 3 <> lObserveSuper) then 476 begin 477 result := eStealthUnit; 478 exit; 479 end; // attacking stealth aircraft not allowed 480 if (DModel.Domain = dAir) and (DModel.Kind <> mkSpecial_Glider) and 481 (PModel.Domain <> dAir) then 482 begin 483 result := eDomainMismatch; 484 exit 485 end; // can't attack plane 486 end; 487 if ((PModel.Cap[mcArtillery] = 0) or ((ServerVersion[pAtt] >= $010200) and 488 (RealMap[Loc] and fTerrain < fGrass) and (DModel.Cap[mcSub] > 0))) 489 // ground units can't attack submarines 490 and ((PModel.Domain = dGround) and (RealMap[Loc] and fTerrain < fGrass) or 491 (PModel.Domain = dSea) and (RealMap[Loc] and fTerrain >= fGrass)) then 492 begin 493 result := eDomainMismatch; 494 exit 495 end; 496 if (PModel.Attack = 0) and not((PModel.Cap[mcBombs] > 0) and 497 (FlagsAtt and unBombsLoaded <> 0) and (DModel.Domain < dAir)) then 498 begin 499 result := eInvalid; 500 exit 501 end; 502 503 if Movement = 0 then 504 begin 505 result := eNoTime_Attack; 506 exit 507 end; 508 509 {$IFOPT O-}assert(InvalidTreatyMap = 0); {$ENDIF} 510 if RW[pAtt].Treaty[Defender] >= trPeace then 511 begin 512 if (PModel.Domain <> dAir) and (PModel.Attack > 0) and 513 (integer(RealMap[Loc] shr 27) = pAtt) then 514 if Movement >= 100 then 437 515 begin // expel friendly unit 438 EndHealthDef:=RW[Defender].Un[Duix].Health; 439 EndHealthAtt:=HealthAtt; 440 result:=eExpelled 441 end 442 else result:=eNoTime_Expel 443 else result:=eTreaty; 444 exit; 445 end; 446 447 // calculate defender strength 448 if RealMap[Loc] and fCity<>0 then 516 EndHealthDef := RW[Defender].Un[Duix].Health; 517 EndHealthAtt := HealthAtt; 518 result := eExpelled 519 end 520 else 521 result := eNoTime_Expel 522 else 523 result := eTreaty; 524 exit; 525 end; 526 527 // calculate defender strength 528 if RealMap[Loc] and fCity <> 0 then 449 529 begin // consider city improvements 450 SearchCity(Loc,Defender,Dcix); 451 if (PModel.Domain<dSea) and (PModel.Cap[mcArtillery]=0) 452 and ((RW[Defender].City[Dcix].Built[imWalls]=1) 453 or (Continent[RW[Defender].City[Dcix].Loc]=GrWallContinent[Defender])) then 454 inc(DBon,8) 455 else if (PModel.Domain=dSea) 456 and (RW[Defender].City[Dcix].Built[imCoastalFort]=1) then 457 inc(DBon,4) 458 else if (PModel.Domain=dAir) 459 and (RW[Defender].City[Dcix].Built[imMissileBat]=1) then 460 inc(DBon,4); 461 if RW[Defender].City[Dcix].Built[imBunker]=1 then 462 inc(DBon,4) 463 end; 464 if (PModel.Domain=dAir) and (DModel.Cap[mcAirDef]>0) then 465 inc(DBon,4); 466 DStr:=DModel.Defense*DBon*100; 467 if (DModel.Domain=dAir) and ((RealMap[Loc] and fCity<>0) 468 or (RealMap[Loc] and fTerImp=tiBase)) then 469 DStr:=0; 470 if (DModel.Domain=dSea) and (RealMap[Loc] and fTerrain>=fGrass) then 471 DStr:=DStr shr 1; 472 473 // calculate attacker strength 474 if PModel.Cap[mcWill]>0 then Time:=100 475 else begin Time:=Movement; if Time>100 then Time:=100; end; 476 ABon:=4+ExpAtt div ExpCost; 477 AStr:=PModel.Attack; 478 if (FlagsAtt and unBombsLoaded<>0) and (DModel.Domain<dAir) then // use bombs 479 AStr:=AStr+PModel.Cap[mcBombs]*PModel.MStrength*2; 480 AStr:=Time*AStr*ABon; 481 482 // calculate base damage for defender 483 if DStr=0 then 484 DBaseDamage:=RW[Defender].Un[Duix].Health 485 else 486 begin 487 DBaseDamage:=HealthAtt*AStr div DStr; 488 if DBaseDamage=0 then 489 DBaseDamage:=1; 490 if DBaseDamage>RW[Defender].Un[Duix].Health then 491 DBaseDamage:=RW[Defender].Un[Duix].Health 492 end; 493 494 // calculate base damage for attacker 495 if AStr=0 then 496 ABaseDamage:=HealthAtt 497 else 498 begin 499 ABaseDamage:=RW[Defender].Un[Duix].Health*DStr div AStr; 500 if ABaseDamage=0 then 501 ABaseDamage:=1; 502 if ABaseDamage>HealthAtt then 503 ABaseDamage:=HealthAtt 504 end; 505 506 // calculate final damage for defender 507 MultiDamage:=2; 508 if (ABaseDamage=HealthAtt) and (PModel.Cap[mcFanatic]>0) 509 and not (RW[pAtt].Government in [gRepublic,gDemocracy,gFuture]) then 510 MultiDamage:=MultiDamage*2; // fanatic attacker died 511 EndHealthDef:=RW[Defender].Un[Duix].Health-MultiDamage*DBaseDamage div 2; 512 if EndHealthDef<0 then EndHealthDef:=0; 513 514 // calculate final damage for attacker 515 MultiDamage:=2; 516 if DBaseDamage=RW[Defender].Un[Duix].Health then 517 begin 518 if (DModel.Cap[mcFanatic]>0) 519 and not (RW[Defender].Government in [gRepublic,gDemocracy,gFuture]) then 520 MultiDamage:=MultiDamage*2; // fanatic defender died 521 if PModel.Cap[mcFirst]>0 then 522 MultiDamage:=MultiDamage shr 1; // first strike unit wins 523 end; 524 Time:=Movement; if Time>100 then Time:=100; 525 EndHealthAtt:=HealthAtt-MultiDamage*ABaseDamage div 2-HostileDamage(pAtt,mixAtt,Loc,Time); 526 if EndHealthAtt<0 then EndHealthAtt:=0; 527 528 if EndHealthDef>0 then result:=eLost 529 else if EndHealthAtt>0 then result:=eWon 530 else result:=eBloody 530 SearchCity(Loc, Defender, Dcix); 531 if (PModel.Domain < dSea) and (PModel.Cap[mcArtillery] = 0) and 532 ((RW[Defender].City[Dcix].Built[imWalls] = 1) or 533 (Continent[RW[Defender].City[Dcix].Loc] = GrWallContinent[Defender])) 534 then 535 inc(DBon, 8) 536 else if (PModel.Domain = dSea) and 537 (RW[Defender].City[Dcix].Built[imCoastalFort] = 1) then 538 inc(DBon, 4) 539 else if (PModel.Domain = dAir) and 540 (RW[Defender].City[Dcix].Built[imMissileBat] = 1) then 541 inc(DBon, 4); 542 if RW[Defender].City[Dcix].Built[imBunker] = 1 then 543 inc(DBon, 4) 544 end; 545 if (PModel.Domain = dAir) and (DModel.Cap[mcAirDef] > 0) then 546 inc(DBon, 4); 547 DStr := DModel.Defense * DBon * 100; 548 if (DModel.Domain = dAir) and ((RealMap[Loc] and fCity <> 0) or 549 (RealMap[Loc] and fTerImp = tiBase)) then 550 DStr := 0; 551 if (DModel.Domain = dSea) and (RealMap[Loc] and fTerrain >= fGrass) then 552 DStr := DStr shr 1; 553 554 // calculate attacker strength 555 if PModel.Cap[mcWill] > 0 then 556 Time := 100 557 else 558 begin 559 Time := Movement; 560 if Time > 100 then 561 Time := 100; 562 end; 563 ABon := 4 + ExpAtt div ExpCost; 564 AStr := PModel.Attack; 565 if (FlagsAtt and unBombsLoaded <> 0) and (DModel.Domain < dAir) then 566 // use bombs 567 AStr := AStr + PModel.Cap[mcBombs] * PModel.MStrength * 2; 568 AStr := Time * AStr * ABon; 569 570 // calculate base damage for defender 571 if DStr = 0 then 572 DBaseDamage := RW[Defender].Un[Duix].Health 573 else 574 begin 575 DBaseDamage := HealthAtt * AStr div DStr; 576 if DBaseDamage = 0 then 577 DBaseDamage := 1; 578 if DBaseDamage > RW[Defender].Un[Duix].Health then 579 DBaseDamage := RW[Defender].Un[Duix].Health 580 end; 581 582 // calculate base damage for attacker 583 if AStr = 0 then 584 ABaseDamage := HealthAtt 585 else 586 begin 587 ABaseDamage := RW[Defender].Un[Duix].Health * DStr div AStr; 588 if ABaseDamage = 0 then 589 ABaseDamage := 1; 590 if ABaseDamage > HealthAtt then 591 ABaseDamage := HealthAtt 592 end; 593 594 // calculate final damage for defender 595 MultiDamage := 2; 596 if (ABaseDamage = HealthAtt) and (PModel.Cap[mcFanatic] > 0) and 597 not(RW[pAtt].Government in [gRepublic, gDemocracy, gFuture]) then 598 MultiDamage := MultiDamage * 2; // fanatic attacker died 599 EndHealthDef := RW[Defender].Un[Duix].Health - MultiDamage * 600 DBaseDamage div 2; 601 if EndHealthDef < 0 then 602 EndHealthDef := 0; 603 604 // calculate final damage for attacker 605 MultiDamage := 2; 606 if DBaseDamage = RW[Defender].Un[Duix].Health then 607 begin 608 if (DModel.Cap[mcFanatic] > 0) and 609 not(RW[Defender].Government in [gRepublic, gDemocracy, gFuture]) then 610 MultiDamage := MultiDamage * 2; // fanatic defender died 611 if PModel.Cap[mcFirst] > 0 then 612 MultiDamage := MultiDamage shr 1; // first strike unit wins 613 end; 614 Time := Movement; 615 if Time > 100 then 616 Time := 100; 617 EndHealthAtt := HealthAtt - MultiDamage * ABaseDamage div 2 - 618 HostileDamage(pAtt, mixAtt, Loc, Time); 619 if EndHealthAtt < 0 then 620 EndHealthAtt := 0; 621 622 if EndHealthDef > 0 then 623 result := eLost 624 else if EndHealthAtt > 0 then 625 result := eWon 626 else 627 result := eBloody 531 628 end 532 end; //GetBattleForecast 533 534 function LoadUnit(p,uix: integer; TestOnly: boolean): integer; 535 var 536 uix1,d,Cost,ToMaster: integer; 537 begin 538 result:=eOk; 539 with RW[p].Un[uix] do 540 begin 541 d:=RW[p].Model[mix].Domain; 542 if (Master>=0) or (d=dSea) 543 or (RW[p].Model[mix].Cap[mcAirTrans] 544 +RW[p].Model[mix].Cap[mcOver]>0) then 545 result:=eViolation 546 else 547 begin 548 ToMaster:=-1; 549 for uix1:=0 to RW[p].nUn-1 do if RW[p].Un[uix1].Loc=Loc then 550 with RW[p].Un[uix1], RW[p].Model[mix] do 551 if (d<dSea) and (TroopLoad<MTrans*(Cap[mcSeaTrans]+Cap[mcAirTrans])) 552 or (d=dAir) and (AirLoad<MTrans*Cap[mcCarrier]) then 553 begin {load onto unit uix1} 554 if (uixSelectedTransport<0) or (uix1=uixSelectedTransport) then 555 begin ToMaster:=uix1; Break end 556 else if ToMaster<0 then 557 ToMaster:=uix1; 558 end; 559 if ToMaster<0 then result:=eNoLoadCapacity 629 end; // GetBattleForecast 630 631 function LoadUnit(p, uix: integer; TestOnly: boolean): integer; 632 var 633 uix1, d, Cost, ToMaster: integer; 634 begin 635 result := eOK; 636 with RW[p].Un[uix] do 637 begin 638 d := RW[p].Model[mix].Domain; 639 if (Master >= 0) or (d = dSea) or 640 (RW[p].Model[mix].Cap[mcAirTrans] + RW[p].Model[mix].Cap[mcOver] > 0) then 641 result := eViolation 560 642 else 561 begin 562 if d=dAir then Cost:=100 563 else Cost:=RW[p].Model[mix].Speed; 564 if Movement<Cost then result:=eNoTime_Load 565 else if not TestOnly then 566 begin 567 FreeUnit(p,uix); 568 dec(Movement,Cost); 569 if d=dAir then inc(RW[p].Un[ToMaster].AirLoad) 570 else inc(RW[p].Un[ToMaster].TroopLoad); 571 Master:=ToMaster; 572 UpdateUnitMap(Loc); 643 begin 644 ToMaster := -1; 645 for uix1 := 0 to RW[p].nUn - 1 do 646 if RW[p].Un[uix1].Loc = Loc then 647 with RW[p].Un[uix1], RW[p].Model[mix] do 648 if (d < dSea) and 649 (TroopLoad < MTrans * (Cap[mcSeaTrans] + Cap[mcAirTrans])) or 650 (d = dAir) and (AirLoad < MTrans * Cap[mcCarrier]) then 651 begin { load onto unit uix1 } 652 if (uixSelectedTransport < 0) or (uix1 = uixSelectedTransport) 653 then 654 begin 655 ToMaster := uix1; 656 Break 657 end 658 else if ToMaster < 0 then 659 ToMaster := uix1; 660 end; 661 if ToMaster < 0 then 662 result := eNoLoadCapacity 663 else 664 begin 665 if d = dAir then 666 Cost := 100 667 else 668 Cost := RW[p].Model[mix].Speed; 669 if Movement < Cost then 670 result := eNoTime_Load 671 else if not TestOnly then 672 begin 673 FreeUnit(p, uix); 674 dec(Movement, Cost); 675 if d = dAir then 676 inc(RW[p].Un[ToMaster].AirLoad) 677 else 678 inc(RW[p].Un[ToMaster].TroopLoad); 679 Master := ToMaster; 680 UpdateUnitMap(Loc); 573 681 end 574 682 end … … 577 685 end; 578 686 579 function UnloadUnit(p,uix: integer; TestOnly: boolean): integer; 580 var 581 Cost: integer; 582 begin 583 result:=eOk; 584 with RW[p].Un[uix] do 585 if Master<0 then result:=eNotChanged 586 else if (RW[p].Model[mix].Domain<dSea) 587 and (RealMap[Loc] and fTerrain<fGrass) then result:=eDomainMismatch 588 // else if (RW[p].Model[mix].Domain<dSea) 589 // and (RW[p].Model[mix].Flags and mdCivil<>0) 590 // and (RealMap[Loc] and fDeadLands<>0) then result:=eEerie 591 else 592 begin 593 if RW[p].Model[mix].Domain=dAir then Cost:=100 594 else Cost:=RW[p].Model[mix].Speed; 595 if Movement<Cost then result:=eNoTime_Load 596 else if not TestOnly then 597 begin 598 dec(Movement,Cost); 599 if RW[p].Model[mix].Domain=dAir then 600 dec(RW[p].Un[Master].AirLoad) 687 function UnloadUnit(p, uix: integer; TestOnly: boolean): integer; 688 var 689 Cost: integer; 690 begin 691 result := eOK; 692 with RW[p].Un[uix] do 693 if Master < 0 then 694 result := eNotChanged 695 else if (RW[p].Model[mix].Domain < dSea) and 696 (RealMap[Loc] and fTerrain < fGrass) then 697 result := eDomainMismatch 698 // else if (RW[p].Model[mix].Domain<dSea) 699 // and (RW[p].Model[mix].Flags and mdCivil<>0) 700 // and (RealMap[Loc] and fDeadLands<>0) then result:=eEerie 701 else 702 begin 703 if RW[p].Model[mix].Domain = dAir then 704 Cost := 100 601 705 else 602 begin 603 dec(RW[p].Un[Master].TroopLoad); 604 // Movement:=0 // no more movement after unload 706 Cost := RW[p].Model[mix].Speed; 707 if Movement < Cost then 708 result := eNoTime_Load 709 else if not TestOnly then 710 begin 711 dec(Movement, Cost); 712 if RW[p].Model[mix].Domain = dAir then 713 dec(RW[p].Un[Master].AirLoad) 714 else 715 begin 716 dec(RW[p].Un[Master].TroopLoad); 717 // Movement:=0 // no more movement after unload 605 718 end; 606 Master:=-1;607 PlaceUnit(p,uix);608 UpdateUnitMap(Loc);719 Master := -1; 720 PlaceUnit(p, uix); 721 UpdateUnitMap(Loc); 609 722 end; 610 723 end 611 724 end; 612 725 613 procedure Recover(p,uix: integer); 614 var 615 cix,Recovery: integer; 616 begin 617 with RW[p],Un[uix] do 618 begin 619 if (Master>=0) and (Model[Un[Master].mix].Cap[mcSupplyShip]>0) then 620 Recovery:=FastRecovery {hospital ship} 621 else if RealMap[Loc] and fTerImp=tiBase then 622 Recovery:=CityRecovery 623 else if RealMap[Loc] and fCity<>0 then 624 begin {unit in city} 625 cix:=nCity-1; 626 while (cix>=0) and (City[cix].Loc<>Loc) do dec(cix); 627 if City[cix].Flags and chDisorder<>0 then 628 Recovery:=NoCityRecovery 629 else if (Model[mix].Domain=dGround) 630 and (City[cix].Built[imBarracks]+City[cix].Built[imElite]>0) 631 or (Model[mix].Domain=dSea) and (City[cix].Built[imDockyard]=1) 632 or (Model[mix].Domain=dAir) and (City[cix].Built[imAirport]=1) then 633 Recovery:=FastRecovery {city has baracks/shipyard/airport} 634 else Recovery:=CityRecovery 726 procedure Recover(p, uix: integer); 727 var 728 cix, Recovery: integer; 729 begin 730 with RW[p], Un[uix] do 731 begin 732 if (Master >= 0) and (Model[Un[Master].mix].Cap[mcSupplyShip] > 0) then 733 Recovery := FastRecovery { hospital ship } 734 else if RealMap[Loc] and fTerImp = tiBase then 735 Recovery := CityRecovery 736 else if RealMap[Loc] and fCity <> 0 then 737 begin { unit in city } 738 cix := nCity - 1; 739 while (cix >= 0) and (City[cix].Loc <> Loc) do 740 dec(cix); 741 if City[cix].Flags and chDisorder <> 0 then 742 Recovery := NoCityRecovery 743 else if (Model[mix].Domain = dGround) and 744 (City[cix].Built[imBarracks] + City[cix].Built[imElite] > 0) or 745 (Model[mix].Domain = dSea) and (City[cix].Built[imDockyard] = 1) or 746 (Model[mix].Domain = dAir) and (City[cix].Built[imAirport] = 1) then 747 Recovery := FastRecovery { city has baracks/shipyard/airport } 748 else 749 Recovery := CityRecovery 635 750 end 636 else if (RealMap[Loc] and fTerrain>=fGrass) and (Model[mix].Domain<>dAir) then 637 Recovery:=NoCityRecovery 638 else Recovery:=0; 639 640 Recovery:=Recovery*Movement div Model[mix].Speed; {recovery depends on movement unused} 641 if Recovery>Health then Recovery:=Health; // health max. doubled each turn 642 if Recovery>100-Health then Recovery:=100-Health; 643 inc(Health,Recovery); 751 else if (RealMap[Loc] and fTerrain >= fGrass) and (Model[mix].Domain <> dAir) 752 then 753 Recovery := NoCityRecovery 754 else 755 Recovery := 0; 756 757 Recovery := Recovery * Movement div Model[mix].Speed; 758 { recovery depends on movement unused } 759 if Recovery > Health then 760 Recovery := Health; // health max. doubled each turn 761 if Recovery > 100 - Health then 762 Recovery := 100 - Health; 763 inc(Health, Recovery); 644 764 end; 645 765 end; 646 766 647 function GetMoveAdvice(p, uix: integer; var a: TMoveAdviceData): integer;767 function GetMoveAdvice(p, uix: integer; var a: TMoveAdviceData): integer; 648 768 const 649 //domains 650 gmaAir=0; gmaSea=1; gmaGround_NoZoC=2; gmaGround_ZoC=3; 651 //flags 652 gmaNav=4; gmaOver=4; gmaAlpine=8; 653 var 654 i,FromLoc,EndLoc,T,T1,maxmov,initmov,Loc,Loc1,FromTile,ToTile,V8, 655 MoveInfo,HeavyCost,RailCost,MoveCost,AddDamage,MaxDamage,MovementLeft: integer; 656 Map: ^TTileList; 657 Q: TIPQ; 658 Adjacent: TVicinity8Loc; 659 From: array[0..lxmax*lymax-1] of integer; 660 Time: array[0..lxmax*lymax-1] of integer; 661 Damage: array[0..lxmax*lymax-1] of integer; 662 MountainDelay, Resistant: boolean; 663 // tt,tt0: int64; 664 begin 665 // QueryPerformanceCounter(tt0); 666 667 MaxDamage:=RW[p].Un[uix].Health-1; 668 if MaxDamage>a.MaxHostile_MovementLeft then 669 if a.MaxHostile_MovementLeft>=0 then 670 MaxDamage:=a.MaxHostile_MovementLeft 671 else MaxDamage:=0; 672 673 Map:=@(RW[p].Map^); 674 if (a.ToLoc<>maNextCity) and ((a.ToLoc<0) or (a.ToLoc>=MapSize)) then 675 begin result:=eInvalid; exit end; 676 if (a.ToLoc<>maNextCity) and (Map[a.ToLoc] and fTerrain=fUNKNOWN) then 677 begin result:=eNoWay; exit end; 678 679 with RW[p].Model[RW[p].Un[uix].mix] do 680 case Domain of 681 dGround: 682 if (a.ToLoc<>maNextCity) and (Map[a.ToLoc] and fTerrain=fOcean) then 683 begin result:=eDomainMismatch; exit end 684 else 685 begin 686 if Flags and mdZOC<>0 then MoveInfo:=gmaGround_ZoC 687 else MoveInfo:=gmaGround_NoZoC; 688 if Cap[mcOver]>0 then inc(MoveInfo,gmaOver); 689 if Cap[mcAlpine]>0 then inc(MoveInfo,gmaAlpine); 690 HeavyCost:=50+(Speed-150)*13 shr 7; 691 if GWonder[woShinkansen].EffectiveOwner=p then RailCost:=0 692 else RailCost:=Speed*(4*1311) shr 17; 693 maxmov:=Speed; 694 initmov:=0; 695 Resistant:= (GWonder[woGardens].EffectiveOwner=p) or 696 (Kind=mkSettler) and (Speed>=200); 769 // domains 770 gmaAir = 0; 771 gmaSea = 1; 772 gmaGround_NoZoC = 2; 773 gmaGround_ZoC = 3; 774 // flags 775 gmaNav = 4; 776 gmaOver = 4; 777 gmaAlpine = 8; 778 var 779 i, FromLoc, EndLoc, T, T1, maxmov, initmov, Loc, Loc1, FromTile, ToTile, V8, 780 MoveInfo, HeavyCost, RailCost, MoveCost, AddDamage, MaxDamage, 781 MovementLeft: integer; 782 Map: ^TTileList; 783 Q: TIPQ; 784 Adjacent: TVicinity8Loc; 785 From: array [0 .. lxmax * lymax - 1] of integer; 786 Time: array [0 .. lxmax * lymax - 1] of integer; 787 Damage: array [0 .. lxmax * lymax - 1] of integer; 788 MountainDelay, Resistant: boolean; 789 // tt,tt0: int64; 790 begin 791 // QueryPerformanceCounter(tt0); 792 793 MaxDamage := RW[p].Un[uix].Health - 1; 794 if MaxDamage > a.MaxHostile_MovementLeft then 795 if a.MaxHostile_MovementLeft >= 0 then 796 MaxDamage := a.MaxHostile_MovementLeft 797 else 798 MaxDamage := 0; 799 800 Map := @(RW[p].Map^); 801 if (a.ToLoc <> maNextCity) and ((a.ToLoc < 0) or (a.ToLoc >= MapSize)) then 802 begin 803 result := eInvalid; 804 exit 805 end; 806 if (a.ToLoc <> maNextCity) and (Map[a.ToLoc] and fTerrain = fUNKNOWN) then 807 begin 808 result := eNoWay; 809 exit 810 end; 811 812 with RW[p].Model[RW[p].Un[uix].mix] do 813 case Domain of 814 dGround: 815 if (a.ToLoc <> maNextCity) and (Map[a.ToLoc] and fTerrain = fOcean) then 816 begin 817 result := eDomainMismatch; 818 exit 819 end 820 else 821 begin 822 if Flags and mdZOC <> 0 then 823 MoveInfo := gmaGround_ZoC 824 else 825 MoveInfo := gmaGround_NoZoC; 826 if Cap[mcOver] > 0 then 827 inc(MoveInfo, gmaOver); 828 if Cap[mcAlpine] > 0 then 829 inc(MoveInfo, gmaAlpine); 830 HeavyCost := 50 + (Speed - 150) * 13 shr 7; 831 if GWonder[woShinkansen].EffectiveOwner = p then 832 RailCost := 0 833 else 834 RailCost := Speed * (4 * 1311) shr 17; 835 maxmov := Speed; 836 initmov := 0; 837 Resistant := (GWonder[woGardens].EffectiveOwner = p) or 838 (Kind = mkSettler) and (Speed >= 200); 697 839 end; 698 dSea: 699 if (a.ToLoc<>maNextCity) and (Map[a.ToLoc] and fTerrain>=fGrass) 700 and (Map[a.ToLoc] and (fCity or fUnit or fCanal)=0) then 701 begin result:=eDomainMismatch; exit end 702 else 703 begin 704 MoveInfo:=gmaSea; 705 if Cap[mcNav]>0 then inc(MoveInfo,gmaNav); 706 maxmov:=UnitSpeed(p,RW[p].Un[uix].mix,100); 707 initmov:=maxmov-UnitSpeed(p,RW[p].Un[uix].mix, 708 RW[p].Un[uix].Health); 840 dSea: 841 if (a.ToLoc <> maNextCity) and (Map[a.ToLoc] and fTerrain >= fGrass) and 842 (Map[a.ToLoc] and (fCity or fUnit or fCanal) = 0) then 843 begin 844 result := eDomainMismatch; 845 exit 846 end 847 else 848 begin 849 MoveInfo := gmaSea; 850 if Cap[mcNav] > 0 then 851 inc(MoveInfo, gmaNav); 852 maxmov := UnitSpeed(p, RW[p].Un[uix].mix, 100); 853 initmov := maxmov - UnitSpeed(p, RW[p].Un[uix].mix, 854 RW[p].Un[uix].Health); 709 855 end; 710 dAir: 711 begin 712 MoveInfo:=gmaAir; 713 maxmov:=Speed; 714 initmov:=0; 715 end 716 end; 717 718 FromLoc:=RW[p].Un[uix].Loc; 719 FillChar(Time,SizeOf(Time),255); {-1} 720 Damage[FromLoc]:=0; 721 Q:=TIPQ.Create(MapSize); 722 Q.Put(FromLoc,(maxmov-RW[p].Un[uix].Movement) shl 8); 723 while Q.Get(Loc,T) do 724 begin 725 Time[Loc]:=T; 726 if T>=(a.MoreTurns+1) shl 20 then begin Loc:=-1; Break end; 727 FromTile:=Map[Loc]; 728 if (Loc=a.ToLoc) or (a.ToLoc=maNextCity) and (FromTile and fCity<>0) then 729 Break; 730 if T and $FFF00=$FFF00 then inc(T,$100000); // indicates mountain delay 731 V8_to_Loc(Loc,Adjacent); 732 for V8:=0 to 7 do 733 begin 734 Loc1:=Adjacent[V8]; 735 if (Loc1>=0) and (Loc1<MapSize) and (Time[Loc1]<0) then 736 begin 737 ToTile:=Map[Loc1]; 738 if (Loc1=a.ToLoc) and (ToTile and (fUnit or fOwned)=fUnit) 739 and not ((MoveInfo and 3=gmaSea) and (FromTile and fTerrain>=fGrass)) 740 and not ((MoveInfo and 3=gmaAir) and ((FromTile and fCity<>0) 741 or (FromTile and fTerImp=tiBase))) then 856 dAir: 857 begin 858 MoveInfo := gmaAir; 859 maxmov := Speed; 860 initmov := 0; 861 end 862 end; 863 864 FromLoc := RW[p].Un[uix].Loc; 865 FillChar(Time, SizeOf(Time), 255); { -1 } 866 Damage[FromLoc] := 0; 867 Q := TIPQ.Create(MapSize); 868 Q.Put(FromLoc, (maxmov - RW[p].Un[uix].Movement) shl 8); 869 while Q.Get(Loc, T) do 870 begin 871 Time[Loc] := T; 872 if T >= (a.MoreTurns + 1) shl 20 then 873 begin 874 Loc := -1; 875 Break 876 end; 877 FromTile := Map[Loc]; 878 if (Loc = a.ToLoc) or (a.ToLoc = maNextCity) and (FromTile and fCity <> 0) 879 then 880 Break; 881 if T and $FFF00 = $FFF00 then 882 inc(T, $100000); // indicates mountain delay 883 V8_to_Loc(Loc, Adjacent); 884 for V8 := 0 to 7 do 885 begin 886 Loc1 := Adjacent[V8]; 887 if (Loc1 >= 0) and (Loc1 < MapSize) and (Time[Loc1] < 0) then 888 begin 889 ToTile := Map[Loc1]; 890 if (Loc1 = a.ToLoc) and (ToTile and (fUnit or fOwned) = fUnit) and 891 not((MoveInfo and 3 = gmaSea) and (FromTile and fTerrain >= fGrass)) 892 and not((MoveInfo and 3 = gmaAir) and ((FromTile and fCity <> 0) or 893 (FromTile and fTerImp = tiBase))) then 742 894 begin // attack position found 743 if Q.Put(Loc1,T+1) then From[Loc1]:=Loc; 744 end 745 else if (ToTile and fTerrain<>fUNKNOWN) 746 and ((Loc1=a.ToLoc) or (ToTile and (fCity or fOwned)<>fCity)) // don't move through enemy cities 747 and ((Loc1=a.ToLoc) or (ToTile and (fUnit or fOwned)<>fUnit)) // way is blocked 748 and (ToTile and not FromTile and fPeace=0) 749 and ((MoveInfo and 3<gmaGround_ZoC) 750 or (ToTile and FromTile and fInEnemyZoc=0) 751 or (ToTile and fOwnZoCUnit<>0) 752 or (FromTile and fCity<>0) 753 or (ToTile and (fCity or fOwned)=fCity or fOwned)) then 754 begin 755 // calculate move cost, must be identic to GetMoveCost function 756 AddDamage:=0; 757 MountainDelay:=false; 758 case MoveInfo of 759 760 gmaAir: 761 MoveCost:=50; {always valid move} 762 763 gmaSea: 764 if (ToTile and (fCity or fCanal)<>0) 765 or (ToTile and fTerrain=fShore) then {domain ok} 766 MoveCost:=50 {valid move} 767 else MoveCost:=-1; 768 769 gmaSea+gmaNav: 770 if (ToTile and (fCity or fCanal)<>0) 771 or (ToTile and fTerrain<fGrass) then {domain ok} 772 MoveCost:=50 {valid move} 773 else MoveCost:=-1; 895 if Q.Put(Loc1, T + 1) then 896 From[Loc1] := Loc; 897 end 898 else if (ToTile and fTerrain <> fUNKNOWN) and 899 ((Loc1 = a.ToLoc) or (ToTile and (fCity or fOwned) <> fCity)) 900 // don't move through enemy cities 901 and ((Loc1 = a.ToLoc) or (ToTile and (fUnit or fOwned) <> fUnit)) 902 // way is blocked 903 and (ToTile and not FromTile and fPeace = 0) and 904 ((MoveInfo and 3 < gmaGround_ZoC) or (ToTile and FromTile and 905 fInEnemyZoc = 0) or (ToTile and fOwnZoCUnit <> 0) or 906 (FromTile and fCity <> 0) or (ToTile and (fCity or fOwned) = fCity or 907 fOwned)) then 908 begin 909 // calculate move cost, must be identic to GetMoveCost function 910 AddDamage := 0; 911 MountainDelay := false; 912 case MoveInfo of 913 914 gmaAir: 915 MoveCost := 50; { always valid move } 916 917 gmaSea: 918 if (ToTile and (fCity or fCanal) <> 0) or 919 (ToTile and fTerrain = fShore) then { domain ok } 920 MoveCost := 50 { valid move } 921 else 922 MoveCost := -1; 923 924 gmaSea + gmaNav: 925 if (ToTile and (fCity or fCanal) <> 0) or 926 (ToTile and fTerrain < fGrass) then { domain ok } 927 MoveCost := 50 { valid move } 928 else 929 MoveCost := -1; 774 930 775 931 else // ground unit 776 if (ToTile and fTerrain>=fGrass) then {domain ok} 777 begin {valid move} 778 if (FromTile and (fRR or fCity)<>0) 779 and (ToTile and (fRR or fCity)<>0) then 780 MoveCost:=RailCost //move along railroad 781 else if (FromTile and (fRoad or fRR or fCity)<>0) 782 and (ToTile and (fRoad or fRR or fCity)<>0) 783 or (FromTile and ToTile and (fRiver or fCanal)<>0) 784 or (MoveInfo and gmaAlpine<>0) then 785 //move along road, river or canal 786 if MoveInfo and gmaOver<>0 then MoveCost:=40 787 else MoveCost:=20 788 else if MoveInfo and gmaOver<>0 then MoveCost:=-1 789 else case Terrain[ToTile and fTerrain].MoveCost of 790 1: MoveCost:=50; // plain terrain 791 2: MoveCost:=HeavyCost; // heavy terrain 792 3: 793 begin 794 MoveCost:=maxmov; 795 MountainDelay:=true; 796 end; 932 if (ToTile and fTerrain >= fGrass) then { domain ok } 933 begin { valid move } 934 if (FromTile and (fRR or fCity) <> 0) and 935 (ToTile and (fRR or fCity) <> 0) then 936 MoveCost := RailCost // move along railroad 937 else if (FromTile and (fRoad or fRR or fCity) <> 0) and 938 (ToTile and (fRoad or fRR or fCity) <> 0) or 939 (FromTile and ToTile and (fRiver or fCanal) <> 0) or 940 (MoveInfo and gmaAlpine <> 0) then 941 // move along road, river or canal 942 if MoveInfo and gmaOver <> 0 then 943 MoveCost := 40 944 else 945 MoveCost := 20 946 else if MoveInfo and gmaOver <> 0 then 947 MoveCost := -1 948 else 949 case Terrain[ToTile and fTerrain].MoveCost of 950 1: 951 MoveCost := 50; // plain terrain 952 2: 953 MoveCost := HeavyCost; // heavy terrain 954 3: 955 begin 956 MoveCost := maxmov; 957 MountainDelay := true; 958 end; 797 959 end; 798 960 799 961 // calculate HostileDamage 800 if not resistant and (ToTile and fTerImp<>tiBase) then 801 if ToTile and (fTerrain or fCity or fRiver or fCanal or fSpecial1{Oasis})=fDesert then 802 begin 803 if V8 and 1<>0 then 804 AddDamage:=((DesertThurst*3)*MoveCost-1) div maxmov +1 805 else AddDamage:=((DesertThurst*2)*MoveCost-1) div maxmov +1 806 end 807 else if ToTile and (fTerrain or fCity or fRiver or fCanal)=fArctic then 808 begin 809 if V8 and 1<>0 then 810 AddDamage:=((ArcticThurst*3)*MoveCost-1) div maxmov +1 811 else AddDamage:=((ArcticThurst*2)*MoveCost-1) div maxmov +1 812 end; 813 end 814 else MoveCost:=-1; 962 if not Resistant and (ToTile and fTerImp <> tiBase) then 963 if ToTile and (fTerrain or fCity or fRiver or fCanal or 964 fSpecial1 { Oasis } ) = fDesert then 965 begin 966 if V8 and 1 <> 0 then 967 AddDamage := ((DesertThurst * 3) * MoveCost - 1) 968 div maxmov + 1 969 else 970 AddDamage := ((DesertThurst * 2) * MoveCost - 1) 971 div maxmov + 1 972 end 973 else if ToTile and (fTerrain or fCity or fRiver or fCanal) = fArctic 974 then 975 begin 976 if V8 and 1 <> 0 then 977 AddDamage := ((ArcticThurst * 3) * MoveCost - 1) 978 div maxmov + 1 979 else 980 AddDamage := ((ArcticThurst * 2) * MoveCost - 1) 981 div maxmov + 1 982 end; 983 end 984 else 985 MoveCost := -1; 815 986 816 987 end; 817 988 818 if (MoveCost>0) and not MountainDelay then 819 if V8 and 1<>0 then inc(MoveCost,MoveCost*2) 820 else inc(MoveCost,MoveCost); 821 822 if (MoveInfo and 2<>0) // ground unit, check transport load/unload 823 and ((MoveCost<0) 824 and (ToTile and (fUnit or fOwned)=fUnit or fOwned) // assume ship/airplane is transport -- load! 825 or (MoveCost>=0) and (FromTile and fTerrain<fGrass)) then 826 MoveCost:=maxmov; // transport load or unload 827 828 if MoveCost>=0 then 829 begin {valid move} 830 MovementLeft:=maxmov-T shr 8 and $FFF-MoveCost; 831 if (MovementLeft<0) or ((MoveCost=0) and (MovementLeft=0)) then 989 if (MoveCost > 0) and not MountainDelay then 990 if V8 and 1 <> 0 then 991 inc(MoveCost, MoveCost * 2) 992 else 993 inc(MoveCost, MoveCost); 994 995 if (MoveInfo and 2 <> 0) // ground unit, check transport load/unload 996 and ((MoveCost < 0) and (ToTile and (fUnit or fOwned) = fUnit or 997 fOwned) // assume ship/airplane is transport -- load! 998 or (MoveCost >= 0) and (FromTile and fTerrain < fGrass)) then 999 MoveCost := maxmov; // transport load or unload 1000 1001 if MoveCost >= 0 then 1002 begin { valid move } 1003 MovementLeft := maxmov - T shr 8 and $FFF - MoveCost; 1004 if (MovementLeft < 0) or ((MoveCost = 0) and (MovementLeft = 0)) 1005 then 832 1006 begin // must wait for next turn 833 // calculate HostileDamage 834 if (MoveInfo and 2<>0){ground unit} 835 and not resistant and (FromTile and fTerImp<>tiBase) then 836 if FromTile and (fTerrain or fCity or fRiver or fCanal or fSpecial1{Oasis})=fDesert then 837 inc(AddDamage, (DesertThurst*(maxmov-T shr 8 and $FFF)-1) div maxmov +1) 838 else if FromTile and (fTerrain or fCity or fRiver or fCanal)=fArctic then 839 inc(AddDamage, (ArcticThurst*(maxmov-T shr 8 and $FFF)-1) div maxmov +1); 840 841 T1:=T and $7FF000FF +$100000+(initmov+MoveCost) shl 8; 1007 // calculate HostileDamage 1008 if (MoveInfo and 2 <> 0) { ground unit } 1009 and not Resistant and (FromTile and fTerImp <> tiBase) then 1010 if FromTile and (fTerrain or fCity or fRiver or fCanal or 1011 fSpecial1 { Oasis } ) = fDesert then 1012 inc(AddDamage, (DesertThurst * (maxmov - T shr 8 and $FFF) - 1013 1) div maxmov + 1) 1014 else if FromTile and (fTerrain or fCity or fRiver or fCanal) = fArctic 1015 then 1016 inc(AddDamage, (ArcticThurst * (maxmov - T shr 8 and $FFF) - 1017 1) div maxmov + 1); 1018 1019 T1 := T and $7FF000FF + $100000 + (initmov + MoveCost) shl 8; 842 1020 end 843 else T1:=T+MoveCost shl 8+1; 844 if MountainDelay then T1:=T1 or $FFF00; 845 if (Damage[Loc]+AddDamage<=MaxDamage) and (T1 and $FF<$FF) then 846 if Q.Put(Loc1,T1) then 1021 else 1022 T1 := T + MoveCost shl 8 + 1; 1023 if MountainDelay then 1024 T1 := T1 or $FFF00; 1025 if (Damage[Loc] + AddDamage <= MaxDamage) and (T1 and $FF < $FF) 1026 then 1027 if Q.Put(Loc1, T1) then 847 1028 begin 848 From[Loc1]:=Loc;849 Damage[Loc1]:=Damage[Loc]+AddDamage;1029 From[Loc1] := Loc; 1030 Damage[Loc1] := Damage[Loc] + AddDamage; 850 1031 end 851 1032 end … … 854 1035 end 855 1036 end; 856 Q.Free; 857 if (Loc=a.ToLoc) or (a.ToLoc=maNextCity) and (Loc>=0) 858 and (Map[Loc] and fCity<>0) then 859 begin 860 a.MoreTurns:=T shr 20; 861 EndLoc:=Loc; 862 a.nStep:=0; 863 while Loc<>FromLoc do 864 begin 865 if Time[Loc]<$100000 then inc(a.nStep); 866 Loc:=From[Loc]; 867 end; 868 Loc:=EndLoc; 869 i:=a.nStep; 870 while Loc<>FromLoc do 871 begin 872 if Time[Loc]<$100000 then 873 begin 874 dec(i); 875 if i<25 then 876 begin 877 a.dx[i]:=((Loc mod lx *2 +Loc div lx and 1) 878 -(From[Loc] mod lx *2 +From[Loc] div lx and 1)+3*lx) mod (2*lx) -lx; 879 a.dy[i]:=Loc div lx-From[Loc] div lx; 1037 Q.Free; 1038 if (Loc = a.ToLoc) or (a.ToLoc = maNextCity) and (Loc >= 0) and 1039 (Map[Loc] and fCity <> 0) then 1040 begin 1041 a.MoreTurns := T shr 20; 1042 EndLoc := Loc; 1043 a.nStep := 0; 1044 while Loc <> FromLoc do 1045 begin 1046 if Time[Loc] < $100000 then 1047 inc(a.nStep); 1048 Loc := From[Loc]; 1049 end; 1050 Loc := EndLoc; 1051 i := a.nStep; 1052 while Loc <> FromLoc do 1053 begin 1054 if Time[Loc] < $100000 then 1055 begin 1056 dec(i); 1057 if i < 25 then 1058 begin 1059 a.dx[i] := ((Loc mod lx * 2 + Loc div lx and 1) - 1060 (From[Loc] mod lx * 2 + From[Loc] div lx and 1) + 3 * lx) 1061 mod (2 * lx) - lx; 1062 a.dy[i] := Loc div lx - From[Loc] div lx; 880 1063 end 881 1064 end; 882 Loc:=From[Loc]; 883 end; 884 a.MaxHostile_MovementLeft:=maxmov-Time[EndLoc] shr 8 and $FFF; 885 if a.nStep>25 then a.nStep:=25; 886 result:=eOK 1065 Loc := From[Loc]; 1066 end; 1067 a.MaxHostile_MovementLeft := maxmov - Time[EndLoc] shr 8 and $FFF; 1068 if a.nStep > 25 then 1069 a.nStep := 25; 1070 result := eOK 887 1071 end 888 else result:=eNoWay; 889 890 // QueryPerformanceCounter(tt);{time in s is: (tt-tt0)/PerfFreq} 1072 else 1073 result := eNoWay; 1074 1075 // QueryPerformanceCounter(tt);{time in s is: (tt-tt0)/PerfFreq} 891 1076 end; // GetMoveAdvice 892 1077 893 function CanPlaneReturn(p,uix: integer; PlaneReturnData: TPlaneReturnData): boolean; 1078 function CanPlaneReturn(p, uix: integer; 1079 PlaneReturnData: TPlaneReturnData): boolean; 894 1080 const 895 mfEnd=1; mfReached=2; 896 var 897 uix1,T,T1,Loc,Loc1,FromTile,ToTile,V8,MoveCost,maxmov: integer; 898 Map: ^TTileList; 899 Q: TIPQ; 900 Adjacent: TVicinity8Loc; 901 MapFlags: array[0..lxmax*lymax-1] of byte; 902 begin 903 Map:=@(RW[p].Map^); 904 905 // calculate possible return points 906 FillChar(MapFlags,SizeOf(MapFlags),0); 907 if RW[p].Model[RW[p].Un[uix].mix].Kind=mkSpecial_Glider then 908 begin 909 for Loc:=0 to MapSize-1 do 910 if Map[Loc] and fTerrain>=fGrass then 911 MapFlags[Loc]:=MapFlags[Loc] or mfEnd; 1081 mfEnd = 1; 1082 mfReached = 2; 1083 var 1084 uix1, T, T1, Loc, Loc1, FromTile, ToTile, V8, MoveCost, maxmov: integer; 1085 Map: ^TTileList; 1086 Q: TIPQ; 1087 Adjacent: TVicinity8Loc; 1088 MapFlags: array [0 .. lxmax * lymax - 1] of byte; 1089 begin 1090 Map := @(RW[p].Map^); 1091 1092 // calculate possible return points 1093 FillChar(MapFlags, SizeOf(MapFlags), 0); 1094 if RW[p].Model[RW[p].Un[uix].mix].Kind = mkSpecial_Glider then 1095 begin 1096 for Loc := 0 to MapSize - 1 do 1097 if Map[Loc] and fTerrain >= fGrass then 1098 MapFlags[Loc] := MapFlags[Loc] or mfEnd; 912 1099 end 913 else 914 begin 915 for Loc:=0 to MapSize-1 do 916 if (Map[Loc] and (fCity or fOwned)=fCity or fOwned) 917 or (Map[Loc] and fTerImp=tiBase) and (Map[Loc] and fObserved<>0) 918 and (Map[Loc] and (fUnit or fOwned)<>fUnit) then 919 MapFlags[Loc]:=MapFlags[Loc] or mfEnd; 920 if RW[p].Model[RW[p].Un[uix].mix].Cap[mcAirTrans]=0 then // plane can land on carriers 921 for uix1:=0 to RW[p].nUn-1 do 922 with RW[p].Un[uix1], RW[p].Model[mix] do 923 if AirLoad<MTrans*Cap[mcCarrier] then 924 MapFlags[Loc]:=MapFlags[Loc] or mfEnd; 1100 else 1101 begin 1102 for Loc := 0 to MapSize - 1 do 1103 if (Map[Loc] and (fCity or fOwned) = fCity or fOwned) or 1104 (Map[Loc] and fTerImp = tiBase) and (Map[Loc] and fObserved <> 0) and 1105 (Map[Loc] and (fUnit or fOwned) <> fUnit) then 1106 MapFlags[Loc] := MapFlags[Loc] or mfEnd; 1107 if RW[p].Model[RW[p].Un[uix].mix].Cap[mcAirTrans] = 0 then 1108 // plane can land on carriers 1109 for uix1 := 0 to RW[p].nUn - 1 do 1110 with RW[p].Un[uix1], RW[p].Model[mix] do 1111 if AirLoad < MTrans * Cap[mcCarrier] then 1112 MapFlags[Loc] := MapFlags[Loc] or mfEnd; 925 1113 end; 926 1114 927 with RW[p].Un[uix] do928 begin 929 if Master>=0 then // can return to same carrier, even if full now930 MapFlags[Loc]:=MapFlags[Loc] or mfEnd;931 maxmov:=RW[p].Model[mix].Speed;1115 with RW[p].Un[uix] do 1116 begin 1117 if Master >= 0 then // can return to same carrier, even if full now 1118 MapFlags[Loc] := MapFlags[Loc] or mfEnd; 1119 maxmov := RW[p].Model[mix].Speed; 932 1120 end; 933 1121 934 result:=false; 935 Q:=TIPQ.Create(MapSize); 936 Q.Put(PlaneReturnData.Loc,(maxmov-PlaneReturnData.Movement) shl 8); 937 while Q.Get(Loc,T) do 938 begin 939 MapFlags[Loc]:=MapFlags[Loc] or mfReached; 940 if T>=(PlaneReturnData.Fuel+1) shl 20 then 941 begin result:=false; break end; 942 if MapFlags[Loc] and mfEnd<>0 then 943 begin result:=true; break end; 944 FromTile:=Map[Loc]; 945 V8_to_Loc(Loc,Adjacent); 946 for V8:=0 to 7 do 947 begin 948 Loc1:=Adjacent[V8]; 949 if (Loc1>=0) and (Loc1<MapSize) and (MapFlags[Loc1] and mfReached=0) then 950 begin 951 ToTile:=Map[Loc1]; 952 if (ToTile and fTerrain<>fUNKNOWN) 953 and (ToTile and (fCity or fOwned)<>fCity) // don't move through enemy cities 954 and (ToTile and (fUnit or fOwned)<>fUnit) // way is blocked 955 and (ToTile and not FromTile and fPeace=0) then 956 begin 957 if V8 and 1<>0 then MoveCost:=150 958 else MoveCost:=100; 959 if MoveCost+T shr 8 and $FFF>maxmov then // must wait for next turn 960 T1:=T and $7FF000FF +$100000+MoveCost shl 8 961 else T1:=T+MoveCost shl 8; 962 Q.Put(Loc1,T1); 1122 result := false; 1123 Q := TIPQ.Create(MapSize); 1124 Q.Put(PlaneReturnData.Loc, (maxmov - PlaneReturnData.Movement) shl 8); 1125 while Q.Get(Loc, T) do 1126 begin 1127 MapFlags[Loc] := MapFlags[Loc] or mfReached; 1128 if T >= (PlaneReturnData.Fuel + 1) shl 20 then 1129 begin 1130 result := false; 1131 Break 1132 end; 1133 if MapFlags[Loc] and mfEnd <> 0 then 1134 begin 1135 result := true; 1136 Break 1137 end; 1138 FromTile := Map[Loc]; 1139 V8_to_Loc(Loc, Adjacent); 1140 for V8 := 0 to 7 do 1141 begin 1142 Loc1 := Adjacent[V8]; 1143 if (Loc1 >= 0) and (Loc1 < MapSize) and (MapFlags[Loc1] and mfReached = 0) 1144 then 1145 begin 1146 ToTile := Map[Loc1]; 1147 if (ToTile and fTerrain <> fUNKNOWN) and 1148 (ToTile and (fCity or fOwned) <> fCity) 1149 // don't move through enemy cities 1150 and (ToTile and (fUnit or fOwned) <> fUnit) // way is blocked 1151 and (ToTile and not FromTile and fPeace = 0) then 1152 begin 1153 if V8 and 1 <> 0 then 1154 MoveCost := 150 1155 else 1156 MoveCost := 100; 1157 if MoveCost + T shr 8 and $FFF > maxmov then 1158 // must wait for next turn 1159 T1 := T and $7FF000FF + $100000 + MoveCost shl 8 1160 else 1161 T1 := T + MoveCost shl 8; 1162 Q.Put(Loc1, T1); 963 1163 end 964 1164 end 965 1165 end 966 1166 end; 967 Q.Free;1167 Q.Free; 968 1168 end; // CanPlaneReturn 969 1169 970 1170 { 971 972 ____________________________________________________________________1171 Terrain Improvement 1172 ____________________________________________________________________ 973 1173 } 974 function CalculateJobWork(p,Loc,Job: integer; var JobWork: integer): integer; 975 var 976 TerrType: integer; 977 begin 978 result:=eOK; 979 TerrType:=RealMap[Loc] and fTerrain; 980 with Terrain[TerrType] do case Job of 981 jCity: 982 if RealMap[Loc] and fCity<>0 then result:=eInvalid 983 else if IrrEff=0 then result:=eNoCityTerrain 984 else JobWork:=CityWork; 985 jRoad: 986 if RealMap[Loc] and (fRoad or fRR)=0 then 987 begin 988 JobWork:=MoveCost*RoadWork; 989 if RealMap[Loc] and fRiver<>0 then 990 if RW[p].Tech[adBridgeBuilding]>=tsApplicable then 991 inc(JobWork,RoadBridgeWork) {across river} 992 else result:=eNoBridgeBuilding 993 end 994 else result:=eInvalid; 995 jRR: 996 if RealMap[Loc] and fRoad=0 then result:=eNoPreq 997 else if RealMap[Loc] and fRR<>0 then result:=eInvalid 998 else 999 begin 1000 JobWork:=MoveCost*RRWork; 1001 if RealMap[Loc] and fRiver<>0 then 1002 inc(JobWork,RRBridgeWork); {across river} 1003 end; 1004 jClear: 1005 if (TerrType=fDesert) 1006 and (GWonder[woGardens].EffectiveOwner<>p) then 1007 result:=eInvalid 1008 else if ClearTerrain>=0 then 1009 JobWork:=IrrClearWork 1010 else result:=eInvalid; 1011 jIrr: 1012 begin 1013 JobWork:=IrrClearWork; 1014 if (IrrEff=0) 1015 or (RealMap[Loc] and fTerImp=tiIrrigation) 1016 or (RealMap[Loc] and fTerImp=tiFarm) then 1017 result:=eInvalid 1018 end; 1019 jFarm: 1020 if RealMap[Loc] and fTerImp<>tiIrrigation then result:=eNoPreq 1021 else 1022 begin 1023 JobWork:=IrrClearWork*FarmWork; 1024 if (JobWork<=0) or (RealMap[Loc] and fTerImp=tiFarm) then 1025 result:=eInvalid 1026 end; 1027 jAfforest: 1028 if AfforestTerrain>=0 then 1029 JobWork:=MineAfforestWork 1030 else result:=eInvalid; 1031 jMine: 1032 begin 1033 JobWork:=MineAfforestWork; 1034 if (MineEff=0) 1035 or (RealMap[Loc] and fTerImp=tiMine) then 1036 result:=eInvalid 1037 end; 1038 jFort: 1039 if RealMap[Loc] and fTerImp<>tiFort then 1040 JobWork:=MoveCost*FortWork 1041 else result:=eInvalid; 1042 jCanal: 1043 if (RealMap[Loc] and fCanal=0) and (TerrType in TerrType_Canalable) then 1044 JobWork:=CanalWork 1045 else result:=eInvalid; 1046 jTrans: 1047 begin 1048 JobWork:=TransWork; 1049 if JobWork<=0 then result:=eInvalid 1050 end; 1051 jPoll: 1052 if RealMap[Loc] and fPoll<>0 then JobWork:=PollWork 1053 else result:=eInvalid; 1054 jBase: 1055 if RealMap[Loc] and fTerImp<>tiBase then 1056 JobWork:=MoveCost*BaseWork 1057 else result:=eInvalid; 1058 jPillage: 1059 if RealMap[Loc] and (fRoad or fRR or fCanal or fTerImp)<>0 then 1060 JobWork:=PillageWork 1061 else result:=eInvalid; 1062 end; 1063 end; //CalculateJobWork 1064 1065 function StartJob(p,uix,NewJob: integer; TestOnly: boolean): integer; 1066 var 1067 JobWork, Loc0, p1, uix1, TerrType: integer; 1068 begin 1069 {$IFOPT O-}assert(1 shl p and InvalidTreatyMap=0);{$ENDIF} 1070 result:=eOK; 1071 with RW[p].Un[uix] do 1072 begin 1073 if NewJob=Job then 1074 begin result:=eNotChanged; exit end; 1075 if NewJob=jNone then 1076 begin if not TestOnly then Job:=jNone; exit end; 1077 Loc0:=Loc; 1078 if (RealMap[Loc0] and fDeadLands<>0) and (NewJob<>jRoad) and (NewJob<>jRR) then 1079 begin result:=eDeadLands; exit end; 1080 TerrType:=RealMap[Loc0] and fTerrain; 1081 if (RealMap[Loc0] and fCity<>0) or (TerrType<fGrass) 1082 or (Master>=0) 1083 or not ((NewJob=jPillage) and (RW[p].Model[mix].Domain=dGround) 1084 or (RW[p].Model[mix].Kind=mkSettler) 1085 or (NewJob<>jCity) and (RW[p].Model[mix].Kind=mkSlaves) 1086 and (GWonder[woPyramids].EffectiveOwner>=0)) then 1087 begin result:=eInvalid; exit end; 1088 if (JobPreq[NewJob]<>preNone) 1089 and (RW[p].Tech[JobPreq[NewJob]]<tsApplicable) then 1090 begin result:=eNoPreq; exit end; 1091 1092 result:=CalculateJobWork(p,Loc0,NewJob,JobWork); 1093 if (Mode=moPlaying) and (result=eOk) and (NewJob<>jPoll) then 1174 function CalculateJobWork(p, Loc, Job: integer; var JobWork: integer): integer; 1175 var 1176 TerrType: integer; 1177 begin 1178 result := eOK; 1179 TerrType := RealMap[Loc] and fTerrain; 1180 with Terrain[TerrType] do 1181 case Job of 1182 jCity: 1183 if RealMap[Loc] and fCity <> 0 then 1184 result := eInvalid 1185 else if IrrEff = 0 then 1186 result := eNoCityTerrain 1187 else 1188 JobWork := CityWork; 1189 jRoad: 1190 if RealMap[Loc] and (fRoad or fRR) = 0 then 1191 begin 1192 JobWork := MoveCost * RoadWork; 1193 if RealMap[Loc] and fRiver <> 0 then 1194 if RW[p].Tech[adBridgeBuilding] >= tsApplicable then 1195 inc(JobWork, RoadBridgeWork) { across river } 1196 else 1197 result := eNoBridgeBuilding 1198 end 1199 else 1200 result := eInvalid; 1201 jRR: 1202 if RealMap[Loc] and fRoad = 0 then 1203 result := eNoPreq 1204 else if RealMap[Loc] and fRR <> 0 then 1205 result := eInvalid 1206 else 1207 begin 1208 JobWork := MoveCost * RRWork; 1209 if RealMap[Loc] and fRiver <> 0 then 1210 inc(JobWork, RRBridgeWork); { across river } 1211 end; 1212 jClear: 1213 if (TerrType = fDesert) and (GWonder[woGardens].EffectiveOwner <> p) 1214 then 1215 result := eInvalid 1216 else if ClearTerrain >= 0 then 1217 JobWork := IrrClearWork 1218 else 1219 result := eInvalid; 1220 jIrr: 1221 begin 1222 JobWork := IrrClearWork; 1223 if (IrrEff = 0) or (RealMap[Loc] and fTerImp = tiIrrigation) or 1224 (RealMap[Loc] and fTerImp = tiFarm) then 1225 result := eInvalid 1226 end; 1227 jFarm: 1228 if RealMap[Loc] and fTerImp <> tiIrrigation then 1229 result := eNoPreq 1230 else 1231 begin 1232 JobWork := IrrClearWork * FarmWork; 1233 if (JobWork <= 0) or (RealMap[Loc] and fTerImp = tiFarm) then 1234 result := eInvalid 1235 end; 1236 jAfforest: 1237 if AfforestTerrain >= 0 then 1238 JobWork := MineAfforestWork 1239 else 1240 result := eInvalid; 1241 jMine: 1242 begin 1243 JobWork := MineAfforestWork; 1244 if (MineEff = 0) or (RealMap[Loc] and fTerImp = tiMine) then 1245 result := eInvalid 1246 end; 1247 jFort: 1248 if RealMap[Loc] and fTerImp <> tiFort then 1249 JobWork := MoveCost * FortWork 1250 else 1251 result := eInvalid; 1252 jCanal: 1253 if (RealMap[Loc] and fCanal = 0) and (TerrType in TerrType_Canalable) 1254 then 1255 JobWork := CanalWork 1256 else 1257 result := eInvalid; 1258 jTrans: 1259 begin 1260 JobWork := TransWork; 1261 if JobWork <= 0 then 1262 result := eInvalid 1263 end; 1264 jPoll: 1265 if RealMap[Loc] and fPoll <> 0 then 1266 JobWork := PollWork 1267 else 1268 result := eInvalid; 1269 jBase: 1270 if RealMap[Loc] and fTerImp <> tiBase then 1271 JobWork := MoveCost * BaseWork 1272 else 1273 result := eInvalid; 1274 jPillage: 1275 if RealMap[Loc] and (fRoad or fRR or fCanal or fTerImp) <> 0 then 1276 JobWork := PillageWork 1277 else 1278 result := eInvalid; 1279 end; 1280 end; // CalculateJobWork 1281 1282 function StartJob(p, uix, NewJob: integer; TestOnly: boolean): integer; 1283 var 1284 JobWork, Loc0, p1, uix1, TerrType: integer; 1285 begin 1286 {$IFOPT O-}assert(1 shl p and InvalidTreatyMap = 0); {$ENDIF} 1287 result := eOK; 1288 with RW[p].Un[uix] do 1289 begin 1290 if NewJob = Job then 1291 begin 1292 result := eNotChanged; 1293 exit 1294 end; 1295 if NewJob = jNone then 1296 begin 1297 if not TestOnly then 1298 Job := jNone; 1299 exit 1300 end; 1301 Loc0 := Loc; 1302 if (RealMap[Loc0] and fDeadLands <> 0) and (NewJob <> jRoad) and 1303 (NewJob <> jRR) then 1304 begin 1305 result := eDeadLands; 1306 exit 1307 end; 1308 TerrType := RealMap[Loc0] and fTerrain; 1309 if (RealMap[Loc0] and fCity <> 0) or (TerrType < fGrass) or (Master >= 0) or 1310 not((NewJob = jPillage) and (RW[p].Model[mix].Domain = dGround) or 1311 (RW[p].Model[mix].Kind = mkSettler) or (NewJob <> jCity) and 1312 (RW[p].Model[mix].Kind = mkSlaves) and (GWonder[woPyramids].EffectiveOwner 1313 >= 0)) then 1314 begin 1315 result := eInvalid; 1316 exit 1317 end; 1318 if (JobPreq[NewJob] <> preNone) and 1319 (RW[p].Tech[JobPreq[NewJob]] < tsApplicable) then 1320 begin 1321 result := eNoPreq; 1322 exit 1323 end; 1324 1325 result := CalculateJobWork(p, Loc0, NewJob, JobWork); 1326 if (Mode = moPlaying) and (result = eOK) and (NewJob <> jPoll) then 1094 1327 begin // not allowed in territory of friendly nation 1095 p1:=RealMap[Loc0] shr 27; // owner of territory 1096 if (p1<nPl) and (p1<>p) and (RW[p].Treaty[p1]>=trPeace) then 1097 result:=eTreaty; // keep peace treaty! 1098 end; 1099 if TestOnly or (result<rExecuted) then exit; 1100 1101 if (ToWork[Loc0,NewJob]=0) or (ToWork[Loc0,NewJob]>JobWork) then 1102 ToWork[Loc0,NewJob]:=JobWork; 1103 Job:=NewJob; 1104 Flags:=Flags and not unFortified; 1105 for uix1:=0 to RW[p].nUn-1 do 1106 if (RW[p].Un[uix1].Loc=Loc) 1107 and (RW[p].Un[uix1].Job in ContraJobs[NewJob]) then 1108 RW[p].Un[uix1].Job:=jNone; // stop contradictive jobs 1109 if ServerVersion[p]<$000EF0 then 1110 if Work(p,uix) then result:=eJobDone; 1111 if (NewJob=jCity) and (result=eJobDone) then 1112 begin 1113 RemoveUnit_UpdateMap(p,uix); 1114 result:=eCity 1328 p1 := RealMap[Loc0] shr 27; // owner of territory 1329 if (p1 < nPl) and (p1 <> p) and (RW[p].Treaty[p1] >= trPeace) then 1330 result := eTreaty; // keep peace treaty! 1331 end; 1332 if TestOnly or (result < rExecuted) then 1333 exit; 1334 1335 if (ToWork[Loc0, NewJob] = 0) or (ToWork[Loc0, NewJob] > JobWork) then 1336 ToWork[Loc0, NewJob] := JobWork; 1337 Job := NewJob; 1338 Flags := Flags and not unFortified; 1339 for uix1 := 0 to RW[p].nUn - 1 do 1340 if (RW[p].Un[uix1].Loc = Loc) and 1341 (RW[p].Un[uix1].Job in ContraJobs[NewJob]) then 1342 RW[p].Un[uix1].Job := jNone; // stop contradictive jobs 1343 if ServerVersion[p] < $000EF0 then 1344 if Work(p, uix) then 1345 result := eJobDone; 1346 if (NewJob = jCity) and (result = eJobDone) then 1347 begin 1348 RemoveUnit_UpdateMap(p, uix); 1349 result := eCity 1115 1350 end 1116 else if Health<=0 then1351 else if Health <= 0 then 1117 1352 begin // victim of HostileDamage 1118 RemoveUnit_UpdateMap(p,uix);1119 result:=result or rUnitRemoved;1120 end; 1121 if Mode>moLoading_Fast then1122 begin 1123 if result=eCity then1124 begin 1125 ObserveLevel[Loc0]:=ObserveLevel[Loc0] and not (3 shl (2*p));1126 Discover21(Loc0,p,lObserveUnhidden,true,true);1127 //CheckContact;1353 RemoveUnit_UpdateMap(p, uix); 1354 result := result or rUnitRemoved; 1355 end; 1356 if Mode > moLoading_Fast then 1357 begin 1358 if result = eCity then 1359 begin 1360 ObserveLevel[Loc0] := ObserveLevel[Loc0] and not(3 shl (2 * p)); 1361 Discover21(Loc0, p, lObserveUnhidden, true, true); 1362 // CheckContact; 1128 1363 end 1129 1364 end 1130 1365 end; // with 1131 end; //StartJob 1132 1133 function Work(p,uix: integer): boolean; 1134 var 1135 uix1,j0: integer; 1136 begin 1137 result:=false; 1138 with RW[p].Un[uix] do if Movement>=100 then 1139 begin 1140 assert(ToWork[Loc,Job]<$FFFF); // should have been set by StartJob 1141 if Job>=jRoad then 1142 if integer(Movement)>=integer(ToWork[Loc,Job]) then {work complete} 1143 begin 1144 result:=true; 1145 if Job<>jIrr then 1146 Health:=Health-HostileDamage(p,mix,Loc,ToWork[Loc,Job]); 1147 dec(Movement,ToWork[Loc,Job]); 1148 if not (Job in [jCity,jPillage,jPoll]) then 1149 inc(Worked[p],ToWork[Loc,Job]); 1150 if Job=jCity then 1151 begin // found new city 1152 FoundCity(p,Loc); 1153 inc(Founded[p]); 1154 with RW[p].City[RW[p].nCity-1] do 1155 begin 1156 ID:=p shl 12+Founded[p]-1; 1157 Flags:=chFounded; 1158 end; 1159 if Mode=moPlaying then 1160 begin 1161 LogCheckBorders(p,RW[p].nCity-1); 1162 RecalcPeaceMap(p); 1163 end; 1164 {$IFOPT O-}if Mode<moPlaying then InvalidTreatyMap:=not(1 shl p);{$ENDIF} 1165 // territory should not be considered for the rest of the command 1166 // execution, because during loading a game it's incorrect before 1167 // subsequent sIntExpandTerritory is processed 1168 RW[p].Un[uix].Health:=0; // causes unit to be removed later 1169 end 1170 else CompleteJob(p,Loc,Job); 1171 ToWork[Loc,Job]:=0; 1172 j0:=Job; 1173 for uix1:=0 to RW[p].nUn-1 do 1174 if (RW[p].Un[uix1].Loc=Loc) and (RW[p].Un[uix1].Job=j0) then 1175 RW[p].Un[uix1].Job:=jNone 1176 end 1366 end; // StartJob 1367 1368 function Work(p, uix: integer): boolean; 1369 var 1370 uix1, j0: integer; 1371 begin 1372 result := false; 1373 with RW[p].Un[uix] do 1374 if Movement >= 100 then 1375 begin 1376 assert(ToWork[Loc, Job] < $FFFF); // should have been set by StartJob 1377 if Job >= jRoad then 1378 if integer(Movement) >= integer(ToWork[Loc, Job]) then { work complete } 1379 begin 1380 result := true; 1381 if Job <> jIrr then 1382 Health := Health - HostileDamage(p, mix, Loc, ToWork[Loc, Job]); 1383 dec(Movement, ToWork[Loc, Job]); 1384 if not(Job in [jCity, jPillage, jPoll]) then 1385 inc(Worked[p], ToWork[Loc, Job]); 1386 if Job = jCity then 1387 begin // found new city 1388 FoundCity(p, Loc); 1389 inc(Founded[p]); 1390 with RW[p].City[RW[p].nCity - 1] do 1391 begin 1392 ID := p shl 12 + Founded[p] - 1; 1393 Flags := chFounded; 1394 end; 1395 if Mode = moPlaying then 1396 begin 1397 LogCheckBorders(p, RW[p].nCity - 1); 1398 RecalcPeaceMap(p); 1399 end; 1400 {$IFOPT O-} if Mode < moPlaying then 1401 InvalidTreatyMap := not(1 shl p); {$ENDIF} 1402 // territory should not be considered for the rest of the command 1403 // execution, because during loading a game it's incorrect before 1404 // subsequent sIntExpandTerritory is processed 1405 RW[p].Un[uix].Health := 0; // causes unit to be removed later 1406 end 1407 else 1408 CompleteJob(p, Loc, Job); 1409 ToWork[Loc, Job] := 0; 1410 j0 := Job; 1411 for uix1 := 0 to RW[p].nUn - 1 do 1412 if (RW[p].Un[uix1].Loc = Loc) and (RW[p].Un[uix1].Job = j0) then 1413 RW[p].Un[uix1].Job := jNone 1414 end 1415 else 1416 begin 1417 dec(ToWork[Loc, Job], Movement); 1418 if not(Job in [jCity, jPillage, jPoll]) then 1419 inc(Worked[p], Movement); 1420 Health := Health - HostileDamage(p, mix, Loc, Movement); 1421 Movement := 0; 1422 end 1423 end 1424 end; // work 1425 1426 function GetJobProgress(p, Loc: integer; 1427 var JobProgressData: TJobProgressData): integer; 1428 var 1429 Job, JobResult, uix: integer; 1430 begin 1431 for Job := 0 to nJob - 1 do 1432 begin 1433 JobResult := CalculateJobWork(p, Loc, Job, JobProgressData[Job].Required); 1434 if JobResult = eOK then 1435 begin 1436 if ToWork[Loc, Job] = $FFFF then // not calculated yet 1437 JobProgressData[Job].Done := 0 1438 else 1439 JobProgressData[Job].Done := JobProgressData[Job].Required - 1440 ToWork[Loc, Job] 1441 end 1177 1442 else 1178 begin 1179 dec(ToWork[Loc,Job],Movement); 1180 if not (Job in [jCity,jPillage,jPoll]) then 1181 inc(Worked[p],Movement); 1182 Health:=Health-HostileDamage(p,mix,Loc,Movement); 1183 Movement:=0; 1184 end 1185 end 1186 end; // work 1187 1188 function GetJobProgress(p,Loc: integer; var JobProgressData: TJobProgressData): integer; 1189 var 1190 Job,JobResult,uix: integer; 1191 begin 1192 for Job:=0 to nJob-1 do 1193 begin 1194 JobResult:=CalculateJobWork(p,Loc,Job,JobProgressData[Job].Required); 1195 if JobResult=eOk then 1196 begin 1197 if ToWork[Loc,Job]=$FFFF then // not calculated yet 1198 JobProgressData[Job].Done:=0 1199 else JobProgressData[Job].Done:=JobProgressData[Job].Required-ToWork[Loc,Job] 1200 end 1201 else 1202 begin 1203 JobProgressData[Job].Required:=0; 1204 JobProgressData[Job].Done:=0; 1205 end; 1206 JobProgressData[Job].NextTurnPlus:=0; 1443 begin 1444 JobProgressData[Job].Required := 0; 1445 JobProgressData[Job].Done := 0; 1446 end; 1447 JobProgressData[Job].NextTurnPlus := 0; 1207 1448 end; 1208 for uix:=0 to RW[p].nUn-1 do 1209 if (RW[p].Un[uix].Loc=Loc) and (RW[p].Un[uix].Movement>=100) then 1210 inc(JobProgressData[RW[p].Un[uix].Job].NextTurnPlus, RW[p].Un[uix].Movement); 1211 result:=eOk; 1449 for uix := 0 to RW[p].nUn - 1 do 1450 if (RW[p].Un[uix].Loc = Loc) and (RW[p].Un[uix].Movement >= 100) then 1451 inc(JobProgressData[RW[p].Un[uix].Job].NextTurnPlus, 1452 RW[p].Un[uix].Movement); 1453 result := eOK; 1212 1454 end; 1213 1455 1214 1215 1456 { 1216 1217 ____________________________________________________________________1457 Start/End Game 1458 ____________________________________________________________________ 1218 1459 } 1219 1460 procedure InitGame; 1220 1461 begin 1221 GetMem(ToWork,2*MapSize*nJob);1222 FillChar(ToWork^,2*MapSize*nJob,$FF);1462 GetMem(ToWork, 2 * MapSize * nJob); 1463 FillChar(ToWork^, 2 * MapSize * nJob, $FF); 1223 1464 end; 1224 1465 1225 1466 procedure ReleaseGame; 1226 1467 begin 1227 FreeMem(ToWork);1468 FreeMem(ToWork); 1228 1469 end; 1229 1470 1230 1471 end. 1231
Note:
See TracChangeset
for help on using the changeset viewer.