From 8898ad9b25fca6afe2374d293a981db02a83d7e9 Mon Sep 17 00:00:00 2001 From: "FWoltermann@gmail.com" Date: Thu, 31 May 2012 14:46:27 +0000 Subject: Committing the documentation to svn to have it accessible online --- Doc/doxygen/html/_weapon_8cpp_source.html | 1301 +++++++++++++++++++++++++++++ 1 file changed, 1301 insertions(+) create mode 100644 Doc/doxygen/html/_weapon_8cpp_source.html (limited to 'Doc/doxygen/html/_weapon_8cpp_source.html') diff --git a/Doc/doxygen/html/_weapon_8cpp_source.html b/Doc/doxygen/html/_weapon_8cpp_source.html new file mode 100644 index 0000000..5f8a501 --- /dev/null +++ b/Doc/doxygen/html/_weapon_8cpp_source.html @@ -0,0 +1,1301 @@ + + + + + +Starshatter_Open: D:/SRC/StarshatterSVN/Stars45/Weapon.cpp Source File + + + + + + + + + + + + + +
+
+ + + + + + +
+
Starshatter_Open +
+
Open source Starshatter engine
+
+
+ + + + + +
+
+ +
+
+
+ +
+ + + + +
+ +
+ +
+
+
Weapon.cpp
+
+
+Go to the documentation of this file.
1 /* Project Starshatter 4.5
+
2  Destroyer Studios LLC
+
3  Copyright © 1997-2004. All Rights Reserved.
+
4 
+
5  SUBSYSTEM: Stars.exe
+
6  FILE: Weapon.cpp
+
7  AUTHOR: John DiCamillo
+
8 
+
9 
+
10  OVERVIEW
+
11  ========
+
12  Weapon class
+
13 */
+
14 
+
15 #include "MemDebug.h"
+
16 #include "Weapon.h"
+
17 #include "Shot.h"
+
18 #include "Drone.h"
+
19 #include "Contact.h"
+
20 #include "Ship.h"
+
21 #include "Sim.h"
+
22 #include "SimEvent.h"
+
23 #include "Random.h"
+
24 
+
25 #include "NetGame.h"
+
26 #include "NetUtil.h"
+
27 
+
28 #include "Game.h"
+
29 #include "Solid.h"
+
30 
+
31 // +----------------------------------------------------------------------+
+
32 
+
33 Weapon::Weapon(WeaponDesign* d, int nmuz, Vec3* muzzles, double az, double el)
+
34 : System(WEAPON, d->type, d->name, d->value,
+
35 d->capacity, d->capacity, d->recharge_rate),
+
36 design(d), group(d->group), ammo(-1), ripple_count(0),
+
37 aim_azimuth((float) az), aim_elevation((float) el),
+
38 old_azimuth(0.0f), old_elevation(0.0f), aim_time(0),
+
39 enabled(true), refire(0.0f),
+
40 mass(d->carry_mass), resist(d->carry_resist),
+
41 guided(d->guided), shot_speed(d->speed),
+
42 active_barrel(0), locked(false), centered(false), firing(false), blocked(false),
+
43 index(0), target(0), subtarget(0), beams(0), orders(MANUAL),
+
44 control(SINGLE_FIRE), sweep(SWEEP_TIGHT), turret(0), turret_base(0)
+
45 {
+
46  ZeroMemory(visible_stores, sizeof(visible_stores));
+
47 
+
48  if (design->primary)
+
49  abrv = Game::GetText("sys.weapon.primary.abrv");
+
50  else
+
51  abrv = Game::GetText("sys.weapon.secondary.abrv");
+
52 
+
53  nbarrels = nmuz;
+
54 
+
55  if (nbarrels > MAX_BARRELS)
+ +
57 
+
58  if (nbarrels == 0 && design->nbarrels > 0) {
+ +
60 
+
61  for (int i = 0; i < nbarrels; i++)
+ +
63 
+
64  ammo = design->ammo * nbarrels;
+
65  }
+
66  else if (nbarrels == 1 && design->nstores > 0) {
+ +
68 
+
69  for (int i = 0; i < nbarrels; i++)
+
70  muzzle_pts[i] = rel_pts[i] = (muzzles[0] + design->attachments[i]);
+
71 
+
72  ammo = nbarrels;
+
73  }
+
74  else {
+
75  for (int i = 0; i < nbarrels; i++)
+
76  muzzle_pts[i] = rel_pts[i] = muzzles[i];
+
77 
+
78  ammo = design->ammo * nbarrels;
+
79  }
+
80 
+
81  if (design->syncro)
+
82  active_barrel = -1;
+
83 
+
84  emcon_power[0] = 0;
+
85  emcon_power[1] = 0;
+
86  emcon_power[2] = 100;
+
87 
+ + + +
91 
+ + + +
95 }
+
96 
+
97 // +----------------------------------------------------------------------+
+
98 
+ +
100 : System(w), design(w.design), ammo(-1), ripple_count(0),
+
101 enabled(true), refire(0.0f),
+
102 mass(w.mass), resist(w.resist),
+
103 aim_azimuth(w.aim_azimuth), aim_elevation(w.aim_elevation),
+
104 old_azimuth(0.0f), old_elevation(0.0f), aim_time(0),
+
105 guided(w.guided), shot_speed(w.shot_speed),
+
106 active_barrel(0), locked(false), centered(false), firing(false), blocked(false),
+
107 target(0), subtarget(0), beams(0), orders(MANUAL),
+
108 control(SINGLE_FIRE), sweep(SWEEP_TIGHT), group(w.group),
+
109 aim_az_max(w.aim_az_max), aim_az_min(w.aim_az_min), aim_az_rest(w.aim_az_rest),
+
110 aim_el_max(w.aim_el_max), aim_el_min(w.aim_el_min), aim_el_rest(w.aim_el_rest),
+
111 turret(0), turret_base(0)
+
112 {
+
113  Mount(w);
+
114  ZeroMemory(visible_stores, sizeof(visible_stores));
+
115 
+
116  nbarrels = w.nbarrels;
+
117 
+
118  for (int i = 0; i < nbarrels; i++) {
+
119  muzzle_pts[i] = rel_pts[i] = w.muzzle_pts[i];
+
120  }
+
121 
+
122  ammo = design->ammo * nbarrels;
+
123 
+
124  if (design->syncro)
+
125  active_barrel = -1;
+
126 
+
127  if (design->beam) {
+
128  beams = new(__FILE__,__LINE__) Shot* [nbarrels];
+
129  ZeroMemory(beams, sizeof(Shot*) * nbarrels);
+
130  }
+
131 
+
132  if (aim_az_rest >= 2*PI)
+ +
134 
+
135  if (aim_el_rest >= 2*PI)
+ +
137 }
+
138 
+
139 // +--------------------------------------------------------------------+
+
140 
+ +
142 {
+
143  if (beams) {
+
144  for (int i = 0; i < nbarrels; i++) {
+
145  if (beams[i]) {
+
146  Ignore(beams[i]);
+
147  delete beams[i];
+
148  beams[i] = 0;
+
149  }
+
150  }
+
151 
+
152  delete [] beams;
+
153  }
+
154 
+ + +
157 
+
158  for (int i = 0; i < MAX_BARRELS; i++)
+ +
160 }
+
161 
+
162 // +--------------------------------------------------------------------+
+
163 
+
164 bool
+ +
166 {
+
167  return design->primary;
+
168 }
+
169 
+
170 bool
+ +
172 {
+
173  return design->drone;
+
174 }
+
175 
+
176 bool
+ +
178 {
+
179  return design->decoy_type != 0;
+
180 }
+
181 
+
182 bool
+ +
184 {
+
185  return design->probe != 0;
+
186 }
+
187 
+
188 bool
+ +
190 {
+
191  return !design->primary;
+
192 }
+
193 
+
194 bool
+ +
196 {
+
197  return design->beam;
+
198 }
+
199 
+
200 // +--------------------------------------------------------------------+
+
201 
+
202 Shot*
+ +
204 {
+
205  if (beams && i >= 0 && i < nbarrels)
+
206  return beams[i];
+
207 
+
208  return 0;
+
209 }
+
210 
+
211 // +--------------------------------------------------------------------+
+
212 
+
213 void
+ +
215 {
+
216  ship = s;
+
217 
+
218  if (design->turret_model) {
+
219  Solid* t = new(__FILE__,__LINE__) Solid;
+ +
221  turret = t;
+
222  }
+
223 
+
224  if (design->turret_base_model) {
+
225  Solid* t = new(__FILE__,__LINE__) Solid;
+ +
227  turret_base = t;
+
228  }
+
229 
+
230  if (!design->primary &&
+ +
232  ammo == nbarrels &&
+
233  design->shot_model != 0)
+
234  {
+
235  for (int i = 0; i < nbarrels; i++) {
+
236  Solid* s = new(__FILE__,__LINE__) Solid;
+ +
238 
+
239  visible_stores[i] = s;
+
240  }
+
241  }
+
242 }
+
243 
+
244 Solid*
+ +
246 {
+
247  return turret;
+
248 }
+
249 
+
250 Solid*
+ +
252 {
+
253  return turret_base;
+
254 }
+
255 
+
256 Solid*
+ +
258 {
+
259  if (i >= 0 && i < MAX_BARRELS)
+
260  return visible_stores[i];
+
261 
+
262  return 0;
+
263 }
+
264 
+
265 void
+ +
267 {
+
268  if (a >= 0) {
+
269  if (active_barrel >= 0 && design->visible_stores) {
+
270  while (a < ammo) {
+
271  if (active_barrel >= nbarrels)
+
272  active_barrel = 0;
+
273 
+ +
275  GRAPHIC_DESTROY(visible_stores[active_barrel]);
+
276  active_barrel++;
+
277  ammo--;
+
278  }
+
279  }
+
280  }
+
281 
+
282  ammo = a;
+
283  }
+
284 }
+
285 
+
286 // +--------------------------------------------------------------------+
+
287 
+
288 void
+
289 Weapon::ExecFrame(double seconds)
+
290 {
+
291  System::ExecFrame(seconds);
+
292 
+
293  if (refire > 0)
+
294  refire -= (float) seconds;
+
295 
+
296  locked = false;
+
297  centered = false;
+
298 
+
299  if (!ship)
+
300  return;
+
301 
+
302  if (orders == POINT_DEFENSE && enabled)
+
303  SelectTarget();
+
304 
+
305  if (beams && !target) {
+
306  for (int i = 0; i < nbarrels; i++) {
+
307  if (beams[i]) {
+
308  // aim beam straight:
+
309  Aim();
+
310  SetBeamPoints(false);
+
311  return;
+
312  }
+
313  }
+
314  }
+
315 
+
316  if (design->self_aiming) {
+ +
318  }
+
319  else if (turret) {
+
320  ZeroAim();
+
321  }
+
322 
+
323  if (ship->CheckFire())
+
324  return;
+
325 
+
326  // aim beam at target:
+
327  bool aim_beams = false;
+
328 
+
329  if (beams) {
+
330  for (int i = 0; i < nbarrels; i++) {
+
331  if (beams[i]) {
+
332  aim_beams = true;
+
333  SetBeamPoints(true);
+
334  break;
+
335  }
+
336  }
+
337  }
+
338 
+
339  if (!aim_beams) {
+
340  if (ripple_count > 0) {
+
341  if (Fire())
+
342  ripple_count--;
+
343  }
+
344 
+
345  else if (locked && !blocked) {
+
346  if (!ship->IsHostileTo(target))
+
347  return;
+
348 
+
349  if (orders == AUTO && centered) {
+
350  if (energy >= design->charge &&
+
351  (ammo < 0 || target && target->Integrity() >= 1) &&
+ +
353  Fire();
+
354  }
+
355 
+
356  else if (orders == POINT_DEFENSE) {
+
357  if (energy >= design->min_charge &&
+
358  (ammo < 0 || target && target->Integrity() >= 1) &&
+ +
360  Fire();
+
361  }
+
362  }
+
363  }
+
364 }
+
365 
+
366 // +----------------------------------------------------------------------+
+
367 
+
368 void
+
369 Weapon::Distribute(double delivered_energy, double seconds)
+
370 {
+
371  if (UsesWatts()) {
+
372  if (seconds < 0.01)
+
373  seconds = 0.01;
+
374 
+
375  // convert Joules to Watts:
+
376  energy = (float) (delivered_energy/seconds);
+
377  }
+
378 
+
379  else if (!Game::Paused()) {
+
380  energy += (float) (delivered_energy * 1.25);
+
381 
+
382  if (energy > capacity)
+
383  energy = capacity;
+
384 
+
385  else if (energy < 0)
+
386  energy = 0.0f;
+
387  }
+
388 }
+
389 
+
390 
+
391 // +--------------------------------------------------------------------+
+
392 
+
393 bool
+ +
395 {
+
396  if (obj == target) {
+
397  target = 0;
+
398  }
+
399 
+
400  else if (beams) {
+
401  for (int i = 0; i < nbarrels; i++)
+
402  if (obj == beams[i])
+
403  beams[i] = 0;
+
404  }
+
405 
+
406  return SimObserver::Update(obj);
+
407 }
+
408 
+
409 const char*
+ +
411 {
+
412  static char name[256];
+
413  sprintf_s(name, "Weapon %s", design->name.data());
+
414  return name;
+
415 }
+
416 
+
417 // +--------------------------------------------------------------------+
+
418 
+
419 void
+ +
421 {
+
422  if (o >= MANUAL && o <= POINT_DEFENSE)
+
423  orders = o;
+
424 }
+
425 
+
426 void
+ +
428 {
+
429  if (m >= SINGLE_FIRE && m <= SALVO_FIRE)
+
430  control = m;
+
431 }
+
432 
+
433 void
+ +
435 {
+
436  if (s >= SWEEP_NONE && s <= SWEEP_WIDE)
+
437  sweep = s;
+
438 }
+
439 
+
440 // +--------------------------------------------------------------------+
+
441 
+
442 bool
+
443 Weapon::CanTarget(DWORD classification) const
+
444 {
+
445  return (design->target_type & classification) ? true : false;
+
446 }
+
447 
+
448 // +--------------------------------------------------------------------+
+
449 
+
450 void
+ +
452 {
+
453  // check self targeting:
+
454  if (targ == (SimObject*) ship)
+
455  return;
+
456 
+
457  // check target class filter:
+
458  if (targ) {
+
459  switch (targ->Type()) {
+
460  case SimObject::SIM_SHIP: {
+
461  Ship* tgt_ship = (Ship*) targ;
+
462 
+
463  if ((tgt_ship->Class() & design->target_type) == 0)
+
464  return;
+
465  }
+
466  break;
+
467 
+
468  case SimObject::SIM_SHOT:
+
469  return;
+
470 
+
471  case SimObject::SIM_DRONE: {
+
472  if ((design->target_type & Ship::DRONE) == 0)
+
473  return;
+
474  }
+
475  break;
+
476 
+
477  default:
+
478  return;
+
479  }
+
480  }
+
481 
+
482  // if ok, target this object:
+
483  if (target != targ) {
+
484  target = targ;
+
485 
+
486  if (target)
+
487  Observe(target);
+
488  }
+
489 
+
490  subtarget = sub;
+
491 }
+
492 
+
493 // +--------------------------------------------------------------------+
+
494 
+
495 void
+ +
497 {
+
498  bool select_locked = false;
+
499  SimObject* targ = 0;
+
500  double dist = 1e9;
+
501  double az = 0;
+
502  double el = 0;
+
503 
+
504  if (ammo && enabled && (availability > crit_level)) {
+
505  ZeroAim();
+
506 
+
507  ListIter<Contact> contact = ship->ContactList();
+
508 
+
509  // lock onto any threatening shots first (if we can):
+
510  if (design->target_type & Ship::DRONE) {
+
511  while (++contact) {
+
512  Shot* c_shot = contact->GetShot();
+
513 
+
514  if (c_shot && contact->Threat(ship)) {
+
515 
+
516  // distance from self to target:
+
517  double distance = Point(c_shot->Location() - muzzle_pts[0]).length();
+
518 
+
519  if (distance > design->min_range &&
+
520  distance < design->max_range &&
+
521  distance < dist) {
+
522  // check aim basket:
+
523  select_locked = CanLockPoint(c_shot->Location(), az, el);
+
524 
+
525  if (select_locked) {
+
526  targ = c_shot;
+
527  dist = distance;
+
528  }
+
529  }
+
530  }
+
531  }
+
532  }
+
533 
+
534  // lock onto a threatening ship only if it is (much) closer:
+
535  dist *= 0.2;
+
536  contact.reset();
+
537  while (++contact) {
+
538  Ship* c_ship = contact->GetShip();
+
539 
+
540  if (!c_ship) continue;
+
541 
+
542  // can we lock onto this target?
+
543  if ((c_ship->IsRogue() || c_ship->GetIFF() > 0 && c_ship->GetIFF() != ship->GetIFF()) &&
+
544  (c_ship->Class() & design->target_type) &&
+
545  c_ship->Weapons().size() > 0) {
+
546  // distance from self to target:
+
547  double distance = Point(c_ship->Location() - muzzle_pts[0]).length();
+
548 
+
549  if (distance < design->max_range && distance < dist) {
+
550  // check aim basket:
+
551  select_locked = CanLockPoint(c_ship->Location(), az, el);
+
552 
+
553  if (select_locked) {
+
554  targ = c_ship;
+
555  dist = distance;
+
556  }
+
557  }
+
558  }
+
559  }
+
560  }
+
561 
+
562  if (!ammo || !enabled) {
+
563  SetTarget(0,0);
+
564  locked = false;
+
565  }
+
566 
+
567  else {
+
568  SetTarget(targ, 0);
+
569  }
+
570 }
+
571 
+
572 // +--------------------------------------------------------------------+
+
573 
+
574 int
+ +
576 {
+
577  if (ammo && enabled && (availability > crit_level)) {
+
578  firing = 0;
+
579  Aim();
+
580  }
+
581  else if (turret) {
+
582  ZeroAim();
+
583  }
+
584 
+
585  return locked;
+
586 }
+
587 
+
588 // +--------------------------------------------------------------------+
+
589 
+
590 Shot*
+ +
592 {
+
593  if (Game::Paused())
+
594  return 0;
+
595 
+
596  if (ship && ship->CheckFire())
+
597  return 0;
+
598 
+
599  if (ship->IsStarship() && target && !centered)
+
600  return 0;
+
601 
+ +
603  return 0;
+
604 
+
605  Shot* shot = 0;
+
606 
+
607  if (ammo && enabled &&
+
608  (refire <= 0) && (energy > design->min_charge) &&
+
609  (availability > crit_level)) {
+
610 
+ +
612 
+
613  NetGame* net_game = NetGame::GetInstance();
+
614  bool net_client = net_game ? net_game->IsClient() : false;
+
615 
+
616  // all barrels
+
617  if (active_barrel < 0) {
+
618  if (net_client || IsPrimary())
+ +
620 
+
621  if (!net_game || IsPrimary()) {
+
622  for (int i = 0; i < nbarrels; i++)
+
623  shot = FireBarrel(i);
+
624  }
+
625 
+
626  else if (net_game && net_game->IsServer() && IsMissile()) {
+
627  for (int i = 0; i < nbarrels; i++) {
+
628  shot = FireBarrel(i);
+
629  NetUtil::SendWepRelease(this, shot);
+
630  }
+
631  }
+
632  }
+
633 
+
634  // single barrel
+
635  else {
+
636  if (net_client || IsPrimary())
+ +
638 
+
639  if (!net_game || IsPrimary()) {
+
640  shot = FireBarrel(active_barrel++);
+
641  }
+
642 
+
643  else if (net_game && net_game->IsServer() && IsMissile()) {
+
644  shot = FireBarrel(active_barrel++);
+
645  NetUtil::SendWepRelease(this, shot);
+
646  }
+
647 
+
648  if (active_barrel >= nbarrels) {
+
649  active_barrel = 0;
+ +
651  }
+
652  }
+
653 
+
654  if (design->ripple_count > 0 && ripple_count <= 0)
+ +
656 
+
657  if (status != NOMINAL)
+
658  refire *= 2;
+
659  }
+
660 
+
661  return shot;
+
662 }
+
663 
+
664 // +--------------------------------------------------------------------+
+
665 
+
666 Shot*
+ +
668 {
+
669  Shot* shot = 0;
+
670 
+
671  if (!IsPrimary() || Game::Paused())
+
672  return shot;
+
673 
+
674  if (active_barrel < 0 || active_barrel >= nbarrels)
+
675  active_barrel = 0;
+
676 
+
677  target = tgt;
+
678  subtarget = sub;
+
679  aim_time = 0;
+
680 
+
681  for (int i = 0; i < count; i++) {
+
682  shot = FireBarrel(active_barrel++);
+
683 
+
684  if (active_barrel >= nbarrels) {
+
685  active_barrel = 0;
+ +
687  }
+
688  }
+
689 
+
690  if (target)
+
691  Observe(target);
+
692 
+
693  return shot;
+
694 }
+
695 
+
696 Shot*
+
697 Weapon::NetFireSecondary(SimObject* tgt, System* sub, DWORD objid)
+
698 {
+
699  Shot* shot = 0;
+
700 
+
701  if (IsPrimary() || Game::Paused())
+
702  return shot;
+
703 
+
704  if (active_barrel < 0 || active_barrel >= nbarrels)
+
705  active_barrel = 0;
+
706 
+
707  target = tgt;
+
708  subtarget = sub;
+
709  aim_time = 0;
+
710 
+
711  shot = FireBarrel(active_barrel++);
+
712 
+
713  if (active_barrel >= nbarrels) {
+
714  active_barrel = 0;
+ +
716  }
+
717 
+
718  if (shot)
+
719  shot->SetObjID(objid);
+
720 
+
721  if (target)
+
722  Observe(target);
+
723 
+
724  return shot;
+
725 }
+
726 
+
727 // +--------------------------------------------------------------------+
+
728 
+
729 Shot*
+ +
731 {
+
732  const Point& base_vel = ship->Velocity();
+
733  Shot* shot = 0;
+
734  SimRegion* region = ship->GetRegion();
+
735 
+
736  if (!region || n < 0 || n >= nbarrels || Game::Paused())
+
737  return 0;
+
738 
+
739  firing = 1;
+
740  Aim();
+
741 
+
742  Camera rail_cam;
+
743  rail_cam.Clone(aim_cam);
+
744 
+
745  Point shotpos = muzzle_pts[n];
+
746  if (design->length > 0)
+
747  shotpos = shotpos + aim_cam.vpn() * design->length;
+
748 
+
749  // guns may be slewed towards target:
+
750  if (design->primary) {
+
751  shot = CreateShot(shotpos, aim_cam, design, ship);
+
752 
+
753  if (shot) {
+
754  shot->SetVelocity(shot->Velocity() + base_vel);
+
755  }
+
756  }
+
757 
+
758  // missiles always launch in rail direction:
+
759  else {
+
760  // unless they are on a mobile launcher
+
761  if (turret && design->self_aiming) {
+
762  shot = CreateShot(shotpos, aim_cam, design, ship);
+
763  shot->SetVelocity(base_vel);
+
764  }
+
765  else {
+
766  shot = CreateShot(shotpos, rail_cam, design, ship);
+
767  if (shot /* && !turret */) {
+
768  Matrix orient = ship->Cam().Orientation();
+
769  if (aim_azimuth != 0) orient.Yaw(aim_azimuth);
+
770  if (aim_elevation != 0) orient.Pitch(aim_elevation);
+
771 
+
772  Point eject = design->eject * orient;
+
773  shot->SetVelocity(base_vel + eject);
+
774  }
+
775  }
+
776 
+
777  if (shot && visible_stores[n]) {
+ +
779  }
+
780  }
+
781 
+
782  if (shot) {
+
783  if (ammo > 0)
+
784  ammo--;
+
785 
+
786  if (guided && target)
+
787  shot->SeekTarget(target, subtarget);
+
788 
+
789  float shot_load;
+
790  if (energy > design->charge)
+
791  shot_load = design->charge;
+
792  else
+
793  shot_load = energy;
+
794 
+
795  energy -= shot_load;
+
796  shot->SetCharge(shot_load * availability);
+
797 
+
798  if (target && design->flak && !design->guided) {
+
799  double speed = shot->Velocity().length();
+
800  double range = (target->Location() - shot->Location()).length();
+
801 
+
802  if (range > design->min_range && range < design->max_range) {
+
803  shot->SetFuse(range / speed);
+
804  }
+
805  }
+
806 
+
807  region->InsertObject(shot);
+
808 
+
809  if (beams) {
+
810  beams[n] = shot;
+
811  Observe(beams[n]);
+
812 
+
813  // aim beam at target:
+
814  SetBeamPoints(true);
+
815  }
+
816 
+
817  if (ship) {
+
818  ShipStats* stats = ShipStats::Find(ship->Name());
+
819 
+
820  if (design->primary)
+
821  stats->AddGunShot();
+
822  else if (design->decoy_type == 0 && design->damage > 0)
+
823  stats->AddMissileShot();
+
824  }
+
825  }
+
826 
+
827  return shot;
+
828 }
+
829 
+
830 Shot*
+
831 Weapon::CreateShot(const Point& loc, const Camera& cam, WeaponDesign* dsn, const Ship* own)
+
832 {
+
833  if (dsn->drone)
+
834  return new(__FILE__,__LINE__) Drone(loc, cam, dsn, own);
+
835 
+
836  else
+
837  return new(__FILE__,__LINE__) Shot(loc, cam, dsn, own);
+
838 }
+
839 
+
840 // +--------------------------------------------------------------------+
+
841 
+
842 void
+ +
844 {
+
845  System::Orient(rep);
+
846 
+
847  const Matrix& orientation = rep->Cam().Orientation();
+
848  Point loc = rep->Location();
+
849 
+
850  // align graphics with camera:
+
851  if (turret) {
+
852  if (!design->self_aiming)
+
853  ZeroAim();
+
854 
+
855  const Matrix& aim = aim_cam.Orientation();
+
856 
+ +
858  turret->SetOrientation(aim);
+
859 
+
860  if (turret_base) {
+
861  Matrix base = orientation;
+
862 
+
863  if (design->turret_axis == 1) {
+
864  base.Pitch(aim_elevation);
+
865  base.Pitch(old_elevation);
+
866  }
+
867  else {
+
868  base.Yaw(aim_azimuth);
+
869  base.Yaw(old_azimuth);
+
870  }
+
871 
+ + +
874  }
+
875 
+
876  for (int i = 0; i < nbarrels; i++) {
+
877  muzzle_pts[i] = (rel_pts[i] * aim) + mount_loc;
+
878 
+
879  if (visible_stores[i]) {
+ + +
882  }
+
883  }
+
884  }
+
885  else {
+
886  for (int i = 0; i < nbarrels; i++) {
+
887  muzzle_pts[i] = (rel_pts[i] * orientation) + loc;
+
888 
+
889  if (visible_stores[i]) {
+
890  visible_stores[i]->SetOrientation(orientation);
+ +
892  }
+
893  }
+
894  }
+
895 }
+
896 
+
897 // +--------------------------------------------------------------------+
+
898 
+
899 void
+ +
901 {
+
902  for (int i = 0; i < nbarrels; i++) {
+
903  if (beams && beams[i]) {
+
904  Point from = muzzle_pts[i];
+
905  Point to;
+
906  double len = design->length;
+
907 
+
908  if (len < 1 || len > 1e7)
+
909  len = design->max_range;
+
910 
+
911  if (len < 1)
+
912  len = 3e5;
+
913 
+
914  else if (len > 1e7)
+
915  len = 1e7;
+
916 
+
917  // always use the aim cam, to enforce slew_rate
+
918  to = from + aim_cam.vpn() * len;
+
919 
+
920  beams[i]->SetBeamPoints(from, to);
+
921  }
+
922  }
+
923 }
+
924 
+
925 // +--------------------------------------------------------------------+
+
926 
+
927 void
+ +
929 {
+
930  locked = false;
+
931  centered = false;
+
932 
+
933  FindObjective();
+
934 
+
935  if (target) {
+
936  double az = 0;
+
937  double el = 0;
+
938 
+
939  locked = CanLockPoint(obj_w, az, el, &objective);
+
940 
+
941  double spread_az = design->spread_az;
+
942  double spread_el = design->spread_el;
+
943 
+
944  // beam sweep target:
+
945  if (design->beam) {
+
946  double factor = 0;
+
947  double az_phase = 0;
+
948  double el_phase = 0;
+
949 
+
950  if (target->Type() == SimObject::SIM_SHIP) {
+
951  Ship* s = (Ship*) target;
+
952 
+
953  if (s->IsStarship()) {
+
954  switch (sweep) {
+
955  default:
+
956  case SWEEP_NONE: factor = 0; break;
+
957  case SWEEP_TIGHT: factor = 1; break;
+
958  case SWEEP_WIDE: factor = 2; break;
+
959  }
+
960  }
+
961  }
+
962 
+
963  if (factor > 0) {
+
964  factor *= atan2(target->Radius(), (double) objective.z);
+
965 
+
966  for (int i = 0; i < nbarrels; i++) {
+
967  if (beams && beams[i]) {
+
968  az_phase = sin(beams[i]->Life() * 0.4 * PI);
+
969  el_phase = sin(beams[i]->Life() * 1.0 * PI);
+
970  break;
+
971  }
+
972  }
+
973 
+
974  az += factor * spread_az * az_phase;
+
975  el += factor * spread_el * el_phase * 0.25;
+
976  }
+
977  }
+
978 
+
979  else if (!design->beam) {
+
980  if (spread_az > 0)
+
981  az += Random(-spread_az, spread_az);
+
982 
+
983  if (spread_el > 0)
+
984  el += Random(-spread_el, spread_el);
+
985  }
+
986 
+
987  AimTurret(az, -el);
+
988 
+
989  // check range for guided weapons:
+
990  if (locked && guided) {
+
991  double range = objective.length();
+
992 
+
993  if (range > design->max_track)
+
994  locked = false;
+
995 
+
996  else if (range > design->max_range) {
+
997  if (firing) {
+
998  if (RandomChance(1,4)) // 1 in 4 chance of locking anyway
+
999  locked = false;
+
1000  }
+
1001  else {
+
1002  locked = false;
+
1003  }
+
1004  }
+
1005  }
+
1006 
+
1007  if (locked) {
+
1008  Point tloc = target->Location();
+
1009  tloc = Transform(tloc);
+
1010 
+
1011  if (tloc.z > 1) {
+
1012  az = atan2(fabs(tloc.x), tloc.z);
+
1013  el = atan2(fabs(tloc.y), tloc.z);
+
1014 
+
1015  double firing_cone = 10*DEGREES;
+
1016 
+
1017  if (orders == MANUAL)
+
1018  firing_cone = 30*DEGREES;
+
1019 
+
1020  if (az < firing_cone && el < firing_cone)
+
1021  centered = true;
+
1022  }
+
1023  }
+
1024  }
+
1025  else {
+ +
1027  }
+
1028 }
+
1029 
+
1030 void
+ +
1032 {
+
1033  ZeroAim();
+
1034 
+
1035  if (!target || !design->self_aiming) {
+
1036  objective = Point();
+
1037  return;
+
1038  }
+
1039 
+
1040  obj_w = target->Location();
+
1041 
+
1042  if (subtarget) {
+ +
1044  }
+
1045  else if (target->Type() == SimObject::SIM_SHIP) {
+
1046  Ship* tgt_ship = (Ship*) target;
+
1047 
+
1048  if (tgt_ship->IsGroundUnit())
+
1049  obj_w += Point(0,150,0);
+
1050  }
+
1051 
+
1052  if (!design->beam && shot_speed > 0) {
+
1053  // distance from self to target:
+
1054  double distance = Point(obj_w - muzzle_pts[0]).length();
+
1055 
+
1056  // TRUE shot speed is relative to ship speed:
+
1057  Point eff_shot_vel = ship->Velocity() + aim_cam.vpn() * shot_speed - target->Velocity();
+
1058  double eff_shot_speed = eff_shot_vel.length();
+
1059 
+
1060  // time to reach target:
+
1061  double time = distance / eff_shot_speed;
+
1062 
+
1063  // where the target will be when the shot reaches it:
+
1064  obj_w += (target->Velocity() - ship->Velocity()) * time +
+
1065  target->Acceleration() * 0.25 * time * time;
+
1066  }
+
1067 
+
1068  // transform into camera coords:
+ +
1070 }
+
1071 
+
1072 Point
+ +
1074 {
+
1075  Point result;
+
1076 
+
1077  Point obj_t = pt - aim_cam.Pos();
+
1078  result.x = obj_t * aim_cam.vrt();
+
1079  result.y = obj_t * aim_cam.vup();
+
1080  result.z = obj_t * aim_cam.vpn();
+
1081 
+
1082  return result;
+
1083 }
+
1084 
+
1085 bool
+
1086 Weapon::CanLockPoint(const Point& test, double& az, double& el, Point* obj)
+
1087 {
+
1088  Point pt = Transform(test);
+
1089  bool locked = true;
+
1090 
+
1091  // first compute az:
+
1092  if (fabs(pt.z) < 0.1) pt.z = 0.1;
+
1093  az = atan(pt.x / pt.z);
+
1094  if (pt.z < 0) az -= PI;
+
1095  if (az < -PI) az += 2*PI;
+
1096 
+
1097  // then, rotate target into az-coords to compute el:
+
1098  Camera tmp;
+
1099  tmp.Clone(aim_cam);
+
1100  aim_cam.Yaw(az);
+
1101  pt = Transform(test);
+
1102  aim_cam.Clone(tmp);
+
1103 
+
1104  if (fabs(pt.z) < 0.1) pt.z = 0.1;
+
1105  el = atan(pt.y / pt.z);
+
1106 
+
1107  if (obj) *obj = pt;
+
1108 
+
1109  // is the target in the basket?
+
1110  // clamp if necessary:
+
1111 
+
1112  if (az > aim_az_max) {
+
1113  az = aim_az_max;
+
1114  locked = false;
+
1115  }
+
1116  else if (az < aim_az_min) {
+
1117  az = aim_az_min;
+
1118  locked = false;
+
1119  }
+
1120 
+
1121  if (el > aim_el_max) {
+
1122  el = aim_el_max;
+
1123  locked = false;
+
1124  }
+
1125  else if (el < aim_el_min) {
+
1126  el = aim_el_min;
+
1127  locked = false;
+
1128  }
+
1129 
+
1130  if (IsDrone() && guided) {
+
1131  double firing_cone = 10*DEGREES;
+
1132 
+
1133  if (orders == MANUAL)
+
1134  firing_cone = 20*DEGREES;
+
1135 
+
1136  if (az < firing_cone && el < firing_cone)
+
1137  locked = true;
+
1138  }
+
1139 
+
1140  return locked;
+
1141 }
+
1142 
+
1143 // +--------------------------------------------------------------------+
+
1144 
+
1145 void
+
1146 Weapon::AimTurret(double az, double el)
+
1147 {
+
1148  double seconds = (Game::GameTime() - aim_time) / 1000.0;
+
1149 
+
1150  // don't let the weapon turn faster than turret slew rate:
+
1151  double max_turn = design->slew_rate * seconds;
+
1152 
+
1153  if (fabs(az-old_azimuth) > max_turn) {
+
1154  if (az > old_azimuth)
+
1155  az = old_azimuth + max_turn;
+
1156  else
+
1157  az = old_azimuth - max_turn;
+
1158  }
+
1159 
+
1160  if (fabs(el-old_elevation) > PI/2 * seconds) {
+
1161  if (el > old_elevation)
+
1162  el = old_elevation + max_turn;
+
1163  else
+
1164  el = old_elevation - max_turn;
+
1165  }
+
1166 
+
1167  aim_cam.Yaw(az);
+
1168  aim_cam.Pitch(el);
+
1169 
+
1170  old_azimuth = (float) az;
+
1171  old_elevation = (float) el;
+
1172 
+ +
1174 }
+
1175 
+
1176 void
+ +
1178 {
+
1179  aim_cam.Clone(ship->Cam());
+
1180  if (aim_azimuth != 0) aim_cam.Yaw(aim_azimuth);
+ +
1182 
+ +
1184 }
+
+
+ + + + -- cgit v1.1