1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13 
14 #ifdef HAVE_CONFIG_H
15 #include <conf.h>
16 #endif
17 
18 #ifdef RCS
19 static char rcsid[] = "$Id: controls.c,v 1.3 2001/10/25 02:15:55 bradleyb Exp $";
20 #endif
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 
25 #include "pstypes.h"
26 #include "mono.h"
27 #include "key.h"
28 #include "joy.h"
29 #include "timer.h"
30 #include "error.h"
31 
32 #include "inferno.h"
33 #include "game.h"
34 #include "object.h"
35 #include "player.h"
36 
37 #include "controls.h"
38 #include "joydefs.h"
39 #include "render.h"
40 #include "args.h"
41 #include "palette.h"
42 #include "mouse.h"
43 #include "kconfig.h"
44 #include "laser.h"
45 #ifdef NETWORK
46 #include "multi.h"
47 #endif
48 #include "vclip.h"
49 #include "fireball.h"
50 
51 //look at keyboard, mouse, joystick, CyberMan, whatever, and set
52 //physics vars rotvel, velocity
53 
54 fix Afterburner_charge=f1_0;
55 
56 #define AFTERBURNER_USE_SECS	3				//use up in 3 seconds
57 #define DROP_DELTA_TIME			(f1_0/15)	//drop 3 per second
58 
59 extern int Drop_afterburner_blob_flag;		//ugly hack
60 
61 extern fix	Seismic_tremor_magnitude;
62 
read_flying_controls(object * obj)63 void read_flying_controls( object * obj )
64 {
65 	fix	forward_thrust_time;
66 
67 	Assert(FrameTime > 0); 		//Get MATT if hit this!
68 
69 	if (Player_is_dead) {
70 		vm_vec_zero(&obj->mtype.phys_info.rotthrust);
71 		vm_vec_zero(&obj->mtype.phys_info.thrust);
72 		return;
73 	}
74 
75 	if ((obj->type!=OBJ_PLAYER) || (obj->id!=Player_num)) return;	//references to player_ship require that this obj be the player
76 
77 	if (Guided_missile[Player_num] && Guided_missile[Player_num]->signature==Guided_missile_sig[Player_num]) {
78 		vms_angvec rotangs;
79 		vms_matrix rotmat,tempm;
80 		fix speed;
81 
82 		//this is a horrible hack.  guided missile stuff should not be
83 		//handled in the middle of a routine that is dealing with the player
84 
85 		vm_vec_zero(&obj->mtype.phys_info.rotthrust);
86 
87 		rotangs.p = Controls.pitch_time / 2 + Seismic_tremor_magnitude/64;
88 		rotangs.b = Controls.bank_time / 2 + Seismic_tremor_magnitude/16;
89 		rotangs.h = Controls.heading_time / 2 + Seismic_tremor_magnitude/64;
90 
91 		vm_angles_2_matrix(&rotmat,&rotangs);
92 
93 		vm_matrix_x_matrix(&tempm,&Guided_missile[Player_num]->orient,&rotmat);
94 
95 		Guided_missile[Player_num]->orient = tempm;
96 
97 		speed = Weapon_info[Guided_missile[Player_num]->id].speed[Difficulty_level];
98 
99 		vm_vec_copy_scale(&Guided_missile[Player_num]->mtype.phys_info.velocity,&Guided_missile[Player_num]->orient.fvec,speed);
100 #ifdef NETWORK
101 		if (Game_mode & GM_MULTI)
102 			multi_send_guided_info (Guided_missile[Player_num],0);
103 #endif
104 
105 	}
106 	else {
107 		obj->mtype.phys_info.rotthrust.x = Controls.pitch_time;
108 		obj->mtype.phys_info.rotthrust.y = Controls.heading_time;
109 		obj->mtype.phys_info.rotthrust.z = Controls.bank_time;
110 	}
111 
112 //	mprintf( (0, "Rot thrust = %.3f,%.3f,%.3f\n", f2fl(obj->mtype.phys_info.rotthrust.x),f2fl(obj->mtype.phys_info.rotthrust.y), f2fl(obj->mtype.phys_info.rotthrust.z) ));
113 
114 	forward_thrust_time = Controls.forward_thrust_time;
115 
116 	if (Players[Player_num].flags & PLAYER_FLAGS_AFTERBURNER)
117 	{
118 		if (Controls.afterburner_state) {			//player has key down
119 			//if (forward_thrust_time >= 0) { 		//..and isn't moving backward
120 			{
121 				fix afterburner_scale;
122 				int old_count,new_count;
123 
124 				//add in value from 0..1
125 				afterburner_scale = f1_0 + min(f1_0/2,Afterburner_charge) * 2;
126 
127 				forward_thrust_time = fixmul(FrameTime,afterburner_scale);	//based on full thrust
128 
129 				old_count = (Afterburner_charge / (DROP_DELTA_TIME/AFTERBURNER_USE_SECS));
130 
131 				Afterburner_charge -= FrameTime/AFTERBURNER_USE_SECS;
132 
133 				if (Afterburner_charge < 0)
134 					Afterburner_charge = 0;
135 
136 				new_count = (Afterburner_charge / (DROP_DELTA_TIME/AFTERBURNER_USE_SECS));
137 
138 				if (old_count != new_count)
139 					Drop_afterburner_blob_flag = 1;	//drop blob (after physics called)
140 			}
141 		}
142 		else {
143 			fix cur_energy,charge_up;
144 
145 			//charge up to full
146 			charge_up = min(FrameTime/8,f1_0 - Afterburner_charge);	//recharge over 8 seconds
147 
148 			cur_energy = max(Players[Player_num].energy-i2f(10),0);	//don't drop below 10
149 
150 			//maybe limit charge up by energy
151 			charge_up = min(charge_up,cur_energy/10);
152 
153 			Afterburner_charge += charge_up;
154 
155 			Players[Player_num].energy -= charge_up * 100 / 10;	//full charge uses 10% of energy
156 		}
157 	}
158 
159 	// Set object's thrust vector for forward/backward
160 	vm_vec_copy_scale(&obj->mtype.phys_info.thrust,&obj->orient.fvec, forward_thrust_time );
161 
162 	// slide left/right
163 	vm_vec_scale_add2(&obj->mtype.phys_info.thrust,&obj->orient.rvec, Controls.sideways_thrust_time );
164 
165 	// slide up/down
166 	vm_vec_scale_add2(&obj->mtype.phys_info.thrust,&obj->orient.uvec, Controls.vertical_thrust_time );
167 
168 	if (obj->mtype.phys_info.flags & PF_WIGGLE) {
169 		fix swiggle;
170 		fix_fastsincos(GameTime, &swiggle, NULL);
171 		vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&obj->orient.uvec,fixmul(swiggle,Player_ship->wiggle));
172 	}
173 
174 	// As of now, obj->mtype.phys_info.thrust & obj->mtype.phys_info.rotthrust are
175 	// in units of time... In other words, if thrust==FrameTime, that
176 	// means that the user was holding down the Max_thrust key for the
177 	// whole frame.  So we just scale them up by the max, and divide by
178 	// FrameTime to make them independant of framerate
179 
180 	//	Prevent divide overflows on high frame rates.
181 	//	In a signed divide, you get an overflow if num >= div<<15
182 	{
183 		fix	ft = FrameTime;
184 
185 		//	Note, you must check for ft < F1_0/2, else you can get an overflow  on the << 15.
186 		if ((ft < F1_0/2) && (ft << 15 <= Player_ship->max_thrust)) {
187 			mprintf((0, "Preventing divide overflow in controls.c for Max_thrust!\n"));
188 			ft = (Player_ship->max_thrust >> 15) + 1;
189 		}
190 
191 		vm_vec_scale( &obj->mtype.phys_info.thrust, fixdiv(Player_ship->max_thrust,ft) );
192 
193 		if ((ft < F1_0/2) && (ft << 15 <= Player_ship->max_rotthrust)) {
194 			mprintf((0, "Preventing divide overflow in controls.c for max_rotthrust!\n"));
195 			ft = (Player_ship->max_thrust >> 15) + 1;
196 		}
197 
198 		vm_vec_scale( &obj->mtype.phys_info.rotthrust, fixdiv(Player_ship->max_rotthrust,ft) );
199 	}
200 
201 }
202