FS2_Open
Open source remastering of the Freespace 2 engine
afterburner.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 
12 #include "freespace2/freespace.h"
13 #include "gamesnd/gamesnd.h"
14 #include "hud/hudets.h"
15 #include "io/joy_ff.h"
16 #include "io/timer.h"
17 #include "network/multi.h"
18 #include "object/object.h"
19 #include "parse/scripting.h"
20 #include "render/3d.h" // needed for View_position, which is used when playing a 3D sound
21 #include "ship/afterburner.h"
22 #include "ship/ship.h"
23 
24 // ----------------------------------------------------------
25 // Global to file
26 // ----------------------------------------------------------
27 static int Player_afterburner_loop_id; // identifies the looping afterburner sound of the player ship
28 static int Player_afterburner_loop_delay; // timestamp used to time the start of the looping afterburner sound
29 static int Player_disengage_timer;
30 static float Player_afterburner_vol;
31 static int Player_afterburner_start_time;
32 
33 
34 // ----------------------------------------------------------
35 // local constants
36 // ----------------------------------------------------------
37 
38 // The minimum required fuel to engage afterburners
39 #define MIN_AFTERBURNER_FUEL_TO_ENGAGE 10
40 
41 #define AFTERBURNER_DEFAULT_VOL 0.5f // default starting volume (0.0f -> 1.0f)
42 #define AFTERBURNER_PERCENT_VOL_ATTENUATE 0.30f // % at which afterburner volume is reduced
43 #define AFTERBURNER_PERCENT_FOR_LOOP_SND 0.33f
44 #define AFTERBURNER_VOLUME_UPDATE 250 // consider changing afterburner volume every 100 ms
45 #define AFTERBURNER_LOOP_DELAY 200 // ms after engage, to start looping sound
46 
47 #define DISENGAGE_TIME 1500 // time in ms to play faded loop sound when afterburner disengages
48 
49 
54 {
55  Player_disengage_timer = 1;
56  Player_afterburner_vol = AFTERBURNER_DEFAULT_VOL;
57  Player_afterburner_loop_id = -1;
58  Player_afterburner_start_time = 0;
59 }
60 
68 void afterburners_start(object *objp)
69 {
70  ship_info *sip;
71  ship *shipp;
72  float percent_left;
73 
74  Assert( objp != NULL );
75 
76  if(objp->type == OBJ_OBSERVER)
77  return;
78 
79  Assert( objp->type == OBJ_SHIP);
80  Assert( objp->instance >= 0 && objp->instance < MAX_SHIPS );
81 
82  shipp = &Ships[objp->instance];
83  Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < static_cast<int>(Ship_info.size()) );
84  sip = &Ship_info[shipp->ship_info_index];
85 
86  // bail if afterburners are locked
87  if (shipp->flags2 & SF2_AFTERBURNER_LOCKED) {
88  return;
89  }
90 
91  if ( (objp->flags & OF_PLAYER_SHIP) && (objp == Player_obj) ) {
92  unsigned int now;
93  now = timer_get_milliseconds();
94 
95  if ( (now - Player_afterburner_start_time) < 1300 ) {
97  return;
98  }
99 
100  if ( objp->phys_info.flags & PF_AFTERBURNER_WAIT ){
101  return;
102  }
103  }
104 
105  if ( objp->phys_info.flags & PF_AFTERBURNER_ON ) {
106  return; // afterburners are already engaged, nothing to do here
107  }
108 
109  //boosters take precedence
110  if (objp->phys_info.flags & PF_BOOSTER_ON)
111  return;
112 
113  if ( !(sip->flags & SIF_AFTERBURNER) ) {
114  return;
115  }
116 
117  // Check if there is enough afterburner fuel
119  if ( objp == Player_obj ) {
121  }
122  return;
123  }
124 
126 
128 
129  percent_left = shipp->afterburner_fuel / sip->afterburner_fuel_capacity;
130 
131  //Do anim
133 
134  if ( objp == Player_obj ) {
135  Player_afterburner_start_time = timer_get_milliseconds();
136  Player_disengage_timer = 1;
137  Player_afterburner_vol = AFTERBURNER_DEFAULT_VOL;
138 
139  if ( percent_left > AFTERBURNER_PERCENT_FOR_LOOP_SND ) {
140  Player_afterburner_loop_delay = timestamp(AFTERBURNER_LOOP_DELAY);
141  }
142  else {
143  Player_afterburner_loop_delay = 0;
144  }
145 
148  } else {
150  }
151 
152  Script_system.SetHookObjects(1, "Ship", objp);
154  Script_system.RemHookVars(1, "Ship");
155 
157 }
158 
168 void afterburners_update(object *objp, float fl_frametime)
169 {
170  Assert( objp != NULL );
171  Assert( objp->type == OBJ_SHIP );
172  Assert( objp->instance >= 0 && objp->instance < MAX_SHIPS );
173 
174  ship_info *sip;
175  ship *shipp;
176  static int volume_chg_timer = 1;
177 
178  shipp = &Ships[objp->instance];
179 
180  Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < static_cast<int>(Ship_info.size()) );
181  sip = &Ship_info[shipp->ship_info_index];
182 
183  if ( (objp->flags & OF_PLAYER_SHIP ) && (Game_mode & GM_DEAD) ) {
184  return;
185  }
186 
187  if ( !(sip->flags & SIF_AFTERBURNER) ) {
188  return; // nothing to update, afterburners are not even on the ship
189  }
190 
191  //shut the afterburners off if we're using the booster tertiary
192  if ( objp->phys_info.flags & PF_BOOSTER_ON)
193  {
194  if (objp==Player_obj) afterburner_stop_sounds();
195  afterburners_stop(objp);
196  return;
197  }
198 
199  if ( objp == Player_obj ) {
200  if ( !timestamp_elapsed(Player_disengage_timer) ) {
201  float remaining;
202  remaining = timestamp_until(Player_disengage_timer) / i2fl(DISENGAGE_TIME);
203  if ( remaining <= 0 ) {
205  }
206  else {
207  snd_set_volume( Player_afterburner_loop_id, remaining*Player_afterburner_vol);
208  }
209  }
210  else {
211  if ( Player_disengage_timer != 1 ) {
213  }
214  }
215  }
216 
217  // single player, multiplayer servers, and clients for their own ships
218  if(!(Game_mode & GM_MULTIPLAYER) || MULTIPLAYER_MASTER || (objp == Player_obj)) {
219  if ( !(objp->phys_info.flags & PF_AFTERBURNER_ON) ) {
220  // Recover afterburner fuel
221 
222  if ( shipp->afterburner_fuel < sip->afterburner_fuel_capacity ) {
223  float recharge_scale;
225  shipp->afterburner_fuel += (sip->afterburner_recover_rate * fl_frametime * recharge_scale);
226 
227  if ( shipp->afterburner_fuel > sip->afterburner_fuel_capacity){
229  }
230  }
231  return;
232  } else {
233  // Check if there is enough afterburner fuel
234  if ( shipp->afterburner_fuel <= 0 ) {
235  shipp->afterburner_fuel = 0.0f;
236  afterburners_stop(objp);
237  return;
238  }
239  }
240 
241  // afterburners are firing at this point
242 
243  // Reduce the afterburner fuel
244  shipp->afterburner_fuel -= (sip->afterburner_burn_rate * fl_frametime);
245  if ( shipp->afterburner_fuel < 0.0f ) {
246  shipp->afterburner_fuel = 0.0f;
247  }
248  }
249 
250  if ( objp == Player_obj ) {
251  if ( timestamp_elapsed(Player_afterburner_loop_delay) ) {
252  Player_afterburner_vol = AFTERBURNER_DEFAULT_VOL;
253  Player_afterburner_loop_delay = 0;
254  if ( Player_afterburner_loop_id == -1 ) {
255  Player_afterburner_loop_id = snd_play_looping( &Snds[ship_get_sound(objp, SND_ABURN_LOOP)], 0.0f , -1, -1);
256  snd_set_volume(Player_afterburner_loop_id, Player_afterburner_vol);
257  }
258  }
259 
260  // Reduce the volume of the afterburner sound if near the end
261  if ( timestamp_elapsed(volume_chg_timer) ) {
262  float percent_afterburner_left;
263  percent_afterburner_left = shipp->afterburner_fuel / sip->afterburner_fuel_capacity;
264  volume_chg_timer = timestamp(AFTERBURNER_VOLUME_UPDATE);
265  if ( percent_afterburner_left < AFTERBURNER_PERCENT_VOL_ATTENUATE ) {
266  Player_afterburner_vol = percent_afterburner_left*(1/AFTERBURNER_PERCENT_VOL_ATTENUATE)*AFTERBURNER_DEFAULT_VOL;
267  snd_set_volume(Player_afterburner_loop_id, Player_afterburner_vol);
268  }
269  } // end if (timestamp_elapsed(volume_chg_timer))
270  }
271 }
272 
279 void afterburners_stop(object *objp, int key_released)
280 {
281  Assert( objp != NULL );
282  Assert( objp->instance >= 0 && objp->instance < MAX_SHIPS );
283 
284  ship_info *sip;
285  ship *shipp;
286 
287  shipp = &Ships[objp->instance];
288 
289  Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < static_cast<int>(Ship_info.size()) );
290  sip = &Ship_info[shipp->ship_info_index];
291 
292  if ( (objp->flags & OF_PLAYER_SHIP) && key_released ) {
294  }
295 
296  if ( !(sip->flags & SIF_AFTERBURNER) ) {
297  nprintf(("Warning","Ship type %s does not have afterburner capability\n", sip->name));
298  return;
299  }
300 
301  if ( !(objp->phys_info.flags & PF_AFTERBURNER_ON) ) {
302  return;
303  }
304 
305  Script_system.SetHookObjects(1, "Ship", objp);
307  Script_system.RemHookVars(1, "Ship");
308 
310 
311  //Do anim
313 
314  if ( objp == Player_obj ) {
315 
316  if ( !key_released ) {
318  }
319 
320  if ( Player_afterburner_loop_id > -1 ) {
321  Player_disengage_timer = timestamp(DISENGAGE_TIME);
322  }
323 
325  }
326 }
327 
333 {
334  if ( Player_afterburner_loop_id != -1 ) {
335  snd_stop(Player_afterburner_loop_id);
336  }
337 
338  Player_afterburner_loop_id = -1;
339  Player_disengage_timer = 1;
340  Player_afterburner_loop_delay = 0;
341 }
bool model_anim_start_type(ship_subsys *pss, int animation_type, int subtype, int direction, bool instant)
Definition: modelanim.cpp:566
int timestamp(int delta_ms)
Definition: timer.cpp:226
#define MULTIPLAYER_CLIENT
Definition: multi.h:132
#define ABURN_DECAY_TIME
Definition: afterburner.h:16
void joy_ff_afterburn_on()
Definition: joy-unix.cpp:585
#define AFTERBURNER_DEFAULT_VOL
Definition: afterburner.cpp:41
vec3d View_position
Definition: 3dsetup.cpp:20
int Game_mode
Definition: systemvars.cpp:24
SCP_vector< game_snd > Snds
Definition: gamesnd.cpp:19
void afterburner_stop_sounds()
physics_info phys_info
Definition: object.h:157
#define MAX_SHIPS
Definition: globals.h:37
#define CHA_AFTERBURNEND
Definition: scripting.h:80
Assert(pm!=NULL)
float afterburner_fuel
Definition: ship.h:648
GLclampf f
Definition: Glext.h:7097
void joy_ff_afterburn_off()
Definition: joy-unix.cpp:580
float afterburner_fuel_capacity
Definition: ship.h:1283
#define CHA_AFTERBURNSTART
Definition: scripting.h:79
#define PF_AFTERBURNER_WAIT
Definition: physics.h:25
#define OF_PLAYER_SHIP
Definition: object.h:109
object * objp
Definition: lua.cpp:3105
#define OBJ_OBSERVER
Definition: object.h:43
ship * shipp
Definition: lua.cpp:9162
vec3d pos
Definition: object.h:152
#define SIF_AFTERBURNER
Definition: ship.h:879
script_state Script_system("FS2_Open Scripting")
#define PF_BOOSTER_ON
Definition: physics.h:31
int instance
Definition: object.h:150
int afterburner_decay
Definition: physics.h:85
void afterburners_stop(object *objp, int key_released)
void afterburners_update(object *objp, float fl_frametime)
#define ANIMATION_SUBTYPE_ALL
Definition: modelanim.h:52
int timestamp_until(int stamp)
Definition: timer.cpp:242
#define nprintf(args)
Definition: pstypes.h:239
#define GM_MULTIPLAYER
Definition: systemvars.h:18
int flags
Definition: ship.h:1227
ai_profile_t * ai_profile
Definition: missionparse.h:168
int ship_get_sound(object *objp, GameSoundsIndex id)
Returns a ship-specific sound index.
Definition: ship.cpp:18614
int snd_play_3d(game_snd *gs, vec3d *source_pos, vec3d *listen_pos, float radius, vec3d *source_vel, int looping, float vol_scale, int priority, vec3d *sound_fvec, float range_factor, int force, bool is_ambient)
Definition: sound.cpp:594
afterburner engage
Definition: gamesnd.h:89
void afterburner_level_init()
Definition: afterburner.cpp:53
int snd_play(game_snd *gs, float pan, float vol_scale, int priority, bool is_voice_msg)
Definition: sound.cpp:517
int engine_recharge_index
Definition: ship.h:639
Definition: ship.h:534
#define MIN_AFTERBURNER_FUEL_TO_ENGAGE
Definition: afterburner.cpp:39
#define DISENGAGE_TIME
Definition: afterburner.cpp:47
char name[NAME_LENGTH]
Definition: ship.h:1163
uint flags
Definition: physics.h:37
float afterburner_recharge_scale[NUM_SKILL_LEVELS]
Definition: ai_profiles.h:107
#define GM_DEAD
Definition: systemvars.h:25
float Energy_levels[NUM_ENERGY_LEVELS]
Definition: hudets.cpp:26
#define SND_PRIORITY_MUST_PLAY
Definition: sound.h:26
#define OBJ_SHIP
Definition: object.h:32
#define AFTERBURNER_VOLUME_UPDATE
Definition: afterburner.cpp:44
int RunCondition(int condition, char format='\0', void *data=NULL, class object *objp=NULL, int more_data=0)
Definition: scripting.cpp:924
void SetHookObjects(int num,...)
Definition: scripting.cpp:556
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
void afterburners_start(object *objp)
Definition: afterburner.cpp:68
#define AFTERBURNER_PERCENT_VOL_ATTENUATE
Definition: afterburner.cpp:42
int snd_play_looping(game_snd *gs, float pan, int start_loop, int stop_loop, float vol_scale, int scriptingUpdateVolume)
Definition: sound.cpp:822
afterburner fail (no fuel when aburn pressed)
Definition: gamesnd.h:92
void RemHookVars(unsigned int num,...)
Definition: scripting.cpp:754
int ship_info_index
Definition: ship.h:539
#define MULTIPLAYER_MASTER
Definition: multi.h:130
void snd_set_volume(int sig, float volume)
Definition: sound.cpp:920
SCP_vector< ship_info > Ship_info
Definition: ship.cpp:164
#define SF2_AFTERBURNER_LOCKED
Definition: ship.h:499
#define timestamp_elapsed(stamp)
Definition: timer.h:102
#define AFTERBURNER_LOOP_DELAY
Definition: afterburner.cpp:45
int Game_skill_level
Definition: fredstubs.cpp:170
#define i2fl(i)
Definition: floating.h:32
object * Player_obj
Definition: object.cpp:56
#define TRIGGER_TYPE_AFTERBURNER
Definition: modelanim.h:35
uint flags2
Definition: ship.h:645
#define PF_AFTERBURNER_ON
Definition: physics.h:20
uint flags
Definition: object.h:151
float radius
Definition: object.h:154
void snd_stop(int sig)
Definition: sound.cpp:875
mission The_mission
char type
Definition: object.h:146
float afterburner_recover_rate
Definition: ship.h:1285
int timer_get_milliseconds()
Definition: timer.cpp:150
#define AFTERBURNER_PERCENT_FOR_LOOP_SND
Definition: afterburner.cpp:43
float afterburner_burn_rate
Definition: ship.h:1284
afterburner burn sound (looped)
Definition: gamesnd.h:90