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