1 /***************************************************************************
2 submarine.cpp - description
3 -------------------
4 begin : Sat Mar 16 2002
5 copyright : (C) 2002 by Michael Bridak
6 email : michael.bridak@verizon.net
7 $Id: submarine.cpp,v 1.6 2003/04/14 05:51:04 mbridak Exp $
8 ***************************************************************************/
9
10 /***************************************************************************
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License. *
15 * . *
16 * *
17 ***************************************************************************/
18
19 #include <iostream>
20 #include <fstream>
21 #include <math.h>
22 #include <limits.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include "submarine.h"
26 #include "files.h"
27 #include "sound.h"
28 #include "map.h"
29
30 using namespace std;
31
Submarine()32 Submarine::Submarine()
33 {
34 Init();
35 }
36
~Submarine()37 Submarine::~Submarine()
38 {
39 }
40
41
42
Init()43 void Submarine::Init()
44 {
45 int index;
46
47 //Passive Sonar Cross Section
48 //in future make different pscs's
49 //based on angle of view, front
50 //side and rear.
51
52 PSCS=83.0;
53 Active = FALSE;
54 CavitationFlag=0;
55 Depth=0;
56 MaxDepth=999;
57 Speed=5.0;
58 MaxSpeed=32;
59 MinSpeed=-12;
60 DesiredSpeed=0;
61 Rudder=10;
62 TorpedosOnBoard=24;
63 NoiseMakers = 12;
64 ShipClass = CLASS_MERCHANT;
65 // clear targets
66 targets = NULL;
67 last_target = NULL;
68 current_target = -1;
69 for (index = 0; index < MAX_TUBES; index++)
70 torpedo_tube[index] = TUBE_EMPTY;
71 next = NULL;
72 target = NULL;
73 owner = NULL;
74 fuel_remaining = INT_MAX;
75 hull_strength = 1;
76 has_sonar = TRUE;
77 mission_status = MISSION_NONE;
78 mission_timer = 0;
79 mood = MOOD_PASSIVE;
80 convoy_course_change = CONVOY_CHANGE_COURSE;
81 radio_message = RADIO_NONE;
82 pinging = FALSE;
83 using_radar = FALSE;
84 map = NULL;
85 ClassName[0] = '\0';
86 ClassType[0] = '\0';
87 }
88
89
90
RadiatedNoise()91 float Submarine::RadiatedNoise(){
92 //This will return how noisey you are
93
94 float unit=40;
95 float multiplier=4.2;
96 float value=0;
97
98 CheckForCavitation();
99 value = PSCS + (unit * CavitationFlag) + (((CheckNegSpeed(Speed)>4.9)*multiplier) * CheckNegSpeed(Speed));
100 if (pinging)
101 value += PING_NOISE;
102 return value;
103 }
104
CheckNegSpeed(float value)105 float Submarine::CheckNegSpeed(float value){
106 if(value < 0){
107 return 100.0 - (100.0 + value);
108 }else{
109 return value;
110 }
111 }
CheckForCavitation()112 void Submarine::CheckForCavitation(){
113
114 //Check to see if we are cavitating...
115 // 4-5kts @ 0-100ft.
116 // 5-14kts @ 100-150ft
117 // 14-35kts @ 150-600ft
118
119 CavitationFlag = 0;
120
121 if ((Depth <100) && (CheckNegSpeed(Speed) > 4.0)){
122 if ((CheckNegSpeed(Speed) - 4.0) > (float) Depth / 100.0){
123 CavitationFlag = 1;
124 }
125 return;
126 }
127
128 if ((Depth < 150) && (CheckNegSpeed(Speed) > 5.0)){
129 if (((CheckNegSpeed(Speed) - 5.0) * 5.555) > (Depth -100)){
130 CavitationFlag = 1;
131 }
132 return;
133 }
134
135 if ((Depth < 600) && (CheckNegSpeed(Speed) > 14.0)){
136 if (((CheckNegSpeed(Speed) - 14.0) * 21.428) > (Depth - 150)){
137 CavitationFlag = 1;
138 }
139 return;
140 }
141 }
BearingToTarget(Submarine * Target)142 double Submarine::BearingToTarget(Submarine *Target){
143 double latdif=0, londif=0, bearing = 0; //atan() needs doubles
144 //LatLonDifference(observer, target, &latdif, &londif);
145
146 if (! Target)
147 return 0;
148 if (Lat_TotalYards > Target->Lat_TotalYards){
149 latdif = Lat_TotalYards - Target->Lat_TotalYards;
150 }
151 else{
152 latdif = Target->Lat_TotalYards - Lat_TotalYards;
153 }
154
155 if (Lon_TotalYards > Target->Lon_TotalYards){
156 londif = Lon_TotalYards - Target->Lon_TotalYards;
157 }
158 else{
159 londif = Target->Lon_TotalYards - Lon_TotalYards;
160 }
161
162 if ((Lon_TotalYards < Target->Lon_TotalYards) &&
163 (Lat_TotalYards < Target->Lat_TotalYards)){
164 bearing = (360 - ((atan(latdif / londif) * 360) / 6.28318530717958647692));
165 }
166 else if ((Lon_TotalYards < Target->Lon_TotalYards) &&
167 (Lat_TotalYards > Target->Lat_TotalYards)){
168 bearing = (0 + ((atan(latdif / londif) * 360) / 6.28318530717958647692));
169 }
170 else if ((Lon_TotalYards > Target->Lon_TotalYards) &&
171 (Lat_TotalYards < Target->Lat_TotalYards)){
172 bearing = (180 + ((atan(latdif / londif) * 360) / 6.28318530717958647692));
173 }
174 else if ((Lon_TotalYards > Target->Lon_TotalYards) &&
175 (Lat_TotalYards > Target->Lat_TotalYards)){
176 bearing = (180 - ((atan(latdif / londif) * 360) / 6.28318530717958647692));
177 }
178 if (londif == 0){
179 if (Lat_TotalYards > Target->Lat_TotalYards){
180 bearing = 90;
181 }else{
182 bearing = 270;
183 }
184 }
185 if (latdif == 0){
186 if (Lon_TotalYards > Target->Lon_TotalYards){
187 bearing = 180;
188 }else{
189 bearing = 0;
190 }
191 }
192 return bearing;
193 }
194
195
BearingToOrigin(Submarine * Target)196 double Submarine::BearingToOrigin(Submarine *Target)
197 {
198 double latdif=0, londif=0, bearing = 0; //atan() needs doubles
199 //LatLonDifference(observer, target, &latdif, &londif);
200
201 if (! Target)
202 return 0;
203 if (Lat_TotalYards > Target->origin_x){
204 latdif = Lat_TotalYards - Target->origin_x;
205 }
206 else{
207 latdif = Target->origin_x - Lat_TotalYards;
208 }
209
210 if (Lon_TotalYards > Target->origin_y){
211 londif = Lon_TotalYards - Target->origin_y;
212 }
213 else{
214 londif = Target->origin_y - Lon_TotalYards;
215 }
216
217 if ((Lon_TotalYards < Target->origin_y) &&
218 (Lat_TotalYards < Target->origin_x)){
219 bearing = (360 - ((atan(latdif / londif) * 360) / 6.28318530717958647692));
220 }
221 if ((Lon_TotalYards < Target->origin_y) &&
222 (Lat_TotalYards > Target->origin_x)){
223 bearing = (0 + ((atan(latdif / londif) * 360) / 6.28318530717958647692));
224 }
225 if ((Lon_TotalYards > Target->origin_y) &&
226 (Lat_TotalYards < Target->origin_x)){
227 bearing = (180 + ((atan(latdif / londif) * 360) / 6.28318530717958647692));
228 }
229 if ((Lon_TotalYards > Target->origin_y) &&
230 (Lat_TotalYards > Target->origin_x)){
231 bearing = (180 - ((atan(latdif / londif) * 360) / 6.28318530717958647692));
232 }
233
234 if (londif == 0){
235 if (Lat_TotalYards > Target->origin_x){
236 bearing = 90;
237 }else{
238 bearing = 270;
239 }
240 }
241 if (latdif == 0){
242 if (Lon_TotalYards > Target->origin_y){
243 bearing = 180;
244 }else{
245 bearing = 0;
246 }
247 }
248 return bearing;
249
250 }
251
252
253
DistanceToTarget(Submarine * Target)254 double Submarine::DistanceToTarget(Submarine *Target){
255 double latdif = 0, londif = 0; //sqrt needs doubles
256 //LatLonDifference( observer, target, &latdif, &londif );
257
258 if (! Target)
259 return 0;
260
261 if (Lat_TotalYards > Target->Lat_TotalYards){
262 latdif = Lat_TotalYards - Target->Lat_TotalYards;
263 }
264 else{
265 latdif = Target->Lat_TotalYards - Lat_TotalYards;
266 }
267
268 if (Lon_TotalYards > Target->Lon_TotalYards){
269 londif = Lon_TotalYards - Target->Lon_TotalYards;
270 }
271 else{
272 londif = Target->Lon_TotalYards - Lon_TotalYards;
273 }
274 return sqrt((latdif * latdif) + (londif * londif));
275 }
276
DEAngle(Submarine * Target)277 float Submarine::DEAngle(Submarine *Target){
278 double distance = 0.0;
279 int depthDifference = 0;
280 double deang = 0.0;
281
282 distance = DistanceToTarget(Target);
283
284 if (Depth < Target->Depth){
285 depthDifference = (int)(Target->Depth - Depth);
286 }else{
287 depthDifference = (int)(Depth - Target->Depth);
288 }
289
290 if (depthDifference != 0) depthDifference = depthDifference * 3;
291
292 if (distance > depthDifference){
293 deang = (atan(distance / depthDifference) * 360) / 6.283185307179;
294 }else{
295 deang = (atan(depthDifference / distance) * 360) / 6.283185307179;
296 }
297
298 if (Depth > Target->Depth){
299 deang = 90.0 - deang;
300 }else{
301 deang = deang - 90.0;
302 }
303
304 return (float)deang;
305
306 }
307
308
309
Handeling()310 void Submarine::Handeling(){
311
312 // This is where we change the ships characteristics
313 // based on the desired variables
314 // First we'll do depth
315
316 // float UpBubble; //The greater the amount the faster the change.
317 // float DownBubble;
318 float AmountOfChange; //How much to turn the boat.
319 float temp_speed = Speed;
320 float delta_depth = 0.0;
321
322 if (temp_speed < 0)
323 temp_speed = -temp_speed;
324 // keep desired depth sane
325 if (DesiredDepth < 0)
326 DesiredDepth = 0;
327 else if (DesiredDepth > MaxDepth)
328 DesiredDepth = MaxDepth;
329
330 delta_depth = temp_speed * PLANES_CHANGE;
331 if (delta_depth < 1.0)
332 delta_depth = 1.0;
333 else if (delta_depth > 5.0)
334 delta_depth = 5.0;
335 if (ShipType == TYPE_TORPEDO)
336 delta_depth *= 2.0;
337
338 if (DesiredDepth > Depth){ //Do we need to go up?
339 // UpBubble = 0.05; //5% up bubble if we're close
340 // if ((DesiredDepth - Depth) > 20){
341 // UpBubble = 0.1; //10% Up Bubble
342 // }
343 // UpBubble *= 4;
344 // Depth += ((temp_speed * PLANES_CHANGE) * UpBubble); //feet per second @ 1kt = 0.185
345 Depth += delta_depth;
346 if (Depth > DesiredDepth){ //if we have risen past the desired depth
347 Depth = DesiredDepth; //Flatten us out
348 }
349 }
350
351 if (DesiredDepth < Depth){ //Do we need to go down?
352 // DownBubble= 0.05; //5% Down Bubble if we're close
353 // if ((Depth - DesiredDepth) >20){
354 // DownBubble = 0.1; //10% down bubble
355 // }
356 // UpBubble *= 4;
357 // Depth -= ((temp_speed * PLANES_CHANGE) * DownBubble);
358 Depth -= delta_depth;
359 if (Depth < DesiredDepth){
360 Depth = DesiredDepth;
361 }
362 }
363
364 //Change Heading
365
366 // AmountOfChange = (Rudder * Speed) * 0.012;
367 AmountOfChange = (Rudder * temp_speed) * RUDDER_CHANGE;
368 #ifdef DEBUG
369 printf("Rudder change %f\n", AmountOfChange);
370 #endif
371 if (Heading > DesiredHeading){
372 if ((Heading - DesiredHeading) < 180){
373 Heading = Heading - AmountOfChange;
374 if ((Heading < DesiredHeading) &&
375 ((DesiredHeading - Heading) < AmountOfChange)){
376 Heading = (float)DesiredHeading;
377 }
378 }
379 else{
380 Heading = Heading + AmountOfChange;
381 if ((Heading > DesiredHeading) &&
382 ((Heading - DesiredHeading) < AmountOfChange)){
383 Heading = (float)DesiredHeading;
384 }
385 }
386 }
387 else{
388 if (Heading < DesiredHeading){
389 if ((DesiredHeading - Heading) < 180){
390 Heading += AmountOfChange;
391 if ((Heading > DesiredHeading) &&
392 ((Heading - DesiredHeading) < AmountOfChange)){
393 Heading = (float)DesiredHeading;
394 }
395 }
396 else{
397 Heading = Heading - AmountOfChange;
398 if ((Heading < DesiredHeading) &&
399 ((DesiredHeading - Heading) < AmountOfChange)){
400 Heading = (float)DesiredHeading;
401 }
402 }
403 }
404 }
405
406 if (Heading > 360){
407 Heading = Heading - 360.0;
408 }
409 else{
410 if (Heading < 0){
411 Heading = Heading + 360.0;
412 }
413 }
414
415 // Change Speed
416
417 if(DesiredSpeed > MaxSpeed) DesiredSpeed = MaxSpeed;
418 if(DesiredSpeed < MinSpeed) DesiredSpeed = MinSpeed;
419 if (DesiredSpeed > Speed){ //Speed Up
420 Speed += 0.45; //a little less than 1/2 a knot per second..
421 if (Speed > DesiredSpeed) Speed = DesiredSpeed; // Did we go past target speed?
422 }
423
424 if (Speed > DesiredSpeed){ //Slow Down
425 Speed -= 0.45;
426 if (Speed < DesiredSpeed) Speed=DesiredSpeed; // Did we slow too much?
427 }
428
429 }
430
431
432
433 // We can detect a new target
434 // Make sure it is on the list.
435 // Function returns TRUE on success or FALSE on error
Add_Target(Submarine * new_sub,float signal_strength)436 int Submarine::Add_Target(Submarine *new_sub, float signal_strength)
437 {
438 int add_contact, found = FALSE;
439 Target *my_target, *new_target, *last_target = NULL;
440
441 if (signal_strength == 2.0)
442 add_contact = CONTACT_WEAK;
443 else if (signal_strength == 1.0)
444 add_contact = CONTACT_WEAK;
445 else if (signal_strength == CONTACT_PING)
446 add_contact = CONTACT_WEAK;
447 else
448 add_contact = 1;
449
450 // check to see if target is already in the list
451 my_target = targets;
452 while ( (my_target) && (! found) )
453 {
454 if (my_target->sub == new_sub)
455 found = TRUE;
456 else
457 {
458 last_target = my_target;
459 my_target = (Target *) my_target->next;
460 }
461 } // end of looking for existing target
462
463 if (found)
464 {
465 if ( (signal_strength == CONTACT_PING) &&
466 (my_target->contact_strength < CONTACT_WEAK) )
467 my_target->contact_strength = CONTACT_WEAK + 2;
468 else if (signal_strength == CONTACT_PING)
469 my_target->contact_strength = my_target->contact_strength;
470 else if ( (add_contact == CONTACT_WEAK) &&
471 (my_target->contact_strength >= CONTACT_WEAK) )
472 my_target->contact_strength = my_target->contact_strength;
473 else
474 my_target->contact_strength += add_contact;
475
476 if (my_target->contact_strength > CONTACT_SOLID)
477 my_target->contact_strength = CONTACT_SOLID;
478 return TRUE;
479 }
480 else // need new contact
481 {
482 #ifdef DEBUG
483 printf("Adding new target\n");
484 #endif
485 new_target = (Target *) calloc( 1, sizeof(Target) );
486 if (! new_target)
487 return FALSE;
488 new_target->sub = new_sub;
489 new_target->contact_strength = add_contact;
490 new_target->next = NULL; // not needed, but let's be careful
491 if (last_target)
492 last_target->next = new_target;
493 else
494 targets = new_target;
495 }
496 return TRUE;
497 }
498
499
500
501 // Find and reduce a target from the list
Remove_Target(Submarine * old_sub)502 void Submarine::Remove_Target(Submarine *old_sub)
503 {
504 int found = FALSE;
505 Target *my_target;
506
507 my_target = targets;
508 while ( (! found) && (my_target) )
509 {
510 if (my_target->sub == old_sub)
511 {
512 if (my_target->contact_strength < 1)
513 Cancel_Target(old_sub);
514 else
515 my_target->contact_strength -= 2;
516 found = TRUE;
517 }
518 else
519 my_target = (Target *)my_target->next;
520 }
521 }
522
523 // Find and completely remove a target from the list
Cancel_Target(Submarine * old_sub)524 void Submarine::Cancel_Target(Submarine *old_sub)
525 {
526 int found = FALSE;
527 Target *my_target, *previous = NULL;
528
529 #ifdef DEBUG
530 printf("Removing target we can't hear.\n");
531 #endif
532 my_target = targets;
533 while ( (!found) && (my_target) )
534 {
535 if (my_target->sub == old_sub)
536 {
537 if (previous)
538 previous->next = my_target->next;
539 else // first item in the list
540 targets = (Target *) my_target->next;
541
542 my_target->next = NULL;
543 if (my_target == last_target)
544 last_target = NULL;
545 free(my_target);
546 found = TRUE;
547 }
548 else
549 {
550 previous = my_target;
551 my_target = (Target *)my_target->next;
552 }
553 }
554 }
555
556
557
558
559 // This function will let us know if a ship is on our target list
560 // Returns the signal strength if the ship exists or FALSE if it does not.
Can_Detect(Submarine * a_sub)561 int Submarine::Can_Detect(Submarine *a_sub)
562 {
563 int found = FALSE;
564 Target *my_target;
565
566 my_target = (Target *)targets;
567 while ( (my_target) && (! found) )
568 {
569 if (my_target->sub == a_sub)
570 found = TRUE;
571 else
572 my_target = (Target *)my_target->next;
573 }
574 if (found)
575 return my_target->contact_strength;
576 else
577 return FALSE;
578 }
579
580
581
582
583 // Find the next available target. Return the target
584 // pointer or NULL if no target is found
585 /*
586 Submarine *Submarine::Next_Target()
587 {
588 Target *original = last_target;
589 Target *my_target;
590
591 if (! targets)
592 {
593 last_target = NULL;
594 return NULL; // no possible targets
595 }
596 if (! original) // nothing selected before, return first item
597 {
598 last_target = targets;
599 return (Submarine *)last_target->sub;
600 }
601
602 my_target = (Target *) original->next;
603 if (my_target)
604 {
605 last_target = my_target;
606 return (Submarine *)last_target->sub;
607 }
608 else
609 {
610 last_target = targets;
611 return (Submarine *)last_target->sub;
612 }
613 }
614 */
Next_Target()615 Submarine *Submarine::Next_Target()
616 {
617 Target *original = NULL;
618 Target *my_target;
619 int found = FALSE;
620
621 // no possible targets to return
622 if (! targets)
623 {
624 last_target = NULL;
625 return NULL;
626 }
627
628 if (! last_target)
629 {
630 last_target = targets;
631 my_target = last_target;
632 }
633 else // we used to have a target
634 {
635 my_target = (Target *) last_target->next;
636 if (! my_target)
637 my_target = targets;
638 }
639
640 // starting from the last target, try to find something
641 // we can use
642 while ( (! found) && (my_target != original) )
643 {
644 #ifdef DEBUG
645 printf("Testing signal strength: %d\n", my_target->contact_strength);
646 #endif
647 if (my_target->contact_strength >= CONTACT_WEAK)
648 found = TRUE;
649 else
650 {
651 if (! original)
652 original = my_target;
653 my_target = (Target *) my_target->next;
654 if (! my_target)
655 my_target = targets;
656 }
657
658 }
659
660 if (found)
661 {
662 #ifdef DEBUG
663 printf("Returning new target.\n");
664 #endif
665 last_target = my_target;
666 return (Submarine *) my_target->sub;
667 }
668 else
669 {
670 #ifdef DEBUG
671 printf("No target found.\n");
672 #endif
673 last_target = targets;
674 return NULL;
675 }
676 }
677
678
679
680 // This function should be called right after the ship is created. It
681 // will load the ship's class specific information from the appropriate
682 // data file.
683 // The data file's format will be
684 // maxspeed maxdepth name rudder torpedoes-carried hull_strength has_sonar, PSCS class-name class-type
Load_Class(char * my_file)685 int Submarine::Load_Class(char *my_file)
686 {
687 // confirm file exists
688 if (! my_file)
689 return FALSE;
690 ifstream infile(my_file, ios::in);
691 if (! infile)
692 return FALSE;
693
694 // load data
695 infile >> MaxSpeed >> MaxDepth >> Rudder >> TorpedosOnBoard >> hull_strength >> has_sonar >> PSCS >> ClassName >> ClassType;
696 infile.close();
697 // if we carry torpedoes, we also carry noisemakers
698 NoiseMakers = TorpedosOnBoard / 2;
699 return TRUE;
700 }
701
702
703 // This function tries to load a single line from the passed file
704 // and translates the contents to the ship's mission.
705 // The function returns TRUE on success and FALSE if an
706 // error occurs.
Load_Mission(FILE * from_file)707 int Submarine::Load_Mission(FILE *from_file)
708 {
709 char line[256];
710 char *status;
711
712 if (! from_file)
713 return FALSE;
714
715 memset(line, '\0', 256);
716 status = fgets(line, 256, from_file);
717 if (status)
718 {
719 #ifndef WIN32
720 if (! strncasecmp(line, "sink", 4) )
721 mission_status = MISSION_SINK;
722 else if (! strncasecmp(line, "find", 4) )
723 mission_status = MISSION_FIND;
724 else if (! strncasecmp(line, "alive", 5) )
725 mission_status = MISSION_ALIVE;
726 else
727 mission_status = MISSION_NONE;
728 #else
729 if (! my_strncasecmp(line, "sink", 4) )
730 mission_status = MISSION_SINK;
731 else if (! my_strncasecmp(line, "find", 4) )
732 mission_status = MISSION_FIND;
733 else if (! my_strncasecmp(line, "alive", 5) )
734 mission_status = MISSION_ALIVE;
735 else
736 mission_status = MISSION_NONE;
737 #endif
738
739 if (mission_status == MISSION_ALIVE)
740 sscanf( &(line[6]), "%d", &mission_timer);
741 }
742 else // could not read line, default to none
743 mission_status = MISSION_NONE;
744
745 return TRUE;
746 }
747
748
749
750
751 // This function will attempt to manipulate a torpedo tube. We can
752 // load a torpedo into a tube, load a noisemaker, empty a tube or
753 // fire the contents of the tube.
754 // The function returns a status number based on what happened or
755 // did not happen.
Use_Tube(int action,int tube_number)756 int Submarine::Use_Tube(int action, int tube_number)
757 {
758 if ( (tube_number < 0) || (tube_number >= MAX_TUBES) )
759 return TUBE_ERROR_NUMBER;
760
761 switch (action)
762 {
763 case LOAD_TORPEDO:
764 if (TorpedosOnBoard <= 0)
765 return TUBE_ERROR_NO_TORPEDO;
766
767 if (torpedo_tube[tube_number] == TUBE_EMPTY)
768 {
769 torpedo_tube[tube_number] = TUBE_TORPEDO;
770 TorpedosOnBoard--;
771 return TUBE_ERROR_TORPEDO_SUCCESS;
772 }
773 else
774 return TUBE_ERROR_FULL;
775 break;
776 case LOAD_NOISEMAKER:
777 if (NoiseMakers <= 0)
778 return TUBE_ERROR_NO_NOISE;
779 if (torpedo_tube[tube_number] == TUBE_EMPTY)
780 {
781 torpedo_tube[tube_number] = TUBE_NOISEMAKER;
782 NoiseMakers--;
783 return TUBE_ERROR_NOISEMAKER_SUCCESS;
784 }
785 else
786 return TUBE_ERROR_FULL;
787 break;
788 case UNLOAD_TUBE:
789 if (torpedo_tube[tube_number] == TUBE_TORPEDO)
790 TorpedosOnBoard++;
791 else if (torpedo_tube[tube_number] == TUBE_NOISEMAKER)
792 NoiseMakers++;
793 torpedo_tube[tube_number] = TUBE_EMPTY;
794 return TUBE_ERROR_UNLOAD_SUCCESS;
795 case FIRE_TUBE:
796 if (torpedo_tube[tube_number] == TUBE_EMPTY)
797 return TUBE_ERROR_FIRE_FAIL;
798 else if (torpedo_tube[tube_number] == TUBE_TORPEDO)
799 {
800 torpedo_tube[tube_number] = TUBE_EMPTY;
801 return TUBE_ERROR_FIRE_SUCCESS;
802 }
803 else if (torpedo_tube[tube_number] == TUBE_NOISEMAKER)
804 {
805 torpedo_tube[tube_number] = TUBE_EMPTY;
806 return TUBE_ERROR_FIRE_NOISEMAKER;
807 }
808 break;
809
810 default:
811 return TUBE_ERROR_ACTION;
812 }
813
814 return TRUE; // this shouldn't happen, but just in case
815 }
816
817
818
819
820 // This function launches a torpedo or noise maker. If the
821 // passed target is NULL, the new torp/noisemaker is given a
822 // random course and no target, leaving it to run in a striaght line.
823 // On success the function passes back a pointer to the new torpedo
824 // and on failure NULL is returned.
Fire_Tube(Submarine * target,char * ship_file)825 Submarine *Submarine::Fire_Tube(Submarine *target, char *ship_file)
826 {
827 Submarine *my_torp;
828 my_torp = new Submarine();
829 if (! my_torp)
830 return NULL;
831
832 my_torp->Load_Class(ship_file);
833 if (target)
834 {
835 my_torp->target = target;
836 // set heading and desired depth
837 my_torp->DesiredHeading = my_torp->Heading = BearingToTarget(target);
838 my_torp->DesiredDepth = target->Depth;
839 my_torp->ShipType = TYPE_TORPEDO;
840 }
841 else // no target, noisemaker
842 {
843 my_torp->target = NULL;
844 // set random heading
845 my_torp->Heading = rand() % 360;
846 my_torp->DesiredHeading = my_torp->Heading;
847 my_torp->ShipType = TYPE_NOISEMAKER;
848 }
849 // set current position
850 my_torp->Lat_TotalYards = Lat_TotalYards;
851 my_torp->Lon_TotalYards = Lon_TotalYards;
852 // set fuel
853 my_torp->fuel_remaining = TORPEDO_FUEL;
854 // set depth
855 my_torp->Depth = Depth;
856 // set speed and desired speed
857 my_torp->Speed = Speed;
858 my_torp->DesiredSpeed = my_torp->MaxSpeed;
859 // my_torp->ShipType = TYPE_TORPEDO;
860 // my_torp->Friend = FOE;
861 my_torp->Friend = Friend;
862 my_torp->origin_x = Lat_TotalYards;
863 my_torp->origin_y = Lon_TotalYards;
864 return my_torp;
865 }
866
867
868
869 // This function lets us know if we can hear another ship/sub/
870 // It returns TRUE if we can hear it and FALSE if we can not.
Can_Hear(Submarine * target)871 int Submarine::Can_Hear(Submarine *target)
872 {
873 float Range = DistanceToTarget(target);
874 float NauticalMiles = (float)Range / 2000.0;
875 float HisPassiveSonarCrosssection = target->PSCS;
876 float EffectiveTargetSpeed;
877 float AmbientNoise;
878 float OwnShipNoise;
879 float TotalNoise;
880 float TargetNoise;
881 float Gb;
882 float Lbp;
883 float NoiseFromSpeed;
884 float BasisNoiseLevel;
885 float value;
886 float SeaState = 3.0; // Anyone want to model the weather.
887 float minimum_sound = -45.0;
888 int thermal_layers = 0;
889
890 // sanity check
891 if (! target)
892 return FALSE;
893
894 /* There is a special case here. If the listener is a surface
895 ship then they have radar. Thus the listener can always
896 detect anything on or above the surface.
897 */
898 if (ShipType == TYPE_SHIP)
899 {
900 if (target->Depth <= 0)
901 return TRUE;
902 if (target->using_radar)
903 return TRUE;
904 }
905
906 if (ShipType == TYPE_TORPEDO)
907 minimum_sound *= 2.5;
908 else if (ShipType == TYPE_SHIP)
909 minimum_sound *= 1.75;
910
911 if (target->Speed <= 5.0){
912 EffectiveTargetSpeed = 0.0;
913 }else{
914 EffectiveTargetSpeed = target->Speed - 5.0;
915 }
916
917 if (target->Speed < 20.0){
918 NoiseFromSpeed = 1.30;
919 BasisNoiseLevel = 0.0;
920 }else{
921 NoiseFromSpeed = 0.65;
922 BasisNoiseLevel = 9.75;
923 }
924 // check just in case we didn't set the map variable
925 if (map)
926 {
927 thermal_layers = map->Thermals_Between(Depth, target->Depth);
928 #ifdef DEBUGMAP
929 printf("%d thermals between ship and target\n", thermal_layers);
930 #endif
931 }
932 AmbientNoise = 89.0 + (5.0 * SeaState);
933 OwnShipNoise = RadiatedNoise();
934 TotalNoise = 10.0 * log10(pow(10.0,OwnShipNoise/10.0) + pow(10.0,AmbientNoise/10.0));
935 Gb = (TotalNoise - AmbientNoise) / 2.9;
936 Lbp = AmbientNoise + Gb;
937 TargetNoise = HisPassiveSonarCrosssection +
938 ((NoiseFromSpeed * EffectiveTargetSpeed) + BasisNoiseLevel);
939 if (target->pinging)
940 TargetNoise += PING_NOISE;
941 if (thermal_layers)
942 TargetNoise -= TargetNoise * (thermal_layers * THERMAL_FILTER);
943 value = TargetNoise - (20.0 * log10(NauticalMiles) + 1.1 * NauticalMiles) - Lbp;
944 // if (!observer)
945 // SonarStation.flowandambientnoise = (Lbp - 34);
946 if (value > minimum_sound){
947 return TRUE;
948 }else{
949 return FALSE;
950 }
951
952 }
953
954
955
956
957 // This function will simply return if we do not have a target.
958 // If we do have a target, and we can hear it, this will adjust the
959 // torpedo's desired heading and desired depth to match the target.
960 // The function returns TRUE.
Torpedo_AI(Submarine * all_subs)961 int Submarine::Torpedo_AI(Submarine *all_subs)
962 {
963 int can_hear_target = FALSE;
964 Submarine *my_sub;
965
966 // if (! target)
967 // return TRUE;
968 // Noisemakers should run at full speed in a straight line
969 if (ShipType == TYPE_NOISEMAKER)
970 return TRUE;
971
972 // check to see if we can hear the target
973 if (target)
974 can_hear_target = Can_Hear(target);
975 // aim for our target if we have one
976 if (can_hear_target)
977 {
978 DesiredHeading = BearingToTarget(target);
979 DesiredDepth = target->Depth;
980 DesiredSpeed = MaxSpeed;
981 return TRUE;
982 }
983
984 // when we delevop active sonar, that should go here
985 // as a backup to passive sonar
986
987 // we cannot hear our target, see if we can detect a new one
988 target = NULL;
989 my_sub = all_subs;
990 while ( (my_sub) && (! target) )
991 {
992 // aim for the first thing we hear
993 if ( (my_sub->Friend != Friend) && ( Can_Hear(my_sub) ) )
994 target = my_sub;
995 else
996 my_sub = my_sub->next;
997 }
998
999 // what if we can't hear any target, go into search mode
1000 if (! target)
1001 {
1002 DesiredHeading = Heading + 90;
1003 DesiredSpeed = MaxSpeed / 2;
1004 }
1005 return TRUE;
1006 }
1007
1008
1009
1010 // This function tells us what AI ships and submarines will do.
1011 // This function returns a link to all torpedoes.
Sub_AI(Submarine * all_ships,Submarine * all_torpedoes,void * helicopters)1012 Submarine *Submarine::Sub_AI(Submarine *all_ships, Submarine *all_torpedoes, void *helicopters)
1013 {
1014 int change;
1015 Submarine *torpedo;
1016 int can_hear_torpedo;
1017 double distance;
1018 int bearing;
1019 Submarine *target = NULL, *my_torpedoes;
1020 int status, found;
1021 int action = 0; // 1 = running, 2 = chasing
1022 Submarine *track_torpedo = NULL;
1023
1024 // most important thing we can do is run away from torpedoes
1025 if (has_sonar)
1026 {
1027 #ifdef AIDEBUG
1028 printf("We have sonar.\n");
1029 #endif
1030 // go through all torpedoes and see if any of them
1031 // chasing us
1032 torpedo = all_torpedoes;
1033 status = FALSE; // make sure we only run away form one torpedo
1034 while ( (torpedo) && (! status) )
1035 {
1036 if (torpedo->ShipType == TYPE_TORPEDO)
1037 {
1038 can_hear_torpedo = Can_Hear(torpedo);
1039 distance = DistanceToTarget(torpedo);
1040 // if we can hear a torpedo, it is close and it is aimed at us
1041 // then we run
1042 if ( (can_hear_torpedo) && (torpedo->target == this) &&
1043 (distance < (MAX_TORPEDO_RANGE * MILES_TO_YARDS) ) )
1044 {
1045 // status = (DesiredSpeed == MaxSpeed);
1046 all_torpedoes = Launch_Noisemaker(all_torpedoes, torpedo);
1047 bearing = (int) BearingToTarget(torpedo);
1048 bearing += 180;
1049 if (bearing >= 360)
1050 bearing = bearing % 360;
1051 DesiredHeading = bearing;
1052 DesiredSpeed = MaxSpeed;
1053 // subs can dive too
1054 if (ShipType == TYPE_SUB)
1055 {
1056 if (torpedo->Depth <= Depth) // it is above us
1057 DesiredDepth = MaxDepth;
1058 else if (torpedo->Depth > Depth) // below us
1059 DesiredDepth = PERISCOPE_DEPTH;
1060 }
1061 if (mood == MOOD_CONVOY)
1062 mood = MOOD_PASSIVE;
1063 // if (! status)
1064 // return all_torpedoes;
1065 action = 1; // running
1066 status = TRUE;
1067 }
1068 // we hear a torpedo but it is not coming after us
1069 else if ( (can_hear_torpedo) && (TorpedosOnBoard) )
1070 {
1071 if (ShipType == TYPE_SHIP)
1072 mood = MOOD_ATTACK;
1073 // if we are not tracking anything, check out the torp
1074 if ( (! track_torpedo) && (torpedo->Friend != Friend) )
1075 {
1076 #ifdef AIDEBUG
1077 printf("Found torpedo to track.\n");
1078 #endif
1079 track_torpedo = torpedo;
1080 }
1081 }
1082
1083 if ( (can_hear_torpedo) && (ShipType == TYPE_SHIP) )
1084 Radio_Signal(all_ships, RADIO_HEAR_TORPEDO);
1085
1086 } // end of this is a torpedo
1087 torpedo = torpedo->next;
1088 } // end of checking out torpedoes in the water
1089
1090 #ifdef AIDEBUG
1091 printf("Checking for targets.\n");
1092 #endif
1093 // see if we can hear a nearby enemy to shoot at
1094 target = Have_Enemy_Target(all_ships);
1095 #ifdef AIDEBUG
1096 if (target) printf("Found enemy.\n");
1097 #endif
1098 int count = Count_Torpedoes(all_torpedoes);
1099 if ( (target) && (TorpedosOnBoard > 0) )
1100 // (count < MAX_TORPEDOES_FIRED) )
1101 {
1102 int target_range = DistanceToTarget(target);
1103 int shooting_range;
1104 // we shoot at different distances, depending on mood
1105 if (mood == MOOD_ATTACK)
1106 shooting_range = TORPEDO_RANGE_ATTACK;
1107 else
1108 shooting_range = TORPEDO_RANGE_PASSIVE;
1109 shooting_range += (rand() % 3) - 2; // add some randomness
1110 target_range *= YARDS_TO_MILES;
1111 #ifdef AIDEBUG
1112 printf("Checking range %d\n", target_range);
1113 #endif
1114 if ( (count < MAX_TORPEDOES_FIRED) &&
1115 (target_range < shooting_range) )
1116 {
1117 #ifdef AIDEBUG
1118 printf("Firing with %d torpedoes.\n", count);
1119 #endif
1120 torpedo_tube[0] = TUBE_TORPEDO;
1121 status = Use_Tube(FIRE_TUBE, 0);
1122 if (status == TUBE_ERROR_FIRE_SUCCESS)
1123 {
1124 char *ship_file, filename[] = "ships/class5.shp";
1125 ship_file = Find_Data_File(filename);
1126 torpedo = Fire_Tube(target, ship_file );
1127 if ( (ship_file) && (ship_file != filename) )
1128 free(ship_file);
1129 if (torpedo)
1130 {
1131 #ifdef AIDEBUG
1132 printf("Successfully fired torpedo.\n");
1133 #endif
1134 torpedo->Friend = Friend;
1135 torpedo->owner = this;
1136 // all_torpedoes = Add_Ship(all_torpedoes, torpedo);
1137 // add torpedo to linked list
1138 if (! all_torpedoes)
1139 all_torpedoes = torpedo;
1140 else
1141 {
1142 my_torpedoes = all_torpedoes;
1143 found = FALSE;
1144 while ( (! found) && (my_torpedoes) )
1145 {
1146 if (my_torpedoes->next)
1147 my_torpedoes = my_torpedoes->next;
1148 else
1149 {
1150 my_torpedoes->next = torpedo;
1151 found = TRUE;
1152 // return all_torpedoes;
1153 }
1154 }
1155 } // add torpedo to list
1156 }
1157 TorpedosOnBoard--;
1158 #ifdef AIDEBUG
1159 printf("I have %d torpedoes left.\n", TorpedosOnBoard);
1160 #endif
1161 return all_torpedoes;
1162 } // torpedo firing was successful
1163 } // can fire torpedo at target in range
1164
1165 // we hear an enemy, but can't fire yet
1166 else if ( (mood == MOOD_ATTACK) && (! action) )
1167 {
1168 DesiredHeading = BearingToTarget(target);
1169 if (ShipType == TYPE_SHIP)
1170 DesiredSpeed = (MaxSpeed / 2) + (rand() % 5) - 2;
1171 else // sub
1172 DesiredSpeed = (MaxSpeed / 3) + (rand() % 3) + 1;
1173 if (ShipType == TYPE_SUB)
1174 {
1175 DesiredDepth = target->Depth;
1176 if (DesiredDepth < PERISCOPE_DEPTH)
1177 DesiredDepth = PERISCOPE_DEPTH;
1178 }
1179 action = 2;
1180 }
1181 } // end of we have a target and we have torpedoes on board
1182
1183 // we are not tracking anything, but we have torpedoes
1184 // and we can hear a torpedo
1185 // move toward the origin of the torpedo we hear
1186 else if ( (TorpedosOnBoard > 0) && (track_torpedo) && (!action) )
1187 {
1188 #ifdef AIDEBUG
1189 printf("We hear a torpedo, tracking it.\n");
1190 printf("We should probably only chase torpedoes if in attack mood\n");
1191 #endif
1192 DesiredHeading = BearingToOrigin(track_torpedo);
1193 if (ShipType == TYPE_SUB)
1194 DesiredDepth = track_torpedo->Depth;
1195 }
1196 // We have no target and no torpedo to follow
1197 // if we are in attack mood we should slow down
1198 // so we can hear better
1199 else if ( (! action) && (!target) && (mood == MOOD_ATTACK) )
1200 {
1201 DesiredSpeed = (MaxSpeed / 3) + ( ( rand() % 5 ) - 3 );
1202 }
1203
1204
1205 // if we got this far we cannot hear a torpedo coming at us
1206 if ( (Speed == MaxSpeed) && (! action) )
1207 DesiredSpeed = MaxSpeed / 3;
1208 } // I think this is the end of "we have sonar" section
1209
1210 // helicopters should go low if there are helicopters
1211 if ( (ShipType == TYPE_SUB) && (helicopters) )
1212 {
1213 if (Depth < map->thermals[0])
1214 DesiredDepth = map->thermals[0] + 25;
1215 }
1216
1217 // when traveling in convoy, we change course once every
1218 // ... twenty minutes?
1219 if (mood == MOOD_CONVOY)
1220 {
1221 convoy_course_change--;
1222 if (! convoy_course_change)
1223 {
1224 convoy_course_change = CONVOY_CHANGE_COURSE;
1225 DesiredHeading += 90;
1226 if (DesiredHeading >= 360)
1227 DesiredHeading = DesiredHeading % 360;
1228 }
1229 }
1230 else // got nothing to do, but perhaps change course
1231 {
1232 change = rand() % CHANCE_COURSE;
1233 if (! change)
1234 {
1235 DesiredHeading = Heading + ( (rand() % 100) - 90);
1236 if (DesiredHeading >= 360)
1237 DesiredHeading = DesiredHeading % 360;
1238 DesiredSpeed = MaxSpeed / 3;
1239 // submarines should change depth too
1240 if (ShipType == TYPE_SUB)
1241 {
1242 DesiredDepth =+ rand() % 200;
1243 DesiredDepth /= 2;
1244 DesiredDepth += PERISCOPE_DEPTH;
1245 // DesiredDepth = ( (rand() % MaxDepth) / 2 ) + 50;
1246 }
1247 }
1248 }
1249
1250 // check for radio message
1251 if ( (ShipType == TYPE_SHIP) && (radio_message) )
1252 {
1253 if ( (radio_message == RADIO_UNDER_ATTACK) && (mood == MOOD_CONVOY) )
1254 {
1255 if (TorpedosOnBoard)
1256 mood = MOOD_ATTACK;
1257 else
1258 {
1259 mood = MOOD_PASSIVE;
1260 DesiredHeading = rand() % 360;
1261 }
1262 DesiredSpeed = MaxSpeed;
1263 }
1264 else if ( (radio_message == RADIO_HEAR_TORPEDO) && (mood == MOOD_CONVOY) )
1265 {
1266 if (TorpedosOnBoard)
1267 mood = MOOD_ATTACK;
1268 else
1269 mood = MOOD_PASSIVE;
1270 }
1271 }
1272 radio_message = RADIO_NONE;
1273 if ( (ShipType == TYPE_SUB) && (Depth < PERISCOPE_DEPTH) )
1274 DesiredDepth = PERISCOPE_DEPTH;
1275 return all_torpedoes;
1276 } // end of Sub_AI
1277
1278
1279
1280
1281 // This function checks on our torpedo to see how it
1282 // is doing. If it has hit its target, we return HIT_TARGET.
1283 // If we run out of fuel, we return OUT_OF_FUEL. Otherwise
1284 // we return STATUS_OK.
1285 // This function just checks status changes, it doesn't do
1286 // anything about them.
Check_Status()1287 int Submarine::Check_Status()
1288 {
1289 double range;
1290 double delta_depth;
1291
1292 // first see if we ran out of fuel
1293 fuel_remaining--;
1294 if (fuel_remaining < 1)
1295 return OUT_OF_FUEL;
1296
1297 if (target)
1298 {
1299 range = DistanceToTarget(target);
1300 delta_depth = fabs(target->Depth - Depth);
1301 if ( (range < HITTING_RANGE) && (delta_depth < HITTING_DEPTH) )
1302 {
1303 char *full_path, *explosion = "sounds/explosion.ogg";
1304 full_path = Find_Data_File(explosion);
1305 Play_Sound(full_path);
1306 if ( (full_path) && (explosion) )
1307 free(full_path);
1308
1309 return HIT_TARGET;
1310 }
1311 }
1312
1313 return STATUS_OK;
1314 }
1315
1316
1317
1318 // This function reduces the remaining strength of the ship's hull.
1319 // If the ship/sub can still float, we return DAMAGE_OK, but if
1320 // the ship is sinking, we return DAMAGE_SINK.
1321 // If the ship sinks, we set Active to FALSE.
Take_Damage()1322 int Submarine::Take_Damage()
1323 {
1324 hull_strength--;
1325 if (hull_strength < 1)
1326 {
1327 Active = FALSE;
1328 return DAMAGE_SINK;
1329 }
1330 else
1331 return DAMAGE_OK;
1332 }
1333
1334
1335
1336 // This function counts how many torpedoes we have active
1337 // in the water (that we fired).
Count_Torpedoes(Submarine * all_torp)1338 int Submarine::Count_Torpedoes(Submarine *all_torp)
1339 {
1340 int count = 0;
1341 Submarine *torp = all_torp;
1342
1343 while (torp)
1344 {
1345 if ( (torp->owner == this) && (torp->ShipType == TYPE_TORPEDO) )
1346 count++;
1347 torp = torp->next;
1348 }
1349 #ifdef DEBUG
1350 printf("We have %d TORPEDOES in the water\n", count);
1351 #endif
1352 return count;
1353 }
1354
1355
1356 // This function counts how many noisemakers we have in the water
Count_Noisemakers(Submarine * all_noise)1357 int Submarine::Count_Noisemakers(Submarine *all_noise)
1358 {
1359 int count = 0;
1360 Submarine *noise = all_noise;
1361
1362 while (noise)
1363 {
1364 if ( (noise->owner == this) && (noise->ShipType == TYPE_NOISEMAKER) )
1365 count++;
1366 noise = noise->next;
1367 }
1368 #ifdef DEBUG
1369 printf("We have %d NOISEMAKERS in the water\n", count);
1370 #endif
1371 return count;
1372 }
1373
1374
1375
1376 // This function checks the list of ships to see if we have any enemies
1377 // to shoot at.
1378 // To get results, we must have torpedoes on board,
1379 // We must be able to hear them clearly.
1380 // They must be an enemy (Friend must be opposite of our FOE or FRIEND).
1381 // In the case of multiple matches, the closest target is returned.
Have_Enemy_Target(Submarine * all_ships)1382 Submarine *Submarine::Have_Enemy_Target(Submarine *all_ships)
1383 {
1384 Submarine *current, *min = NULL;
1385 int current_distance, min_distance = INT_MAX;
1386 int making_noise;
1387
1388 // can we shoot?
1389 if (TorpedosOnBoard < 1)
1390 return NULL;
1391 // do we even have enemies?
1392 if ( (Friend != FRIEND) && (Friend != FOE) )
1393 return NULL;
1394
1395 current = all_ships;
1396 while (current)
1397 {
1398 if ( ( (current->Friend == FOE) && (Friend == FRIEND) ) ||
1399 ( (current->Friend == FRIEND) && (Friend == FOE) ) )
1400 {
1401 #ifdef AIDEBUG
1402 printf("Examining enemy ship.\n");
1403 #endif
1404 // we do not like this ship, are they closer than our current min?
1405 current_distance = DistanceToTarget(current);
1406 if (current_distance < min_distance)
1407 {
1408 #ifdef AIDEBUG
1409 printf("Within range to become target.\n");
1410 #endif
1411 // they are close, can we hear them?
1412 making_noise = Can_Hear(current);
1413 if (making_noise)
1414 {
1415 #ifdef AIDEBUG
1416 printf("We can hear this ship. Make it the target.\n");
1417 #endif
1418 min = current;
1419 min_distance = current_distance;
1420 // if the target is hostile and pinging, and
1421 // we are in a convoy, switch to attack mood
1422 if ( (current->pinging) && (mood == MOOD_CONVOY) )
1423 mood = MOOD_ATTACK;
1424
1425 }
1426 }
1427 }
1428 current = current->next;
1429 }
1430 return min;
1431 }
1432
1433
1434
1435
1436 // This function is only to be used by the AI. Here we assume
1437 // we are being chased by a torpedo. We check to see how many
1438 // noisemakers we have in the water. If it is less than the max
1439 // number, we launch a noisemaker.
1440 // This function returns a pointer to all torpedoes/noisemakers
Launch_Noisemaker(Submarine * all_noisemakers,Submarine * chased_by)1441 Submarine *Submarine::Launch_Noisemaker(Submarine *all_noisemakers, Submarine *chased_by)
1442 {
1443 int existing_noisemakers;
1444 Submarine *new_noisemaker = NULL, *my_noise;
1445 int status, found;
1446
1447 if ( (! chased_by) || (! all_noisemakers) )
1448 return NULL; // shouldn't happen, but just in case
1449
1450 // do we have a noisemaker?
1451 if (NoiseMakers < 1)
1452 return all_noisemakers;
1453
1454 // see if we are allowed to fire any more
1455 existing_noisemakers = Count_Noisemakers(all_noisemakers);
1456 if (existing_noisemakers >= MAX_NOISEMAKERS_FIRED)
1457 return all_noisemakers;
1458
1459 // we are allowd to launch one
1460 torpedo_tube[0] = TUBE_NOISEMAKER;
1461 status = Use_Tube(FIRE_TUBE, 0);
1462 if (status == TUBE_ERROR_FIRE_NOISEMAKER)
1463 {
1464 char *ship_file, filename[] = "ships/class6.shp";
1465 ship_file = Find_Data_File(filename);
1466 new_noisemaker = Fire_Tube(NULL, ship_file );
1467 if ( (ship_file) && (ship_file != filename) )
1468 free(ship_file);
1469 if (new_noisemaker)
1470 {
1471 new_noisemaker->Friend = Friend;
1472 new_noisemaker->owner = this;
1473 if (! all_noisemakers)
1474 all_noisemakers = new_noisemaker;
1475 else
1476 {
1477 my_noise = all_noisemakers;
1478 found = FALSE;
1479 while ( (!found) && (my_noise) )
1480 {
1481 if (my_noise->next)
1482 my_noise = my_noise->next;
1483 else
1484 {
1485 my_noise->next = new_noisemaker;
1486 found = TRUE;
1487 // return all_noisemakers;
1488 }
1489 }
1490 } // end of add noisemaker to list
1491 } // created new noisemaker
1492 } // status
1493 NoiseMakers--;
1494 if (new_noisemaker)
1495 {
1496 new_noisemaker->DesiredHeading = chased_by->DesiredHeading;
1497 chased_by->Is_Distracted_By_Noisemaker(new_noisemaker);
1498 }
1499 return all_noisemakers;
1500 }
1501
1502
1503
1504
1505 // This function checks to see if the torpedo will get distracted
1506 // by a given noisemaker
1507 // Returns TRUE if distracted and FALSE if not. In the case where
1508 // the torpedo is distracted, its target variable is reset
1509 // to chase the noisemaker
Is_Distracted_By_Noisemaker(Submarine * noisemaker)1510 int Submarine::Is_Distracted_By_Noisemaker(Submarine *noisemaker)
1511 {
1512 int chance;
1513
1514 if (! noisemaker) // this should not happen, but just in case
1515 return FALSE;
1516
1517 chance = rand() % DISTRACTED_CHANCE;
1518 if (! chance)
1519 {
1520 target = noisemaker;
1521 return TRUE;
1522 #ifdef DEBUG
1523 printf("Torpedo going off course to chase noisemaker.\n");
1524 #endif
1525 }
1526
1527 #ifdef DEBUG
1528 printf("Torpedo was not distracted by noisemaker.\n");
1529 #endif
1530 return FALSE;
1531 }
1532
1533
1534
1535 // This function sends a radio signal to all other ships of the same
1536 // nationality.
1537 // The function returns TRUE
Radio_Signal(Submarine * all_ships,int my_signal)1538 int Submarine::Radio_Signal(Submarine *all_ships, int my_signal)
1539 {
1540 Submarine *current_ship;
1541
1542 current_ship = all_ships;
1543 while (current_ship)
1544 {
1545 if ( (current_ship->Friend == Friend) &&
1546 (current_ship->ShipType == TYPE_SHIP) )
1547 current_ship->radio_message = my_signal;
1548
1549 current_ship = current_ship->next;
1550 }
1551
1552 return TRUE;
1553 }
1554
1555
1556 // This function sends out a ping signal. We should then be
1557 // able to "see" any ships/subs in front of us.
1558 // This function does not detect aircraft (for obvious reasons)
1559 // and sets "pinging" to true, which means we will be very
1560 // noisy for a while.
Send_Ping(Submarine * all_ships)1561 int Submarine::Send_Ping(Submarine *all_ships)
1562 {
1563 Submarine *current;
1564 int status;
1565 char *full_path, *ping_file = "sounds/sonar-ping.ogg";
1566 // some craft do not have sonar
1567 if (! has_sonar)
1568 return FALSE;
1569
1570 full_path = Find_Data_File(ping_file);
1571 Play_Sound(full_path);
1572 if ( (full_path) && (full_path != ping_file) )
1573 free(full_path);
1574
1575 pinging = 2;
1576 current = all_ships;
1577 while (current)
1578 {
1579 if (current != this)
1580 {
1581 status = ! ( InBaffles(current, 1, NULL) );
1582 if (status)
1583 {
1584 // got return signal from ping
1585 Add_Target(current, CONTACT_PING);
1586
1587 }
1588 }
1589 current = current->next;
1590 }
1591
1592 return TRUE;
1593 }
1594
1595
1596
1597 /*********************************************
1598 This function will return if a target is in
1599 the observers Baffles and therefore not
1600 detectable. Values for 'int sensor' are 1 for
1601 spherical array, 2 for towed array, 3 for port
1602 hull array and 4 for starboard hull array.
1603
1604 Might want to move the calculations of the
1605 baffle angles to the Coord class so they don't
1606 have to be calculated all the time.
1607 *********************************************/
InBaffles(Submarine * target,int sensor,TowedArray * TB16)1608 int Submarine::InBaffles(Submarine *target, int sensor, TowedArray *TB16)
1609 {
1610 int array_heading;
1611 int relative_bearing;
1612 int sensordeaf=1;
1613 int bearing_to_target;
1614
1615 switch(sensor){
1616 case 1: //Spherical
1617 sensordeaf = 0;
1618 array_heading = (int)Heading;
1619 bearing_to_target = (int)BearingToTarget( target);
1620 if(array_heading > bearing_to_target) bearing_to_target += 360;
1621 relative_bearing = bearing_to_target - array_heading;
1622 if(relative_bearing > 150 && relative_bearing < 210) sensordeaf = 1;
1623 if (target == this) sensordeaf = 1;
1624 break;
1625 case 2: //Towed
1626 if (! TB16)
1627 sensordeaf = TRUE;
1628 else
1629 {
1630 sensordeaf = 0;
1631 array_heading = (int)TB16->ReturnHeading();
1632 bearing_to_target = (int)TB16->BearingToTarget(target->Lat_TotalYards, target->Lon_TotalYards);
1633 if(array_heading > bearing_to_target) bearing_to_target += 360;
1634 relative_bearing = bearing_to_target - array_heading;
1635 if(relative_bearing < 30 || relative_bearing > 330) sensordeaf = 1;
1636 }
1637 break;
1638
1639 case 3: //port hull
1640 case 4: //sb hull
1641 default:
1642 break;
1643 }
1644 return sensordeaf;
1645 }
1646
1647