Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
CombatUnit.cpp
Go to the documentation of this file.
1 /* Project Starshatter 4.5
2  Destroyer Studios LLC
3  Copyright © 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: Stars.exe
6  FILE: CombatUnit.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  A ship, station, or ground unit in the dynamic campaign.
13 */
14 
15 #include "MemDebug.h"
16 #include "CombatUnit.h"
17 #include "CombatGroup.h"
18 #include "Campaign.h"
19 #include "ShipDesign.h"
20 #include "Ship.h"
21 
22 #include "Game.h"
23 
24 // +----------------------------------------------------------------------+
25 
26 inline double random() { return (double) rand() / (double) RAND_MAX; }
27 
28 // +----------------------------------------------------------------------+
29 
30 CombatUnit::CombatUnit(const char* n, const char* reg, int t, const char* d, int c, int i)
31 : name(n), regnum(reg), type(t), design_name(d), design(0),
32 count(c), iff(i), leader(false), dead_count(0), available(c),
33 carrier(0), plan_value(0), launch_time(-1e6), jump_time(0),
34 sustained_damage(0), target(0), group(0), heading(0)
35 { }
36 
38 : name(u.name), regnum(u.regnum), type(u.type), design_name(u.design_name),
39 design(u.design), count(u.count), iff(u.iff),
40 dead_count(u.dead_count), available(u.available),
41 leader(u.leader), region(u.region), location(u.location),
42 carrier(u.carrier), plan_value(0), launch_time(u.launch_time),
43 jump_time(u.jump_time), sustained_damage(u.sustained_damage),
44 target(0), group(0), heading(u.heading)
45 { }
46 
47 // +----------------------------------------------------------------------+
48 
49 const ShipDesign*
51 {
52  if (!design)
53  design = ShipDesign::Get(design_name);
54 
55  return design;
56 }
57 
58 int
60 {
61  if (design)
62  return design->type;
63 
64  return type;
65 }
66 
67 int
69 {
70  return GetSingleValue() * LiveCount();
71 }
72 
73 int
75 {
76  return Ship::Value(GetShipClass());
77 }
78 
79 // +----------------------------------------------------------------------+
80 
81 const char*
83 {
84  if (!design) {
85  CombatUnit* pThis = (CombatUnit*) this; // cast-away const
86  pThis->GetDesign();
87  }
88 
89  static char desc[256];
90 
91  if (!design) {
92  strcpy_s(desc, Game::GetText("[unknown]").data());
93  }
94 
95  else if (count > 1) {
96  sprintf_s(desc, "%dx %s %s", LiveCount(), design->abrv, design->DisplayName());
97  }
98 
99  else {
100  if (regnum.length() > 0)
101  sprintf_s(desc, "%s-%s %s", design->abrv, (const char*) regnum, (const char*) name);
102  else
103  sprintf_s(desc, "%s %s", design->abrv, (const char*) name);
104 
105  if (dead_count > 0) {
106  strcat_s(desc, " ");
107  strcat_s(desc, Game::GetText("killed.in.action"));
108  }
109  }
110 
111  return desc;
112 }
113 
114 // +----------------------------------------------------------------------+
115 
116 bool
118 {
119  bool result = false;
120 
121  switch (type) {
122  case Ship::FIGHTER:
123  case Ship::ATTACK:
124  case Ship::CORVETTE:
125  case Ship::FRIGATE:
126  case Ship::DESTROYER:
127  case Ship::CRUISER:
128  case Ship::CARRIER: result = true; break;
129  }
130 
131  return result;
132 }
133 
134 // +----------------------------------------------------------------------+
135 
136 bool
138 {
139  bool result = false;
140 
141  switch (type) {
142  case Ship::FIGHTER:
143  case Ship::ATTACK: result = (Campaign::Stardate() - launch_time) >= 300;
144  break;
145 
146  case Ship::CORVETTE:
147  case Ship::FRIGATE:
148  case Ship::DESTROYER:
149  case Ship::CRUISER:
150  case Ship::CARRIER: result = true;
151  break;
152  }
153 
154  return result;
155 }
156 
157 // +----------------------------------------------------------------------+
158 
159 Color
161 {
162  return Ship::IFFColor(iff);
163 }
164 
165 bool
167 {
168  return (design && (design->type & Ship::GROUND_UNITS)) ? true : false;
169 }
170 
171 bool
173 {
174  return (design && (design->type & Ship::STARSHIPS)) ? true : false;
175 }
176 
177 bool
179 {
180  return (design && (design->type & Ship::DROPSHIPS)) ? true : false;
181 }
182 
183 bool
185 {
186  return design && (design->type >= Ship::STATION);
187 }
188 
189 // +----------------------------------------------------------------------+
190 
191 double
193 {
194  return 100e3;
195 }
196 
198 {
199  return 50e3;
200 }
201 
203 {
204  if (type == Ship::FIGHTER || type == Ship::ATTACK)
205  return 15e3;
206 
207  return 30e3;
208 }
209 
210 // +----------------------------------------------------------------------+
211 
213 {
214  if (unit == 0 || unit == this)
215  return false;
216 
217  if (type > Ship::STATION)
218  return false;
219 
220  double distance = (location - unit->location).length();
221 
222  if (type > unit->type)
223  return false;
224 
225  if (distance > MaxRange())
226  return false;
227 
228  return true;
229 }
230 
231 // +----------------------------------------------------------------------+
232 
234 {
235  if (tgt == 0 || tgt == this || available < 1)
236  return 0;
237 
238  if (type > Ship::STATION)
239  return 0;
240 
241  double effectiveness = 1;
242  double distance = (location - tgt->location).length();
243 
244  if (distance > MaxRange())
245  return 0;
246 
247  if (distance > MaxEffectiveRange())
248  effectiveness = 0.5;
249 
250  if (type == Ship::FIGHTER) {
251  if (tgt->type == Ship::FIGHTER || tgt->type == Ship::ATTACK)
252  return Ship::FIGHTER * 2 * available * effectiveness;
253  else
254  return 0;
255  }
256  else if (type == Ship::ATTACK) {
257  if (tgt->type > Ship::ATTACK)
258  return Ship::ATTACK * 3 * available * effectiveness;
259  else
260  return 0;
261  }
262  else if (type == Ship::CARRIER) {
263  return 0;
264  }
265  else if (type == Ship::CRUISER) {
266  if (tgt->type <= Ship::ATTACK)
267  return type * effectiveness;
268 
269  else
270  return 0;
271  }
272  else {
273  if (tgt->type > Ship::ATTACK)
274  return type * effectiveness;
275  else
276  return type * 0.1 * effectiveness;
277  }
278 
279  return 0;
280 }
281 
282 // +----------------------------------------------------------------------+
283 
284 int
286 {
287  int assign = count;
288 
289  if (count > 4)
290  assign = 4;
291 
292  if (assign > 0) {
293  available -= assign;
294  launch_time = Campaign::Stardate();
295  return assign;
296  }
297 
298  return 0;
299 }
300 
301 // +----------------------------------------------------------------------+
302 
303 void
305 {
306  Disengage();
307 
308  if (count > 4)
309  available += 4;
310 
311  else
312  available += count;
313 }
314 
315 // +----------------------------------------------------------------------+
316 
317 void
319 {
320  if (!carrier)
321  location = loc;
322  else
323  location = carrier->location;
324 }
325 
326 // +----------------------------------------------------------------------+
327 
328 void
330 {
331  if (!tgt)
332  Disengage();
333 
334  else if (!tgt->attackers.contains(this))
335  tgt->attackers.append(this);
336 
337  target = tgt;
338 }
339 
340 void
342 {
343  if (target)
344  target->attackers.remove(this);
345 
346  target = 0;
347 }
348 
349 // +----------------------------------------------------------------------+
350 
351 static int KillGroup(CombatGroup* group)
352 {
353  int value_killed = 0;
354 
355  if (group) {
356  ListIter<CombatUnit> u_iter = group->GetUnits();
357  while (++u_iter) {
358  CombatUnit* u = u_iter.value();
359  value_killed += u->Kill(u->LiveCount());
360  }
361 
362  ListIter<CombatGroup> g_iter = group->GetComponents();
363  while (++g_iter) {
364  CombatGroup* g = g_iter.value();
365  value_killed += KillGroup(g);
366  }
367  }
368 
369  return value_killed;
370 }
371 
372 int
374 {
375  int killed = n;
376 
377  if (killed > LiveCount())
378  killed = LiveCount();
379 
380  dead_count += killed;
381 
382  int value_killed = killed * GetSingleValue();
383 
384  if (killed) {
385  // if unit could support children, kill them too:
386  if (type == Ship::CARRIER ||
387  type == Ship::STATION ||
388  type == Ship::STARBASE) {
389 
390  if (group) {
391  ListIter<CombatGroup> iter = group->GetComponents();
392  while (++iter) {
393  CombatGroup* g = iter.value();
394  value_killed += KillGroup(g);
395  }
396  }
397  }
398  }
399 
400  return value_killed;
401 }
402