source: branches/AlphaChannel/AI Template/Project/Lib/ModelBase.cs

Last change on this file was 191, checked in by chronos, 5 years ago
  • Added: AI Template directory with manual for development of custom AI from original game.
File size: 12.4 KB
Line 
1using System;
2using System.Collections.Generic;
3using AI;
4
5namespace CevoAILib
6{
7 enum ModelDomain { Ground = 0, Sea = 1, Air = 2 }
8
9 enum ModelKind
10 {
11 OwnDesign = 0x00, ForeignDesign = 0x01, LongBoats = 0x08, TownGuard = 0x10, Glider = 0x11,
12 Slaves = 0x21, Settlers = 0x22, SpecialCommando = 0x23, Freight = 0x24, Engineers = 0x122
13 }
14
15 enum ModelProperty
16 {
17 Weapons = 0, Armor = 1, Mobility = 2, SeaTransport = 3, Carrier = 4,
18 Turbines = 5, Bombs = 6, Fuel = 7, AirTransport = 8, Navigation = 9,
19 RadarSonar = 10, Submarine = 11, Artillery = 12, Alpine = 13, SupplyShip = 14,
20 Overweight = 15, AirDefence = 16, SpyPlane = 17, SteamPower = 18, NuclearPower = 19,
21 JetEngines = 20, Stealth = 21, Fanatic = 22, FirstStrike = 23, PowerOfWill = 24,
22 AcademyTraining = 25, LineProduction = 26
23 }
24
25 struct Stage
26 {
27 public readonly int MaximumWeight;
28 public readonly int StrengthMultiplier;
29 public readonly int TransportMultiplier;
30 public readonly int CostMultiplier;
31 readonly int upgradeArray;
32 bool ContainsUpgrade(int upgrade) { return (upgradeArray & (1 << upgrade)) != 0; }
33
34 public Stage(int maximumWeight, int strengthMultiplier, int transportMultiplier, int costMultiplier, int upgradeArray)
35 {
36 this.MaximumWeight = maximumWeight;
37 this.StrengthMultiplier = strengthMultiplier;
38 this.TransportMultiplier = transportMultiplier;
39 this.CostMultiplier = costMultiplier;
40 this.upgradeArray = upgradeArray;
41 }
42
43 public override string ToString()
44 {
45 return string.Format("x{0}", StrengthMultiplier);
46 }
47 }
48
49 /// <summary>
50 /// basic model information as available for both own and foreign models
51 /// </summary>
52 abstract class ModelBase
53 {
54 #region abstract
55 public abstract int ID { get; }
56 public abstract ModelKind Kind { get; }
57 public abstract Nation Nation { get; }
58 public abstract ModelDomain Domain { get; }
59 public abstract int Attack { get; }
60 public abstract int AttackPlusWithBombs { get; }
61 public abstract int Defense { get; }
62 public abstract int Speed { get; }
63 public abstract int Cost { get; }
64 public abstract int TransportCapacity { get; }
65 public abstract int CarrierCapacity { get; }
66 public abstract int Fuel { get; }
67 public abstract int Weight { get; }
68 public abstract bool HasFeature(ModelProperty feature);
69 #endregion
70
71 /// <summary>
72 /// whether model has 2 tiles observation range (distance 5) instead of adjacent locations only
73 /// </summary>
74 public bool HasExtendedObservationRange
75 {
76 get
77 {
78 return (Kind == ModelKind.SpecialCommando ||
79 Domain == ModelDomain.Air ||
80 HasFeature(ModelProperty.RadarSonar) ||
81 HasFeature(ModelProperty.AcademyTraining) ||
82 CarrierCapacity > 0);
83 }
84 }
85
86 public bool HasZoC { get { return Domain == ModelDomain.Ground && Kind != ModelKind.SpecialCommando; } }
87
88 public bool IsCivil { get { return Attack + AttackPlusWithBombs == 0 || Kind == ModelKind.SpecialCommando; } }
89
90 /// <summary>
91 /// whether units of this model are capable of doing settler jobs
92 /// </summary>
93 public bool CanDoJobs { get { return Kind == ModelKind.Settlers || Kind == ModelKind.Engineers || Kind == ModelKind.Slaves; } }
94
95 public bool CanCaptureCity { get { return Domain == ModelDomain.Ground && !IsCivil; } }
96
97 public bool CanBombardCity
98 {
99 get
100 {
101 return Attack + AttackPlusWithBombs > 0 &&
102 ((Domain == ModelDomain.Sea && HasFeature(ModelProperty.Artillery)) ||
103 Domain == ModelDomain.Air);
104 }
105 }
106
107 /// <summary>
108 /// whether units of this model pass hostile terrain without damage
109 /// </summary>
110 public bool IsTerrainResistant { get { return Domain != ModelDomain.Ground || Kind == ModelKind.Engineers; } }
111
112 /// <summary>
113 /// By which value the size of a city grows when a unit of this model is added to it. 0 if adding to a city is not possible.
114 /// </summary>
115 public int AddsToCitySize
116 {
117 get
118 {
119 switch (Kind)
120 {
121 case ModelKind.Settlers: return 2;
122 case ModelKind.Slaves: return 1;
123 default: return 0;
124 }
125 }
126 }
127 }
128
129 /// <summary>
130 /// own model, abstract base class
131 /// </summary>
132 unsafe abstract class AModel : ModelBase
133 {
134 protected readonly Empire theEmpire;
135
136 public AModel(Empire empire, int indexInSharedMemory)
137 {
138 this.theEmpire = empire;
139 this.IndexInSharedMemory = indexInSharedMemory;
140 address = (int*)theEmpire.address[6] + ROReadPoint.SizeOfModel * indexInSharedMemory;
141 }
142
143 protected AModel(Empire empire) // for Blueprint only
144 {
145 this.theEmpire = empire;
146 this.IndexInSharedMemory = -1;
147 address = theEmpire.address + ROReadPoint.TestFlags + 19;
148 }
149
150 public override string ToString()
151 {
152 if (Kind == ModelKind.OwnDesign || Kind == ModelKind.ForeignDesign)
153 return string.Format("Model{0}.{1}({2}/{3}/{4})", (address[2] >> 12) & 0xF, address[2] & 0xFFF, Attack, Defense, Speed);
154 else
155 return string.Format("{0}", Kind);
156 }
157
158 byte* capacity { get { return (byte*)(address + 10); } }
159
160 #region IModel Members
161 /// <summary>
162 /// unique model ID
163 /// </summary>
164 public override int ID { get { return (address[2] & 0xFFFF); } }
165
166 public override ModelKind Kind
167 {
168 get
169 {
170 ModelKind kind = (ModelKind)(address[4] & 0xFF);
171 if (kind == ModelKind.Settlers && ((address[5] >> 16) & 0xFFFF) > 150) // assume fast settlers are engineers
172 return ModelKind.Engineers;
173 else
174 return kind;
175 }
176 }
177
178 public override Nation Nation { get { return theEmpire.Us; } }
179 public override ModelDomain Domain { get { return (ModelDomain)((address[4] >> 8) & 0xFF); } }
180 public override int Attack { get { return (address[4] >> 16) & 0xFFFF; } }
181 public override int AttackPlusWithBombs { get { return capacity[(int)ModelProperty.Bombs] * Stage.StrengthMultiplier * 2; } }
182 public override int Defense { get { return address[5] & 0xFFFF; } }
183 public override int Speed { get { return (address[5] >> 16) & 0xFFFF; } }
184 public override int Cost { get { return address[6] & 0xFFFF; } }
185 public override int CarrierCapacity { get { return capacity[(int)ModelProperty.Carrier] * Stage.TransportMultiplier; } }
186 public override int Fuel { get { return capacity[(int)ModelProperty.Fuel]; } }
187 public override int Weight { get { return (address[7] >> 16) & 0xFF; } }
188
189 public override int TransportCapacity
190 {
191 get
192 {
193 if (Domain == ModelDomain.Air)
194 return capacity[(int)ModelProperty.AirTransport] * Stage.TransportMultiplier;
195 else
196 return capacity[(int)ModelProperty.SeaTransport] * Stage.TransportMultiplier;
197 }
198 }
199
200 /// <summary>
201 /// Whether model has a certain feature.
202 /// Does not work for capacities (Weapons, Armor, Mobility, SeaTransport, Carrier, Turbines, Bombs, Fuel), always returns false for these.
203 /// </summary>
204 /// <param name="feature">the feature</param>
205 /// <returns>true if model has feature, false if not</returns>
206 public override bool HasFeature(ModelProperty feature)
207 {
208 if ((int)feature >= Protocol.mcFirstNonCap)
209 return capacity[(int)feature] > 0;
210 else
211 return false; // to maintain consistency with AForeignModel (capacities have special properties)
212 }
213 #endregion
214
215 public bool RequiresDoubleSupport { get { return (address[9] & Protocol.mdDoubleSupport) != 0; } }
216
217 public int TurnOfIntroduction { get { return (address[2] >> 16) & 0xFFFF; } }
218 public Stage Stage { get { return new Stage((address[7] >> 24) & 0xFF, (address[6] >> 16) & 0xFFFF, address[7] & 0xFF, (address[7] >> 8) & 0xFF, address[8]); } }
219 public int NumberBuilt { get { return address[3] & 0xFFFF; } }
220 public int NumberLost { get { return (address[3] >> 16) & 0xFFFF; } }
221
222 /// <summary>
223 /// persistent custom value
224 /// </summary>
225 public int Status
226 {
227 get { return address[0]; }
228 set { address[0] = value; }
229 }
230
231 #region template internal stuff
232 /// <summary>
233 /// INTERNAL - only access from CevoAILib classes!
234 /// </summary>
235 public int IndexInSharedMemory;
236
237 int* address;
238 #endregion
239 }
240
241 /// <summary>
242 /// foreign model, abstract base class
243 /// </summary>
244 unsafe abstract class AForeignModel : ModelBase
245 {
246 protected readonly Empire theEmpire;
247
248 public AForeignModel(Empire empire, int indexInSharedMemory)
249 {
250 this.theEmpire = empire;
251 this.indexInSharedMemory = indexInSharedMemory;
252 address = (int*)theEmpire.address[9] + ROReadPoint.SizeOfModelInfo * indexInSharedMemory;
253 }
254
255 public override string ToString()
256 {
257 if (Kind == ModelKind.OwnDesign || Kind == ModelKind.ForeignDesign)
258 return string.Format("Model{0}.{1}({2}/{3}/{4})", (address[1] >> 12) & 0xF, address[1] & 0xFFF, Attack, Defense, Speed);
259 else
260 return string.Format("{0}", Kind);
261 }
262
263 #region IModel Members
264 /// <summary>
265 /// unique model ID
266 /// </summary>
267 public override int ID { get { return address[1] & 0xFFFF; } }
268
269 public override ModelKind Kind
270 {
271 get
272 {
273 ModelKind kind = (ModelKind)((address[1] >> 16) & 0xFF);
274 if (kind == ModelKind.Settlers && (address[3] & 0xFFFF) > 150) // assume fast settlers are engineers
275 return ModelKind.Engineers;
276 else
277 return kind;
278 }
279 }
280
281 public override Nation Nation { get { return new Nation(theEmpire, address[0] & 0xFFFF); } }
282 public override ModelDomain Domain { get { return (ModelDomain)((address[1] >> 24) & 0xFF); } }
283 public override int Attack { get { return address[2] & 0xFFFF; } }
284 public override int AttackPlusWithBombs { get { return (address[4] >> 16) & 0xFFFF; } }
285 public override int Defense { get { return (address[2] >> 16) & 0xFFFF; } }
286 public override int Speed { get { return address[3] & 0xFFFF; } }
287 public override int Cost { get { return (address[3] >> 16) & 0xFFFF; } }
288 public override int TransportCapacity { get { return address[4] & 0xFF; } }
289 public override int Weight { get { return (address[6] >> 8) & 0xFF; } }
290
291 public override int CarrierCapacity
292 {
293 get
294 {
295 if (Domain == ModelDomain.Sea)
296 return (address[4] >> 8) & 0xFF;
297 else
298 return 0;
299 }
300 }
301
302 public override int Fuel
303 {
304 get
305 {
306 if (Domain == ModelDomain.Air)
307 return (address[4] >> 8) & 0xFF;
308 else
309 return 0;
310 }
311 }
312
313 /// <summary>
314 /// Whether model has a certain feature.
315 /// Does not work for capacities (Weapons, Armor, Mobility, SeaTransport, Carrier, Turbines, Bombs, Fuel), always returns false for these.
316 /// </summary>
317 /// <param name="feature">the feature</param>
318 /// <returns>true if model has feature, false if not</returns>
319 public override bool HasFeature(ModelProperty feature)
320 {
321 if ((int)feature >= Protocol.mcFirstNonCap)
322 return (address[5] & (1 << ((int)feature - Protocol.mcFirstNonCap))) != 0;
323 else
324 return false;
325 }
326 #endregion
327
328 public int NumberDefeatet { get { return (address[6] >> 16) & 0xFFFF; } }
329
330 #region template internal stuff
331 int indexInSharedMemory = -1;
332 int* address;
333
334 /// <summary>
335 /// INTERNAL - only access from CevoAILib classes!
336 /// </summary>
337 public int IndexInNationsSharedMemory { get { return (address[0] >> 16) & 0xFFFF; } }
338 #endregion
339 }
340
341 /// <summary>
342 /// Model blueprint for military research. Class of AEmpire.Blueprint.
343 /// </summary>
344 class Blueprint : AModel
345 {
346 public Blueprint(Empire empire)
347 : base(empire)
348 {
349 }
350
351 /// <summary>
352 /// Set domain of model. Do this before setting properties.
353 /// </summary>
354 /// <param name="domain">the domain</param>
355 /// <returns>result of operation</returns>
356 public PlayResult SetDomain__Turn(ModelDomain domain)
357 {
358 if (theEmpire.Researching == Advance.MilitaryResearch)
359 return new PlayResult(PlayError.ResearchInProgress);
360 else
361 return theEmpire.Play(Protocol.sCreateDevModel, (int)domain);
362 }
363
364 /// <summary>
365 /// Set property of model. Do this after setting the domain. Earlier calls for the same property are voided.
366 /// </summary>
367 /// <param name="property">the property</param>
368 /// <param name="value">for capacities: count of usage, for features: 1 = use, 0 = don't use</param>
369 /// <returns>result of operation</returns>
370 public PlayResult SetProperty__Turn(ModelProperty property, int value)
371 {
372 if (theEmpire.Researching == Advance.MilitaryResearch)
373 return new PlayResult(PlayError.ResearchInProgress);
374 else
375 return theEmpire.Play(Protocol.sSetDevModelCap + (value << 4), (int)property);
376 }
377 }
378}
Note: See TracBrowser for help on using the repository browser.