/*--------------------------------------------------------
  RADAR.C -                                                                   
  	purpose, simulate a radar Nike Hercules missile game in Windows
  		using keyboard (Fn keys), mouse inputs, also special i/o boards
  		which can do analog i/o and logic i/o  
    				
  	---------------------------------
  	---------------------------------
  	ManMachineInterface
  	Outputs to human
  	Function		note
  	--------		----
  	Missile Launched Lamp (on Launch Panel)	---------(a)
  	Missile Speed Meter (was Missile Ground Speed)	-----	(b)
  	PPI display (CRT)	--------------------	(c)
  			- Designate Circle
  			- Tracked Target (Target Tracking Radar)
  			- IFF
  			- Missile 
  			- Predicted Point of Intercept
  	Range of Designate Circle Meter (on Designate Panel)	--(d)
  	Target Altitude	Meter	------------------(e)
  	Target Ground Speed	Meter	----------------	(f)
  	Time to Predicted Intercept	---------------	(g)
  		
    Control inputs
    Function		keyboard		other			note
    ----------		--------		-----			----
	About the program	
									A,a      
	Alert Status	----------------------	(1)
                    light in van
	Command Missile Burst	------------------(2)
		B,b				switch on cmd
	Designate Target (near select circle)	----------	(3)
		D,d			switch on az
	Evasive Action by any designated target	--------	(4)
	                     E = on, e = off     switch on PPI  
	Fast time on missile in flight	-------------	(5)
 			F = on, f = off
  	History, StorageDisplayMode	---------------	(6)
			H = on, h = off			switch on PPI
	IFF (Identification Friend or Foe)( friend has 3 lines)	-	(7)
			I = on, i = off			switch in PPI
	Keyboard Inputs	---------------------	(8)
		K - keyboard only	(no external inputs)
		k -	also input from pots and switches  
	Launch a Hercules missile (must be in red alert)	----	(9)
		L,l				switch on cmd
	Move Designate Circle	------------------	(10)
		<,^,>,v (arrows)    pots in az system
	New Targets if less than 3 (starts east about 150,000 yd)	(11)
		N - on, n = off			switch on PPI
      PPI Display Range   	          PPI switch	---(12)
    		3 = 350,000 yards
		2 = 250,000 yards
		1 = 150,000 yards 
		0 =  50,000 yards                          
	Quit, go back to DOS
	          Q,q									no switch
	Restart (red alert, new planes, etc.)	----------	(13)
		R,r									switch on heater 
	Speed radar RPM sweep	(ignored, always fast)	------(14)
   	Text, current event recorder data	-----------	-	(15)
   		T = yes,t = no			switch on PPI
	WarGame - automatic threat response	----------- (16)
   	      W = on, w = off			switch on heater


				
	-------------------------------------------------------------
	Notes                                                          
	(a)	Missile Launched Lamp (on Launch Panel)			
		- uses van -24 volt power supply as energy source
		CO_3	
		current return to power supply

		
  	(b) Missile Speed Meter (was Missile Ground Speed)
		- missile speed through air, not ground speed
  			(this was chosen to give feel of quick boost)
  		DAC_2 
  						
  		meter return
  					
	(c) PPI display (CRT)	- 14" VGA emulation of radial electrostatic
		VGA cable from computer to PPI 
  		- Point Radar reflection  (like airplane)            
  			- small arc (about 2 degrees, less at long range)
  			- details
  			spread wide due to radar beam width 
  				about 2 degrees (effectively wider on strong echos)
  				spread deep due to length of radar pulse (1 microsecond)
  					(167 yards per microsecond pulse length)
  			- ground clutter  (Moving Target Indicator (MTI) not emulated)
  			 (no MTI gives better feel of local and  range)
  			- local clutter as bright spot in center		                                       
  			- to west,  Farallon islands
  			- to north, coast to Point Reyes
  			-	to east,  Angel Island and Oakland coast
  			- to south, coast to Half Moon Bay
  			- Designate Circle
  			- Tracked Target (Target Tracking Radar)
  			- radial line, if with target, looks like a cross
  		- IFF
				shown as fixed, unchopped 3 bar code
  		- Missile (normally not shown on PPI, 
  			shown as "x" since plotting boards not connected)
  		- Predicted Point of Intercept (normally not shown on PPI,
  			shown as "#" since plotting boards not connected)
		
		
	(d) Range of Designate Circle Meter (on Designate Panel)
		- feed back to operator about distance of Circle
		DAC_3
				
		meter return
		
		
  	(e)	Target Altitude	Meter
		- shown (instead of missiles) since plotting boards
  							are not connected
  			DAC_4 
  							
				meter return
				  							
  	(f)	Target Ground Speed	Meter	
  			DAC_1 - 
  			
  			meter return
  			
  	(g)	Time to Predicted Intercept	
  			- shown in strange meter since plotting boards are
  							not connected
  			DAC_7 
  							
				meter return  							
		
		
		
		(1)	Alert Status	
				computer reads RED ALERT lamp in van, MUST be RED to launch
				CI_1
				
				Switch ground      
				
				
		(2) Command Missile Burst
			 	causes missile to be eliminated
				and status to be pre-launch 				
				CI_6	- on Switch Panel
										
				switch ground
		
		
		(3)  Designate Target (near select circle) 
					CI_4	- on azimuth handle  
					
					switch ground
		
		
		(4)  Evasive Action by any designated target
		     causes any designated target to "randomly" 
		     		change yaw acceleration. 		(normally 0 g's)
		     This is usually an advantage to an aircraft formation
		     		1) causes longer missile flight times and
		     				reduces the number of targets which 
		     				can be attacked in a given time.
		     	  2) if an almost out-of-range but incoming target 
		     				turns around (runs away) it may cause the missile
		     				to exceed its effective range, and be wasted.
		    CI_9 - on heater
		     		
				switch ground
						     		
		(5) Fast time on missile in flight
		  										F = on, f = off 
				causes real time to move faster when missile in flight
		     		
		
		(6)  History, StorageDisplayMode
				 if ON,  PPI scope acts as storage scope
				 if OFF, PPI scope acts as normal slow decay phosphor
				 if ON->OFF, erase with flash
		    CI_7 - on PPI
		    
				switch ground
				
						
		(7)  IFF (Identification Friend or Foe)( friend has 3 lines)
				if ON, friend plane (top) shows 3 lines further out 
							and Target Tracking will not track it!
				(this control is forced on if in WarGame mode)
				if OFF, no IFF simulation		
		    CI_11 	- on heater
		    
		    switch ground
		
		(8)  Keyboard inputs - input only from an optional keyboard
				- system starts out reading van inputs,  these will 
					over-ride keyboard inputs (like PPI Range)
				- so then type "K"
				- also, if ADC_4 (pot center) is near 0, 
					assume no van inputs, 
					do not read more ADCs and Contact Inputs
		

		(9)  Launch a Hercules missile (must be in red alert)
				 (computer always sets internal red alert)
				 CI_5	- on Switch Panel
		
					switch ground		                 
		                 
		(10) Move Designate Circle	
					ADC_1 - Range control pot, knob in slot in az assembly 
					                         
					pot exitation
					
					pot ground
										                         
					(following 3 supply azmuth info, from the az circular disk)
					ADC_2 - Azimuth sin function, rotate az assembly
					   
					pot exitation, 
					
					pot ground, (see ADC_1)
					
					ADC_3 - Azimuth cos function, rotate az assembly   
					
					pot exitation, 
					
					pot ground, (see ADC_1)
					
					ADC_4	- mid-point of sin and cos pots, no operator input
					
					pot exitation, 
					
					pot ground, (see ADC_1)
					
		
		
	(11) New Targets (if < 3)                         
		(this control is forced on if in WarGame mode)
		Every scan, a count of enemy targets is made
		if (( count < 3) and (this switch is closed))
			several aircraft (mostly enemy) are launched
			from about 150,000 yards (85 miles) to the
			west heading east.  
							
			This distance was chosen (instead of 350,000 yards) 
			to make the WarGame go faster, but is possibly 
			also reasonable for:
				- very low flying planes to avoid radar
				- submarine launched drones
				- actual identification in heavy jamming
									
			Two or three planes are launched at a time and
			about 1 in 6 is a friend (possibly simulating:
			- friendly fighter planes returning from
					offshore battles
			- civilian aircraft caught by suprise
		
		          
		    CI_10  - 
		    
		    switch ground
		
		          
		
		(12)	PPI Display Range ,binary switch on PPI,
				4 ranges 
				(using binary switch to save contact inputs)
				CI_2   - 2^0 value                               
				
				CI_3	 - 2^1 value
				
				Switch ground -
		
		
		(13) Restart (red alert, new planes, etc.)
		       (asserted at 'off' to 'on' transition
		     					
		     CI_8   - on heater
		     
		    switch ground 
		    
		(14) Sweep speed - (BC van value ignored, always fast)
					(Slow is boooooring)
		
		(15) Text, current event recorder data 
				- if OFF, no text                          
				if ON->OFF, erase PPI to clear text
				- if ON,  update text in east part of scope
				CI_0	on PPI
						
		    switch ground

		(16) WarGame - automatic threat response
   	                      W = ON, w = OFF			switch on heater
   	     the computer acts as a Battery Commander, 
   	     			shooting missiles at the incoming aircraft
   	     (a quick exit if missile is flying is to
   	     			- turn off switch
   	     			- burst the missile)
   	    (initialize Getting_Info, Launch_command flags to off)
   	    (called every 100 ms)
      	if W_ON               
      		force IFF and NewTargets on
      		if (missile flying), 
      				if (flying over 150 seconds)
      						command burst
      				return                                  
      		if (Launch_Command flag)
      				if (target tracked)
      						launch missile, clear Launch_Command flag
      						(should cause missile flying next 100 ms)
      						return
      				else
      					  lost track error handling
      		else if (not Getting_Info flag)
      				clear internal tables and controls 
      				set Getting_Info  flag
      		if (target tracked)        
		      				save PI time into table
      		if (any target not in internal table)
      				designate target (assume instant auto tracking)
      				return
      		else (no more targets)
      			  find shortest PI time
      			  select that target 
      			  	(assumes instant tracked and tracking data)
      			  set Launch_Command flag
      			  clear Getting_Info flag
      			  return
      CI_12 - on heater
      
      ground
		
// -----------------------------------------------  		
  		Plan for end of phase 1
  		1) bill for material
  		2) lengthen 40 pin and 50 pin cables from 36" to 72 "
  		3) permanently mount termination blocks 
  				to eliminate flexing of solid input wires
  				- block 1 for ADC and DAC cards (term blocks exist)
  				- block 2 for parallel port input (add block)
  		4) add termination block to PPI, add switches for
  				- Historical
  				- IFF
  				- Evasive action 
  				- restart
  				- event recorder
  				- start plane 
  		5) add switches (on heater) for
  				- restart
  				- 
  				
  		Ignoring
  				- alert status (always ready to fire)
  				- antenna speed (who wants a slow demo?)
  				
  		Phase 2 - plotting boards  (far future)
 					- pens
  					- position (computer DACs, error & volocity, motors)
  					- lift/down
  					- test position
  					- off sheet (paper change)
  				- interference logic 
  						(inter change target/missile, lights)
  				- ignoring
  					- paper supplies
  					- ink and ink maintenance
  				- possible approaches
  					- use existing tube opamps/modulators/low power amps
  							(can probably fake it with one +- 270 volt ps)
  					- use silicon
  							+ 5 volts on pots (ADCs 0-5 volts?)
  							error and speed from pots
  							pulse time in phase B to triacs
  							excite motors with phases A-C
  							
  				
  		
  		                          
    noted in schematics
    		1) PRF is 500 hz, 2000 us per pulse (328000- e yards?)
  		
  	environment 
  	-------------------
  		using microsoft c++ 1.5  
  			options, (compiler) 386, inline 80x87 calls 
  		desk top
  			800x600   16 bit color
        DOS 6.0 or above  (clock tick name incompatability with 5.1?)
      special hardware for interface
      	ADC card, 40 pin cable, terminal and isolation block
      		4 ADC channels (0 -> +5 volts)
      				term board has 47K protective resistors
      		+ 5 volt source
      		8 contact inputs (TTL)
      				term board has pull-up resistor nets for -28 input)
      		8 contact outputs (TTL)
      				term board has darlington transistors 
      					(for -28 v relays and lamps)
      		gnd                                            
      		
      	DAC card, 50 pin cable, (same block as above)
      		8 DAC channels  (-5 -> +5 volts)
      				term board has 2 K ohm protective resistors
      		+ 5 volt source
      		gnd
      	(if no bc van, demo unit, or keyboard(and event recorder disp))
      	parallel port, cable, switch block
					? TTL outputs
					5 TTL inputs 	- seems to pull up to +5 volts
							(block has 5 switches, no resistors for -28 volts)
					gnd
					(can't get parallel port base+2,c5 to go bi-directional)
        
    		
    		? bi-directional printer port ?
    		reading status lines only
    		---------------------------
    		 		(looking into holes of female connector)
    		 		   /--------------------------------------\
    		 		  /   25 24 23 22 21 20 19 18 17 16 15 14  \
    		     /  13 12 11 10 09 08 07 06 05 04 03 02 01  \
    				/--------------------------------------------\
    				
    			female        male
    			(switches)		(machine)		
    			 2			25          				gnd
    			 9			15		CI_8		S3+  show event recorder
    			13			13		CI_9		S4+	 
    			12			12		CI_10		S5+	 start plane east

    			11			11		CI_12		S7-	
    			10			10		CI_11		S6+	  
   				these TTL inputs float hi
    			Note:  all are active low (you can pull unit out w/o trouble)
    			
        


Notes on stealth and detectable range
	1) a big problem for the aircraft designer, 
		echo strength ~ effective cross section /(range^4) 
		or
		effective detectable range ~ (effective cross section)^0.25
		   the same detectability at half the range means 
		   		reducing effective cross section by 16             
		   		
		(the radar designer has already faced the problem:
			target reflected power ~ 
				target radar cross section * radar power * antenna gain 
				/ range^2
			power from target into receiver ~ 
				reflected power * antenna gain / range^2
			so
			effective radar range ~ ((antenna gain ^2) * radar power) ^0.25
				double the detectable range means increasing power by 16

External i/o interface  (by i/o device)
	Analog Input  (RTD AD210, base address ADCboard = 0x300)
		(board set to 0 to +5 volt)
		ADC_1 	- Target Select Range,  (47K ohm series) from excited pot,
		ADC_2 	- Target Select Azimuth, (47K ohm series) from excited pot
								sin?
		ADC_3		- Target Select Azimuth
								cos?
		ADC_4 	- Target Select pot center point (ADC 0-5 volt, no neg.)
		                                 
		the +5 reference voltage to excite the pots is 
		the input isolation is in the form of a series 47K ohm resistor 
			between	the screw and the input line
		
	Analog Output (RTD DA720, base address DACboard = 0x320)
		(board set to +-5 volt)
		DAC_1 - Target Speed, 	 analog meter
		DAC_2	- Missile Speed Meter
		DAC_3 - Target Range Meter
		DAC_4	- Target Altitude Meter
		DAC_5	
		DAC_6	
		DAC_7	- Time to Intercept
		DAC_8	                     
		the board has calibrated isolation amplifiers
			? propose using 1K resistors for further isolation
		
	Contact Input  (RTD AD210, base address ADCboard = 0x300)
		CI_0 	-   
		CI_1	- 
		CI_2	- PPI Range,	0's bit	- prog switch B (pen contact?)
		CI_3	- PPI Range,	1's bit	- prog switch B
		CI_4 	- Target Select,  button, 0=null, 1=select
		CI_5	- Launch Missile, button, 0=null, 1=launch
		CI_6 	- Manual Command Burst,  button, 0=null, 1=burst
		CI_7	- Show Storage Display    (? PPI ?)
		
		  // following from Parallel port
		CI_8 	- Show Event Recorder, sw	0=don't, 1=do  (? PPI ?)
		CI_9 	- IFF                                     (? PPI ?)
		CI_10 - Start plane east if ( #enemy < 3)
		CI_11	- Target Evasion                          (? PPI ?)
		CI_12	- start problem again (? Heater cabinet momentary switch?)
		
		
				- restart initial situation (CI_0) ? 
		           
		currently, a 47 K ohm pull up resistor to + 5 volt
					and a 47 K ohm resistor series resistor
					
	Contact Output (RTD AD210, base address ADCboard = 0x300)
		CO_0 	- Alert Status,  on = Red   
		CO_1 	- Target  Tracked, 
		CO_2	- PI in dead zone
		CO_3	- Missile in flight,
		CO_4	- 
		CO_5  - 
		CO_6 	- 
		CO_7	- 
                              
		expected loads:
			- 24 volt incandecent lamps (appendix says more peripheral 
				drivers are damaged by incandecents than any other load)
				(the initial current is 9 to 10 times the steady state 
				 current) A common technique is to use a switch bypass
				 resistor to warm the filament to barely glowing when the
				 switch is open. This reduces the surge current to maybe
				 2 times steady state.  (Hi surge current leads to heating 
				 in two ways 
				 	1) normal i * emitter drop (i * 1.3 v)
				 	2) switch saturation, with added heating effects
			- signal class relays 24 volts (? resistance, ? inductance)
				schematics show that (all?) relays are shunted by something
				
        proposed, either of 2:
        	a) used a pnp darlington with voltage divider input to base
        		  (logic) 2500 ohm ,pnp base, 6000 ohm to -12 volts
        		  with stubbing network.
        		  	pnp collector, 100 ohm, 1 ufd (100 v?) to digital gnd.
        	b) could not find National DS3687 negative peripheral driver
        		(looks good for driving the -24 volt based low duty relays)
        		(equiped with a -60 volt zener equivalent)
        		(both inputs +5 turn it off, any input 0 causes conductivity)
        		
        		  	
External i/o (by function)

	STATUS
		Alert status      
			
		Show Event Recorder
			input, switch	CI_8	0=don't, 1=do
			
	ANTENNA AND PPI RANGE
		Antenna Speed
			
		PPI Range
			input	prog sw	CI_2,3	0=50K,1=150K,2=250K,3=350K
			
	TARGET SELECTION
		Target Select Range
			input	ex pot	ADC_1	
			
		Target Select Azimuth
			input	ex pots	ADC_2,3
			input ex pot center points
			
		Target Select Command
			input	button,	CI_4	0=null,1=active
			
	TARGET CONDITION
		Target Tracked
			output	led		CO_1	0=null, 1=tracked
			
		Target Speed
			output 	meter	DAC_1	analog meter, 0=not tracked
			
	PREDICTED INTERCEPT
		Time to Intercept	
			output	meter	DAC_2	DVM			, 0=not tracked
			
        Predicted Intercept in dead zone
        	output	led		CO_2
        	
    MISSILE CONDITION
    	Launch Missile
    		input	button	CI_5	0=null, 1=launch
    		
    	Missile in flight
    		output	led		CO_3	0=null, 1=launched & tracking
    	
    	Manual Command to Burst Missile
    		input	button	CI_6	0=null, 1=burst

-------------------------------------------------------------  
    
                            
	0) Senario
		a) situation starts in:
			- Blue alert (stations manned, equipment running)
			- a number of mach 0.7 and mach 1.5 planes
				- flying toward San Francisco from the west 
				- at about 160,000 yards range
		b) destroy as many as possible, 
		c) hints, 
			- you must be in Red alert status to fire a missile
			- target the fast ones first
		
        	
    
Nike system summary
-------------------
Radar summary
	There were 3 main radar systems with 1 or more radars each.
	Acquisition Radar - to get overall picture, select target.
		The battery commander saw the display of this radar,
		selected targets to the Target Tracking operators.
		There were several types of these radars, with aids
		to suppress ground clutter, low speed aircraft, and
		several forms of jamming.
		
	Target Tracking Radar - three operators aided tracking in
		range, elevation and azimuth of the selected target.
		The  range, elevation angle and azimuth angle were converted 
		at the radar mount by sin/cosine potentiomenters into 
		h(altitude), x(N/S), and y(E/W).  
		These values were delivered to the computer as voltages.
	Target Range Radar special characteristics helped the 
		range operator handle Electronic Counter Measures (jamming).
		
	Missile Tracking Radar - to track and command the missile.
		The missile height, x, y, values delivered to computer.
		                                                  
Computer
	An analog computer (distances and times were voltages) used
	inputs from the Target Tracking and Missile Tracking Radars.
	
	These values (and derived target and missile velocities) were
	used to calculate the remaining flight time and Predicted 
	Intercept point.  The missile was guided to the predicted
	intercept point by the computer generated steering commands 
	sent through the Missile Tracking Radar.  
	
	About 0.1 second before 	intercept, a burst command was sent 
	to explode the missile and hopefully disable the target.
	
Missile guidance summary
    To keep flight times down, (and increase the effective range) 
    the missile is aimed ahead of the target at a calculated 
    Predicted Intercept point.  If the aircraft flies a straight
    line, the missile horizontal flight path will also be straight.
    (A dog chasing a target runs directly toward the target,
     involving a longer run if the target runs straight.)
    
    The missile is launched (essentially) straight up,  boosted
    to about mach 1.7 in 3.4 seconds.  It then turns its belly 
    toward the calculated Predicted Intercept (allow 1 second).
    A sustainer rocket starts to increase the speed to mach 3.5. 
    A full dive command is sent to the missile to dive it 
    from vertical toward horizontal to intercept the flight path 
    of the target.  When the missile has reached a vertical angle
    that will be a good flight path to the intercept point, the 
    full dive command is removed and normal steering begins.   
    
    The missile is command guided by coded sequences of pulses from
    the missile tracking radar to the predicted intercept point.  
    The predicted intercept point is constantly being updated by 
    the computer from data from the target tracking radar and 
    the missile tracking radar.
    
    About 0.1 seconds before the missile will be closest to the 
    target, a missile burst command is send by a coded pulse 
    sequence to the missile by the missile tracking radar.   
    This burst command is decoded and the missile warhead exploded.
    
			

 This Demo System as School  
    This demonstration system is basicly a Surface to Air (SAM) 
    shooting gallery for novice (you) battery commanders, 
    with simulated aircraft appearing on a display similar to that 
    seen by actual Nike battery commanders. (At the end of 
    training, and periodically thereafter, Nike crews and officers 
    traveled to a test site (usually to Red Canyon, New Mexico) 
    and fired actual missiles at tiny (8 foot wing span) 
    drone aircraft.
    
    Think of this demo as the lab for college course SAM 1, 
    necessary (but not sufficient) to do the antiaircraft mission.
    The battery commanders (and other personel) needed much more
    training (especially in counter measures by the aircraft) 
    to begin to handle actual combat situations. 
    	
    You, the student battery commander will view a CRT picture 
    similar to that presented by Nike acquisition radar.  You
    can operate switches and knobs that perform responses to the 
    real controls available to a battery commander. 
    Simulated radar tracks the selected simulated targets and
    the missile launch switch starts a simulated missile. 
    The simulated computer generates commands which guide the 
    simulated missile to the simulated target.  
    
Tools for the student battery commander
    Provided for the student (as battery commander) are:
    	1) the acquition radar display 
    		Plan Position Indication - (PPI) - with:
    		a) some targets and ground clutter
    		b) Identification Friend or Foe (IFF) 
    		c) target selection circle
    		d) predicted intercept point 
    		   (presented on PPI, not automatic plotting boards
    		e) predicted time to intercept 
    		   (presented on meter, not automatic ploting boards)
    		f) missile position
    		   (presented on PPI, not automatic plotting boards)
    		
    	2) various other important indications and controls
    		a) alert status
    			 the site is always "RED ALERT"
    			 
    		b) radar scan speed (fast/slow rather than the actual
    		   5, 10, 15 RPM)  a switch marked ANTENNA FAST/SLOW
    			
    		c) range shown on PPI 
    			(350,000  250,000  150,000 50,000 yards)
    			a rotary switch marked as above
    			
    		d) target selection command button 
    			a bush button marked "Target Select"
    			
    		e) selected Target Tracked light, 
    			from Target Tracking operators
    			a led marked "Target Tracked
    			
    		f) target speed indicator
    			a meter marked in mach numbers 
    				(assuming mach 1.0 = 750 miles per hour)
    				
				g) a meter indicating time to intercept
					 - before launch - flight time if launched right now
					 - after  launch - flight time remaining
				
    		h) launch missile switch 
    			(the higher performance Hercules is launched)
    			
    		i) missile destroy in flight (operational problem)
    		
    		j) "dead zone" 
    			(can't hit target within 7,000 yards of site) 
    			(presented as a warning light, 
    				not on the time/elevation plotting boards)
    				
				k) event recorder 
					(shows mission history & estimated miss distance)
					(presented by push button presenting text
					  no photographic film to be developed later)
				
    Important items not present or assumed perfect are:
    		a) tracking antennas are correctly adjusted, that is
    				boresignted, leveled ( a high maintenance item), 
				b) all other system adjustments correct
				c) system powered up sufficiently, (it takes at least
						15 minutes to get the acquisition radar tubes
						correctly warmed for use)
    		d) no communication with other batteries and headquarters 
    				(who sees what, who shoots at what, etc)
    		e) communication with the launcher area, 
    				(the launcher section always has missiles ready)
    		f) communication with the tracking radar operators 
    					(target is acquired & tracked easily, for demo!)
    				3 target tracking operators 
    					(azimuth, elevation and range)
    				1 missile tracking operator
    		g) the automatic plotting system is not present
    				(Predicted Intercept and missile are on the PPI)
    				(elevation is not presented in this demo)
    				(time to intercept is on a meter rather than the
    				  axis of 2 plots on the automatic plotting system)
    		
    The following items help simplify the problem for the student:
    	a) IFF (Identification Friend or Foe) is always on 
    			(see top aircraft)
    		
    	b) The aircraft fly right in
    		- no turning back to get you to waste ammunition 
    		- no multiple aircraft trying to appear as one 
    		
    	c) No stealth aircraft to cause suprises
    	
    	d) No passive jamming (chaff) to obscure the area
    	
    	e) There is no active jamming (a major aircraft defense)
    		
			f) And the aircraft don't threaten to shoot back with:
					- radar seeking missiles
					- pre-targeted missiles with you as the destination
					
			g) Aircraft	do not carry missiles (must drop bombs)
				  (just keep the enemy 10 miles away (18,000 yards)
		
---------------------------------------------------------------------------
      		
  		
  						
			also, improve predicted time to intercept
					- existing was ajax at fixed mach 2.5  						
					- this hack initial dives at mach 1.7, 
						then fires sustainer to mach 3.5
						causing big changes in predicted intercept, 
						and 0.5 g horizontal g's
						
  		
  		14) study using system tube modulators for plotting board
  				- +- 5 volts from DACs and across plotting board pots 
  					(not 100 volts)            
  				- fire up bc van filaments 
  				- fire up bc van power supplies,  
  				
  		15) study effect of running analog computer
  				- clone simulates and displays one or more targets
  					- video to display
  				- clone picks up target select command, (video to display)
  				- clone slews TTR to target and sends "tracked" signal
  				- clone "tracks" target, supplying to bc computer
  					(+- 5 volts * 20)
  					(auto rc van target acquire)
  					- slant range to elevation pot
  						- height to computer
  					- ground range to az pot
  						- x, y to computer

  				- (clone simulates launch area signals? - missile select?,
  					 ready?, etc)
  				- clone inputs missile fire from bc van
  					- simulates missile launch
  					- inputs steering commands from computer
  					- simulates missile behavior & tracking data
  						(missile data to computer +- 5 v *20)
  					- slant range to elevation pot
  						- height to computer
  					- ground range to az pot
  						- x, y to computer
  				- clone takes burst signal (allows x ms) and calculates 
  						miss distance
  				- clone records "every thing" including event recorder info
  				- bc van does all else
  					- human inputs
  					- predicted point of intercept, (gyro), 
  						and predicted time of intercept
  					- values to plotting boards
  					- missile steering commands
  					- alert status 
  					
  					
  		17) if tube supply or zero set problem in computer
  			- use +- 5 volts for reference voltages 
  			(op amp, ADC and DAC limits
  			- replace all tube op amps (+- 100v)with chopped op amps (+-5v)
  				(leave tube op amps there, but unscrew supply plug
  				  into supply plug insert dual chopped op amp with 
  				  	simple power supply)
  				- assume tubes supplied with 12 volts center tapped
  					- simple unfiltered +- 9 volts to chopped op amps
  						(totally ignore other voltages)
  				- if zero set amplifier works, the neon flasher can be 
  					used to find non"zero" inputs to op amps for 
  					diagnostics.  (correction voltage
  					not needed as op amp is already chopped.
  			- need servo amplifiers to drive pots 
  				- tube modulators for high voltages eliminates need 
  					for fancy electronic work by me.
  			
i/o board generalities and details - 
------------------------------------
 	all from Real Time Devices, Inc
 		820 North University Drive
 		P. O. Box 906
 		State College, Pennsylvania  16804
 			phone (814) 234-8087
 			FAX	  (814) 234-5218
 	AD210
 	-----
 		ADC	4 single ended 12 bit ADC inputs (0 to +5 v factory default)
 		16 external TTL i/o
 		8  internal logic i/?
 		Jumpers
 			P3	base address			0x300		(factory default)
 			P4	A/D end of convert      PPI PB7		(factory default)
 			P5	external int or PPI		disabled	(factory default)
 			P6	timer to int channel	disabled	(factory default)
 			P7	configures 8254 counter	cascaded	(factory default)
 
  			
  		            
  missile data
	combined booster and body
  		length		    39 feet
  		weight		10,550 pounds  		            
  	body
  		length		    27 feet
  		weight		 5,250 pounds  
  		body diam       32 inches
  		fin diam	    90 inches
  		thrust 		13,500 pounds
  		burn time	    29 seconds
  	booster
  		length		    14 feet  (including 2 feet of coupling with body
  		weight		  5300 pounds
  		body diam	    34 inches
  		fin diam	   138 inches
  		thrust	   173,600 pounds
  		burn time	   3.4 sec 
	(following is with delayed sustainer)  		
  	speed distance profile (estimated from weight, thrust, and distance          
  	time (sec)	speed (m/s)		mach	hz, km		hz, miles	alt, ft. 
  	----------	-----------		-----   ------		---------	--------
  		0 		   0 		
  	    3.4	     633 		 1.82     0		    0		 3,336
  	    	(end of booster, assume 1/2 weight is propellant)                       
  	    	(details (2 g's needed for 1g of vertical speed gain)
  	    	(start of boost		17 g (16 for vert acc.)
  	    	(end of boost		21 g (20 for vert acc.)  average 18g vert
  	    4.2		 633		1.82	0			0		 5,270
  	    	(if minimum dive radius needed (low alt), delay sustainer t+9)
  	    	(s = start of sustainer motor, < 3% loss in altitude gain)
  	    	start and end of burn 2 g acceleration (less propellant/weight)
  	    	drag assumed constant at 3000 pounds ( ~ 1/2 g)
  	    10	     733		 2.1	0.8			0.5		14,100		
  	    	(missile has completed 30 degrees in initial dive)		
  	    15		 933		2.6	2.8			1.7		20.5
  		    	(missile has completed 60 degrees in initial dive, 
  	    s+0		 633		1.82	0			0		 5,270
  	    s+10	 833             2.4		
  	    s+20	1033             2.9
  	    s+30	1218			 3.6	(end of sustainer)
  		    s+40	1118             3.2
  		    s+50	1018             2.9
  		    s+60	 918             2.6
  		    s+70	 818			 2.3
  		    s+80	 718			 2.06
  		    
  		
---------------------------------------------------------------							  		                                                       
  	general form: 
  		  center is radar/missile launch near SF, left is west 
  			(radar sweep simulated by blanking just before scan)
   				- simulated long persistance display phosphor or
  					(no) digital memory of past target position
  					(most recent scan = yellow,
  					 aged each x? degrees after scan
  				- missile is x
  				- predicted intercept point is #
  				- IFF response (from friendly aircraft)
  	
			- all angles start with 0==north, clockwise
			- east is +x, south is -y
			                                                        
			- visible objects in simulation
				(mouse is arrow, hot spot is tip
					- lift right button selects target (if 
					- lift left  button 
				- system objects are from 1-9                
					- 1=map object (vectors) 
					- 2=target Tracked icon, a box
					- 3=target tracking radar, a +
					- 4=predicted point of intercept, a circle 
					- 5=missile icon, ajax,   also missile tracking radar
					- 6=missile icon, hercules, also missile tracking radar
				- trackable objects are types OBJ_T_MIN -> OBJ_T_MAX
				   including
				   mach 1.5, OBJ_AIRCRAFT
				             OBJ_BIRDS,           
				             
	Plotting Rules
		Horizontal x,y - scale = +- 200,000 yards     
			plotted (target select until fire)
				target and intercept 				             
			plotted (fire until intercept)
				target and missile
			timing marks (10 sec)   left,  return, up,   return spikes
			fire marks              right, return, down, return spikes
			pen ids (TARGET/MISSILE) in lower left/right corners 
				- a flag 'target_left' is toggled by the 'xy hit detect'
				- if this flag is set, the 
		Altitude   z,t - scale   0-100,000 feet,  0-160 seconds
			timing marks (10 sec)   vertical spikes			
		
  --------------------------------------------------------*/ 
// note: objects are stored in type sorted order

//  event recorder       
//	recording, to file single file EVENT.TXT, restart kills previous file
//  button on/off, 
//	  0        1         2         3         4         5         6     
//	  1234567890123456789012345678901234567890123456789012345678901234
//	                   Sx       Sy      Sz       Vx     Vy     Vz      
//					   km       km      km       m/s    m/s    m/s
//	  m_time	target snnn.n	snnn.n	snnn.n   snnnn  snnnn  snnnn  
//              missil snnn.n	snnn.n	snnn.n   snnnn  snnnn  snnnn  
//				pre in snnn.n	snnn.n	snnn.n   snnnn  snnnn  snnnn                  
//              g ang  nnn      
//				status m=sssssssssssssss  c=sssssssssssssssss

// current limitations
//   g's	I cant currently calculate the g steering forces needed 
//			to steer a missile in its 3 dimentional space to a given point.
//			So, for now, i will calculate the x,y steering forces in the 
//			game's x,y plane and the vertical steering forces in a plane
//			through the z axis.   This will be close enough.
//			Displayed missile g's calculated from x,y and z
//
//	time to intercept is calculated in the game's x,y plane only
//

#define STRICT					// further checking gives more warnings
            
#define DEBUG_R 0			// record + print debug features are off(0)/on(1) 

#define LPT1   0x278
						// printer port    0x278 on 486
						//					0x378 on NCA

//////////////////////            
#define ADCboard 0x300 	// base address of adc board containing 4 ADCs 
						//	and 16 external discrete lines  PA0-7 is input
						//		PC0-7 is output
						// card takes 24. port addresses  
#define ADC_1	0		// Target Select Range					
#define ADC_2	1		// Target Select Azimuth, sin		
#define ADC_3	2		// Target Select Azimuth, cos	
#define ADC_4	3		//  

//(some normal contact inputs deleted due to limited inputs 
#define CI_0	0		// WarGame
#define CI_1	1		// About this program
#define CI_2	2		// PPI Range, 2^0					
#define CI_3	3		// PPI Range, 2^1					
#define CI_4	4		// Target Select					
#define CI_5	5		// Launch Missile					
#define CI_6	6		// Manual Command Burst				
#define CI_7	7		// Show Storage Display
   // added from parallel port
#define	CI_8	8		// Show Event Recorder
#define	CI_9	9		// IFF 
#define	CI_10	10	// Start planes east if (#enemy < 3)
#define	CI_11	11	// Selected Target Evades
#define	CI_12	12	// Restart

// some contact outputs added until plotting boards)
#define CO_0	0		// Alert Status 1==Red ( not connected)				 
#define CO_1	1		// Target Tracked ( not connected)					
#define CO_2	2		// PI in dead zone ( not connected)	
#define CO_3	3		// Missile in flight                
#define CO_4	4		// Missile steering limit, vert ( not connected)
#define CO_5	5		// Missile steering limit, horz ( not connected)
#define CO_6	6		// 
#define CO_7	7		// 

///////////////////////						
#define DACboard 0x320	// base address of dac board containing 8 DACs
						// also viewed as 800. decimal
						// card takes 16. port addresses
#define DAC_1	0		// Target Speed Meter
#define DAC_2	1		// Missile Speed Meter					
#define DAC_3	2		// Target Range Meter
#define DAC_4	3		// Target Altitude Meter
#define DAC_5	4		// 
#define DAC_6	5		// 
#define DAC_7	6		// 			
#define DAC_8	7		// Time to Intercept Meter



///////////////////////
// keyboard constants
#define VK_F1 0x81		
#define VK_F2 0x82		
#define VK_F3 0x83		
#define VK_F4 0x84		
#define VK_F5 0x85		
#define VK_F6 0x86		
#define VK_F7 0x87		
#define VK_F8 0x88		
#define VK_F9 0x89		
#define VK_F10 0x8a		
#define VK_F11 0x8b		
#define VK_F12 0x8c
#define UP_ARROW	0x91		
#define RIGHT_ARROW	0x92		
#define DOWN_ARROW	0x93		
#define LEFT_ARROW	0x94		

#define PI 					3.141592653
#define DEG_PER_RAD 		(180.0/PI)

#define OBJ_MAP_V			1	// map line(s)
#define OBJ_TTR				2   // target tracking radar position 
#define OBJ_TAR_DES			3   // target designator circle
#define OBJ_PI				4   // predicted intercept point
#define OBJ_MTR	 			5   // missile tracking radar
#define OBJ_EXPLOSION 		6

#define OBJ_T_MIN			100
#define OBJ_T_MAX			127	
#define OBJ_AIRCRAFT	100 //  does not respond to IFF
#define OBJ_AIRCRAFT_F 101  // responds to IFF
#define OBJ_BIRDS			103
#define OBJ_BIG				104
#define OBJ_SMALL			105  

#define TIMER_SCAN 1
#define SCAN_INTERVAL 10
#define RADIUS_IN_PIXELS 	400 
#define CENTER_PIXEL_X 400
#define CENTER_PIXEL_Y 300
#define PIXELS_PER_ARROW 20

//  plotting board scaling
#define MAX_PLOT_HZ  300000   // +- 300,000 yards
#define MAX_PLOT_VT   50000   // 0 to +50,000 yards

// Object display structure
#define MAX_OBJ 100

#define PULSES_PER_RAD  	114    // about 2 pulses/degree
#define LIM_PULSE_CNTS		(int)( 2 * PI * PULSES_PER_RAD)
#define	MAX_PHASES			6		// counting 0 -> 5  

#define MAX_STEERING_ACC  100.0	// maximum vert or horizontal steering 
				// in acc meters/sec/sec         // about 10 g's
// vertical space for text
#define VERT_TEXT_STEP 1	 

// message types
#define MY_CREATE 		9901
#define MY_TIMER  		9902
#define MY_KEYUP  		9903
//#define MY_MOUSEMOVE   	9904
//#define MY_LBUTTONUP   	9905
//#define MY_LBUTTONDOWN 	9906
//#define MY_RBUTTONUP   	9907
//#define MY_RBUTTONDOWN	9908
//#define MY_DESTROY   	9909
      
  
 // define STRICT    // further checking gives warnings
// #include 
#include 
#include 
#include 
#include 
//#include   // _ellipse 
#include 
#include  
// following added for floating point underflow exceptions
#include 
#include 
#include 
#include       




// local subroutines
long ClearDisplayHistory();                           
long SetDisplayTo(int ColorNumber);
long CheckIt( char * string);  	// if i != -1, make box with string, ok
long ComputeMissileMiss_H_V();
long CreateInitialSituation(int);
long CreateSystemObjects();  // predict int, targ sel, missile

long DisplayObjects(int iScan); 
long GetAnalog(int id, double * val, double min, double max);
				// id is port 1 through 4, val in engineering units
				//  offset and scaling is in subroutine
				//   if error, return = -1, val - -9999999.9 
long GetDigital (int id);	// return digital channel (1 - 8), else -1
char GetPrinterPort();
long About_Ed(int);			// author Ed's message
long About_Menu(int);		// message menu and array

long InitializeObject(int iObj); 
int  KeyboardAscii() ;		// convert a keyboard hit to ascii
long KeyboardInput(int wParam);			// process keyboard hits

long Log();	// post the message in szLogEntry
 
long My_Beep (int i);   // DOS does not provide a beep
void MyLine (int x1, int y1, int x2, int y2, short color);
long  MyProc (int iMsgType, int wParam); // main processing area

long PaintObject( int iObj, int iPulse);
long PutAnalog(int id, double * val, double min, double max);	
			// id is port 1 through 8, val in engineering units
			// NOTE*** the min will cause -5 volts, the max +4.99 volts  
			//  offset and scaling is in subroutine
			//   if error,  return = -1,  
long PutDigital(int id, char val);	// id=dig chan (0-7), val = 0/1
			// return 0 if legal, else -1  
			
long RecordEvent();		// write data to event recorder
long RemoveOutOfViewTargets();  // return # remaining

long SelectTarget(double x, double y);
long set_video_SVGA256 ();   // set video to SuperVGA 800x600, 
void Sleep( clock_t wait );  // from Help 
long SpecialInput();					// input from special cards and LPT1
long SpecialOutput();					// output to special cards
long StartPlaneEast(int iSpeedy, int designate);

long UnPaint(int iObj);			// remove all paint sequences of obj
long UpdatePlotPosition(int v );   // move current position into plot data
								//    (current quadrant)
long UpdateMissile();
long UpdateIntercept();
long UpdateTargets();
long UpdateText(int cmd);

long WarGame(); // - automatic threat response 


                                         
// local globals 
// ------------------
char  cInputKeyboardOnly = 0;  // input select for simulation 
		// 0=ADC & switches, 1=mouse & keyboard 
char	cTargetTrackLeftArm = 1;	// west == left (usual expectation)
char	cIFF = 0;					// IFF flag (toggle)
char	cWarGame = 0;     // flag to cause automatic response
char	cEvasiveAction = 0;	// designated target random yaw accelerations
char	cStartPlaneEast = 0;	// start new targets if < 3 targets remain
char	cAbout_Keyboard = 0;		// messages from author, from keyboard
char	cAbout_Switch   = 0;		// messages from author, from switch
char	cAbout_Seq			= 0;		// sequence # if from switches 
char	cFastMissileTime = 0;	// faster missile flight for fun
					// not included in switches:
					//		- we ran out
					//		- not authentic, a cheap thrill
													
char szLogEntry[100];	// user can sprintf text here and call Log
char my_text[100];
                                         
char	cDisplayEventRecorder = 0;	// enable show engineering data,
char	cClearMyScreen=1;	// trigger clear screen
char	cStartPlane=0;		// start plane request

double dPixelPerMeter = RADIUS_IN_PIXELS/350000.0;	// initial
double dVisibleRange;
double dOldPixelPerMeter = 0;
double dMeterCalib = 1.5/1.75;	// convert units to meter readings
 
double dGlobal1 = 0, dGlobal2 = 0; // debug printouts 

double dSecondsSim;	//from the beginning of world (Jan 1,1970) no delay
		// until fSeccondsSem > LSecondsUnix - lSecondsStart)
double dSecondsSys; // system time,  bring fSecondsSim up to this  
		// before scan
double dSecondsDelta=0.1;  // time to advance one simulation cycle

double dSecondsMissile=0; // 0 at start of boost
double dPIRadNorth;			// predicted intercept, radians from north
char   cMissile_Over_Range;	// set by missile tracking radar 
  
double fMissRange, fMiss_x,fMiss_y,fMiss_z; // calculated miss distance,

int iPulseCnt; 	// pulses this scan,
double	dSweepRad;	// = (double)iPulseCnt/PULSES_PER_RAD;
double  dSweepSin;	// = sin(dSweepRad); 
double  dSweepCos;	// = cos(dSweepRad);       // for sweep

int iPulsesPerTimer= 10;	// controls sweep speed 10 gives about 15 RPM
                  
// --- enumerated stati -----------
// missile status
typedef enum {eMSPreLaunch, eMSBoost, eMSInitialDive, eMSCruse,
		eMSExplode} eMissileStatus;
eMissileStatus MissileStatus  =eMSPreLaunch;
char *pszMissileStatus[] = {"PreLaunch","Boost","InitialDive", 
                "Cruse","Explode"};
// computer status
typedef enum {eCSNoTargDesig, eCSTargNoTrack, eCSTrackBadSolution,
		eCSOutOfRange, eCSInRange, 
		eCInDeadZone} eComputerStatus;
eComputerStatus ComputerStatus=eCSNoTargDesig;
char *pszComputerStatus[] = {"NoTargDesig","NoTrack","BadSolution",
		"OutOfRange","InRange","InDeadZone"};
		
// alert status
typedef enum {eASWhite, eASYellow, eASRed} eASAlertStatus;
eASAlertStatus  AlertStatus = eASRed;
char *pszAlertStatus[] = {"White","Yellow", "Red"};
// end-- enumerated stati ----------- 

   // set global values for predicted Intercept program, end of initial dive
double dReleaseTime, dReleaseRange, dReleaseZ, dReleaseSpeed;
double dMaxRange, dDeadZoneRange;   
double dTarDesRange, dTarDesAz;

double dSecondsIntercept; // time to intercept
int iTargetTracked = 0;	// object number of selected target, 0=none
double dTargSpeedMach = 0;		// Target Speed in mach number
double dMissileSpeedMach = 0;

 FILE *fdRE = NULL;	// file descriptor of RecordEvent
 char szAppName[] = "WinRadar" ; 
		
struct sDispObj {
	char iObjType;		// 0=available for assignment (and not displayed)
						// (dynamics) 
						//  1 = map line
						//  2 = Target Radar    (OBJ_TTR)
						//	3 = target designator circle OBJ_TAR_DES
						//  4 = Predicted Intercept (OBJ_PI)
						//  5 = Missile  (OBJ_MTR)
				   		//	 OBJ_AIRCRAFT
				        //   OBJ_BIRDS,
						
	double dSx, dSy, dSz;	// position (cartiasian)       
							// - begin vector x,y - line count
	double dVx, dVy, dVz, dVs;	// velocity (cartiasian and "speed") 	
							// - corner xy, corner xy
	double dAx, dAy;		// the various ObjTypes contain the limits  
							// - corner xy
	double dAyaw_r, dApitch_u;		// acceleration, r=right, u=up          	
							// - corner xy, 
	char iObjPict;       // 1=dot, 2=2x2, 3=3x3, 100+ icons
						//  100=missile, 101=des targ, 102=pred interc
						//  also used to count explosion sequences
	char reflectivity; // for stealth plot characteristics
	char IFF[MAX_PHASES];	// controls writing of IFF echos
  	int	w_iPulse[MAX_PHASES];	// write plot on this pulse 
  				// (0 pulse is north, swing east, s,w, etc.                  
				// note: w_x[0], w_y[0] are not updated until 
				//  w_iPulse[0] is < 0 to prevent
				//	multiple hi intensity writes on fast moving targets
				//			(the multiple do not fade).
	double w_dAngRad[MAX_PHASES];	//  write angle in radians, 
									// clockwise from north
	int	w_x[MAX_PHASES];		// write x postion in pixels, rel origin
	int	w_y[MAX_PHASES];		// write y postion in pixels, rel origin
	int iEndB1x[MAX_PHASES];	// long & short lines of two intensities)      		
	int iEndB1y[MAX_PHASES];	      		
	int iEndB2x[MAX_PHASES];	      		
	int iEndB2y[MAX_PHASES];	      		
	int iEndS1x[MAX_PHASES];	      		
	int iEndS1y[MAX_PHASES];	      		
	int iEndS2x[MAX_PHASES];	      		
	int iEndS2y[MAX_PHASES];	      		
	} stDispObj[MAX_OBJ]; 
	
	short sIntensF, sIntensC, sIntens8, sIntens6, 
     sIntens4, sIntens2, sIntens0;  // set of intensities
short sDecayArray[2*MAX_PHASES]; 	// above sequence, 

char bStorageDisplayMode = 0;
char bStorageDisplayModeHistory = 0;
	// if operating in StorageDisplayMode,
	//		paint Phase 1 pixels only (no fade)
	// if leaving StorageDisplayMode,
	//		flash screen (just like Techtronics)
	//			all bright, all dark
 
char cRestartSwitch = 0;   // switch input, edge triggered
char cRestart = 0; // demand

// **************************

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
int main ()
     {  
  long lStackVal=0;         
	int iType = 0, i=0;     
	char cKill = 0, cFirstTime = 1;   
	
	clock_t	 OldTick, CurrentTick;    // storage for clock tick values

////	My_Beep(1); 

	srand( 4 );     // start randomizer
	set_video_SVGA256 ();    // set video 800x600, 256 colors, set yellow
	// set up colors
	sIntens0   	= 0; // black
	sDecayArray[0] = sIntensF	= 2;   // most intense
	sDecayArray[1] = sIntensC	= 8;
	sDecayArray[2] = sIntens8	= 14;
	sDecayArray[3] = sIntens6	= 20;
	sDecayArray[4] = sIntens4	= 26;
	for (i=5; i<(2*MAX_PHASES); i++)
			sDecayArray[i] = sIntens0;
	SetDisplayTo(sIntens0);       // blank screen
			         
	cKill = 0; cFirstTime = 1;         
	OldTick = clock();	 

  while ( ! cKill )    // MAIN LOOP //////////
    { 
		if (cFirstTime)
			{
			MyProc (MY_CREATE, 0); // pseudo Windows
			cFirstTime = 0;
			}
			// check a keyboard hit
		else if ( _kbhit() )
			{                  
			iType = KeyboardAscii();
			MyProc ( MY_KEYUP, iType );
			}                            
      // check for timer count change
		else if  (CurrentTick = clock())  // force read in context
			{   
			if  ( (OldTick > CurrentTick) // clock roll over
					 ||((OldTick+(CLOCKS_PER_SEC/10)) <= CurrentTick)
					 || (  (MissileStatus != eMSPreLaunch)  // <><>
					     &&(cFastMissileTime) )  // <><>
					 		 )	                  
				{             	// 0.1 second or more
				MyProc (  MY_TIMER, 0); 
				if (CurrentTick > OldTick)
					OldTick += (CLOCKS_PER_SEC/10);  // normal processing
				else
					OldTick = CurrentTick + (CLOCKS_PER_SEC/10); // roll over 
				if ( OldTick < (CurrentTick+10) ) 
					OldTick = CurrentTick;  // limit catch-up 
				if ( OldTick > (CurrentTick+10) ) 
					OldTick = CurrentTick;  // limit catch-up 
				}                         
			}
         // nothing to do this time in loop
 		else
        ;		// could not find sleep till next tick
    }
   _setvideomode( _DEFAULTMODE );	// exit kindly? 
   return (0);
   } 
   
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
long  MyProc (int iMsgType, int wParam)
     {   
     static char info_buffer[40];
     
     int i, iObj, j;
     int x,y;   
     static short rbgSaveArray[RADIUS_IN_PIXELS];	// color
     static int iDelayCnt=0;	// for text display and setpoint output
     static int iCenterDot=5;	// controls width of main bang clutter
     
	 char bRptScan;		// helps control modulo scanning
	 				// x pulses per 100 ms time interval   
   char	cSkipScan;  // used in speeding simulation     		


		if (cRestart)
			{
 			cRestart = 0;
			SetDisplayTo(sIntens0);       // blank screen
			for (iObj=0; iObj< MAX_OBJ; iObj++)
			InitializeObject(iObj); 
			CreateSystemObjects();	// predict int, targ sel, missile
			CreateInitialSituation(1);  // application
      AlertStatus = eASRed; 
      cIFF = 0;             
      cDisplayEventRecorder  = 0;
      MissileStatus = eMSPreLaunch;
 			dSecondsSim = time(0)-1; 
 			dSecondsSys = dSecondsSim+1; 
			cIFF = 0;					// IFF flag (toggle)
			cWarGame = 0;     // flag to cause automatic response
			cEvasiveAction = 0;	// designated target random yaw accelerations
			cAbout_Keyboard = 0;
			cAbout_Switch   = 0;
			cAbout_Seq			= 0;
 			}
      
     switch (iMsgType)
        { 
        case MY_KEYUP: 
        	KeyboardInput( wParam);			// process keyboard hits
  		 		return 0;
  		 		break;
  		   	
        case MY_CREATE:
					// null each object 
					for (i=0; i< MAX_OBJ; i++)
					InitializeObject(i); 
					CreateSystemObjects();	// predict int, targ sel, missile
					CreateInitialSituation(1);  // application
			 		// get time 
			 		dSecondsSim = time(0)-1; 
			 		dSecondsSys = dSecondsSim+1; 
 				
					dPixelPerMeter = RADIUS_IN_PIXELS/350000.0;	// initial
					dVisibleRange = RADIUS_IN_PIXELS/dPixelPerMeter;
					dOldPixelPerMeter = 0;

         	return 0;
         	break;   

			
        case MY_TIMER:  
       		dSecondsSim += dSecondsDelta;
       		
       		if (cAbout_Keyboard || cAbout_Switch)
       			{
       			if (cAbout_Keyboard)   // assure correct sourse
       					About_Menu( 1 );		// even if both set
       			else
       					{
       					switch (cAbout_Seq)
       						{
       						case (0):
       							About_Ed (0);
       							cAbout_Seq++;	// sequence to next message
       							break;
       						case (1):
       							About_Ed (0);
       							cAbout_Seq = 0;	// start over again
       							break;
       						}
       					}
       			cAbout_Keyboard = 0;
       			cAbout_Switch   = 0;
       			}
       			 
       		
					// do simulated radar ppi scan, with minimum resources
     			if  (  (MissileStatus != eMSPreLaunch) && ( cFastMissileTime ) )
     				cSkipScan = 1;
     			else
     				{
     				cSkipScan = 0;
          	dSweepRad = (double)iPulseCnt/PULSES_PER_RAD;
      			dSweepSin = sin(dSweepRad); 
     				dSweepCos = cos(dSweepRad);       // for sweep
     				if (dVisibleRange < 60000)
     					iCenterDot = 8;
     				else if (dVisibleRange < 160000)
     					iCenterDot = 4;
     				else if (dVisibleRange < 260000)
     					iCenterDot = 3;
     				else 
     					iCenterDot = 2;
     					
					for (i = 0;(i < RADIUS_IN_PIXELS); i++)
						{ 
						_setcolor( sIntensF);
						if (  ( i < iCenterDot) 
						    ||    ( (i<25) && (!(i % 2)) )
						    ||    (  (i<75) && (!(i % 4)) )
								|| ( (i > 75) && ( i<200)&& (!(i % 6)) )
							    	|| ( (i > 200)&&( i iCenterDot)
					    && (   (  (i<75) && (!(i % 4)) )
					        ||  (  (i<25) && (!(i % 2)) )
						    	|| ( (i > 75) && ( i<200)&& (!(i % 6)) )
					      	|| ( (i > 200)&&( i
#include 

enum NOTES      /* Enumeration of notes and frequencies     */
{
    C0 = 262, D0 = 296, E0 = 330, F0 = 349, G0 = 392, A0 = 440, B0 = 494,
    C1 = 523, D1 = 587, E1 = 659, F1 = 698, G1 = 784, A1 = 880, B1 = 988,
    EIGHTH = 125, QUARTER = 250, HALF = 500, WHOLE = 1000, END = 0
} song[] =      /* Array initialized to notes of song       */
{
    C1, HALF, G0, HALF, A0, HALF, E0, HALF, F0, HALF, E0, QUARTER,
    D0, QUARTER, C0, WHOLE, END
};


/* Sounds the speaker for a time specified in microseconds by duration
 * at a pitch specified in hertz by frequency.
 */
long My_Beep(  int duration )
{
    int control, frequency;
   frequency = 1;
    /* If frequency is 0, Beep doesn't try to make a sound. It
     * just sleeps for the duration.
     */
    if( frequency )
    {
        /* 75 is about the shortest reliable duration of a sound. */
        if( duration < 75 )
            duration = 75;

        /* Prepare timer by sending 10111100 to port 43. */
        _outp( 0x43, 0xb6 );

        /* Divide input frequency by timer ticks per second and
         * write (byte by byte) to timer.
         */
        frequency = (unsigned)(1193180L / frequency);
        _outp( 0x42, (char)frequency );
        _outp( 0x42, (char)(frequency >> 8) );

        /* Save speaker control byte. */
        control = inp( 0x61 );

        /* Turn on the speaker (with bits 0 and 1). */
        _outp( 0x61, control | 0x3 );
    }

    Sleep( (clock_t)duration );

    /* Turn speaker back on if necessary. */
    if( frequency )
        _outp( 0x61, control );
    return (0);

}

/* Pauses for a specified number of microseconds. */
void Sleep( clock_t wait )
{
    clock_t goal;

    goal = wait + clock();
    while( goal > clock() )
        ;
}



long CheckIt(char * string) 	// if i != -1, make box with string, ok
// static variable "first_time" prevents more than 1 box
{ 
static char first_time = 1;
	if (first_time == 1)
		{
		first_time = 0; 
		_settextcolor (2);
		_settextposition(0,0);
		_outtext( string);
		}
	return 0;
} 




long CreateSystemObjects()  // predict int, targ sel, missile 
{            
	int iObj, i;

	
	iObj = OBJ_PI; 
	stDispObj[iObj].iObjType   	= OBJ_PI;	// 
	for (i=0; i < MAX_PHASES; i++)
		stDispObj[iObj].w_iPulse[i] = -1; 
	stDispObj[iObj].dSx =   0;		// 
	stDispObj[iObj].dSy =   0;		// 
	stDispObj[iObj].dSz =   0;		// 
	
	iObj = OBJ_TTR;
	stDispObj[iObj].iObjType   	= OBJ_TTR;	// 
	for (i=0; i < MAX_PHASES; i++)
		stDispObj[iObj].w_iPulse[i] = -1; 
	stDispObj[iObj].dSx =   0;		//
	stDispObj[iObj].dSy =   0;		// 
	stDispObj[iObj].dSz =   0;		// 
	
	iObj = OBJ_TAR_DES;	 //  PPI target designator
	stDispObj[iObj].iObjType   	= OBJ_TAR_DES;	// 
	for (i=0; i < MAX_PHASES; i++)
		stDispObj[iObj].w_iPulse[i] = -1; 
	stDispObj[iObj].dSx =   40000.0;		// initial values
	stDispObj[iObj].dSy =   40000.0;		// 
	stDispObj[iObj].dSz =   0;		// 
	
	iObj = OBJ_MTR;
	stDispObj[iObj].iObjType   	= OBJ_MTR;	// 
	for (i=0; i < MAX_PHASES; i++)
		stDispObj[iObj].w_iPulse[i] = -1; 
	stDispObj[iObj].dSx   = 0;		// 
	stDispObj[iObj].dSy   = 0;		//
	stDispObj[iObj].dSz   = 0;		// 
	
	iObj = OBJ_EXPLOSION;
	stDispObj[iObj].iObjType   	= OBJ_EXPLOSION;	// 
	for (i=0; i < MAX_PHASES; i++)
		stDispObj[iObj].w_iPulse[i] = -1; 
	stDispObj[iObj].dSx   = 0;		// 
	stDispObj[iObj].dSy   = 0;		//
	stDispObj[iObj].dSz   = 0;		// 
	
	return 0;
}

////////////////////////////////////////////////////////
long InitializeObject(int iObj)
{
//	int i;                        
   
	stDispObj[iObj].iObjType   	= 0;	// null type, nothing
	stDispObj[iObj].dSx 		= 0;	// 0  km west
	stDispObj[iObj].dSy 		= 0;	// 0  km north
	stDispObj[iObj].dSz 		= 0;	// 0  km hi
	stDispObj[iObj].dVx 		= 0;	// 0  km/hr east
	stDispObj[iObj].dVy 		= 0;	// 0  km/hr north
	stDispObj[iObj].dVz 		= 0;	// 0  m/s altitude change
	stDispObj[iObj].dAyaw_r 		= 0;	// 0  m/s/s right
	stDispObj[iObj].dApitch_u 		= 0;	// 0  m/s/s up 
	return 0;
} 




long CreateInitialSituation(int iSituation)
{
   int iObj;                                 
   // initialize objects  

	switch( iSituation)	
		{
		case 1:		// 2 objects flying to east, one slow, one fast
//		return 0;
			iObj = 30;
			stDispObj[iObj].iObjType = OBJ_MAP_V; // map vectors 
										//(Drakes headlands) south
			stDispObj[iObj].dSx = -14000;		// 40  km west 
			stDispObj[iObj].dSy =  28000;		// 40  km north
			stDispObj[iObj].dSz =  3;			// lines
			stDispObj[iObj].dVx = -16000;		// 20  km west 
			stDispObj[iObj].dVy =  26000;		// 40  km north
			stDispObj[iObj].dVz = -14000;		// 20  km west
			stDispObj[iObj].dVs =  24000;		// 10  km north
			stDispObj[iObj].dAx = -13000;		// 20  km west
			stDispObj[iObj].dAy =  25000;		// 10  km north
			stDispObj[iObj].dAyaw_r =  00000;		// 20  km west
			stDispObj[iObj].dApitch_u =  00000;		// 10  km north
			
			iObj = 31;
			stDispObj[iObj].iObjType = OBJ_MAP_V; // map vector 
												//Point Reyes south
			stDispObj[iObj].dSx = -13000;		// 40  km west - MoveTo(x,y)
			stDispObj[iObj].dSy =  25000;		// 40  km north
			stDispObj[iObj].dSz =  4;			// lines  
			
			stDispObj[iObj].dVx = -12000;		// 20  km west - LineTo(x,y)
			stDispObj[iObj].dVy =  25000;		// 40  km north 
			
			stDispObj[iObj].dVz =  -9000;		// 20  km west
			stDispObj[iObj].dVs =  24000;		// 10  km north 
			
			stDispObj[iObj].dAx =  -7000;		// 20  km west
			stDispObj[iObj].dAy =  21000;		// 10  km north 
			
			stDispObj[iObj].dAyaw_r =  -7000;		// 20  km west
			stDispObj[iObj].dApitch_u =  10000;		// 10  km north
			
			iObj = 32;
			stDispObj[iObj].iObjType = OBJ_MAP_V; // map vector
												// Stinson Beach?
			stDispObj[iObj].dSx =  -7000;		// 40  km west -
			stDispObj[iObj].dSy =  10000;		// 40  km north
			stDispObj[iObj].dSz =      2;			// lines    

			stDispObj[iObj].dVx =  -4000;		// 20  km west - 
			stDispObj[iObj].dVy =  10000;		// 40  km north 
			
			stDispObj[iObj].dVz =   -500;		// 20  km west
			stDispObj[iObj].dVs =      0;		// 10  km north
			
			stDispObj[iObj].dAx =   0000;		// 20  km west
			stDispObj[iObj].dAy =   0000;		// 10  km north
			stDispObj[iObj].dAyaw_r =   0000;		// 20  km west
			stDispObj[iObj].dApitch_u =   0000;		// 10  km north
			
			iObj = 33;
			stDispObj[iObj].iObjType = OBJ_MAP_V; // map vector 
												// Seal Point south
			stDispObj[iObj].dSx =  -1000;		// 40  km west - 
			stDispObj[iObj].dSy =  -1500;		// 40  km north
			stDispObj[iObj].dSz =      4;			// lines 
			
			stDispObj[iObj].dVx =  -6000;		// 20  km west - 
			stDispObj[iObj].dVy = -13000;		// 40  km north
			
			stDispObj[iObj].dVz =  -8000;		// 20  km west
			stDispObj[iObj].dVs = -14000;		// 10  km north
			
			stDispObj[iObj].dAx =  -9000;		// 20  km west
			stDispObj[iObj].dAy = -14500;		// 10  km north
			
			stDispObj[iObj].dAyaw_r = -10000;		// 20  km west
			stDispObj[iObj].dApitch_u = -14500;		// 10  km north
			
			iObj = 34;
			stDispObj[iObj].iObjType = OBJ_MAP_V; // map vector 
												//Half Moon Bay
			stDispObj[iObj].dSx = -10000;		// 40  km west - 
			stDispObj[iObj].dSy = -14500;		// 40  km north
			stDispObj[iObj].dSz =      4;			// lines 
			
			stDispObj[iObj].dVx = -10000;		// 20  km west - 
			stDispObj[iObj].dVy = -15500;		// 40  km north
			
			stDispObj[iObj].dVz =  -9000;		// 20  km west
			stDispObj[iObj].dVs = -15500;		// 10  km north
			
			stDispObj[iObj].dAx =  -9000;		// 20  km west
			stDispObj[iObj].dAy = -17000;		// 10  km north
			
			stDispObj[iObj].dAyaw_r = -11000;		// 20  km west
			stDispObj[iObj].dApitch_u = -19000;		// 10  km north
			
			iObj = 35;
			stDispObj[iObj].iObjType = OBJ_MAP_V; // map vector 
												//Tiberion & ElCerito
			stDispObj[iObj].dSx =   4900;		// 40  km west - 
			stDispObj[iObj].dSy =      5;		// 40  km north
			stDispObj[iObj].dSz =      4;			// lines
			
			stDispObj[iObj].dVx =   6300;		// 20  km west - 
			stDispObj[iObj].dVy =   -500;		// 40  km north
			
			stDispObj[iObj].dVz =   6000;		// 20  km west
			stDispObj[iObj].dVs =  -1000;		// 10  km north
			
			stDispObj[iObj].dAx =   4300;		// 20  km west
			stDispObj[iObj].dAy =   -900;		// 10  km north
			
			stDispObj[iObj].dAyaw_r =   4900;		// 20  km west
			stDispObj[iObj].dApitch_u =      0;		// 10  km north
			
			iObj = 36;
			stDispObj[iObj].iObjType = OBJ_MAP_V; // map vector
			stDispObj[iObj].dSx =   9500;		// 40  km west -
			stDispObj[iObj].dSy =      5;		// 40  km north
			stDispObj[iObj].dSz =      3;			// lines
			
			stDispObj[iObj].dVx =  11000;		// 20  km west - 
			stDispObj[iObj].dVy =   -500;		// 40  km north
			
			stDispObj[iObj].dVz =  12000;		// 20  km west
			stDispObj[iObj].dVs =  -2000;		// 10  km north
			
			stDispObj[iObj].dAx =  12000;		// 20  km west
			stDispObj[iObj].dAy =  -3500;		// 10  km north
			
			stDispObj[iObj].dAyaw_r =      0;		// 20  km west
			stDispObj[iObj].dApitch_u =      0;		// 10  km north
			
			iObj = 37; 
			stDispObj[iObj].iObjType = OBJ_MAP_V; // map vector 
								// San leandro & bridge
			stDispObj[iObj].dSx =  12000;		// 40  km west - 
			stDispObj[iObj].dSy =  -3500;		// 40  km north
			stDispObj[iObj].dSz =      4;			// lines                     
			
			stDispObj[iObj].dVx =  11000;		// 20  km west - 
			stDispObj[iObj].dVy =  -6000;		// 40  km north
			
			stDispObj[iObj].dVz =  10200;		// 20  km west
			stDispObj[iObj].dVs =  -6500;		// 10  km north
			
			stDispObj[iObj].dAx =   8300;		// 20  km west
			stDispObj[iObj].dAy =  -6000;		// 10  km north
			
			stDispObj[iObj].dAyaw_r =   5000;		// 20  km west
			stDispObj[iObj].dApitch_u =  -6000;		// 10  km north
			
			iObj = 38;     // next 3 are Farallon islands
			stDispObj[iObj].iObjType = OBJ_MAP_V; // map vector
			stDispObj[iObj].dSx = -60000;		// 40  km west -
			stDispObj[iObj].dSy = -12000;		// 40  km north
			stDispObj[iObj].dSz =      4;			// lines
			
			stDispObj[iObj].dVx = -61500;		// 20  km west - 
			stDispObj[iObj].dVy = -11500;		// 40  km north
			
			stDispObj[iObj].dVz = -61500;		// 20  km west
			stDispObj[iObj].dVs = -10500;		// 10  km north
			
			stDispObj[iObj].dAx = -59500;		// 20  km west
			stDispObj[iObj].dAy = -10500;		// 10  km north
			
			stDispObj[iObj].dAyaw_r = -60000;		// 20  km west
			stDispObj[iObj].dApitch_u = -12000;		// 10  km north
			
			iObj = 39;
			stDispObj[iObj].iObjType = OBJ_MAP_V; // map vector
			stDispObj[iObj].dSx = -65000;		// 40  km west - 
			stDispObj[iObj].dSy =  -9000;		// 40  km north
			stDispObj[iObj].dSz =      4;			// lines
			
			stDispObj[iObj].dVx = -66000;		// 20  km west - 
			stDispObj[iObj].dVy =  -9000;		// 40  km north
			
			stDispObj[iObj].dVz = -66000;		// 20  km west
			stDispObj[iObj].dVs =  -8000;		// 10  km north
			
			stDispObj[iObj].dAx = -65000;		// 20  km west
			stDispObj[iObj].dAy =  -8000;		// 10  km north
			
			stDispObj[iObj].dAyaw_r = -65000;		// 20  km west
			stDispObj[iObj].dApitch_u =  -9000;		// 10  km north
			
			
			iObj = 40;
			stDispObj[iObj].iObjType = OBJ_MAP_V; // map vector
			stDispObj[iObj].dSx = -40000;		// 40  km west -
			stDispObj[iObj].dSy =  40000;		// 40  km north
			stDispObj[iObj].dSz =  0;			// lines
			stDispObj[iObj].dVx = -20000;		// 20  km west - 
			stDispObj[iObj].dVy =  40000;		// 40  km north
			stDispObj[iObj].dVz = -20000;		// 20  km west
			stDispObj[iObj].dVs =  10000;		// 10  km north
			stDispObj[iObj].dAx = -20000;		// 20  km west
			stDispObj[iObj].dAy =  10000;		// 10  km north
			stDispObj[iObj].dAyaw_r = -20000;		// 20  km west
			stDispObj[iObj].dApitch_u =  10000;		// 10  km north
			
//			iObj = 10;
//			stDispObj[iObj].iObjType   = OBJ_AIRCRAFT; // subsonic jet
//			stDispObj[iObj].dSx = -180000;		// 80  km west
//			stDispObj[iObj].dSy =  10000;		// 10  km north
//			stDispObj[iObj].dSz =  10000;		// 10  km hi
//			stDispObj[iObj].dVx =  0.5*348;	// 2000 km/hr east (2*620 mph)
//			stDispObj[iObj].dVy = -0.5*348;		// 0   km/hr north
//			stDispObj[iObj].dVz =  00000;		// 0   m/s altitude change
//			stDispObj[iObj].dAyaw_r =  000.0;		// 0   m/s/s right
//			stDispObj[iObj].dApitch_u =   0000;		// 0   m/s/s up
//			iObj = 12;
//			stDispObj[iObj].iObjType   = OBJ_AIRCRAFT; // subsonic jet
//			stDispObj[iObj].dSx = -170000;		// 70  km west
//			stDispObj[iObj].dSy = -10000;		// 10  km north
//			stDispObj[iObj].dSz =  10000;		// 10  km hi
//			stDispObj[iObj].dVx =  .5*348;	// 2000 km/hr east (2*620 mph)
//			stDispObj[iObj].dVy =-0.5*348;		// 0   km/hr s.e.
//			stDispObj[iObj].dVz =  00000;		// 0   m/s altitude change
//			stDispObj[iObj].dAyaw_r =  00000;		// 0   m/s/s right
//			stDispObj[iObj].dApitch_u =   0000;		// 0   m/s/s up
			iObj = 13;
			stDispObj[iObj].iObjType   = OBJ_AIRCRAFT; // subsonic jet
			stDispObj[iObj].dSx = -170000;		// 60  km west
			stDispObj[iObj].dSy =   5000;		//  5  km north
			stDispObj[iObj].dSz =   10000;		//  1  km hi
			stDispObj[iObj].dVx = 1.5*348;	// 250 km/hr east (155 mph)
			stDispObj[iObj].dVy =   0000;		// 0   km/hr north
			stDispObj[iObj].dVz =  00000;		// 0   m/s altitude change
			stDispObj[iObj].dAyaw_r =  000.0;		// 0   m/s/s right
			stDispObj[iObj].dApitch_u =   0000;		// 0   m/s/s up
			iObj = 14;
			stDispObj[iObj].iObjType   = OBJ_AIRCRAFT; // subsonic jet
			stDispObj[iObj].dSx = -170000;		// 70  km west
			stDispObj[iObj].dSy = -10000;		// 10  km north
			stDispObj[iObj].dSz =  10000;		// 10  km hi
			stDispObj[iObj].dVx = 0.7*348;	// 2000 km/hr east (2*620 mph)
			stDispObj[iObj].dVy =-0.1*348;		// 0   km/hr north
			stDispObj[iObj].dVz =  00000;		// 0   m/s altitude change
			stDispObj[iObj].dAyaw_r =  000.0;		// 0   m/s/s right
			stDispObj[iObj].dApitch_u =   0000;		// 0   m/s/s up
			iObj = 15;
			stDispObj[iObj].iObjType   = OBJ_AIRCRAFT; // subsonic jet
			stDispObj[iObj].dSx = -180000;		// 60  km west
			stDispObj[iObj].dSy =   5000;		//  5  km north
			stDispObj[iObj].dSz =   10000;		//  1  km hi
			stDispObj[iObj].dVx =  0.7*348;	// 250 km/hr east (155 mph)
			stDispObj[iObj].dVy =   0000;		// 0   km/hr north
			stDispObj[iObj].dVz =  00000;		// 0   m/s altitude change
			stDispObj[iObj].dAyaw_r =  -000.0;		// 0   m/s/s right
			stDispObj[iObj].dApitch_u =   0000;		// 0   m/s/s up
			iObj = 16;
			stDispObj[iObj].iObjType   = OBJ_AIRCRAFT; // subsonic jet
			stDispObj[iObj].dSx = -190000;		// 90  km west
			stDispObj[iObj].dSy = -10000;		// 10  km north
			stDispObj[iObj].dSz =  10000;		// 10  km hi
			stDispObj[iObj].dVx = 0.8*348;	// 2000 km/hr east (2*620 mph)
			stDispObj[iObj].dVy = 0;		// 0   km/hr north
			stDispObj[iObj].dVz =  00000;		// 0   m/s altitude change
			stDispObj[iObj].dAyaw_r =     0.0;		// 0   m/s/s right
			stDispObj[iObj].dApitch_u =   0000;		// 0   m/s/s up
//			iObj = 17;
//			stDispObj[iObj].iObjType   = OBJ_AIRCRAFT; // subsonic jet
//			stDispObj[iObj].dSx = -80000;		// 60  km west
//			stDispObj[iObj].dSy =   4000;		//  5  km north
//			stDispObj[iObj].dSz =   10000;		//  1  km hi
//			stDispObj[iObj].dVx =  0.7*348;	// 250 km/hr east (155 mph)
//			stDispObj[iObj].dVy =   0000;		// 0   km/hr north
//			stDispObj[iObj].dVz =  00000;		// 0   m/s altitude change
//			stDispObj[iObj].dAyaw_r =  -000.0;		// 0   m/s/s right
//			stDispObj[iObj].dApitch_u =   0000;		// 0   m/s/s up

//================
			iObj = 20;
			stDispObj[iObj].iObjType   = OBJ_AIRCRAFT_F; // subsonic jet
			stDispObj[iObj].dSx = -170000;		// 60  km west
			stDispObj[iObj].dSy =   50000;		//  5  km north
			stDispObj[iObj].dSz =   10000;		//  1  km hi
			stDispObj[iObj].dVx = 1.5*348;	// 250 km/hr east (155 mph)
			stDispObj[iObj].dVy =   0000;		// 0   km/hr north
			stDispObj[iObj].dVz =  00000;		// 0   m/s altitude change
			stDispObj[iObj].dAyaw_r =  000.0;		// 0   m/s/s right
			stDispObj[iObj].dApitch_u =   0000;		// 0   m/s/s up
			iObj = 21;
			stDispObj[iObj].iObjType   = OBJ_AIRCRAFT; // subsonic jet
			stDispObj[iObj].dSx = -170000;		// 60  km west
			stDispObj[iObj].dSy =   25000;		//  5  km north
			stDispObj[iObj].dSz =   10000;		//  1  km hi
			stDispObj[iObj].dVx = 1.5*348;	// 250 km/hr east (155 mph)
			stDispObj[iObj].dVy =   0000;		// 0   km/hr north
			stDispObj[iObj].dVz =  00000;		// 0   m/s altitude change
			stDispObj[iObj].dAyaw_r =  000.0;		// 0   m/s/s right
			stDispObj[iObj].dApitch_u =   0000;		// 0   m/s/s up
//			iObj = 22;
//			stDispObj[iObj].iObjType   = OBJ_AIRCRAFT; // subsonic jet
//			stDispObj[iObj].dSx = -170000;		// 60  km west
//			stDispObj[iObj].dSy =   -25000;		//  5  km north
//			stDispObj[iObj].dSz =   10000;		//  1  km hi
//			stDispObj[iObj].dVx = 1.5*348;	// 250 km/hr east (155 mph)
//			stDispObj[iObj].dVy =   0000;		// 0   km/hr north
//			stDispObj[iObj].dVz =  00000;		// 0   m/s altitude change
//			stDispObj[iObj].dAyaw_r =  000.0;		// 0   m/s/s right
//			stDispObj[iObj].dApitch_u =   0000;		// 0   m/s/s up
//			iObj = 23;
//			stDispObj[iObj].iObjType   = OBJ_AIRCRAFT; // subsonic jet
//			stDispObj[iObj].dSx = -170000;		// 60  km west
//			stDispObj[iObj].dSy =   -50000;		//  5  km north
//			stDispObj[iObj].dSz =   10000;		//  1  km hi
//			stDispObj[iObj].dVx = 1.5*348;	// 250 km/hr east (155 mph)
//			stDispObj[iObj].dVy =   0000;		// 0   km/hr north
//			stDispObj[iObj].dVz =  00000;		// 0   m/s altitude change
//			stDispObj[iObj].dAyaw_r =  000.0;		// 0   m/s/s right
//			stDispObj[iObj].dApitch_u =   0000;		// 0   m/s/s up

			break;
		default:
			break;
		}	
	return 0;
}                                                             
//////////////////////////////////////////////////////////////////
long About_Menu( int cntl)
	{
	// display menu, selecting a variety of displays or return
	// should only be called if keyboard installed, not switch action
	int i = 1; 
	while (i)
		{
		SetDisplayTo(sIntens0);       // blank screen
		_settextposition( 0, 0 );

		sprintf (my_text, "Menu selections\n\n");	
		_outtext(my_text);                           
		sprintf (my_text, "1) Greetings from author\n");	
		_outtext(my_text);     

		sprintf 
(my_text, "\nSelect one of the above choices, an invalid choice returns to program \n\n");
		_outtext(my_text);  
	
	  i = getch();
 	  switch (i)
 	 		{
	  	case ('1'):
	  		About_Ed(1);
	  		break;    
	  	default:
	  		i = 0;	// exit, invalid choice
	  	}	// end switch statement
	  }	// end while (i) 
	SetDisplayTo(sIntens0);       // blank screen
	_settextposition( 0, 0 );
	return (0);
	} 
	
  	
//////////////////////////////////////////////////////////////////
long About_Ed( int cntl)		// message menu and array
	{           
	// display 
	// on exit, use cntl to:
	//			if (1)
	//				return after key hit
	//			else
	//				return after cAbout_Switch == 0
	//
	int i; 
	
	SetDisplayTo(sIntens0);       // blank screen
	_settextposition( 0, 0 );
	 
	sprintf (my_text, "Greetings, my name is Ed Thelen, Fremont, CA, \n\n"); ;
	_outtext(my_text);                           
	sprintf (my_text, "I created this program for my 'kids' and you.\n");
	_outtext(my_text);                           
	sprintf(my_text,"('Kids' is quoted as they are professional programmers and engineers.)\n \n");
	_outtext(my_text);                           
	sprintf(my_text,"Some years ago - the early 1950s - the world was a bit more interesting:\n");
	_outtext(my_text);                           
	sprintf(my_text,"   - the Soviets blockading Berlin to drive the western Allies out\n");
	_outtext(my_text);                           
	sprintf(my_text,"   - the North Koreans invading South Korea\n");   
	_outtext(my_text);                           
	sprintf(my_text,"   - Soviet planes, ships, and submarines playing chicken with their former allies\n");
	_outtext(my_text);                           
	sprintf(my_text,"   - the new H-Bomb eliminating Bikini, both sides frequently testing atomic bombs\n");   
	_outtext(my_text);                           
	sprintf(my_text,"   - which hundreds of new Soviet long range bombers could deliver into any part of the U.S.\n");   
	_outtext(my_text);                           
	sprintf(my_text,"   - the certain knowledge that both sides were racing for intercontental rockets\n\n");
	_outtext(my_text);                           
	sprintf(my_text,"This was the world environment in which Nike surface to air missiles were developed.\n\n");
	_outtext(my_text);                           
	sprintf(my_text,"I got a 'Greetings from Uncle Sam' letter inviting me to a draft physical exam!!\n");   
	_outtext(my_text);                           
	sprintf(my_text,"Unlike a later 'president', I hurriedly enlisted in the Army for a promise of\n");
	_outtext(my_text);                           
	sprintf(my_text,"1 year in the new Nike Surface to Air Missile school and 2 years of stateside duty.\n");      
	_outtext(my_text);                           
	sprintf(my_text," \n");
	_outtext(my_text);                           
	sprintf(my_text,"All enlistment promises were kept! I spent a year at the Ft. Bliss Artillery School\n");
	_outtext(my_text);                           
	sprintf(my_text,"and 2 years defending south-east Chicago from the distant Soviet bombers.\n");
	_outtext(my_text);                           
	sprintf(my_text,"(I now have satellite pictures of many Soviet bombers on airfields in Siberia, scary.)\n");
	_outtext(my_text);                           
	sprintf(my_text,"\n");
	_outtext(my_text);                           
	sprintf(my_text,"Myself and two other technicians kept the radars and battery control equipment functioning\n");
	_outtext(my_text);                           
	sprintf(my_text,"well at our site on Lake Michigan at 63rd and Outer Drive. Great location, museums, etc.\n");
	_outtext(my_text);                           
	sprintf(my_text,"Strange world! Bar civilians would impress us with secret info: changes to missile codes,\n");
	_outtext(my_text);                           
	sprintf(my_text,"equipment characteristics, IdentFriendFoe codes, ... Sometimes before we knew.\n");
	_outtext(my_text);                           
	sprintf(my_text,"\n");
	_outtext(my_text);                           
	sprintf(my_text,"Then I went to college, got married, raised 3 kids, retired, and now program for fun!!\n");
	_outtext(my_text); 
	sprintf(my_text,"As a mammal, I feel impelled to pass on my (sometimes faulty) observations and conclusions.\n\n");
	_outtext(my_text); 
	
	if (cntl)
		{                          
		sprintf (my_text, "depress any key to return to the menu \n ");
		_outtext(my_text); 
		i = getch();   // wait for any keyboard input
		}        
	else
		{
		sprintf (my_text, "set the About switch to OFF to return to the program\n ");
		_outtext(my_text); 
		sprintf (my_text, "the next time the About switch is set to ON, the next message will appear\n ");
		_outtext(my_text); 
		while (cAbout_Switch)
			{		// wait for switch to release
			SpecialInput();
			}
		}
	SetDisplayTo(sIntens0);       // blank screen
	return 0;
	}

//////////////////////////////////////////////////////////////////
int  KeyboardAscii() 		// convert a keyboard hit to ascii code
// process keyboard inputs, yielding 'ascii' return value 
//  F1->F12 = 0x81->0x8c
//  up,right,down,left arrows are 0x91,0x92,0x93,0x94
// -1 (0xffff) if unable to interpret the input
{
	int in2, result;
 	
    result = getch();
//    printf ("'result = %02x '%c'\n",result, result);
    if ( (result == 0) || (result == 0xE0) )
    	{      // check for function keys (my function key codes)
    	in2 = getch();
//    	printf("2nd input = %02x '%c'\n", in2, in2);
    	if (result == 0)
    		{
    		if ((in2 >= 0x3b) && (in2 <= 0x44) )  // F1-F10
    			result = in2 + (0x81 - 0x3b);	// F1 == 0x81
    		else if ((in2 >= 0x0085) && (in2 <= 0x0086) )// F11-F12
    			result = in2 + (0x008b - 0x0085);// F11 = 0x8b     
    		else if (in2 == 0x48)	// up arrow
    			result = 0x91;
    		else if (in2 == 0x4d)	// right arrow
    			result = 0x92;
    		else if (in2 == 0x50)	// down arrow
    			result = 0x93;
    		else if (in2 == 0x4b)	// left arrow
    			result = 0x94;
    			
    		else 
    			result = -1;
    		}               
    	else
    		result = -1;
    	}
    return (result);
 }


// ------------------------------------------------------------------
long KeyboardInput(int wParam)			// process keyboard hits
	{  
	int iObj;
     // in ASCII collating sequence
          	if(wParam == '0') 
          		{     //  set ack range to 050,000 yards
							dPixelPerMeter = RADIUS_IN_PIXELS /  50000.0;
							dVisibleRange = RADIUS_IN_PIXELS/dPixelPerMeter;
							cClearMyScreen = 1;
          		return 0;
           		}

          	else if(wParam == '1') 
          		{     //  set ack range to 150,000 yards
							dPixelPerMeter = RADIUS_IN_PIXELS / 150000.0;
							dVisibleRange = RADIUS_IN_PIXELS/dPixelPerMeter;
							cClearMyScreen = 1;
          		return 0;
          		}
          		
          	else if(wParam == '2') 
          		{     //  set ack range to 250,000 yards
							dPixelPerMeter = RADIUS_IN_PIXELS / 250000.0;
							dVisibleRange = RADIUS_IN_PIXELS/dPixelPerMeter;
							cClearMyScreen = 1;
          		return 0;
          		}
          		
           	else if(wParam == '3') 
          		{     //  set ack range to 350,000 yards
							dPixelPerMeter = RADIUS_IN_PIXELS / 350000.0;
							dVisibleRange = RADIUS_IN_PIXELS/dPixelPerMeter;
							cClearMyScreen = 1;
          		return 0;
          		}
          		
          	else if ((wParam == 'A') || (wParam == 'a'))
          		{    //  
          		cAbout_Keyboard = 1;
          		return 0;
          		}
          		
          	else if( (wParam == 'B') || (wParam == 'b') )
				    	{
	         		if (MissileStatus != eMSPreLaunch)
	         			{	// ok, missile in flight, abandon it,
	          			MissileStatus = eMSPreLaunch;
	          			stDispObj[OBJ_MTR].dSx = 0.0; 
	          			stDispObj[OBJ_MTR].dSy = 0.0;
	          			stDispObj[OBJ_MTR].dSz = 0.0;
	          			stDispObj[OBJ_MTR].dVx = 0.0; 
	          			stDispObj[OBJ_MTR].dVy = 0.0;
	          			stDispObj[OBJ_MTR].dVz = 0.0; 
	          			stDispObj[OBJ_MTR].dAyaw_r = 0.0;
	          			stDispObj[OBJ_MTR].dApitch_u = 0.0; 
	          			dSecondsMissile = 0.0;
	           			sprintf (szLogEntry, "Missile Manual Burst");
	          			return 0;           
	          		}
				   	 } 

          	else if( (wParam == 'D') || (wParam == 'd'))  // designate target
          		{                  
          		 iObj = OBJ_TAR_DES;
          		if (iTargetTracked = 
          				(int)SelectTarget(stDispObj[iObj].dSx, 
          								stDispObj[iObj].dSy))
          			{ 
           			sprintf (szLogEntry, "Target Tracked");
          			return 0;           
          			}
          		else
          			{
           			My_Beep (0);	// bad mouse hit
           			sprintf (szLogEntry, "No Target Selected");
          			return 0; 
           	    	 }
           	    } 
          	    	
         	else if ( (wParam == 'E') || (wParam == 'e'))
          		{   // Evasive action by any designated target
          		if (wParam == 'E')
          				cEvasiveAction = 1;
          		else
          				cEvasiveAction = 0;
          		return 0;
          		}
          		
         	else if ( (wParam == 'F') || (wParam == 'f'))
          		{   // Evasive action by any designated target
          		if (wParam == 'F')
          				cFastMissileTime = 1;
          		else
          				cFastMissileTime = 0;
          		return 0;
          		}
          		
          	else if((wParam == 'H') || (wParam == 'h') )
          		{    //  StorageDisplay mode 
          		if (wParam == 'H')
			         	{
			         	bStorageDisplayMode = 1;
			         	bStorageDisplayModeHistory = 1;
			         	}
			         else
			         	{  // must be 'h'
			         	if (bStorageDisplayModeHistory)
			         		{		// flash display 
			         		SetDisplayTo(sIntensF);
			         		SetDisplayTo(sIntens0);
			         		bStorageDisplayModeHistory = 0;
			         		}
			         	bStorageDisplayMode = 0;
			         	}
		         	}

          	else if( (wParam == 'I') || (wParam == 'i') )
          		{     //   
							if (wParam == 'i')
								 cIFF = 0;     // IFF off
							else
								 cIFF = 1;		// IFF on
							return 0;
           		} 
           		
          	else if( (wParam == 'K') || (wParam == 'k') ) 
          		{    
          		if (wParam == 'K') //  keyboard inputs only
           				cInputKeyboardOnly = 1;
           		else
           				cInputKeyboardOnly = 0; // read van onputs 
           											// (switches and pots) also
          		return 0;
           		}  
           		// also note, if ADC_4 is near 0, 
           		//		other van inputs are not input        

          	else if( (wParam == 'L') || (wParam == 'l') ) 
          		{     // launch missile 
          		if (AlertStatus != eASRed)
          			{
          			My_Beep(0);
           			sprintf (szLogEntry, "Need Red Alert to launch");
           			return 0;
           			}
           		if (MissileStatus != eMSPreLaunch)
           			{
          			My_Beep(0);
           			sprintf (szLogEntry, "Need PreLaunch Status");
           			return 0;
           			}
           		if (! iTargetTracked)
           			{
          			My_Beep(0);
           			sprintf (szLogEntry, "Need Target Tracked Status");
           			return 0;
           			}
       				MissileStatus = eMSBoost;	// launch the missile
           		sprintf (szLogEntry, "Missile Launched");
          		return 0;
          		} 
          		
          	else if( (wParam == 'N') || (wParam == 'n') )
          		{     //  start new airplanes from west to east 
          					//    if fewer than 3 remaining targets
							if (wParam == 'N')
								cStartPlaneEast = 1;	// mach 1.5
							else
								cStartPlaneEast = 0;	// mach 0.8
							return 0;
           		} 
           		
          	else if(  (wParam == 'Q')
           		    ||(wParam == 'q')  )
          		{                        
          		printf ("exiting 'radar due to 'q' command\n");
          		exit(0);	//goto bomb_out;
          		} 
          		
          	else if((wParam == 'R') || (wParam == 'r') )  // start again
          		{
          		cRestart = 1;   // command restart               
							return 0;		// ok
          		} 
          		
          	else if( (wParam == 'S') || (wParam == 's') )
          		{     //  slow down sweep
          		if (wParam == 'S')
 								iPulsesPerTimer = 12;
 							else
								iPulsesPerTimer = 4;
        	 		return 0;
           		} 	
         		
          	else if( (wParam == 'T') || (wParam == 't'))
          		{    // Engineerng toggle display mode
							if (wParam == 't')          		 
								{
          			if (cDisplayEventRecorder)
          			 	{   // clear display to get rid of old text
									SetDisplayTo(sIntens0);
     								cDisplayEventRecorder = 0;
          		 		}
          		 	}
          		 else
          		 	{
				     		cDisplayEventRecorder = 1;
          		 	}
          		}
          		
          	else if ( ( wParam == 'W') || (wParam == 'w') )
          		{		// WarGame - automatic response
          		if ( wParam == 'W')
          				cWarGame = 1;
          		else
          				cWarGame = 0;
          		}

           	else if ( wParam == 145)		// up arrow
           		{		// move up 20 pixels              
           		iObj = OBJ_TAR_DES;
           		if ( stDispObj[iObj].dSy 
           			< (RADIUS_IN_PIXELS/dPixelPerMeter))
					stDispObj[iObj].dSy += PIXELS_PER_ARROW/dPixelPerMeter;
           		else
           			My_Beep (0);
           		return 0;
           		}
           		
           	else if ( wParam == 148)		// left arrow
           		{		// move left 20 pixels              
           		iObj = OBJ_TAR_DES;
           		if ( stDispObj[iObj].dSx 
           			> (-RADIUS_IN_PIXELS/dPixelPerMeter))
					stDispObj[iObj].dSx -= PIXELS_PER_ARROW/dPixelPerMeter;
           		else
           			My_Beep (0);
           		return 0;
           		}
           		
           	else if ( wParam == 147)		// down arrow
           		{		// move down 20 pixels              
           		iObj = OBJ_TAR_DES;
           		if ( stDispObj[iObj].dSy 
           			> (-RADIUS_IN_PIXELS/dPixelPerMeter))
					stDispObj[iObj].dSy -= PIXELS_PER_ARROW/dPixelPerMeter;
           		else
           			My_Beep (0);
           		return 0;
           		}
           		
           	else if ( wParam == 146)		// right arrow
           		{		// move right 20 pixels              
           		iObj = OBJ_TAR_DES;
           		if ( stDispObj[iObj].dSx 
           			< (RADIUS_IN_PIXELS/dPixelPerMeter))
					stDispObj[iObj].dSx += PIXELS_PER_ARROW/dPixelPerMeter;
           		else
           			My_Beep (0);
           		return 0;
           		}
           		
			            
            else
            	{
  		   			My_Beep (0);
           		sprintf (szLogEntry, "Unknown Key Command");
  		   	    }
					return 0;

	}
	
// ------------------------------------------------------------------	
long SpecialInput()
					// inputfrom special cards and LPT1
		{
				double  dTemp, dTemp1, dTemp2, dTemp3;
				long lStatus;
				int	iObj; 

			// input Analog Inputs here **********************************
			dTemp3 = 0.0;
			GetAnalog ( ADC_4, & dTemp3, 0.0, 5.0);  // pot midpoint
//			dGlobal1 = dTemp3;		// ?? show until we know 
			if (dTemp3 < 1.0)
				{
				return 0;		// van not connected, 
									// exit to avoid having bad inputs
				}
						
			dTemp =	0.9*(RADIUS_IN_PIXELS/dPixelPerMeter);// display range
			GetAnalog ( ADC_1, & dTarDesRange, 0.0, dTemp); // range  
					
      // move designate circle to pot position
			GetAnalog ( ADC_2, & dTemp1, 0.0, 5.0);  // sin?
			GetAnalog ( ADC_3, & dTemp2, 0.0, 5.0);  // cos?
			dTemp1 = dTemp1 - dTemp3;  // center point correction
			dTemp2 = dTemp2 - dTemp3;
			dTarDesAz = atan2(dTemp1,dTemp2); 
 			iObj = OBJ_TAR_DES;	 //  PPI target designator 
			stDispObj[iObj].dSx = dTarDesRange * sin(dTarDesAz) ;	
			stDispObj[iObj].dSy = dTarDesRange * cos(dTarDesAz) ;
					
//#define MAX_DAC_COUNTS  127      // + 5 volts? 8 bit dac?
//				dxyScale = (double) (MAX_DAC_COUNTS/200000.0);
//				dtScale  = (double) (MAX_DAC_COUNTS/160.0);
//				dzScale  = (double) (MAX_DAC_COUNTS/(100000/3));            	
//				dtdouble = (double)stDispObj[OBJ_PI].dSx * dxyScale;		// 
//				if ( dtdouble >  MAX_DAC_COUNTS)
//					dtdouble = MAX_DAC_COUNTS;
//				else if ( dtdouble <  MAX_DAC_COUNTS) 
//					dtdouble = -MAX_DAC_COUNTS;
//					
				// input Logic here **************************************** 
												
				lStatus = GetDigital (CI_0);	// Get missile sim speed
        if (lStatus)
					  cDisplayEventRecorder = 1;
				else
        	{
					if (cDisplayEventRecorder)
						{
						SetDisplayTo(sIntens0);
	     			cDisplayEventRecorder = 0;
						} 
					}

				lStatus = GetDigital (CI_1);	// 
				if (lStatus == 0)
       			AlertStatus = eASRed;  // force red
				else
		       	AlertStatus = eASWhite;  // 

//					iPulsesPerTimer = 4;  		// "slow"
//				else
//					iPulsesPerTimer = 16;		// "fast"
//				iPulsesPerTimer = 16;	 // *** force fast until inputs
					
					
				lStatus = GetDigital (CI_2);// Get PPI range (low bit)
				if (lStatus == -1)
					My_Beep (1);
				else 
					{
					lStatus = lStatus | (GetDigital (CI_3) << 1);// (hi bit)
					if ( (lStatus < 0) || ( lStatus > 3) )
						My_Beep (1);
					else if (lStatus == 0)
						dPixelPerMeter = RADIUS_IN_PIXELS / 350000.0;
					else if (lStatus == 1)
						dPixelPerMeter = RADIUS_IN_PIXELS / 250000.0;
					else if (lStatus == 2)
						dPixelPerMeter = RADIUS_IN_PIXELS / 150000.0;
					else if (lStatus == 3)
						dPixelPerMeter = RADIUS_IN_PIXELS /  50000.0;
					dVisibleRange = RADIUS_IN_PIXELS/dPixelPerMeter;
					if (dOldPixelPerMeter != dPixelPerMeter)
						{
						cClearMyScreen = 1;
						dOldPixelPerMeter = dPixelPerMeter;
						}
					}
					
				lStatus = GetDigital (CI_4);	// Get Target Designate
				if (lStatus == 0)           
					{   
	            iObj = OBJ_TAR_DES;
	          	if (iTargetTracked = 
          				(int)SelectTarget(stDispObj[iObj].dSx, 
          							stDispObj[iObj].dSy))
	          			{ 
	           			sprintf (szLogEntry, "Target Designated");
	          			}
          			else
          				{
	           			My_Beep (0);	// 
	           			sprintf (szLogEntry, "No Target Designated");
	           	    }
	         }
	           	    
				lStatus = GetDigital (CI_5);	// Launch missile
				if (lStatus == 0)  // **** switch in normally open, 
          			{     // launch missile 
          			if (AlertStatus != eASRed)
          				{
          				My_Beep(0);
           				sprintf (szLogEntry, "Need Red Alert to launch");
   	        			}
	           		else if (MissileStatus != eMSPreLaunch)
     	      			{
   		      			My_Beep(0);
 	   	      			sprintf (szLogEntry, "Need PreLaunch Status");
 	          			}
	           		else if (MissileStatus == eMSBoost)
     	      			{  // allow a 3 seconds  to remove signal
 	          			}
	           		else if (! iTargetTracked)
           				{
	          			My_Beep(0);
 	          			sprintf (szLogEntry, "Need Target Tracked Status");
	           			}
	           		else
	           			{
		       			MissileStatus = eMSBoost;	// launch the missile
		           		sprintf (szLogEntry, "Missile Launched");
		          		} 
		          	}

				lStatus = GetDigital (CI_6);	// Manual Command Burst
				if (lStatus == 1)
					;
				else
				    {
	          		if (MissileStatus != eMSPreLaunch)
	          			{	// ok, missile in flight, abandon it,
	          			MissileStatus = eMSPreLaunch;
	          			stDispObj[OBJ_MTR].dSx = 0.0; 
	          			stDispObj[OBJ_MTR].dSy = 0.0;
	          			stDispObj[OBJ_MTR].dSz = 0.0;
	          			stDispObj[OBJ_MTR].dVx = 0.0; 
	          			stDispObj[OBJ_MTR].dVy = 0.0;
	          			stDispObj[OBJ_MTR].dVz = 0.0; 
	          			stDispObj[OBJ_MTR].dAyaw_r = 0.0;
	          			stDispObj[OBJ_MTR].dApitch_u = 0.0; 
	          			dSecondsMissile = 0.0;
	           			sprintf (szLogEntry, "Missile Manual Burst");
	          			return 0;           
	          			}
				    } 
					
				lStatus = GetDigital (CI_7);	
				if (lStatus == 0)	//  storage scope requested (backward)
	         	{
	         	bStorageDisplayMode = 1;
	         	bStorageDisplayModeHistory = 1;
	         	}
	      else
	         	{          // no storage scope requested
	         	if (bStorageDisplayModeHistory)
	         		{		// flash display 
	         		SetDisplayTo(sIntensF);
	         		SetDisplayTo(sIntens0);
	         		bStorageDisplayModeHistory = 0;
	         		}
	         	bStorageDisplayMode = 0;
 	        	}
					
				    
				    
				lStatus = GetDigital (CI_8);	// Restart
				if (lStatus != 0)
					{ 
					if (cRestartSwitch == 0) // edge triggered
						{ 
						cRestart = 1;
            cRestartSwitch = 1;   
            }
           else
           	{} 
					}
				else
					cRestartSwitch = 0;

				lStatus = GetDigital (CI_9); // operate IFF?
				if (lStatus == 0)
								 cIFF = 0;     // IFF off
				else
								 cIFF = 1;		// IFF on

					
				lStatus = GetDigital (CI_10);	 //Start plane east if <3 targets
				if (lStatus != 0)
						cStartPlane = 1;
				else
						cStartPlane = 0;
							 

				lStatus = GetDigital (CI_11);	// should it evade?
				if (lStatus != 0)
						cEvasiveAction = 1;
				else     
						cEvasiveAction = 0;
						

				lStatus = GetDigital (CI_12);	
				if (lStatus )  // wired backwords
        		cWarGame = 1;
        else
        		cWarGame = 0;
				
		return 0; 
		}


// --------------------------------------------------------------
long SpecialOutput()
	{ 
	int iObj;
	char cLogic;                               
	double dTemp, dTemp1;
#define CONSOLE_DAC_CON 1	
				                     
				// output DA here  ********************************************
				dTemp1 = dTargSpeedMach;
				// dTemp1 = 0.250;
				// 3 element piecewise linear approximation
				// mach 1 = 796 knots
				// dTemp	gives	needs
				//	1.5					1200
				//	1.0		1200 	790
				//	0.7					560
				//	0.5		 800
				//	0.26   560     
				if (dTemp1 < 0.7)
					dTemp = 0.00 + ( ((0.26-0.00)/(0.7-0.0))*(dTemp1-0.0));
				else if (dTemp1 < 1.0)
					dTemp = 0.26 + ( ((0.5-0.26)/(1.0-0.7))*(dTemp1-0.7));
				else
					dTemp = 0.50 + ( ((1.0-0.50)/(1.5-1.0))*(dTemp1-1.0));
				PutAnalog(DAC_1, & dTemp, -3.0, 3.0);
					
				dTemp1 = dMissileSpeedMach;
//				dTemp1 = stDispObj[OBJ_MTR].dVx;
//				dTemp  = stDispObj[OBJ_MTR].dVy;   
//				dTemp1 = sqrt(dTemp1*dTemp1 + dTemp*dTemp);  // gnd meters/sec
//				dTemp1 /= 348.0;		// convert to mach
				dTemp = 0.250*(796.0/2100.0)*dTemp1; // meter conversion-
				PutAnalog(DAC_2, & dTemp, -3.0, 3.0);
					
#define TARGET_RANGE_METER_SCALE  400000.0					
				PutAnalog(DAC_3, & 	dTarDesRange, -TARGET_RANGE_METER_SCALE, 
										 TARGET_RANGE_METER_SCALE);
              
				// output target height info here                         
#define TARGET_HEIGHT_SCALE 0.333
				dTemp1 =  stDispObj[OBJ_TTR].dSz * TARGET_HEIGHT_SCALE;
				PutAnalog(DAC_4, & 	dTemp1, -MAX_PLOT_VT,  
										MAX_PLOT_VT); 
										
				dTemp = dSecondsIntercept;
#define SECONDS_METER_CONSTANT 12.0/100.0
				dTemp *= SECONDS_METER_CONSTANT;				   
				PutAnalog(DAC_7, & dTemp, -100.0, 100.0);
				
goto skip_dac;
				if ( MissileStatus != eMSPreLaunch)  // missile in flight 
					iObj = OBJ_MTR;	// plot missile
				else
					iObj = OBJ_PI;	// plot Predicted Intercept	
				PutAnalog(DAC_8, & 	stDispObj[iObj].dSz, -MAX_PLOT_VT,  
										MAX_PLOT_VT);
			  
				if (cTargetTrackLeftArm)
					{
					PutAnalog(DAC_3, & stDispObj[OBJ_TAR_DES].dSx, -MAX_PLOT_HZ, 
										 MAX_PLOT_HZ);
					PutAnalog(DAC_4, & stDispObj[OBJ_TAR_DES].dSy, -MAX_PLOT_HZ,  
										MAX_PLOT_HZ);
					PutAnalog(DAC_6, & stDispObj[iObj].dSx, -MAX_PLOT_HZ,  
										MAX_PLOT_HZ);
					PutAnalog(DAC_7, & stDispObj[iObj].dSy, -MAX_PLOT_HZ,  
										MAX_PLOT_HZ);
					}
				else
					{
					PutAnalog(DAC_6, & stDispObj[OBJ_TAR_DES].dSx, -MAX_PLOT_HZ, 
										 MAX_PLOT_HZ);
					PutAnalog(DAC_7, & stDispObj[OBJ_TAR_DES].dSy, -MAX_PLOT_HZ,  
										MAX_PLOT_HZ);
					PutAnalog(DAC_3, & stDispObj[iObj].dSx, -MAX_PLOT_HZ,  
										MAX_PLOT_HZ);
					PutAnalog(DAC_4, & stDispObj[iObj].dSy, -MAX_PLOT_HZ,  
										MAX_PLOT_HZ);
					}   
skip_dac:					  
					
				// output Logic here ***************************************
				if (  AlertStatus == eASRed )	// CO_0, alert status
												// (red == 1)
					cLogic = 1;  else 	cLogic = 0;
				PutDigital(CO_0, cLogic);
				
				if (  iTargetTracked )	// CO_1,  TargetTracked 
					cLogic = 1;  else	cLogic = 0;
				PutDigital(CO_1, cLogic); 
				
				if (  ComputerStatus == eCInDeadZone )// PI in dead zone
					cLogic = 1;   else	cLogic = 0;
				PutDigital(CO_2, cLogic); 
				
				if (  MissileStatus != eMSPreLaunch )// Missile in flight
					cLogic = 1;   else	cLogic = 0;
				PutDigital(CO_3, cLogic); 
				
				if (  (stDispObj[OBJ_MTR].dApitch_u >=  MAX_STEERING_ACC)
				    ||(stDispObj[OBJ_MTR].dApitch_u <= -MAX_STEERING_ACC)  )	
				    			// missile steering limit, vertical
					cLogic = 1;   
				else	cLogic = 0;
				PutDigital(CO_4, cLogic); 
				
				if (  (stDispObj[OBJ_MTR].dAyaw_r >=  MAX_STEERING_ACC)
				    ||(stDispObj[OBJ_MTR].dAyaw_r <= -MAX_STEERING_ACC)  )	
				    			// missile steering limit, horizontal
					cLogic = 1;   
				else	cLogic = 0;
				PutDigital(CO_5, cLogic); 
				
				if (  1 == 0 )	// not assigned ...
					cLogic = 1;   else	cLogic = 0;
				PutDigital(CO_6, cLogic); 

				if ( cTargetTrackLeftArm  )	// cTargetTrackLeftArm 
					cLogic = 1;   else	cLogic = 0;
				PutDigital(CO_7, cLogic);    
				
	
	return 0;
	}  
	
	
//////////////////////////////////////////////////////////////////
long UpdatePlotPosition(int v ) 
// purpose:  
//	set current display pulse and current x,y into index[0] 
//	(do not do this if w_iPulse[0] >= 0)
//	(had trouble with targets moving west to east in north semi 
		//when single at 0)
{
	int iObj;   // i_p, i_x, i_y ; 
	double dRad;			// radians, ccw starting at ease
	double dRadcw_n0, dTest;	// radians 0=north, clockwise 
	double dMeterOffsetX, dMeterOffsetY;
	                                    
	dMeterOffsetX = CENTER_PIXEL_X  / dPixelPerMeter;
	dMeterOffsetY = CENTER_PIXEL_Y  / dPixelPerMeter;
	dTest = CENTER_PIXEL_Y;
	for (iObj=0; iObj< MAX_OBJ; iObj++)
		{	// do each object
		 if ( stDispObj[iObj].iObjType > 0)	// object enabled for display
		 	{ 
		 	if(  (stDispObj[iObj].w_iPulse[0] == -1 )  
		 								// prevent multi hi intens
 			   &&(stDispObj[iObj].w_iPulse[1] != -1 )  )
 			   { }
 			else
		 	   {  //
 			 	 if (  ( stDispObj[iObj].dSx != 0.0) 
 			 	 	 && (stDispObj[iObj].dSy != 0.0))
			 	 	{
			 	     dRad = atan2( stDispObj[iObj].dSy , 
			 	     		 	   stDispObj[iObj].dSx  );
			 	     dRadcw_n0	= -dRad + ( PI/2.0);
			  		 if ( dRadcw_n0 < 0.0)
			  		   	 dRadcw_n0 += ( PI * 2); 
			  		 }
			 	 else 
			 	 	{
			 	 	 dRad = 0.0; 
			  		 dRadcw_n0 = 0; 
			         }
			     stDispObj[iObj].w_x[0] = (int)( stDispObj[iObj].dSx 
			     							* dPixelPerMeter) 
			     								+ CENTER_PIXEL_X ;
			     stDispObj[iObj].w_y[0] = - (int)( stDispObj[iObj].dSy 
			     							* dPixelPerMeter)
			     		     					+ CENTER_PIXEL_Y ;
	             stDispObj[iObj].w_dAngRad[0] =  dRad;
		     	
		     	
			     if ( ((int)( stDispObj[iObj].dSx)) 
			     			|| ((int)( stDispObj[iObj].dSy))  )	// no
				     stDispObj[iObj].w_iPulse[0] 
				     		= (int)( dRadcw_n0 *PULSES_PER_RAD );
			     else 
			          stDispObj[iObj].w_iPulse[0] = -1;	// don't display 0,0 
			     if (cIFF)
			          stDispObj[iObj].IFF[0] = 1;	// show IFF
			     else
			          stDispObj[iObj].IFF[0] = 0;	// don't show IFF
			     
		          
//			     i_p = stDispObj[iObj].w_iPulse[0];
//			     i_x = stDispObj[iObj].w_x[0];
//			     i_y = stDispObj[iObj].w_y[0];
		 	   }	// end update object in quadrant ....
		 	} 	// end object enabled for display
		} 	// for (iObj...
	return 0;
} 


 //////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////

long ClearDisplayHistory() 
// should be followed by clear screen to clear decaying objects
{
	int iObj, j;
 	for ( iObj=0; iObj< MAX_OBJ; iObj++)
		{	// do each object           
		if ( (stDispObj[iObj].iObjType > 0) )
			{ 
			for (j=0; j < MAX_PHASES; j++)
				stDispObj[iObj].w_iPulse[j]	= -1;
				 }
		} 	// for ( iObj... 
	return 0;
}
//////////////////////////////////////////////////////////////////
long DisplayObjects( int iPulse)
{
	int iObj; 
	 
 	for ( iObj=0; iObj< MAX_OBJ; iObj++)
		{	// do each object           
		if ( (stDispObj[iObj].iObjType > 0) )
			{ 
			 PaintObject( iObj, iPulse);
			 }
		} 	// for ( iObj... 
				
	return 0;
}

 
//////////////////////////////////////////////////////////////////

long PaintObject( int iObj, int iPulse) 

{ 
	int 	iObjType, x, y, i,j,radix, iPhase ; 
	int		x1, x2, y1, y2; 
	static unsigned seed; 
	double 	dAngRad;  
	double 	dWidth, dPerpAngRad;
	int 	iBigDeltaX, iBigDeltaY, iSmallDeltaX, iSmallDeltaY;
	long 	i_x, i_y;
	short rgb;
    int 	iEndB1x, iEndB1y, iEndB2x, iEndB2y;
    int   iEndS1x, iEndS1y, iEndS2x, iEndS2y; 
    int 	iLineCnt;
    int 	iLineToX[6], iLineToY[6];



		for (i=0, j = -1; (i 4)
						iLineCnt = 4;    // prevent runaway
						for (i = 0;  i< iLineCnt; i++)
						{						
						x2 = iLineToX[i] + CENTER_PIXEL_X ;
						y2 = -iLineToY[i] + CENTER_PIXEL_Y ;
						MyLine( x1, y1, x2, y2, rgb);
						x1 = x2; y1 = y2;	// new starting point
						}						
					break;

						  
					case OBJ_MTR:  
						// a little x  
					    _setcolor( sDecayArray[iPhase]);  // bright,
						_setpixel( x+2 , y+2);
						_setpixel(x+1 , y+1);
						_setpixel(  x-1 , y-1);
						_setpixel( x-2 , y-2);
						_setpixel(  x+2 , y-2);
						_setpixel(  x+1 , y-1);
						_setpixel(  x-1 , y+1);
						_setpixel(  x-2 , y+2);
						break; 
						
					case OBJ_PI:		// predicted intercept pt
								// a box  
					    _setcolor( sDecayArray[iPhase]);  // bright,
						_setpixel(  x+2 , y+2);
						_setpixel(  x+1 , y+2);
						_setpixel(  x+0 , y+2);
						_setpixel(  x-1 , y+2);
						_setpixel(  x-2 , y+2);

						_setpixel(  x+2 , y-2);
						_setpixel(  x+1 , y-2);
						_setpixel(  x+0 , y-2);
						_setpixel( x-1 , y-2);
						_setpixel( x-2 , y-2);
							
						_setpixel( x+2 , y+1);
						_setpixel(  x+2 , y+0);
						_setpixel( x+2 , y-1);
							
						_setpixel( x-2 , y+1);
						_setpixel( x-2 , y+0);
						_setpixel(x-2 , y-1);
						break;                           
							
				case OBJ_TTR:      // radial line perpendicular to target
					i_x = CENTER_PIXEL_X - x;
					i_y = CENTER_PIXEL_Y - y;

					if (iPhase == 0)
						{			//  compute useful things  
						iBigDeltaY = (int)(4*(sin(dAngRad)));
						iBigDeltaX = -(int)(4*(cos(dAngRad)));

						iEndB1x =  x + iBigDeltaX;
						iEndB1y =  y + iBigDeltaY;
						iEndB2x =  x - iBigDeltaX;
						iEndB2y =  y - iBigDeltaY;
						 stDispObj[iObj].iEndB1x[1] = iEndB1x;// big line
						 stDispObj[iObj].iEndB1y[1] = iEndB1y;
						 stDispObj[iObj].iEndB2x[1] = iEndB2x;
						 stDispObj[iObj].iEndB2y[1] = iEndB2y;
						 } 
					else
						{
						iEndB1x =  stDispObj[iObj].iEndB1x[iPhase];  // big line
						iEndB1y =  stDispObj[iObj].iEndB1y[iPhase]; 
						iEndB2x =  stDispObj[iObj].iEndB2x[iPhase];
						iEndB2y =  stDispObj[iObj].iEndB2y[iPhase]; 
						}
				    _setcolor( sDecayArray[iPhase]);  // duller
					_moveto(  iEndB1x, iEndB1y);
					_lineto(  iEndB2x, iEndB2y);	
					break;  
						
					// aircraft
		 			case OBJ_AIRCRAFT:
		 			case OBJ_AIRCRAFT_F:
//		 			case OBJ_BIRDS:
					// 
						i_x = CENTER_PIXEL_X - x;
						i_y = CENTER_PIXEL_Y - y;

						if (iPhase == 0)
							{			//  compute useful things  
							dWidth = 8 - 0.01*sqrt( (double)(i_x*i_x) 
									+ (double)(i_y*i_y) );
							dPerpAngRad = dAngRad + (PI / 2) ;  
							if (  dPerpAngRad > PI )
								dPerpAngRad = dPerpAngRad - (PI * 2);
							iBigDeltaY = (int)(dWidth*(sin(dPerpAngRad)));
							iBigDeltaX = -(int)(dWidth*(cos(dPerpAngRad)));
							 
							iSmallDeltaX = iBigDeltaX / 2;
							iSmallDeltaY = iBigDeltaY / 2;
							
							iEndB1x =  x + iBigDeltaX;
							iEndB1y =  y + iBigDeltaY;
							iEndB2x =  x - iBigDeltaX;
							iEndB2y =  y - iBigDeltaY;
							iEndS1x =  x + iSmallDeltaX;
							iEndS1y =  y + iSmallDeltaY;
							iEndS2x =  x - iSmallDeltaX;
							iEndS2y =  y - iSmallDeltaY;
							 stDispObj[iObj].iEndB1x[1] = iEndB1x;// big line
							 stDispObj[iObj].iEndB1y[1] = iEndB1y;
							 stDispObj[iObj].iEndB2x[1] = iEndB2x;
							 stDispObj[iObj].iEndB2y[1] = iEndB2y;
							 stDispObj[iObj].iEndS1x[1] = iEndS1x;// short line
							 stDispObj[iObj].iEndS1y[1] = iEndS1y;
							 stDispObj[iObj].iEndS2x[1] = iEndS2x;
							 stDispObj[iObj].iEndS2y[1] = iEndS2y; 
						    }
						else
							{
							iEndB1x =  stDispObj[iObj].iEndB1x[iPhase];  // big line
							iEndB1y =  stDispObj[iObj].iEndB1y[iPhase]; 
							iEndB2x =  stDispObj[iObj].iEndB2x[iPhase];
							iEndB2y =  stDispObj[iObj].iEndB2y[iPhase]; 
							iEndS1x =  stDispObj[iObj].iEndS1x[iPhase];  // short line
							iEndS1y =  stDispObj[iObj].iEndS1y[iPhase];
							iEndS2x =  stDispObj[iObj].iEndS2x[iPhase]; 
							iEndS2y =  stDispObj[iObj].iEndS2y[iPhase]; 
							}

					   // create wide, dull line
							 						
					    _setcolor( sDecayArray[iPhase+2]);  // duller
						_moveto(  iEndB1x, iEndB1y);
						_lineto(  iEndB2x, iEndB2y);	
												
						    
						// create narrow, brighter section
						 						
					    _setcolor( sDecayArray[iPhase]);  // bright,
						_moveto(  iEndS1x, iEndS1y);
						_lineto(  iEndS2x, iEndS2y);	                
						
						if ( (stDispObj[iObj].IFF[iPhase])
								&&(iObjType == OBJ_AIRCRAFT_F ) )
							{ // show IFF lines
							iBigDeltaX =  (int)(5*cos(dAngRad));
							iBigDeltaY = -(int)(5*sin(dAngRad));
							iEndB1x += 2*iBigDeltaX;
							iEndB1y += 2*iBigDeltaY;
							iEndB2x += 2*iBigDeltaX;
							iEndB2y += 2*iBigDeltaY;
					    _setcolor( sDecayArray[iPhase]);  // use brighter col,
							_moveto(  iEndB1x, iEndB1y);
							_lineto(  iEndB2x, iEndB2y);	                
							iEndB1x += 1*iBigDeltaX;
							iEndB1y += 1*iBigDeltaY;
							iEndB2x += 1*iBigDeltaX;
							iEndB2y += 1*iBigDeltaY;
							_moveto(  iEndB1x, iEndB1y);
							_lineto(  iEndB2x, iEndB2y);	                
							iEndB1x += 1*iBigDeltaX;
							iEndB1y += 1*iBigDeltaY;
							iEndB2x += 1*iBigDeltaX;
							iEndB2y += 1*iBigDeltaY;
							_moveto(  iEndB1x, iEndB1y);
							_lineto(  iEndB2x, iEndB2y);	                
							}
						break;                     
						
					case OBJ_EXPLOSION:	
						radix = 3; // break;
						seed = (unsigned) iObj;  // allow multiple simul.
						srand( seed);     
						if      (iPhase == 0)
							rgb = sIntensF;
						else if (iPhase == 1)
							rgb = sIntens8;
						else if (iPhase == 2)
							rgb = sIntens4;
						else if (iPhase == 3)
							rgb = sIntens0;
						_setcolor(rgb);
						for (i=0; i< 4; i++)
							{
							for ( j=0; j<4; j++)
								{
								if ( ( i+j) < 14)
									{
									if (! ( ( rand()) % radix) )
									   _setpixel (  x+i, y+j);
									if (! ( ( rand()) % radix) )
									   _setpixel(  x-i, y+j);
									if (! ( ( rand()) % radix) )
									   _setpixel(  x+i, y-j);
									if (! ( ( rand()) % radix) )
									   _setpixel(  x-i, y-j);
									}		
								} // end for(j...
							} // end for(i...
								
						if ( iPhase == 3)
							{
							InitializeObject( iObj); // unassign
						    }
						break;   // end case OBJ_EXPLOSION:
								
					default:
						break;
           			}	// switch ( iObjType...
           		}	// in viewable box
           	else	// not in viewable box 
           		{
 //    			stDispObj[iObj].w_iPulse[0]=-1; // kill the dot
           		}
           	}	// if (this pulse)
     return ( 0);
}

///////////////////////////////////////////////////////////////////
long UpdateMissile( )
{  
//  This replaces the missile tracking radar to update:
//		 1) missile position, 
//		 2) velocity, 
//	along the missile axis from boost, sustainer and drag
//	and up and right from g commands sent to the missile
//		 & during cruse in response to g commands set into the object
//			by the predicted Intercept module
//	
//	and also computes missile run time, and missile status, 
//	
//	It is obviously closely tied with the predicted
//		Intercept program, and end of initial dive experience must be
//		fed into the predicted Intercept program.
//
//  What do the acceleration commands really mean? 
//		There is a gyro on board, the spin axis at right angles to 
//			the vertical plane containing:
//				a) a vertical line up from the launch site 
//				b) the predicted intercept point at time of launch
//		Missile internal "roll" servos keep a plane containing 
//			a line defined as "missile down" perpendicular the spin axis
//			of the gyro.  A crisis develops if during steering operations,
//			the axis of the missile approaches with in 20 degrees of 
//			the spin axis.  This is called "Gymbol Limits" and if pushed,
//			will cause total disorientation of the missile in the sense
//			that what the commanding system calls "up" does not mean
//			what the missile calls "up" 
//  1) What does "accelerate negative yaw" mean to a missile?
//		  Move the control surfaces so that an acceloromotor whose
//			sensitive direction is perpendicular to the missile axis
//			and perpendicular to the missile down line will give a
//			negative signal.  For humans in the missile facing toward the
//			nose, head end "up",  this would appear "left".
//			
//	2) What is "up" to a missile going straight up?          
//			The direction opposite the line defined as "missile down"
//			passing from the missile center perpendicular to the missile
//			axis passing through the "bottom" of the missile.
//
//	3) What does "accelerate positive pitch" mean to a missile?
//			Move the control surfcaes so that an acceloorometer
//			whose sensitive direction is opposite "missile down"
//			will give a positive signal.  For humans in the missile, 
//			facing toward the nose, head end "up", this would appear "up".

	// current assumptions for hercules:               
	//			constant speed after boost    
	//			speed of sound for mach = 345 m/s    
	//		prelaunch
	//		boost (18 g) phase
	//			3.4 sec, gets 633.0 meters/sec, 1888 MPH, 3000 kM/h,
	//				mach <><>, at 1500 meters high (0.9 miles)
	//		initial dive to horizontal             
	//			radius = 5,700 meters, quarter circle = 1.57 radians
	//				15 sec to do the quarter circle,
	//		boost and initial dive 
	//			takes 22.4 sec total,
	//			missile is 12,200 meters high (36,000 ft) (5.5 miles)
	//			range (in x,y) 10,800 meters
	//			?radar range?=16 km (10 miles)
	//		cruse,
	//			see velocity profile 
	//		
  // if no target Tracked, set intercept at center 0,0, time = 999
  static int iDiveCycle;
  static int iSecondsTenths;
  static eMissileStatus OldMissileStatus;		// status history
//  static double dBoostAcc = 18*9.8;		// 18*9.8 Herk (average) boost m/s/s
  static double dBoostAcc = 28*9.8;		// 18*9.8 Herk (average) boost m/s/s
  static double dBoostTimeLimit=3.4;	// time limit of boost 
//  static double dSustainerAcc = +2.7*9.8;	// acceleration due to sustainer
  static double dSustainerAcc = +2.0*9.8;	// acceleration due to sustainer
  static double dDragAcc	  = -0.3*9.8;// no sustainer drag
  static double dSzBoost, dVzBoost; // hight & speed at end of boost
  static double dRadDive;			// radius of initial dive, calc
  static double dDeltaAngleInitialDive;	// angle change each delta time, calc 
  static double dGyroAngle;			// gyro angle at start of boost
  									// set from Intercept at start of boost
  static double dSustainerTimeLimit=29.0;	// time Herk sustainer runs
  static double dSustainerTime;		// length of time sustainer burning
   
   double dTimeSq;					// time squared                      
   double dWorkSx, dWorkSy, dWorkSz; 
   double  dMRad,dMRadPPI,dMDistance ;  
   
   double  dPredIntGndRange, fSecondsIntercept, dPredIntSupElev;
   static double dPredIntSuperRad; 

   // set global values for predicted Intercept program// change for herk
   dReleaseTime 	= 17.2;
   dReleaseRange 	= 5300;
   dReleaseZ		= 6260;
   dReleaseSpeed 	= 850;
   dMaxRange      	= 120000;	// herk?
   dDeadZoneRange	= 15000;
   
  	if (stDispObj[OBJ_PI].iObjType != OBJ_PI)
  	{        //  no target Tracked
  		cMissile_Over_Range = 0;
		return 0;
	}  
	// initialize at start of boost, catch transition
	if (  ( MissileStatus == eMSBoost)
	    &&( OldMissileStatus != eMSBoost) )
	    {
	    cMissile_Over_Range = 0;
	    dSecondsMissile = 0;
	    dSustainerTime  = 0;
	    stDispObj[OBJ_MTR].dSx = 0;
	    stDispObj[OBJ_MTR].dSy = 0;
	    stDispObj[OBJ_MTR].dSz = 0; 
	    stDispObj[OBJ_MTR].dVx = 0;
	    stDispObj[OBJ_MTR].dVy = 0;
	    stDispObj[OBJ_MTR].dVz = 0;
	    stDispObj[OBJ_MTR].dAyaw_r = 0;
	    stDispObj[OBJ_MTR].dApitch_u = 0;
	    stDispObj[OBJ_MTR].dAx = 0;
	    stDispObj[OBJ_MTR].dAy = 0;
	    //  capture predicted intercept angle into gyro angle
	    dGyroAngle=dPIRadNorth;
	    //   gyro angle stays locked  
	    iDiveCycle = 0;	// start dive here
	    }
	OldMissileStatus = MissileStatus;  
	// target is Tracked, see which mode
	if ( MissileStatus == eMSPreLaunch)
	{   // pre_launch
	
	}
	else if ( MissileStatus == eMSBoost)
	{   // status is set by launch command
	    dSecondsMissile += dSecondsDelta;
	    dTimeSq = dSecondsMissile*dSecondsMissile;
	    stDispObj[OBJ_MTR].dSx = 0;              
	    stDispObj[OBJ_MTR].dSy = 0;
	    stDispObj[OBJ_MTR].dSz = 0.5*dBoostAcc*dTimeSq; 
	    stDispObj[OBJ_MTR].dVx = 0;
	    stDispObj[OBJ_MTR].dVy = 0;
	    stDispObj[OBJ_MTR].dVz = dBoostAcc*dSecondsMissile;
	    stDispObj[OBJ_MTR].dAyaw_r = 0;
	    stDispObj[OBJ_MTR].dApitch_u = 0;
	    iSecondsTenths = (int)( dSecondsMissile*10);
	    if ( dSecondsMissile >= dBoostTimeLimit)
	    	{
	        MissileStatus = eMSInitialDive;	// next mode
	        dSzBoost = stDispObj[OBJ_MTR].dSz; // hight
	        dVzBoost = stDispObj[OBJ_MTR].dVz;	// speed
	        // calc initial dive radius           
	        dRadDive = ( dVzBoost*dVzBoost)/(MAX_STEERING_ACC); 
	        // calc change of angled each dSecondsDelta in dive
	        dDeltaAngleInitialDive = ( dVzBoost/dRadDive)*dSecondsDelta;	
	        					// radians
	        iDiveCycle = 1;	// start dive here 
	        // calculate possible early release from initial dive
	        dPredIntGndRange = sqrt( (stDispObj[OBJ_PI].dSx 
	        							* stDispObj[OBJ_PI].dSx)             
	    					+(stDispObj[OBJ_PI].dSy * stDispObj[OBJ_PI].dSy) );
			   if (fSecondsIntercept > 10.0)  // apply 1/2 super elevation
	    	  	dPredIntSupElev  = 0.5*0.5*9.8*((fSecondsIntercept-10)
	    							*(fSecondsIntercept-10));
	    	 else
                dPredIntSupElev  = 0;
         dPredIntSupElev += stDispObj[OBJ_PI].dSz;
         if (dPredIntSupElev > 30000)
          	dPredIntSupElev = 30000; 
         if ((dPredIntSupElev != 0.0) && (dPredIntGndRange != 0.0)) 
          	dPredIntSuperRad = atan2(dPredIntSupElev, dPredIntGndRange);
         else
          	dPredIntSuperRad = 0.0;
         if ( dPredIntSuperRad < 1.0)  //// clamp for stability
          	dPredIntSuperRad = 1.0;
	    	}
	}
	else if (MissileStatus == eMSInitialDive)
		{	// status is set by eMSBoost && top of dive for now
	    dSecondsMissile += dSecondsDelta;
	    // calculate missile height
	    dWorkSz = dSzBoost 
	    					+ ( dRadDive*sin( dDeltaAngleInitialDive*iDiveCycle));
	    // calculate x,y as due West, then fix x,y by gyro angle
	    //	relative to launch point (0,0)
	    dWorkSx = ( dRadDive*cos( dDeltaAngleInitialDive*iDiveCycle)) 
	    					- dRadDive;
	    iDiveCycle +=1;
	    dWorkSy =  -dWorkSx*cos( dGyroAngle);
	    dWorkSx =  -dWorkSx*sin( dGyroAngle); // west is positive?
	    // calc velocities as (new-old)/deltatime;
	    stDispObj[OBJ_MTR].dVx = ( dWorkSx-stDispObj[OBJ_MTR].dSx)
	    										/dSecondsDelta;
	    stDispObj[OBJ_MTR].dVy = ( dWorkSy-stDispObj[OBJ_MTR].dSy)
	    									/dSecondsDelta;
	    stDispObj[OBJ_MTR].dVz = ( dWorkSz-stDispObj[OBJ_MTR].dSz)
	    									/dSecondsDelta;
	    stDispObj[OBJ_MTR].dSx = dWorkSx;
	    stDispObj[OBJ_MTR].dSy = dWorkSy;
	    stDispObj[OBJ_MTR].dSz = dWorkSz; 
	    stDispObj[OBJ_MTR].dAyaw_r = 0;
	    stDispObj[OBJ_MTR].dApitch_u = -MAX_STEERING_ACC;
	    iSecondsTenths = (int)( dSecondsMissile*10); 
	    if (  (stDispObj[OBJ_MTR].dVz <= 0)	// dive done when horizontal!?!?
	    	||(dPredIntSuperRad <= (dDeltaAngleInitialDive*iDiveCycle) ) )
	    	{
	        MissileStatus = eMSCruse;	// next mode
	        stDispObj[OBJ_MTR].dApitch_u = 0; 
	      }	
		}
	else if ( MissileStatus == eMSCruse)
		{	
	    dSecondsMissile += dSecondsDelta;
	    // find missile horizontal direction angle 
	    if ( (stDispObj[OBJ_MTR].dVy != 0.0) 
	    			&& (stDispObj[OBJ_MTR].dVx != 0.0))
	    	dMRad = atan2(stDispObj[OBJ_MTR].dVy, stDispObj[OBJ_MTR].dVx);
	    else 
	        dMRad = 0.0;
    	dMRadPPI = dMRad+PI/2;
    	if ( dMRadPPI >= PI)
    		dMRadPPI -= ( PI*2);
			dMDistance = stDispObj[OBJ_MTR].dAyaw_r;
			stDispObj[OBJ_MTR].dAx = dMDistance*cos( dMRadPPI);	    
	    stDispObj[OBJ_MTR].dAy = dMDistance*sin( dMRadPPI);
	    // update velocity from g based steering
	    stDispObj[OBJ_MTR].dVx += stDispObj[OBJ_MTR].dAx*dSecondsDelta;
	    stDispObj[OBJ_MTR].dVy += stDispObj[OBJ_MTR].dAy*dSecondsDelta;
	    stDispObj[OBJ_MTR].dVz += stDispObj[OBJ_MTR].dApitch_u*dSecondsDelta; 
	    // update velocity from sustainer motor (or drag) (x,y only)
	    if ( dSustainerTime <  dSustainerTimeLimit)
	    	{                                     
	    	dSustainerTime += dSecondsDelta;
		    stDispObj[OBJ_MTR].dVx += cos(dMRad)*dSustainerAcc*dSecondsDelta;
		    stDispObj[OBJ_MTR].dVy += sin(dMRad)*dSustainerAcc*dSecondsDelta;
	   		}
	   	else	// sustainer motor done
	   		{
		    stDispObj[OBJ_MTR].dVx += cos(dMRad)*dDragAcc*dSecondsDelta;
		    stDispObj[OBJ_MTR].dVy += sin(dMRad)*dDragAcc*dSecondsDelta;
	   		}
	    
	    // update position
		stDispObj[OBJ_MTR].dSx += stDispObj[OBJ_MTR].dVx*dSecondsDelta;	
		stDispObj[OBJ_MTR].dSy += stDispObj[OBJ_MTR].dVy*dSecondsDelta;	
		stDispObj[OBJ_MTR].dSz += stDispObj[OBJ_MTR].dVz*dSecondsDelta;	
	   
	    
	    // check for flight exhaustion (50 km range exceeded)
	    //	or missile range > intercept range
	    dWorkSx = sqrt( ( stDispObj[OBJ_MTR].dSx*stDispObj[OBJ_MTR].dSx)
	    			  +( stDispObj[OBJ_MTR].dSy*stDispObj[OBJ_MTR].dSy) );
	    if ( dWorkSx > dMaxRange)      // 
	    	{
	    	cMissile_Over_Range = 1;
	    	}
	    	
	    iSecondsTenths = (int)( dSecondsMissile*10);
	}
	else
		return ( 1);

	return 0;                                                      
	
	
	
//////////////////////////////////////////////////////////////	
}
long UpdateTargets( )
{ 
    double dTarRad;
	int iObj, iObjType, iRand ;
	double dX, dY, dZ;
	
	for ( iObj=0; iObj< MAX_OBJ; iObj++)
		{	// do each object
		iObjType = stDispObj[iObj].iObjType; 
		switch ( iObjType)
			{   
						// aircraft
			case OBJ_AIRCRAFT: // 
			case OBJ_AIRCRAFT_F: // 
			case OBJ_BIRDS: 
				if ( 	(	cEvasiveAction ) && (iObj == iTargetTracked) )
					{   // vary horizontal g's, limit +- 3 g, 0.1g/0.1 sec
					iRand = rand( );
					stDispObj[iObj].dAyaw_r += ((double)( iRand % 3) - 1)/5; 
					// clamp to +- 1 g's
					if ( stDispObj[iObj].dAyaw_r > 10)
						stDispObj[iObj].dAyaw_r = 10;
					if ( stDispObj[iObj].dAyaw_r < -10)
						stDispObj[iObj].dAyaw_r = -10;
				  }   
				else
					{
					stDispObj[iObj].dAyaw_r = 0;
					}
				if ( stDispObj[iObj].dAyaw_r != 0.0)
					{  // target turning, update velocity
					if (  (stDispObj[iObj].dVy != 0.0) 
							&& (stDispObj[iObj].dVx != 0.0))
					  dTarRad = atan2( stDispObj[iObj].dVy, stDispObj[iObj].dVx);
					else
					    dTarRad = 0.0;
					if (stDispObj[iObj].dVs == 0.0)
						{  // calculate speed once
						 stDispObj[iObj].dVs = 
						 				sqrt( ( stDispObj[iObj].dVx
						 				      *stDispObj[iObj].dVx )
						 				     +( stDispObj[iObj].dVy
						 				      *stDispObj[iObj].dVy ));
						}
					if ( stDispObj[iObj].dVs > 0.01)
						{  // ok to divide
						dTarRad += ( stDispObj[iObj].dAyaw_r/stDispObj[iObj].dVs);
						stDispObj[iObj].dVx = 
								stDispObj[iObj].dVs*cos( dTarRad);
						stDispObj[iObj].dVy =            
								stDispObj[iObj].dVs*sin( dTarRad);
					    }
					}
					
				// linear, update position 1 dSecondDelta time
				stDispObj[iObj].dSx += stDispObj[iObj].dVx*dSecondsDelta;	
				stDispObj[iObj].dSy += stDispObj[iObj].dVy*dSecondsDelta;	
				stDispObj[iObj].dSz += stDispObj[iObj].dVz*dSecondsDelta;
				if ( DEBUG_R)
					{
					dX = stDispObj[iObj].dSx;
					dY = stDispObj[iObj].dSy; 	
					dZ = stDispObj[iObj].dSx; 
					}	
				break;
			default:
				break;
            }
		}
	return 0;
} 


///////////////////////////////////////////////////
long UpdateIntercept( )      // also sends steering commands during cruise
{                      
	// update Predicted Intercept in 3 modes
	//	0) prelaunch
	//	1) boost and initial dive until horizontal
	//	2) cruse to kill
	// - if no target Tracked, set at origin
	//
	// assumptions:               
	//			constant speed after boost    
	//			speed of sound for mach = 345 m/s    
	//		prelaunch
	//		boost (25 g) phase
	//			3.4 sec, gets 850.0 meters/sec, 1888 MPH, 3000 kM/h,
	//				mach 2.45, at 1500 meters high (0.9 miles)
	//		initial dive to horizontal             
	//			radius = 10,300 meters, quarter circle = 1.57 radians
	//				length of quarter circle = 16,171 meters
	//				19 sec to do the quarter circle,
	//		boost and initial dive 
	//			takes 22.4 sec total,
	//			missile is 17,700 meters high (58,000 ft) (11 miles)
	//			range 16 km (10 miles)
	//		cruse,
	//			constant speed of 850 meters/sec until intercept
	//			if (dSecondsMissile  < 50)  and (speed < mach 2.5)
	//				set speed to mach 2.5 
	//		
  // if no target Tracked, set intercept at center 0,0, time = 999	
  int i;                  
  double dTryPx, dTryPy, dTryPz;
  double dTryMx, dTryMy, dTryMz;
  double dTryTGRange, dTryTRad, dTryMGRange;
  double dMx, dMy, dMRange;	// missile data
  double dTx, dTy, dTRange;	// target  data
  
  static  double dTryMTime, dTryMRad; 
  double dMPx, dMPy, dMPz;	// midpoint between missile and PredInt
  double  dWTime, dWTime2;
  double fMVRadN, fM2Ix,fM2Iy,fM2Ir,fMGoalRadN,fMErrorRadH;
  

	if ( iTargetTracked == 0)
  	{        //  no target Tracked
  		// move predicted point of Intercept to 0,0
		stDispObj[OBJ_PI].dSx = 0;
		stDispObj[OBJ_PI].dSy = 0;
		stDispObj[OBJ_PI].dSz = 0;		       
		// show impractical time value
  		dSecondsIntercept = -1.0;
  		// move target tracking radar to 0,0
		stDispObj[OBJ_TTR].dSx = 0;
		stDispObj[OBJ_TTR].dSy = 0;
		stDispObj[OBJ_TTR].dSz = 0;		
		stDispObj[OBJ_TTR].dVx = 0;
		stDispObj[OBJ_TTR].dVy = 0;
		stDispObj[OBJ_TTR].dVz = 0;
		stDispObj[OBJ_TTR].dAyaw_r = 0;
		stDispObj[OBJ_TTR].dApitch_u = 0;           
		// make message
		ComputerStatus = eCSNoTargDesig;
		return 0;
	}                                                        
	if ( iTargetTracked < 0)
		{
		My_Beep(0);
		return (0);
		}
	
	// target is Tracked, copy values into OBJ_TTR
	i = iTargetTracked;
	stDispObj[OBJ_TTR].dSx = stDispObj[i].dSx;
	stDispObj[OBJ_TTR].dSy = stDispObj[i].dSy;
	stDispObj[OBJ_TTR].dSz = stDispObj[i].dSz;		
	stDispObj[OBJ_TTR].dVx = stDispObj[i].dVx;
	stDispObj[OBJ_TTR].dVy = stDispObj[i].dVy;
	stDispObj[OBJ_TTR].dVz = stDispObj[i].dVz;
	stDispObj[OBJ_TTR].dAyaw_r = stDispObj[i].dAyaw_r;
	stDispObj[OBJ_TTR].dApitch_u = stDispObj[i].dApitch_u;
	
	// target is Tracked, see which mode
	switch (MissileStatus)
		{
		case  eMSPreLaunch:
			// check to see if present algorithm can calc it
			
			// predict from default constants 
			if ( dTryMTime100)
				dTryMTime = 100; 
			if ( dTryMRad > PI)
				dTryMRad = (2*PI);
			if ( dTryMRad < -PI)
				dTryMRad = -PI;
			for ( i=0; i<4; i++)	// limit to 2 range & az iterations/cycle
				{   // trial target position & range
				dTryPx =  stDispObj[OBJ_TTR].dSx 
							+ ( stDispObj[OBJ_TTR].dVx*dTryMTime);
				dTryPy =  stDispObj[OBJ_TTR].dSy 
							+ ( stDispObj[OBJ_TTR].dVy*dTryMTime);
				dTryTGRange = sqrt( ( dTryPx*dTryPx) + (dTryPy*dTryPy) );
				if (  (dTryPy != 0.0) && (dTryPx != 0.0))	
					dTryTRad = atan2( dTryPy,dTryPx);
				else
					dTryTRad = 0.0;
					// trial missile position
				dTryMGRange = dReleaseRange 
							+ ( dReleaseSpeed * (dTryMTime - dReleaseTime) );
				dTryMx = dTryMGRange * cos( dTryMRad);
				dTryMy = dTryMGRange * sin( dTryMRad);
				dTryMz = dReleaseZ;
				// if (i is even)do angle, else do time
				if (!( i && 1))
					dTryMRad = dTryMRad + ( ( dTryTRad-dTryMRad)/2);
				else
					dTryMTime = dTryMTime 
					+ ( ( ( dTryTGRange-dTryMGRange)/dReleaseSpeed)/2);
				}	
			stDispObj[OBJ_PI].dSx = dTryPx;
			stDispObj[OBJ_PI].dSy = dTryPy;
			stDispObj[OBJ_PI].dSz = stDispObj[OBJ_TTR].dSz 
							+ ( stDispObj[OBJ_TTR].dVz*dTryMTime);;
			dSecondsIntercept = dTryMTime;
			dPIRadNorth = ( -dTryTRad)+(PI/2);
			if (dPIRadNorth < 0)
				dPIRadNorth += PI*2;
			// set computer status
			if ( dTryTGRange < dDeadZoneRange)
				ComputerStatus = eCInDeadZone;
			else if ( dTryTGRange > dMaxRange)
				ComputerStatus = eCSOutOfRange;
			else
				ComputerStatus = eCSInRange;
			break;   
			
 		case  eMSBoost: 
 			// Note: no break 
 		
		case  eMSInitialDive:
			dTryMTime -= dSecondsDelta;
			if ( dTryMTime < dSecondsDelta)
				  dTryMTime = dSecondsDelta;  // clamp
			dSecondsIntercept = dTryMTime;  
			RecordEvent( );
			break;	
					
		case  eMSCruse:
			// predict PredInt from missile values 
			dTryMTime -= dSecondsDelta;	// new trial time 
			for (i=0; i<2; i++)	// limit to 2 range iterations/cycle
				{   // trial target position & range  
				dTryPx =  stDispObj[OBJ_TTR].dSx 
						+( stDispObj[OBJ_TTR].dVx*dTryMTime);
				dTryPy =  stDispObj[OBJ_TTR].dSy 
						+( stDispObj[OBJ_TTR].dVy*dTryMTime);
				dTryTGRange = sqrt((dTryPx*dTryPx) + (dTryPy*dTryPy)); 
				if (  (dTryPy != 0.0) 
				    ||(dTryPx != 0.0) )
					dTryTRad = atan2(dTryPy,dTryPx);
				else
					dTryTRad = 0.0;
				
					// trial missile position
				dTryMx =  stDispObj[OBJ_MTR].dSx 
						+( stDispObj[OBJ_MTR].dVx*dTryMTime);
				dTryMy =  stDispObj[OBJ_MTR].dSy 
						+( stDispObj[OBJ_MTR].dVy*dTryMTime);
				dTryMGRange = sqrt( ( dTryMx*dTryMx) + (dTryMy*dTryMy) ); 
				dTryMTime = dTryMTime 
						+ ( ( ( dTryTGRange-dTryMGRange)/dReleaseSpeed)/2.0);
				}	// end itterative Predicted Intercept pointtrials 
				
			stDispObj[OBJ_PI].dSx = dTryPx; // predicted intercept point
			stDispObj[OBJ_PI].dSy = dTryPy;
			stDispObj[OBJ_PI].dSz = dTryPz = stDispObj[OBJ_TTR].dSz 
						+( stDispObj[OBJ_TTR].dVz*dTryMTime);	
				
			dSecondsIntercept = dTryMTime;
			dPIRadNorth = ( -dTryTRad)+(PI/2);
			if (dPIRadNorth < 0)
				dPIRadNorth += PI*2; 
				
			// set computer status
			if ( dTryTGRange < dDeadZoneRange)
				ComputerStatus = eCInDeadZone;
			else if ( dTryTGRange > dMaxRange)
				ComputerStatus = eCSOutOfRange;
			else
				ComputerStatus = eCSInRange;
			RecordEvent( );
	
			// Generate acceleration commands to steer missile 
			//	- General steering theory (not used in Nike)
			//		Steer so that the missile will pass through
			//		a point midway between the current missile
			//		and the current predicted point of Intercept.
			//		This should appear critically damped.
			 
			// find mid-point window (between PredInt and Missile)
			dMPx = ( dTryPx + stDispObj[OBJ_MTR].dSx)/2.0;
			dMPy = ( dTryPy + stDispObj[OBJ_MTR].dSy)/2.0;
			dMPz = ( dTryPz + stDispObj[OBJ_MTR].dSz)/2.0;
			// find mid-point missile position before steering corrections
			dWTime = dTryMTime/2.0;
			if ( dWTime >  0.001)
				{
				dTryMx =   stDispObj[OBJ_MTR].dSx 
						+ ( stDispObj[OBJ_MTR].dVx*dWTime);
				dTryMy =   stDispObj[OBJ_MTR].dSy 
						+ ( stDispObj[OBJ_MTR].dVy*dWTime);
				dTryMz =   stDispObj[OBJ_MTR].dSz 
						+ ( stDispObj[OBJ_MTR].dVz*dWTime);
			// now we have the desired position and the projected position
			//	basicly a=( 2*S)/(t*t)
				dWTime2 = dWTime*dWTime;	// time squared
				// calculate vertical steering
				stDispObj[OBJ_MTR].dApitch_u = (2*(dMPz-dTryMz))/ dWTime2;  // up 
				if ( stDispObj[OBJ_MTR].dApitch_u > MAX_STEERING_ACC)
					stDispObj[OBJ_MTR].dApitch_u = MAX_STEERING_ACC;    // clamp
				if ( stDispObj[OBJ_MTR].dApitch_u < -MAX_STEERING_ACC)
					stDispObj[OBJ_MTR].dApitch_u = -MAX_STEERING_ACC; 
					
				// calculate horizontal steering            
				if (  (stDispObj[OBJ_MTR].dVy != 0.0) 
						|| (stDispObj[OBJ_MTR].dVx != 0.0) )
					fMVRadN = atan2(stDispObj[OBJ_MTR].dVy,
									stDispObj[OBJ_MTR].dVx);// missile angle
				else
				    fMVRadN = 0.0;
				fMVRadN += PI/2;  // rotate 0 to north? 
				if ( fMVRadN < 0.0)
					 fMVRadN += PI*2;  // missile flight radians from north
				if ( fMVRadN >= PI*2)
					 fMVRadN -= PI*2;  // missile flight radians from north
				
				fM2Ix = dTryPx - stDispObj[OBJ_MTR].dSx;
				fM2Iy = dTryPy - stDispObj[OBJ_MTR].dSy;
				fM2Ir = sqrt ( ( fM2Ix*fM2Ix)+(fM2Iy*fM2Iy)); //  m-> int
				if (  (fM2Iy != 0.0) || (fM2Ix != 0.0) )
					fMGoalRadN = atan2( fM2Iy, fM2Ix); // 
				else 
					fMGoalRadN = 0.0;
				fMGoalRadN += PI/2;
				if ( fMGoalRadN < 0.0)
					 fMGoalRadN += PI*2;  // radians missile to intercept 
				if ( fMGoalRadN >= PI*2)
					 fMGoalRadN -= PI*2;  // radians missile to intercept 
					
				fMErrorRadH = fMGoalRadN - fMVRadN; // e rad in h flight 
				if (fMErrorRadH > PI)
					fMErrorRadH -= PI*2;   // keep in bounds
				if (fMErrorRadH < -PI)
					fMErrorRadH += PI*2;
				
				stDispObj[OBJ_MTR].dAyaw_r = ( 2*( fM2Ir*fMErrorRadH))
								/ dWTime2;// right
				if ( stDispObj[OBJ_MTR].dAyaw_r > MAX_STEERING_ACC)
					stDispObj[OBJ_MTR].dAyaw_r = MAX_STEERING_ACC; // clamp steering
				if ( stDispObj[OBJ_MTR].dAyaw_r < -MAX_STEERING_ACC)
					stDispObj[OBJ_MTR].dAyaw_r = -MAX_STEERING_ACC;
				stDispObj[OBJ_MTR].dAx = stDispObj[OBJ_MTR].dAyaw_r
										*sin( fMVRadN); // from north
				stDispObj[OBJ_MTR].dAy =  stDispObj[OBJ_MTR].dAyaw_r
										*cos( fMVRadN); // from north
				} 
				
				
				// -----------------------------------------------------
			dMx =   stDispObj[OBJ_MTR].dSx; 
			dMy =   stDispObj[OBJ_MTR].dSy; 
			dMRange = sqrt ((dMx*dMx)+(dMy*dMy));
			
			dTx =  stDispObj[OBJ_TTR].dSx; 
			dTy =  stDispObj[OBJ_TTR].dSy; 
			dTRange = sqrt((dTx*dTx) + (dTy*dTy));
							
	    if (  ( dTRange  <  dMRange)  // passed target
	   	    ||( dSecondsIntercept <= 0.004)
	   	    ||( cMissile_Over_Range      ) )   
	   		{   
	   		RecordEvent( ); 
    		if ( fdRE != NULL)  // close file if open
	   			{
		   		fclose ( fdRE); 
	    		fdRE = NULL;
	    		}
    		MissileStatus = eMSPreLaunch;
//  		My_Beep ( 0);     // missile terminated
 		   	ComputeMissileMiss_H_V();
 		    	
		  	if ( cMissile_Over_Range )
		  		{
		 			sprintf( szLogEntry,	"missile exhausted, removed");
		 			cMissile_Over_Range = 0;
		 			}
		 		else if (  (  ( dSecondsIntercept < 1.0)
		 				        ||( dSecondsIntercept > -1.0) )  // HORIZONTAL
		 				     &&(fabs( stDispObj[OBJ_TTR].dSz 
		 			  	   		- stDispObj[OBJ_MTR].dSz) < 200.0)  )
		 			{
		 			sprintf( szLogEntry,	"** INTERCEPT **");
					stDispObj[OBJ_MTR].iObjType = // explode the MISSILE, not target
							OBJ_EXPLOSION;
					stDispObj[OBJ_MTR].iObjPict = 0;  // explosion sequence
					UnPaint(iTargetTracked);		// remove visual traces
					UnPaint(OBJ_TTR);				// remove visual traces
					stDispObj[iTargetTracked].iObjType = 0;// remove target
					iTargetTracked = 0;								
		 			} // else if ( ( ( dSec
				else
					{
					sprintf( szLogEntry,"missile passed target, removed");
		   		}
				Log( );	// post the message in szLogEntry
				if (fdRE != NULL)
					{ 
					fclose(fdRE);	// close event recorder file 
					fdRE = NULL;
					}
				InitializeObject(OBJ_MTR); // unassign missile
				stDispObj[OBJ_MTR].iObjType   	= OBJ_MTR;	//
	    	} 
 			break;
 		case  eMSExplode:
 			break;
 		default:
 			break;
		}
	return ( 0); 
	
}                                                  


/////////////////////////////////////////////////////////////////
long Log()	// post the message in szLogEntry
{         
	return 0; 
}	
	
	
///////////////////////////////////////////////////////////////
long RemoveOutOfViewTargets( )    // (all w_iPulse == -1)
// returns number of non IFF identified targets remaining on 
{
	int iObj, iLObjType;
	long lTarCnt ; 
//	return 0;
	lTarCnt = 0; 
	for ( iObj=0; iObj< MAX_OBJ; iObj++)
		{	// do each object  
		iLObjType = stDispObj[iObj].iObjType;  
    if ( ( iLObjType >= OBJ_T_MIN) && (iLObjType <= OBJ_T_MAX) )  
   		// aircraft
   	 	{
     	if (  (fabs(stDispObj[iObj].dSx) > 350000.0)    
         	||(fabs(stDispObj[iObj].dSy) > 350000.0) )  
       	{ 
        if (iTargetTracked == iObj)
       		  iTargetTracked = 0;
       	UnPaint (iObj);					// remove video traces
				InitializeObject( iObj); // unassign
       	} 
      else                              
      	{
      	if (cIFF && (iLObjType == OBJ_AIRCRAFT_F))
      			;	// ignore friendly aircraft if IFF is on
      	else
       			lTarCnt++;		// increment # targets remaining
       	}
     	}	// if iObjType , aircraft, birds
		} 	// for (iObj...  
	return lTarCnt;
}                                                                  

//-----------------------------------------------------------------
long SelectTarget( double x, double y)
{ 
	int i;
	int closest_obj = 0;
	double dW, dDeltaX, dDeltaY, closest_dist = 99999999.9;
	
	// select closest visible target, but not during WarGames
	//   do not select if IFF is showing and friend
	if ( cWarGame )
		return 0;		// no manual selection during WarGames
	 
	for (i = 0; i=  OBJ_T_MIN)
		    &&(stDispObj[i].iObjType <=  OBJ_T_MAX) )
		    {     // target correct type 
		    if (cIFF && (stDispObj[i].iObjType == OBJ_AIRCRAFT_F))
		    	{}
		    else
		    	{
		    	dW = sqrt(  (stDispObj[i].dSx*stDispObj[i].dSx)
		    					 +(stDispObj[i].dSy*stDispObj[i].dSy) );
		    	if (dW < 	dVisibleRange)
		    		{  // target is visable,  pick closest target
			    	dDeltaX = stDispObj[i].dSx - x;
			    	dDeltaY = stDispObj[i].dSy - y;
			    	dW =  sqrt( (dDeltaX*dDeltaX) + (dDeltaY*dDeltaY) ); 
			    	if (dW < closest_dist)
			    		{   // closest so far
			    		closest_obj = i;
			    		closest_dist = dW;
			    		}
			   	 } // end visable
			   	}	// end if (cIFF && (stDisp
		    } // end correct type
		}	// end seach targets for closest mouse hit 
	if (closest_dist <= 200/dPixelPerMeter)   // was 20 until bad pots
		{	//  close enough?
		return closest_obj;
		}
	else
		return 0;
	
}
          	
//-----------------------------------------------------------------
long RecordEvent()
{       
	int iObj;
	double dTemp1, dTemp2, 	dTemp3,	dTemp4 ;
	
	if (DEBUG_R == 0)
		return 0;   // do not record unless in debug
		
	if (fdRE == NULL)
		{
		fdRE = fopen("EVENT.TXT","w");
		if (fdRE == NULL)
			{
			My_Beep(0);
	        CheckIt ( "Unable to open file EVENT.TXT !");
	        exit (0);
			}                                                
		// make message header
//		 0        1         2         3         4         5         6         7      
//		 1234567890123456789012345678901234567890123456789012345678901234567890123456
	fprintf(fdRE,"time      item     Sx       Sy       Sz       Vx       Vy       Vz       \n");
	fprintf(fdRE,"                   km       km       km       m/s      m/s      m/s \n");
		}                                                                                
	iObj = OBJ_TTR;
	fprintf(fdRE,    "%8.4f  target  %8.1f %8.1f %8.1f %8.1f %8.1f %8.1f %05.2 %05.2\n",
		dSecondsMissile,
		stDispObj[iObj].dSx, stDispObj[iObj].dSy, stDispObj[iObj].dSz,		
		stDispObj[iObj].dVx, stDispObj[iObj].dVy, stDispObj[iObj].dVz,
		0,0);		
	iObj = OBJ_MTR;
	fprintf(fdRE, "          missil  %8.1f %8.1f %8.1f %8.1f %8.1f %8.1f %05.2 %05.2\n",
		stDispObj[iObj].dSx, stDispObj[iObj].dSy, stDispObj[iObj].dSz,		
		stDispObj[iObj].dVx, stDispObj[iObj].dVy, stDispObj[iObj].dVz,
		0,0);		
	iObj = OBJ_PI;
	fprintf(fdRE, "          pre in  %8.1f %8.1f %8.1f %8.1f %8.1f %8.1f %05.2 %05.2\n",
		stDispObj[iObj].dSx, stDispObj[iObj].dSy, stDispObj[iObj].dSz,		
		stDispObj[iObj].dVx, stDispObj[iObj].dVy, stDispObj[iObj].dVz,
		0,0);                 
	dTemp1 = stDispObj[OBJ_MTR].dVx;
	dTemp2 = stDispObj[OBJ_MTR].dVy;
	dTemp3 = stDispObj[OBJ_MTR].dVz;
	dTemp4 = sqrt((dTemp1*dTemp1) 
					+ (dTemp2*dTemp2)
					+ (dTemp3*dTemp3)); // meters/sec
	dTemp1 = stDispObj[OBJ_MTR].dSx;
	dTemp2 = stDispObj[OBJ_MTR].dSy;
	dTemp3 = sqrt((dTemp1*dTemp1) 
					+ (dTemp2*dTemp2) );


	fprintf(fdRE, "t to i  %4.4f, msl m/s = %6.1f, msl km xy = %6.1f\n",
		dSecondsIntercept,  dTemp4, dTemp3 );	
	fprintf(fdRE,"\n");
	return 0;		
    } 					

//---------------------------------------------------------------
long UnPaint(int iObj)			// remove all paint sequences of obj
{
	int i, j ;
	for (i=iPulseCnt; i 1.0)
    	fS = 1.0;
    else if (fS < -1.0)
    	fS = -1.0;
    	  	
	// target position at time 0
	// get 3 d miss distance
	fMiss_x = (stDispObj[OBJ_TTR].dSx 
				+ (stDispObj[OBJ_TTR].dVx*fS) )
			 - (stDispObj[OBJ_MTR].dSx 
				+ (stDispObj[OBJ_MTR].dVx*fS) ); 
	fMiss_y = (stDispObj[OBJ_TTR].dSy 
				+ (stDispObj[OBJ_TTR].dVy*fS) ) 
			 - (stDispObj[OBJ_MTR].dSy 
				+(stDispObj[OBJ_MTR].dVy*fS) ); 
	fMiss_z = (stDispObj[OBJ_TTR].dSz 
				+ (stDispObj[OBJ_TTR].dVz*fS) ) 
			 - (stDispObj[OBJ_MTR].dSz 
				+(stDispObj[OBJ_MTR].dVz*fS) ); 
	fMissRange = sqrt((fMiss_x*fMiss_x) + (fMiss_y*fMiss_y)
						+ (fMiss_z*fMiss_z) ); 
	
	 return 0;
	}    		      

	

//-----------------------------------------------------

long UpdateText(  int cmd)
	{   // update the text details 
	// usually at beginning of scan after other updates complete
	//	cmd		updated
	//	---		-------
	//	  1		text
	//	  2		designated target #'s
	//	  3		missile #'s
	//	  4		predicted intercetp #'s
	//
	//	units are: km, speed km/hr, bearing in degrees rel north
	//		acceleration in g's
	//	designated target	- x,y,z,speed,range,bearing,accel
	//	missile				- x,y,z,speed,range,bearing,acceleration
	//	predicted intercept	- x,y,z,speed,range,bearing
	//      
	int iRelX, iRelY, iStartY, iObj, i;
	int	iCol1, iCol2, iCol3, iCol4;
	short rgb; 
	double dTemp1, dTemp2, dTemp3, dTemp4;
	
	iCol1 = 60;  
	iCol2 = iCol1+8; 
	iCol3 = iCol2+8; 
	iCol4 = iCol3+8;
	iStartY = 10; 
	 			// set text and background colors 
 	rgb = 2;
 	_settextcolor( rgb);
 	
 	// set likely object
 	switch (cmd)
 		{
 		case 1:  
 			iRelX=iCol1;
 			break;
 		case 2:
 			iRelX=iCol2;
 			iObj = OBJ_TTR;
 			break;
 		case 3:
 			iRelX=iCol3;
 			iObj = OBJ_MTR;
 			break;
 		case 4:
 			iRelX=iCol4;
 			iObj = OBJ_PI;
 			break;
 		}
 		
	//Line1	- header 1 ,  target missile & predicted intercept
	switch (cmd)
		{
		case 1:    
                              //123456789012345678901234567890   
			sprintf (my_text, "------- Event Recorder -------");
			_settextposition (iStartY+(0*VERT_TEXT_STEP), iCol1 );
			_outtext( my_text);
                              //123456789012345678901234567890   
			sprintf (my_text, "        Targ    Misl   P.Int  ");
			_settextposition( iStartY+(1*VERT_TEXT_STEP), iCol1 );
			_outtext( 	my_text);
			break;
		}
			
	//Line2 -  x in km       
	iRelY = iStartY+(2*VERT_TEXT_STEP);
	switch (cmd)
		{
		case 1:
                              //123456789012345678901234567890   
			sprintf (my_text, "e-kY                       ");
			_settextposition(  iRelY, iCol1); 
			_outtext( 	my_text);
			break;
		case 2: 
		case 3:   
		case 4:  
			dTemp1 = stDispObj[iObj].dSx;
			sprintf (my_text, "%7.1f",	stDispObj[iObj].dSx/1000);
			_settextposition( iRelY,  iRelX); 
			_outtext( 		my_text);
			break;
		} 
			
	//Line3	- y in km
	iRelY= iStartY+(3*VERT_TEXT_STEP);
	switch (cmd)
		{
		case 1:  
                              //123456789012345678901234567890   
			sprintf (my_text, "n-kY                       ");
			_settextposition( 	iRelY, iRelX); 
			_outtext( 		my_text);
			break;
		case 2:
		case 3:   
		case 4:
			dTemp2 = stDispObj[iObj].dSy;
			sprintf (my_text, "%7.1f",	stDispObj[iObj].dSy/1000);
			_settextposition(  iRelY, iRelX); 
			_outtext( 		my_text);
			break;
		}
			
	//Line4	- z in meters
	iRelY = iStartY+(4*VERT_TEXT_STEP);
	switch (cmd)
		{
		case 1:
                              //123456789012345678901234567890   
			sprintf (my_text, "h-kF                         ");
			_settextposition( iRelY,  iRelX); 
			_outtext( 		my_text);
			break;
		case 2:
		case 3:   
		case 4:
			sprintf (my_text, "%7.1f",	stDispObj[iObj].dSz*3/1000);
			_settextposition( iRelY,  iRelX);
			_outtext(  my_text);
			break;		
		}
		
	//Line5	- range in kM
	iRelY = iStartY+(5*VERT_TEXT_STEP);
	switch (cmd)
		{
		case 1:
                              //123456789012345678901234567890   
			sprintf (my_text, "r-kY                        ");
			_settextposition( iRelY,  iRelX); 
			_outtext( 		my_text);
			break;
		case 2:
		case 3:   
		case 4: 
			// note this is range in x,y only, 
			//		useful in inter-site coordination
			dTemp1 = stDispObj[iObj].dSx;
			dTemp2 = stDispObj[iObj].dSy;
			dTemp3 = sqrt((dTemp1*dTemp1) + (dTemp2*dTemp2));
			sprintf (my_text, "%7.1f",	dTemp3/1000);
			_settextposition( iRelY, iRelX);
			_outtext(  my_text);
			break;
		}	
			
	//Line6	- speed in mach (mach 1 == 348 m/s)
	iRelY = iStartY+(6*VERT_TEXT_STEP);
	switch (cmd)
		{
		case 1:
                              //123456789012345678901234567890   
			sprintf (my_text, "mach                      ");
			_settextposition(iStartY+(6*VERT_TEXT_STEP),  iRelX);
			_outtext( 		my_text);
			break;
		case 2:
		case 3:   
		case 4: 
			dTemp1 = stDispObj[iObj].dVx;
			dTemp2 = stDispObj[iObj].dVy;
			dTemp3 = stDispObj[iObj].dVz;
			dTemp4 = sqrt((dTemp1*dTemp1) 
							+ (dTemp2*dTemp2)
							+ (dTemp3*dTemp3)); // meters/sec
			dTemp4 = dTemp4/348.0;    // mach  
			if (iObj == OBJ_TTR)
                 dTargSpeedMach = dTemp4;	// update for analog output
      if (iObj == OBJ_MTR)
      					 dMissileSpeedMach = dTemp4;
			sprintf (my_text, "%7.1f",	dTemp4);
			_settextposition( iRelY,  iRelX);
			_outtext(  my_text);
			break;
		}
					
	//Line7	- bearing in Deg
	iRelY = iStartY+(7*VERT_TEXT_STEP);
	switch (cmd)
		{
		case 1:
                              //123456789012345678901234567890   
			sprintf (my_text, "deg                        ");
			_settextposition(iStartY+(7*VERT_TEXT_STEP),  iRelX);
			_outtext( 		my_text);
			break;
		case 2:
		case 3:   
		case 4: 
			if (  (stDispObj[iObj].dSx != 0.0) && (stDispObj[iObj].dSy != 0.0) ) 
			 	dTemp2 = DEG_PER_RAD 
			 		* atan2 (stDispObj[iObj].dSx,stDispObj[iObj].dSy);   
			 			// degrees from north 
			 else
			 	 dTemp2 = 0.0;
			 if (dTemp2 < 0.0)
			     dTemp2 += 360.0;    // degrees from north
			sprintf (my_text, "%7.1f",	dTemp2);
			_settextposition( iRelY,  iRelX);
			_outtext(  my_text);
			break;
		} 

	//Line8- horizontal g's
	iRelY = iStartY+(8*VERT_TEXT_STEP);
	switch (cmd)
		{
		case 1:
                              //123456789012345678901234567890   
			sprintf (my_text, "hz gs                       ");
			_settextposition(iStartY+(8*VERT_TEXT_STEP),  iRelX);
			_outtext( 		my_text);
			break;
		case 2:
			break;
		case 3:
		// no case 4, intercept
			dTemp4 = stDispObj[iObj].dAyaw_r/9.8;    // g's         
			sprintf (my_text, "%7.2f ", dTemp4);
			_settextposition(iRelY,  iRelX);
			_outtext(  my_text);
			break;
		}
					
	//Line9- vertical g's
	iRelY = iStartY+(9*VERT_TEXT_STEP);
	switch (cmd)
		{
		case 1:
                              //123456789012345678901234567890   
			sprintf (my_text, "vt gs                       ");
			_settextposition( iStartY+(9*VERT_TEXT_STEP),  iRelX); 
			_outtext( 		my_text);
			break;
		case 2:
			break;
		case 3:
		// no case 4, intercept
			dTemp4 = stDispObj[iObj].dApitch_u/9.8;    // g's         
			sprintf (my_text, "%7.2f ", dTemp4);
			_settextposition(iRelY,  iRelX);
			_outtext( 			 my_text);

			break;
		}
		
	//Line10	- time to intercept
	iRelY = iStartY+(10*VERT_TEXT_STEP);
	switch (cmd)
		{
		case 1:
                       //123456789012345678901234567890   
			sprintf (my_text, "time to intercept          ");
			_settextposition( iRelY,  iRelX);
			_outtext( 		my_text);
			break;
		case 4:
			sprintf (my_text, "%7.1f",	dSecondsIntercept);
			_settextposition(iRelY,  iRelX);
			_outtext(  my_text);
			break;
		}
					
	//Line11	- missile time
	iRelY = iStartY+(11*VERT_TEXT_STEP);
	switch (cmd)
		{
		case 1:
                       //123456789012345678901234567890   
			sprintf (my_text, "missile flight time         ");
			_settextposition( iRelY,  iRelX);
			_outtext( 		my_text);
			break;
		case 4:
			sprintf (my_text, "%7.1f", dSecondsMissile	);
			_settextposition(iRelY,  iRelX);
			_outtext(  my_text);
			break;
		}
		
					
	if (cmd == 1)	// update status only on end of scan
		{ 
		// line 12 miss distance
		iRelY = iStartY+(12*VERT_TEXT_STEP);
                      	 //123456789012345678901234567890   
		sprintf (my_text, "missed %6.0f yards     ",fMissRange);
		_settextposition( iRelY,  iCol1); 
		_outtext( my_text);  
		
		// line 13 miss x,y,z
		iRelY = iStartY+(13*VERT_TEXT_STEP);
                      	 //123456789012345678901234567890   
		sprintf (my_text, " x,y,z %6.0f%6.0f%6.0f  ",
							fMiss_x,fMiss_y,fMiss_z);   
		_settextposition( iRelY, iCol1); 
		_outtext( my_text);  
	    }
	if (cmd == 1)	// update status only on end of scan
		{
		//Line24- Alert Status
		iRelY = iStartY+(14*VERT_TEXT_STEP);
   	                     //123456789012345678901234567890   
//		sprintf (my_text, "Alert   Status = %s           ",
//				pszAlertStatus[AlertStatus]);   
		if (AlertStatus == eASRed)
				sprintf (my_text, "Alert   Status =     Red Status");
		else
				sprintf (my_text, "Alert   Status = not Red Status");
		_settextposition( iRelY,  iCol1);
		_outtext(  my_text);
	    }
	    
	if ((cmd == 1) || (cmd == 3))	
		{
		//Line15- Missile Status
		iRelY = iStartY+(15*VERT_TEXT_STEP);
   	                     //123456789012345678901234567890   
		sprintf (my_text, "Missile Status = %s           ",
				pszMissileStatus[MissileStatus]);
		_settextposition( iRelY,  iCol1);
		_outtext(  my_text);
		}
	
	if (cmd == 1)	// update status only on end of scan
		{
		//Line16- Computer Status
		iRelY = iStartY+(16*VERT_TEXT_STEP);
   	                     //123456789012345678901234567890   
		sprintf (my_text, "Comput  Status = %s           ",
				pszComputerStatus[ComputerStatus]);
		_settextposition(iRelY,  iCol1);
		_outtext(  my_text);
	     }                             
	      
	     
	if (cmd == 1)  // log entry 
		{
		//Line 17,18 - beep or other message
		iRelY = iStartY+(17*VERT_TEXT_STEP);
   	                     //123456789012345678901234567890   
		sprintf (my_text, "-------- last message ------");
		_settextposition(iRelY,  iCol1); 
		_outtext(my_text);
		iRelY = iStartY+(18*VERT_TEXT_STEP);
   	                     //123456789012345678901234567890   
		sprintf (my_text, "                              ");
		_settextposition( iRelY,  iCol1);
		_outtext(my_text);           
	    i = strlen(szLogEntry);
	    if (i > 28)
	    	 szLogEntry[28] = 0;
		_settextposition(iRelY,  iCol1);
		_outtext(szLogEntry);
        }
    if (DEBUG_R)
		{
		//Line19- debug info
		iRelY = iStartY+(19*VERT_TEXT_STEP);
   	                   //123456789012345678901234567890   
		sprintf (my_text, "dGlobal1 = %10.4f           ",dGlobal1);
		_settextposition(  iRelY, iCol1);
		_outtext( my_text);
	
		iRelY = iStartY+(20*VERT_TEXT_STEP);
    	                  //123456789012345678901234567890   
		sprintf (my_text, "dGlobal2 = %10.4f           ",dGlobal2);
		_settextposition(iRelY,  iCol1);
		_outtext( my_text);  
	    }
	
	return 0;
}
	
	
long SetDisplayTo(int ColorNumber)
{

	int y ; 
	
	 _setbkcolor( 0 );    // background
   _setcolor(ColorNumber);			// line color
	for (y = 0;  y< 600; y++)
		{						
		_moveto(  0, y);
		_lineto(  799, y);
		}						
    return 0 ;
}                                         




//////////////////////////////////////////////////////
long GetAnalog(int id, double * val, double min, double max)	
			// id is port 0 through 3, val in engineering units
			//  offset and scaling is in subroutine
			//   if error, return = -1, val - -9999999.9 
{          
	// start assembly language 
unsigned char busy,  msb, lsb;
int result, port, count;
                                   
	if (  (id < 0)  
		||(id > 3)  )         
		{
		*val = -99999999.9;
		return (-1);	// error in call 
		}  
	
	// verify that busy is not set
		_asm
			{                 
				mov dx,ADCboard + 1	
				in  al,dx
				mov	busy,al			
			}
		if ( busy & 128)		// 
			return -1;			// error, should not be busy
				
	// outporttb (board+((channel-1)*2);		
	port = ADCboard + ((id)*2);
	_asm
		{ 
		mov dx,port		// set port address
		mov ax,0x0		// set what to output (anything is ok)
		out dx,ax      //
		}                                    

	// do 
	//		{ 
	//		count++;
	//		busy = inportb(board+1);
	//		busy = busy & 128;
	//		}
	// while ((busy >= 128) &&  (count != 0));
	      
	count = busy = 0;	// size?, preset to 0
	do
		{ 
		count++;		// increment counter
		_asm
			{                 
				mov dx,ADCboard + 1	//
				in	al,dx			//
				mov	busy,al			//
			}
		busy = busy & 128;		//
		}
	while (busy >= 128);		//          
	
//	if (count == 1)
//		return -1;	// did not go busy, error
			           
		// msb = inportb(board+1);
		_asm
		{                 
			mov dx,ADCboard + 1;
			in	al,dx
			mov	msb,al
		}
		
		// lsb = inportb(board);  
		_asm
		{                 
			mov dx,ADCboard;
			in	al,dx
			mov	lsb,al
		}
	msb = msb & 0x7f;		// strip busy bit		
	result = (msb*256)+lsb;	// concatonate

	// scale counts to engineering units here
	*val = min + ((max * result)/4095);
	return (0);		// and exit
} 

//////////////////////////////////////////////////////
long PutAnalog( int id, double * val, double min, double max)
// purpose, output setpoint to x,y plotters and other units
// by RTD convention, DAC units are numbered from 1 through 8
//   if illegal id, return = -1
//   outputs are clamped to min,max with no warning
//   assumes board output set for +- 5 volts              
//		(matches 0 to +5 input of ADC to some extent)
//		(we may wish to use +-10 volts at some future date)
//  please note for purests: the voltage range is actually
//		counts	voltage		comments
//		------	-------		--------
//		4095	+4.9976     maximum 
//		2048	 0.0
//		1024	-2.500
//		   0	-5.000		minimum
{          
	// start assembly language 
int w_base, count, msb, lsb;                 
double w_val;
	if ( (id < 0) || (id > 7))
		return -1;
	else  // channel legal, crash on
		{   // clamp and scale inputs
		w_val = *val;
		if (w_val < min)
			w_val = min;
		else if (w_val > max)
			w_val = max;
		w_val = w_val * dMeterCalib;
		count = (int)( ((w_val - min)*4095.0)/(max - min) );
		msb = count >> 8;
		lsb = count & 0x00ff;
		w_base = DACboard + ((id)*2);
		_asm
			{ 
			// outporttb (board+((channel-1)*2);		
			mov dx,w_base	// set port address of this channel
			mov ax,lsb		// set to output lsb
			out dx,ax       // do it
			inc	dx			// go to msb address
			mov ax,msb
			out	dx,ax		// output most significant byte
			mov	dx,DACboard	// now read low channel to update output
			in	al,dx
			}
		}
	return 0;
}

/////////////////////////////////////////////////////////
long GetDigital (int id)
// returns value of id bit (0 through 7) in low bit of long
//	if error,long is set to -1
	{
	int 	port;
    char 	lsb;

	if (id < 0)
		return -1;
	else if (id < 8)
		{	// use ADC card 
		port = ADCboard + 11;
		_asm
			{ 
			mov dx,port		// set port address
			mov ax,0x92		// set all mode 0, A = input, B = input, C = output
			out dx,al      //
			}                                    
		port = ADCboard + 8;
		_asm
			{
			mov dx,port		// set port address
			in	al,dx		// input value
			mov	lsb,al		// to memory
			} 
		return ( (lsb >> (id) ) & 0x01);
		} 
	else if (id < 13)
		{  // use printer port status lines for input
     port = LPT1+2;		// printer port command register
		_asm
			{
			mov dx,port		// set port address
			mov ax,0x00		// disable IRQ
			out dx,al      //
			} 
     port = LPT1+1;		// printer port status register
		_asm
			{
			mov dx,port		// set port address
			in	al,dx		// input value 
			not al 
			xor	al,0x80
			mov	lsb,al		// to memory
			} 
		return ( (lsb >> (id-8+3) ) & 0x01);
//		return ( lsb & 0x00FF );
     }
  else
  	return -1;
  }
////////////////////////////////////////////////////////////////////////
char GetPrinterPort()
// return value in char
{
	char val;
	int control, status, e_port, portP3;
	static int port = 0x0378, cnt=0;
  
  portP3  = port + 3;
	control = port + 2; 
	status  = port + 1;
	e_port  = port | 0x400;
	
	_asm
		{                
		mov dx,portP3
		xor al,al
		out	dx,al			//  kill possible extended operations

		mov dx,e_port
		xor al,al
		out	dx,al			//  kill possible extended operations

		mov dx,control // set for read
		mov al,0x20		// sets bidirectional bit to tri-state output
		out dx,al  		// sets bidirectional bit to tri-state output
		
		mov dx,port		// set port address
//		mov dx,status		// set port address
//		mov ax,cnt
//	 	out dx,al  		// sets 
		in	al,dx		// input value
		mov	val,al		// to memory
		}
		cnt++; 
	return ( val );
}


///////////////////////////////////////////////////////////////////	 
long PutDigital(int id, char val)	// id=dig chan (0-7), val = 0/1
			// return 0 if legal, else -1  
			// proposed method of interfacing to relays operated from -26 volts
			//				(a voltage limiter is assumed across the coil)
			//    inverted logical out, + 5 is open, 0 = closed
			//	logic- 
			//        |             	+--- gnd of - 24 v power
			//		|					|/
			//		 R1 (2500 ohm)	                |
			//        |			                |/|\                   .
			//		 +---------pnp darlington--|   \                  .
			//		|                         |\ --+                 .
			//	R2 (6000 ohm)                     |
			//		|			(collector to coil shunted by limiter)
			//	-12v			 - 24 volts
			//  (this software in inverting, 0 input causes 1 output)
{        
int port;
static int w_val = 0;  // history, not sure what is read, preset to 0

	if ( (id < 0) || (id > 7) )
		return -1;	// error
	else
		{              

		w_val = w_val & (~(1<< id)); // clear bit in w_val
		if ( ! val) 	// ** inverting output **
			w_val = w_val | (1 << id);	// assure bit in proper position
		// update w_val
		port = ADCboard + 11;
		_asm
			{ 
			mov dx,port		// set port address
			mov ax,0x92		// set all mode 0, A = input, B = input, C = output
			out dx,al      //
			}  // ok, got the mode set,                                   
		port = ADCboard + 10;
		_asm
			{
			mov dx,port		// set port address
			mov ax,w_val	// value to output
			out dx,al   	// 
			} 
		 return 0;	// ok
		}
}		
                                      
///////////////////////////////////////////////////////////////////  
void MyLine (int x1, int y1, int x2, int y2, short color)
	{               
	int inc_x, inc_y, slope64, temp; 
	
	_setcolor(color);   // seems to work ok in DOS version
	_moveto(x1,y1);
	_lineto(x2,y2);
	return;	                 
	                 
//  having trouble with stability of SDK line call - like no more lines
	// normalize into draw from low x to hi x
	if (x1 > x2)
		{ temp = x1; x1 = x2; x2 = temp;    // flip ends
		  temp = y1; y1 = y2; y2 = temp; }
	if ( x1 == x2 )
		{	// vertical or point 
		if ( y2 < y1)
		  	{temp = y1; y1 = y2; y2 = temp; }	// go in correct sequence
		_setcolor (color);
		for (inc_y = y1; inc_y <= y2; inc_y++)
		
			_setpixel( x1, inc_y);
		}
	else if ( y1 == y2 )
		{	// horizontal, x1 already < x2
		_setcolor (color);
		for (inc_x = x1; inc_x <= x2; inc_x++)
			_setpixel( inc_x, y1);
		}
	else
		{	// diagonal (all of our lines are short)
		slope64 = ((y2-y1)*64)/(x2 - x1);
//		if (slope64 <= 64)
			{ 	// low slope, (<= 1)  step along x
			_setcolor( color);
			_setpixel( x1, y1);	// 1st to prevent divide by 0
			for (inc_x = x1+1, inc_y = y1; inc_x <= x2; inc_x++)
				{                   
				temp = 1;	// show x not printed
				if (slope64 > 0)
					{  // positive increments of y 
					_setcolor (color);
					while (   ( (((inc_y - y1)*64) / (inc_x - x1)) < slope64) 
						   && (inc_y < y2)  )
						   { inc_y++; _setpixel( inc_x, inc_y); temp = 0;}
					}
				else
					{	// negative increments of y 
					_setcolor (color);
					while (   ( (((inc_y - y1)*64) / (inc_x - x1)) > slope64)
						   && (inc_y > y2)  )
						   { inc_y--; _setpixel( inc_x, inc_y); temp = 0;}
					}                            
				if (temp)
					{
					_setcolor (color);
					 _setpixel( inc_x, inc_y); // need to set pixel
					}					
				}	
			_setcolor (color);
			_setpixel( x2, y2);	// final point
			}
//		else
			{	// hi slope, step along y
			
			}
		}
	}		
	
	
long set_video_SVGA256 ()
// set video to SuperVGA 800x600, 
// color colors 0,1 = 0 (black)
// color colors 2,33 =31 yellow in decreasing intensity
// if error, exit(0)
{
#define PLENG 256
long int pal[PLENG];

  int i;
  long  int c_red, c_green, c_blue;
///  long int a,b,c;
#define CYC 31

 pal[0] = 0;   	// border color?
 pal[1] = 0;	// background color (black)
  /* make  yellow -> black */
  c_red = 62; c_green = 62; c_blue = 0;
  for ( i=2 ; i < CYC; i++)
  {
    pal[i] = c_red | (c_green << 8) | (c_blue << 16);
    c_red -= 2; c_green -= 2;
  }
  for (  ; i < 256; i++)
  	pal[i] = 0;

// for ( i=2 ; i> 8 ) & 0xFFL;
//     c = ( pal[i] >> 16) & 0xFFL;
//     printf(" %8d, %8lX, %8lX, %8lX, %8lX \n",i,a,b,c, pal[i]);
//  }
 /*     */

  if (_setvideomode( _SRES256COLOR ) == 0)
    { printf( "Tins program requires a SVGA card.\n");
      exit( 1 );
    }
    _remapallpalette( &(pal[0]) );

    _setvieworg( 0, 0 );

  return (0);
}
	
//________________________________________________________________-
long StartPlaneEast(int iSpeedy, int desig)
           	    //  start new airplane from west to east from 
          					//    target designate circle if desig != 0
          					//		else
          					//			start from mid west
	{
	int iObj;
	
  for (iObj=10; iObj < MAX_OBJ; iObj++)
  		{     // look for unassigned object
  		if (stDispObj[iObj].iObjType == 0)
   				{	// found one
   				InitializeObject(iObj);
   				if (  rand() % 6) 
   					stDispObj[iObj].iObjType   = OBJ_AIRCRAFT;
   				else
   					stDispObj[iObj].iObjType   = OBJ_AIRCRAFT_F;
   				 
   				if (desig)
   					{
					stDispObj[iObj].dSx = stDispObj[OBJ_TAR_DES].dSx;
					stDispObj[iObj].dSy = stDispObj[OBJ_TAR_DES].dSy;
					}
				else
					{
					stDispObj[iObj].dSx = -150000.0 + (rand()*15000.0)/RAND_MAX;
					stDispObj[iObj].dSy =  -30000.0 + (rand()*60000.0)/RAND_MAX;
					}
				stDispObj[iObj].dSz =   
						100 + ((rand()*15000.0)/RAND_MAX);//0.3-46k ft 
				if (iSpeedy)
						stDispObj[iObj].dVx = 1.5*348;	// mach 1.5
				else
						stDispObj[iObj].dVx = 0.8*348;	// mach 0.8
				stDispObj[iObj].dVy =   0000;	// 0   km/hr north
				stDispObj[iObj].dVz =  00000;	// 0   m/s  change
				stDispObj[iObj].dAyaw_r =  000.0;	// 0   m/s/s right
				stDispObj[iObj].dApitch_u =   0000;	// 0   m/s/s up 
				sprintf( szLogEntry, "started plane east");
				return 0;
    			} 	// end of initializing one plane
    	}
  		My_Beep (1);   // no free objects
		 	sprintf( szLogEntry,	"** cant start targ **");
     	return 0;
   } 
           		
// ---------------------------------------------------------
long WarGame() // - automatic threat response 
/*   	                      W = W_ON, w = W_OFF			switch on heater
   	    (initialize Getting_Info, Launch_command flags to off)
   	    (called every 100 ms)
      	if W_ON
      		if (missile flying), 
      				if (flying over 150 seconds)
      						command burst
      				return                                  
      		if (Launch_Command flag)
      				if (target tracked)
 			     			  wait 5 seconds for human to catch up
      						launch missile, clear Launch_Command flag
      						(should cause missile flying next 100 ms)
      						return
      				else
      					  lost track error handling
      		else if (not Getting_Info flag)
      				clear internal tables and controls 
      				set Getting_Info  flag
      		if (target tracked)        
		      				save PI time into table
      		if (any target not in internal table)
      				designate target (assume instant auto tracking)
      				return
      		else (no more targets)
      			  find shortest PI time
      			  select that target 
      			  	(assumes instant tracked and tracking data)
      			  set Launch_Command flag
      			  clear Getting_Info flag
      			  return
*/
	{
	static char cGetting_Info = 0, cLaunch_Command=0; 
	static struct Targ_Info_Struct
		{
		int iTargID;			// object number, preset to < 0 (empty)
		int iTargPI_Time;	//
		eComputerStatus eTargStatus;		// computer target status
		} Targ_Info[MAX_OBJ];
	static int iDesignTarg;	// used to retain previoiusly selected targ
	static int iNumber_In_Table=0;	// used to retain 
  static double dDecisionTime;		// used to delay launch for human
	int i, j, k;	// temporary variables
	
	// verify that we should be here
	if ( ! cWarGame)
			{
			cGetting_Info = 0;
			return 0;    
			}
	if (MissileStatus  != eMSPreLaunch)
			{	// missile flying, check for too long
			if (dSecondsMissile > 150.0)
				{
	 			MissileStatus = eMSPreLaunch;
	 			stDispObj[OBJ_MTR].dSx = 0.0; 
	 			stDispObj[OBJ_MTR].dSy = 0.0;
	 			stDispObj[OBJ_MTR].dSz = 0.0;
	 			stDispObj[OBJ_MTR].dVx = 0.0; 
	 			stDispObj[OBJ_MTR].dVy = 0.0;
	 			stDispObj[OBJ_MTR].dVz = 0.0; 
	 			stDispObj[OBJ_MTR].dAyaw_r = 0.0;
	 			stDispObj[OBJ_MTR].dApitch_u = 0.0; 
	 			dSecondsMissile = 0.0;
	 			sprintf (szLogEntry, "WG Missile Burst");
				}
			return 0;
			}  
	// if here, missile is not flying, ie. prelaunch
	if (cLaunch_Command)
			{
			if (iTargetTracked) 
					{
					if (dSecondsSim >= (dDecisionTime + 5.0))
							{		// target is tracked, launch request
							MissileStatus  = eMSBoost;
	 						sprintf (szLogEntry, "WG launch"); 
	 						}
	 				else
	 						return 0;
					}
			else
				  {	// lost track in interval, try again
	 				sprintf (szLogEntry, "WG lost track after launch req");
	 				// ????
				  }
			cLaunch_Command = 0;
			cGetting_Info = 0;		// get info when missile bursts
			return 0;		// exit, no more to do for a while
			} // end if (	cLaunch_Command
	else if ( !  cGetting_Info )
			{	// not getting info 
			for (i = 0; i < MAX_OBJ; i++)
					{	// clear internal tables
					Targ_Info[i].iTargID = -2;
					Targ_Info[i].iTargPI_Time = -2;
					Targ_Info[i].eTargStatus = eCSTrackBadSolution;
					}
			iDesignTarg = -1;	// used to retain previously selected targ
			iNumber_In_Table=0;	// used to retain 
			cGetting_Info = 1;	// start gathering info
			iTargetTracked = 0;
			} 
			
	if (iTargetTracked > 0)
			{ 
			i = iNumber_In_Table;
			Targ_Info[i].iTargID = iTargetTracked;
			Targ_Info[i].iTargPI_Time = (int)dSecondsIntercept; 
			Targ_Info[i].eTargStatus = ComputerStatus;
			iNumber_In_Table++;		// increment # values in table
			}                                                   
	
	// track each target to get predicted intercept time 		
	for (i=0; i < MAX_OBJ; i++)
			{
			if (stDispObj[i].iObjType == OBJ_AIRCRAFT)
					{	// a target, is it in the table
					for (j=0; j< iNumber_In_Table; j++)
							{		// search table for match
							if ( i == Targ_Info[j].iTargID)
									goto next_object;
							}	// end inner loop, continue 
					// this AIRCRAFT is not in list, designate it
					iTargetTracked = i;
					return 0;	// and exit, give TTR and Computer 100 ms
					}	// end if (AIRCRAFT 
next_object:	
			;				
			}	// end search table
	// info from all targets collected, now select best target
	//    this system looks for greatest threat by
	//		picking target with smallest PI time, but 
	//				- fast, incoming targets get top priority
	//				- a target that is leaving gets a low priority
	j = 1000;	// bad intercept time 
	k = -1;		// invalid table index
	for (i=0; i < iNumber_In_Table; i++)
			{   // ignore targets in dead zone - unsightly, untidy
			if (  ( Targ_Info[i].iTargPI_Time < j)
					&&(  ( Targ_Info[i].eTargStatus = eCSInRange)
						 ||( Targ_Info[i].eTargStatus = eCSOutOfRange ) ) )
					{
					j = Targ_Info[i].iTargPI_Time;	// looks better
					k = i;
					}
			}	// end for (i=0
	if ( k >= 0)
			{ // a valid index found
			iTargetTracked = 	Targ_Info[k].iTargID;	// designate best
			stDispObj[OBJ_TAR_DES].dSx = stDispObj[iTargetTracked].dSx ;
			stDispObj[OBJ_TAR_DES].dSy = stDispObj[iTargetTracked].dSy ;
			if ( Targ_Info[k].eTargStatus = eCSInRange )
					{
					cLaunch_Command = 1;   // a good chance, launch  
					dDecisionTime = dSecondsSim;
					}	// end if ( ... InRange)
			} 	// end if ( k >= 0)  
	cGetting_Info = 0;		// clear table 
	return 0;
	}