Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
ShipDesign.cpp
Go to the documentation of this file.
1 /* Project Starshatter 5.0
2  Destroyer Studios LLC
3  Copyright (C) 1997-2007. All Rights Reserved.
4 
5  SUBSYSTEM: Stars.exe
6  FILE: ShipDesign.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Starship Design parameters class
13 */
14 
15 #include "MemDebug.h"
16 #include "ShipDesign.h"
17 #include "Ship.h"
18 #include "Shot.h"
19 #include "Power.h"
20 #include "HardPoint.h"
21 #include "Weapon.h"
22 #include "WeaponDesign.h"
23 #include "Shield.h"
24 #include "Sensor.h"
25 #include "NavLight.h"
26 #include "NavSystem.h"
27 #include "Drive.h"
28 #include "QuantumDrive.h"
29 #include "Farcaster.h"
30 #include "Thruster.h"
31 #include "FlightDeck.h"
32 #include "LandingGear.h"
33 #include "Computer.h"
34 #include "SystemDesign.h"
35 #include "Component.h"
36 
37 #include "Game.h"
38 #include "Solid.h"
39 #include "Skin.h"
40 #include "Sprite.h"
41 #include "Light.h"
42 #include "Bitmap.h"
43 #include "Sound.h"
44 #include "DataLoader.h"
45 #include "ParseUtil.h"
46 
47 // +--------------------------------------------------------------------+
48 
49 const char* ship_design_class_name[32] = {
50  "Drone", "Fighter",
51  "Attack", "LCA",
52  "Courier", "Cargo",
53  "Corvette", "Freighter",
54 
55  "Frigate", "Destroyer",
56  "Cruiser", "Battleship",
57  "Carrier", "Dreadnaught",
58 
59  "Station", "Farcaster",
60 
61  "Mine", "DEFSAT",
62  "COMSAT", "SWACS",
63 
64  "Building", "Factory",
65  "SAM", "EWR",
66  "C3I", "Starbase",
67 
68  "0x04000000", "0x08000000",
69  "0x10000000", "0x20000000",
70  "0x40000000", "0x80000000"
71 };
72 
73 // +--------------------------------------------------------------------+
74 
75 static const int NAMELEN = 64;
76 static bool degrees = false;
77 
79  static const char* TYPENAME() { return "ShipCatalogEntry"; }
80 
81  ShipCatalogEntry() : hide(false), design(0) {}
82 
83  ShipCatalogEntry(const char* n, const char* t, const char* p, const char* f, bool h=false) :
84  name(n), type(t), path(p), file(f), hide(h), design(0) {}
85 
86  ~ShipCatalogEntry() { delete design; }
87 
92  bool hide;
93 
95 };
96 
97 static List<ShipCatalogEntry> catalog;
98 static List<ShipCatalogEntry> mod_catalog;
99 
100 // +--------------------------------------------------------------------+
101 
102 #define GET_DEF_BOOL(n) if (defname==(#n)) GetDefBool((n), def, filename)
103 #define GET_DEF_TEXT(n) if (defname==(#n)) GetDefText((n), def, filename)
104 #define GET_DEF_NUM(n) if (defname==(#n)) GetDefNumber((n), def, filename)
105 #define GET_DEF_VEC(n) if (defname==(#n)) GetDefVec((n), def, filename)
106 
107 static char cockpit_name[80];
108 static List<Text> detail[4];
109 static List<Point> offset[4];
110 
111 static char errmsg[256];
112 
113 // +--------------------------------------------------------------------+
114 
116 {
117  ZeroMemory(name, sizeof(name));
118  ZeroMemory(load, sizeof(load));
119  mass = 0;
120 }
121 
123 {
124  name[0] = 0;
125  design = 0;
126  count = 4;
127  avail = 4;
128 }
129 
130 static void PrepareModel(Model& model)
131 {
132  bool uses_bumps = false;
133 
134  ListIter<Material> iter = model.GetMaterials();
135  while (++iter && !uses_bumps) {
136  Material* mtl = iter.value();
137  if (mtl->tex_bumpmap != 0 && mtl->bump != 0)
138  uses_bumps = true;
139  }
140 
141  if (uses_bumps)
142  model.ComputeTangents();
143 }
144 
145 // +--------------------------------------------------------------------+
146 
148 : sensor(0), navsys(0), shield(0), type(0), decoy(0),
149 probe(0), gear(0), valid(false), secret(false), auto_roll(1), cockpit_model(0),
150 bolt_hit_sound_resource(0), beam_hit_sound_resource(0), lod_levels(0)
151 {
152  ZeroMemory(filename, sizeof(filename));
153  ZeroMemory(path_name, sizeof(path_name));
154  ZeroMemory(name, sizeof(name));
155  ZeroMemory(display_name, sizeof(display_name));
156  ZeroMemory(abrv, sizeof(abrv));
157 
158  for (int i = 0; i < 4; i++)
159  feature_size[i] = 0.0f;
160 }
161 
162 // +--------------------------------------------------------------------+
163 
164 ShipDesign::ShipDesign(const char* n, const char* p, const char* fname, bool s)
165 : sensor(0), navsys(0), shield(0), type(0),
166 quantum_drive(0), farcaster(0), thruster(0), shield_model(0), decoy(0),
167 probe(0), gear(0), valid(false), secret(s), auto_roll(1), cockpit_model(0),
168 bolt_hit_sound_resource(0), beam_hit_sound_resource(0), lod_levels(0)
169 {
170  ZeroMemory(filename, sizeof(filename));
171  ZeroMemory(path_name, sizeof(path_name));
172  ZeroMemory(name, sizeof(name));
173  ZeroMemory(display_name, sizeof(display_name));
174  ZeroMemory(abrv, sizeof(abrv));
175 
176  strcpy_s(name, n);
177 
178  if (!strstr(fname, ".def"))
179  sprintf_s(filename, "%s.def", fname);
180  else
181  strcpy_s(filename, fname);
182 
183  for (int i = 0; i < 4; i++)
184  feature_size[i] = 0.0f;
185 
186  scale = 1.0f;
187 
188  agility = 2e2f;
189  air_factor = 0.1f;
190  vlimit = 8e3f;
191  drag = 2.5e-5f;
192  arcade_drag = 1.0f;
193  roll_drag = 5.0f;
194  pitch_drag = 5.0f;
195  yaw_drag = 5.0f;
196 
197  roll_rate = 0.0f;
198  pitch_rate = 0.0f;
199  yaw_rate = 0.0f;
200 
201  trans_x = 0.0f;
202  trans_y = 0.0f;
203  trans_z = 0.0f;
204 
205  turn_bank = (float) (PI/8);
206 
207  CL = 0.0f;
208  CD = 0.0f;
209  stall = 0.0f;
210 
211  prep_time = 30.0f;
212  avoid_time = 0.0f;
213  avoid_fighter = 0.0f;
214  avoid_strike = 0.0f;
215  avoid_target = 0.0f;
216  commit_range = 0.0f;
217 
218  splash_radius = -1.0f;
219  scuttle = 5e3f;
220  repair_speed = 1.0f;
221  repair_teams = 2;
222  repair_auto = true;
223  repair_screen = true;
224  wep_screen = true;
225 
226  chase_vec = Vec3(0, -100, 20);
227  bridge_vec = Vec3(0, 0, 0);
228  beauty_cam = Vec3(0, 0, 0);
229  cockpit_scale = 1.0f;
230 
231  radius = 1.0f;
232  integrity = 500.0f;
233 
234  primary = 0;
235  secondary = 1;
236  main_drive = -1;
237 
238  pcs = 3.0f;
239  acs = 1.0f;
240  detet = 250.0e3f;
241  e_factor[0] = 0.1f;
242  e_factor[1] = 0.3f;
243  e_factor[2] = 1.0f;
244 
245  explosion_scale = 0.0f;
246  death_spiral_time = 3.0f;
247 
248  if (!secret)
249  Print("Loading ShipDesign '%s'\n", name);
250 
251  strcpy_s(path_name, p);
252  if (path_name[strlen(path_name)-1] != '/')
253  strcat_s(path_name, "/");
254 
255  // Load Design File:
256  DataLoader* loader = DataLoader::GetLoader();
257  loader->SetDataPath(path_name);
258 
259  BYTE* block;
260  int blocklen = loader->LoadBuffer(filename, block, true);
261 
262  // file not found:
263  if (blocklen <= 4) {
264  valid = false;
265  return;
266  }
267 
268  Parser parser(new(__FILE__,__LINE__) BlockReader((const char*) block, blocklen));
269  Term* term = parser.ParseTerm();
270 
271  if (!term) {
272  Print("ERROR: could not parse '%s'\n", filename);
273  valid = false;
274  return;
275  }
276  else {
277  TermText* file_type = term->isText();
278  if (!file_type || file_type->value() != "SHIP") {
279  Print("ERROR: invalid ship design file '%s'\n", filename);
280  valid = false;
281  return;
282  }
283  }
284 
285  cockpit_name[0] = 0;
286  valid = true;
287  degrees = false;
288 
289  do {
290  delete term;
291 
292  term = parser.ParseTerm();
293 
294  if (term) {
295  TermDef* def = term->isDef();
296  if (def) {
297  ParseShip(def);
298  }
299  else {
300  Print("WARNING: term ignored in '%s'\n", filename);
301  term->print();
302  }
303  }
304  }
305  while (term);
306 
307  for (int i = 0; i < 4; i++) {
308  int n = 0;
309  ListIter<Text> iter = detail[i];
310  while (++iter) {
311  const char* model_name = iter.value()->data();
312 
313  Model* model = new(__FILE__,__LINE__) Model;
314  if (!model->Load(model_name, scale)) {
315  Print("ERROR: Could not load detail %d, model '%s'\n", i, model_name);
316  delete model;
317  model = 0;
318  valid = false;
319  }
320 
321  else {
322  lod_levels = i+1;
323 
324  if (model->Radius() > radius)
325  radius = (float) model->Radius();
326 
327  models[i].append(model);
328  PrepareModel(*model);
329 
330  if (offset[i].size()) {
331  *offset[i].at(n) *= scale;
332  offsets[i].append(offset[i].at(n)); // transfer ownership
333  }
334  else
335  offsets[i].append(new(__FILE__,__LINE__) Point);
336 
337  n++;
338  }
339  }
340 
341  detail[i].destroy();
342  }
343 
344  if (!secret)
345  Print(" Ship Design Radius = %f\n", radius);
346 
347  if (cockpit_name[0]) {
348  const char* model_name = cockpit_name;
349 
350  cockpit_model = new(__FILE__,__LINE__) Model;
351  if (!cockpit_model->Load(model_name, cockpit_scale)) {
352  Print("ERROR: Could not load cockpit model '%s'\n", model_name);
353  delete cockpit_model;
354  cockpit_model = 0;
355  }
356  else {
357  if (!secret)
358  Print(" Loaded cockpit model '%s', preparing tangents\n", model_name);
359  PrepareModel(*cockpit_model);
360  }
361  }
362 
363  if (beauty.Width() < 1 && loader->FindFile("beauty.pcx"))
364  loader->LoadBitmap("beauty.pcx", beauty);
365 
366  if (hud_icon.Width() < 1 && loader->FindFile("hud_icon.pcx"))
367  loader->LoadBitmap("hud_icon.pcx", hud_icon);
368 
369  loader->ReleaseBuffer(block);
370  loader->SetDataPath(0);
371 
372  if (abrv[0] == 0) {
373  switch (type) {
374  case Ship::DRONE: strcpy_s(abrv, "DR"); break;
375  case Ship::FIGHTER: strcpy_s(abrv, "F"); break;
376  case Ship::ATTACK: strcpy_s(abrv, "F/A"); break;
377  case Ship::LCA: strcpy_s(abrv, "LCA"); break;
378  case Ship::CORVETTE: strcpy_s(abrv, "FC"); break;
379  case Ship::COURIER:
380  case Ship::CARGO:
381  case Ship::FREIGHTER: strcpy_s(abrv, "MV"); break;
382  case Ship::FRIGATE: strcpy_s(abrv, "FF"); break;
383  case Ship::DESTROYER: strcpy_s(abrv, "DD"); break;
384  case Ship::CRUISER: strcpy_s(abrv, "CA"); break;
385  case Ship::BATTLESHIP: strcpy_s(abrv, "BB"); break;
386  case Ship::CARRIER: strcpy_s(abrv, "CV"); break;
387  case Ship::DREADNAUGHT: strcpy_s(abrv, "DN"); break;
388  case Ship::MINE: strcpy_s(abrv, "MINE"); break;
389  case Ship::COMSAT: strcpy_s(abrv, "COMS"); break;
390  case Ship::DEFSAT: strcpy_s(abrv, "DEFS"); break;
391  case Ship::SWACS: strcpy_s(abrv, "SWAC"); break;
392  default: break;
393  }
394  }
395 
396  if (scuttle < 1)
397  scuttle = 1;
398 
399  if (splash_radius < 0)
400  splash_radius = radius * 12.0f;
401 
402  if (repair_speed <= 1e-6)
403  repair_speed = 1.0e-6f;
404 
405  if (commit_range <= 0) {
406  if (type <= Ship::LCA)
407  commit_range = 80.0e3f;
408  else
409  commit_range = 200.0e3f;
410  }
411 
412  // calc standard loadout weights:
414  while (++sl) {
415  for (int i = 0; i < hard_points.size(); i++) {
416  HardPoint* hp = hard_points[i];
417  sl->mass += hp->GetCarryMass(sl->load[i]);
418  }
419  }
420 }
421 
422 // +--------------------------------------------------------------------+
423 
425 {
428  delete cockpit_model;
429  delete navsys;
430  delete sensor;
431  delete shield;
432  delete thruster;
433  delete farcaster;
434  delete quantum_drive;
435  delete decoy;
436  delete probe;
437  delete gear;
438 
439  navlights.destroy();
442  computers.destroy();
443  weapons.destroy();
444  drives.destroy();
445  reactors.destroy();
446  loadouts.destroy();
448 
449  delete shield_model;
450  for (int i = 0; i < 4; i++) {
451  models[i].destroy();
452  offsets[i].destroy();
453  }
454 
456 
457  for (int i = 0; i < 10; i++) {
458  delete debris[i].model;
459  }
460 }
461 
462 const char*
464 {
465  if (display_name[0])
466  return display_name;
467 
468  return name;
469 }
470 
471 // +--------------------------------------------------------------------+
472 
473 void AddModCatalogEntry(const char* design_name, const char* design_path)
474 {
475  if (!design_name || !*design_name)
476  return;
477 
478  ShipCatalogEntry* entry = 0;
479 
480  for (int i = 0; i < catalog.size(); i++) {
481  ShipCatalogEntry* e = catalog[i];
482  if (e->name == design_name) {
483  if (design_path && *design_path && e->path != design_path)
484  continue;
485  entry = e;
486  return;
487  }
488  }
489 
490  for (int i = 0; i < mod_catalog.size(); i++) {
491  ShipCatalogEntry* e = mod_catalog[i];
492  if (e->name == design_name) {
493  if (design_path && *design_path) {
494  Text full_path = "Mods/Ships/";
495  full_path += design_path;
496 
497  if (e->path != full_path)
498  continue;
499  }
500 
501  entry = e;
502  return;
503  }
504  }
505 
506  // still here? not found yet:
507  Text file = Text(design_name) + ".def";
508  Text path = Text("Mods/Ships/");
509  Text name;
510  Text type;
511  bool valid = false;
512 
513  if (design_path && *design_path)
514  path += design_path;
515  else
516  path += design_name;
517 
518  path += "/";
519 
520  DataLoader* loader = DataLoader::GetLoader();
521  loader->SetDataPath(path);
522 
523  BYTE* block;
524  int blocklen = loader->LoadBuffer(file, block, true);
525 
526  // file not found:
527  if (blocklen <= 4) {
528  return;
529  }
530 
531  Parser parser(new(__FILE__,__LINE__) BlockReader((const char*) block, blocklen));
532  Term* term = parser.ParseTerm();
533 
534  if (!term) {
535  Print("ERROR: could not parse '%s'\n", file.data());
536  delete block;
537  return;
538  }
539  else {
540  TermText* file_type = term->isText();
541  if (!file_type || file_type->value() != "SHIP") {
542  Print("ERROR: invalid ship design file '%s'\n", file.data());
543  delete block;
544  return;
545  }
546  }
547 
548  valid = true;
549 
550  do {
551  delete term;
552 
553  term = parser.ParseTerm();
554 
555  if (term) {
556  TermDef* def = term->isDef();
557  if (def) {
558  Text defname = def->name()->value();
559  defname.setSensitive(false);
560 
561  if (defname == "class") {
562  if (!GetDefText(type, def, file)) {
563  Print("WARNING: invalid or missing ship class in '%s'\n", file.data());
564  valid = false;
565  }
566  }
567 
568  else if (defname == "name") {
569  if (!GetDefText(name, def, file)) {
570  Print("WARNING: invalid or missing ship name in '%s'\n", file.data());
571  valid = false;
572  }
573  }
574  }
575  else {
576  Print("WARNING: term ignored in '%s'\n", file.data());
577  term->print();
578  }
579  }
580  }
581  while (term && valid && (name.length() < 1 || type.length() < 1));
582 
583  delete block;
584 
585  if (valid && name.length() && type.length()) {
586  Print("Add Mod Catalog Entry '%s' Class '%s'\n", name.data(), type.data());
587 
588  ShipCatalogEntry* entry = new(__FILE__,__LINE__) ShipCatalogEntry(name, type, path, file);
589  mod_catalog.append(entry);
590  }
591 }
592 
593 void
595 {
596  if (catalog.size()) return;
597 
598  LoadCatalog("Ships/", "catalog.def");
599  LoadSkins("Mods/Skins/");
600 
601  List<Text> mod_designs;
602  DataLoader* loader = DataLoader::GetLoader();
603  loader->SetDataPath("Mods/Ships/");
604  loader->ListFiles("*.def", mod_designs, true);
605 
606  for (int i = 0; i < mod_designs.size(); i++) {
607  Text full_name = *mod_designs[i];
608  full_name.setSensitive(false);
609 
610  if (full_name.contains('/') && !full_name.contains("catalog")) {
611  char path[1024];
612  strcpy_s(path, full_name.data());
613 
614  char* name = path + full_name.length();
615  while (*name != '/')
616  name--;
617 
618  *name++ = 0;
619 
620  char* p = strrchr(name, '.');
621  if (p && strlen(p) > 3) {
622  if ((p[1] == 'd' || p[1] == 'D') &&
623  (p[2] == 'e' || p[2] == 'E') &&
624  (p[3] == 'f' || p[3] == 'F')) {
625 
626  *p = 0;
627  }
628  }
629 
630  // Just do a quick parse of the def file and add the
631  // info to the catalog. DON'T preload all of the models,
632  // textures, and weapons at this time. That takes way
633  // too long with some of the larger user mods.
634 
635  AddModCatalogEntry(name, path);
636  }
637  }
638 
639  mod_designs.destroy();
640  loader->SetDataPath(0);
641 }
642 
643 void
645 {
646  mod_catalog.destroy();
647  catalog.destroy();
648 }
649 
650 // +--------------------------------------------------------------------+
651 
652 int
653 ShipDesign::LoadCatalog(const char* path, const char* fname, bool mod)
654 {
655  int result = 0;
656 
657  // Load Design Catalog File:
658  DataLoader* loader = DataLoader::GetLoader();
659  loader->SetDataPath(path);
660 
661  char filename[NAMELEN];
662  ZeroMemory(filename, NAMELEN);
663  strncpy(filename, fname, NAMELEN-1);
664 
665  Print("Loading ship design catalog: %s%s\n", path, filename);
666 
667  BYTE* block;
668  int blocklen = loader->LoadBuffer(filename, block, true);
669  Parser parser(new(__FILE__,__LINE__) BlockReader((const char*) block, blocklen));
670  Term* term = parser.ParseTerm();
671 
672  if (!term) {
673  Print("ERROR: could not parse '%s'\n", filename);
674  loader->ReleaseBuffer(block);
675  loader->SetDataPath(0);
676  return result;
677  }
678  else {
679  TermText* file_type = term->isText();
680  if (!file_type || file_type->value() != "SHIPCATALOG") {
681  Print("ERROR: invalid ship catalog file '%s'\n", filename);
682  loader->ReleaseBuffer(block);
683  loader->SetDataPath(0);
684  return result;
685  }
686  }
687 
688  do {
689  delete term;
690 
691  term = parser.ParseTerm();
692 
693  Text name, type, fname, path;
694  bool hide = false;
695 
696  if (term) {
697  TermDef* def = term->isDef();
698  if (def && def->term() && def->term()->isStruct()) {
699  TermStruct* val = def->term()->isStruct();
700 
701  for (int i = 0; i < val->elements()->size(); i++) {
702  TermDef* pdef = val->elements()->at(i)->isDef();
703  if (pdef) {
704  Text defname = pdef->name()->value();
705  defname.setSensitive(false);
706 
707  if (defname == "name") {
708  if (!GetDefText(name, pdef, filename))
709  Print("WARNING: invalid or missing ship name in '%s'\n", filename);
710  }
711  else if (defname == "type") {
712  if (!GetDefText(type, pdef, filename))
713  Print("WARNING: invalid or missing ship type in '%s'\n", filename);
714  }
715  else if (defname == "path") {
716  if (!GetDefText(path, pdef, filename))
717  Print("WARNING: invalid or missing ship path in '%s'\n", filename);
718  }
719  else if (defname == "file") {
720  if (!GetDefText(fname, pdef, filename))
721  Print("WARNING: invalid or missing ship file in '%s'\n", filename);
722  }
723  else if (defname == "hide" || defname == "secret") {
724  GetDefBool(hide, pdef, filename);
725  }
726  }
727  }
728 
729  ShipCatalogEntry* entry = new(__FILE__,__LINE__) ShipCatalogEntry(name, type, path, fname, hide);
730 
731  if (mod) mod_catalog.append(entry);
732  else catalog.append(entry);
733 
734  result++;
735  }
736  else {
737  Print("WARNING: term ignored in '%s'\n", filename);
738  term->print();
739  }
740  }
741  }
742  while (term);
743 
744  loader->ReleaseBuffer(block);
745  loader->SetDataPath(0);
746 
747  return result;
748 }
749 
750 // +--------------------------------------------------------------------+
751 
752 void
753 ShipDesign::LoadSkins(const char* path, const char* archive)
754 {
755  // Load MOD Skin Files:
756  List<Text> list;
757  DataLoader* loader = DataLoader::GetLoader();
758  bool oldfs = loader->IsFileSystemEnabled();
759 
760  loader->UseFileSystem(true);
761  loader->SetDataPath(path);
762  loader->ListArchiveFiles(archive, "*.def", list);
763 
764  ListIter<Text> iter = list;
765  while (++iter) {
766  Text filename = *iter.value();
767  BYTE* block;
768  int blocklen = loader->LoadBuffer(filename, block, true);
769 
770  // file not found:
771  if (blocklen <= 4) {
772  continue;
773  }
774 
775  Parser parser(new(__FILE__,__LINE__) BlockReader((const char*) block, blocklen));
776  Term* term = parser.ParseTerm();
777  ShipDesign* design = 0;
778 
779  if (!term) {
780  Print("ERROR: could not parse '%s'\n", filename.data());
781  return;
782  }
783  else {
784  TermText* file_type = term->isText();
785  if (!file_type || file_type->value() != "SKIN") {
786  Print("ERROR: invalid skin file '%s'\n", filename.data());
787  return;
788  }
789  }
790 
791  do {
792  delete term;
793 
794  term = parser.ParseTerm();
795 
796  if (term) {
797  TermDef* def = term->isDef();
798  if (def) {
799  Text defname = def->name()->value();
800  defname.setSensitive(false);
801 
802  if (defname == "name") {
803  Text name;
804  GetDefText(name, def, filename);
805  design = Get(name);
806  }
807 
808  else if (defname == "skin" && design != 0) {
809  if (!def->term() || !def->term()->isStruct()) {
810  Print("WARNING: skin struct missing in '%s'\n", filename.data());
811  }
812  else {
813  TermStruct* val = def->term()->isStruct();
814  Skin* skin = design->ParseSkin(val);
815 
816  if (skin)
817  skin->SetPath(archive);
818  }
819  }
820  }
821  }
822  }
823  while (term);
824  }
825 
826  loader->UseFileSystem(oldfs);
827 }
828 
829 // +--------------------------------------------------------------------+
830 
831 int
833 {
834  return catalog.size();
835 }
836 
837 void
839 {
840  if (index >= 0 && index < catalog.size()) {
841  ShipCatalogEntry* entry = catalog[index];
842 
843  if (entry->hide)
844  return;
845 
846  int ship_class = ClassForName(entry->type);
847  if (ship_class > Ship::STARSHIPS)
848  return;
849 
850  if (!entry->path.contains("Alliance_"))
851  return;
852 
853  if (!entry->design) {
854  entry->design = new(__FILE__,__LINE__) ShipDesign(entry->name,
855  entry->path,
856  entry->file,
857  entry->hide);
858  }
859  }
860 
861  else {
862  ListIter<ShipCatalogEntry> iter = catalog;
863  while (++iter) {
864  ShipCatalogEntry* entry = iter.value();
865 
866  if (!entry->design) {
867  entry->design = new(__FILE__,__LINE__) ShipDesign(entry->name,
868  entry->path,
869  entry->file,
870  entry->hide);
871  }
872  }
873  }
874 }
875 
876 // +--------------------------------------------------------------------+
877 
878 bool
879 ShipDesign::CheckName(const char* design_name)
880 {
881  ShipCatalogEntry* entry = 0;
882 
883  for (int i = 0; i < catalog.size(); i++) {
884  if (catalog.at(i)->name == design_name) {
885  entry = catalog.at(i);
886  break;
887  }
888  }
889 
890  if (!entry) {
891  for (int i = 0; i < mod_catalog.size(); i++) {
892  if (mod_catalog.at(i)->name == design_name) {
893  entry = mod_catalog.at(i);
894  break;
895  }
896  }
897  }
898 
899  return entry != 0;
900 }
901 
902 // +--------------------------------------------------------------------+
903 
904 ShipDesign*
905 ShipDesign::Get(const char* design_name, const char* design_path)
906 {
907  if (!design_name || !*design_name)
908  return 0;
909 
910  ShipCatalogEntry* entry = 0;
911 
912  for (int i = 0; i < catalog.size(); i++) {
913  ShipCatalogEntry* e = catalog[i];
914  if (e->name == design_name) {
915  if (design_path && *design_path && e->path != design_path)
916  continue;
917  entry = e;
918  break;
919  }
920  }
921 
922  if (!entry) {
923  for (int i = 0; i < mod_catalog.size(); i++) {
924  ShipCatalogEntry* e = mod_catalog[i];
925  if (e->name == design_name) {
926  if (design_path && *design_path) {
927  Text full_path = "Mods/Ships/";
928  full_path += design_path;
929 
930  if (e->path != full_path)
931  continue;
932  }
933 
934  entry = e;
935  break;
936  }
937  }
938  }
939 
940  if (entry) {
941  if (!entry->design) {
942  entry->design = new(__FILE__,__LINE__) ShipDesign(entry->name,
943  entry->path,
944  entry->file,
945  entry->hide);
946  }
947  return entry->design;
948  }
949  else {
950  Print("ShipDesign: no catalog entry for design '%s', checking mods...\n", design_name);
951  return ShipDesign::FindModDesign(design_name, design_path);
952  }
953 }
954 
955 ShipDesign*
956 ShipDesign::FindModDesign(const char* design_name, const char* design_path)
957 {
958  Text file = Text(design_name) + ".def";
959  Text path = Text("Mods/Ships/");
960 
961  if (design_path && *design_path)
962  path += design_path;
963  else
964  path += design_name;
965 
966  DataLoader* loader = DataLoader::GetLoader();
967  loader->SetDataPath(path);
968 
969  ShipDesign* design = new(__FILE__,__LINE__) ShipDesign(design_name, path, file);
970 
971  if (design->valid) {
972  Print("ShipDesign: found mod design '%s'\n", design->name);
973 
974  ShipCatalogEntry* entry = new(__FILE__,__LINE__) ShipCatalogEntry(design->name,
975  ClassName(design->type),
976  path,
977  file);
978  mod_catalog.append(entry);
979  entry->design = design;
980  return entry->design;
981  }
982  else {
983  delete design;
984  }
985 
986  return 0;
987 }
988 
989 void
991 {
992  mod_catalog.destroy();
993 
994  for (int i = 0; i < catalog.size(); i++) {
995  ShipCatalogEntry* e = catalog[i];
996 
997  if (e && e->design) {
998  ListIter<Skin> iter = e->design->skins;
999 
1000  while (++iter) {
1001  Skin* skin = iter.value();
1002  if (*skin->Path())
1003  iter.removeItem();
1004  }
1005  }
1006  }
1007 }
1008 
1009 // +--------------------------------------------------------------------+
1010 
1011 int
1013 {
1014  designs.clear();
1015 
1016  for (int i = 0; i < catalog.size(); i++) {
1017  ShipCatalogEntry* e = catalog[i];
1018 
1019  int etype = ClassForName(e->type);
1020  if (etype & type) {
1021  if (!e->design)
1022  e->design = new(__FILE__,__LINE__) ShipDesign(e->name,
1023  e->path,
1024  e->file,
1025  e->hide);
1026 
1027  if (e->hide || !e->design || !e->design->valid || e->design->secret)
1028  continue;
1029 
1030  designs.append(&e->name);
1031  }
1032  }
1033 
1034  for (int i = 0; i < mod_catalog.size(); i++) {
1035  ShipCatalogEntry* e = mod_catalog[i];
1036 
1037  int etype = ClassForName(e->type);
1038  if (etype & type) {
1039  designs.append(&e->name);
1040  }
1041  }
1042 
1043  return designs.size();
1044 }
1045 
1046 // +--------------------------------------------------------------------+
1047 
1048 int
1049 ShipDesign::ClassForName(const char* name)
1050 {
1051  if (!name || !name[0])
1052  return 0;
1053 
1054  for (int i = 0; i < 32; i++) {
1055  if (!_stricmp(name, ship_design_class_name[i])) {
1056  return 1 << i;
1057  }
1058  }
1059 
1060  return 0;
1061 }
1062 
1063 const char*
1065 {
1066  if (type != 0) {
1067  int index = 0;
1068 
1069  while (!(type & 1)) {
1070  type >>= 1;
1071  index++;
1072  }
1073 
1074  if (index >= 0 && index < 32)
1075  return ship_design_class_name[index];
1076  }
1077 
1078  return "Unknown";
1079 }
1080 
1081 // +--------------------------------------------------------------------+
1082 
1083 void
1085 {
1086  char detail_name[NAMELEN];
1087  Vec3 off_loc;
1088  Vec3 spin;
1089  Text defname = def->name()->value();
1090 
1091  defname.setSensitive(false);
1092 
1093  if (defname == "cockpit_model") {
1094  if (!GetDefText(cockpit_name, def, filename))
1095  Print("WARNING: invalid or missing cockpit_model in '%s'\n", filename);
1096  }
1097 
1098  else if (defname == "model" || defname == "detail_0") {
1099  if (!GetDefText(detail_name, def, filename))
1100  Print("WARNING: invalid or missing model in '%s'\n", filename);
1101 
1102  detail[0].append(new(__FILE__,__LINE__) Text(detail_name));
1103  }
1104 
1105  else if (defname == "detail_1") {
1106  if (!GetDefText(detail_name, def, filename))
1107  Print("WARNING: invalid or missing detail_1 in '%s'\n", filename);
1108 
1109  detail[1].append(new(__FILE__,__LINE__) Text(detail_name));
1110  }
1111 
1112  else if (defname == "detail_2") {
1113  if (!GetDefText(detail_name, def, filename))
1114  Print("WARNING: invalid or missing detail_2 in '%s'\n", filename);
1115 
1116  detail[2].append(new(__FILE__,__LINE__) Text(detail_name));
1117  }
1118 
1119  else if (defname == "detail_3") {
1120  if (!GetDefText(detail_name, def, filename))
1121  Print("WARNING: invalid or missing detail_3 in '%s'\n", filename);
1122 
1123  detail[3].append(new(__FILE__,__LINE__) Text(detail_name));
1124  }
1125 
1126  else if (defname == "spin") {
1127  if (!GetDefVec(spin, def, filename))
1128  Print("WARNING: invalid or missing spin in '%s'\n", filename);
1129 
1130  spin_rates.append(new(__FILE__,__LINE__) Point(spin));
1131  }
1132 
1133  else if (defname == "offset_0") {
1134  if (!GetDefVec(off_loc, def, filename))
1135  Print("WARNING: invalid or missing offset_0 in '%s'\n", filename);
1136 
1137  offset[0].append(new(__FILE__,__LINE__) Point(off_loc));
1138  }
1139 
1140  else if (defname == "offset_1") {
1141  if (!GetDefVec(off_loc, def, filename))
1142  Print("WARNING: invalid or missing offset_1 in '%s'\n", filename);
1143 
1144  offset[1].append(new(__FILE__,__LINE__) Point(off_loc));
1145  }
1146 
1147  else if (defname == "offset_2") {
1148  if (!GetDefVec(off_loc, def, filename))
1149  Print("WARNING: invalid or missing offset_2 in '%s'\n", filename);
1150 
1151  offset[2].append(new(__FILE__,__LINE__) Point(off_loc));
1152  }
1153 
1154  else if (defname == "offset_3") {
1155  if (!GetDefVec(off_loc, def, filename))
1156  Print("WARNING: invalid or missing offset_3 in '%s'\n", filename);
1157 
1158  offset[3].append(new(__FILE__,__LINE__) Point(off_loc));
1159  }
1160 
1161  else if (defname == "beauty") {
1162  if (def->term() && def->term()->isArray()) {
1163  GetDefVec(beauty_cam, def, filename);
1164 
1165  if (degrees) {
1166  beauty_cam.x *= (float) DEGREES;
1167  beauty_cam.y *= (float) DEGREES;
1168  }
1169  }
1170 
1171  else {
1172  char beauty_name[64];
1173  if (!GetDefText(beauty_name, def, filename))
1174  Print("WARNING: invalid or missing beauty in '%s'\n", filename);
1175 
1176  DataLoader* loader = DataLoader::GetLoader();
1177  loader->LoadBitmap(beauty_name, beauty);
1178  }
1179  }
1180 
1181  else if (defname == "hud_icon") {
1182  char hud_icon_name[64];
1183  if (!GetDefText(hud_icon_name, def, filename))
1184  Print("WARNING: invalid or missing hud_icon in '%s'\n", filename);
1185 
1186  DataLoader* loader = DataLoader::GetLoader();
1187  loader->LoadBitmap(hud_icon_name, hud_icon);
1188  }
1189 
1190  else if (defname == "feature_0") {
1191  if (!GetDefNumber(feature_size[0], def, filename))
1192  Print("WARNING: invalid or missing feature_0 in '%s'\n", filename);
1193  }
1194 
1195  else if (defname == "feature_1") {
1196  if (!GetDefNumber(feature_size[1], def, filename))
1197  Print("WARNING: invalid or missing feature_1 in '%s'\n", filename);
1198  }
1199 
1200  else if (defname == "feature_2") {
1201  if (!GetDefNumber(feature_size[2], def, filename))
1202  Print("WARNING: invalid or missing feature_2 in '%s'\n", filename);
1203  }
1204 
1205  else if (defname == "feature_3") {
1206  if (!GetDefNumber(feature_size[3], def, filename))
1207  Print("WARNING: invalid or missing feature_3 in '%s'\n", filename);
1208  }
1209 
1210 
1211  else if (defname == "class") {
1212  char typestr[64];
1213  if (!GetDefText(typestr, def, filename))
1214  Print("WARNING: invalid or missing ship class in '%s'\n", filename);
1215 
1216  type = ClassForName(typestr);
1217 
1218  if (type <= Ship::LCA) {
1219  repair_auto = false;
1220  repair_screen = false;
1221  wep_screen = false;
1222  }
1223  }
1224 
1225  else GET_DEF_TEXT(name);
1226  else GET_DEF_TEXT(description);
1227  else GET_DEF_TEXT(display_name);
1228  else GET_DEF_TEXT(abrv);
1229  else GET_DEF_NUM(pcs);
1230  else GET_DEF_NUM(acs);
1231  else GET_DEF_NUM(detet);
1232  else GET_DEF_NUM(scale);
1234  else GET_DEF_NUM(mass);
1235  else GET_DEF_NUM(vlimit);
1236  else GET_DEF_NUM(agility);
1237  else GET_DEF_NUM(air_factor);
1238  else GET_DEF_NUM(roll_rate);
1239  else GET_DEF_NUM(pitch_rate);
1240  else GET_DEF_NUM(yaw_rate);
1241  else GET_DEF_NUM(integrity);
1242  else GET_DEF_NUM(drag);
1243  else GET_DEF_NUM(arcade_drag);
1244  else GET_DEF_NUM(roll_drag);
1245  else GET_DEF_NUM(pitch_drag);
1246  else GET_DEF_NUM(yaw_drag);
1247  else GET_DEF_NUM(trans_x);
1248  else GET_DEF_NUM(trans_y);
1249  else GET_DEF_NUM(trans_z);
1250  else GET_DEF_NUM(turn_bank);
1251  else GET_DEF_NUM(cockpit_scale);
1252  else GET_DEF_NUM(auto_roll);
1253 
1254  else GET_DEF_NUM(CL);
1255  else GET_DEF_NUM(CD);
1256  else GET_DEF_NUM(stall);
1257 
1258  else GET_DEF_NUM(prep_time);
1259  else GET_DEF_NUM(avoid_time);
1260  else GET_DEF_NUM(avoid_fighter);
1261  else GET_DEF_NUM(avoid_strike);
1262  else GET_DEF_NUM(avoid_target);
1263  else GET_DEF_NUM(commit_range);
1264 
1265  else GET_DEF_NUM(splash_radius);
1266  else GET_DEF_NUM(scuttle);
1267  else GET_DEF_NUM(repair_speed);
1268  else GET_DEF_NUM(repair_teams);
1269  else GET_DEF_BOOL(secret);
1270  else GET_DEF_BOOL(repair_auto);
1272  else GET_DEF_BOOL(wep_screen);
1273  else GET_DEF_BOOL(degrees);
1274 
1275  else if (defname == "emcon_1") {
1276  GetDefNumber(e_factor[0], def, filename);
1277  }
1278 
1279  else if (defname == "emcon_2") {
1280  GetDefNumber(e_factor[1], def, filename);
1281  }
1282 
1283  else if (defname == "emcon_3") {
1284  GetDefNumber(e_factor[2], def, filename);
1285  }
1286 
1287  else if (defname == "chase") {
1288  if (!GetDefVec(chase_vec, def, filename))
1289  Print("WARNING: invalid or missing chase cam loc in '%s'\n", filename);
1290 
1291  chase_vec *= (float) scale;
1292  }
1293 
1294  else if (defname == "bridge") {
1295  if (!GetDefVec(bridge_vec, def, filename))
1296  Print("WARNING: invalid or missing bridge cam loc in '%s'\n", filename);
1297 
1298  bridge_vec *= (float) scale;
1299  }
1300 
1301  else if (defname == "power") {
1302  if (!def->term() || !def->term()->isStruct()) {
1303  Print("WARNING: power source struct missing in '%s'\n", filename);
1304  }
1305  else {
1306  TermStruct* val = def->term()->isStruct();
1307  ParsePower(val);
1308  }
1309  }
1310 
1311  else if (defname == "main_drive" || defname == "drive") {
1312  if (!def->term() || !def->term()->isStruct()) {
1313  Print("WARNING: main drive struct missing in '%s'\n", filename);
1314  }
1315  else {
1316  TermStruct* val = def->term()->isStruct();
1317  ParseDrive(val);
1318  }
1319  }
1320 
1321  else if (defname == "quantum" || defname == "quantum_drive") {
1322  if (!def->term() || !def->term()->isStruct()) {
1323  Print("WARNING: quantum_drive struct missing in '%s'\n", filename);
1324  }
1325  else {
1326  TermStruct* val = def->term()->isStruct();
1327  ParseQuantumDrive(val);
1328  }
1329  }
1330 
1331  else if (defname == "sender" || defname == "farcaster") {
1332  if (!def->term() || !def->term()->isStruct()) {
1333  Print("WARNING: farcaster struct missing in '%s'\n", filename);
1334  }
1335  else {
1336  TermStruct* val = def->term()->isStruct();
1337  ParseFarcaster(val);
1338  }
1339  }
1340 
1341  else if (defname == "thruster") {
1342  if (!def->term() || !def->term()->isStruct()) {
1343  Print("WARNING: thruster struct missing in '%s'\n", filename);
1344  }
1345  else {
1346  TermStruct* val = def->term()->isStruct();
1347  ParseThruster(val);
1348  }
1349  }
1350 
1351  else if (defname == "navlight") {
1352  if (!def->term() || !def->term()->isStruct()) {
1353  Print("WARNING: navlight struct missing in '%s'\n", filename);
1354  }
1355  else {
1356  TermStruct* val = def->term()->isStruct();
1357  ParseNavlight(val);
1358  }
1359  }
1360 
1361  else if (defname == "flightdeck") {
1362  if (!def->term() || !def->term()->isStruct()) {
1363  Print("WARNING: flightdeck struct missing in '%s'\n", filename);
1364  }
1365  else {
1366  TermStruct* val = def->term()->isStruct();
1367  ParseFlightDeck(val);
1368  }
1369  }
1370 
1371  else if (defname == "gear") {
1372  if (!def->term() || !def->term()->isStruct()) {
1373  Print("WARNING: gear struct missing in '%s'\n", filename);
1374  }
1375  else {
1376  TermStruct* val = def->term()->isStruct();
1377  ParseLandingGear(val);
1378  }
1379  }
1380 
1381  else if (defname == "weapon") {
1382  if (!def->term() || !def->term()->isStruct()) {
1383  Print("WARNING: weapon struct missing in '%s'\n", filename);
1384  }
1385  else {
1386  TermStruct* val = def->term()->isStruct();
1387  ParseWeapon(val);
1388  }
1389  }
1390 
1391  else if (defname == "hardpoint") {
1392  if (!def->term() || !def->term()->isStruct()) {
1393  Print("WARNING: hardpoint struct missing in '%s'\n", filename);
1394  }
1395  else {
1396  TermStruct* val = def->term()->isStruct();
1397  ParseHardPoint(val);
1398  }
1399  }
1400 
1401  else if (defname == "loadout") {
1402  if (!def->term() || !def->term()->isStruct()) {
1403  Print("WARNING: loadout struct missing in '%s'\n", filename);
1404  }
1405  else {
1406  TermStruct* val = def->term()->isStruct();
1407  ParseLoadout(val);
1408  }
1409  }
1410 
1411  else if (defname == "decoy") {
1412  if (!def->term() || !def->term()->isStruct()) {
1413  Print("WARNING: decoy struct missing in '%s'\n", filename);
1414  }
1415  else {
1416  TermStruct* val = def->term()->isStruct();
1417  ParseWeapon(val);
1418  }
1419  }
1420 
1421  else if (defname == "probe") {
1422  if (!def->term() || !def->term()->isStruct()) {
1423  Print("WARNING: probe struct missing in '%s'\n", filename);
1424  }
1425  else {
1426  TermStruct* val = def->term()->isStruct();
1427  ParseWeapon(val);
1428  }
1429  }
1430 
1431  else if (defname == "sensor") {
1432  if (!def->term() || !def->term()->isStruct()) {
1433  Print("WARNING: sensor struct missing in '%s'\n", filename);
1434  }
1435  else {
1436  TermStruct* val = def->term()->isStruct();
1437  ParseSensor(val);
1438  }
1439  }
1440 
1441  else if (defname == "nav") {
1442  if (!def->term() || !def->term()->isStruct()) {
1443  Print("WARNING: nav struct missing in '%s'\n", filename);
1444  }
1445  else {
1446  TermStruct* val = def->term()->isStruct();
1447  ParseNavsys(val);
1448  }
1449  }
1450 
1451  else if (defname == "computer") {
1452  if (!def->term() || !def->term()->isStruct()) {
1453  Print("WARNING: computer struct missing in '%s'\n", filename);
1454  }
1455  else {
1456  TermStruct* val = def->term()->isStruct();
1457  ParseComputer(val);
1458  }
1459  }
1460 
1461  else if (defname == "shield") {
1462  if (!def->term() || !def->term()->isStruct()) {
1463  Print("WARNING: shield struct missing in '%s'\n", filename);
1464  }
1465  else {
1466  TermStruct* val = def->term()->isStruct();
1467  ParseShield(val);
1468  }
1469  }
1470 
1471  else if (defname == "death_spiral") {
1472  if (!def->term() || !def->term()->isStruct()) {
1473  Print("WARNING: death spiral struct missing in '%s'\n", filename);
1474  }
1475  else {
1476  TermStruct* val = def->term()->isStruct();
1477  ParseDeathSpiral(val);
1478  }
1479  }
1480 
1481  else if (defname == "map") {
1482  if (!def->term() || !def->term()->isStruct()) {
1483  Print("WARNING: map struct missing in '%s'\n", filename);
1484  }
1485  else {
1486  TermStruct* val = def->term()->isStruct();
1487  ParseMap(val);
1488  }
1489  }
1490 
1491  else if (defname == "squadron") {
1492  if (!def->term() || !def->term()->isStruct()) {
1493  Print("WARNING: squadron struct missing in '%s'\n", filename);
1494  }
1495  else {
1496  TermStruct* val = def->term()->isStruct();
1497  ParseSquadron(val);
1498  }
1499  }
1500 
1501  else if (defname == "skin") {
1502  if (!def->term() || !def->term()->isStruct()) {
1503  Print("WARNING: skin struct missing in '%s'\n", filename);
1504  }
1505  else {
1506  TermStruct* val = def->term()->isStruct();
1507  ParseSkin(val);
1508  }
1509  }
1510 
1511  else {
1512  Print("WARNING: unknown parameter '%s' in '%s'\n",
1513  defname.data(), filename);
1514  }
1515 
1516  if (description.length())
1518 }
1519 
1520 // +--------------------------------------------------------------------+
1521 
1522 void
1524 {
1525  int stype = 0;
1526  float output = 1000.0f;
1527  float fuel = 0.0f;
1528  Vec3 loc(0.0f, 0.0f, 0.0f);
1529  float size = 0.0f;
1530  float hull = 0.5f;
1531  Text design_name;
1532  Text pname;
1533  Text pabrv;
1534  int etype = 0;
1535  int emcon_1 = -1;
1536  int emcon_2 = -1;
1537  int emcon_3 = -1;
1538 
1539  for (int i = 0; i < val->elements()->size(); i++) {
1540  TermDef* pdef = val->elements()->at(i)->isDef();
1541  if (pdef) {
1542  Text defname = pdef->name()->value();
1543  defname.setSensitive(false);
1544 
1545  if (defname == "type") {
1546  TermText* tname = pdef->term()->isText();
1547 
1548  if (tname) {
1549  if (tname->value()[0] == 'B') stype = PowerSource::BATTERY;
1550  else if (tname->value()[0] == 'A') stype = PowerSource::AUX;
1551  else if (tname->value()[0] == 'F') stype = PowerSource::FUSION;
1552  else Print("WARNING: unknown power source type '%s' in '%s'\n", tname->value().data(), filename);
1553  }
1554  }
1555 
1556  else if (defname == "name") {
1557  GetDefText(pname, pdef, filename);
1558  }
1559 
1560  else if (defname == "abrv") {
1561  GetDefText(pabrv, pdef, filename);
1562  }
1563 
1564  else if (defname == "design") {
1565  GetDefText(design_name, pdef, filename);
1566  }
1567 
1568  else if (defname == "max_output") {
1569  GetDefNumber(output, pdef, filename);
1570  }
1571  else if (defname == "fuel_range") {
1572  GetDefNumber(fuel, pdef, filename);
1573  }
1574 
1575  else if (defname == "loc") {
1576  GetDefVec(loc, pdef, filename);
1577  loc *= (float) scale;
1578  }
1579  else if (defname == "size") {
1580  GetDefNumber(size, pdef, filename);
1581  size *= (float) scale;
1582  }
1583  else if (defname == "hull_factor") {
1584  GetDefNumber(hull, pdef, filename);
1585  }
1586 
1587  else if (defname == "explosion") {
1588  GetDefNumber(etype, pdef, filename);
1589  }
1590 
1591  else if (defname == "emcon_1") {
1592  GetDefNumber(emcon_1, pdef, filename);
1593  }
1594 
1595  else if (defname == "emcon_2") {
1596  GetDefNumber(emcon_2, pdef, filename);
1597  }
1598 
1599  else if (defname == "emcon_3") {
1600  GetDefNumber(emcon_3, pdef, filename);
1601  }
1602  }
1603  }
1604 
1605  PowerSource* source = new(__FILE__,__LINE__) PowerSource((PowerSource::SUBTYPE) stype, output);
1606  if (pname.length()) source->SetName(pname);
1607  if (pabrv.length()) source->SetName(pabrv);
1608  source->SetFuelRange(fuel);
1609  source->Mount(loc, size, hull);
1610  source->SetExplosionType(etype);
1611 
1612  if (design_name.length()) {
1613  SystemDesign* sd = SystemDesign::Find(design_name);
1614  if (sd)
1615  source->SetDesign(sd);
1616  }
1617 
1618  if (emcon_1 >= 0 && emcon_1 <= 100)
1619  source->SetEMCONPower(1, emcon_1);
1620 
1621  if (emcon_2 >= 0 && emcon_2 <= 100)
1622  source->SetEMCONPower(1, emcon_2);
1623 
1624  if (emcon_3 >= 0 && emcon_3 <= 100)
1625  source->SetEMCONPower(1, emcon_3);
1626 
1627  reactors.append(source);
1628 }
1629 
1630 // +--------------------------------------------------------------------+
1631 
1632 void
1634 {
1635  Text dname;
1636  Text dabrv;
1637  int dtype = 0;
1638  int etype = 0;
1639  float dthrust = 1.0f;
1640  float daug = 0.0f;
1641  float dscale = 1.0f;
1642  Vec3 loc(0.0f, 0.0f, 0.0f);
1643  float size = 0.0f;
1644  float hull = 0.5f;
1645  Text design_name;
1646  int emcon_1 = -1;
1647  int emcon_2 = -1;
1648  int emcon_3 = -1;
1649  bool trail = true;
1650  Drive* drive = 0;
1651 
1652  for (int i = 0; i < val->elements()->size(); i++) {
1653  TermDef* pdef = val->elements()->at(i)->isDef();
1654  if (pdef) {
1655  Text defname = pdef->name()->value();
1656  defname.setSensitive(false);
1657 
1658  if (defname == "type") {
1659  TermText* tname = pdef->term()->isText();
1660 
1661  if (tname) {
1662  Text tval = tname->value();
1663  tval.setSensitive(false);
1664 
1665  if (tval == "Plasma") dtype = Drive::PLASMA;
1666  else if (tval == "Fusion") dtype = Drive::FUSION;
1667  else if (tval == "Alien") dtype = Drive::GREEN;
1668  else if (tval == "Green") dtype = Drive::GREEN;
1669  else if (tval == "Red") dtype = Drive::RED;
1670  else if (tval == "Blue") dtype = Drive::BLUE;
1671  else if (tval == "Yellow") dtype = Drive::YELLOW;
1672  else if (tval == "Stealth") dtype = Drive::STEALTH;
1673 
1674  else Print("WARNING: unknown drive type '%s' in '%s'\n", tname->value().data(), filename);
1675  }
1676  }
1677  else if (defname == "name") {
1678  if (!GetDefText(dname, pdef, filename))
1679  Print("WARNING: invalid or missing name for drive in '%s'\n", filename);
1680  }
1681 
1682  else if (defname == "abrv") {
1683  if (!GetDefText(dabrv, pdef, filename))
1684  Print("WARNING: invalid or missing abrv for drive in '%s'\n", filename);
1685  }
1686 
1687  else if (defname == "design") {
1688  if (!GetDefText(design_name, pdef, filename))
1689  Print("WARNING: invalid or missing design for drive in '%s'\n", filename);
1690  }
1691 
1692  else if (defname == "thrust") {
1693  if (!GetDefNumber(dthrust, pdef, filename))
1694  Print("WARNING: invalid or missing thrust for drive in '%s'\n", filename);
1695  }
1696 
1697  else if (defname == "augmenter") {
1698  if (!GetDefNumber(daug, pdef, filename))
1699  Print("WARNING: invalid or missing augmenter for drive in '%s'\n", filename);
1700  }
1701 
1702  else if (defname == "scale") {
1703  if (!GetDefNumber(dscale, pdef, filename))
1704  Print("WARNING: invalid or missing scale for drive in '%s'\n", filename);
1705  }
1706 
1707  else if (defname == "port") {
1708  Vec3 port;
1709  float flare_scale = 0;
1710 
1711  if (pdef->term()->isArray()) {
1712  GetDefVec(port, pdef, filename);
1713  port *= scale;
1714  flare_scale = dscale;
1715  }
1716 
1717  else if (pdef->term()->isStruct()) {
1718  TermStruct* val = pdef->term()->isStruct();
1719 
1720  for (int i = 0; i < val->elements()->size(); i++) {
1721  TermDef* pdef2 = val->elements()->at(i)->isDef();
1722  if (pdef2) {
1723  if (pdef2->name()->value() == "loc") {
1724  GetDefVec(port, pdef2, filename);
1725  port *= scale;
1726  }
1727 
1728  else if (pdef2->name()->value() == "scale") {
1729  GetDefNumber(flare_scale, pdef2, filename);
1730  }
1731  }
1732  }
1733 
1734  if (flare_scale <= 0)
1735  flare_scale = dscale;
1736  }
1737 
1738  if (!drive)
1739  drive = new(__FILE__,__LINE__) Drive((Drive::SUBTYPE) dtype, dthrust, daug, trail);
1740 
1741  drive->AddPort(port, flare_scale);
1742  }
1743 
1744  else if (defname == "loc") {
1745  if (!GetDefVec(loc, pdef, filename))
1746  Print("WARNING: invalid or missing loc for drive in '%s'\n", filename);
1747  loc *= (float) scale;
1748  }
1749 
1750  else if (defname == "size") {
1751  if (!GetDefNumber(size, pdef, filename))
1752  Print("WARNING: invalid or missing size for drive in '%s'\n", filename);
1753  size *= (float) scale;
1754  }
1755 
1756  else if (defname == "hull_factor") {
1757  if (!GetDefNumber(hull, pdef, filename))
1758  Print("WARNING: invalid or missing hull_factor for drive in '%s'\n", filename);
1759  }
1760 
1761  else if (defname == "explosion") {
1762  if (!GetDefNumber(etype, pdef, filename))
1763  Print("WARNING: invalid or missing explosion for drive in '%s'\n", filename);
1764  }
1765 
1766  else if (defname == "emcon_1") {
1767  GetDefNumber(emcon_1, pdef, filename);
1768  }
1769 
1770  else if (defname == "emcon_2") {
1771  GetDefNumber(emcon_2, pdef, filename);
1772  }
1773 
1774  else if (defname == "emcon_3") {
1775  GetDefNumber(emcon_3, pdef, filename);
1776  }
1777 
1778  else if (defname == "trail" || defname == "show_trail") {
1779  GetDefBool(trail, pdef, filename);
1780  }
1781  }
1782  }
1783 
1784  if (!drive)
1785  drive = new(__FILE__,__LINE__) Drive((Drive::SUBTYPE) dtype, dthrust, daug, trail);
1786 
1787  drive->SetSourceIndex(reactors.size()-1);
1788  drive->Mount(loc, size, hull);
1789  if (dname.length()) drive->SetName(dname);
1790  if (dabrv.length()) drive->SetAbbreviation(dabrv);
1791  drive->SetExplosionType(etype);
1792 
1793  if (design_name.length()) {
1794  SystemDesign* sd = SystemDesign::Find(design_name);
1795  if (sd)
1796  drive->SetDesign(sd);
1797  }
1798 
1799  if (emcon_1 >= 0 && emcon_1 <= 100)
1800  drive->SetEMCONPower(1, emcon_1);
1801 
1802  if (emcon_2 >= 0 && emcon_2 <= 100)
1803  drive->SetEMCONPower(1, emcon_2);
1804 
1805  if (emcon_3 >= 0 && emcon_3 <= 100)
1806  drive->SetEMCONPower(1, emcon_3);
1807 
1808  main_drive = drives.size();
1809  drives.append(drive);
1810 }
1811 
1812 // +--------------------------------------------------------------------+
1813 
1814 void
1816 {
1817  double capacity = 250e3;
1818  double consumption = 1e3;
1819  Vec3 loc(0.0f, 0.0f, 0.0f);
1820  float size = 0.0f;
1821  float hull = 0.5f;
1822  float countdown = 5.0f;
1823  Text design_name;
1824  Text type_name;
1825  Text abrv;
1826  int subtype = QuantumDrive::QUANTUM;
1827  int emcon_1 = -1;
1828  int emcon_2 = -1;
1829  int emcon_3 = -1;
1830 
1831  for (int i = 0; i < val->elements()->size(); i++) {
1832  TermDef* pdef = val->elements()->at(i)->isDef();
1833  if (pdef) {
1834  Text defname = pdef->name()->value();
1835  defname.setSensitive(false);
1836 
1837  if (defname == "design") {
1838  GetDefText(design_name, pdef, filename);
1839  }
1840  else if (defname == "abrv") {
1841  GetDefText(abrv, pdef, filename);
1842  }
1843  else if (defname == "type") {
1844  GetDefText(type_name, pdef, filename);
1845  type_name.setSensitive(false);
1846 
1847  if (type_name.contains("hyper")) {
1848  subtype = QuantumDrive::HYPER;
1849  }
1850  }
1851  else if (defname == "capacity") {
1852  GetDefNumber(capacity, pdef, filename);
1853  }
1854  else if (defname == "consumption") {
1855  GetDefNumber(consumption, pdef, filename);
1856  }
1857  else if (defname == "loc") {
1858  GetDefVec(loc, pdef, filename);
1859  loc *= (float) scale;
1860  }
1861  else if (defname == "size") {
1862  GetDefNumber(size, pdef, filename);
1863  size *= (float) scale;
1864  }
1865  else if (defname == "hull_factor") {
1866  GetDefNumber(hull, pdef, filename);
1867  }
1868  else if (defname == "jump_time") {
1869  GetDefNumber(countdown, pdef, filename);
1870  }
1871  else if (defname == "countdown") {
1872  GetDefNumber(countdown, pdef, filename);
1873  }
1874 
1875  else if (defname == "emcon_1") {
1876  GetDefNumber(emcon_1, pdef, filename);
1877  }
1878 
1879  else if (defname == "emcon_2") {
1880  GetDefNumber(emcon_2, pdef, filename);
1881  }
1882 
1883  else if (defname == "emcon_3") {
1884  GetDefNumber(emcon_3, pdef, filename);
1885  }
1886  }
1887  }
1888 
1889  QuantumDrive* drive = new(__FILE__,__LINE__) QuantumDrive((QuantumDrive::SUBTYPE) subtype, capacity, consumption);
1890  drive->SetSourceIndex(reactors.size()-1);
1891  drive->Mount(loc, size, hull);
1892  drive->SetCountdown(countdown);
1893 
1894  if (design_name.length()) {
1895  SystemDesign* sd = SystemDesign::Find(design_name);
1896  if (sd)
1897  drive->SetDesign(sd);
1898  }
1899 
1900  if (abrv.length())
1901  drive->SetAbbreviation(abrv);
1902 
1903  if (emcon_1 >= 0 && emcon_1 <= 100)
1904  drive->SetEMCONPower(1, emcon_1);
1905 
1906  if (emcon_2 >= 0 && emcon_2 <= 100)
1907  drive->SetEMCONPower(1, emcon_2);
1908 
1909  if (emcon_3 >= 0 && emcon_3 <= 100)
1910  drive->SetEMCONPower(1, emcon_3);
1911 
1912  quantum_drive = drive;
1913 }
1914 
1915 // +--------------------------------------------------------------------+
1916 
1917 void
1919 {
1920  Text design_name;
1921  double capacity = 300e3;
1922  double consumption = 15e3; // twenty second recharge
1923  int napproach = 0;
1925  Vec3 loc(0.0f, 0.0f, 0.0f);
1926  Vec3 start(0.0f, 0.0f, 0.0f);
1927  Vec3 end(0.0f, 0.0f, 0.0f);
1928  float size = 0.0f;
1929  float hull = 0.5f;
1930  int emcon_1 = -1;
1931  int emcon_2 = -1;
1932  int emcon_3 = -1;
1933 
1934  for (int i = 0; i < val->elements()->size(); i++) {
1935  TermDef* pdef = val->elements()->at(i)->isDef();
1936  if (pdef) {
1937  Text defname = pdef->name()->value();
1938  defname.setSensitive(false);
1939 
1940  if (defname == "design") {
1941  GetDefText(design_name, pdef, filename);
1942  }
1943  else if (defname == "capacity") {
1944  GetDefNumber(capacity, pdef, filename);
1945  }
1946  else if (defname == "consumption") {
1947  GetDefNumber(consumption, pdef, filename);
1948  }
1949  else if (defname == "loc") {
1950  GetDefVec(loc, pdef, filename);
1951  loc *= (float) scale;
1952  }
1953  else if (defname == "size") {
1954  GetDefNumber(size, pdef, filename);
1955  size *= (float) scale;
1956  }
1957  else if (defname == "hull_factor") {
1958  GetDefNumber(hull, pdef, filename);
1959  }
1960 
1961  else if (defname == "start") {
1962  GetDefVec(start, pdef, filename);
1963  start *= (float) scale;
1964  }
1965  else if (defname == "end") {
1966  GetDefVec(end, pdef, filename);
1967  end *= (float) scale;
1968  }
1969  else if (defname == "approach") {
1970  if (napproach < Farcaster::NUM_APPROACH_PTS) {
1971  GetDefVec(approach[napproach], pdef, filename);
1972  approach[napproach++] *= (float) scale;
1973  }
1974  else {
1975  Print("WARNING: farcaster approach point ignored in '%s' (max=%d)\n",
1977  }
1978  }
1979 
1980  else if (defname == "emcon_1") {
1981  GetDefNumber(emcon_1, pdef, filename);
1982  }
1983 
1984  else if (defname == "emcon_2") {
1985  GetDefNumber(emcon_2, pdef, filename);
1986  }
1987 
1988  else if (defname == "emcon_3") {
1989  GetDefNumber(emcon_3, pdef, filename);
1990  }
1991  }
1992  }
1993 
1994  Farcaster* caster = new(__FILE__,__LINE__) Farcaster(capacity, consumption);
1995  caster->SetSourceIndex(reactors.size()-1);
1996  caster->Mount(loc, size, hull);
1997 
1998  if (design_name.length()) {
1999  SystemDesign* sd = SystemDesign::Find(design_name);
2000  if (sd)
2001  caster->SetDesign(sd);
2002  }
2003 
2004  caster->SetStartPoint(start);
2005  caster->SetEndPoint(end);
2006 
2007  for (int i = 0; i < napproach; i++)
2008  caster->SetApproachPoint(i, approach[i]);
2009 
2010  if (emcon_1 >= 0 && emcon_1 <= 100)
2011  caster->SetEMCONPower(1, emcon_1);
2012 
2013  if (emcon_2 >= 0 && emcon_2 <= 100)
2014  caster->SetEMCONPower(1, emcon_2);
2015 
2016  if (emcon_3 >= 0 && emcon_3 <= 100)
2017  caster->SetEMCONPower(1, emcon_3);
2018 
2019  farcaster = caster;
2020 }
2021 
2022 // +--------------------------------------------------------------------+
2023 
2024 void
2026 {
2027  if (thruster) {
2028  Print("WARNING: additional thruster ignored in '%s'\n", filename);
2029  return;
2030  }
2031 
2032  double thrust = 100;
2033 
2034  Vec3 loc(0.0f, 0.0f, 0.0f);
2035  float size = 0.0f;
2036  float hull = 0.5f;
2037  Text design_name;
2038  float tscale = 1.0f;
2039  int emcon_1 = -1;
2040  int emcon_2 = -1;
2041  int emcon_3 = -1;
2042  int dtype = 0;
2043 
2044  Thruster* drive = 0;
2045 
2046  for (int i = 0; i < val->elements()->size(); i++) {
2047  TermDef* pdef = val->elements()->at(i)->isDef();
2048  if (pdef) {
2049  Text defname = pdef->name()->value();
2050  defname.setSensitive(false);
2051 
2052 
2053  if (defname == "type") {
2054  TermText* tname = pdef->term()->isText();
2055 
2056  if (tname) {
2057  Text tval = tname->value();
2058  tval.setSensitive(false);
2059 
2060  if (tval == "Plasma") dtype = Drive::PLASMA;
2061  else if (tval == "Fusion") dtype = Drive::FUSION;
2062  else if (tval == "Alien") dtype = Drive::GREEN;
2063  else if (tval == "Green") dtype = Drive::GREEN;
2064  else if (tval == "Red") dtype = Drive::RED;
2065  else if (tval == "Blue") dtype = Drive::BLUE;
2066  else if (tval == "Yellow") dtype = Drive::YELLOW;
2067  else if (tval == "Stealth") dtype = Drive::STEALTH;
2068 
2069  else Print("WARNING: unknown thruster type '%s' in '%s'\n", tname->value().data(), filename);
2070  }
2071  }
2072 
2073  else if (defname == "thrust") {
2074  GetDefNumber(thrust, pdef, filename);
2075  }
2076 
2077  else if (defname == "design") {
2078  GetDefText(design_name, pdef, filename);
2079  }
2080 
2081  else if (defname == "loc") {
2082  GetDefVec(loc, pdef, filename);
2083  loc *= (float) scale;
2084  }
2085  else if (defname == "size") {
2086  GetDefNumber(size, pdef, filename);
2087  size *= (float) scale;
2088  }
2089  else if (defname == "hull_factor") {
2090  GetDefNumber(hull, pdef, filename);
2091  }
2092  else if (defname == "scale") {
2093  GetDefNumber(tscale, pdef, filename);
2094  }
2095  else if (defname.contains("port") && pdef->term()) {
2096  Vec3 port;
2097  float port_scale = 0;
2098  DWORD fire = 0;
2099 
2100  if (pdef->term()->isArray()) {
2101  GetDefVec(port, pdef, filename);
2102  port *= scale;
2103  port_scale = tscale;
2104  }
2105 
2106  else if (pdef->term()->isStruct()) {
2107  TermStruct* val = pdef->term()->isStruct();
2108 
2109  for (int i = 0; i < val->elements()->size(); i++) {
2110  TermDef* pdef2 = val->elements()->at(i)->isDef();
2111  if (pdef2) {
2112  if (pdef2->name()->value() == "loc") {
2113  GetDefVec(port, pdef2, filename);
2114  port *= scale;
2115  }
2116 
2117  else if (pdef2->name()->value() == "fire") {
2118  GetDefNumber(fire, pdef2, filename);
2119  }
2120 
2121  else if (pdef2->name()->value() == "scale") {
2122  GetDefNumber(port_scale, pdef2, filename);
2123  }
2124  }
2125  }
2126 
2127  if (port_scale <= 0)
2128  port_scale = tscale;
2129  }
2130 
2131  if (!drive)
2132  drive = new(__FILE__,__LINE__) Thruster(dtype, thrust, tscale);
2133 
2134  if (defname == "port" || defname == "port_bottom")
2135  drive->AddPort(Thruster::BOTTOM, port, fire, port_scale);
2136 
2137  else if (defname == "port_top")
2138  drive->AddPort(Thruster::TOP, port, fire, port_scale);
2139 
2140  else if (defname == "port_left")
2141  drive->AddPort(Thruster::LEFT, port, fire, port_scale);
2142 
2143  else if (defname == "port_right")
2144  drive->AddPort(Thruster::RIGHT, port, fire, port_scale);
2145 
2146  else if (defname == "port_fore")
2147  drive->AddPort(Thruster::FORE, port, fire, port_scale);
2148 
2149  else if (defname == "port_aft")
2150  drive->AddPort(Thruster::AFT, port, fire, port_scale);
2151  }
2152 
2153  else if (defname == "emcon_1") {
2154  GetDefNumber(emcon_1, pdef, filename);
2155  }
2156 
2157  else if (defname == "emcon_2") {
2158  GetDefNumber(emcon_2, pdef, filename);
2159  }
2160 
2161  else if (defname == "emcon_3") {
2162  GetDefNumber(emcon_3, pdef, filename);
2163  }
2164  }
2165  }
2166 
2167  if (!drive)
2168  drive = new(__FILE__,__LINE__) Thruster(dtype, thrust, tscale);
2169  drive->SetSourceIndex(reactors.size()-1);
2170  drive->Mount(loc, size, hull);
2171 
2172  if (design_name.length()) {
2173  SystemDesign* sd = SystemDesign::Find(design_name);
2174  if (sd)
2175  drive->SetDesign(sd);
2176  }
2177 
2178  if (emcon_1 >= 0 && emcon_1 <= 100)
2179  drive->SetEMCONPower(1, emcon_1);
2180 
2181  if (emcon_2 >= 0 && emcon_2 <= 100)
2182  drive->SetEMCONPower(1, emcon_2);
2183 
2184  if (emcon_3 >= 0 && emcon_3 <= 100)
2185  drive->SetEMCONPower(1, emcon_3);
2186 
2187  thruster = drive;
2188 }
2189 
2190 // +--------------------------------------------------------------------+
2191 
2192 void
2194 {
2195  Text dname;
2196  Text dabrv;
2197  Text design_name;
2198  int nlights = 0;
2199  float dscale = 1.0f;
2200  float period = 10.0f;
2201  Vec3 bloc[NavLight::MAX_LIGHTS];
2202  int btype[NavLight::MAX_LIGHTS];
2203  DWORD pattern[NavLight::MAX_LIGHTS];
2204 
2205  for (int i = 0; i < val->elements()->size(); i++) {
2206  TermDef* pdef = val->elements()->at(i)->isDef();
2207  if (pdef) {
2208  Text defname = pdef->name()->value();
2209  defname.setSensitive(false);
2210 
2211  if (defname == "name")
2212  GetDefText(dname, pdef, filename);
2213  else if (defname == "abrv")
2214  GetDefText(dabrv, pdef, filename);
2215 
2216  else if (defname == "design") {
2217  GetDefText(design_name, pdef, filename);
2218  }
2219 
2220  else if (defname == "scale") {
2221  GetDefNumber(dscale, pdef, filename);
2222  }
2223  else if (defname == "period") {
2224  GetDefNumber(period, pdef, filename);
2225  }
2226  else if (defname == "light") {
2227  if (!pdef->term() || !pdef->term()->isStruct()) {
2228  Print("WARNING: light struct missing for ship '%s' in '%s'\n", name, filename);
2229  }
2230  else {
2231  TermStruct* val = pdef->term()->isStruct();
2232 
2233  Vec3 loc;
2234  int t = 0;
2235  DWORD ptn = 0;
2236 
2237  for (int i = 0; i < val->elements()->size(); i++) {
2238  TermDef* pdef = val->elements()->at(i)->isDef();
2239  if (pdef) {
2240  Text defname = pdef->name()->value();
2241  defname.setSensitive(false);
2242 
2243  if (defname == "type") {
2244  GetDefNumber(t, pdef, filename);
2245  }
2246  else if (defname == "loc") {
2247  GetDefVec(loc, pdef, filename);
2248  }
2249  else if (defname == "pattern") {
2250  GetDefNumber(ptn, pdef, filename);
2251  }
2252  }
2253  }
2254 
2255  if (t < 1 || t > 4)
2256  t = 1;
2257 
2258  if (nlights < NavLight::MAX_LIGHTS) {
2259  bloc[nlights] = loc * scale;
2260  btype[nlights] = t-1;
2261  pattern[nlights] = ptn;
2262  nlights++;
2263  }
2264  else {
2265  Print("WARNING: Too many lights ship '%s' in '%s'\n", name, filename);
2266  }
2267  }
2268  }
2269  }
2270  }
2271 
2272  NavLight* nav = new(__FILE__,__LINE__) NavLight(period, dscale);
2273  if (dname.length()) nav->SetName(dname);
2274  if (dabrv.length()) nav->SetAbbreviation(dabrv);
2275 
2276  if (design_name.length()) {
2277  SystemDesign* sd = SystemDesign::Find(design_name);
2278  if (sd)
2279  nav->SetDesign(sd);
2280  }
2281 
2282  for (int i = 0; i < nlights; i++)
2283  nav->AddBeacon(bloc[i], pattern[i], btype[i]);
2284 
2285  navlights.append(nav);
2286 }
2287 
2288 // +--------------------------------------------------------------------+
2289 
2290 void
2292 {
2293  Text dname;
2294  Text dabrv;
2295  Text design_name;
2296  float dscale = 1.0f;
2297  float az = 0.0f;
2298  int etype = 0;
2299 
2300  bool launch = false;
2301  bool recovery = false;
2302  int nslots = 0;
2303  int napproach = 0;
2304  int nrunway = 0;
2305  DWORD filters[10];
2306  Vec3 spots[10];
2308  Vec3 runway[2];
2309  Vec3 loc(0,0,0);
2310  Vec3 start(0,0,0);
2311  Vec3 end(0,0,0);
2312  Vec3 cam(0,0,0);
2313  Vec3 box(0,0,0);
2314  float cycle_time = 0.0f;
2315  float size = 0.0f;
2316  float hull = 0.5f;
2317 
2318  float light = 0.0f;
2319 
2320  for (int i = 0; i < val->elements()->size(); i++) {
2321  TermDef* pdef = val->elements()->at(i)->isDef();
2322  if (pdef) {
2323  Text defname = pdef->name()->value();
2324  defname.setSensitive(false);
2325 
2326  if (defname == "name")
2327  GetDefText(dname, pdef, filename);
2328  else if (defname == "abrv")
2329  GetDefText(dabrv, pdef, filename);
2330  else if (defname == "design")
2331  GetDefText(design_name, pdef, filename);
2332 
2333  else if (defname == "start") {
2334  GetDefVec(start, pdef, filename);
2335  start *= (float) scale;
2336  }
2337  else if (defname == "end") {
2338  GetDefVec(end, pdef, filename);
2339  end *= (float) scale;
2340  }
2341  else if (defname == "cam") {
2342  GetDefVec(cam, pdef, filename);
2343  cam *= (float) scale;
2344  }
2345  else if (defname == "box" || defname == "bounding_box") {
2346  GetDefVec(box, pdef, filename);
2347  box *= (float) scale;
2348  }
2349  else if (defname == "approach") {
2350  if (napproach < FlightDeck::NUM_APPROACH_PTS) {
2351  GetDefVec(approach[napproach], pdef, filename);
2352  approach[napproach++] *= (float) scale;
2353  }
2354  else {
2355  Print("WARNING: flight deck approach point ignored in '%s' (max=%d)\n",
2357  }
2358  }
2359  else if (defname == "runway") {
2360  GetDefVec(runway[nrunway], pdef, filename);
2361  runway[nrunway++] *= (float) scale;
2362  }
2363  else if (defname == "spot") {
2364  if (pdef->term()->isStruct()) {
2365  TermStruct* s = pdef->term()->isStruct();
2366  for (int i = 0; i < s->elements()->size(); i++) {
2367  TermDef* d = s->elements()->at(i)->isDef();
2368  if (d) {
2369  if (d->name()->value() == "loc") {
2370  GetDefVec(spots[nslots], d, filename);
2371  spots[nslots] *= (float) scale;
2372  }
2373  else if (d->name()->value() == "filter") {
2374  GetDefNumber(filters[nslots], d, filename);
2375  }
2376  }
2377  }
2378 
2379  nslots++;
2380  }
2381 
2382  else if (pdef->term()->isArray()) {
2383  GetDefVec(spots[nslots], pdef, filename);
2384  spots[nslots] *= (float) scale;
2385  filters[nslots++] = 0xf;
2386  }
2387  }
2388 
2389  else if (defname == "light") {
2390  GetDefNumber(light, pdef, filename);
2391  }
2392 
2393  else if (defname == "cycle_time") {
2394  GetDefNumber(cycle_time, pdef, filename);
2395  }
2396 
2397  else if (defname == "launch") {
2398  GetDefBool(launch, pdef, filename);
2399  }
2400 
2401  else if (defname == "recovery") {
2402  GetDefBool(recovery, pdef, filename);
2403  }
2404 
2405  else if (defname == "azimuth") {
2406  GetDefNumber(az, pdef, filename);
2407  if (degrees) az *= (float) DEGREES;
2408  }
2409 
2410  else if (defname == "loc") {
2411  GetDefVec(loc, pdef, filename);
2412  loc *= (float) scale;
2413  }
2414  else if (defname == "size") {
2415  GetDefNumber(size, pdef, filename);
2416  size *= (float) scale;
2417  }
2418  else if (defname == "hull_factor") {
2419  GetDefNumber(hull, pdef, filename);
2420  }
2421  else if (defname == "explosion") {
2422  GetDefNumber(etype, pdef, filename);
2423  }
2424  }
2425  }
2426 
2427  FlightDeck* deck = new(__FILE__,__LINE__) FlightDeck();
2428  deck->Mount(loc, size, hull);
2429  if (dname.length()) deck->SetName(dname);
2430  if (dabrv.length()) deck->SetAbbreviation(dabrv);
2431 
2432  if (design_name.length()) {
2433  SystemDesign* sd = SystemDesign::Find(design_name);
2434  if (sd)
2435  deck->SetDesign(sd);
2436  }
2437 
2438  if (launch)
2439  deck->SetLaunchDeck();
2440  else if (recovery)
2441  deck->SetRecoveryDeck();
2442 
2443  deck->SetAzimuth(az);
2444  deck->SetBoundingBox(box);
2445  deck->SetStartPoint(start);
2446  deck->SetEndPoint(end);
2447  deck->SetCamLoc(cam);
2448  deck->SetExplosionType(etype);
2449 
2450  if (light > 0)
2451  deck->SetLight(light);
2452 
2453  for (int i = 0; i < napproach; i++)
2454  deck->SetApproachPoint(i, approach[i]);
2455 
2456  for (int i = 0; i < nrunway; i++)
2457  deck->SetRunwayPoint(i, runway[i]);
2458 
2459  for (int i = 0; i < nslots; i++)
2460  deck->AddSlot(spots[i], filters[i]);
2461 
2462  if (cycle_time > 0)
2463  deck->SetCycleTime(cycle_time);
2464 
2465  flight_decks.append(deck);
2466 }
2467 
2468 // +--------------------------------------------------------------------+
2469 
2470 void
2472 {
2473  Text dname;
2474  Text dabrv;
2475  Text design_name;
2476  int ngear = 0;
2477  Vec3 start[LandingGear::MAX_GEAR];
2479  Model* model[LandingGear::MAX_GEAR];
2480 
2481  for (int i = 0; i < val->elements()->size(); i++) {
2482  TermDef* pdef = val->elements()->at(i)->isDef();
2483  if (pdef) {
2484  Text defname = pdef->name()->value();
2485  defname.setSensitive(false);
2486 
2487  if (defname == "name")
2488  GetDefText(dname, pdef, filename);
2489  else if (defname == "abrv")
2490  GetDefText(dabrv, pdef, filename);
2491 
2492  else if (defname == "design") {
2493  GetDefText(design_name, pdef, filename);
2494  }
2495 
2496  else if (defname == "gear") {
2497  if (!pdef->term() || !pdef->term()->isStruct()) {
2498  Print("WARNING: gear struct missing for ship '%s' in '%s'\n", name, filename);
2499  }
2500  else {
2501  TermStruct* val = pdef->term()->isStruct();
2502 
2503  Vec3 v1, v2;
2504  char mod_name[256];
2505 
2506  ZeroMemory(mod_name, sizeof(mod_name));
2507 
2508  for (int i = 0; i < val->elements()->size(); i++) {
2509  TermDef* pdef = val->elements()->at(i)->isDef();
2510  if (pdef) {
2511  defname = pdef->name()->value();
2512  defname.setSensitive(false);
2513 
2514  if (defname == "model") {
2515  GetDefText(mod_name, pdef, filename);
2516  }
2517  else if (defname == "start") {
2518  GetDefVec(v1, pdef, filename);
2519  }
2520  else if (defname == "end") {
2521  GetDefVec(v2, pdef, filename);
2522  }
2523  }
2524  }
2525 
2526  if (ngear < LandingGear::MAX_GEAR) {
2527  Model* m = new(__FILE__,__LINE__) Model;
2528  if (!m->Load(mod_name, scale)) {
2529  Print("WARNING: Could not load landing gear model '%s'\n", mod_name);
2530  delete m;
2531  m = 0;
2532  }
2533  else {
2534  model[ngear] = m;
2535  start[ngear] = v1 * scale;
2536  end[ngear] = v2 * scale;
2537  ngear++;
2538  }
2539  }
2540  else {
2541  Print("WARNING: Too many landing gear ship '%s' in '%s'\n", name, filename);
2542  }
2543  }
2544  }
2545  }
2546  }
2547 
2548  gear = new(__FILE__,__LINE__) LandingGear();
2549  if (dname.length()) gear->SetName(dname);
2550  if (dabrv.length()) gear->SetAbbreviation(dabrv);
2551 
2552  if (design_name.length()) {
2553  SystemDesign* sd = SystemDesign::Find(design_name);
2554  if (sd)
2555  gear->SetDesign(sd);
2556  }
2557 
2558  for (int i = 0; i < ngear; i++)
2559  gear->AddGear(model[i], start[i], end[i]);
2560 }
2561 
2562 // +--------------------------------------------------------------------+
2563 
2564 void
2566 {
2567  Text wtype;
2568  Text wname;
2569  Text wabrv;
2570  Text design_name;
2571  Text group_name;
2572  int nmuz = 0;
2573  Vec3 muzzles[Weapon::MAX_BARRELS];
2574  Vec3 loc(0.0f, 0.0f, 0.0f);
2575  float size = 0.0f;
2576  float hull = 0.5f;
2577  float az = 0.0f;
2578  float el = 0.0f;
2579  float az_max = 1e6f;
2580  float az_min = 1e6f;
2581  float el_max = 1e6f;
2582  float el_min = 1e6f;
2583  float az_rest = 1e6f;
2584  float el_rest = 1e6f;
2585  int etype = 0;
2586  int emcon_1 = -1;
2587  int emcon_2 = -1;
2588  int emcon_3 = -1;
2589 
2590  for (int i = 0; i < val->elements()->size(); i++) {
2591  TermDef* pdef = val->elements()->at(i)->isDef();
2592  if (pdef) {
2593  Text defname = pdef->name()->value();
2594  defname.setSensitive(false);
2595 
2596  if (defname == "type")
2597  GetDefText(wtype, pdef, filename);
2598  else if (defname == "name")
2599  GetDefText(wname, pdef, filename);
2600  else if (defname == "abrv")
2601  GetDefText(wabrv, pdef, filename);
2602  else if (defname == "design")
2603  GetDefText(design_name, pdef, filename);
2604  else if (defname == "group")
2605  GetDefText(group_name, pdef, filename);
2606 
2607  else if (defname == "muzzle") {
2608  if (nmuz < Weapon::MAX_BARRELS) {
2609  GetDefVec(muzzles[nmuz], pdef, filename);
2610  nmuz++;
2611  }
2612  else {
2613  Print("WARNING: too many muzzles (max=%d) for weapon in '%s'\n", filename, Weapon::MAX_BARRELS);
2614  }
2615  }
2616  else if (defname == "loc") {
2617  GetDefVec(loc, pdef, filename);
2618  loc *= (float) scale;
2619  }
2620  else if (defname == "size") {
2621  GetDefNumber(size, pdef, filename);
2622  size *= (float) scale;
2623  }
2624  else if (defname == "hull_factor") {
2625  GetDefNumber(hull, pdef, filename);
2626  }
2627  else if (defname == "azimuth") {
2628  GetDefNumber(az, pdef, filename);
2629  if (degrees) az *= (float) DEGREES;
2630  }
2631  else if (defname == "elevation") {
2632  GetDefNumber(el, pdef, filename);
2633  if (degrees) el *= (float) DEGREES;
2634  }
2635 
2636  else if (defname==("aim_az_max")) {
2637  GetDefNumber(az_max,pdef,filename);
2638  if (degrees) az_max *= (float) DEGREES;
2639  az_min = 0.0f - az_max;
2640  }
2641 
2642  else if (defname==("aim_el_max")) {
2643  GetDefNumber(el_max,pdef,filename);
2644  if (degrees) el_max *= (float) DEGREES;
2645  el_min = 0.0f - el_max;
2646  }
2647 
2648  else if (defname==("aim_az_min")) {
2649  GetDefNumber(az_min,pdef,filename);
2650  if (degrees) az_min *= (float) DEGREES;
2651  }
2652 
2653  else if (defname==("aim_el_min")) {
2654  GetDefNumber(el_min,pdef,filename);
2655  if (degrees) el_min *= (float) DEGREES;
2656  }
2657 
2658  else if (defname==("aim_az_rest")) {
2659  GetDefNumber(az_rest,pdef,filename);
2660  if (degrees) az_rest *= (float) DEGREES;
2661  }
2662 
2663  else if (defname==("aim_el_rest")) {
2664  GetDefNumber(el_rest,pdef,filename);
2665  if (degrees) el_rest *= (float) DEGREES;
2666  }
2667 
2668  else if (defname == "rest_azimuth") {
2669  GetDefNumber(az_rest, pdef, filename);
2670  if (degrees) az_rest *= (float) DEGREES;
2671  }
2672  else if (defname == "rest_elevation") {
2673  GetDefNumber(el_rest, pdef, filename);
2674  if (degrees) el_rest *= (float) DEGREES;
2675  }
2676  else if (defname == "explosion") {
2677  GetDefNumber(etype, pdef, filename);
2678  }
2679 
2680  else if (defname == "emcon_1") {
2681  GetDefNumber(emcon_1, pdef, filename);
2682  }
2683 
2684  else if (defname == "emcon_2") {
2685  GetDefNumber(emcon_2, pdef, filename);
2686  }
2687 
2688  else if (defname == "emcon_3") {
2689  GetDefNumber(emcon_3, pdef, filename);
2690  }
2691  else {
2692  Print("WARNING: unknown weapon parameter '%s' in '%s'\n",
2693  defname.data(), filename);
2694  }
2695  }
2696  }
2697 
2698  WeaponDesign* meta = WeaponDesign::Find(wtype);
2699  if (!meta) {
2700  Print("WARNING: unusual weapon name '%s' in '%s'\n", (const char*) wtype, filename);
2701  }
2702  else {
2703  // non-turret weapon muzzles are relative to ship scale:
2704  if (meta->turret_model == 0) {
2705  for (int i = 0; i < nmuz; i++)
2706  muzzles[i] *= (float) scale;
2707  }
2708 
2709  // turret weapon muzzles are relative to weapon scale:
2710  else {
2711  for (int i = 0; i < nmuz; i++)
2712  muzzles[i] *= (float) meta->scale;
2713  }
2714 
2715  Weapon* gun = new(__FILE__,__LINE__) Weapon(meta, nmuz, muzzles, az, el);
2716  gun->SetSourceIndex(reactors.size()-1);
2717  gun->Mount(loc, size, hull);
2718 
2719  if (az_max < 1e6) gun->SetAzimuthMax(az_max);
2720  if (az_min < 1e6) gun->SetAzimuthMin(az_min);
2721  if (az_rest < 1e6) gun->SetRestAzimuth(az_rest);
2722 
2723  if (el_max < 1e6) gun->SetElevationMax(el_max);
2724  if (el_min < 1e6) gun->SetElevationMin(el_min);
2725  if (el_rest < 1e6) gun->SetRestElevation(el_rest);
2726 
2727  if (emcon_1 >= 0 && emcon_1 <= 100)
2728  gun->SetEMCONPower(1, emcon_1);
2729 
2730  if (emcon_2 >= 0 && emcon_2 <= 100)
2731  gun->SetEMCONPower(1, emcon_2);
2732 
2733  if (emcon_3 >= 0 && emcon_3 <= 100)
2734  gun->SetEMCONPower(1, emcon_3);
2735 
2736  if (wname.length()) gun->SetName(wname);
2737  if (wabrv.length()) gun->SetAbbreviation(wabrv);
2738 
2739  if (design_name.length()) {
2740  SystemDesign* sd = SystemDesign::Find(design_name);
2741  if (sd)
2742  gun->SetDesign(sd);
2743  }
2744 
2745  if (group_name.length()) {
2746  gun->SetGroup(group_name);
2747  }
2748 
2749  gun->SetExplosionType(etype);
2750 
2751  if (meta->decoy_type && !decoy)
2752  decoy = gun;
2753  else if (meta->probe && !probe)
2754  probe = gun;
2755  else
2756  weapons.append(gun);
2757  }
2758 
2759  DataLoader* loader = DataLoader::GetLoader();
2760  loader->SetDataPath(path_name);
2761 }
2762 
2763 // +--------------------------------------------------------------------+
2764 
2765 void
2767 {
2768  Text wtypes[8];
2769  Text wname;
2770  Text wabrv;
2771  Text design;
2772  Vec3 muzzle;
2773  Vec3 loc(0.0f, 0.0f, 0.0f);
2774  float size = 0.0f;
2775  float hull = 0.5f;
2776  float az = 0.0f;
2777  float el = 0.0f;
2778  int ntypes = 0;
2779  int emcon_1 = -1;
2780  int emcon_2 = -1;
2781  int emcon_3 = -1;
2782 
2783  for (int i = 0; i < val->elements()->size(); i++) {
2784  TermDef* pdef = val->elements()->at(i)->isDef();
2785  if (pdef) {
2786  Text defname = pdef->name()->value();
2787  defname.setSensitive(false);
2788 
2789  if (defname == "type")
2790  GetDefText(wtypes[ntypes++], pdef, filename);
2791  else if (defname == "name")
2792  GetDefText(wname, pdef, filename);
2793  else if (defname == "abrv")
2794  GetDefText(wabrv, pdef, filename);
2795  else if (defname == "design")
2796  GetDefText(design, pdef, filename);
2797 
2798  else if (defname == "muzzle") {
2799  GetDefVec(muzzle, pdef, filename);
2800  muzzle *= (float) scale;
2801  }
2802  else if (defname == "loc") {
2803  GetDefVec(loc, pdef, filename);
2804  loc *= (float) scale;
2805  }
2806  else if (defname == "size") {
2807  GetDefNumber(size, pdef, filename);
2808  size *= (float) scale;
2809  }
2810  else if (defname == "hull_factor") {
2811  GetDefNumber(hull, pdef, filename);
2812  }
2813  else if (defname == "azimuth") {
2814  GetDefNumber(az, pdef, filename);
2815  if (degrees) az *= (float) DEGREES;
2816  }
2817  else if (defname == "elevation") {
2818  GetDefNumber(el, pdef, filename);
2819  if (degrees) el *= (float) DEGREES;
2820  }
2821 
2822  else if (defname == "emcon_1") {
2823  GetDefNumber(emcon_1, pdef, filename);
2824  }
2825 
2826  else if (defname == "emcon_2") {
2827  GetDefNumber(emcon_2, pdef, filename);
2828  }
2829 
2830  else if (defname == "emcon_3") {
2831  GetDefNumber(emcon_3, pdef, filename);
2832  }
2833  else {
2834  Print("WARNING: unknown weapon parameter '%s' in '%s'\n",
2835  defname.data(), filename);
2836  }
2837  }
2838  }
2839 
2840  HardPoint* hp = new(__FILE__,__LINE__) HardPoint(muzzle, az, el);
2841  if (hp) {
2842  for (int i = 0; i < ntypes; i++) {
2843  WeaponDesign* meta = WeaponDesign::Find(wtypes[i]);
2844  if (!meta) {
2845  Print("WARNING: unusual weapon name '%s' in '%s'\n", (const char*) wtypes[i], filename);
2846  }
2847  else {
2848  hp->AddDesign(meta);
2849  }
2850  }
2851 
2852  hp->Mount(loc, size, hull);
2853  if (wname.length()) hp->SetName(wname);
2854  if (wabrv.length()) hp->SetAbbreviation(wabrv);
2855  if (design.length()) hp->SetDesign(design);
2856 
2857  hard_points.append(hp);
2858  }
2859 
2860  DataLoader* loader = DataLoader::GetLoader();
2861  loader->SetDataPath(path_name);
2862 }
2863 
2864 // +--------------------------------------------------------------------+
2865 
2866 void
2868 {
2869  ShipLoad* load = new(__FILE__,__LINE__) ShipLoad;
2870 
2871  if (!load) return;
2872 
2873  for (int i = 0; i < val->elements()->size(); i++) {
2874  TermDef* pdef = val->elements()->at(i)->isDef();
2875  if (pdef) {
2876  Text defname = pdef->name()->value();
2877  defname.setSensitive(false);
2878 
2879  if (defname == "name")
2880  GetDefText(load->name, pdef, filename);
2881 
2882  else if (defname == "stations")
2883  GetDefArray(load->load, 16, pdef, filename);
2884 
2885  else
2886  Print("WARNING: unknown loadout parameter '%s' in '%s'\n",
2887  defname.data(), filename);
2888  }
2889  }
2890 
2891  loadouts.append(load);
2892 }
2893 
2894 // +--------------------------------------------------------------------+
2895 
2896 void
2898 {
2899  Text design_name;
2900  Vec3 loc(0.0f, 0.0f, 0.0f);
2901  float size = 0.0f;
2902  float hull = 0.5f;
2903  int nranges = 0;
2904  float ranges[8];
2905  int emcon_1 = -1;
2906  int emcon_2 = -1;
2907  int emcon_3 = -1;
2908 
2909  ZeroMemory(ranges, sizeof(ranges));
2910 
2911  for (int i = 0; i < val->elements()->size(); i++) {
2912  TermDef* pdef = val->elements()->at(i)->isDef();
2913  if (pdef) {
2914  Text defname = pdef->name()->value();
2915  defname.setSensitive(false);
2916 
2917  if (defname == "range") {
2918  GetDefNumber(ranges[nranges++], pdef, filename);
2919  }
2920  else if (defname == "loc") {
2921  GetDefVec(loc, pdef, filename);
2922  loc *= (float) scale;
2923  }
2924  else if (defname == "size") {
2925  size *= (float) scale;
2926  GetDefNumber(size, pdef, filename);
2927  }
2928  else if (defname == "hull_factor") {
2929  GetDefNumber(hull, pdef, filename);
2930  }
2931  else if (defname == "design") {
2932  GetDefText(design_name, pdef, filename);
2933  }
2934  else if (defname == "emcon_1") {
2935  GetDefNumber(emcon_1, pdef, filename);
2936  }
2937 
2938  else if (defname == "emcon_2") {
2939  GetDefNumber(emcon_2, pdef, filename);
2940  }
2941 
2942  else if (defname == "emcon_3") {
2943  GetDefNumber(emcon_3, pdef, filename);
2944  }
2945  }
2946  }
2947 
2948  if (!sensor) {
2949  sensor = new(__FILE__,__LINE__) Sensor();
2950 
2951  if (design_name.length()) {
2952  SystemDesign* sd = SystemDesign::Find(design_name);
2953  if (sd)
2954  sensor->SetDesign(sd);
2955  }
2956 
2957  for (int i = 0; i < nranges; i++)
2958  sensor->AddRange(ranges[i]);
2959 
2960  if (emcon_1 >= 0 && emcon_1 <= 100)
2961  sensor->SetEMCONPower(1, emcon_1);
2962 
2963  if (emcon_2 >= 0 && emcon_2 <= 100)
2964  sensor->SetEMCONPower(1, emcon_2);
2965 
2966  if (emcon_3 >= 0 && emcon_3 <= 100)
2967  sensor->SetEMCONPower(1, emcon_3);
2968 
2969  sensor->Mount(loc, size, hull);
2971  }
2972  else {
2973  Print("WARNING: additional sensor ignored in '%s'\n", filename);
2974  }
2975 }
2976 
2977 // +--------------------------------------------------------------------+
2978 
2979 void
2981 {
2982  Text design_name;
2983  Vec3 loc(0.0f, 0.0f, 0.0f);
2984  float size = 0.0f;
2985  float hull = 0.5f;
2986 
2987  for (int i = 0; i < val->elements()->size(); i++) {
2988  TermDef* pdef = val->elements()->at(i)->isDef();
2989  if (pdef) {
2990  Text defname = pdef->name()->value();
2991  defname.setSensitive(false);
2992 
2993  if (defname == "loc") {
2994  GetDefVec(loc, pdef, filename);
2995  loc *= (float) scale;
2996  }
2997  else if (defname == "size") {
2998  size *= (float) scale;
2999  GetDefNumber(size, pdef, filename);
3000  }
3001  else if (defname == "hull_factor") {
3002  GetDefNumber(hull, pdef, filename);
3003  }
3004  else if (defname == "design")
3005  GetDefText(design_name, pdef, filename);
3006  }
3007  }
3008 
3009  if (!navsys) {
3010  navsys = new(__FILE__,__LINE__) NavSystem;
3011 
3012  if (design_name.length()) {
3013  SystemDesign* sd = SystemDesign::Find(design_name);
3014  if (sd)
3015  navsys->SetDesign(sd);
3016  }
3017 
3018  navsys->Mount(loc, size, hull);
3020  }
3021  else {
3022  Print("WARNING: additional nav system ignored in '%s'\n", filename);
3023  }
3024 }
3025 
3026 // +--------------------------------------------------------------------+
3027 
3028 void
3030 {
3031  Text comp_name("Computer");
3032  Text comp_abrv("Comp");
3033  Text design_name;
3034  int comp_type = 1;
3035  Vec3 loc(0.0f, 0.0f, 0.0f);
3036  float size = 0.0f;
3037  float hull = 0.5f;
3038 
3039  for (int i = 0; i < val->elements()->size(); i++) {
3040  TermDef* pdef = val->elements()->at(i)->isDef();
3041  if (pdef) {
3042  Text defname = pdef->name()->value();
3043  defname.setSensitive(false);
3044 
3045  if (defname == "name") {
3046  GetDefText(comp_name, pdef, filename);
3047  }
3048  else if (defname == "abrv") {
3049  GetDefText(comp_abrv, pdef, filename);
3050  }
3051  else if (defname == "design") {
3052  GetDefText(design_name, pdef, filename);
3053  }
3054  else if (defname == "type") {
3055  GetDefNumber(comp_type, pdef, filename);
3056  }
3057  else if (defname == "loc") {
3058  GetDefVec(loc, pdef, filename);
3059  loc *= (float) scale;
3060  }
3061  else if (defname == "size") {
3062  size *= (float) scale;
3063  GetDefNumber(size, pdef, filename);
3064  }
3065  else if (defname == "hull_factor") {
3066  GetDefNumber(hull, pdef, filename);
3067  }
3068  }
3069  }
3070 
3071  Computer* comp = new(__FILE__,__LINE__) Computer(comp_type, comp_name);
3072  comp->Mount(loc, size, hull);
3073  comp->SetAbbreviation(comp_abrv);
3074  comp->SetSourceIndex(reactors.size()-1);
3075 
3076  if (design_name.length()) {
3077  SystemDesign* sd = SystemDesign::Find(design_name);
3078  if (sd)
3079  comp->SetDesign(sd);
3080  }
3081 
3082  computers.append(comp);
3083 }
3084 
3085 // +--------------------------------------------------------------------+
3086 
3087 void
3089 {
3090  Text dname;
3091  Text dabrv;
3092  Text design_name;
3093  Text model_name;
3094  double factor = 0;
3095  double capacity = 0;
3096  double consumption = 0;
3097  double cutoff = 0;
3098  double curve = 0;
3099  double def_cost = 1;
3100  int shield_type = 0;
3101  Vec3 loc(0.0f, 0.0f, 0.0f);
3102  float size = 0.0f;
3103  float hull = 0.5f;
3104  int etype = 0;
3105  bool shield_capacitor = false;
3106  bool shield_bubble = false;
3107  int emcon_1 = -1;
3108  int emcon_2 = -1;
3109  int emcon_3 = -1;
3110 
3111  for (int i = 0; i < val->elements()->size(); i++) {
3112  TermDef* pdef = val->elements()->at(i)->isDef();
3113  if (pdef) {
3114  Text defname = pdef->name()->value();
3115  defname.setSensitive(false);
3116 
3117  if (defname == "type") {
3118  GetDefNumber(shield_type, pdef, filename);
3119  }
3120  else if (defname == "name")
3121  GetDefText(dname, pdef, filename);
3122  else if (defname == "abrv")
3123  GetDefText(dabrv, pdef, filename);
3124  else if (defname == "design")
3125  GetDefText(design_name, pdef, filename);
3126  else if (defname == "model")
3127  GetDefText(model_name, pdef, filename);
3128 
3129  else if (defname == "loc") {
3130  GetDefVec(loc, pdef, filename);
3131  loc *= (float) scale;
3132  }
3133  else if (defname == "size") {
3134  GetDefNumber(size, pdef, filename);
3135  size *= (float) scale;
3136  }
3137  else if (defname == "hull_factor")
3138  GetDefNumber(hull, pdef, filename);
3139 
3140  else if (defname.contains("factor"))
3141  GetDefNumber(factor, pdef, filename);
3142  else if (defname.contains("cutoff"))
3143  GetDefNumber(cutoff, pdef, filename);
3144  else if (defname.contains("curve"))
3145  GetDefNumber(curve, pdef, filename);
3146  else if (defname.contains("capacitor"))
3147  GetDefBool(shield_capacitor, pdef, filename);
3148  else if (defname.contains("bubble"))
3149  GetDefBool(shield_bubble, pdef, filename);
3150  else if (defname == "capacity")
3151  GetDefNumber(capacity, pdef, filename);
3152  else if (defname == "consumption")
3153  GetDefNumber(consumption, pdef, filename);
3154  else if (defname == "deflection_cost")
3155  GetDefNumber(def_cost, pdef, filename);
3156  else if (defname == "explosion")
3157  GetDefNumber(etype, pdef, filename);
3158 
3159  else if (defname == "emcon_1") {
3160  GetDefNumber(emcon_1, pdef, filename);
3161  }
3162 
3163  else if (defname == "emcon_2") {
3164  GetDefNumber(emcon_2, pdef, filename);
3165  }
3166 
3167  else if (defname == "emcon_3") {
3168  GetDefNumber(emcon_3, pdef, filename);
3169  }
3170 
3171  else if (defname == "bolt_hit_sound") {
3173  }
3174 
3175  else if (defname == "beam_hit_sound") {
3177  }
3178  }
3179  }
3180 
3181  if (!shield) {
3182  if (shield_type) {
3183  shield = new(__FILE__,__LINE__) Shield((Shield::SUBTYPE) shield_type);
3185  shield->Mount(loc, size, hull);
3186  if (dname.length()) shield->SetName(dname);
3187  if (dabrv.length()) shield->SetAbbreviation(dabrv);
3188 
3189  if (design_name.length()) {
3190  SystemDesign* sd = SystemDesign::Find(design_name);
3191  if (sd)
3192  shield->SetDesign(sd);
3193  }
3194 
3195  shield->SetExplosionType(etype);
3196  shield->SetShieldCapacitor(shield_capacitor);
3197  shield->SetShieldBubble(shield_bubble);
3198 
3199  if (factor > 0) shield->SetShieldFactor(factor);
3200  if (capacity > 0) shield->SetCapacity(capacity);
3201  if (cutoff > 0) shield->SetShieldCutoff(cutoff);
3202  if (consumption > 0) shield->SetConsumption(consumption);
3203  if (def_cost > 0) shield->SetDeflectionCost(def_cost);
3204  if (curve > 0) shield->SetShieldCurve(curve);
3205 
3206  if (emcon_1 >= 0 && emcon_1 <= 100)
3207  shield->SetEMCONPower(1, emcon_1);
3208 
3209  if (emcon_2 >= 0 && emcon_2 <= 100)
3210  shield->SetEMCONPower(1, emcon_2);
3211 
3212  if (emcon_3 >= 0 && emcon_3 <= 100)
3213  shield->SetEMCONPower(1, emcon_3);
3214 
3215  if (model_name.length()) {
3216  shield_model = new(__FILE__,__LINE__) Model;
3217  if (!shield_model->Load(model_name, scale)) {
3218  Print("ERROR: Could not load shield model '%s'\n", model_name.data());
3219  delete shield_model;
3220  shield_model = 0;
3221  valid = false;
3222  }
3223  else {
3224  shield_model->SetDynamic(true);
3225  shield_model->SetLuminous(true);
3226  }
3227  }
3228 
3229  DataLoader* loader = DataLoader::GetLoader();
3230  DWORD SOUND_FLAGS = Sound::LOCALIZED | Sound::LOC_3D;
3231 
3232  if (bolt_hit_sound.length()) {
3233  if (!loader->LoadSound(bolt_hit_sound, bolt_hit_sound_resource, SOUND_FLAGS, true)) {
3234  loader->SetDataPath("Sounds/");
3235  loader->LoadSound(bolt_hit_sound, bolt_hit_sound_resource, SOUND_FLAGS);
3236  loader->SetDataPath(path_name);
3237  }
3238  }
3239 
3240  if (beam_hit_sound.length()) {
3241  if (!loader->LoadSound(beam_hit_sound, beam_hit_sound_resource, SOUND_FLAGS, true)) {
3242  loader->SetDataPath("Sounds/");
3243  loader->LoadSound(beam_hit_sound, beam_hit_sound_resource, SOUND_FLAGS);
3244  loader->SetDataPath(path_name);
3245  }
3246  }
3247  }
3248  else {
3249  Print("WARNING: invalid shield type in '%s'\n", filename);
3250  }
3251  }
3252  else {
3253  Print("WARNING: additional shield ignored in '%s'\n", filename);
3254  }
3255 }
3256 
3257 // +--------------------------------------------------------------------+
3258 
3259 void
3261 {
3262  int exp_index = -1;
3263  int debris_index = -1;
3264  int fire_index = -1;
3265 
3266  for (int i = 0; i < val->elements()->size(); i++) {
3267  TermDef* def = val->elements()->at(i)->isDef();
3268  if (def) {
3269  Text defname = def->name()->value();
3270  defname.setSensitive(false);
3271 
3272  if (defname == "time") {
3274  }
3275 
3276  else if (defname == "explosion") {
3277  if (!def->term() || !def->term()->isStruct()) {
3278  Print("WARNING: explosion struct missing in '%s'\n", filename);
3279  }
3280  else {
3281  TermStruct* val = def->term()->isStruct();
3282  ParseExplosion(val, ++exp_index);
3283  }
3284  }
3285 
3286  // BACKWARD COMPATIBILITY:
3287  else if (defname == "explosion_type") {
3288  GetDefNumber(explosion[++exp_index].type, def, filename);
3289  }
3290 
3291  else if (defname == "explosion_time") {
3292  GetDefNumber(explosion[exp_index].time, def, filename);
3293  }
3294 
3295  else if (defname == "explosion_loc") {
3296  GetDefVec(explosion[exp_index].loc, def, filename);
3297  explosion[exp_index].loc *= (float) scale;
3298  }
3299 
3300  else if (defname == "final_type") {
3301  GetDefNumber(explosion[++exp_index].type, def, filename);
3302  explosion[exp_index].final = true;
3303  }
3304 
3305  else if (defname == "final_loc") {
3306  GetDefVec(explosion[exp_index].loc, def, filename);
3307  explosion[exp_index].loc *= (float) scale;
3308  }
3309 
3310 
3311  else if (defname == "debris") {
3312  if (def->term() && def->term()->isText()) {
3313  Text model_name;
3314  GetDefText(model_name, def, filename);
3315  Model* model = new(__FILE__,__LINE__) Model;
3316  if (!model->Load(model_name, scale)) {
3317  Print("Could not load debris model '%s'\n", model_name.data());
3318  delete model;
3319  return;
3320  }
3321 
3322  PrepareModel(*model);
3323  debris[++debris_index].model = model;
3324  fire_index = -1;
3325  }
3326  else if (!def->term() || !def->term()->isStruct()) {
3327  Print("WARNING: debris struct missing in '%s'\n", filename);
3328  }
3329  else {
3330  TermStruct* val = def->term()->isStruct();
3331  ParseDebris(val, ++debris_index);
3332  }
3333  }
3334 
3335  else if (defname == "debris_mass") {
3336  GetDefNumber(debris[debris_index].mass, def, filename);
3337  }
3338 
3339  else if (defname == "debris_speed") {
3340  GetDefNumber(debris[debris_index].speed, def, filename);
3341  }
3342 
3343  else if (defname == "debris_drag") {
3344  GetDefNumber(debris[debris_index].drag, def, filename);
3345  }
3346 
3347  else if (defname == "debris_loc") {
3348  GetDefVec(debris[debris_index].loc, def, filename);
3349  debris[debris_index].loc *= (float) scale;
3350  }
3351 
3352  else if (defname == "debris_count") {
3353  GetDefNumber(debris[debris_index].count, def, filename);
3354  }
3355 
3356  else if (defname == "debris_life") {
3357  GetDefNumber(debris[debris_index].life, def, filename);
3358  }
3359 
3360  else if (defname == "debris_fire") {
3361  if (++fire_index < 5) {
3362  GetDefVec(debris[debris_index].fire_loc[fire_index], def, filename);
3363  debris[debris_index].fire_loc[fire_index] *= (float) scale;
3364  }
3365  }
3366 
3367  else if (defname == "debris_fire_type") {
3368  GetDefNumber(debris[debris_index].fire_type, def, filename);
3369  }
3370  }
3371  }
3372 }
3373 
3374 // +--------------------------------------------------------------------+
3375 
3376 void
3378 {
3379  ShipExplosion* exp = &explosion[index];
3380 
3381  for (int i = 0; i < val->elements()->size(); i++) {
3382  TermDef* def = val->elements()->at(i)->isDef();
3383  if (def) {
3384  Text defname = def->name()->value();
3385  defname.setSensitive(false);
3386 
3387  if (defname == "time") {
3388  GetDefNumber(exp->time, def, filename);
3389  }
3390 
3391  else if (defname == "type") {
3392  GetDefNumber(exp->type, def, filename);
3393  }
3394 
3395  else if (defname == "loc") {
3396  GetDefVec(exp->loc, def, filename);
3397  exp->loc *= (float) scale;
3398  }
3399 
3400  else if (defname == "final") {
3401  GetDefBool(exp->final, def, filename);
3402  }
3403  }
3404  }
3405 }
3406 
3407 // +--------------------------------------------------------------------+
3408 
3409 void
3411 {
3412  char model_name[NAMELEN];
3413  int fire_index = 0;
3414  ShipDebris* deb = &debris[index];
3415 
3416  for (int i = 0; i < val->elements()->size(); i++) {
3417  TermDef* def = val->elements()->at(i)->isDef();
3418  if (def) {
3419  Text defname = def->name()->value();
3420 
3421  if (defname == "model") {
3422  GetDefText(model_name, def, filename);
3423  Model* model = new(__FILE__,__LINE__) Model;
3424  if (!model->Load(model_name, scale)) {
3425  Print("Could not load debris model '%s'\n", model_name);
3426  delete model;
3427  return;
3428  }
3429 
3430  PrepareModel(*model);
3431  deb->model = model;
3432  }
3433 
3434  else if (defname == "mass") {
3435  GetDefNumber(deb->mass, def, filename);
3436  }
3437 
3438  else if (defname == "speed") {
3439  GetDefNumber(deb->speed, def, filename);
3440  }
3441 
3442  else if (defname == "drag") {
3443  GetDefNumber(deb->drag, def, filename);
3444  }
3445 
3446  else if (defname == "loc") {
3447  GetDefVec(deb->loc, def, filename);
3448  deb->loc *= (float) scale;
3449  }
3450 
3451  else if (defname == "count") {
3452  GetDefNumber(deb->count, def, filename);
3453  }
3454 
3455  else if (defname == "life") {
3456  GetDefNumber(deb->life, def, filename);
3457  }
3458 
3459  else if (defname == "fire") {
3460  if (fire_index < 5) {
3461  GetDefVec(deb->fire_loc[fire_index], def, filename);
3462  deb->fire_loc[fire_index] *= (float) scale;
3463  fire_index++;
3464  }
3465  }
3466 
3467  else if (defname == "fire_type") {
3468  GetDefNumber(deb->fire_type, def, filename);
3469  }
3470  }
3471  }
3472 }
3473 
3474 // +--------------------------------------------------------------------+
3475 
3476 void
3478 {
3479  char sprite_name[NAMELEN];
3480 
3481  for (int i = 0; i < val->elements()->size(); i++) {
3482  TermDef* pdef = val->elements()->at(i)->isDef();
3483  if (pdef) {
3484  Text defname = pdef->name()->value();
3485  defname.setSensitive(false);
3486 
3487  if (defname == "sprite") {
3488  GetDefText(sprite_name, pdef, filename);
3489 
3490  Bitmap* sprite = new(__FILE__,__LINE__) Bitmap();
3491  DataLoader* loader = DataLoader::GetLoader();
3492  loader->LoadBitmap(sprite_name, *sprite, Bitmap::BMP_TRANSLUCENT);
3493 
3494  map_sprites.append(sprite);
3495  }
3496  }
3497  }
3498 }
3499 
3500 // +--------------------------------------------------------------------+
3501 
3502 void
3504 {
3505  char name[NAMELEN];
3506  char design[NAMELEN];
3507  int count = 4;
3508  int avail = 4;
3509 
3510  name[0] = 0;
3511  design[0] = 0;
3512 
3513  for (int i = 0; i < val->elements()->size(); i++) {
3514  TermDef* pdef = val->elements()->at(i)->isDef();
3515  if (pdef) {
3516  Text defname = pdef->name()->value();
3517  defname.setSensitive(false);
3518 
3519  if (defname == "name") {
3520  GetDefText(name, pdef, filename);
3521  }
3522  else if (defname == "design") {
3523  GetDefText(design, pdef, filename);
3524  }
3525  else if (defname == "count") {
3526  GetDefNumber(count, pdef, filename);
3527  }
3528  else if (defname == "avail") {
3529  GetDefNumber(avail, pdef, filename);
3530  }
3531  }
3532  }
3533 
3534  ShipSquadron* s = new(__FILE__,__LINE__) ShipSquadron;
3535  strcpy_s(s->name, name);
3536 
3537  s->design = Get(design);
3538  s->count = count;
3539  s->avail = avail;
3540 
3541  squadrons.append(s);
3542 }
3543 
3544 // +--------------------------------------------------------------------+
3545 
3546 Skin*
3548 {
3549  Skin* skin = 0;
3550  char name[NAMELEN];
3551 
3552  name[0] = 0;
3553 
3554  for (int i = 0; i < val->elements()->size(); i++) {
3555  TermDef* def = val->elements()->at(i)->isDef();
3556  if (def) {
3557  Text defname = def->name()->value();
3558  defname.setSensitive(false);
3559 
3560  if (defname == "name") {
3561  GetDefText(name, def, filename);
3562 
3563  skin = new(__FILE__,__LINE__) Skin(name);
3564  }
3565  else if (defname == "material" || defname == "mtl") {
3566  if (!def->term() || !def->term()->isStruct()) {
3567  Print("WARNING: skin struct missing in '%s'\n", filename);
3568  }
3569  else {
3570  TermStruct* val = def->term()->isStruct();
3571  ParseSkinMtl(val, skin);
3572  }
3573  }
3574  }
3575  }
3576 
3577  if (skin && skin->NumCells()) {
3578  skins.append(skin);
3579  }
3580 
3581  else if (skin) {
3582  delete skin;
3583  skin = 0;
3584  }
3585 
3586  return skin;
3587 }
3588 
3589 void
3591 {
3592  Material* mtl = new(__FILE__,__LINE__) Material;
3593 
3594  for (int i = 0; i < val->elements()->size(); i++) {
3595  TermDef* def = val->elements()->at(i)->isDef();
3596  if (def) {
3597  Text defname = def->name()->value();
3598  defname.setSensitive(false);
3599 
3600  if (defname == "name") {
3601  GetDefText(mtl->name, def, filename);
3602  }
3603  else if (defname == "Ka") {
3604  GetDefColor(mtl->Ka, def, filename);
3605  }
3606  else if (defname == "Kd") {
3607  GetDefColor(mtl->Kd, def, filename);
3608  }
3609  else if (defname == "Ks") {
3610  GetDefColor(mtl->Ks, def, filename);
3611  }
3612  else if (defname == "Ke") {
3613  GetDefColor(mtl->Ke, def, filename);
3614  }
3615  else if (defname == "Ns" || defname == "power") {
3616  GetDefNumber(mtl->power, def, filename);
3617  }
3618  else if (defname == "bump") {
3619  GetDefNumber(mtl->bump, def, filename);
3620  }
3621  else if (defname == "luminous") {
3622  GetDefBool(mtl->luminous, def, filename);
3623  }
3624 
3625  else if (defname == "blend") {
3626  if (def->term() && def->term()->isNumber())
3627  GetDefNumber(mtl->blend, def, filename);
3628 
3629  else if (def->term() && def->term()->isText()) {
3630  Text val;
3631  GetDefText(val, def, filename);
3632  val.setSensitive(false);
3633 
3634  if (val == "alpha" || val == "translucent")
3636 
3637  else if (val == "additive")
3639 
3640  else
3641  mtl->blend = Material::MTL_SOLID;
3642  }
3643  }
3644 
3645  else if (defname.indexOf("tex_d") == 0) {
3646  char tex_name[64];
3647  if (!GetDefText(tex_name, def, filename))
3648  Print("WARNING: invalid or missing tex_diffuse in '%s'\n", filename);
3649 
3650  DataLoader* loader = DataLoader::GetLoader();
3651  loader->LoadTexture(tex_name, mtl->tex_diffuse);
3652  }
3653 
3654  else if (defname.indexOf("tex_s") == 0) {
3655  char tex_name[64];
3656  if (!GetDefText(tex_name, def, filename))
3657  Print("WARNING: invalid or missing tex_specular in '%s'\n", filename);
3658 
3659  DataLoader* loader = DataLoader::GetLoader();
3660  loader->LoadTexture(tex_name, mtl->tex_specular);
3661  }
3662 
3663  else if (defname.indexOf("tex_b") == 0) {
3664  char tex_name[64];
3665  if (!GetDefText(tex_name, def, filename))
3666  Print("WARNING: invalid or missing tex_bumpmap in '%s'\n", filename);
3667 
3668  DataLoader* loader = DataLoader::GetLoader();
3669  loader->LoadTexture(tex_name, mtl->tex_bumpmap);
3670  }
3671 
3672  else if (defname.indexOf("tex_e") == 0) {
3673  char tex_name[64];
3674  if (!GetDefText(tex_name, def, filename))
3675  Print("WARNING: invalid or missing tex_emissive in '%s'\n", filename);
3676 
3677  DataLoader* loader = DataLoader::GetLoader();
3678  loader->LoadTexture(tex_name, mtl->tex_emissive);
3679  }
3680  }
3681  }
3682 
3683  if (skin && mtl)
3684  skin->AddMaterial(mtl);
3685 }
3686 
3687 const Skin*
3688 ShipDesign::FindSkin(const char* skin_name) const
3689 {
3690  int n = skins.size();
3691 
3692  for (int i = 0; i < n; i++) {
3693  Skin* s = skins[n-1-i];
3694 
3695  if (!strcmp(s->Name(), skin_name))
3696  return s;
3697  }
3698 
3699  return 0;
3700 }