Mercurial > repos > IBBoard.WarFoundry.API
comparison API/Objects/UnitType.cs @ 337:3c4a6403a88c
* Fix capitalisation so that new files are in the namespace
no-open-ticket
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Sun, 03 Apr 2011 18:50:32 +0000 |
parents | |
children | d34ae0057a39 |
comparison
equal
deleted
inserted
replaced
336:3631c1493c7f | 337:3c4a6403a88c |
---|---|
1 // This file (UnitType.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2007, 2008, 2009 IBBoard. | |
2 // | |
3 // The file and the library/program it is in are licensed and distributed, without warranty, under the GNU Affero GPL license, either version 3 of the License or (at your option) any later version. Please see COPYING for more information and the full license. | |
4 | |
5 using System; | |
6 using System.Collections.Generic; | |
7 using System.Xml; | |
8 using IBBoard.Limits; | |
9 using IBBoard.Logging; | |
10 using IBBoard.WarFoundry.API.Requirements; | |
11 | |
12 namespace IBBoard.WarFoundry.API.Objects | |
13 { | |
14 /// <summary> | |
15 /// A UnitType is a type for a <see cref=" Unit"/>, normally relating to an entry in an army list. The UnitType defines the name, cost, minimum and maximum limits of a unit, and the equipment units of the type can take. | |
16 /// </summary> | |
17 public class UnitType : WarFoundryObject | |
18 { | |
19 private Category mainCat; | |
20 private Race race; | |
21 private int min, max, baseSize = 0; | |
22 private int minSize, maxSize; | |
23 private double baseUnitCost; | |
24 private double costPerTrooper; | |
25 private Stats stats; | |
26 private List<UnitRequirement> requirements = new List<UnitRequirement>(); | |
27 private Dictionary<string, UnitEquipmentItem> equipment = new Dictionary<string, UnitEquipmentItem>(); | |
28 private Dictionary<string, List<UnitEquipmentItem>> equipmentExclusionGroups = new Dictionary<string, List<UnitEquipmentItem>>(); | |
29 private List<string> equipmentKeyOrder = new List<string>(); | |
30 private Dictionary<string, Ability> requiredAbilities = new Dictionary<string, Ability>(); | |
31 private Dictionary<string, Ability> optionalAbilities = new Dictionary<string, Ability>(); | |
32 private String notes = ""; | |
33 private List<UnitType> containedTypes = new List<UnitType>(); | |
34 private Dictionary<string, string> extraData = new Dictionary<string, string>(); | |
35 private Dictionary<string, ILimit> slotLimits = new Dictionary<string, ILimit>(); | |
36 private Dictionary<string, UnitMemberType> unitMemberTypes = new Dictionary<string, UnitMemberType>(); | |
37 private List<Category> cats = new List<Category>(); | |
38 | |
39 | |
40 public UnitType(string id, string typeName, Race parentRace) : base(id, typeName) | |
41 { | |
42 race = parentRace; | |
43 } | |
44 | |
45 public GameSystem GameSystem | |
46 { | |
47 get { return Race.GameSystem; } | |
48 } | |
49 | |
50 /// <value> | |
51 /// Gets the <see cref=" Race"/> that this unit belongs to. | |
52 /// </value> | |
53 public Race Race | |
54 { | |
55 get { return race; } | |
56 } | |
57 | |
58 /// <value> | |
59 /// Gets or sets the default <see cref=" Category"/> that this unit type is a member of. | |
60 /// If it is not already in the collection of categories then it will be added. | |
61 /// </value> | |
62 public virtual Category MainCategory | |
63 { | |
64 get | |
65 { | |
66 return mainCat; | |
67 } | |
68 set | |
69 { | |
70 mainCat = value; | |
71 AddCategory(value); | |
72 } | |
73 } | |
74 /// <summary> | |
75 /// Gets the collection of <see cref="Category"/> objects that this UnitType can be a member of | |
76 /// </summary> | |
77 public Category[] Categories | |
78 { | |
79 get | |
80 { | |
81 return cats.ToArray(); | |
82 } | |
83 } | |
84 | |
85 /// <summary> | |
86 /// Adds a category to the set of categories that this unit can be taken from. The first category added will automatically become the MainCategory. | |
87 /// </summary> | |
88 /// <param name="cat"> | |
89 /// A <see cref="Category"/> that this unit can be taken from | |
90 /// </param> | |
91 public void AddCategory(Category cat) | |
92 { | |
93 if (!cats.Contains(cat)) | |
94 { | |
95 cats.Add(cat); | |
96 | |
97 if (MainCategory == null) | |
98 { | |
99 MainCategory = cat; | |
100 } | |
101 } | |
102 } | |
103 | |
104 /// <value> | |
105 /// Gets or sets the minimum size of each unit of this type. Note: This should be set AFTER MaxSize, otherwise an unintended default value may be set for the minimum | |
106 /// </value> | |
107 public int MinSize | |
108 { | |
109 get { return minSize; } | |
110 set | |
111 { | |
112 minSize = (value >= 0 ? value : 0); | |
113 CheckMinimumSize(); | |
114 } | |
115 } | |
116 | |
117 /// <value> | |
118 /// Gets or sets the maximum size of each unit of this type. Note: This should be set BEFORE MinSize, otherwise an unintended default value may be set for the minimum | |
119 /// </value> | |
120 public int MaxSize | |
121 { | |
122 get { return maxSize; } | |
123 set | |
124 { | |
125 maxSize = (value >= 0 ? value : WarFoundryCore.INFINITY); | |
126 CheckMinimumSize(); | |
127 } | |
128 } | |
129 | |
130 /// <value> | |
131 /// Gets or sets the minimum number of units of this type that must be taken in an army. Note: This should be set AFTER MaxNumber, otherwise an unintended default value may be set for the minimum | |
132 /// </value> | |
133 public int MinNumber | |
134 { | |
135 get { return min; } | |
136 set | |
137 { | |
138 min = (value >= 0 ? value : 0); | |
139 CheckMinimumNumber(); | |
140 } | |
141 } | |
142 | |
143 /// <value> | |
144 /// Gets or sets the maximum number of units of this type that can be taken in an army. Note: This should be set BEFORE MinNumber, otherwise an unintended default value may be set for the minimum | |
145 /// </value> | |
146 public int MaxNumber | |
147 { | |
148 get { return max; } | |
149 set | |
150 { | |
151 max = (value >= 0 ? value : WarFoundryCore.INFINITY); | |
152 CheckMinimumNumber(); | |
153 } | |
154 } | |
155 | |
156 /// <summary> | |
157 /// Makes sure that the minimum number isn't more than the maximum number, hence the warning on the properties | |
158 /// </summary> | |
159 private void CheckMinimumNumber() | |
160 { | |
161 if (MinNumber > MaxNumber && MaxNumber!=WarFoundryCore.INFINITY) | |
162 { | |
163 MinNumber = MaxNumber; | |
164 LogNotifier.WarnFormat(GetType(), "Unit type {0} ({1}) had a minimum number greater than their maximum number.", Name, ID); | |
165 } | |
166 } | |
167 | |
168 /// <summary> | |
169 /// Makes sure that the minimum unit size isn't more than the maximum unit size, hence the warning on the properties | |
170 /// </summary> | |
171 private void CheckMinimumSize() | |
172 { | |
173 if (MinSize > MaxSize && MaxSize!=WarFoundryCore.INFINITY) | |
174 { | |
175 MinSize = MaxSize; | |
176 LogNotifier.WarnFormat(GetType(), "Unit type {0} ({1}) had a minimum size greater than their maximum size.", Name, ID); | |
177 } | |
178 } | |
179 | |
180 //// <value> | |
181 /// Gets or sets the "base size" of a unit, which is the number of troopers the unit has in it for its "base cost". For a lot of units this value will be 0 as the cost is worked out based on the total number of members. | |
182 /// </value> | |
183 public int BaseSize | |
184 { | |
185 get { return baseSize; } | |
186 set { baseSize = (value >= 0 ? value : 0); } | |
187 } | |
188 | |
189 /// <value> | |
190 /// The number of points that a "base unit" of <code>BaseSize</code> models costs. Additional models are charged at <code>CostPerTrooper</code> each. | |
191 /// </value> | |
192 public double BaseUnitCost | |
193 { | |
194 get { return baseUnitCost; } | |
195 set { baseUnitCost = (value >= 0 ? value : 0); } | |
196 } | |
197 | |
198 //// <value> | |
199 /// The cost of an individual trooper. This value is the cost for a basic trooper without weapons, which are added on top of the cost before calculating a unit cost. | |
200 /// </value> | |
201 public double CostPerTrooper | |
202 { | |
203 get { return costPerTrooper; } | |
204 set { costPerTrooper = (value >= 0 ? value : 0); } | |
205 } | |
206 | |
207 protected override string DefaultName() | |
208 { | |
209 throw new InvalidOperationException("Unit type with id "+id+" did not have a name specified"); | |
210 } | |
211 | |
212 /// <value> | |
213 /// The array of <see cref="Stat"/>s for each of the unit's stat lines | |
214 /// </value> | |
215 public Stat[][] UnitStatsArrays | |
216 { | |
217 get | |
218 { | |
219 Stat[][] statsArray; | |
220 | |
221 if (stats != null) | |
222 { | |
223 statsArray = new Stat[][]{ stats.StatsArray }; | |
224 } | |
225 else if (unitMemberTypes.Count > 0) | |
226 { | |
227 int memTypeCount = unitMemberTypes.Count; | |
228 statsArray = new Stat[memTypeCount][]; | |
229 int i = 0; | |
230 | |
231 foreach (UnitMemberType memType in unitMemberTypes.Values) | |
232 { | |
233 statsArray[i] = memType.StatsArray; | |
234 i++; | |
235 } | |
236 } | |
237 else | |
238 { | |
239 SystemStats systemStats = GameSystem.StandardSystemStats; | |
240 Stats tempStats = new Stats(systemStats); | |
241 statsArray = new Stat[][]{ tempStats.StatsArray }; | |
242 } | |
243 | |
244 return statsArray; | |
245 } | |
246 } | |
247 | |
248 public string[] UnitStatsArrayIDs | |
249 { | |
250 get | |
251 { | |
252 string[] ids; | |
253 | |
254 if (stats != null) | |
255 { | |
256 ids = new string[]{ stats.StatsID }; | |
257 } | |
258 else if (unitMemberTypes.Count > 0) | |
259 { | |
260 ids = new string[unitMemberTypes.Count]; | |
261 int i = 0; | |
262 | |
263 foreach (UnitMemberType memType in unitMemberTypes.Values) | |
264 { | |
265 ids[i] = memType.StatsID; | |
266 i++; | |
267 } | |
268 } | |
269 else | |
270 { | |
271 ids = new string[]{ GameSystem.StandardSystemStatsID }; | |
272 } | |
273 | |
274 return ids; | |
275 } | |
276 } | |
277 | |
278 //// <value> | |
279 /// The array of <see cref="Stat"/>s for each of the unit's stat lines including an additional column that contains the unit type name | |
280 /// </value> | |
281 public Stat[][] UnitStatsArraysWithName | |
282 { | |
283 get | |
284 { | |
285 Stat[][] statsArray; | |
286 | |
287 if (stats != null) | |
288 { | |
289 statsArray = new Stat[][]{ ExtendStatsArrayWithName(stats.StatsArray) }; | |
290 } | |
291 else if (unitMemberTypes.Count > 0) | |
292 { | |
293 int memTypeCount = unitMemberTypes.Count; | |
294 statsArray = new Stat[memTypeCount][]; | |
295 int i = 0; | |
296 | |
297 foreach (UnitMemberType memType in unitMemberTypes.Values) | |
298 { | |
299 statsArray[i] = memType.StatsArrayWithName; | |
300 i++; | |
301 } | |
302 } | |
303 else | |
304 { | |
305 SystemStats systemStats = GameSystem.StandardSystemStats; | |
306 Stats tempStats = new Stats(systemStats); | |
307 statsArray = new Stat[][]{ ExtendStatsArrayWithName(tempStats.StatsArray) }; | |
308 } | |
309 | |
310 return statsArray; | |
311 } | |
312 } | |
313 | |
314 public Stat[] ExtendStatsArrayWithName(Stat[] statsArray) | |
315 { | |
316 Stat[] extendedStats = new Stat[statsArray.Length+1]; | |
317 extendedStats[0] = new Stat(new StatSlot("name"), Name); | |
318 statsArray.CopyTo(extendedStats, 1); | |
319 return extendedStats; | |
320 } | |
321 | |
322 public void SetUnitStats(Stats newStats) | |
323 { | |
324 stats = newStats; | |
325 } | |
326 | |
327 public string GetStatValue(string statName) | |
328 { | |
329 return stats.GetStatValue(statName.ToLower()); | |
330 } | |
331 | |
332 internal void AddEquipmentItem(UnitEquipmentItem item) | |
333 { | |
334 if (!equipment.ContainsKey(item.ID)) | |
335 { | |
336 equipment.Add(item.ID, item); | |
337 equipmentKeyOrder.Add(item.ID); | |
338 AddToMutexGroups(item); | |
339 } | |
340 } | |
341 | |
342 private void AddToMutexGroups(UnitEquipmentItem item) | |
343 { | |
344 string[] mutexGroups = item.MutexGroups; | |
345 | |
346 foreach (string mutexGroup in mutexGroups) | |
347 { | |
348 List<UnitEquipmentItem> items = DictionaryUtils.GetValue(equipmentExclusionGroups, mutexGroup); | |
349 | |
350 if (items == null) | |
351 { | |
352 items = new List<UnitEquipmentItem>(); | |
353 equipmentExclusionGroups.Add(mutexGroup, items); | |
354 } | |
355 | |
356 items.Add(item); | |
357 } | |
358 } | |
359 | |
360 /// <summary> | |
361 /// Gets a <see cref="UnitEquipmentItem"/> for the given ID string, or <code>null</code> if nothing exists for that ID | |
362 /// </summary> | |
363 /// <param name="id"> | |
364 /// The ID of the UnitEquipmentItem to get | |
365 /// </param> | |
366 /// <returns> | |
367 /// The <see cref="UnitEquipmentItem"/> for the given ID string, or <code>null</code> if nothing exists for that ID | |
368 /// </returns> | |
369 public UnitEquipmentItem GetEquipmentItem(string id) | |
370 { | |
371 return DictionaryUtils.GetValue(equipment, id); | |
372 } | |
373 | |
374 /// <summary> | |
375 /// Gets a <see cref=" UnitEquipmentItem"/> for the given <see cref=" EquipmentItem"/>, or <code>null</code> if the unit can't take that <code>EquipmentItem</code> | |
376 /// </summary> | |
377 /// <param name="item"> | |
378 /// The <see cref="EquipmentItem"/> to get the <see cref=" UnitEquipmentItem"/> | |
379 /// </param> | |
380 /// <returns> | |
381 /// The <see cref="UnitEquipmentItem"/> that definies the UnitType's restrictions for taking the <see cref=" EquipmentItem"/> | |
382 /// </returns> | |
383 public UnitEquipmentItem GetEquipmentItem(EquipmentItem item) | |
384 { | |
385 return GetEquipmentItem(item.ID); | |
386 } | |
387 | |
388 /// <summary> | |
389 /// Gets an array of all available <see cref="UnitEquipmentItem"/>s for this UnitType | |
390 /// </summary> | |
391 /// <returns> | |
392 /// An array of all available <see cref="UnitEquipmentItem"/>s for this UnitType | |
393 /// </returns> | |
394 public UnitEquipmentItem[] GetEquipmentItems() | |
395 { | |
396 return DictionaryUtils.ToArray<string, UnitEquipmentItem>(equipment); | |
397 } | |
398 | |
399 public UnitEquipmentItem[] GetEquipmentItemsByExclusionGroup(string group) | |
400 { | |
401 return GetEquipmentItemsByExclusionGroups(new string[] { group }); | |
402 } | |
403 | |
404 public UnitEquipmentItem[] GetEquipmentItemsByExclusionGroups(string[] groups) | |
405 { | |
406 List<UnitEquipmentItem> list = new List<UnitEquipmentItem>(); | |
407 | |
408 foreach (string group in groups) | |
409 { | |
410 List<UnitEquipmentItem> groupList = DictionaryUtils.GetValue(equipmentExclusionGroups, group); | |
411 | |
412 if (groupList != null) | |
413 { | |
414 list.AddRange(groupList); | |
415 } | |
416 } | |
417 | |
418 return list.ToArray(); | |
419 } | |
420 | |
421 public bool IsRatioLimitedEquipmentItem(EquipmentItem item) | |
422 { | |
423 UnitEquipmentItem equip = GetEquipmentItem(item); | |
424 return equip != null && equip.IsRatioLimit; | |
425 } | |
426 | |
427 public bool IsAbsoluteLimitedEquipmentItem(EquipmentItem item) | |
428 { | |
429 UnitEquipmentItem equip = GetEquipmentItem(item); | |
430 return equip != null && !equip.IsRatioLimit; | |
431 } | |
432 | |
433 public ICollection<Ability> GetRequiredAbilities() | |
434 { | |
435 return requiredAbilities.Values; | |
436 } | |
437 | |
438 public ICollection<Ability> GetOptionalAbilities() | |
439 { | |
440 return optionalAbilities.Values; | |
441 } | |
442 | |
443 public void AddAbility(Ability ability, bool isRequired) | |
444 { | |
445 string id = ability.ID; | |
446 | |
447 if (!requiredAbilities.ContainsKey(id) && !optionalAbilities.ContainsKey(id)) | |
448 { | |
449 if (isRequired) | |
450 { | |
451 requiredAbilities[id] = ability; | |
452 } | |
453 else | |
454 { | |
455 optionalAbilities[id] = ability; | |
456 } | |
457 } | |
458 } | |
459 | |
460 public void AddRequirement(UnitRequirement requirement) | |
461 { | |
462 requirements.Add(requirement); | |
463 } | |
464 | |
465 public UnitRequirement[] Requirements | |
466 { | |
467 get { return requirements.ToArray(); } | |
468 } | |
469 | |
470 public List<FailedUnitRequirement> CanAddToArmy(Army army) | |
471 { | |
472 List<FailedUnitRequirement> failures = new List<FailedUnitRequirement>(); | |
473 | |
474 if (requirements!=null && requirements.Count > 0) | |
475 { | |
476 foreach (UnitRequirement requirement in requirements) | |
477 { | |
478 FailedUnitRequirement failure = (FailedUnitRequirement)requirement.CanAddToWarFoundryObject(army); | |
479 | |
480 if (failure!=null) | |
481 { | |
482 failures.Add(failure); | |
483 } | |
484 } | |
485 } | |
486 | |
487 return failures; | |
488 } | |
489 | |
490 public List<FailedUnitRequirement> CanRemoveFromArmy(Army army) | |
491 { | |
492 List<FailedUnitRequirement> failures = new List<FailedUnitRequirement>(); | |
493 | |
494 if (requirements!=null && requirements.Count > 0) | |
495 { | |
496 foreach (UnitRequirement requirement in requirements) | |
497 { | |
498 FailedUnitRequirement failure = (FailedUnitRequirement)requirement.CanRemoveFromWarFoundryObject(army); | |
499 | |
500 if (failure!=null) | |
501 { | |
502 failures.Add(failure); | |
503 } | |
504 } | |
505 } | |
506 | |
507 return failures; | |
508 } | |
509 | |
510 public string Notes | |
511 { | |
512 get { return notes; } | |
513 set { notes = value; } | |
514 } | |
515 | |
516 public bool CanContainUnit(Unit unit) | |
517 { | |
518 return CanContainUnitType(unit.UnitType); | |
519 } | |
520 | |
521 public bool CanContainUnitType(UnitType unitType) | |
522 { | |
523 return containedTypes.Contains(unitType); | |
524 } | |
525 | |
526 public UnitType[] ContainedUnitTypes | |
527 { | |
528 get { return containedTypes.ToArray(); } | |
529 } | |
530 | |
531 public void AddContainedUnitType(UnitType containedType) | |
532 { | |
533 containedTypes.Add(containedType); | |
534 } | |
535 | |
536 public void AddExtraData(string id, string data) | |
537 { | |
538 extraData[id] = data; | |
539 } | |
540 | |
541 public string GetExtraData(string id) | |
542 { | |
543 return DictionaryUtils.GetValue(extraData, id); | |
544 } | |
545 | |
546 public string StatsID | |
547 { | |
548 get | |
549 { | |
550 return stats.StatsID; | |
551 } | |
552 } | |
553 | |
554 public void AddEquipmentSlot(string slotName, ILimit slotLimit) | |
555 { | |
556 slotLimits.Add(slotName, slotLimit); | |
557 } | |
558 | |
559 public bool HasEquipmentSlot(string slotName) | |
560 { | |
561 return slotLimits.ContainsKey(slotName); | |
562 } | |
563 | |
564 /// <summary> | |
565 /// Gets the maximum limit on the number of items allowed in a single slot | |
566 /// </summary> | |
567 /// <param name="slotName">The name of the equipment slot to get the limit for</param> | |
568 /// <returns>The limit of the number of items allowed in a slot, or an infinite limit if the slot is the default one or has not been specified</returns> | |
569 public ILimit GetEquipmentSlotLimit(string slotName) | |
570 { | |
571 ILimit slotLimit = null; | |
572 | |
573 if (HasEquipmentSlot(slotName)) | |
574 { | |
575 slotLimit = DictionaryUtils.GetValue(slotLimits, slotName); | |
576 } | |
577 | |
578 if (slotLimit == null) | |
579 { | |
580 slotLimit = new UnlimitedLimit(); | |
581 } | |
582 | |
583 return slotLimit; | |
584 } | |
585 | |
586 public void AddUnitMemberType(UnitMemberType unitMemberType) | |
587 { | |
588 unitMemberTypes.Add(unitMemberType.ID, unitMemberType); | |
589 } | |
590 } | |
591 } |