Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Element.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
6  FILE: Element.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Package Element (e.g. Flight) class implementation
13 */
14 
15 #include "MemDebug.h"
16 #include "Element.h"
17 #include "Instruction.h"
18 #include "RadioMessage.h"
19 #include "RadioHandler.h"
20 #include "Sim.h"
21 #include "Ship.h"
22 #include "NetUtil.h"
23 
24 #include "Game.h"
25 
26 // +----------------------------------------------------------------------+
27 
28 static int id_key = 1000;
29 
30 Element::Element(const char* call_sign, int a_iff, int a_type)
31 : id(id_key++), name(call_sign), type(a_type), iff(a_iff),
32 player(0), command_ai(1), commander(0), assignment(0), carrier(0),
33 combat_group(0), combat_unit(0), launch_time(0), hold_time(0),
34 zone_lock(0), respawns(0), count(0), rogue(false), playable(true), intel(0)
35 {
36  if (!call_sign) {
37  char buf[32];
38  sprintf_s(buf, "Pkg %d", id);
39  name = buf;
40  }
41 
42  SetLoadout(0);
43 }
44 
46 {
50 
51  for (int i = 0; i < ships.size(); i++)
52  ships[i]->SetElement(0);
53 
54  respawns = 0;
55 }
56 
57 // +----------------------------------------------------------------------+
58 
59 int
60 Element::AddShip(Ship* ship, int index)
61 {
62  if (ship && !ships.contains(ship)) {
63  Observe(ship);
64 
65  if (index < 0) {
66  ships.append(ship);
67  index = ships.size();
68  }
69  else {
70  ships.insert(ship, index-1);
71  }
72 
73  ship->SetElement(this);
74 
75  if (respawns < ship->RespawnCount())
76  respawns = ship->RespawnCount();
77  }
78 
79  return index;
80 }
81 
82 void
84 {
85  if (ship && ships.contains(ship)) {
86  ships.remove(ship);
87  ship->SetElement(0);
88 
89  if (ships.isEmpty())
90  respawns = ship->RespawnCount();
91  }
92 }
93 
94 Ship*
95 Element::GetShip(int index)
96 {
97  if (index >= 1 && index <= ships.size())
98  return ships[index-1];
99 
100  return 0;
101 }
102 
103 int
105 {
106  if (ships.size())
107  return ships[0]->Class();
108 
109  return 0;
110 }
111 
112 int
114 {
115  return ships.index(s) + 1;
116 }
117 
118 bool
120 {
121  return ships.contains(s);
122 }
123 
124 bool
126 {
127  bool active = false;
128 
129  for (int i = 0; i < ships.size() && !active; i++) {
130  Ship* s = ships[i];
131  if (s->Life() && s->MissionClock())
132  active = true;
133  }
134 
135  return active;
136 }
137 
138 bool
140 {
141  bool finished = false;
142 
143  if (launch_time > 0 && respawns < 1) {
144  finished = true;
145 
146  if (ships.size() > 0) {
147  for (int i = 0; i < ships.size() && finished; i++) {
148  Ship* s = ships[i];
149  if (s->RespawnCount() > 0 ||
150  s->MissionClock() == 0 ||
151  s->Life() && !s->GetInbound())
152  finished = false;
153  }
154  }
155  }
156 
157  return finished;
158 }
159 
160 bool
162 {
163  bool observer = !IsSquadron();
164 
165  for (int i = 0; i < ships.size() && observer; i++) {
166  Ship* s = ships[i];
167 
168  if (!s->IsNetObserver())
169  observer = false;
170  }
171 
172  return observer;
173 }
174 
175 bool
177 {
178  return count > 0;
179 }
180 
181 bool
183 {
184  if (IsSquadron() || IsFinished())
185  return false;
186 
187  const Ship* s = ships.at(0);
188  if (s && s->IsStatic())
189  return true;
190 
191  return false;
192 }
193 
194 // +----------------------------------------------------------------------+
195 
196 bool
197 Element::IsHostileTo(const Ship* s) const
198 {
199  if (iff <= 0 || iff >= 100 || !s || launch_time == 0 || IsFinished())
200  return false;
201 
202  if (IsSquadron())
203  return false;
204 
205  if (s->IsRogue())
206  return true;
207 
208  int s_iff = s->GetIFF();
209 
210  if (s_iff <= 0 || s_iff >= 100 || s_iff == iff)
211  return false;
212 
213  if (ships.size() > 0 && ships[0]->GetRegion() != s->GetRegion())
214  return false;
215 
216  return true;
217 }
218 
219 bool
220 Element::IsHostileTo(int iff_code) const
221 {
222  if (iff <= 0 || iff >= 100 || launch_time == 0 || IsFinished())
223  return false;
224 
225  if (IsSquadron())
226  return false;
227 
228  if (iff_code <= 0 || iff_code >= 100 || iff_code == iff)
229  return false;
230 
231  return true;
232 }
233 
234 bool
236 {
237  if (!s || launch_time == 0 || IsFinished())
238  return false;
239 
240  const char* e_name = Name().data();
241  int e_len = Name().length();
242 
243  Instruction* orders = s->GetRadioOrders();
244  if (orders && orders->Action() > Instruction::SWEEP) {
245  const char* o_name = orders->TargetName();
246  int o_len = 0;
247 
248  if (o_name && *o_name)
249  o_len = strlen(o_name);
250 
251  if (e_len < o_len)
252  o_len = e_len;
253 
254  if (!strncmp(e_name, o_name, o_len))
255  return true;
256  }
257 
258  Element* elem = s->GetElement();
259  if (elem) {
260  for (int i = 0; i < elem->NumObjectives(); i++) {
261  Instruction* obj = elem->GetObjective(i);
262 
263  if (obj) {
264  const char* o_name = obj->TargetName();
265  int o_len = 0;
266 
267  if (o_name && *o_name)
268  o_len = strlen(o_name);
269 
270  if (e_len < o_len)
271  o_len = e_len;
272 
273  if (!strncmp(e_name, o_name, o_len))
274  return true;
275  }
276  }
277  }
278 
279  return false;
280 }
281 
282 // +----------------------------------------------------------------------+
283 
284 void
286 {
287  if (launch_time == 0 || t == 0)
288  launch_time = t;
289 }
290 
291 double
293 {
294  return hold_time;
295 }
296 
297 void
299 {
300  if (t >= 0)
301  hold_time = t;
302 }
303 
304 bool
306 {
307  return zone_lock;
308 }
309 
310 void
312 {
313  zone_lock = z;
314 }
315 
316 void
318 {
319  if (l) {
320  CopyMemory(load, l, sizeof(load));
321  }
322  else {
323  for (int i = 0; i < 16; i++)
324  load[i] = -1;
325  }
326 }
327 
328 // +----------------------------------------------------------------------+
329 
330 bool
332 {
333  // false alarm, keep watching:
334  if (obj->Life() != 0) {
335  ::Print("Element (%s) false update on (%s) life = %f\n", Name().data(), obj->Name(), obj->Life());
336  return false;
337  }
338 
339  Ship* s = (Ship*) obj;
340  ships.remove(s);
341 
342  if (ships.isEmpty())
343  respawns = s->RespawnCount();
344 
345  return SimObserver::Update(obj);
346 }
347 
348 const char*
350 {
351  return (const char*) (Text("Element ") + Name());
352 }
353 
354 // +----------------------------------------------------------------------+
355 
356 void
357 Element::AddNavPoint(Instruction* pt, Instruction* afterPoint, bool send)
358 {
359  if (pt && !flight_plan.contains(pt)) {
360  int index = -1;
361 
362  if (afterPoint) {
363  index = flight_plan.index(afterPoint);
364 
365  if (index > -1)
366  flight_plan.insert(pt, index+1);
367  else
368  flight_plan.append(pt);
369  }
370 
371  else {
372  flight_plan.append(pt);
373  }
374 
375  if (send) {
376  NetUtil::SendNavData(true, this, index, pt);
377  }
378  }
379 }
380 
381 void
383 {
384  // XXX MEMORY LEAK
385  // This is a small memory leak, but I'm not sure if it is
386  // safe to delete the navpoint when removing it from the
387  // flight plan. Other ships in the element might have
388  // pointers to the object...?
389 
390  if (pt) {
391  int index = flight_plan.index(pt);
392  flight_plan.remove(pt);
393 
394  if (send) {
395  NetUtil::SendNavDelete(this, index);
396  }
397  }
398 }
399 
400 // +----------------------------------------------------------------------+
401 
402 void
404 {
405  hold_time = 0;
409 
410  if (send) {
411  NetUtil::SendNavDelete(this, -1);
412  }
413 }
414 
415 // +----------------------------------------------------------------------+
416 
419 {
420  if (hold_time <= 0 && flight_plan.size() > 0) {
422  while (++iter) {
423  Instruction* navpt = iter.value();
424 
425  if (navpt->Status() == Instruction::COMPLETE && navpt->HoldTime() > 0)
426  return navpt;
427 
428  if (navpt->Status() <= Instruction::ACTIVE)
429  return navpt;
430  }
431  }
432 
433  return 0;
434 }
435 
436 // +----------------------------------------------------------------------+
437 
438 int
440 {
441  int index = 0;
442 
443  if (flight_plan.size() > 0) {
445  while (++navpt) {
446  index++;
447  if (navpt.value() == n)
448  return index;
449  }
450  }
451 
452  return 0;
453 }
454 
455 // +----------------------------------------------------------------------+
456 
459 {
460  return flight_plan;
461 }
462 
463 int
465 {
466  return flight_plan.size();
467 }
468 
469 // +----------------------------------------------------------------------+
470 
471 void
473 {
475 }
476 
477 void
479 {
480  objectives.append(obj);
481 }
482 
485 {
486  if (objectives.isEmpty())
487  return 0;
488 
489  if (index < 0)
490  index = 0;
491 
492  else if (index >= objectives.size())
493  index = index % objectives.size();
494 
495  return objectives.at(index);
496 }
497 
500 {
501  for (int i = 0; i < objectives.size(); i++) {
502  Instruction* obj = objectives[i];
503 
504  if (obj->Status() <= Instruction::ACTIVE) {
505  switch (obj->Action()) {
507  case Instruction::STRIKE:
509  case Instruction::SWEEP:
510  case Instruction::PATROL:
511  case Instruction::RECON:
512  case Instruction::ESCORT:
513  case Instruction::DEFEND:
514  return obj;
515 
516  default:
517  break;
518  }
519  }
520  }
521 
522  return 0;
523 }
524 
525 // +----------------------------------------------------------------------+
526 
527 void
529 {
531 }
532 
533 void
534 Element::AddInstruction(const char* instr)
535 {
536  instructions.append(new(__FILE__,__LINE__) Text(instr));
537 }
538 
539 Text
541 {
542  if (instructions.isEmpty())
543  return Text();
544 
545  if (index < 0)
546  index = 0;
547 
548  if (index >= instructions.size())
549  index = index % instructions.size();
550 
551  return *instructions.at(index);
552 }
553 
554 // +----------------------------------------------------------------------+
555 
556 void
558 {
559  SetAssignment(0);
560 
561  if (objectives.isEmpty())
562  return;
563 
564  Instruction* objective = 0;
565 
566  for (int i = 0; i < objectives.size() && !objective; i++) {
567  Instruction* instr = objectives[i];
568 
569  if (instr->Status() <= Instruction::ACTIVE) {
570  switch (instr->Action()) {
572  case Instruction::STRIKE:
574  objective = instr;
575  break;
576  }
577  }
578  }
579 
580  if (objective) {
581  Sim* sim = Sim::GetSim();
582 
583  ListIter<Element> iter = sim->GetElements();
584  while (++iter) {
585  Element* elem = iter.value();
586  SimObject* tgt = objective->GetTarget();
587 
588  if (tgt && tgt->Type() == SimObject::SIM_SHIP && elem->Contains((const Ship*) tgt)) {
589  SetAssignment(elem);
590  return;
591  }
592  }
593  }
594 }
595 
596 // +----------------------------------------------------------------------+
597 
598 void
600 {
601  if (!msg) return;
602 
603  static RadioHandler rh;
604 
605  // if this is a message from within the element,
606  // then all ships should report in. Otherwise,
607  // just the leader will acknowledge the message.
608  int full_report = ships.contains(msg->Sender());
609  int reported = false;
610 
611  ListIter<Ship> s = ships;
612  while (++s) {
613  if (rh.ProcessMessage(msg, s.value())) {
614  if (full_report) {
615  if (s.value() != msg->Sender())
616  rh.AcknowledgeMessage(msg, s.value());
617  }
618 
619  else if (!reported) {
620  rh.AcknowledgeMessage(msg, s.value());
621  reported = true;
622  }
623  }
624  }
625 }
626 
627 // +----------------------------------------------------------------------+
628 
629 bool
631 {
632  while (e) {
633  if (e->commander == this)
634  return true;
635  e = e->commander;
636  }
637 
638  return false;
639 }
640 
641 // +----------------------------------------------------------------------+
642 
643 void
644 Element::ExecFrame(double seconds)
645 {
646  if (hold_time > 0) {
647  hold_time -= seconds;
648  return;
649  }
650 
652  while (++iter) {
653  Instruction* instr = iter.value();
654 
655  if (instr->Status() == Instruction::COMPLETE && instr->HoldTime() > 0)
656  instr->SetHoldTime(instr->HoldTime() - seconds);
657  }
658 }
659 
660 // +----------------------------------------------------------------------+
661 
662 void
664 {
665  for (int i = 0; i < ships.size(); i++)
666  ships[i]->SetIFF(iff);
667 }