FS2_Open
Open source remastering of the Freespace 2 engine
hudartillery.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 
13 #include "ai/ai.h"
14 #include "fireball/fireballs.h"
15 #include "gamesnd/gamesnd.h"
16 #include "globalincs/alphacolors.h"
17 #include "globalincs/linklist.h"
18 #include "hud/hudartillery.h"
19 #include "hud/hudmessage.h"
20 #include "io/timer.h"
21 #include "math/vecmat.h"
22 #include "network/multi.h"
23 #include "object/object.h"
24 #include "parse/parselo.h"
25 #include "sound/sound.h"
26 #include "weapon/beam.h"
27 #include "weapon/weapon.h"
28 
29 // -----------------------------------------------------------------------------------------------------------------------
30 // ARTILLERY DEFINES/VARS
31 //
32 // Goober5000 - moved to hudartillery.h
33 
34 // -----------------------------------------------------------------------------------------------------------------------
35 // ARTILLERY FUNCTIONS
36 //
37 
38 // test code for subspace missile strike -------------------------------------------
39 
40 // ssm_info, like ship_info etc.
42 
43 // list of active strikes
45 
46 // Goober5000
47 int ssm_info_lookup(const char *name)
48 {
49  if(name == NULL)
50  return -1;
51 
52  for (auto it = Ssm_info.cbegin(); it != Ssm_info.cend(); ++it)
53  if (!stricmp(name, it->name))
54  return std::distance(Ssm_info.cbegin(), it);
55 
56  return -1;
57 }
58 
59 void parse_ssm(const char *filename)
60 {
61  char weapon_name[NAME_LENGTH];
62 
63  try
64  {
65  read_file_text(filename, CF_TYPE_TABLES);
66  reset_parse();
67 
68  // parse the table
69  while(required_string_either("#end", "$SSM:")) {
70  required_string("$SSM:");
71  ssm_info s;
72  int string_index;
73 
74  // name
76  if (*s.name == 0) {
77  sprintf(s.name, "SSM " SIZE_T_ARG, Ssm_info.size());
78  mprintf(("Found an SSM entry without a name. Assigning \"%s\".\n", s.name));
79  }
80 
81  // stuff data
82  required_string("+Weapon:");
83  stuff_string(weapon_name, F_NAME, NAME_LENGTH);
84 
85  string_index = optional_string_either("+Count:", "+Min Count:");
86  if (string_index == 0) {
87  stuff_int(&s.count);
88  s.max_count = -1;
89  } else if (string_index == 1) {
90  stuff_int(&s.count);
91  required_string("+Max Count:");
92  stuff_int(&s.max_count);
93  } else {
94  s.count = 1;
95  s.max_count = -1;
96  }
97 
98  required_string("+WarpRadius:");
100 
101  if (optional_string("+WarpTime:")) {
103  // According to fireballs.cpp, "Warp lifetime must be at least 4 seconds!"
104  if ( (s.warp_time) < 4.0f) {
105  // So let's warn them before they try to use it, shall we?
106  Warning(LOCATION, "Expected a '+WarpTime:' value equal or greater than 4.0, found '%f' in weapon '%s'.\n Setting to 4.0, please check and set to a number 4.0 or greater!\n", s.warp_time, weapon_name);
107  // And then make the Assert obsolete -- Zacam
108  s.warp_time = 4.0f;
109  }
110  } else {
111  s.warp_time = 4.0f;
112  }
113 
114  string_index = required_string_either("+Radius:", "+Min Radius:");
115  if (string_index == 0) {
116  required_string("+Radius:");
117  stuff_float(&s.radius);
118  s.max_radius = -1.0f;
119  } else {
120  required_string("+Min Radius:");
121  stuff_float(&s.radius);
122  required_string("+Max Radius:");
124  }
125 
126  string_index = optional_string_either("+Offset:", "+Min Offset:");
127  if (string_index == 0) {
128  stuff_float(&s.offset);
129  s.max_offset = -1.0f;
130  } else if (string_index == 1) {
131  stuff_float(&s.offset);
132  required_string("+Max Offset:");
134  } else {
135  s.offset = 0.0f;
136  s.max_offset = -1.0f;
137  }
138 
139  if (optional_string("+Shape:")) {
140  switch(required_string_one_of(3, "Point", "Circle", "Sphere")) {
141  case 0:
142  required_string("Point");
144  break;
145  case 1:
146  required_string("Circle");
147  case -1: // If we're ignoring parse errors and can't identify the shape, go with a circle.
149  break;
150  case 2:
151  required_string("Sphere");
153  break;
154  default:
155  Assertion(false, "Impossible return value from required_string_one_of(); get a coder!\n");
156  }
157  } else {
159  }
160 
161  if (optional_string("+HUD Message:"))
163  else
164  s.send_message = true;
165 
166  if (optional_string("+Custom Message:")) {
168  s.use_custom_message = true;
169  }
170 
171  s.sound_index = -1;
172  parse_sound("+Alarm Sound:", &s.sound_index, s.name);
173 
174  // see if we have a valid weapon
175  s.weapon_info_index = weapon_info_lookup(weapon_name);
176  if(s.weapon_info_index >= 0) {
177  // valid
178  int existing = ssm_info_lookup(s.name);
179  if (existing >= 0) { // Redefined the existing entry instead of adding a duplicate.
180  Ssm_info[existing] = s;
181  } else {
182  Ssm_info.push_back(s);
183  }
184  }
185  }
186  }
187  catch (const parse::ParseException& e)
188  {
189  mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
190  return;
191  }
192 }
193 
194 // game init
195 void ssm_init()
196 {
197  if (cf_exists_full("ssm.tbl", CF_TYPE_TABLES)) {
198  mprintf(("TABLES => Starting parse of 'ssm.tbl'...\n"));
199  parse_ssm("ssm.tbl");
200  }
201  parse_modular_table(NOX("*-ssm.tbm"), parse_ssm);
202 
203  // Now that we've populated Ssm_info, let's validate weapon $SSM: entries.
205 }
206 
207 void ssm_get_random_start_pos(vec3d *out, vec3d *start, matrix *orient, int ssm_index)
208 {
209  vec3d temp;
210  ssm_info *s = &Ssm_info[ssm_index];
211  float radius, offset;
212 
213  if (s->max_radius == -1.0f)
214  radius = s->radius;
215  else
216  radius = frand_range(s->radius, s->max_radius);
217 
218  if (s->max_offset == -1.0f)
219  offset = s->offset;
220  else
221  offset = frand_range(s->offset, s->max_offset);
222 
223  switch (s->shape) {
224  case SSM_SHAPE_SPHERE:
225  // get a random vector in a sphere around the target
226  vm_vec_random_in_sphere(&temp, start, orient, radius, 1);
227  break;
228  case SSM_SHAPE_CIRCLE:
229  // get a random vector in the circle of the firing plane
230  vm_vec_random_in_circle(&temp, start, orient, radius, 1);
231  break;
232  case SSM_SHAPE_POINT:
233  // boooring
234  vm_vec_scale_add(&temp, start, &orient->vec.fvec, radius);
235  break;
236  default:
237  Assertion(false, "Unknown shape '%d' in SSM type #%d ('%s'). This should not be possible; get a coder!\n", s->shape, ssm_index, s->name);
238  break;
239  }
240 
241  // offset it a bit
242  vm_vec_scale_add(out, &temp, &orient->vec.fvec, offset);
243 }
244 
245 // level init
247 {
248 }
249 
250 // start a subspace missile effect
251 void ssm_create(object *target, vec3d *start, size_t ssm_index, ssm_firing_info *override, int team)
252 {
253  ssm_strike ssm;
254  matrix dir;
255  int idx, count;
256 
257  // sanity
258  Assert(target != NULL);
259  if(target == NULL){
260  return;
261  }
262  Assert(start != NULL);
263  if(start == NULL){
264  return;
265  }
266  if (ssm_index >= Ssm_info.size()) {
267  return;
268  }
269 
270  // Init the ssm data
271 
272  count = Ssm_info[ssm_index].count;
273  if (Ssm_info[ssm_index].max_count != -1) {
274  // To get a range of values between min and max, inclusive:
275  // random value = min + randon number % (max - min + 1)
276  count += rand32() % (Ssm_info[ssm_index].max_count - count + 1);
277  }
278 
279  // override in multiplayer
280  if(override != NULL){
281  ssm.sinfo = *override;
282  }
283  // single player or the server
284  else {
285  // forward orientation
286  vec3d temp;
287 
288  vm_vec_sub(&temp, &target->pos, start);
289  vm_vec_normalize(&temp);
290 
291  vm_vector_2_matrix(&dir, &temp, NULL, NULL);
292 
293  // stuff info
294  ssm.sinfo.count = count;
295  ssm.sinfo.ssm_index = ssm_index;
296  ssm.sinfo.target = target;
297  ssm.sinfo.ssm_team = team;
298 
299  // Instead of pushing them on one at a time, let's just grab all the memory we'll need at once
300  // (as a side effect, don't need to change the logic from the old array-based code)
301  ssm.sinfo.delay_stamp.resize(count);
302  ssm.sinfo.start_pos.resize(count);
303 
304  for (idx = 0; idx < count; idx++) {
305  ssm.sinfo.delay_stamp[idx] = timestamp(200 + (int)frand_range(-199.0f, 1000.0f));
306  ssm_get_random_start_pos(&ssm.sinfo.start_pos[idx], start, &dir, ssm_index);
307  }
308 
309  ssm_info *si = &Ssm_info[ssm_index];
311  if (wip->wi_flags & WIF_BEAM) {
312  ssm.sinfo.duration = ((si->warp_time - ((wip->b_info.beam_warmup / 1000.0f) + wip->b_info.beam_life + (wip->b_info.beam_warmdown / 1000.0f))) / 2.0f) / si->warp_time;
313  } else {
314  ssm.sinfo.duration = 0.5f;
315  }
316 
317  // if we're the server, send a packet
318  if(MULTIPLAYER_MASTER){
319  //
320  }
321  }
322 
323  ssm.done_flags.clear();
324  ssm.done_flags.resize(count);
325  ssm.fireballs.clear();
326  ssm.fireballs.resize(count, -1);
327 
328  if(Ssm_info[ssm_index].send_message) {
329  if (!Ssm_info[ssm_index].use_custom_message)
330  HUD_printf(XSTR("Firing artillery", 1570));
331  else
332  HUD_printf(Ssm_info[ssm_index].message);
333  }
334  if (Ssm_info[ssm_index].sound_index >= 0) {
335  snd_play(&Snds[Ssm_info[ssm_index].sound_index]);
336  }
337 
338  Ssm_strikes.push_back(ssm);
339 }
340 
341 // delete a finished ssm effect
343 {
344  Ssm_strikes.erase(ssm);
345 }
346 
347 // process subspace missile stuff
349 {
350  int idx, finished;
351  SCP_list<ssm_strike>::iterator moveup, eraser;
352  ssm_info *si;
353  int weapon_objnum;
354 
355  // process all strikes
356  moveup = Ssm_strikes.begin();
357  while ( moveup != Ssm_strikes.end() ) {
358  // get the type
359  if(moveup->sinfo.ssm_index < 0){
360  continue;
361  }
362  si = &Ssm_info[moveup->sinfo.ssm_index];
363 
364  // check all the individual missiles
365  finished = 1;
366  for(idx=0; idx<moveup->sinfo.count; idx++){
367  // if this guy is not marked as done
368  if(!moveup->done_flags[idx]){
369  finished = 0;
370 
371  // if he already has the fireball effect
372  if(moveup->fireballs[idx] >= 0){
373  if ((1.0f - fireball_lifeleft_percent(&Objects[moveup->fireballs[idx]])) >= moveup->sinfo.duration) {
375  // are we a beam? -MageKing17
376  if (wip->wi_flags & WIF_BEAM) {
377  beam_fire_info fire_info;
378  memset(&fire_info, 0, sizeof(beam_fire_info));
379 
380  fire_info.accuracy = 0.000001f; // this will guarantee a hit
381  fire_info.shooter = NULL;
382  fire_info.turret = NULL;
383  fire_info.target = moveup->sinfo.target;
384  fire_info.target_subsys = NULL;
385  fire_info.bfi_flags |= BFIF_FLOATING_BEAM;
386  fire_info.starting_pos = moveup->sinfo.start_pos[idx];
387  fire_info.beam_info_index = si->weapon_info_index;
388  fire_info.team = static_cast<char>(moveup->sinfo.ssm_team);
389 
390  // fire the beam
391  beam_fire(&fire_info);
392 
393  moveup->done_flags[idx] = true;
394  } else {
395  // get an orientation
396  vec3d temp;
397  matrix orient;
398 
399  vm_vec_sub(&temp, &moveup->sinfo.target->pos, &moveup->sinfo.start_pos[idx]);
400  vm_vec_normalize(&temp);
401  vm_vector_2_matrix(&orient, &temp, NULL, NULL);
402 
403  // fire the missile and flash the screen
404  weapon_objnum = weapon_create(&moveup->sinfo.start_pos[idx], &orient, si->weapon_info_index, -1, -1, 1);
405 
406  if (weapon_objnum >= 0) {
407  Weapons[Objects[weapon_objnum].instance].team = moveup->sinfo.ssm_team;
408  Weapons[Objects[weapon_objnum].instance].homing_object = moveup->sinfo.target;
409  Weapons[Objects[weapon_objnum].instance].target_sig = moveup->sinfo.target->signature;
410  }
411 
412  // this makes this particular missile done
413  moveup->done_flags[idx] = true;
414  }
415  }
416  }
417  // maybe create his warpin effect
418  else if((moveup->sinfo.delay_stamp[idx] >= 0) && timestamp_elapsed(moveup->sinfo.delay_stamp[idx])){
419  // get an orientation
420  vec3d temp;
421  matrix orient;
422 
423  vm_vec_sub(&temp, &moveup->sinfo.target->pos, &moveup->sinfo.start_pos[idx]);
424  vm_vec_normalize(&temp);
425  vm_vector_2_matrix(&orient, &temp, NULL, NULL);
426  moveup->fireballs[idx] = fireball_create(&moveup->sinfo.start_pos[idx], FIREBALL_WARP, FIREBALL_WARP_EFFECT, -1, si->warp_radius, 0, &vmd_zero_vector, si->warp_time, 0, &orient);
427  }
428  }
429  }
430  if(finished){
431  eraser = moveup;
432  ++moveup;
433  ssm_delete(eraser);
434  continue;
435  }
436 
437  ++moveup;
438  }
439 }
440 
441 
442 // test code for subspace missile strike -------------------------------------------
443 
444 // level init
446 {
447 }
448 
449 // update all hud artillery related stuff
451 {
452 }
453 
454 // render all hud artillery related stuff
456 {
457  // render how long the player has been painting his target
458  if((Player_ai != NULL) && (Player_ai->artillery_objnum >= 0)){
461  }
462 }
int timestamp(int delta_ms)
Definition: timer.cpp:226
weapon Weapons[MAX_WEAPONS]
Definition: weapons.cpp:78
ai_info * Player_ai
Definition: ai.cpp:24
int beam_info_index
Definition: beam.h:57
object * homing_object
Definition: weapon.h:177
SCP_list< ssm_strike > Ssm_strikes
void vm_vec_scale_add(vec3d *dest, const vec3d *src1, const vec3d *src2, float k)
Definition: vecmat.cpp:266
SCP_vector< vec3d > start_pos
Definition: hudartillery.h:49
float frand_range(float min, float max)
Return a floating point number in the range min..max.
Definition: floating.cpp:50
weapon_info Weapon_info[MAX_WEAPON_TYPES]
Definition: weapons.cpp:79
void hud_artillery_render()
SCP_vector< game_snd > Snds
Definition: gamesnd.cpp:19
object * target
Definition: beam.h:62
int required_string_one_of(int arg_count,...)
Checks for one of any of the given required strings.
Definition: parselo.cpp:708
#define SSM_SHAPE_CIRCLE
Definition: hudartillery.h:24
int weapon_create(vec3d *pos, matrix *orient, int weapon_type, int parent_obj, int group_id=-1, int is_locked=0, int is_spawned=0, float fof_cooldown=0.0f, ship_subsys *src_turret=NULL)
Definition: weapons.cpp:5246
void ssm_process()
SCP_vector< ssm_info > Ssm_info
int weapon_info_lookup(const char *name=NULL)
Definition: weapons.cpp:467
void _cdecl void void _cdecl void _cdecl Warning(char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
Assert(pm!=NULL)
int bfi_flags
Definition: beam.h:71
Definition: pstypes.h:88
#define mprintf(args)
Definition: pstypes.h:238
float artillery_lock_time
Definition: ai.h:544
int weapon_info_index
Definition: hudartillery.h:32
SCP_vector< int > fireballs
Definition: hudartillery.h:60
ship_subsys * turret
Definition: beam.h:60
CButton * team
ship_subsys * target_subsys
Definition: beam.h:63
GLclampf f
Definition: Glext.h:7097
#define SIZE_T_ARG
Definition: clang.h:61
void vm_vec_random_in_sphere(vec3d *out, const vec3d *in, const matrix *orient, float radius, int on_edge)
Definition: vecmat.cpp:2494
int center_offset_y
Definition: 2d.h:364
#define Assertion(expr, msg,...)
Definition: clang.h:41
vec3d starting_pos
Definition: beam.h:66
void parse_ssm(const char *filename)
GLenum GLuint GLenum GLsizei const GLchar * message
Definition: Glext.h:5156
void gr_set_color_fast(color *dst)
Definition: 2d.cpp:1197
float beam_life
Definition: weapon.h:254
hull_check orient
Definition: lua.cpp:5049
int beam_warmdown
Definition: weapon.h:256
int rand32()
Definition: systemvars.cpp:112
int required_string_either(char *str1, char *str2)
Checks for one of two required strings.
Definition: parselo.cpp:673
vec3d pos
Definition: object.h:152
SCP_vector< int > delay_stamp
Definition: hudartillery.h:48
void stuff_float(float *f)
Definition: parselo.cpp:2328
class object * target
Definition: hudartillery.h:53
float warp_radius
Definition: hudartillery.h:33
float warp_time
Definition: hudartillery.h:34
void ssm_level_init()
#define SSM_SHAPE_SPHERE
Definition: hudartillery.h:25
int instance
Definition: object.h:150
beam_weapon_info b_info
Definition: weapon.h:456
matrix * vm_vector_2_matrix(matrix *m, const vec3d *fvec, const vec3d *uvec, const vec3d *rvec)
Definition: vecmat.cpp:850
GLintptr offset
Definition: Glext.h:5497
void parse_sound(const char *tag, int *idx_dest, const char *object_name, parse_sound_flags flags)
Definition: gamesnd.cpp:445
#define SSM_SHAPE_POINT
Definition: hudartillery.h:23
struct matrix::@228::@230 vec
void ssm_get_random_start_pos(vec3d *out, vec3d *start, matrix *orient, int ssm_index)
int team
Definition: weapon.h:167
int cf_exists_full(const char *filename, int dir_type)
Definition: cfile.cpp:527
char * filename
float max_offset
Definition: hudartillery.h:38
void stuff_string(char *outstr, int type, int len, char *terminators)
Definition: parselo.cpp:1189
#define CF_TYPE_TABLES
Definition: cfile.h:50
sprintf(buf,"(%f,%f,%f)", v3->xyz.x, v3->xyz.y, v3->xyz.z)
#define BFIF_FLOATING_BEAM
Definition: beam.h:53
float max_radius
Definition: hudartillery.h:36
int required_string(const char *pstr)
Definition: parselo.cpp:468
int snd_play(game_snd *gs, float pan, float vol_scale, int priority, bool is_voice_msg)
Definition: sound.cpp:517
GLdouble s
Definition: Glext.h:5321
int optional_string(const char *pstr)
Definition: parselo.cpp:539
char message[NAME_LENGTH]
Definition: hudartillery.h:39
float fireball_lifeleft_percent(object *obj)
Definition: fireballs.cpp:686
char name[NAME_LENGTH]
Definition: hudartillery.h:29
void read_file_text(const char *filename, int mode, char *processed_text, char *raw_text)
Definition: parselo.cpp:1995
float offset
Definition: hudartillery.h:37
int beam_fire(beam_fire_info *fire_info)
Definition: beam.cpp:281
int idx
Definition: multiui.cpp:761
#define FIREBALL_WARP
Definition: fireballs.h:29
SCP_vector< bool > done_flags
Definition: hudartillery.h:61
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
int ssm_info_lookup(const char *name)
int wi_flags
Definition: weapon.h:384
const char * XSTR(const char *str, int index)
Definition: localize.cpp:851
void ssm_init()
void stuff_boolean(int *i, bool a_to_eol)
Definition: parselo.cpp:2519
#define NOX(s)
Definition: pstypes.h:473
GLuint start
Definition: Gl.h:1502
void ssm_create(object *target, vec3d *start, size_t ssm_index, ssm_firing_info *override, int team)
int target_sig
Definition: weapon.h:173
void vm_vec_random_in_circle(vec3d *out, const vec3d *in, const matrix *orient, float radius, int on_edge)
Definition: vecmat.cpp:2481
void reset_parse(char *text)
Definition: parselo.cpp:3305
GLuint const GLchar * name
Definition: Glext.h:5608
void vm_vec_sub(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:168
void stuff_int(int *i)
Definition: parselo.cpp:2372
#define NAME_LENGTH
Definition: globals.h:15
int artillery_objnum
Definition: ai.h:542
float radius
Definition: hudartillery.h:35
int optional_string_either(char *str1, char *str2)
Definition: parselo.cpp:551
GLenum target
Definition: Glext.h:6872
screen gr_screen
Definition: 2d.cpp:46
#define WIF_BEAM
Definition: weapon.h:76
void validate_SSM_entries()
Definition: weapons.cpp:7461
bool send_message
Definition: hudartillery.h:41
object * shooter
Definition: beam.h:58
int center_offset_x
Definition: 2d.h:364
#define MULTIPLAYER_MASTER
Definition: multi.h:130
int sound_index
Definition: hudartillery.h:42
#define F_NAME
Definition: parselo.h:34
#define LOCATION
Definition: pstypes.h:245
#define timestamp_elapsed(stamp)
Definition: timer.h:102
float accuracy
Definition: beam.h:61
void hud_init_artillery()
GLint GLsizei count
Definition: Gl.h:1491
int parse_modular_table(const char *name_check, void(*parse_callback)(const char *filename), int path_type, int sort_type)
Definition: parselo.cpp:4205
int temp
Definition: lua.cpp:4996
bool use_custom_message
Definition: hudartillery.h:40
void HUD_printf(const char *format,...)
Definition: hudmessage.cpp:527
color Color_bright_blue
Definition: alphacolors.cpp:31
void _cdecl gr_printf_no_resize(int x, int y, const char *format,...)
Definition: font.cpp:342
#define FIREBALL_WARP_EFFECT
Definition: fireballs.h:25
char team
Definition: beam.h:72
vec3d vmd_zero_vector
Definition: vecmat.cpp:24
int max_count
Definition: hudartillery.h:31
#define stricmp(s1, s2)
Definition: config.h:271
void hud_artillery_update()
void ssm_delete(SCP_list< ssm_strike >::iterator ssm)
ssm_firing_info sinfo
Definition: hudartillery.h:64
float vm_vec_normalize(vec3d *v)
Definition: vecmat.cpp:460
int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_obj, float size, int reverse, vec3d *velocity, float warp_lifetime, int ship_class, matrix *orient_override, int low_res, int extra_flags, int warp_open_sound, int warp_close_sound)
Definition: fireballs.cpp:788