Mercurial > repos > IBDev-IBBoard.WarFoundry.API
comparison API/Objects/Unit.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 | 7179c585d31d |
comparison
equal
deleted
inserted
replaced
336:3631c1493c7f | 337:3c4a6403a88c |
---|---|
1 // This file (Unit.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2009 2007, 2008, 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.Text; | |
8 using System.Xml; | |
9 using IBBoard.Lang; | |
10 using IBBoard.Limits; | |
11 using IBBoard.WarFoundry.API.Util; | |
12 | |
13 namespace IBBoard.WarFoundry.API.Objects | |
14 { | |
15 /// <summary> | |
16 /// Summary description for UnitInstance. | |
17 /// </summary> | |
18 public class Unit : WarFoundryObject, ICostedWarFoundryObject | |
19 { | |
20 private UnitType type; | |
21 private int size; | |
22 private Unit parentUnit; | |
23 private double points; | |
24 private ArmyCategory cat; | |
25 private Dictionary<UnitEquipmentItem, AbstractUnitEquipmentItemSelection> equipment = new Dictionary<UnitEquipmentItem, AbstractUnitEquipmentItemSelection>(); | |
26 private Dictionary<string, List<AbstractUnitEquipmentItemSelection>> equipmentSlots = new Dictionary<string, List<AbstractUnitEquipmentItemSelection>>(); | |
27 private List<Unit> containedUnits = new List<Unit>(); | |
28 | |
29 public event DoubleValChangedDelegate PointsValueChanged; | |
30 public event IntValChangedDelegate UnitSizeChanged; | |
31 public event DoubleValChangedDelegate UnitEquipmentAmountChanged; | |
32 | |
33 public Unit(UnitType unitType, ArmyCategory parentArmyCat) : this(unitType, unitType.MinSize, parentArmyCat) | |
34 { | |
35 //Do nothing extra | |
36 } | |
37 | |
38 public Unit(UnitType unitType, int startSize, ArmyCategory parentArmyCat) : this("", "", startSize, unitType, parentArmyCat) | |
39 { | |
40 SetInitialEquipment(); | |
41 UnitSizeChanged += new IntValChangedDelegate(RefreshUnitEquipmentAmounts); | |
42 } | |
43 | |
44 public Unit(string id, string name, int startSize, UnitType unitType, ArmyCategory parentArmyCat) : base(id, name) | |
45 { | |
46 Category = parentArmyCat; | |
47 type = unitType; | |
48 Size = startSize; | |
49 CalcCost(); | |
50 UnitEquipmentAmountChanged += new DoubleValChangedDelegate(UnitEquipmentAmountChangedHandler); | |
51 UnitSizeChanged += new IntValChangedDelegate(UnitSizeChangedHandler); | |
52 Translation.TranslationChanged += HandleTranslationChanged; | |
53 } | |
54 | |
55 private void UnitEquipmentAmountChangedHandler(WarFoundryObject obj, double oldVal, double newVal) | |
56 { | |
57 CalcCost(); | |
58 } | |
59 | |
60 private void UnitSizeChangedHandler(WarFoundryObject obj, int oldVal, int newVal) | |
61 { | |
62 CalcCost(); | |
63 | |
64 if (HasDefaultName()) | |
65 { | |
66 OnNameChanged("", Name); | |
67 } | |
68 } | |
69 | |
70 protected override string DefaultName() | |
71 { | |
72 if (type != null) | |
73 { | |
74 if (size == 1) | |
75 { | |
76 return type.Name; | |
77 } | |
78 else | |
79 { | |
80 return String.Format(Translation.GetTranslation("defaultUnitName"), size, type.Name); | |
81 } | |
82 } | |
83 else | |
84 { | |
85 return "Unknown Unit"; | |
86 } | |
87 } | |
88 | |
89 private void HandleTranslationChanged() | |
90 { | |
91 if (type != null && HasDefaultName() && size != 1) | |
92 { | |
93 OnNameChanged(null, DefaultName()); | |
94 } | |
95 } | |
96 | |
97 private void SetInitialEquipment() | |
98 { | |
99 foreach (UnitEquipmentItem unitEquip in UnitType.GetEquipmentItems()) | |
100 { | |
101 if (unitEquip.IsRequired) | |
102 { | |
103 if (CanEquipWithItem(unitEquip)) | |
104 { | |
105 ILimit minLimit = unitEquip.MinLimit; | |
106 | |
107 if (minLimit is IPercentageLimit) | |
108 { | |
109 SetEquipmentRatio(unitEquip, UnitEquipmentUtil.GetMinEquipmentPercentage(this, unitEquip)); | |
110 } | |
111 else | |
112 { | |
113 SetEquipmentAmount(unitEquip, UnitEquipmentUtil.GetMinEquipmentCount(this, unitEquip)); | |
114 } | |
115 } | |
116 } | |
117 } | |
118 } | |
119 | |
120 private void CalcCost() | |
121 { | |
122 double oldpoints = points; | |
123 points = type.CostPerTrooper * AdditionalTroopers + type.BaseUnitCost; | |
124 | |
125 foreach (AbstractUnitEquipmentItemSelection equipSelection in equipment.Values) | |
126 { | |
127 points += equipSelection.TotalCost; | |
128 } | |
129 | |
130 if (oldpoints != points) | |
131 { | |
132 OnPointsValueChanged(oldpoints, points); | |
133 } | |
134 } | |
135 | |
136 public int AdditionalTroopers | |
137 { | |
138 get { return Math.Max(Size - type.BaseSize, 0); } | |
139 } | |
140 | |
141 public int Size | |
142 { | |
143 get { return size; } | |
144 set | |
145 { | |
146 if (value != size) | |
147 { | |
148 int oldValue = size; | |
149 size = (value > 0 ? value : 1); | |
150 OnUnitSizeChanged(oldValue, size); | |
151 } | |
152 } | |
153 } | |
154 | |
155 public UnitType UnitType | |
156 { | |
157 get { return type; } | |
158 } | |
159 | |
160 public Army Army | |
161 { | |
162 get { return (Category == null ? null : Category.ParentArmy); } | |
163 } | |
164 | |
165 public Race Race | |
166 { | |
167 get { return UnitType.Race; } | |
168 } | |
169 | |
170 public ArmyCategory Category | |
171 { | |
172 get | |
173 { | |
174 return cat; | |
175 } | |
176 set { cat = value; } | |
177 } | |
178 | |
179 public double Points | |
180 { | |
181 get | |
182 { | |
183 if (points == 0) | |
184 { | |
185 CalcCost(); | |
186 } | |
187 | |
188 return points; | |
189 } | |
190 } | |
191 | |
192 public Unit[] ContainedUnits | |
193 { | |
194 get { return containedUnits.ToArray(); } | |
195 } | |
196 | |
197 public void AddContainedUnit(Unit unit) | |
198 { | |
199 if (UnitType.CanContainUnit(unit)) | |
200 { | |
201 if (!containedUnits.Contains(unit)) | |
202 { | |
203 containedUnits.Add(unit); | |
204 } | |
205 | |
206 unit.ParentUnit = this; | |
207 } | |
208 else | |
209 { | |
210 throw new InvalidContainershipException(this, unit); | |
211 } | |
212 } | |
213 | |
214 public void RemoveContainedUnit(Unit unit) | |
215 { | |
216 containedUnits.Remove(unit); | |
217 } | |
218 | |
219 public Unit ParentUnit | |
220 { | |
221 get { return parentUnit; } | |
222 set | |
223 { | |
224 if (!(parentUnit == value || (parentUnit != null && parentUnit.Equals(value)))) | |
225 { | |
226 parentUnit = value; | |
227 | |
228 if (value != null) | |
229 { | |
230 value.AddContainedUnit(this); | |
231 } | |
232 } | |
233 } | |
234 } | |
235 | |
236 public UnitEquipmentItem[] GetEquipment() | |
237 { | |
238 return DictionaryUtils.ToKeyArray(equipment); | |
239 } | |
240 | |
241 public EquipmentItem[] GetRequiredEquipment() | |
242 { | |
243 List<EquipmentItem> list = new List<EquipmentItem>(); | |
244 | |
245 foreach (UnitEquipmentItem item in GetEquipment()) | |
246 { | |
247 if (item.IsRequired) | |
248 { | |
249 list.Add(item.EquipmentItem); | |
250 } | |
251 } | |
252 | |
253 return list.ToArray(); | |
254 } | |
255 | |
256 internal AbstractUnitEquipmentItemSelection GetEquipmentSelection(UnitEquipmentItem item) | |
257 { | |
258 return DictionaryUtils.GetValue(equipment, item); | |
259 } | |
260 | |
261 public void SetEquipmentAmount(UnitEquipmentItem equip, int amount) | |
262 { | |
263 if (amount < 1 && amount != WarFoundryCore.INFINITY) | |
264 { | |
265 amount = 0; | |
266 } | |
267 | |
268 if (amount == 0) | |
269 { | |
270 RemoveEquipmentItem(equip); | |
271 } | |
272 else | |
273 { | |
274 AbstractUnitEquipmentItemSelection currSelection = DictionaryUtils.GetValue(equipment, equip); | |
275 double oldAmount = (currSelection == null ? 0 : currSelection.AmountTaken); | |
276 | |
277 if (amount != oldAmount) | |
278 { | |
279 if (oldAmount == 0) | |
280 { | |
281 AddEquipmentAmount(equip, amount); | |
282 } | |
283 else if (currSelection is UnitEquipmentNumericSelection) | |
284 { | |
285 //A UnitEquipmentItem shouldn't change its IsRatio value, so assume we already have the right sub-type | |
286 currSelection.AmountTaken = amount; | |
287 } | |
288 else | |
289 { | |
290 RemoveEquipmentItem(equip); | |
291 AddEquipmentAmount(equip, amount); | |
292 } | |
293 | |
294 OnUnitEquipmentAmountChanged(equip, oldAmount, amount); | |
295 } | |
296 } | |
297 } | |
298 | |
299 private void AddEquipmentAmount(UnitEquipmentItem equip, int amount) | |
300 { | |
301 AbstractUnitEquipmentItemSelection newItem = new UnitEquipmentNumericSelection(this, equip, amount); | |
302 equipment[equip] = newItem; | |
303 List<AbstractUnitEquipmentItemSelection> selections = DictionaryUtils.GetValue(equipmentSlots, equip.SlotName); | |
304 | |
305 if (selections == null) | |
306 { | |
307 selections = new List<AbstractUnitEquipmentItemSelection>(); | |
308 equipmentSlots[equip.SlotName] = selections; | |
309 } | |
310 | |
311 selections.Add(newItem); | |
312 } | |
313 | |
314 public void SetEquipmentRatio(UnitEquipmentItem equip, double ratio) | |
315 { | |
316 if (!equip.IsRatioLimit) | |
317 { | |
318 throw new InvalidOperationException("Equipment with ID " + equip.ID + " for unit of type " + UnitType.ID + " has an absolute limit, not a ratio limit"); | |
319 } | |
320 | |
321 if (ratio > 100) | |
322 { | |
323 ratio = 100; | |
324 } | |
325 else if (ratio < 0) | |
326 { | |
327 ratio = 0; | |
328 } | |
329 | |
330 if (ratio == 0) | |
331 { | |
332 RemoveEquipmentItem(equip); | |
333 } | |
334 else | |
335 { | |
336 AbstractUnitEquipmentItemSelection currSelection = DictionaryUtils.GetValue(equipment, equip); | |
337 double oldRatio = (currSelection == null ? 0 : currSelection.AmountTaken); | |
338 | |
339 if (ratio != oldRatio) | |
340 { | |
341 if (oldRatio == 0) | |
342 { | |
343 AddEquipmentRatio(equip, ratio); | |
344 } | |
345 else if (currSelection is UnitEquipmentRatioSelection) | |
346 { | |
347 currSelection.AmountTaken = ratio; | |
348 } | |
349 else | |
350 { | |
351 RemoveEquipmentItem(equip); | |
352 AddEquipmentRatio(equip, ratio); | |
353 } | |
354 | |
355 OnUnitEquipmentAmountChanged(equip, oldRatio, ratio); | |
356 } | |
357 } | |
358 } | |
359 | |
360 private void AddEquipmentRatio(UnitEquipmentItem equip, double ratio) | |
361 { | |
362 UnitEquipmentRatioSelection newItem = new UnitEquipmentRatioSelection(this, equip, ratio); | |
363 equipment[equip] = newItem; | |
364 List<AbstractUnitEquipmentItemSelection> selections = DictionaryUtils.GetValue(equipmentSlots, equip.SlotName); | |
365 | |
366 if (selections == null) | |
367 { | |
368 selections = new List<AbstractUnitEquipmentItemSelection>(); | |
369 equipmentSlots[equip.SlotName] = selections; | |
370 } | |
371 | |
372 selections.Add(newItem); | |
373 } | |
374 | |
375 private void RemoveEquipmentItem(UnitEquipmentItem equip) | |
376 { | |
377 double oldAmount = UnitEquipmentUtil.GetEquipmentAmount(this, equip); | |
378 | |
379 if (oldAmount != 0) | |
380 { | |
381 AbstractUnitEquipmentItemSelection selection = DictionaryUtils.GetValue(equipment, equip); | |
382 equipment.Remove(equip); | |
383 List<AbstractUnitEquipmentItemSelection> slotSelections = DictionaryUtils.GetValue(equipmentSlots, equip.SlotName); | |
384 slotSelections.Remove(selection); | |
385 OnUnitEquipmentAmountChanged(equip, oldAmount, 0); | |
386 } | |
387 } | |
388 | |
389 public bool CanEquipWithItem(UnitEquipmentItem item) | |
390 { | |
391 string[] mutexes = item.MutexGroups; | |
392 bool canEquip = false; | |
393 | |
394 if (mutexes.Length == 0) | |
395 { | |
396 canEquip = true; | |
397 } | |
398 else | |
399 { | |
400 canEquip = UnitEquipmentUtil.GetBlockingEquipmentItems(this, item).Count == 0; | |
401 } | |
402 | |
403 return canEquip; | |
404 } | |
405 | |
406 public bool CanEquipWithItem(string equipID) | |
407 { | |
408 return CanEquipWithItem(UnitType.GetEquipmentItem(equipID)); | |
409 } | |
410 | |
411 private void OnPointsValueChanged(double oldValue, double newValue) | |
412 { | |
413 if (PointsValueChanged != null) | |
414 { | |
415 PointsValueChanged(this, oldValue, newValue); | |
416 } | |
417 } | |
418 | |
419 private void OnUnitSizeChanged(int oldValue, int newValue) | |
420 { | |
421 if (UnitSizeChanged != null) | |
422 { | |
423 UnitSizeChanged(this, oldValue, newValue); | |
424 } | |
425 } | |
426 | |
427 private void OnUnitEquipmentAmountChanged(UnitEquipmentItem equip, double oldValue, double newValue) | |
428 { | |
429 if (UnitEquipmentAmountChanged != null) | |
430 { | |
431 UnitEquipmentAmountChanged(equip, oldValue, newValue); | |
432 } | |
433 } | |
434 | |
435 public Stat[][] UnitStatsArrays | |
436 { | |
437 get { return UnitType.UnitStatsArrays; } | |
438 } | |
439 | |
440 public Stat[][] UnitStatsArraysWithName | |
441 { | |
442 get { return UnitType.UnitStatsArraysWithName; } | |
443 } | |
444 | |
445 public string[] UnitStatsArrayIDs | |
446 { | |
447 get | |
448 { | |
449 return UnitType.UnitStatsArrayIDs; | |
450 } | |
451 } | |
452 | |
453 public string GetStatValue(string statName) | |
454 { | |
455 return UnitType.GetStatValue(statName); | |
456 } | |
457 | |
458 public int GetEquipmentAmountInSlot(string slotName) | |
459 { | |
460 int amount = 0; | |
461 | |
462 List<AbstractUnitEquipmentItemSelection> selections = GetEquipmentSlotSelections(slotName); | |
463 | |
464 if (selections != null) | |
465 { | |
466 amount = GetSelectionTotal(selections); | |
467 } | |
468 | |
469 return amount; | |
470 } | |
471 | |
472 internal List<AbstractUnitEquipmentItemSelection> GetEquipmentSlotSelections(string slotName) | |
473 { | |
474 return DictionaryUtils.GetValue(equipmentSlots, slotName); | |
475 } | |
476 | |
477 /// <summary> | |
478 /// Gets the total amount of items taken for the item's slot, excluding the provided item | |
479 /// </summary> | |
480 /// <param name="item">the item to exclude from the count</param> | |
481 /// <returns>the total number of items</returns> | |
482 public int GetEquipmentAmountInSlotExcludingItem(UnitEquipmentItem item) | |
483 { | |
484 int amount = 0; | |
485 | |
486 List<AbstractUnitEquipmentItemSelection> selections = DictionaryUtils.GetValue(equipmentSlots, item.SlotName); | |
487 | |
488 if (selections != null) | |
489 { | |
490 selections = new List<AbstractUnitEquipmentItemSelection>(selections); | |
491 RemoveSelectionFromList(item, selections); | |
492 amount = GetSelectionTotal(selections); | |
493 } | |
494 | |
495 return amount; | |
496 } | |
497 | |
498 private void RemoveSelectionFromList(UnitEquipmentItem item, List<AbstractUnitEquipmentItemSelection> selections) | |
499 { | |
500 AbstractUnitEquipmentItemSelection selection = GetEquipmentSelection(item); | |
501 | |
502 if (selection != null) | |
503 { | |
504 selections.Remove(selection); | |
505 } | |
506 } | |
507 | |
508 private int GetSelectionTotal(List<AbstractUnitEquipmentItemSelection> selections) | |
509 { | |
510 int amount = 0; | |
511 | |
512 foreach (AbstractUnitEquipmentItemSelection selection in selections) | |
513 { | |
514 amount += selection.NumberTaken; | |
515 } | |
516 | |
517 return amount; | |
518 } | |
519 | |
520 /// <summary> | |
521 /// Default stub implementation of getting the unit's abilities - defaults to just the unit type's required abilities until we get a way to modify them | |
522 /// </summary> | |
523 public ICollection<Ability> Abilities | |
524 { | |
525 get | |
526 { | |
527 return UnitType.GetRequiredAbilities(); | |
528 } | |
529 } | |
530 | |
531 private void RefreshUnitEquipmentAmounts(WarFoundryObject obj, int oldValue, int newValue) | |
532 { | |
533 foreach (UnitEquipmentItem item in equipment.Keys) | |
534 { | |
535 AbstractUnitEquipmentItemSelection selection = equipment[item]; | |
536 | |
537 if (selection is UnitEquipmentRatioSelection) | |
538 { | |
539 OnUnitEquipmentAmountChanged(item, selection.AmountTaken, selection.AmountTaken); | |
540 } | |
541 } | |
542 } | |
543 } | |
544 } |