1 /*
2 weapons.c
3
4 Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
5 and the "Aleph One" developers.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 This license is contained in the file "COPYING",
18 which is included with this source code; it is available online at
19 http://www.gnu.org/licenses/gpl.html
20
21 Saturday, May 13, 1995 4:41:04 PM- rdm created.
22 Recreating to fix all the annoying problems.
23
24 Feb. 4, 2000 (Loren Petrich):
25 Changed halt() to assert(false) for better debugging
26
27 Feb 19, 2000 (Loren Petrich):
28 Suppressed debug checking of which weapons and triggers
29 in get_trigger_definition()
30
31 March 2, 2000 (Loren Petrich):
32 Suppressed player_weapon_has_ammo() assert in should_switch_to_weapon();
33 causes problems in "Missed Island"'s first level.
34
35 March 3, 2000 (Loren Petrich):
36 Suppressed complicated assert in fire_weapon();
37 causes problems in the map "Dirt Devil", which turns the flamethrower into a jetpack.
38
39 Apr 27, 2000 (Loren Petrich):
40 Added Josh Elsasser's "don't switch weapons" patch
41
42 May 23, 2000 (Loren Petrich):
43 Correct behavior of weapon luminosity; it now adds to miner's light
44 rather than substituting for it.
45
46 May 26, 2000 (Loren Petrich):
47 Added XML configuration of shell casings and weapon order.
48 Attempted to add more graceful behavior for some weapons being NONE.
49 In Muerte Machine, the weapons are disabled if the fists have weapon type NONE;
50 implemented the use of this as a flag.
51
52 Added "CannotWieldWeapons()" test; it returns true if the fists have a weapon type of NONE
53
54 Jun 14, 2000 (Loren Petrich):
55 Suppressed assertion about multiple triggers that follows the Dirt-Devil one
56
57 Jun 15, 2000 (Loren Petrich):
58 Added support for Chris Pruett's Pfhortran
59
60 Jul 1, 2000 (Loren Petrich):
61 Made some accessors inline
62
63 Jul 1, 2000 (Loren Petrich):
64 Added Benad's changes
65
66 Aug 31, 2000 (Loren Petrich):
67 Added stuff for unpacking and packing
68
69 Sep 3, 2000 (Loren Petrich):
70 Suppressed "assert(weapon_type!=NUMBER_OF_WEAPONS);" in a search-for-which-weapon loop;
71 some physics models get to this without causing other trouble
72
73 Oct 19, 2000 (Loren Petrich):
74 Weapon-sprite absence in get_weapon_display_information() handled by bugging out instead of
75 a failed assertion; having a SMG will not crash if one's using a M2 shapes file.
76 Also, added a bug-out in case of no view being found.
77
78 Dec 24, 2000 (Loren Petrich):
79 Added support for idle-weapon animations
80
81 Dec 31, 2000 (Loren Petrich):
82 Turned a remaining out-of-range assert into a no-render
83
84 Jan 6, 2001 (Loren Petrich):
85 Added modification of guided-projectile patch from AlexJLS@aol.com;
86 one can now shoot guided missiles.
87
88 Feb 1, 2001 (Loren Petrich):
89 Added fix for firing-animation wraparound; prevent_wrap is true for those animations also.
90
91 Apr 10, 2003 (Woody Zenfell):
92 Fixed bug where dropping the skull made two of them (had this really been in there for almost 3 years??)
93 */
94
95 #include "cseries.h"
96 #include "map.h"
97 #include "projectiles.h"
98 #include "player.h"
99 #include "weapons.h"
100 #include "SoundManager.h"
101 #include "interface.h"
102 #include "items.h"
103 #include "monsters.h"
104 #include "game_window.h"
105 #include "preferences.h"
106 #include "InfoTree.h"
107
108 #include "Packing.h"
109 #include "shell.h"
110
111 #include <string.h>
112 #include <stdlib.h>
113 #include <limits.h>
114
115 #include "weapon_definitions.h"
116
117 // To Do:
118 // lowering second weapon on ammo empty flubs.
119
120 /* ------------- enums */
121 enum /* weapon states */
122 {
123 _weapon_idle, /* if weapon_delay is non-zero, the weapon cannot be fired again yet */
124 _weapon_raising, /* weapon is rising to idle position */
125 _weapon_lowering, /* weapon is lowering off the screen */
126 _weapon_charging, /* Weapon is charging to fire.. */
127 _weapon_charged, /* Ready to fire.. */
128 _weapon_firing, /* in firing animation */
129 _weapon_recovering, /* Weapon is recovering from firing. */
130 _weapon_awaiting_reload, /* About to start reload sequence */
131 _weapon_waiting_to_load, /* waiting to actually put bullets in */
132 _weapon_finishing_reload, /* finishing the reload */
133
134 _weapon_lowering_for_twofisted_reload, /* lowering so the other weapon can reload */
135 _weapon_awaiting_twofisted_reload, /* waiting for other to lower.. */
136 _weapon_waiting_for_twofist_to_reload, /* we are offscreen, waiting for the other to finish its load */
137 _weapon_sliding_over_to_second_position, /* pistol is going across when the weapon is present */
138 _weapon_sliding_over_from_second_position, /* Pistol returning to center of screen.. */
139 _weapon_waiting_for_other_idle_to_reload, /* Pistol awaiting friend's idle.. */
140 NUMBER_OF_WEAPON_STATES
141 };
142
143 enum {
144 _trigger_down= 0x0001,
145 _primary_weapon_is_up= 0x0002,
146 _secondary_weapon_is_up= 0x0004,
147 _wants_twofist= 0x0008,
148 _flip_state= 0x0010
149 };
150
151 enum {
152 _weapon_type= 0,
153 _shell_casing_type,
154 _weapon_ammo_type,
155 NUMBER_OF_DATA_TYPES
156 };
157
158 enum { /* For the flags */ /* [11.unused 1.horizontal 1.vertical 3.unused] */
159 _flip_shape_horizontal= 0x08,
160 _flip_shape_vertical= 0x10
161 };
162
163 #define PRIMARY_WEAPON_IS_VALID(wd) ((wd)->flags & _primary_weapon_is_up)
164 #define SECONDARY_WEAPON_IS_VALID(wd) ((wd)->flags & _secondary_weapon_is_up)
165 #define SET_PRIMARY_WEAPON_IS_VALID(wd, v) ((void)((v) ? ((wd)->flags |= _primary_weapon_is_up) : ((wd)->flags &= ~_primary_weapon_is_up)))
166 #define SET_SECONDARY_WEAPON_IS_VALID(wd, v) ((void)((v) ? ((wd)->flags |= _secondary_weapon_is_up) : ((wd)->flags &= ~_secondary_weapon_is_up)))
167
168 #define SET_WEAPON_WANTS_TWOFIST(wd, v) ((void)((v) ? ((wd)->flags |= _wants_twofist) : ((wd)->flags &= ~_wants_twofist)))
169 #define WEAPON_WANTS_TWOFIST(wd) ((wd)->flags & _wants_twofist)
170
171 #define TRIGGER_IS_DOWN(wd) ((wd)->flags & _trigger_down)
172 #define SET_TRIGGER_DOWN(wd, v) ((void)((v) ? ((wd)->flags |= _trigger_down) : ((wd)->flags &= ~_trigger_down)))
173
174 #define GET_WEAPON_VARIANCE_SIGN(wd) (((wd)->flags & _flip_state) ? (1) : (-1))
175 #define FLIP_WEAPON_VARIANCE_SIGN(wd) (((wd)->flags & _flip_state) ? ((wd)->flags &= ~_flip_state) : ((wd)->flags |= _flip_state))
176
177 #define PISTOL_SEPARATION_WIDTH (FIXED_ONE/4)
178 #define AUTOMATIC_STILL_FIRING_DURATION (4)
179 #define FIRING_BEFORE_SHELL_CASING_SOUND_IS_PLAYED (TICKS_PER_SECOND/2)
180 #define COST_PER_CHARGED_WEAPON_SHOT 4
181 #define ANGULAR_VARIANCE (32)
182
183 #define M1_MISSILE_AMMO_SEQUENCE 20
184 #define M1_MISSILE_AMMO_XOFFSET (FIXED_ONE/12)
185 #define M1_MISSILE_AMMO_YOFFSET (-FIXED_ONE/15)
186
187 enum // shell casing flags
188 {
189 _shell_casing_is_reversed= 0x0001
190 };
191 #define SHELL_CASING_IS_REVERSED(s) ((s)->flags&_shell_casing_is_reversed)
192
193 /* ----------- structures */
194 /* ...were all moved to weapons.h */
195
196 /* ------------- globals */
197 /* The array of player weapon states */
198 static struct player_weapon_data *player_weapons_array;
199
200 /* ------------- macros */
201 #define get_maximum_number_of_players() (MAXIMUM_NUMBER_OF_PLAYERS)
202 #define BUILD_WEAPON_IDENTIFIER(weapon, trigger) (weapon<<1+trigger)
203 #define GET_WEAPON_FROM_IDENTIFIER(identifier) (identifier>>1)
204 #define GET_TRIGGER_FROM_IDENTIFIER(identifier) (identifier&1)
205
206 /*static*/ player_weapon_data *get_player_weapon_data(
207 const short player_index);
208
209 static weapon_definition *get_weapon_definition(
210 const short weapon_type);
211
212 static shell_casing_definition *get_shell_casing_definition(
213 const short type);
214
215 /* -------------- accessors */
216
get_player_weapon_data(const short player_index)217 player_weapon_data *get_player_weapon_data(
218 const short player_index)
219 {
220 player_weapon_data *data = GetMemberWithBounds(player_weapons_array,player_index,get_maximum_number_of_players());
221 assert(data);
222
223 return data;
224 }
225
get_weapon_definition(const short weapon_type)226 weapon_definition *get_weapon_definition(
227 const short weapon_type)
228 {
229 weapon_definition *definition = GetMemberWithBounds(weapon_definitions,weapon_type,NUMBER_OF_WEAPONS);
230 assert(definition);
231
232 return definition;
233 }
234
get_shell_casing_definition(const short type)235 shell_casing_definition *get_shell_casing_definition(
236 const short type)
237 {
238 shell_casing_definition *definition = GetMemberWithBounds(shell_casing_definitions,type,NUMBER_OF_SHELL_CASING_TYPES);
239 assert(definition);
240
241 return definition;
242 }
243
244 /* ------------- local prototypes */
245 static void reset_trigger_data(short player_index, short weapon_type, short which_trigger);
246 static bool weapon_works_in_current_environment(short weapon_index);
247 /*static*/ void select_next_best_weapon(short player_index);
248 static struct trigger_data *get_player_trigger_data(short player_index,
249 short which_trigger);
250 struct trigger_data *get_trigger_data(short player_index, short weapon_index,
251 short which_trigger);
252 static struct weapon_data *get_player_current_weapon(short player_index);
253 static void fire_weapon(short player_index, short which_trigger,
254 _fixed charged_amount, bool flail_wildly);
255 static struct trigger_definition *get_trigger_definition(short player_index, short which_weapon,
256 short which_trigger);
257 static bool should_switch_to_weapon(short player_index, short new_weapon);
258 /* CP Addition: 'static' removed from decleration of ready_weapon() */
259 /*static*/ bool ready_weapon(short player_index, short weapon_index);
260 struct weapon_definition *get_current_weapon_definition(short player_index);
261 static bool reload_weapon(short player_index, short which_trigger);
262 static struct trigger_definition *get_player_trigger_definition(short player_index,
263 short which_trigger);
264 static bool handle_trigger_down(short player_index, short which_trigger);
265 static bool handle_trigger_up(short player_index, short which_trigger);
266 static void put_rounds_into_weapon(short player_index, short which_weapon, short which_trigger);
267 static void blow_up_player(short player_index);
268 static void select_next_weapon(short player_index, bool forward);
269 static void calculate_weapon_position_for_idle(short player_index, short count, short weapon_type,
270 _fixed *height, _fixed *width, bool use_elevation);
271 static void add_random_flutter(_fixed flutter_base, _fixed *height, _fixed *width);
272 static void calculate_weapon_origin_and_vector(short player_index, short which_trigger,
273 world_point3d *origin, world_point3d *_vector, short *origin_polygon, angle delta_theta);
274 static void play_weapon_sound(short player_index, short sound, _fixed pitch);
275 static bool player_weapon_has_ammo(short player_index, short weapon_index);
276 static void lower_weapon(short player_index, short weapon_index);
277 static void raise_weapon(short player_index, short weapon_index);
278 static bool check_reload(short player_index, short which_trigger);
279 static short get_active_trigger_count_and_states(short player_index,
280 short weapon_index, uint32 action_flags, short *first_trigger, bool *triggers_down);
281 static bool dual_function_secondary_has_control(short player_index);
282 static void calculate_ticks_from_shapes(void);
283 static void update_sequence(short player_index, short which_trigger);
284 static void update_automatic_sequence(short player_index, short which_trigger);
285 static bool get_weapon_data_type_for_count(short player_index, short count, short *type,
286 short *index, short *flags);
287 static void update_player_ammo_count(short player_index);
288 /*static*/ bool player_has_valid_weapon(short player_index);
289 static void idle_weapon(short player_index);
290 static void test_raise_double_weapon(short player_index, uint32 *action_flags);
291 static void modify_position_for_two_weapons(short player_index, short count, _fixed *width, _fixed *height);
292 static void change_to_desired_weapon(short player_index);
293 static void destroy_current_weapon(short player_index);
294 static void initialize_shell_casings(short player_index);
295 static short new_shell_casing(short player_index, short type, uint16 flags);
296 static void update_shell_casings(short player_index);
297 static bool get_shell_casing_display_data(struct weapon_display_information *display, short index);
298 static bool automatic_still_firing(short player_index, short which_trigger);
299 static void play_shell_casing_sound(short player_index, short sound_index);
300 static short find_weapon_power_index(short weapon_type);
301
302 #ifdef DEBUG
303 static void debug_weapon(short index);
304 static void debug_trigger_data(short weapon_type, short which_trigger);
305 #endif
306
307
308 // LP addition: this function indicates whether weapons can be wielded
309 // Set to fists being NONE
CannotWieldWeapons()310 inline bool CannotWieldWeapons()
311 {return get_weapon_definition(_weapon_fist)->weapon_class == NONE;}
312
313 // For animating the idle weapons shape
314 static void UpdateIdleAnimation(short player_index, short which_trigger);
315
316
317 /* ------------ code starts */
initialize_weapon_manager(void)318 void initialize_weapon_manager(
319 void)
320 {
321 player_weapons_array= (struct player_weapon_data *) malloc(MAXIMUM_NUMBER_OF_PLAYERS*sizeof(struct player_weapon_data));
322 assert(player_weapons_array);
323
324 objlist_clear(player_weapons_array, MAXIMUM_NUMBER_OF_PLAYERS);
325 }
326
initialize_player_weapons_for_new_game(short player_index)327 void initialize_player_weapons_for_new_game(
328 short player_index)
329 {
330 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
331
332 /* Clear the shots fired and all that jazz */
333 obj_clear(*player_weapons);
334
335 /* initialize the weapons to known states. */
336 initialize_player_weapons(player_index);
337 initialize_shell_casings(player_index);
338 }
339
340 /* initialize the given players weapons-> called after creating a player */
initialize_player_weapons(short player_index)341 void initialize_player_weapons(
342 short player_index)
343 {
344 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
345 struct player_data *player= get_player_data(player_index);
346
347 for(unsigned weapon_type= 0; weapon_type<NUMBER_OF_WEAPONS; ++weapon_type)
348 {
349 short which_trigger;
350
351 for(which_trigger= 0; which_trigger<NUMBER_OF_TRIGGERS; ++which_trigger)
352 {
353 reset_trigger_data(player_index, weapon_type, which_trigger);
354 }
355
356 /* We _could_ figure this out, but this is easier.. */
357 player_weapons->weapons[weapon_type].weapon_type= weapon_type;
358 player_weapons->weapons[weapon_type].flags= 0;
359 player_weapons->weapons[weapon_type].unused= 0;
360 }
361
362 /* Reset the current and desired weapon.. */
363 player_weapons->current_weapon= NONE;
364 player_weapons->desired_weapon= NONE;
365
366 /* Reset the player crap.. */
367 player->weapon_intensity= NATURAL_LIGHT_INTENSITY;
368 player->weapon_intensity_decay= 0;
369 }
370
371 /* Mark the weapon collections for loading or unloading.. */
mark_weapon_collections(bool loading)372 void mark_weapon_collections(
373 bool loading)
374 {
375 for(unsigned index= 0; index<NUMBER_OF_WEAPONS; ++index)
376 {
377 struct weapon_definition *definition= get_weapon_definition(index);
378
379 /* Mark the weapon�s collection */
380 loading ? mark_collection_for_loading(definition->collection) :
381 mark_collection_for_unloading(definition->collection);
382
383 /* Mark the projectile�s collection, NONE is handled correctly */
384 if(index != _weapon_ball)
385 {
386 mark_projectile_collections(definition->weapons_by_trigger[_primary_weapon].projectile_type, loading);
387 mark_projectile_collections(definition->weapons_by_trigger[_secondary_weapon].projectile_type, loading);
388 }
389 }
390 }
391
player_hit_target(short player_index,short weapon_identifier)392 void player_hit_target(
393 short player_index,
394 short weapon_identifier)
395 {
396 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
397 short weapon_id, trigger;
398
399 weapon_id= GET_WEAPON_FROM_IDENTIFIER(weapon_identifier);
400 trigger= GET_TRIGGER_FROM_IDENTIFIER(weapon_identifier);
401
402 assert(weapon_id>=0 && weapon_id<short(NUMBER_OF_WEAPONS));
403 player_weapons->weapons[weapon_id].triggers[trigger].shots_hit++;
404 }
405
406 /* Called on entry to a level, and will change weapons if this one doesn't work */
407 /* in the given environment. */
check_player_weapons_for_environment_change(void)408 void check_player_weapons_for_environment_change(
409 void)
410 {
411 short player_index;
412
413 for(player_index=0; player_index<dynamic_world->player_count; ++player_index)
414 {
415 if(player_has_valid_weapon(player_index))
416 {
417 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
418
419 if(!weapon_works_in_current_environment(player_weapons->current_weapon))
420 {
421 /* Change out of the current weapon immediately.. */
422 player_weapons->current_weapon= NONE;
423
424 /* Select the next best weapon for this person.. */
425 select_next_best_weapon(player_index);
426 }
427 }
428 }
429
430 /* while we are at it, setup the definitions for the weapons */
431 calculate_ticks_from_shapes();
432 }
433
434 /* Called when a player dies to discharge the weapons that they have charged up. */
discharge_charged_weapons(short player_index)435 void discharge_charged_weapons(
436 short player_index)
437 {
438 struct trigger_data *weapon;
439 short which_trigger;
440
441 if(player_has_valid_weapon(player_index))
442 {
443 short first_trigger, trigger_count;
444 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
445
446 trigger_count= get_active_trigger_count_and_states(player_index, player_weapons->current_weapon,
447 0l, &first_trigger, NULL);
448 for(which_trigger= first_trigger; which_trigger<trigger_count; ++which_trigger)
449 {
450 weapon= get_player_trigger_data(player_index, which_trigger);
451 if(weapon->state==_weapon_charged)
452 {
453 /* Fire the weapon! (give it to them fully charged..) */
454 fire_weapon(player_index, which_trigger, FIXED_ONE, true);
455 }
456 }
457 }
458 }
459
460 /* When the player runs over an item, check for reloads, etc. */
process_new_item_for_reloading(short player_index,short item_type)461 void process_new_item_for_reloading(
462 short player_index,
463 short item_type)
464 {
465 /* Is this a weapon? */
466 switch(get_item_kind(item_type))
467 {
468 case _ball:
469 case _weapon:
470 for(unsigned weapon_type= 0; weapon_type<NUMBER_OF_WEAPONS; ++weapon_type)
471 {
472 struct weapon_definition *definition= get_weapon_definition(weapon_type);
473
474 /* If this is actually a weapon.. */
475 if(definition->item_type==item_type)
476 {
477 short which_trigger, first_trigger, trigger_count;
478 struct player_data *player= get_player_data(player_index);
479
480 /* Load the weapons */
481 if(definition->weapon_class==_twofisted_pistol_class)
482 {
483 // Skip over unrecognized ones
484 assert(definition->item_type>=0 && definition->item_type<NUMBER_OF_ITEMS);
485 if(player->items[definition->item_type]>1)
486 {
487 /* Just load the secondary one.. */
488 first_trigger= _secondary_weapon;
489 trigger_count= 2;
490
491 /* Go ahead and mark the weapon display as dirty (because it will be) */
492 update_player_ammo_count(player_index);
493 if(player_index==current_player_index) mark_weapon_display_as_dirty();
494 } else {
495 first_trigger= _primary_weapon;
496 trigger_count= 1;
497 }
498 } else {
499 /* They aren't twofisted pistols */
500 first_trigger= _primary_weapon;
501 switch(definition->weapon_class)
502 {
503 case _normal_class:
504 trigger_count= 1;
505 break;
506
507 case _dual_function_class:
508 case _melee_class:
509 case _multipurpose_class:
510 trigger_count= 2;
511 break;
512
513 // LP change: no weapon
514 case NONE:
515 case _twofisted_pistol_class:
516 default:
517 trigger_count = 0;
518 break;
519 }
520 }
521
522 /* Reset the trigger data.. */
523 for(which_trigger= first_trigger; which_trigger<trigger_count; ++which_trigger)
524 {
525 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
526 struct trigger_definition *trigger_definition=
527 get_trigger_definition(player_index, weapon_type, which_trigger);
528
529 /* Reset it. */
530 reset_trigger_data(player_index, weapon_type, which_trigger);
531
532 if(definition->flags & _weapon_has_random_ammo_on_pickup)
533 {
534 short rounds_given;
535
536 rounds_given= trigger_definition->rounds_per_magazine/2 +
537 (global_random()%(trigger_definition->rounds_per_magazine/2+1));
538 player_weapons->weapons[weapon_type].triggers[which_trigger].rounds_loaded=
539 rounds_given;
540
541 /* Sync the weapons ammo amounts.. */
542 if(definition->flags & _weapon_triggers_share_ammo)
543 {
544 player_weapons->weapons[weapon_type].triggers[!which_trigger].rounds_loaded=
545 rounds_given;
546 }
547 } else {
548 player_weapons->weapons[weapon_type].triggers[which_trigger].rounds_loaded=
549 trigger_definition->rounds_per_magazine;
550 }
551 }
552
553 if(should_switch_to_weapon(player_index, weapon_type))
554 {
555 if(!ready_weapon(player_index, weapon_type))
556 {
557 dprintf("Error! Unable to ready something I should: %d weapon: %d;g",
558 player_index, weapon_type);
559 }
560 }
561 break; /* Out of the for loop */
562 }
563 }
564 // One comes here if a weapon had not been on one of the list
565 // assert(weapon_type!=NUMBER_OF_WEAPONS);
566 break;
567
568 case _ammunition:
569 /* Don't try to reload if the player has an invalid weapon */
570 if(player_has_valid_weapon(player_index))
571 {
572 for(unsigned weapon_type= 0; weapon_type<NUMBER_OF_WEAPONS; ++weapon_type)
573 {
574 short which_trigger, first_trigger, trigger_count;
575
576 trigger_count= get_active_trigger_count_and_states(player_index, weapon_type, 0l, &first_trigger, NULL);
577 for(which_trigger= first_trigger; which_trigger<trigger_count; ++which_trigger)
578 {
579 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
580 struct trigger_definition *trigger_definition=
581 get_trigger_definition(player_index, weapon_type, which_trigger);
582
583 if(trigger_definition->ammunition_type==item_type &&
584 int(weapon_type)==player_weapons->current_weapon &&
585 player_weapons->current_weapon==player_weapons->desired_weapon)
586 {
587 struct weapon_data *weapon= get_player_current_weapon(player_index);
588
589 /* reload it. */
590 if(weapon->triggers[which_trigger].state==_weapon_idle &&
591 weapon->triggers[which_trigger].rounds_loaded==0)
592 {
593 if(!reload_weapon(player_index, which_trigger))
594 {
595 dprintf("Error reloading!?");
596 }
597 }
598 }
599 }
600 }
601 }
602 break;
603
604 default:
605 break;
606 }
607 }
608
609 #define IDLE_PHASE_COUNT 1000 // doesn't matter
610 #define CHARGED_WEAPON_OVERLOAD (60*TICKS_PER_SECOND)
611 #define WEAPON_FORWARD_DISPLACEMENT (WORLD_ONE_FOURTH/2)
612 #define WEAPON_SHORTED_SOUND NONE
613
614 /* Update the given player's weapons */
update_player_weapons(short player_index,uint32 action_flags)615 void update_player_weapons(
616 short player_index,
617 uint32 action_flags)
618 {
619 update_shell_casings(player_index);
620
621 if(player_has_valid_weapon(player_index))
622 {
623 struct player_data *player= get_player_data(player_index);
624 struct weapon_data *weapon= get_player_current_weapon(player_index);
625 struct weapon_definition *definition= get_current_weapon_definition(player_index);
626 short which_trigger, trigger_count, first_trigger;
627 bool triggers_down[NUMBER_OF_TRIGGERS];
628
629 /* Did they want to raise a second weapon? */
630 test_raise_double_weapon(player_index, &action_flags);
631
632 /* Calculate how many triggers we have to deal with.. */
633 trigger_count= get_active_trigger_count_and_states(player_index, weapon->weapon_type,
634 action_flags, &first_trigger, triggers_down);
635
636 /* twiddle with their weapon_intensity decay */
637 if (player->weapon_intensity_decay>0)
638 {
639 if(definition->firing_intensity_decay_ticks)
640 {
641 player->weapon_intensity= NATURAL_LIGHT_INTENSITY +
642 // LP change: now adds correctly, rather than replacing
643 ((definition->firing_light_intensity)*
644 player->weapon_intensity_decay)/definition->firing_intensity_decay_ticks;
645 player->weapon_intensity_decay--;
646 } else {
647 player->weapon_intensity_decay= 0;
648 }
649 } else
650 player->weapon_intensity = NATURAL_LIGHT_INTENSITY;
651
652 // wheee!!!
653 for(which_trigger= first_trigger; which_trigger<trigger_count; ++which_trigger)
654 {
655 struct trigger_data *trigger= get_player_trigger_data(player_index, which_trigger);
656
657 /* Twiddle the sequence (done after we change our states..) */
658 /* This has to be in front of the trigger stuff, otherwise you won't see the first */
659 /* tick of the firing animation frame. But it also needs to be after the state change */
660 /* so that you don't wrap on the reloading sequence. This is fixed by special casing */
661 /* the loading such that it doesn't update on the last tick. */
662 update_sequence(player_index, which_trigger);
663
664 /* Check for trigger down states before entering the state machine. */
665 if(triggers_down[which_trigger])
666 {
667 handle_trigger_down(player_index, which_trigger);
668 } else {
669 handle_trigger_up(player_index, which_trigger);
670 }
671
672 /* Increment ticks since last shot, decrement the phase. */
673 trigger->ticks_since_last_shot++;
674 trigger->phase--;
675
676 /* Update the ticks firing */
677 if(which_trigger==_primary_weapon &&
678 (definition->flags & _weapon_is_automatic) &&
679 (trigger->state==_weapon_firing || trigger->state==_weapon_recovering ||
680 (trigger->state==_weapon_idle && automatic_still_firing(player_index, _primary_weapon))))
681 {
682 trigger->ticks_firing++;
683 } else {
684 trigger->ticks_firing= 0;
685 }
686
687 /* If we had a state change.. */
688 if(trigger->phase<=0)
689 {
690 switch(trigger->state)
691 {
692 case _weapon_waiting_to_load:
693 /* This is th point that you actually load the wepaon */
694 if(definition->finish_loading_ticks)
695 {
696 trigger->state= _weapon_finishing_reload;
697 trigger->phase= definition->finish_loading_ticks;
698 } else {
699 /* Don't go to a state with a zero duration */
700 trigger->state= _weapon_idle;
701 trigger->sequence= 0;
702 trigger->phase= IDLE_PHASE_COUNT;
703 }
704
705 /* Bracketed for optimization (stupidity) gains. */
706 {
707 struct player_weapon_data *player_weapons=
708 get_player_weapon_data(player_index);
709
710 put_rounds_into_weapon(player_index, player_weapons->current_weapon,
711 which_trigger);
712 }
713 break;
714
715 case _weapon_raising:
716 trigger->phase= IDLE_PHASE_COUNT; // doesn't matter.
717 trigger->state= _weapon_idle;
718 trigger->sequence= 0;
719 check_reload(player_index, which_trigger);
720 break;
721
722 case _weapon_finishing_reload:
723 case _weapon_sliding_over_to_second_position:
724 case _weapon_sliding_over_from_second_position:
725 trigger->phase= IDLE_PHASE_COUNT; // doesn't matter.
726 trigger->state= _weapon_idle;
727 trigger->sequence= 0;
728 break;
729
730 // LP: separate case here, because it is now animated
731 case _weapon_idle:
732 trigger->phase= IDLE_PHASE_COUNT; // doesn't matter.
733 trigger->state= _weapon_idle;
734 break;
735
736 case _weapon_recovering:
737 trigger->phase= IDLE_PHASE_COUNT; // doesn't matter.
738 trigger->state= _weapon_idle;
739 trigger->sequence= 0;
740
741 check_reload(player_index, which_trigger);
742 break;
743
744 case _weapon_waiting_for_other_idle_to_reload:
745 /* This is a twofisted weapon, waiting for its friend to be idle so it can */
746 /* load.. */
747 {
748 struct trigger_data *other_trigger= get_player_trigger_data(player_index, !which_trigger);
749
750 if(other_trigger->state==_weapon_idle)
751 {
752 trigger->state= _weapon_awaiting_twofisted_reload;
753 trigger->phase= definition->ready_ticks;
754 other_trigger->state= _weapon_lowering_for_twofisted_reload;
755 other_trigger->phase= definition->ready_ticks;
756 } else {
757 /* Try again next time.. */
758 trigger->phase= 0;
759 }
760 }
761 break;
762
763 case _weapon_lowering:
764 if(definition->item_type==_i_red_ball)
765 {
766 short ball_color= find_player_ball_color(player_index);
767 world_point3d origin, _vector;
768 short origin_polygon, item_type;
769
770 //START Benad
771 if (ball_color != NONE)
772 {
773 item_type= ball_color+BALL_ITEM_BASE;
774
775 calculate_weapon_origin_and_vector(player_index, _primary_weapon,
776 &origin, &_vector, &origin_polygon, 0);
777
778 drop_the_ball(&origin, origin_polygon, player->monster_index,
779 _monster_marine, item_type);
780 destroy_current_weapon(player_index);
781 }
782 // END Benad
783 }
784
785 if(which_trigger==_primary_weapon)
786 {
787 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
788
789 if(trigger_count==1 && player_weapons->current_weapon != player_weapons->desired_weapon)
790 {
791 change_to_desired_weapon(player_index);
792 }
793
794 /* Reset for the next time.. */
795 SET_PRIMARY_WEAPON_IS_VALID(weapon, false);
796 // dprintf("prim down;g");
797 } else {
798 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
799
800 if(player_weapons->current_weapon!=player_weapons->desired_weapon)
801 {
802 change_to_desired_weapon(player_index);
803 }
804
805 /* Lowering the second weapon for a twofisted weapon */
806 /* Reset for the next time.. */
807 SET_SECONDARY_WEAPON_IS_VALID(weapon, false);
808 // dprintf("second down;g");
809 }
810
811 /* Reset to idle to be consistent */
812 trigger->phase= IDLE_PHASE_COUNT;
813 trigger->state= _weapon_idle;
814 trigger->sequence= 0;
815 break;
816
817 case _weapon_charging:
818 trigger->phase= CHARGED_WEAPON_OVERLOAD;
819 trigger->state= _weapon_charged;
820 break;
821
822 case _weapon_charged:
823 if(definition->flags & _weapon_overloads)
824 {
825 /* just in case we don't kill them.. */
826 trigger->phase= IDLE_PHASE_COUNT; // doesn't matter.
827 trigger->state= _weapon_idle;
828 trigger->sequence= 0;
829
830 /* oops. */
831 blow_up_player(player_index);
832 } else {
833 /* Reenter the _weapon_charged state. */
834 trigger->phase= CHARGED_WEAPON_OVERLOAD;
835 trigger->state= _weapon_charged;
836 }
837 break;
838
839 case _weapon_firing:
840 {
841 struct trigger_definition *trigger_definition=
842 get_player_trigger_definition(player_index, which_trigger);
843
844 if(trigger_definition->recovery_ticks==0)
845 {
846 trigger->state= _weapon_idle;
847 trigger->phase= 0;
848
849 if(which_trigger==_primary_weapon && TRIGGER_IS_DOWN(weapon) && (definition->flags & _weapon_is_automatic))
850 {
851 /* Don't reset the sequence for the amount of time we consider to be still firing... */
852 trigger->phase= AUTOMATIC_STILL_FIRING_DURATION;
853 // dprintf("Ticks firing: %d;g", trigger->ticks_firing);
854 } else {
855 trigger->sequence= 0;
856 }
857
858 /* Check reload state & phase take precedence over the AUTOMATIC_STILL_FIRING stuff. */
859 check_reload(player_index, which_trigger);
860 } else {
861 trigger->state= _weapon_recovering;
862 trigger->phase= trigger_definition->recovery_ticks;
863 if (definition->flags & _weapon_is_marathon_1)
864 {
865 trigger->sequence = 0;
866 }
867 }
868 }
869 break;
870
871 case _weapon_awaiting_reload:
872 /* enter the state where we wait to actually put the bullets in */
873 assert(definition->loading_ticks);
874 trigger->state= _weapon_waiting_to_load;
875 trigger->phase= definition->loading_ticks;
876 break;
877
878 case _weapon_lowering_for_twofisted_reload:
879 /* We are off the screen, and waiting for the other guy to finish loading */
880 trigger->state= _weapon_waiting_for_twofist_to_reload;
881 trigger->phase= definition->await_reload_ticks+definition->loading_ticks+
882 definition->finish_loading_ticks;
883 break;
884
885 case _weapon_awaiting_twofisted_reload:
886 /* The other guy is off the screen, we can load now.. */
887 if(definition->await_reload_ticks)
888 {
889 trigger->state= _weapon_awaiting_reload;
890 trigger->phase= definition->await_reload_ticks; // should this be by trigger?
891 } else {
892 trigger->state= _weapon_waiting_to_load;
893 trigger->phase= definition->loading_ticks; // should this be by trigger?
894 }
895 break;
896
897 case _weapon_waiting_for_twofist_to_reload:
898 /* Raise back up.. */
899 trigger->state= _weapon_raising;
900 trigger->phase= definition->ready_ticks;
901 break;
902
903 default:
904 vhalt(csprintf(temporary, "What the hell is state: %d?", trigger->state));
905 break;
906 }
907 }
908 }
909 }
910
911 /* If they didn't just finish switching weapons.. */
912 if(action_flags & _cycle_weapons_forward)
913 {
914 select_next_weapon(player_index, true);
915 }
916
917 /* Cycle the weapon backward */
918 if(action_flags & _cycle_weapons_backward)
919 {
920 select_next_weapon(player_index, false);
921 }
922
923 /* And switch the weapon.. */
924 idle_weapon(player_index);
925
926 // dprintf("done;g");
927 }
928
929 // START Benad
destroy_players_ball(short player_index)930 void destroy_players_ball(
931 short player_index)
932 {
933 if (film_profile.destroy_players_ball_fix && !player_has_valid_weapon(player_index))
934 return;
935
936 struct player_data *player= get_player_data(player_index);
937 short ball_color= find_player_ball_color(player_index);
938 struct weapon_data *weapon= get_player_current_weapon(player_index);
939 short item_type;
940
941 assert(ball_color!=NONE);
942 item_type= ball_color+BALL_ITEM_BASE;
943
944 /*
945 world_point3d origin, vector;
946 short origin_polygon;
947 calculate_weapon_origin_and_vector(player_index, _primary_weapon,
948 &origin, &vector, &origin_polygon, 0);
949
950 drop_the_ball(&origin, origin_polygon, player->monster_index,
951 _monster_marine, item_type);
952 */
953
954 weapon->triggers[0].rounds_loaded = 0;
955 weapon->triggers[1].rounds_loaded = 0;
956 weapon->weapon_type = _weapon_ball;
957 player->items[item_type]= NONE;
958 object_was_just_destroyed(_object_is_item, item_type);
959
960 //destroy_current_weapon(player_index);
961
962 mark_player_inventory_as_dirty(player_index, _i_knife);
963 select_next_best_weapon(player_index);
964
965 }
966 // END Benad
967
get_player_desired_weapon(short player_index)968 short get_player_desired_weapon(
969 short player_index)
970 {
971 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
972
973 return player_weapons->desired_weapon;
974 }
975
get_player_weapon_ammo_count(short player_index,short which_weapon,short which_trigger)976 short get_player_weapon_ammo_count(
977 short player_index,
978 short which_weapon,
979 short which_trigger)
980 {
981 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
982 struct weapon_definition *definition= get_weapon_definition(which_weapon);
983 short rounds_loaded;
984 struct player_data *player= get_player_data(player_index);
985
986 assert(which_weapon>=0 && which_weapon<short(NUMBER_OF_WEAPONS));
987 assert(which_trigger>=0 && which_trigger<NUMBER_OF_TRIGGERS);
988
989 switch(definition->weapon_class)
990 {
991 case _melee_class:
992 case _normal_class:
993 case _dual_function_class:
994 case _multipurpose_class:
995 rounds_loaded= player_weapons->weapons[which_weapon].triggers[which_trigger].rounds_loaded;
996 break;
997
998 case _twofisted_pistol_class:
999 if(player->items[definition->item_type]<=1 && which_trigger==_secondary_weapon)
1000 {
1001 rounds_loaded= NONE;
1002 } else {
1003 rounds_loaded= player_weapons->weapons[which_weapon].triggers[which_trigger].rounds_loaded;
1004 }
1005 break;
1006
1007 // LP change: no weapon
1008 case NONE:
1009 default:
1010 rounds_loaded = NONE;
1011 break;
1012 }
1013
1014 return rounds_loaded;
1015 }
1016
get_player_weapon_ammo_maximum(short player_index,short which_weapon,short which_trigger)1017 short get_player_weapon_ammo_maximum(
1018 short player_index,
1019 short which_weapon,
1020 short which_trigger)
1021 {
1022 struct trigger_definition *trigger_definition= get_trigger_definition(player_index,
1023 which_weapon, which_trigger);
1024
1025 assert(which_weapon>=0 && which_weapon<short(NUMBER_OF_WEAPONS));
1026 assert(which_trigger>=0 && which_trigger<NUMBER_OF_TRIGGERS);
1027
1028 return trigger_definition->rounds_per_magazine;
1029 }
1030
get_player_weapon_ammo_type(short player_index,short which_weapon,short which_trigger)1031 int16 get_player_weapon_ammo_type(
1032 short player_index,
1033 short which_weapon,
1034 short which_trigger)
1035 {
1036 struct trigger_definition *trigger_definition= get_trigger_definition(player_index,
1037 which_weapon, which_trigger);
1038
1039 assert(which_weapon>=0 && which_weapon<short(NUMBER_OF_WEAPONS));
1040 assert(which_trigger>=0 && which_trigger<NUMBER_OF_TRIGGERS);
1041
1042 return trigger_definition->ammunition_type;
1043 }
1044
get_player_weapon_drawn(short player_index,short which_weapon,short which_trigger)1045 bool get_player_weapon_drawn(
1046 short player_index,
1047 short which_weapon,
1048 short which_trigger)
1049 {
1050 struct player_weapon_data *pd = get_player_weapon_data(player_index);
1051 if (pd->current_weapon != which_weapon)
1052 return false;
1053
1054 return which_trigger == 0 ? PRIMARY_WEAPON_IS_VALID(&pd->weapons[which_weapon])
1055 : SECONDARY_WEAPON_IS_VALID(&pd->weapons[which_weapon]);
1056 }
1057
1058 #ifdef DEBUG
debug_print_weapon_status(void)1059 void debug_print_weapon_status(
1060 void)
1061 {
1062 struct player_weapon_data *player_weapons= get_player_weapon_data(current_player_index);
1063
1064 dprintf("Current: %d Desired: %d;g", player_weapons->current_weapon, player_weapons->desired_weapon);
1065 for(unsigned index= 0; index<NUMBER_OF_WEAPONS; ++index)
1066 {
1067 debug_weapon(index);
1068 }
1069 }
1070
debug_weapon(short index)1071 static void debug_weapon(
1072 short index)
1073 {
1074 struct player_weapon_data *player_weapons= get_player_weapon_data(current_player_index);
1075
1076 dprintf("Weapon: %d;g", index);
1077 dprintf("weapon_type: %d flags: %d unused: %d;g", player_weapons->weapons[index].weapon_type,
1078 player_weapons->weapons[index].flags, player_weapons->weapons[index].unused);
1079
1080 debug_trigger_data(index, _primary_weapon);
1081
1082 switch(index)
1083 {
1084 case _weapon_missile_launcher:
1085 case _weapon_flamethrower:
1086 case _weapon_alien_shotgun:
1087 break;
1088
1089 default:
1090 debug_trigger_data(index, _secondary_weapon);
1091 break;
1092 }
1093 }
1094
debug_trigger_data(short weapon_type,short which_trigger)1095 static void debug_trigger_data(
1096 short weapon_type,
1097 short which_trigger)
1098 {
1099 struct player_weapon_data *player_weapons= get_player_weapon_data(current_player_index);
1100 struct trigger_data *trigger;
1101 struct trigger_definition *trigger_definition;
1102 struct weapon_definition *weapon_definition= get_weapon_definition(weapon_type);
1103
1104 trigger= &player_weapons->weapons[weapon_type].triggers[which_trigger];
1105
1106 dprintf("%d) State: %d Phase: %d;g", which_trigger, trigger->state, trigger->phase);
1107 dprintf("%d) Loaded: %d Shot: %d Hit: %d;g", which_trigger, trigger->rounds_loaded,
1108 trigger->shots_fired, trigger->shots_hit);
1109 dprintf("%d) Ticks Since Last: %d;g", which_trigger, trigger->ticks_since_last_shot);
1110
1111 trigger_definition= get_trigger_definition(current_player_index,
1112 weapon_type, which_trigger);
1113
1114 if(weapon_definition->item_type != NONE)
1115 {
1116 dprintf("%d) Has %d items;g", which_trigger,
1117 current_player->items[weapon_definition->item_type]);
1118 } else {
1119 dprintf("%d) Item type is NONE;g", which_trigger);
1120 }
1121
1122 if(trigger_definition->ammunition_type != NONE)
1123 {
1124 dprintf("%d) Player has %d clips;g", which_trigger,
1125 current_player->items[trigger_definition->ammunition_type]);
1126 } else {
1127 dprintf("%d) Ammunition type is NONE;g", which_trigger);
1128 }
1129 }
1130 #endif
1131
get_weapon_array(void)1132 void *get_weapon_array(
1133 void)
1134 {
1135 return player_weapons_array;
1136 }
1137
calculate_weapon_array_length(void)1138 int32 calculate_weapon_array_length(
1139 void)
1140 {
1141 return dynamic_world->player_count*sizeof(struct player_weapon_data);
1142 }
1143
1144 /* -------------------------- functions related to rendering */
1145 /* Functions related to rendering! */
1146 /* while this returns true, keep calling.. */
get_weapon_display_information(short * count,struct weapon_display_information * data)1147 bool get_weapon_display_information(
1148 short *count,
1149 struct weapon_display_information *data)
1150 {
1151 bool valid= false;
1152 short player_index= current_player_index;
1153
1154 /* If the player's current weapon is not NONE.. */
1155 if(player_has_valid_weapon(player_index))
1156 {
1157 struct weapon_data *weapon= get_player_current_weapon(player_index);
1158 struct weapon_definition *definition= get_weapon_definition(weapon->weapon_type);
1159 _fixed width, height;
1160 short frame, which_trigger, shape_index, type, flags;
1161 struct shape_animation_data *high_level_data;
1162
1163 /* Get the default width and height */
1164 width= definition->idle_width;
1165 height= definition->idle_height;
1166 modify_position_for_two_weapons(player_index, *count, &width, &height);
1167
1168 /* What type of item is this? */
1169 if(get_weapon_data_type_for_count(player_index, *count, &type, &which_trigger, &flags))
1170 {
1171 struct shape_and_transfer_mode owner_transfer_data;
1172
1173 /* Assume the best.. */
1174 valid= true;
1175
1176 if(type==_weapon_type || type==_weapon_ammo_type)
1177 {
1178 short phase;
1179
1180 /* Tell the weapon a frame passed, in case it cares. */
1181 phase= weapon->triggers[which_trigger].phase;
1182
1183 /* Calculate the base location.. */
1184 if (definition->flags & _weapon_is_marathon_1) {
1185 // only add in bob height if we're firing
1186 if (weapon->triggers[which_trigger].state == _weapon_idle && !automatic_still_firing(player_index, which_trigger)) {
1187 calculate_weapon_position_for_idle(player_index, which_trigger, weapon->weapon_type, &height, &width, false);
1188 }
1189 }
1190 else
1191 {
1192 calculate_weapon_position_for_idle(player_index, which_trigger, weapon->weapon_type, &height, &width, true);
1193 }
1194
1195 /* Figure out where to draw it. */
1196 switch(weapon->triggers[which_trigger].state)
1197 {
1198 case _weapon_lowering:
1199 assert(definition->ready_ticks);
1200 height = (3*FIXED_ONE/2)-(((3*FIXED_ONE/2)-definition->idle_height)*phase)/definition->ready_ticks;
1201 shape_index= definition->idle_shape;
1202 break;
1203
1204 case _weapon_raising:
1205 assert(definition->ready_ticks);
1206 height += (((3*FIXED_ONE/2)-definition->idle_height)*phase)/definition->ready_ticks;
1207 shape_index= definition->idle_shape;
1208 break;
1209
1210 case _weapon_charged:
1211 if(definition->flags & _weapon_overloads)
1212 {
1213 _fixed flutter_base;
1214
1215 /* 0-> FIXED ONE as it gets closer to nova.. */
1216 flutter_base= (FIXED_ONE*(CHARGED_WEAPON_OVERLOAD-phase))/CHARGED_WEAPON_OVERLOAD;
1217 add_random_flutter(flutter_base, &height, &width);
1218 } else {
1219 /* Calculate for idle, and then make it bounce */
1220 add_random_flutter(FIXED_ONE, &height, &width);
1221 }
1222
1223 /* This is a fully charged weapon.. */
1224 if(definition->charged_shape != NONE)
1225 {
1226 shape_index= definition->charged_shape;
1227 } else {
1228 shape_index= definition->idle_shape;
1229 }
1230 break;
1231
1232 case _weapon_charging:
1233 /* This is a fully charged weapon.. */
1234 if(definition->charging_shape != NONE)
1235 {
1236 shape_index= definition->charging_shape;
1237 } else {
1238 shape_index= definition->idle_shape;
1239 }
1240 break;
1241
1242 case _weapon_waiting_for_twofist_to_reload:
1243 /* Get it off the screen.. */
1244 height= 4*FIXED_ONE;
1245 shape_index= definition->idle_shape;
1246 break;
1247
1248 case _weapon_awaiting_twofisted_reload:
1249 case _weapon_waiting_for_other_idle_to_reload:
1250 shape_index= definition->idle_shape;
1251 break;
1252
1253 case _weapon_idle:
1254 if(definition->flags & _weapon_is_automatic)
1255 {
1256 if(which_trigger==_primary_weapon ||
1257 (which_trigger==_secondary_weapon && (definition->flags & _weapon_secondary_has_angular_flipping)))
1258 {
1259 if(automatic_still_firing(current_player_index, which_trigger))
1260 {
1261 shape_index= definition->firing_shape;
1262 if (definition->flags & _weapon_flutters_while_firing)
1263 {
1264 add_random_flutter(FIXED_ONE, &height, &width);
1265 }
1266 } else {
1267 shape_index= definition->idle_shape;
1268 // Now handled in UpdateIdleWeapons()
1269 // weapon->triggers[which_trigger].sequence= 0;
1270 }
1271 } else {
1272 shape_index= definition->idle_shape;
1273 }
1274 } else {
1275 shape_index= definition->idle_shape;
1276 }
1277 break;
1278
1279 case _weapon_sliding_over_to_second_position:
1280 if(definition->weapon_class==_twofisted_pistol_class)
1281 {
1282 if(which_trigger==_primary_weapon)
1283 {
1284 width-= ((weapon->triggers[which_trigger].phase)
1285 *(PISTOL_SEPARATION_WIDTH/2))/definition->ready_ticks;
1286 } else {
1287 width+= ((weapon->triggers[which_trigger].phase)
1288 *(PISTOL_SEPARATION_WIDTH/2))/definition->ready_ticks;
1289 }
1290 } else {
1291 /* Melee weapons stay where they were. */
1292 }
1293 shape_index= definition->idle_shape;
1294 break;
1295
1296 case _weapon_sliding_over_from_second_position:
1297 if(definition->weapon_class==_twofisted_pistol_class)
1298 {
1299 short sign;
1300
1301 if(which_trigger==_primary_weapon)
1302 {
1303 sign= -1;
1304 } else {
1305 sign= 1;
1306 }
1307 width+= sign*((definition->ready_ticks-weapon->triggers[which_trigger].phase)*(PISTOL_SEPARATION_WIDTH/2))/
1308 definition->ready_ticks;
1309 } else {
1310 /* Melee weapons stay where they were. */
1311 }
1312 shape_index= definition->idle_shape;
1313 break;
1314
1315 case _weapon_firing:
1316 /* We are going up.. */
1317 {
1318 struct trigger_definition *trigger_definition;
1319
1320 trigger_definition= get_player_trigger_definition(player_index, which_trigger);
1321 height -= (definition->kick_height*(trigger_definition->ticks_per_round-phase))/trigger_definition->ticks_per_round;
1322 shape_index= definition->firing_shape;
1323 if (definition->flags & _weapon_flutters_while_firing)
1324 {
1325 add_random_flutter(FIXED_ONE, &height, &width);
1326 }
1327 }
1328 break;
1329
1330 case _weapon_recovering:
1331 /* Going back down.. */
1332 {
1333 struct trigger_definition *trigger_definition= get_player_trigger_definition(player_index, which_trigger);
1334 assert(trigger_definition->recovery_ticks);
1335 height-= (definition->kick_height*phase)/trigger_definition->recovery_ticks;
1336 if (definition->flags & _weapon_is_marathon_1)
1337 {
1338 shape_index = definition->idle_shape;
1339 }
1340 else
1341 {
1342 shape_index= definition->firing_shape;
1343 }
1344 }
1345 break;
1346
1347 case _weapon_awaiting_reload:
1348 if(definition->reloading_shape==NONE)
1349 {
1350 assert(definition->await_reload_ticks);
1351 height+= (((3*FIXED_ONE/2)-definition->idle_height)*(definition->await_reload_ticks-phase))/definition->await_reload_ticks;
1352 shape_index= definition->idle_shape;
1353 } else {
1354 height= definition->reload_height;
1355 shape_index= definition->reloading_shape;
1356 }
1357 break;
1358
1359 case _weapon_waiting_to_load:
1360 if(definition->reloading_shape==NONE)
1361 {
1362 /* Consider it offscreen */
1363 valid= false;
1364 shape_index= definition->idle_shape;
1365 } else {
1366 height= definition->reload_height;
1367 shape_index= definition->reloading_shape;
1368 }
1369 break;
1370
1371 case _weapon_finishing_reload:
1372 if(definition->reloading_shape==NONE)
1373 {
1374 assert(definition->finish_loading_ticks);
1375 height+= (((3*FIXED_ONE/2)-definition->idle_height)*phase)/definition->finish_loading_ticks;
1376
1377 shape_index= definition->idle_shape;
1378 } else {
1379 height= definition->reload_height;
1380 shape_index= definition->reloading_shape;
1381 }
1382 break;
1383
1384 case _weapon_lowering_for_twofisted_reload:
1385 assert(definition->ready_ticks);
1386 height = (3*FIXED_ONE/2)-(((3*FIXED_ONE/2)-definition->idle_height)*phase)/definition->ready_ticks;
1387 shape_index= definition->idle_shape;
1388 break;
1389
1390 default:
1391 assert(false);
1392 break;
1393 }
1394
1395 /* Determine our frame. */
1396 if (type==_weapon_ammo_type)
1397 {
1398 // hardcoded for Marathon 1 rocket launcher
1399 shape_index = M1_MISSILE_AMMO_SEQUENCE;
1400 frame = weapon->triggers[which_trigger].rounds_loaded - 1;
1401 }
1402 else
1403 frame= GET_SEQUENCE_FRAME(weapon->triggers[which_trigger].sequence);
1404
1405 if (type==_weapon_type)
1406 {
1407 /* Go to the next frame for automatics.. */
1408 update_automatic_sequence(current_player_index, which_trigger);
1409
1410 // Also for idle weapons
1411 UpdateIdleAnimation(current_player_index, which_trigger);
1412 }
1413
1414 /* setup the positioning information */
1415 high_level_data= get_shape_animation_data(BUILD_DESCRIPTOR(definition->collection,
1416 shape_index));
1417
1418 // LP: bug out if there is no weapon sequence to render
1419 if (!high_level_data) return false;
1420 if (!(frame>=0 && frame<high_level_data->frames_per_view))
1421 return false;
1422
1423 data->collection= BUILD_COLLECTION(definition->collection, 0);
1424 data->shape_index = shape_index;
1425 data->low_level_shape_index= high_level_data->low_level_shape_indexes[frame];
1426 data->vertical_positioning_mode= _position_center;
1427 data->horizontal_positioning_mode= _position_center;
1428 data->vertical_position= height;
1429 data->horizontal_position= width;
1430 if(flags & _flip_shape_vertical)
1431 {
1432 data->flip_vertical= true;
1433 } else {
1434 data->flip_vertical= false;
1435 }
1436
1437 if(flags & _flip_shape_horizontal)
1438 {
1439 data->flip_horizontal= true;
1440 } else {
1441 data->flip_horizontal= false;
1442 }
1443
1444 if (type==_weapon_ammo_type)
1445 {
1446 // hardcoded for Marathon 1 rocket launcher
1447 data->vertical_position += M1_MISSILE_AMMO_YOFFSET;
1448 data->horizontal_position += M1_MISSILE_AMMO_XOFFSET;
1449 }
1450
1451 /* Fill in the transfer mode and phase */
1452 /* Cached, so that we only do it the first time through.. */
1453 if(!(*count))
1454 {
1455 struct player_data *player= get_player_data(player_index);
1456
1457 get_object_shape_and_transfer_mode(&player->camera_location, player->object_index,
1458 &owner_transfer_data);
1459 // Bug out in case of nonexistent shape
1460 if (owner_transfer_data.collection_code == NONE) return false;
1461
1462 data->transfer_mode= owner_transfer_data.transfer_mode;
1463 data->transfer_phase= owner_transfer_data.transfer_phase;
1464
1465 // LP: model animation data
1466 data->Frame = owner_transfer_data.Frame;
1467 data->NextFrame = owner_transfer_data.NextFrame;
1468 data->Phase = owner_transfer_data.Phase;
1469 data->Ticks = owner_transfer_data.Ticks;
1470 }
1471 }
1472 else if(type==_shell_casing_type)
1473 {
1474 get_shell_casing_display_data(data, which_trigger);
1475 } else {
1476 assert(false);
1477 }
1478 }
1479
1480 (*count)++;
1481 }
1482
1483 return valid;
1484 }
1485
get_player_weapon_mode_and_type(short player_index,short * shape_weapon_type,short * shape_mode)1486 void get_player_weapon_mode_and_type(
1487 short player_index,
1488 short *shape_weapon_type,
1489 short *shape_mode)
1490 {
1491
1492 if(player_has_valid_weapon(player_index))
1493 {
1494 struct weapon_definition *definition= get_current_weapon_definition(player_index);
1495 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
1496 struct weapon_data *weapon_data= get_player_current_weapon(player_index);
1497 short which_trigger, mode;
1498 short first_trigger, trigger_count;
1499
1500 *shape_weapon_type= player_weapons->current_weapon;
1501
1502 /* If we are a twofisted pistol, and both are up */
1503 if(definition->weapon_class==_twofisted_pistol_class && PRIMARY_WEAPON_IS_VALID(weapon_data) && SECONDARY_WEAPON_IS_VALID(weapon_data))
1504 {
1505 switch(player_weapons->current_weapon)
1506 {
1507 case _weapon_shotgun:
1508 *shape_weapon_type= _weapon_doublefisted_shotguns;
1509 break;
1510
1511 case _weapon_pistol:
1512 default:
1513 *shape_weapon_type= _weapon_doublefisted_pistols;
1514 break;
1515 }
1516 }
1517
1518 mode= NONE;
1519
1520 trigger_count= get_active_trigger_count_and_states(player_index, player_weapons->current_weapon, 0l, &first_trigger, NULL);
1521 for(which_trigger= first_trigger; which_trigger<trigger_count; ++which_trigger)
1522 {
1523 struct trigger_data *trigger= get_player_trigger_data(player_index, which_trigger);
1524
1525 switch (trigger->state)
1526 {
1527 case _weapon_idle:
1528 if(automatic_still_firing(player_index, which_trigger))
1529 {
1530 mode= MAX(mode, _shape_weapon_firing);
1531 } else {
1532 mode= MAX(mode, _shape_weapon_idle);
1533 }
1534 break;
1535
1536 case _weapon_raising:
1537 case _weapon_lowering:
1538 case _weapon_awaiting_reload:
1539 case _weapon_waiting_to_load:
1540 case _weapon_finishing_reload:
1541 case _weapon_sliding_over_to_second_position:
1542 case _weapon_sliding_over_from_second_position:
1543 case _weapon_lowering_for_twofisted_reload:
1544 case _weapon_awaiting_twofisted_reload:
1545 case _weapon_waiting_for_twofist_to_reload:
1546 case _weapon_waiting_for_other_idle_to_reload:
1547 mode= MAX(mode, _shape_weapon_idle);
1548 break;
1549
1550 case _weapon_charging:
1551 case _weapon_charged:
1552 mode= MAX(_shape_weapon_charging, mode);
1553 break;
1554
1555 case _weapon_firing:
1556 case _weapon_recovering:
1557 mode= MAX(_shape_weapon_firing, mode);
1558 break;
1559
1560 default:
1561 assert(false);
1562 break;
1563 }
1564 }
1565
1566 // LP change: suppressed error checking
1567 if (mode == NONE) mode = _shape_weapon_idle;
1568 *shape_mode= mode;
1569 } else {
1570 /* No weapon.. */
1571 *shape_mode= _shape_weapon_idle;
1572 *shape_weapon_type= _weapon_fist;
1573 }
1574 }
1575
1576 /* -------- general static code */
reset_trigger_data(short player_index,short weapon_type,short which_trigger)1577 static void reset_trigger_data(
1578 short player_index,
1579 short weapon_type,
1580 short which_trigger)
1581 {
1582 struct trigger_data *trigger= get_trigger_data(player_index, weapon_type, which_trigger);
1583
1584 trigger->state= _weapon_idle;
1585 trigger->phase= 0;
1586 trigger->rounds_loaded= 0;
1587 /* Note that trigger->shots_fired, and trigger->shots_hit are not reset (for total carnage graphs) */
1588 trigger->ticks_since_last_shot= 0;
1589 trigger->ticks_firing= 0;
1590 trigger->sequence= 0;
1591 }
1592
weapon_works_in_current_environment(short weapon_index)1593 static bool weapon_works_in_current_environment(
1594 short weapon_index)
1595 {
1596 bool weapon_works= true;
1597
1598 if(weapon_index!=NONE)
1599 {
1600 struct weapon_definition *definition= get_weapon_definition(weapon_index);
1601 weapon_works= item_valid_in_current_environment(definition->item_type);
1602 }
1603
1604 return weapon_works;
1605 }
1606
1607 /* This selects the next best weapon */
select_next_best_weapon(short player_index)1608 /*static*/ void select_next_best_weapon(
1609 short player_index)
1610 {
1611 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
1612 int index, current_weapon_index;
1613
1614 /* Find where we are in the array. */
1615 current_weapon_index= find_weapon_power_index(player_weapons->current_weapon);
1616
1617 /* Find the next weapon that the player has. */
1618 for(index=current_weapon_index+1; index<NUMBER_OF_WEAPONS; ++index)
1619 {
1620 if(ready_weapon(player_index, weapon_ordering_array[index])) break;
1621 }
1622
1623 if(index==NUMBER_OF_WEAPONS)
1624 {
1625 /* Try going down.. */
1626 for(index= current_weapon_index-1; index>=0; index--)
1627 {
1628 if(ready_weapon(player_index, weapon_ordering_array[index])) break;
1629 }
1630 }
1631
1632 /* if we didn't change, we punt */
1633 }
1634
select_next_weapon(short player_index,bool forward)1635 static void select_next_weapon(
1636 short player_index,
1637 bool forward)
1638 {
1639 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
1640
1641 if(player_weapons->desired_weapon!=_weapon_ball && player_weapons->current_weapon!=_weapon_ball)
1642 {
1643 short desired_weapon_index;
1644
1645 desired_weapon_index= find_weapon_power_index(player_weapons->desired_weapon);
1646
1647 /* This starts at one because we are trying to go forward or backward.. */
1648 for(unsigned index=1; index<NUMBER_OF_WEAPONS; ++index)
1649 {
1650 short test_weapon_index;
1651
1652 if(forward)
1653 {
1654 test_weapon_index= (index+desired_weapon_index)%NUMBER_OF_WEAPONS;
1655 } else {
1656 test_weapon_index= (desired_weapon_index-index+NUMBER_OF_WEAPONS)%NUMBER_OF_WEAPONS;
1657 }
1658
1659 if(ready_weapon(player_index, weapon_ordering_array[test_weapon_index])) break;
1660 }
1661 }
1662 }
1663
get_player_trigger_definition(short player_index,short which_trigger)1664 static struct trigger_definition *get_player_trigger_definition(
1665 short player_index,
1666 short which_trigger)
1667 {
1668 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
1669 return get_trigger_definition(player_index, player_weapons->current_weapon, which_trigger);
1670 }
1671
get_trigger_definition(short player_index,short which_weapon,short which_trigger)1672 static struct trigger_definition *get_trigger_definition(
1673 short player_index,
1674 short which_weapon,
1675 short which_trigger)
1676 {
1677 struct weapon_definition *definition= get_weapon_definition(which_weapon);
1678 struct trigger_definition *trigger_definition;
1679
1680 assert(which_trigger>=0 && which_trigger<NUMBER_OF_TRIGGERS);
1681 assert(which_weapon>=0 && which_weapon<short(NUMBER_OF_WEAPONS));
1682
1683 trigger_definition= &definition->weapons_by_trigger[which_trigger];
1684
1685 return trigger_definition;
1686 }
1687
get_player_trigger_data(short player_index,short which_trigger)1688 static struct trigger_data *get_player_trigger_data(
1689 short player_index,
1690 short which_trigger)
1691 {
1692 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
1693
1694 assert(player_weapons->current_weapon>=0 && player_weapons->current_weapon<short(NUMBER_OF_WEAPONS));
1695
1696 return get_trigger_data(player_index, player_weapons->current_weapon, which_trigger);
1697 }
1698
get_trigger_data(short player_index,short weapon_index,short which_trigger)1699 struct trigger_data *get_trigger_data(
1700 short player_index,
1701 short weapon_index,
1702 short which_trigger)
1703 {
1704 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
1705
1706 assert(which_trigger>=0 && which_trigger<NUMBER_OF_TRIGGERS);
1707 assert(weapon_index>=0 && weapon_index<short(NUMBER_OF_WEAPONS));
1708
1709 return &player_weapons->weapons[weapon_index].triggers[which_trigger];
1710 }
1711
get_player_current_weapon(short player_index)1712 static struct weapon_data *get_player_current_weapon(
1713 short player_index)
1714 {
1715 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
1716
1717 assert(player_weapons->current_weapon>=0 && player_weapons->current_weapon<short(NUMBER_OF_WEAPONS));
1718
1719 return &player_weapons->weapons[player_weapons->current_weapon];
1720 }
1721
1722 /*
1723 This function does the following:
1724 1) Calculates how many shots to fire.
1725 2) creates all of the projectiles,
1726 3) handles recoil
1727 4) plays sounds
1728 5) updates shots fired/rounds loaded
1729 */
fire_weapon(short player_index,short which_trigger,_fixed charged_amount,bool flail_wildly)1730 static void fire_weapon(
1731 short player_index,
1732 short which_trigger,
1733 _fixed charged_amount,
1734 bool flail_wildly)
1735 {
1736 struct player_data *player= get_player_data(player_index);
1737 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
1738 struct weapon_definition *definition= get_weapon_definition(player_weapons->current_weapon);
1739 struct trigger_definition *trigger_definition;
1740 struct trigger_data *trigger;
1741 world_point3d origin, _vector;
1742 short origin_polygon, flailing_bonus, rounds_to_fire;
1743 _fixed damage_modifier;
1744
1745 /* if they are under water, and it isn't a melee weapon, they lose */
1746 if ((player->variables.flags&_HEAD_BELOW_MEDIA_BIT) && !(definition->flags&_weapon_fires_under_media))
1747 {
1748 play_weapon_sound(player_index, WEAPON_SHORTED_SOUND, FIXED_ONE);
1749 return;
1750 }
1751
1752 /* Delta theta.. */
1753 flailing_bonus= flail_wildly ? 30 : 0;
1754
1755 /* Get the weapon they are using... */
1756 trigger_definition= get_player_trigger_definition(player_index, which_trigger);
1757 trigger= get_player_trigger_data(player_index, which_trigger);
1758
1759 /* Calculate the number of rounds to fire.. */
1760 if(trigger_definition->burst_count)
1761 {
1762 if(trigger_definition->charging_ticks)
1763 {
1764 rounds_to_fire= (short)((trigger_definition->burst_count*charged_amount)/FIXED_ONE);
1765 } else {
1766 /* Non charging weapon.. */
1767 rounds_to_fire= trigger_definition->burst_count;
1768 }
1769 } else {
1770 rounds_to_fire= 1;
1771 }
1772
1773 /* I hear you.. */
1774 if(definition->weapon_class != _melee_class)
1775 {
1776 int32 range = -1;
1777 if (static_world->environment_flags & _environment_activation_ranges)
1778 range = trigger_definition->sound_activation_range * WORLD_ONE;
1779
1780 if(which_trigger==_primary_weapon && (definition->flags & _weapon_is_automatic) && trigger->ticks_firing<2)
1781 {
1782 activate_nearby_monsters(player->monster_index, player->monster_index,
1783 _pass_one_zone_border|_activate_invisible_monsters, range);
1784 } else {
1785 activate_nearby_monsters(player->monster_index, player->monster_index,
1786 _pass_one_zone_border|_activate_invisible_monsters, range);
1787 }
1788 }
1789
1790 /* If we have any rounds of ammunition */
1791 if(trigger->rounds_loaded>0)
1792 {
1793 angle delta_theta= 0;
1794
1795 /* Handle the second trigger of the alien weapon.. */
1796 if(which_trigger==_secondary_weapon && (definition->flags & _weapon_secondary_has_angular_flipping))
1797 {
1798 struct weapon_data *weapon= get_player_current_weapon(player_index);
1799
1800 delta_theta= ANGULAR_VARIANCE*GET_WEAPON_VARIANCE_SIGN(weapon);
1801 FLIP_WEAPON_VARIANCE_SIGN(weapon);
1802 }
1803
1804 /* Note that we no longer pin the rounds to fire by the amount in the gun.. */
1805 if(rounds_to_fire>trigger->rounds_loaded)
1806 {
1807 rounds_to_fire= trigger->rounds_loaded;
1808 }
1809
1810 /* Spawn the projectile. I can't update the shots_hit until it actually hits the */
1811 /* target, which comes in update */
1812 calculate_weapon_origin_and_vector(player_index, which_trigger,
1813 &origin, &_vector, &origin_polygon, delta_theta);
1814
1815 /* If it is a melee weapon, add in the damage based on their speed.. */
1816 if(definition->weapon_class==_melee_class)
1817 {
1818 /* Damage is in range of [FIXED_ONE/8, FIXED_ONE] */
1819 /* Therefore melee damage should be pretty high. */
1820 damage_modifier= get_player_forward_velocity_scale(player_index);
1821 damage_modifier= MAX(damage_modifier, FIXED_ONE/8);
1822 } else {
1823 damage_modifier= FIXED_ONE;
1824 }
1825
1826 while(rounds_to_fire--)
1827 {
1828 /* Increment rounds fired count */
1829 player_weapons->weapons[player_weapons->current_weapon].triggers[which_trigger].shots_fired++;
1830 player_weapons->weapons[player_weapons->current_weapon].triggers[which_trigger].rounds_loaded--;
1831
1832 /* Update the player ammunition count */
1833 update_player_ammo_count(player_index);
1834
1835 /* on certain weapons, keep the weapon ammo pools synced.... */
1836 if(definition->flags & _weapon_triggers_share_ammo)
1837 {
1838 player_weapons->weapons[player_weapons->current_weapon].triggers[!which_trigger].rounds_loaded--;
1839 }
1840
1841 /* on dual function classes, keep the two ammo pools synched.. */
1842 if(definition->weapon_class==_dual_function_class)
1843 {
1844 /* Dual function class, charging weapons use 4x the ammo. */
1845 if(which_trigger==_secondary_weapon && trigger_definition->charging_ticks)
1846 {
1847 short rounds_count;
1848
1849 rounds_count= MIN(COST_PER_CHARGED_WEAPON_SHOT-1, player_weapons->weapons[player_weapons->current_weapon].triggers[which_trigger].rounds_loaded);
1850
1851 /* Decrement the ammo.. */
1852 player_weapons->weapons[player_weapons->current_weapon].triggers[which_trigger].rounds_loaded-= rounds_count;
1853
1854 /* Decrement the other ammo as well.. */
1855 if(definition->flags & _weapon_triggers_share_ammo)
1856 {
1857 player_weapons->weapons[player_weapons->current_weapon].triggers[!which_trigger].rounds_loaded-= rounds_count;
1858 }
1859 }
1860 }
1861
1862 /* Fire the projectile */
1863 // Added modification of guided-projectile patch from AlexJLS@aol.com;
1864 // avoid doing search for targets for an unguided projectile.
1865 if(trigger_definition->projectile_type!=_projectile_ball_dropped)
1866 {
1867 short Target = player_settings.PlayerShotsGuided ?
1868 (ProjectileIsGuided(trigger_definition->projectile_type) ?
1869 find_closest_appropriate_target(player->monster_index,false) :
1870 NONE) : NONE;
1871 new_projectile(&origin, origin_polygon, &_vector,
1872 trigger_definition->theta_error+flailing_bonus,
1873 trigger_definition->projectile_type,
1874 player->monster_index, _monster_marine, Target, damage_modifier);
1875 // player->monster_index, _monster_marine, NONE, damage_modifier);
1876 }
1877 }
1878
1879 /* Spawn a shell casing.... */
1880 if (trigger_definition->shell_casing_type!=NONE)
1881 {
1882 short type= trigger_definition->shell_casing_type;
1883 uint16 flags= 0;
1884
1885 if (type==_shell_casing_pistol)
1886 {
1887 struct weapon_data *weapon= get_player_current_weapon(player_index);
1888
1889 if (SECONDARY_WEAPON_IS_VALID(weapon))
1890 {
1891 if (PRIMARY_WEAPON_IS_VALID(weapon))
1892 {
1893 type= which_trigger ? _shell_casing_pistol_left : _shell_casing_pistol_right;
1894 }
1895 else
1896 {
1897 flags|= _shell_casing_is_reversed;
1898 }
1899 }
1900 }
1901
1902 new_shell_casing(player_index, type, flags);
1903 }
1904
1905 /* setup the weapon phase.. */
1906 trigger->state= _weapon_firing;
1907 trigger->phase= trigger_definition->ticks_per_round;
1908 trigger->ticks_since_last_shot= 0;
1909
1910 /* Setup the decay.. */
1911 player->weapon_intensity_decay= definition->firing_intensity_decay_ticks;
1912
1913 /* Blam */
1914 play_weapon_sound(player_index, trigger_definition->firing_sound, FIXED_ONE);
1915
1916 /* Push them back.. */
1917 if(trigger_definition->recoil_magnitude)
1918 {
1919 accelerate_monster(player->monster_index,
1920 -(trigger_definition->recoil_magnitude*sine_table[player->elevation])>>TRIG_SHIFT,
1921 NORMALIZE_ANGLE(player->facing+HALF_CIRCLE),
1922 (trigger_definition->recoil_magnitude*cosine_table[player->elevation])>>TRIG_SHIFT);
1923 }
1924 } else {
1925 /* uh oh, no bullets. */
1926 while(rounds_to_fire--)
1927 {
1928 play_weapon_sound(player_index, trigger_definition->click_sound, FIXED_ONE);
1929 }
1930 }
1931 }
1932
get_current_weapon_definition(short player_index)1933 struct weapon_definition *get_current_weapon_definition(
1934 short player_index)
1935 {
1936 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
1937
1938 assert(player_weapons->current_weapon>=0 && player_weapons->current_weapon<short(NUMBER_OF_WEAPONS));
1939
1940 return get_weapon_definition(player_weapons->current_weapon);
1941 }
1942
calculate_weapon_origin_and_vector(short player_index,short which_trigger,world_point3d * origin,world_point3d * _vector,short * origin_polygon,angle delta_theta)1943 static void calculate_weapon_origin_and_vector(
1944 short player_index,
1945 short which_trigger,
1946 world_point3d *origin,
1947 world_point3d *_vector,
1948 short *origin_polygon,
1949 angle delta_theta)
1950 {
1951 struct player_data *player= get_player_data(player_index);
1952 struct object_data *object= get_object_data(player->object_index);
1953 struct trigger_definition *trigger_definition;
1954 struct weapon_definition *definition= get_current_weapon_definition(player_index);
1955 struct weapon_data *weapon_data= get_player_current_weapon(player_index);
1956 short dx_translation_amount;
1957 world_point3d destination;
1958 angle projectile_facing;
1959
1960 trigger_definition= get_player_trigger_definition(player_index, which_trigger);
1961
1962 *origin= player->camera_location;
1963 origin->z += trigger_definition->dz;
1964
1965 /* Translate the projectile out to the end of the gun barrel.. */
1966 translate_point3d(origin, WEAPON_FORWARD_DISPLACEMENT,
1967 player->facing, player->elevation);
1968
1969 /* Do left/right translation */
1970 /* if it is twofisted, and both weapons aren't up, don't translate.. */
1971 /* JM: Bungie originally had precedence wrong, but it didn't matter in practice */
1972 if(definition->weapon_class==_twofisted_pistol_class &&
1973 ((PRIMARY_WEAPON_IS_VALID(weapon_data) && !SECONDARY_WEAPON_IS_VALID(weapon_data)) ||
1974 (!PRIMARY_WEAPON_IS_VALID(weapon_data) && SECONDARY_WEAPON_IS_VALID(weapon_data))))
1975 {
1976 dx_translation_amount= 0;
1977 } else {
1978 dx_translation_amount= trigger_definition->dx;
1979 }
1980
1981 /* Handle the left/right translation */
1982 translate_point2d((world_point2d *) origin, dx_translation_amount,
1983 NORMALIZE_ANGLE(player->facing+QUARTER_CIRCLE));
1984
1985 /* Get a second point to build up a vector.. */
1986 destination= *origin;
1987 projectile_facing= NORMALIZE_ANGLE(player->facing+delta_theta);
1988 translate_point3d(&destination, WORLD_ONE_HALF,
1989 projectile_facing, player->elevation);
1990
1991 /* And create the vector.. */
1992 _vector->x= destination.x-origin->x;
1993 _vector->y= destination.y-origin->y;
1994 _vector->z= destination.z-origin->z;
1995
1996 /* Now calculate the origin polygon index */
1997 *origin_polygon= find_new_object_polygon((world_point2d *) &player->location,
1998 (world_point2d *)origin, object->polygon);
1999
2000 /* They blew the pooch- this is expensive, therefore let's hope it doesn't happen often */
2001 if(*origin_polygon==NONE)
2002 {
2003 short source_polygon= object->polygon;
2004 short line_crossed = NONE;
2005 struct line_data *line;
2006 world_distance distance;
2007
2008 while(source_polygon != NONE)
2009 {
2010 line_crossed= find_line_crossed_leaving_polygon(source_polygon, (world_point2d *)
2011 &player->location, (world_point2d *) origin);
2012 source_polygon= find_adjacent_polygon(source_polygon, line_crossed);
2013 }
2014
2015 line= get_line_data(line_crossed);
2016 find_line_intersection(&get_endpoint_data(line->endpoint_indexes[0])->vertex,
2017 &get_endpoint_data(line->endpoint_indexes[1])->vertex,
2018 &player->location, origin, origin);
2019
2020 /* Now guess the distance.. */
2021 distance= distance2d((world_point2d *)&player->location, (world_point2d *) origin);
2022 distance-= 50; /* Fudge factor */
2023
2024 *origin= player->location;
2025 translate_point2d((world_point2d *) origin, distance,
2026 NORMALIZE_ANGLE(player->facing+QUARTER_CIRCLE));
2027
2028 *origin_polygon= find_new_object_polygon((world_point2d *) &player->location,
2029 (world_point2d *)origin, object->polygon);
2030 assert(*origin_polygon != NONE);
2031 }
2032 }
2033
reload_weapon(short player_index,short which_trigger)2034 static bool reload_weapon(
2035 short player_index,
2036 short which_trigger)
2037 {
2038 struct trigger_data *trigger= get_player_trigger_data(player_index, which_trigger);
2039 struct trigger_definition *trigger_definition=
2040 get_player_trigger_definition(player_index, which_trigger);
2041 struct player_data *player= get_player_data(player_index);
2042 struct weapon_definition *definition= get_current_weapon_definition(player_index);
2043 bool can_reload;
2044
2045 // LP change: bugging out if these cannot be done
2046 if (!(trigger->state==_weapon_idle && trigger->rounds_loaded==0)) return false;
2047 if (!(trigger_definition->ammunition_type==NONE || (trigger_definition->ammunition_type>=0 && trigger_definition->ammunition_type<NUMBER_OF_ITEMS))) return false;
2048
2049 if(trigger_definition->ammunition_type != NONE && player->items[trigger_definition->ammunition_type]>0)
2050 {
2051 struct weapon_data *weapon= get_player_current_weapon(player_index);
2052
2053 /* If this is a twofisted weapon & it doesn't reload in one hand... */
2054 /* If it is a twofisted weapon, doesn't reload in one hand, and both weapons are valid */
2055 if(definition->weapon_class==_twofisted_pistol_class &&
2056 !(definition->flags & _weapon_reloads_in_one_hand)
2057 && PRIMARY_WEAPON_IS_VALID(weapon) && SECONDARY_WEAPON_IS_VALID(weapon))
2058 {
2059 struct trigger_data *other_trigger= get_player_trigger_data(player_index, !which_trigger);
2060
2061 /* Note the presence of two weapons trying to reload simultaneously.. */
2062 if(other_trigger->state==_weapon_waiting_for_other_idle_to_reload)
2063 {
2064 /* He already had priority. */
2065 trigger->state= _weapon_lowering_for_twofisted_reload;
2066 trigger->phase= definition->ready_ticks;
2067 other_trigger->state= _weapon_awaiting_twofisted_reload;
2068 other_trigger->phase= definition->ready_ticks;
2069 } else {
2070 /* Try as we go through the loop next time.. */
2071 trigger->state= _weapon_waiting_for_other_idle_to_reload;
2072 trigger->phase= 0;
2073 }
2074 } else {
2075 /* Don't go to a state that has a zero duration.. */
2076 if(definition->await_reload_ticks)
2077 {
2078 trigger->state= _weapon_awaiting_reload;
2079 trigger->phase= definition->await_reload_ticks; // should this be by trigger?
2080 } else {
2081 trigger->state= _weapon_waiting_to_load;
2082 trigger->phase= definition->loading_ticks; // should this be by trigger?
2083 }
2084 }
2085 trigger->sequence= 0; // Reset this here, because it won't get reset otherwise.
2086 can_reload= true;
2087 } else {
2088 /* If this weapon needs to dissappear */
2089 if(definition->flags & _weapon_disappears_after_use)
2090 {
2091 destroy_current_weapon(player_index);
2092 }
2093 can_reload= false;
2094 }
2095
2096 return can_reload;
2097 }
2098
destroy_current_weapon(short player_index)2099 static void destroy_current_weapon(
2100 short player_index)
2101 {
2102 struct player_data *player= get_player_data(player_index);
2103 struct weapon_definition *definition= get_current_weapon_definition(player_index);
2104 short item_type;
2105
2106 assert(definition->item_type>=0 && definition->item_type<NUMBER_OF_ITEMS);
2107 if(get_item_kind(definition->item_type)==_ball)
2108 {
2109 /* Drop the ball.. */
2110 short ball_color= find_player_ball_color(player_index);
2111 // START Benad
2112 // assert(ball_color!=NONE);
2113 if (ball_color != NONE)
2114 item_type= find_player_ball_color(player_index)+BALL_ITEM_BASE;
2115 else
2116 return;
2117 // END Benad
2118 } else {
2119 item_type= definition->item_type;
2120 }
2121
2122 /* Decrement the item.. */
2123 player->items[item_type]--;
2124 if(player->items[item_type]<=0) player->items[item_type]= NONE;
2125
2126 /* Second parameter: */
2127 /* NONE- don't switch to ammo list */
2128 /* _i_magnum_magazine- switch to ammo list */
2129 mark_player_inventory_as_dirty(player_index, _i_magnum_magazine);
2130 }
2131
check_reload(short player_index,short which_trigger)2132 static bool check_reload(
2133 short player_index,
2134 short which_trigger)
2135 {
2136 struct trigger_data *trigger= get_player_trigger_data(player_index, which_trigger);
2137 struct weapon_definition *definition=
2138 get_current_weapon_definition(player_index);
2139 bool reloaded_weapon= false;
2140
2141 /* Check to see if the weapon is empty.. */
2142 if(!trigger->rounds_loaded)
2143 {
2144 switch(definition->weapon_class)
2145 {
2146 case _melee_class:
2147 /* Always have a round loaded.. */
2148 trigger->rounds_loaded= 1;
2149 break;
2150
2151 case _dual_function_class:
2152 if(definition->flags & _weapon_triggers_share_ammo)
2153 {
2154 which_trigger= _primary_weapon;
2155 }
2156 /* Fallthrough */
2157 case _normal_class:
2158 /* Hmmm.. we are out of ammunition */
2159 if(!reload_weapon(player_index, which_trigger))
2160 {
2161 /* Switch to the next weapon.. */
2162 select_next_best_weapon(player_index);
2163 } else {
2164 reloaded_weapon= true;
2165 }
2166 break;
2167
2168 case _twofisted_pistol_class:
2169 {
2170 struct weapon_data *weapon= get_player_current_weapon(player_index);
2171
2172 if(PRIMARY_WEAPON_IS_VALID(weapon) && SECONDARY_WEAPON_IS_VALID(weapon))
2173 {
2174 if(!reload_weapon(player_index, which_trigger))
2175 {
2176 /* Okay, we couldn't reload one of them. */
2177 /* Does the other one have ammo? */
2178 struct trigger_data *other_trigger_data=
2179 get_player_trigger_data(player_index, !which_trigger);
2180
2181 if(!other_trigger_data->rounds_loaded)
2182 {
2183 /* We have to change... */
2184 select_next_best_weapon(player_index);
2185 } else {
2186 if(which_trigger==_primary_weapon)
2187 {
2188 /* ���Problems? */
2189 struct trigger_data *other_trigger=
2190 get_player_trigger_data(player_index, !which_trigger);
2191
2192 trigger->state= _weapon_lowering;
2193 trigger->phase= definition->ready_ticks-1;
2194 trigger->sequence= 0;
2195
2196 other_trigger->state= _weapon_sliding_over_from_second_position;
2197 other_trigger->phase= definition->ready_ticks;
2198 other_trigger->sequence= 0;
2199 } else {
2200 struct trigger_data *other_trigger=
2201 get_player_trigger_data(player_index, !which_trigger);
2202
2203 assert(which_trigger==_secondary_weapon);
2204 trigger->state= _weapon_lowering;
2205 trigger->phase= definition->ready_ticks;
2206 trigger->sequence= 0;
2207
2208 other_trigger->state= _weapon_sliding_over_from_second_position;
2209 other_trigger->phase= definition->ready_ticks;
2210 other_trigger->sequence= 0;
2211 }
2212 }
2213 } else {
2214 reloaded_weapon= true;
2215 }
2216 } else {
2217 /* Hmmm.. we are out of ammunition */
2218 if(!reload_weapon(player_index, which_trigger))
2219 {
2220 /* Switch to the next weapon.. */
2221 select_next_best_weapon(player_index);
2222 } else {
2223 reloaded_weapon= true;
2224 }
2225 }
2226 }
2227 break;
2228
2229 case _multipurpose_class:
2230 /* Only switch if both of them are out of ammo, and we can't reload the one we */
2231 /* just fired with. */
2232 if(!reload_weapon(player_index, which_trigger))
2233 {
2234 short other_trigger= !which_trigger;
2235 struct trigger_data *other_trigger_data;
2236
2237 /* check to see if the other one is empty. */
2238 other_trigger_data= get_player_trigger_data(
2239 player_index, other_trigger);
2240
2241 if(!other_trigger_data->rounds_loaded)
2242 {
2243 switch(other_trigger_data->state)
2244 {
2245 case _weapon_awaiting_reload:
2246 case _weapon_waiting_to_load:
2247 case _weapon_finishing_reload:
2248 /* Don't switch, because the other is empty now, but not for long.. */
2249 break;
2250
2251 default:
2252 //dprintf("Unable to reload ar & other out of ammo (Which: %d)", which_trigger);
2253 /* Switch to the next weapon.. */
2254 select_next_best_weapon(player_index);
2255 break;
2256 }
2257 }
2258 } else {
2259 reloaded_weapon= true;
2260 }
2261 break;
2262
2263 // LP change: no weapon
2264 case NONE:
2265 default:
2266 break;
2267 }
2268 }
2269
2270 return reloaded_weapon;
2271 }
2272
put_rounds_into_weapon(short player_index,short which_weapon,short which_trigger)2273 static void put_rounds_into_weapon(
2274 short player_index,
2275 short which_weapon,
2276 short which_trigger)
2277 {
2278 struct trigger_data *trigger= get_trigger_data(player_index, which_weapon, which_trigger);
2279 struct trigger_definition *trigger_definition= get_trigger_definition(player_index, which_weapon, which_trigger);
2280 struct weapon_definition *definition= get_weapon_definition(which_weapon);
2281 struct player_data *player= get_player_data(player_index);
2282
2283 assert(trigger_definition->ammunition_type>=0 && trigger_definition->ammunition_type<NUMBER_OF_ITEMS);
2284 if (player->items[trigger_definition->ammunition_type] == 0) {
2285 trigger->state = _weapon_lowering;
2286 return;
2287 }
2288
2289 /* Load the gun */
2290 trigger->rounds_loaded= trigger_definition->rounds_per_magazine;
2291
2292 /* Decrement the ammo magazine count. */
2293 player->items[trigger_definition->ammunition_type]--;
2294
2295 /* Update the inventory display. Second parameter: NONE- don't switch to ammo list */
2296 /* _i_magnum_magazine- switch to ammo list */
2297 mark_player_inventory_as_dirty(player_index, _i_magnum_magazine);
2298
2299 /* Keep the ammo stores in sync for dual function class weapons */
2300 if(definition->flags & _weapon_triggers_share_ammo)
2301 {
2302 trigger= get_player_trigger_data(player_index, !which_trigger);
2303 trigger->rounds_loaded= trigger_definition->rounds_per_magazine;
2304 }
2305
2306
2307 /* Update the world ammunition count for the placement data */
2308 object_was_just_destroyed(_object_is_item, trigger_definition->ammunition_type);
2309
2310 /* Update the player ammunition count */
2311 update_player_ammo_count(player_index);
2312
2313 /* Play the sound. */
2314 play_weapon_sound(player_index, trigger_definition->reloading_sound, FIXED_ONE);
2315 }
2316
2317 /* This, my friend, is the trickiest of the functions */
handle_trigger_down(short player_index,short which_trigger)2318 static bool handle_trigger_down(
2319 short player_index,
2320 short which_trigger)
2321 {
2322 struct weapon_data *weapon= get_player_current_weapon(player_index);
2323 bool fired= false;
2324
2325 /* IF this weapon is idle.. */
2326 if(weapon->triggers[which_trigger].state==_weapon_idle)
2327 {
2328 struct trigger_definition *trigger_definition= get_player_trigger_definition(
2329 player_index, which_trigger);
2330
2331 /* If this weapon charges.. */
2332 if(trigger_definition->charging_ticks)
2333 {
2334 struct weapon_definition *definition= get_weapon_definition(weapon->weapon_type);
2335
2336 /* Either the other weapon is idle and we are dual, or we aren't dual */
2337 if(definition->weapon_class != _dual_function_class ||
2338 (definition->weapon_class==_dual_function_class && weapon->triggers[!which_trigger].state==_weapon_idle))
2339 {
2340 /* start charging... */
2341 weapon->triggers[which_trigger].state= _weapon_charging;
2342 weapon->triggers[which_trigger].phase= trigger_definition->charging_ticks;
2343 play_weapon_sound(player_index, trigger_definition->charging_sound, FIXED_ONE);
2344 }
2345 } else {
2346 struct weapon_definition *definition= get_current_weapon_definition(player_index);
2347
2348 switch(definition->weapon_class)
2349 {
2350 case _melee_class:
2351 case _twofisted_pistol_class:
2352 /* Stagger the weapons firing. */
2353 /* Rocky modification */
2354 if(PRIMARY_WEAPON_IS_VALID(weapon) && SECONDARY_WEAPON_IS_VALID(weapon))
2355 {
2356 if(definition->flags & _weapon_fires_out_of_phase)
2357 {
2358 short total_delay, delay;
2359 struct trigger_definition *other_trigger_definition= get_player_trigger_definition(
2360 player_index, !which_trigger);
2361
2362 total_delay= other_trigger_definition->recovery_ticks+other_trigger_definition->ticks_per_round;
2363 delay= total_delay-weapon->triggers[!which_trigger].phase;
2364 switch(weapon->triggers[!which_trigger].state)
2365 {
2366 case _weapon_firing: delay-= trigger_definition->recovery_ticks;
2367 case _weapon_recovering:
2368 break;
2369
2370 default:
2371 total_delay= delay= 1;
2372 break;
2373 }
2374
2375 /* Only able to fire exactly out of sync. */
2376 if(delay>total_delay/2)
2377 {
2378 fired= true;
2379 }
2380 }
2381 else
2382 {
2383 switch(weapon->triggers[!which_trigger].state)
2384 {
2385 case _weapon_firing:
2386 case _weapon_recovering:
2387 break;
2388
2389 default:
2390 fired= true;
2391 break;
2392 }
2393 }
2394 }
2395 else
2396 {
2397 /* Both aren't up. They can fire.. */
2398 fired= true;
2399 }
2400 break;
2401
2402 case _normal_class:
2403 /* Always able to fire.. */
2404 fired= true;
2405 break;
2406
2407 case _multipurpose_class:
2408 if(which_trigger==_secondary_weapon)
2409 {
2410 switch(weapon->triggers[_primary_weapon].state)
2411 {
2412 case _weapon_idle:
2413 case _weapon_recovering:
2414 case _weapon_firing:
2415 fired= true;
2416 break;
2417
2418 default:
2419 /* Don't fire the other weapon when we are reloading, raising, lowering, etc. */
2420 break;
2421 }
2422 } else {
2423 /* Can always fire an idle multifunction class */
2424 fired= true;
2425 }
2426 break;
2427
2428 case _dual_function_class:
2429 fired= true;
2430 break;
2431
2432 // LP change: no weapon -- do nothing
2433 case NONE:
2434 default:
2435 break;
2436 }
2437
2438 if(fired)
2439 {
2440 fire_weapon(player_index, which_trigger, FIXED_ONE, false);
2441 }
2442 }
2443 }
2444
2445 /* Set the trigger down state */
2446 if(which_trigger==_primary_weapon)
2447 SET_TRIGGER_DOWN(weapon, true);
2448
2449 return fired;
2450 }
2451
2452 /* we only care about the trigger going up on charged weapons.. */
handle_trigger_up(short player_index,short which_trigger)2453 static bool handle_trigger_up(
2454 short player_index,
2455 short which_trigger)
2456 {
2457 struct weapon_data *weapon= get_player_current_weapon(player_index);
2458 struct trigger_definition *trigger_definition=
2459 get_player_trigger_definition(player_index, which_trigger);
2460 bool discharge;
2461 _fixed charged_amount = 0;
2462
2463 /* On charged weapons, when the trigger goes up, we discharge.. */
2464 switch(weapon->triggers[which_trigger].state)
2465 {
2466 case _weapon_charging:
2467 discharge= true;
2468 charged_amount= ((trigger_definition->charging_ticks-weapon->triggers[which_trigger].phase)*FIXED_ONE)/FIXED_ONE;
2469 break;
2470
2471 case _weapon_charged:
2472 /* These are the only states that we really care about. */
2473 discharge= true;
2474 charged_amount= FIXED_ONE;
2475 break;
2476
2477 default:
2478 discharge= false;
2479 break;
2480 }
2481
2482 /* Fire the weapon (but only if it is at least 90% charged.) */
2483 if(discharge)
2484 {
2485 struct player_data *player= get_player_data(player_index);
2486
2487 /* Don't discharge on teleporting. */
2488 if(!PLAYER_IS_TELEPORTING(player) && !PLAYER_IS_INTERLEVEL_TELEPORTING(player))
2489 {
2490 if(charged_amount>(9*FIXED_ONE)/10)
2491 {
2492 fire_weapon(player_index, which_trigger, charged_amount, false);
2493 } else {
2494 struct player_data *player= get_player_data(player_index);
2495
2496 /* You lose. */
2497 weapon->triggers[which_trigger].state= _weapon_idle;
2498 weapon->triggers[which_trigger].phase= IDLE_PHASE_COUNT;
2499 weapon->triggers[which_trigger].sequence= 0;
2500 SoundManager::instance()->StopSound(player->object_index, trigger_definition->charging_sound);
2501 }
2502 }
2503 }
2504
2505 /* Trigger down is only maintained to avoid switching a weapon */
2506 if(which_trigger==_primary_weapon)
2507 {
2508 SET_TRIGGER_DOWN(weapon, false);
2509
2510 if(weapon->triggers[which_trigger].ticks_firing>FIRING_BEFORE_SHELL_CASING_SOUND_IS_PLAYED)
2511 {
2512 struct trigger_definition *trigger_definition= get_player_trigger_definition(player_index,
2513 which_trigger);
2514
2515 weapon->triggers[which_trigger].ticks_firing= 0;
2516 play_shell_casing_sound(player_index, trigger_definition->shell_casing_sound);
2517 }
2518 }
2519
2520 return discharge;
2521 }
2522
2523 /* Need to put a reload weapon in here, if that is what we want to do.. */
2524 /* Need to put a reload weapon in here, if that is what we want to do.. */
2525 /* CP Addition: removed 'static' to provide extern access
2526 static bool ready_weapon(
2527 short player_index,
2528 short weapon_index)
2529
2530 */
ready_weapon(short player_index,short weapon_index)2531 bool ready_weapon(
2532 short player_index,
2533 short weapon_index)
2534 {
2535 bool able_to_ready= false;
2536 struct weapon_definition *definition= get_weapon_definition(weapon_index);
2537 struct player_data *player= get_player_data(player_index);
2538 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
2539
2540 if(weapon_works_in_current_environment(weapon_index))
2541 {
2542 if(player_weapons->desired_weapon != weapon_index)
2543 {
2544 if(player->items[definition->item_type] > 0 || weapon_index==_weapon_ball)
2545 {
2546 if(player_weapon_has_ammo(player_index, weapon_index))
2547 {
2548 player_weapons->desired_weapon= weapon_index;
2549
2550 /* update the weapon display */
2551 if(player_index==current_player_index) mark_weapon_display_as_dirty();
2552 able_to_ready= true;
2553 }
2554 }
2555 }
2556 }
2557
2558 return able_to_ready;
2559 }
2560
player_weapon_has_ammo(short player_index,short weapon_index)2561 static bool player_weapon_has_ammo(
2562 short player_index,
2563 short weapon_index)
2564 {
2565 struct player_data *player= get_player_data(player_index);
2566 struct weapon_definition *definition= get_weapon_definition(weapon_index);
2567 bool has_ammo= false;
2568
2569 if(definition->weapon_class==_melee_class)
2570 {
2571 has_ammo= true;
2572 } else {
2573 short which_trigger, max_triggers;
2574
2575 switch(definition->weapon_class)
2576 {
2577 case _melee_class:
2578 case _dual_function_class:
2579 case _twofisted_pistol_class:
2580 case _multipurpose_class:
2581 max_triggers= 2;
2582 break;
2583
2584 case _normal_class:
2585 max_triggers= 1;
2586 break;
2587
2588 // LP change: no weapon -- do nothing
2589 case NONE:
2590 default:
2591 max_triggers= 0;
2592 break;
2593 }
2594
2595 for(which_trigger= _primary_weapon; !has_ammo && which_trigger<max_triggers; ++which_trigger)
2596 {
2597 struct trigger_data *trigger= get_trigger_data(player_index, weapon_index,
2598 which_trigger);
2599
2600 if(trigger->rounds_loaded>0)
2601 {
2602 has_ammo= true;
2603 } else {
2604 struct trigger_definition *trigger_definition=
2605 get_trigger_definition(player_index, weapon_index, which_trigger);
2606
2607 /* Could we load this guy? */
2608 if( trigger_definition->ammunition_type != NONE &&
2609 player->items[trigger_definition->ammunition_type] > 0)
2610 {
2611 has_ammo= true;
2612 }
2613 }
2614 }
2615 }
2616
2617 return has_ammo;
2618 }
2619
lower_weapon(short player_index,short weapon_index)2620 static void lower_weapon(
2621 short player_index,
2622 short weapon_index)
2623 {
2624 struct weapon_definition *definition= get_weapon_definition(weapon_index);
2625 short which_trigger, active_trigger_count, first_trigger;
2626
2627 active_trigger_count= get_active_trigger_count_and_states(player_index, weapon_index,
2628 0l, &first_trigger, NULL);
2629 for(which_trigger= first_trigger; which_trigger<active_trigger_count; ++which_trigger)
2630 {
2631 struct trigger_data *trigger= get_trigger_data(player_index, weapon_index,
2632 which_trigger);
2633
2634 /* If this weapon isn't already lowering.. */
2635 if(trigger->state != _weapon_lowering)
2636 {
2637 /* If we aren't raising, set the phase. Otherwise use */
2638 /* the current phase to go back down.. */
2639 if( trigger->state==_weapon_idle)
2640 {
2641 trigger->phase= definition->ready_ticks;
2642 } else {
2643 assert(trigger->state==_weapon_raising);
2644 trigger->phase= definition->ready_ticks - trigger->phase;
2645 }
2646
2647 trigger->state= _weapon_lowering;
2648 trigger->sequence= 0;
2649 }
2650 }
2651 }
2652
2653 /*
2654 note that if we are raising a weapon, we want to fill it up with ammo first,
2655 if we can (and should). This means that if you switch weapons during a lengthy
2656 reload, you can win.
2657 */
raise_weapon(short player_index,short weapon_index)2658 static void raise_weapon(
2659 short player_index,
2660 short weapon_index)
2661 {
2662 struct weapon_definition *definition= get_weapon_definition(weapon_index);
2663 short which_trigger, active_trigger_count, first_trigger;
2664
2665 // dprintf("Raising: %d;g", weapon_index);
2666 active_trigger_count= get_active_trigger_count_and_states(player_index, weapon_index, 0l,
2667 &first_trigger, NULL);
2668 for(which_trigger= first_trigger; which_trigger<active_trigger_count; ++which_trigger)
2669 {
2670 struct trigger_data *trigger= get_trigger_data(player_index, weapon_index,
2671 which_trigger);
2672
2673 if(trigger->state!=_weapon_raising)
2674 {
2675 /* If we aren't raising, set the phase. Otherwise use */
2676 /* the current phase to go back down.. */
2677 if(trigger->state==_weapon_idle)
2678 {
2679 trigger->phase= definition->ready_ticks;
2680 } else {
2681 vassert(trigger->state==_weapon_lowering, csprintf(temporary, "State: %d phase: %d trigger: %d weapon: %d",
2682 trigger->state, trigger->phase, which_trigger, weapon_index));
2683 trigger->phase= definition->ready_ticks-trigger->phase;
2684 // dprintf("Lowering: Phase: %d;g", trigger->phase);
2685 }
2686 trigger->state= _weapon_raising;
2687 trigger->sequence= 0;
2688
2689 if(which_trigger==_primary_weapon)
2690 {
2691 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
2692
2693 SET_PRIMARY_WEAPON_IS_VALID(&player_weapons->weapons[weapon_index], true);
2694 } else {
2695 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
2696
2697 // dprintf("Second valid;g");
2698 SET_SECONDARY_WEAPON_IS_VALID(&player_weapons->weapons[weapon_index], true);
2699 }
2700 }
2701 }
2702 }
2703
2704 /* Note that we are guaranteed that the current weapon has ammo.. */
should_switch_to_weapon(short player_index,short new_weapon)2705 static bool should_switch_to_weapon(
2706 short player_index,
2707 short new_weapon)
2708 {
2709 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
2710 bool should_change= false;
2711
2712 /* Switch to it if we should.. */
2713 /* Change if: */
2714 /* The current weapon is the desired weapon, the trigger is not down, AND either: */
2715 /* A) They don't have a weapon */
2716 /* B) The new weapon is better and the current weapon is not charging OR */
2717 /* C) The current weapon has no ammunition */
2718 if(weapon_works_in_current_environment(new_weapon))
2719 {
2720 if(player_weapons->desired_weapon==player_weapons->current_weapon || new_weapon==_weapon_ball)
2721 {
2722 short new_weapon_index, current_weapon_index;
2723
2724 /* Find the relative powers of the weapons to determine which is greater */
2725 new_weapon_index= find_weapon_power_index(new_weapon);
2726 current_weapon_index= find_weapon_power_index(player_weapons->current_weapon);
2727
2728 /* If the new weapon is better.. */
2729 if(new_weapon_index>current_weapon_index)
2730 {
2731 if(player_weapons->current_weapon==NONE)
2732 {
2733 /* Always change if they didn't have a weapon.. */
2734 should_change= true;
2735 } else {
2736 struct weapon_data *weapon= get_player_current_weapon(player_index);
2737
2738 if(new_weapon==_weapon_ball)
2739 {
2740 should_change= true;
2741 } else {
2742 /* If this weapon is not charging or charged.. */
2743 if(weapon->triggers[_primary_weapon].state!=_weapon_charging &&
2744 weapon->triggers[_primary_weapon].state!=_weapon_charged &&
2745 weapon->triggers[_secondary_weapon].state!=_weapon_charging &&
2746 weapon->triggers[_secondary_weapon].state!=_weapon_charged)
2747 {
2748 /* If this weapon doesn't have the trigger down... */
2749 // LP addition: Josh Elsasser's dont-switch-weapons patch
2750 if(!TRIGGER_IS_DOWN(weapon))
2751 {
2752 if (!PLAYER_DOESNT_AUTO_SWITCH_WEAPONS(get_player_data(player_index)))
2753 should_change= true;
2754 }
2755 }
2756 }
2757 }
2758 }
2759 /* or the current weapon doesn't have ammo */
2760 else if(!player_weapon_has_ammo(player_index, player_weapons->current_weapon))
2761 {
2762 should_change= true;
2763 }
2764 }
2765 }
2766
2767 return should_change;
2768 }
2769
calculate_weapon_position_for_idle(short player_index,short count,short weapon_type,_fixed * height,_fixed * width,bool use_elevation)2770 static void calculate_weapon_position_for_idle(
2771 short player_index,
2772 short count,
2773 short weapon_type,
2774 _fixed *height,
2775 _fixed *width,
2776 bool use_elevation)
2777 {
2778 struct weapon_definition *definition= get_weapon_definition(weapon_type);
2779 struct player_data *player= get_player_data(player_index);
2780 _fixed horizontal_phase, vertical_angle, bob_height, bob_width;
2781 short *table;
2782
2783 if(count==0)
2784 {
2785 table= sine_table;
2786 horizontal_phase= player->variables.step_phase;
2787 vertical_angle= player->variables.step_phase>>(FIXED_FRACTIONAL_BITS-ANGULAR_BITS);
2788 } else {
2789 table= cosine_table;
2790 vertical_angle= NORMALIZE_ANGLE((player->variables.step_phase>>(FIXED_FRACTIONAL_BITS-ANGULAR_BITS))+HALF_CIRCLE);
2791 horizontal_phase= player->variables.step_phase;
2792 }
2793 /* Weapons are the first thing drawn */
2794 bob_height= (player->variables.step_amplitude*definition->bob_amplitude)>>FIXED_FRACTIONAL_BITS;
2795 bob_height= (bob_height*table[vertical_angle])>>TRIG_SHIFT;
2796 if (!graphics_preferences->screen_mode.camera_bob) bob_height= 0;
2797 if (use_elevation) bob_height+= sine_table[player->elevation]<<3;
2798 *height+= bob_height;
2799
2800 bob_width= (player->variables.step_amplitude*definition->horizontal_amplitude)>>FIXED_FRACTIONAL_BITS;
2801 bob_width= (bob_width*table[horizontal_phase>>(FIXED_FRACTIONAL_BITS-ANGULAR_BITS)])>>TRIG_SHIFT;
2802 if (!graphics_preferences->screen_mode.camera_bob) bob_width= 0;
2803 *width += bob_width;
2804 }
2805
modify_position_for_two_weapons(short player_index,short count,_fixed * width,_fixed * height)2806 static void modify_position_for_two_weapons(
2807 short player_index,
2808 short count,
2809 _fixed *width,
2810 _fixed *height)
2811 {
2812 struct weapon_definition *definition= get_current_weapon_definition(player_index);
2813
2814 /* Handle modifying the width for twofisted weapons.. */
2815 switch(definition->weapon_class)
2816 {
2817 case _melee_class:
2818 {
2819 if (definition->flags & _weapon_is_marathon_1) {
2820 break;
2821 }
2822
2823 struct weapon_data *weapon= get_player_current_weapon(player_index);
2824 struct trigger_definition *trigger_definition;
2825 short total_delay, delay, breakpoint_delay, sign;
2826
2827 if(PRIMARY_WEAPON_IS_VALID(weapon) && SECONDARY_WEAPON_IS_VALID(weapon))
2828 {
2829 switch(count)
2830 {
2831 case 0:
2832 case 1:
2833 sign= (count) ? -1 : 1;
2834 *width+= (PISTOL_SEPARATION_WIDTH*sign);
2835 trigger_definition= get_player_trigger_definition(player_index, !count);
2836 total_delay= trigger_definition->ticks_per_round+trigger_definition->recovery_ticks;
2837 breakpoint_delay= (2*total_delay)/3;
2838 delay= total_delay-weapon->triggers[!count].phase;
2839 switch(weapon->triggers[!count].state)
2840 {
2841 case _weapon_firing: delay-= trigger_definition->recovery_ticks;
2842 case _weapon_recovering:
2843 if(delay>=breakpoint_delay)
2844 {
2845 /* Delay needs to go from breakpoint_delay to zero */
2846 delay= total_delay - delay;
2847 *width+= sign*((FIXED_ONE/8)*delay)/(total_delay-breakpoint_delay);
2848 *height+= ((FIXED_ONE/16)*delay)/(total_delay-breakpoint_delay);
2849 } else {
2850 *width+= sign*((FIXED_ONE/8)*delay)/breakpoint_delay;
2851 *height+= ((FIXED_ONE/16)*delay)/breakpoint_delay;
2852 }
2853 break;
2854 }
2855 break;
2856
2857 default:
2858 break;
2859 }
2860 } else {
2861 *width+= FIXED_ONE_HALF/2;
2862 }
2863 }
2864 break;
2865
2866 case _twofisted_pistol_class:
2867 {
2868 struct weapon_data *weapon= get_player_current_weapon(player_index);
2869
2870 if(PRIMARY_WEAPON_IS_VALID(weapon) && SECONDARY_WEAPON_IS_VALID(weapon))
2871 {
2872 switch(count)
2873 {
2874 case 0: *width += PISTOL_SEPARATION_WIDTH/2; break;
2875 case 1: *width -= PISTOL_SEPARATION_WIDTH/2; break;
2876 default: break;
2877 }
2878 }
2879 }
2880 break;
2881
2882 default:
2883 break;
2884 }
2885 }
2886
add_random_flutter(_fixed flutter_base,_fixed * height,_fixed * width)2887 static void add_random_flutter(
2888 _fixed flutter_base,
2889 _fixed *height,
2890 _fixed *width)
2891 {
2892 _fixed delta_height, delta_width;
2893
2894 delta_height= flutter_base>>4;
2895 delta_width= flutter_base>>6;
2896
2897 /* Note that we MUST use rand() here, and not global_random() */
2898 if(delta_height) *height += (rand()%delta_height)-(delta_height/2);
2899 if(delta_width) *width += (rand()%delta_width)-(delta_width/2);
2900 }
2901
play_weapon_sound(short player_index,short sound,_fixed pitch)2902 static void play_weapon_sound(
2903 short player_index,
2904 short sound,
2905 _fixed pitch)
2906 {
2907 struct player_data *player= get_player_data(player_index);
2908 struct monster_data *monster= get_monster_data(player->monster_index);
2909 struct object_data *object= get_object_data(monster->object_index);
2910 _fixed old_pitch= object->sound_pitch;
2911
2912 object->sound_pitch= pitch;
2913 play_object_sound(monster->object_index, sound);
2914 object->sound_pitch= old_pitch;
2915 }
2916
get_active_trigger_count_and_states(short player_index,short weapon_index,uint32 action_flags,short * first_trigger,bool * triggers_down)2917 static short get_active_trigger_count_and_states(
2918 short player_index,
2919 short weapon_index,
2920 uint32 action_flags,
2921 short *first_trigger,
2922 bool *triggers_down)
2923 {
2924 struct weapon_definition *definition= get_weapon_definition(weapon_index);
2925 short active_count = 0;
2926
2927 assert(first_trigger);
2928
2929 if(triggers_down)
2930 {
2931 triggers_down[0]= triggers_down[1]= false;
2932 }
2933
2934 (*first_trigger)= _primary_weapon;
2935
2936 int16 weapon_class = definition->weapon_class;
2937 if (weapon_class == _melee_class && (definition->flags & _weapon_is_marathon_1)) {
2938 weapon_class = _normal_class;
2939 }
2940
2941 switch(weapon_class)
2942 {
2943 case _normal_class:
2944 active_count= 1;
2945 if(triggers_down)
2946 {
2947 if(action_flags & _left_trigger_state || action_flags & _right_trigger_state) triggers_down[0]= true;
2948 }
2949 break;
2950
2951 case _melee_class:
2952 case _twofisted_pistol_class:
2953 {
2954 struct player_data *player= get_player_data(player_index);
2955 struct weapon_data *weapon= get_player_current_weapon(player_index);
2956
2957 if(player->items[definition->item_type]>1 &&
2958 PRIMARY_WEAPON_IS_VALID(weapon) && SECONDARY_WEAPON_IS_VALID(weapon))
2959 {
2960 if(triggers_down)
2961 {
2962 if(action_flags & _left_trigger_state) triggers_down[0]= true;
2963 if(action_flags & _right_trigger_state) triggers_down[1]= true;
2964 }
2965 active_count= 2;
2966 } else {
2967 if(SECONDARY_WEAPON_IS_VALID(weapon))
2968 {
2969 if(triggers_down)
2970 {
2971 if(action_flags & _left_trigger_state) triggers_down[1]= true;
2972 if(action_flags & _right_trigger_state) triggers_down[1]= true;
2973 }
2974
2975 (*first_trigger)= _secondary_weapon;
2976 active_count= 2;
2977 } else {
2978 if(triggers_down)
2979 {
2980 if(action_flags & _left_trigger_state) triggers_down[0]= true;
2981 if(action_flags & _right_trigger_state) triggers_down[0]= true;
2982 }
2983 active_count= 1;
2984 }
2985 }
2986 }
2987 break;
2988
2989 case _dual_function_class:
2990 if(triggers_down)
2991 {
2992 if(dual_function_secondary_has_control(player_index))
2993 {
2994 triggers_down[_primary_weapon]= false;
2995 } else {
2996 if(action_flags & _left_trigger_state) triggers_down[0]= true;
2997 }
2998
2999 /* check the right trigger */
3000 if(action_flags & _right_trigger_state) triggers_down[1]= true;
3001 }
3002 active_count= 2;
3003 break;
3004
3005 case _multipurpose_class:
3006 if(triggers_down)
3007 {
3008 if(action_flags & _left_trigger_state) triggers_down[0]= true;
3009 if(action_flags & _right_trigger_state) triggers_down[1]= true;
3010 }
3011 active_count= 2;
3012 break;
3013
3014 // LP change: no weapon
3015 case NONE:
3016 default:
3017 break;
3018 }
3019
3020 return active_count;
3021 }
3022
dual_function_secondary_has_control(short player_index)3023 static bool dual_function_secondary_has_control(
3024 short player_index)
3025 {
3026 struct trigger_data *trigger= get_player_trigger_data(player_index, _secondary_weapon);
3027 bool secondary_has_control;
3028
3029 switch(trigger->state)
3030 {
3031 case _weapon_recovering:
3032 case _weapon_firing:
3033 case _weapon_charging:
3034 case _weapon_charged:
3035 /* You can't fire your primary until secondary is idle */
3036 secondary_has_control= true;
3037 break;
3038
3039 default:
3040 secondary_has_control= false;
3041 break;
3042 }
3043
3044 return secondary_has_control;
3045 }
3046
3047 /* Called once the shapes are loaded */
calculate_ticks_from_shapes(void)3048 static void calculate_ticks_from_shapes(
3049 void)
3050 {
3051 for(unsigned weapon_type= 0; weapon_type<NUMBER_OF_WEAPONS; ++weapon_type)
3052 {
3053 struct weapon_definition *definition= get_weapon_definition(weapon_type);
3054
3055 /* Handle the firing ticks */
3056 if(definition->weapons_by_trigger[_primary_weapon].ticks_per_round==NONE)
3057 {
3058 struct shape_animation_data *high_level_data;
3059 short total_ticks;
3060
3061 trigger_definition& primary = definition->weapons_by_trigger[_primary_weapon];
3062 trigger_definition& secondary = definition->weapons_by_trigger[_secondary_weapon];
3063
3064 high_level_data= get_shape_animation_data(BUILD_DESCRIPTOR(definition->collection,
3065 definition->firing_shape));
3066 // Skip over if the sequence is nonexistent
3067 if(!high_level_data) continue;
3068
3069 total_ticks= high_level_data->ticks_per_frame*high_level_data->frames_per_view;
3070
3071 if (definition->flags & _weapon_is_marathon_1)
3072 {
3073 if (definition->flags & _weapon_is_automatic)
3074 {
3075 primary.ticks_per_round = total_ticks - 1;
3076 primary.recovery_ticks = 0;
3077 }
3078 else
3079 {
3080 primary.ticks_per_round = total_ticks - 1;
3081 }
3082 }
3083 else if(definition->flags & _weapon_is_automatic)
3084 {
3085 /* All automatic weapons have no recovery time.. */
3086 primary.ticks_per_round= total_ticks;
3087 primary.recovery_ticks= 0;
3088 } else {
3089 primary.ticks_per_round=
3090 (high_level_data->key_frame+1)*high_level_data->ticks_per_frame;
3091 primary.recovery_ticks= total_ticks-
3092 definition->weapons_by_trigger[_primary_weapon].ticks_per_round;
3093 }
3094
3095 /* Fixup the secondary trigger.. */
3096 if(secondary.ticks_per_round== NONE && (definition->flags & _weapon_triggers_share_ammo))
3097 {
3098 secondary.ticks_per_round= primary.ticks_per_round;
3099 secondary.recovery_ticks= primary.recovery_ticks;
3100 }
3101
3102 /* Rocky modification */
3103 if(definition->weapon_class==_melee_class || definition->weapon_class==_twofisted_pistol_class)
3104 {
3105 if (definition->flags & _weapon_is_marathon_1)
3106 {
3107 secondary.ticks_per_round = total_ticks - 1;
3108 } else {
3109 secondary.ticks_per_round=
3110 (high_level_data->key_frame+1)*high_level_data->ticks_per_frame;
3111 secondary.recovery_ticks= total_ticks-
3112 definition->weapons_by_trigger[_secondary_weapon].ticks_per_round;
3113 }
3114 }
3115 }
3116
3117 /* Handle the reloading ticks */
3118 if(definition->reloading_shape != NONE)
3119 {
3120 struct shape_animation_data *high_level_data;
3121 short total_ticks;
3122
3123 high_level_data= get_shape_animation_data(BUILD_DESCRIPTOR(definition->collection,
3124 definition->reloading_shape));
3125 // Skip over if the sequence is nonexistent
3126 if(!high_level_data) continue;
3127
3128 total_ticks= high_level_data->ticks_per_frame*high_level_data->frames_per_view;
3129 definition->await_reload_ticks= 0;
3130 definition->loading_ticks= high_level_data->ticks_per_frame*(high_level_data->key_frame+1)
3131 - definition->await_reload_ticks;
3132 definition->finish_loading_ticks= total_ticks - definition->loading_ticks
3133 - definition->await_reload_ticks;
3134 } else {
3135 /* This shape doesn't have a reloading shape, therefore the reload */
3136 /* time is calculated here. */
3137 short total_ticks= definition->await_reload_ticks +
3138 definition->loading_ticks +
3139 definition->finish_loading_ticks;
3140
3141 /* Each are set to the same value.. */
3142 definition->await_reload_ticks= total_ticks/3;
3143 definition->loading_ticks= total_ticks/3;
3144 definition->finish_loading_ticks= total_ticks/3;
3145 }
3146 }
3147 }
3148
update_automatic_sequence(short player_index,short which_trigger)3149 static void update_automatic_sequence(
3150 short player_index,
3151 short which_trigger)
3152 {
3153 struct weapon_definition *definition= get_current_weapon_definition(player_index);
3154
3155 if(definition->flags & _weapon_is_automatic)
3156 {
3157 if(which_trigger==_primary_weapon ||
3158 (which_trigger==_secondary_weapon && (definition->flags & _weapon_secondary_has_angular_flipping)))
3159 {
3160 struct trigger_data *trigger= get_player_trigger_data(player_index, which_trigger);
3161 struct shape_animation_data *high_level_data= NULL;
3162
3163 switch(trigger->state)
3164 {
3165 case _weapon_firing:
3166 case _weapon_recovering:
3167 high_level_data= get_shape_animation_data(BUILD_DESCRIPTOR(definition->collection,
3168 definition->firing_shape));
3169 break;
3170
3171 case _weapon_idle:
3172 if(automatic_still_firing(player_index, which_trigger))
3173 {
3174 high_level_data= get_shape_animation_data(BUILD_DESCRIPTOR(definition->collection,
3175 definition->firing_shape));
3176 } else {
3177 // Now handled in UpdateIdleWeapon()
3178 // trigger->sequence= BUILD_SEQUENCE(0, 0);
3179 }
3180 break;
3181
3182 default:
3183 break;
3184 }
3185
3186 if(high_level_data)
3187 {
3188 short frame;
3189
3190 frame= GET_SEQUENCE_FRAME(trigger->sequence);
3191
3192 // does Marathon 1 have a bug or something?
3193 if (definition->flags & _weapon_is_marathon_1 && high_level_data->frames_per_view == 2)
3194 {
3195 if (++frame >= 1) {
3196 frame = 0;
3197 }
3198 }
3199 else if(++frame>=high_level_data->frames_per_view)
3200 {
3201 frame= 0;
3202 }
3203 trigger->sequence= BUILD_SEQUENCE(frame, 0);
3204 }
3205 }
3206 }
3207 }
3208
3209 // LP addition: update the idle-weapon animation:
UpdateIdleAnimation(short player_index,short which_trigger)3210 static void UpdateIdleAnimation(
3211 short player_index,
3212 short which_trigger)
3213 {
3214 struct trigger_data *trigger= get_player_trigger_data(player_index, which_trigger);
3215 if (trigger->state != _weapon_idle) return;
3216 if (automatic_still_firing(player_index, which_trigger)) return;
3217
3218 struct weapon_definition *definition= get_current_weapon_definition(player_index);
3219 struct shape_animation_data *animation =
3220 get_shape_animation_data(BUILD_DESCRIPTOR(definition->collection, definition->idle_shape));
3221 if (!animation) return;
3222
3223 // Code cribbed from animate_object() in map.cpp
3224
3225 /* if this animation has frames, animate it */
3226 if (animation->frames_per_view>=1 && animation->number_of_views!=_unanimated && !(definition->flags & _weapon_is_marathon_1))
3227 {
3228 short frame, phase;
3229
3230 // LP change: added some idiot-proofing to the ticks-per-frame value
3231 if (animation->ticks_per_frame <= 0)
3232 animation->ticks_per_frame = 1;
3233
3234 frame= GET_SEQUENCE_FRAME(trigger->sequence);
3235 phase= GET_SEQUENCE_PHASE(trigger->sequence);
3236 if (!frame && (!phase || phase>=animation->ticks_per_frame)) play_weapon_sound(player_index, animation->first_frame_sound, FIXED_ONE);
3237
3238 /* phase is left unadjusted if it goes over ticks_per_frame until the next call */
3239 if (phase>=animation->ticks_per_frame) phase-= animation->ticks_per_frame;
3240 if ((phase+= 1)>=animation->ticks_per_frame)
3241 {
3242 frame+= 1;
3243 // LP change: interchanged these two so that
3244 // 1: keyframe 0 would get recognized
3245 // 2: to keep the timing correct in the nonzero case
3246 // LP change: inverted the order yet again to get more like Moo,
3247 // but this time, added detection of cases
3248 // keyframe = 0 and keyframe = [frames per view]
3249 // Inverted the order yet again (!) to supporess Hunter death bug
3250 if (frame>=animation->frames_per_view)
3251 {
3252 frame= animation->loop_frame;
3253 if (animation->last_frame_sound!=NONE) play_weapon_sound(player_index, animation->last_frame_sound, FIXED_ONE);
3254 }
3255 short offset_frame = frame + animation->frames_per_view; // LP addition
3256 if (frame==animation->key_frame || offset_frame==animation->key_frame)
3257 {
3258 if (animation->key_frame_sound!=NONE) play_weapon_sound(player_index, animation->first_frame_sound, FIXED_ONE);
3259 }
3260 }
3261
3262 trigger->sequence= BUILD_SEQUENCE(frame, phase);
3263 } else {
3264 trigger->sequence = BUILD_SEQUENCE(0, 0);
3265 }
3266 }
3267
3268
3269 /* Automatic weapons should always show every frame of their firing animation */
3270 /* If it is automatic: do nothing for idle/firing/recovery. frame time: increment frame */
update_sequence(short player_index,short which_trigger)3271 static void update_sequence(
3272 short player_index,
3273 short which_trigger)
3274 {
3275 struct weapon_definition *definition= get_current_weapon_definition(player_index);
3276 struct trigger_data *trigger= get_player_trigger_data(player_index, which_trigger);
3277 struct shape_animation_data *high_level_data= NULL;
3278 bool prevent_wrap= false; /* GROSS! */
3279 _fixed pitch= FIXED_ONE;
3280 short sound_id= NONE;
3281
3282 switch(trigger->state)
3283 {
3284 case _weapon_firing:
3285 case _weapon_recovering:
3286 prevent_wrap = true; // These animations should not repeat
3287 if((which_trigger==_primary_weapon && (definition->flags & _weapon_is_automatic))
3288 || (which_trigger==_secondary_weapon && (definition->flags & _weapon_is_automatic) && (definition->flags & _weapon_secondary_has_angular_flipping)))
3289 {
3290 } else if (trigger->state == _weapon_recovering && (definition->flags & _weapon_is_marathon_1)) {
3291 high_level_data = get_shape_animation_data(BUILD_DESCRIPTOR(definition->collection, definition->idle_shape));
3292 } else {
3293 high_level_data= get_shape_animation_data(BUILD_DESCRIPTOR(definition->collection,
3294 definition->firing_shape));
3295 }
3296 break;
3297
3298 case _weapon_idle:
3299 if((which_trigger==_primary_weapon && (definition->flags & _weapon_is_automatic))
3300 || (which_trigger==_secondary_weapon && (definition->flags & _weapon_is_automatic) && (definition->flags & _weapon_secondary_has_angular_flipping)))
3301 {
3302 } else {
3303 // Now handled in UpdateIdleAnimation
3304 // trigger->sequence= 0;
3305 }
3306 break;
3307
3308 case _weapon_charged:
3309 {
3310 struct trigger_definition *trigger_definition= get_player_trigger_definition(player_index, which_trigger);
3311
3312 high_level_data= get_shape_animation_data(BUILD_DESCRIPTOR(definition->collection,
3313 definition->charged_shape));
3314
3315 /* Get the charged sound */
3316 sound_id= trigger_definition->charged_sound;
3317
3318 /* If this weapon overloads, play with the pitch */
3319 if(definition->flags & _weapon_overloads)
3320 {
3321 pitch= FIXED_ONE+(FIXED_ONE*(CHARGED_WEAPON_OVERLOAD-trigger->phase))/CHARGED_WEAPON_OVERLOAD;
3322 }
3323 }
3324 break;
3325
3326 case _weapon_awaiting_reload:
3327 case _weapon_waiting_to_load:
3328 case _weapon_finishing_reload:
3329 if(definition->reloading_shape!=NONE)
3330 {
3331 high_level_data= get_shape_animation_data(BUILD_DESCRIPTOR(definition->collection,
3332 definition->reloading_shape));
3333 prevent_wrap= true;
3334 } else {
3335 trigger->sequence= 0;
3336 }
3337 break;
3338
3339 default:
3340 trigger->sequence= 0;
3341 break;
3342 }
3343
3344 if(high_level_data)
3345 {
3346 short frame, phase;
3347
3348 frame= GET_SEQUENCE_FRAME(trigger->sequence);
3349 phase= GET_SEQUENCE_PHASE(trigger->sequence);
3350
3351 if(++phase>=high_level_data->ticks_per_frame)
3352 {
3353 if(++frame>=high_level_data->frames_per_view)
3354 {
3355 /* Gross hack, but necessary due to weapons synchronicity problems. */
3356 if(prevent_wrap)
3357 {
3358 frame--;
3359 frame = MAX(frame,0);
3360 /*
3361 frame--;
3362 assert(trigger->phase==1);
3363 assert(frame>=0);
3364 */
3365 } else {
3366 frame= 0;
3367 }
3368 }
3369
3370 /* Play the keyframe sound. */
3371 if(frame==high_level_data->key_frame)
3372 {
3373 play_weapon_sound(player_index, sound_id, pitch);
3374 }
3375
3376 phase= 0;
3377 }
3378 trigger->sequence= BUILD_SEQUENCE(frame, phase);
3379 }
3380 }
3381
blow_up_player(short player_index)3382 static void blow_up_player(
3383 short player_index)
3384 {
3385 struct player_data *player= get_player_data(player_index);
3386 struct object_data *object= get_object_data(player->object_index);
3387
3388 detonate_projectile(&object->location, object->polygon, _projectile_overloaded_fusion_dispersal,
3389 player->monster_index, _monster_marine, FIXED_ONE);
3390 }
3391
get_weapon_data_type_for_count(short player_index,short count,short * type,short * index,short * flags)3392 static bool get_weapon_data_type_for_count(
3393 short player_index,
3394 short count,
3395 short *type,
3396 short *index,
3397 short *flags)
3398 {
3399 struct weapon_definition *definition= get_current_weapon_definition(player_index);
3400 struct weapon_data *weapon= get_player_current_weapon(player_index);
3401 bool valid= true;
3402
3403 *flags= 0;
3404 *type= NONE;
3405 *index= NONE;
3406
3407 if ((definition->flags & _weapon_is_marathon_1) &&
3408 (definition == get_weapon_definition(_weapon_missile_launcher)) &&
3409 weapon->triggers[_primary_weapon].rounds_loaded)
3410 {
3411 if (count == 0)
3412 {
3413 *type= _weapon_ammo_type;
3414 *index= _primary_weapon;
3415 return true;
3416 }
3417 count -= 1;
3418 }
3419
3420 switch(definition->weapon_class)
3421 {
3422 case _normal_class:
3423 switch(count)
3424 {
3425 case 0:
3426 *type= _weapon_type;
3427 *index= _primary_weapon;
3428 break;
3429 default:
3430 *type= _shell_casing_type;
3431 *index= count-1;
3432 valid= get_shell_casing_display_data((struct weapon_display_information *) NULL, *index);
3433 break;
3434 }
3435 break;
3436
3437 case _multipurpose_class:
3438 switch(count)
3439 {
3440 case 0:
3441 *type= _weapon_type;
3442 if(definition->flags & _weapon_secondary_has_angular_flipping)
3443 {
3444 switch(weapon->triggers[_secondary_weapon].state)
3445 {
3446 case _weapon_idle:
3447 if(automatic_still_firing(player_index, _secondary_weapon))
3448 {
3449 *index= _secondary_weapon;
3450 } else {
3451 *index= _primary_weapon;
3452 }
3453 break;
3454
3455 case _weapon_firing:
3456 case _weapon_recovering:
3457 *index= _secondary_weapon;
3458 break;
3459
3460 default:
3461 *index= _primary_weapon;
3462 break;
3463 }
3464 } else {
3465 *index= _primary_weapon;
3466 }
3467 break;
3468
3469 default:
3470 *type= _shell_casing_type;
3471 *index= count-1;
3472 valid= get_shell_casing_display_data((struct weapon_display_information *) NULL, *index);
3473 break;
3474 }
3475 break;
3476
3477 case _dual_function_class:
3478 switch(count)
3479 {
3480 case 0:
3481 *type= _weapon_type;
3482 if(dual_function_secondary_has_control(player_index))
3483 {
3484 *index= _secondary_weapon;
3485 } else {
3486 *index= _primary_weapon;
3487 }
3488 break;
3489
3490 default:
3491 *type= _shell_casing_type;
3492 *index= count-1;
3493 valid= get_shell_casing_display_data((struct weapon_display_information *) NULL, *index);
3494 break;
3495 }
3496 break;
3497
3498 case _melee_class:
3499 case _twofisted_pistol_class:
3500 {
3501 struct player_data *player= get_player_data(player_index);
3502
3503 if(player->items[definition->item_type]>1 &&
3504 PRIMARY_WEAPON_IS_VALID(weapon) && SECONDARY_WEAPON_IS_VALID(weapon))
3505 {
3506 switch(count)
3507 {
3508 case 0: *type= _weapon_type; *index= _primary_weapon; break;
3509 case 1: *type= _weapon_type; *index= _secondary_weapon; *flags |= _flip_shape_horizontal; break;
3510 default:
3511 *type= _shell_casing_type;
3512 *index= count-2;
3513 valid= get_shell_casing_display_data((struct weapon_display_information *) NULL, *index);
3514 break;
3515 }
3516 } else {
3517 /* Only have one up */
3518 switch(count)
3519 {
3520 case 0:
3521 *type= _weapon_type;
3522 if(SECONDARY_WEAPON_IS_VALID(weapon))
3523 {
3524 *index= _secondary_weapon;
3525 *flags |= _flip_shape_horizontal;
3526 } else {
3527 *index= _primary_weapon;
3528 }
3529 break;
3530
3531 default:
3532 *type= _shell_casing_type;
3533 *index= count-1;
3534 valid= get_shell_casing_display_data((struct weapon_display_information *) NULL, *index);
3535 break;
3536 }
3537 }
3538 }
3539 break;
3540
3541 // LP change: no weapon
3542 case NONE:
3543 default:
3544 break;
3545 }
3546
3547 return valid;
3548 }
3549
update_player_ammo_count(short player_index)3550 static void update_player_ammo_count(
3551 short player_index)
3552 {
3553 if(player_index==current_player_index)
3554 {
3555 mark_ammo_display_as_dirty();
3556 }
3557 }
3558
3559 extern bool LuaPlayerCanWieldWeapons(short);
3560
player_has_valid_weapon(short player_index)3561 /*static*/ bool player_has_valid_weapon(
3562 short player_index)
3563 {
3564 // LP change:
3565 if (CannotWieldWeapons() || !LuaPlayerCanWieldWeapons(player_index)) return false;
3566
3567 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
3568
3569 return (player_weapons->current_weapon!=NONE);
3570 }
3571
idle_weapon(short player_index)3572 static void idle_weapon(
3573 short player_index)
3574 {
3575 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
3576
3577 if(player_weapons->desired_weapon != player_weapons->current_weapon)
3578 {
3579 if(player_weapons->current_weapon==NONE)
3580 {
3581 change_to_desired_weapon(player_index);
3582 } else {
3583 struct weapon_data *weapon= get_player_current_weapon(player_index);
3584 short active_triggers, which_trigger, first_trigger;
3585 bool should_change= true;
3586
3587 active_triggers= get_active_trigger_count_and_states(player_index,
3588 player_weapons->current_weapon, 0l, &first_trigger, NULL);
3589
3590 for(which_trigger= first_trigger; which_trigger<active_triggers; ++which_trigger)
3591 {
3592 switch(weapon->triggers[which_trigger].state)
3593 {
3594 case _weapon_idle:
3595 case _weapon_raising:
3596 break;
3597
3598 case _weapon_waiting_to_load:
3599 {
3600 struct weapon_definition *definition= get_weapon_definition(player_weapons->current_weapon);
3601
3602 if(definition->reloading_shape==NONE)
3603 {
3604 /* Allow them to change if it is completely offscreen */
3605 weapon->triggers[_primary_weapon].state= _weapon_lowering;
3606 weapon->triggers[_primary_weapon].phase= 1;
3607 weapon->triggers[_primary_weapon].sequence= 0;
3608
3609 weapon->triggers[_secondary_weapon].state= _weapon_lowering;
3610 weapon->triggers[_secondary_weapon].phase= 1;
3611 weapon->triggers[_secondary_weapon].sequence= 0;
3612 } else {
3613 should_change= false;
3614 }
3615 }
3616 break;
3617
3618 default:
3619 should_change= false;
3620 break;
3621 }
3622 }
3623
3624 if(should_change)
3625 {
3626 lower_weapon(player_index, player_weapons->current_weapon);
3627 }
3628 }
3629 }
3630 else /* desired==current */
3631 {
3632 if(player_weapons->current_weapon!=NONE)
3633 {
3634 struct weapon_data *weapon= get_player_current_weapon(player_index);
3635 short active_triggers, which_trigger, first_trigger;
3636 bool should_change= true;
3637
3638 active_triggers= get_active_trigger_count_and_states(player_index,
3639 player_weapons->current_weapon, 0l, &first_trigger, NULL);
3640
3641 for(which_trigger= first_trigger; which_trigger<active_triggers; ++which_trigger)
3642 {
3643 switch(weapon->triggers[which_trigger].state)
3644 {
3645 case _weapon_lowering:
3646 break;
3647
3648 default:
3649 should_change= false;
3650 break;
3651 }
3652 }
3653
3654 /* They switched back to this weapon... */
3655 if(should_change)
3656 {
3657 raise_weapon(player_index, player_weapons->current_weapon);
3658 } else {
3659 struct weapon_definition *definition= get_current_weapon_definition(player_index);
3660
3661 /* Check for double weapon activation... */
3662 if(definition->weapon_class==_twofisted_pistol_class ||
3663 definition->weapon_class==_melee_class)
3664 {
3665 if(WEAPON_WANTS_TWOFIST(weapon))
3666 {
3667 should_change= true;
3668
3669 /* Start raising the other one.. */
3670 for(which_trigger= first_trigger; which_trigger<active_triggers; ++which_trigger)
3671 {
3672 switch(weapon->triggers[which_trigger].state)
3673 {
3674 case _weapon_idle:
3675 break;
3676
3677 default:
3678 should_change= false;
3679 break;
3680 }
3681 }
3682
3683 if(should_change)
3684 {
3685 short moving_weapon, raising_weapon;
3686
3687 if(!PRIMARY_WEAPON_IS_VALID(weapon))
3688 {
3689 /* Raise the primary.. */
3690 moving_weapon= _secondary_weapon;
3691 raising_weapon= _primary_weapon;
3692 SET_PRIMARY_WEAPON_IS_VALID(weapon, true);
3693 // dprintf("Prim up TF;g");
3694 } else {
3695 assert(!SECONDARY_WEAPON_IS_VALID(weapon));
3696 moving_weapon= _primary_weapon;
3697 raising_weapon= _secondary_weapon;
3698 SET_SECONDARY_WEAPON_IS_VALID(weapon, true);
3699 // dprintf("Second up TF;g");
3700 }
3701
3702 /* Raise the secondary.. */
3703 weapon->triggers[moving_weapon].state= _weapon_sliding_over_to_second_position;
3704 weapon->triggers[raising_weapon].state= _weapon_raising;
3705 weapon->triggers[moving_weapon].phase= definition->ready_ticks;
3706 weapon->triggers[raising_weapon].phase= definition->ready_ticks;
3707 SET_WEAPON_WANTS_TWOFIST(weapon, false);
3708 }
3709 }
3710 }
3711 }
3712 }
3713 }
3714 }
3715
3716 /* We are requesting to raise the second pistol for a twofisted class... */
test_raise_double_weapon(short player_index,uint32 * action_flags)3717 static void test_raise_double_weapon(
3718 short player_index,
3719 uint32 *action_flags)
3720 {
3721 struct weapon_definition *definition= get_current_weapon_definition(player_index);
3722 struct player_data *player= get_player_data(player_index);
3723
3724 if(definition->weapon_class==_twofisted_pistol_class || (definition->weapon_class==_melee_class && !(definition->flags & _weapon_is_marathon_1)))
3725 {
3726 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
3727
3728 /* Don't switch if it isn't hte current & the desired weapon.. */
3729 if(player_weapons->desired_weapon==player_weapons->current_weapon)
3730 {
3731 struct weapon_data *weapon= get_player_current_weapon(player_index);
3732
3733 /* Only raise if they have more than one, and both aren't up.. */
3734 if(player->items[definition->item_type]>1)
3735 {
3736 if (((*action_flags) & _left_trigger_state) && !PRIMARY_WEAPON_IS_VALID(weapon))
3737 {
3738 struct player_data *player= get_player_data(player_index);
3739 struct trigger_definition *trigger_definition=
3740 get_player_trigger_definition(player_index, _primary_weapon);
3741
3742 assert(SECONDARY_WEAPON_IS_VALID(weapon));
3743
3744 /* Try to raise the secondary weapon.. */
3745 if(weapon->triggers[_primary_weapon].rounds_loaded ||
3746 trigger_definition->ammunition_type==NONE ||
3747 player->items[trigger_definition->ammunition_type]>0)
3748 {
3749 //dprintf("1 twofist;g");
3750 SET_WEAPON_WANTS_TWOFIST(weapon, true);
3751 (*action_flags) &= ~_left_trigger_state;
3752 }
3753 }
3754 else if (((*action_flags) & _right_trigger_state) && !SECONDARY_WEAPON_IS_VALID(weapon))
3755 {
3756 struct player_data *player= get_player_data(player_index);
3757 struct trigger_definition *trigger_definition=
3758 get_player_trigger_definition(player_index, _secondary_weapon);
3759
3760 assert(PRIMARY_WEAPON_IS_VALID(weapon));
3761
3762 /* Try to raise the primary weapon.. */
3763 if(weapon->triggers[_secondary_weapon].rounds_loaded ||
3764 trigger_definition->ammunition_type==NONE ||
3765 player->items[trigger_definition->ammunition_type]>0)
3766 {
3767 //dprintf("2 twofist;g");
3768 SET_WEAPON_WANTS_TWOFIST(weapon, true);
3769 (*action_flags) &= ~_right_trigger_state;
3770 }
3771 }
3772 }
3773 }
3774 }
3775 }
3776
change_to_desired_weapon(short player_index)3777 static void change_to_desired_weapon(
3778 short player_index)
3779 {
3780 struct player_weapon_data *player_weapons= get_player_weapon_data(player_index);
3781 struct weapon_definition *definition= get_weapon_definition(player_weapons->desired_weapon);
3782 short first_trigger = _primary_weapon, which_trigger, trigger_count = 1;
3783
3784 // dprintf("Changing!");
3785 assert(player_weapons->desired_weapon != player_weapons->current_weapon);
3786
3787 /* Reset this weapons flags */
3788 if(player_weapons->current_weapon!=NONE)
3789 {
3790 player_weapons->weapons[player_weapons->current_weapon].flags= 0;
3791 }
3792
3793 /* Reset the desired weapon flags. */
3794 player_weapons->weapons[player_weapons->desired_weapon].flags= 0;
3795
3796 /* Set the desired weapon. */
3797 player_weapons->current_weapon= player_weapons->desired_weapon;
3798
3799 /* How many triggers do I need to update? */
3800 switch(definition->weapon_class)
3801 {
3802 case _normal_class:
3803 first_trigger= _primary_weapon;
3804 trigger_count= 1;
3805 break;
3806
3807 case _multipurpose_class:
3808 case _dual_function_class:
3809 first_trigger= _primary_weapon;
3810 trigger_count= 2;
3811 break;
3812
3813 case _melee_class:
3814 case _twofisted_pistol_class:
3815 /* We only ever raise one of them. */
3816 /* If the first one has ammunition, we raise it. If they have */
3817 /* two of them, and the first one doesn't have ammunition, then */
3818 /* we raise the second one. */
3819 {
3820 struct player_data *player= get_player_data(player_index);
3821 if(player->items[definition->item_type]==1)
3822 {
3823 /* Only can raise the first one. */
3824 first_trigger= _primary_weapon;
3825 trigger_count= 1;
3826 } else {
3827 struct trigger_data *trigger= get_trigger_data(player_index,
3828 player_weapons->desired_weapon, _primary_weapon);
3829 struct trigger_definition *trigger_definition= get_trigger_definition(player_index,
3830 player_weapons->desired_weapon, _primary_weapon);
3831
3832 /* If it is loaded or we can load it... */
3833 if(trigger->rounds_loaded || trigger_definition->ammunition_type==NONE ||
3834 player->items[trigger_definition->ammunition_type]>0)
3835 {
3836 first_trigger= _primary_weapon;
3837 trigger_count= 1;
3838 // LP change: adding fallback in case this does not succeed
3839 } else if (get_trigger_data(player_index, player_weapons->desired_weapon, _secondary_weapon)->rounds_loaded) {
3840 // assert(get_trigger_data(player_index, player_weapons->desired_weapon, _secondary_weapon)->rounds_loaded);
3841 first_trigger= _secondary_weapon;
3842 trigger_count= 2;
3843 } else
3844 {
3845 first_trigger = _primary_weapon;
3846 trigger_count = 2;
3847 }
3848 }
3849 }
3850 break;
3851
3852 // LP change: no weapon
3853 case NONE:
3854 default:
3855 break;
3856 }
3857
3858 /* Essentially the same as raise weapon, but it is always a full sequence */
3859 for(which_trigger= first_trigger; which_trigger<trigger_count; ++which_trigger)
3860 {
3861 struct trigger_data *trigger= get_trigger_data(player_index, player_weapons->desired_weapon, which_trigger);
3862
3863 trigger->phase= definition->ready_ticks;
3864 trigger->state= _weapon_raising;
3865
3866 if(which_trigger==_primary_weapon)
3867 {
3868 SET_PRIMARY_WEAPON_IS_VALID(&player_weapons->weapons[player_weapons->desired_weapon], true);
3869 } else {
3870 SET_SECONDARY_WEAPON_IS_VALID(&player_weapons->weapons[player_weapons->desired_weapon], true);
3871 }
3872
3873 /* if it has no ammunition, load it- only if it has an offscreen reload. */
3874 if(!trigger->rounds_loaded && definition->reloading_shape==NONE)
3875 {
3876 struct trigger_definition *trigger_definition=
3877 get_trigger_definition(player_index, player_weapons->current_weapon, which_trigger);
3878 struct player_data *player= get_player_data(player_index);
3879
3880 if(player->items[trigger_definition->ammunition_type] > 0)
3881 {
3882 put_rounds_into_weapon(player_index, player_weapons->current_weapon, which_trigger);
3883 }
3884 }
3885 }
3886 }
3887
automatic_still_firing(short player_index,short which_trigger)3888 static bool automatic_still_firing(
3889 short player_index,
3890 short which_trigger)
3891 {
3892 bool still_firing= false;
3893 struct weapon_data *weapon= get_player_current_weapon(player_index);
3894 struct weapon_definition *definition= get_weapon_definition(weapon->weapon_type);
3895
3896 if(which_trigger==_primary_weapon ||
3897 (which_trigger==_secondary_weapon && (definition->flags & _weapon_secondary_has_angular_flipping)))
3898 {
3899 assert(weapon->triggers[which_trigger].state==_weapon_idle);
3900 if(definition->flags & _weapon_is_automatic)
3901 {
3902 if(TRIGGER_IS_DOWN(weapon) && weapon->triggers[which_trigger].ticks_since_last_shot<AUTOMATIC_STILL_FIRING_DURATION)
3903 {
3904 still_firing= true;
3905 }
3906 }
3907 }
3908
3909 return still_firing;
3910 }
3911
play_shell_casing_sound(short player_index,short sound_index)3912 static void play_shell_casing_sound(
3913 short player_index,
3914 short sound_index)
3915 {
3916 struct player_data *player= get_player_data(player_index);
3917
3918 if (!(player->variables.flags&_FEET_BELOW_MEDIA_BIT))
3919 {
3920 struct world_location3d location;
3921
3922 location.point= player->camera_location;
3923 location.polygon_index= player->camera_polygon_index;
3924 location.yaw= location.pitch= 0;
3925 location.velocity.i= location.velocity.j= location.velocity.k= 0;
3926
3927 SoundManager::instance()->PlaySound(sound_index, &location, NONE);
3928 }
3929 }
3930
find_weapon_power_index(short weapon_type)3931 static short find_weapon_power_index(
3932 short weapon_type)
3933 {
3934 if(weapon_type==NONE)
3935 return NONE;
3936 else {
3937 unsigned index;
3938 for (index=0; index<NUMBER_OF_WEAPONS; ++index) {
3939 if (weapon_type == weapon_ordering_array[index])
3940 break;
3941 }
3942 assert(index != NUMBER_OF_WEAPONS);
3943 return index;
3944 }
3945 }
3946
3947 /* ---------- shell casing stuff */
3948
initialize_shell_casings(short player_index)3949 static void initialize_shell_casings(
3950 short player_index)
3951 {
3952 short shell_casing_index;
3953 struct shell_casing_data *shell_casing;
3954
3955 for (shell_casing_index= 0, shell_casing= get_player_weapon_data(player_index)->shell_casings; shell_casing_index<MAXIMUM_SHELL_CASINGS; ++shell_casing_index, ++shell_casing)
3956 {
3957 MARK_SLOT_AS_FREE(shell_casing);
3958 }
3959 }
3960
new_shell_casing(short player_index,short type,uint16 flags)3961 static short new_shell_casing(
3962 short player_index,
3963 short type,
3964 uint16 flags)
3965 {
3966 short shell_casing_index;
3967 struct shell_casing_data *shell_casing;
3968
3969 for (shell_casing_index= 0, shell_casing= get_player_weapon_data(player_index)->shell_casings; shell_casing_index<MAXIMUM_SHELL_CASINGS; ++shell_casing_index, ++shell_casing)
3970 {
3971 if (SLOT_IS_FREE(shell_casing)) break;
3972 }
3973
3974 if (shell_casing_index==MAXIMUM_SHELL_CASINGS)
3975 {
3976 shell_casing_index= NONE;
3977 }
3978 else
3979 {
3980 struct shell_casing_definition *definition= get_shell_casing_definition(type);
3981
3982 shell_casing->type= type;
3983 shell_casing->flags= flags;
3984 shell_casing->x= definition->x0, shell_casing->y= definition->y0;
3985 shell_casing->vx= SHELL_CASING_IS_REVERSED(shell_casing) ? -definition->vx0 : definition->vx0, shell_casing->vy= definition->vy0;
3986
3987 shell_casing->frame= local_random()&7;
3988 shell_casing->x+= ((local_random()&0xff)*shell_casing->vx)>>9;
3989 shell_casing->y+= ((local_random()&0xff)*shell_casing->vy)>>9;
3990
3991 MARK_SLOT_AS_USED(shell_casing);
3992 }
3993
3994 return shell_casing_index;
3995 }
3996
update_shell_casings(short player_index)3997 static void update_shell_casings(
3998 short player_index)
3999 {
4000 short shell_casing_index;
4001 struct shell_casing_data *shell_casing;
4002
4003 for (shell_casing_index= 0, shell_casing= get_player_weapon_data(player_index)->shell_casings; shell_casing_index<MAXIMUM_SHELL_CASINGS; ++shell_casing_index, ++shell_casing)
4004 {
4005 if (SLOT_IS_USED(shell_casing))
4006 {
4007 struct shell_casing_definition *definition= get_shell_casing_definition(shell_casing->type);
4008
4009 shell_casing->x+= shell_casing->vx;
4010 shell_casing->y+= shell_casing->vy;
4011 shell_casing->vx+= SHELL_CASING_IS_REVERSED(shell_casing) ? -definition->dvx : definition->dvx;
4012 shell_casing->vy+= definition->dvy;
4013
4014 if (shell_casing->x>=FIXED_ONE || shell_casing->x<0)
4015 {
4016 MARK_SLOT_AS_FREE(shell_casing);
4017 }
4018 }
4019 }
4020 }
4021
get_shell_casing_display_data(struct weapon_display_information * display,short index)4022 static bool get_shell_casing_display_data(
4023 struct weapon_display_information *display,
4024 short index)
4025 {
4026 bool valid= false;
4027 short shell_casing_index;
4028 struct shell_casing_data *shell_casing;
4029
4030 for (shell_casing_index= 0, shell_casing= get_player_weapon_data(current_player_index)->shell_casings; shell_casing_index<MAXIMUM_SHELL_CASINGS; ++shell_casing_index, ++shell_casing)
4031 {
4032 if (SLOT_IS_USED(shell_casing))
4033 {
4034 if ((index-= 1)<0)
4035 {
4036 if (display)
4037 {
4038 struct shell_casing_definition *definition= get_shell_casing_definition(shell_casing->type);
4039 struct shape_animation_data *high_level_data=
4040 get_shape_animation_data(BUILD_DESCRIPTOR(definition->collection, definition->shape));
4041 // Skip over if the sequence is nonexistent
4042 if(!high_level_data) continue;
4043
4044 // animate it
4045 if ((shell_casing->frame+= 1)>=high_level_data->frames_per_view) shell_casing->frame= 0;
4046
4047 display->collection= definition->collection;
4048 display->shape_index = definition->shape;
4049 display->low_level_shape_index= high_level_data->low_level_shape_indexes[shell_casing->frame];
4050 display->flip_horizontal= display->flip_vertical= false;
4051 display->vertical_positioning_mode= display->horizontal_positioning_mode= _position_center;
4052 display->vertical_position= FIXED_ONE-shell_casing->y, display->horizontal_position= shell_casing->x;
4053 display->transfer_mode= _xfer_normal, display->transfer_phase= 0;
4054
4055
4056 // LP: model animation data
4057 display->Frame = shell_casing->frame;
4058 display->NextFrame = display->Frame + 1;
4059 if (display->NextFrame >= high_level_data->frames_per_view)
4060 display->NextFrame = 0;
4061 // Apparently one frame per engine tick
4062 display->Phase = 0;
4063 display->Ticks = 1;
4064
4065 }
4066
4067 valid= true;
4068 break;
4069 }
4070 }
4071 }
4072
4073 return valid;
4074 }
4075
4076
StreamToTrigData(uint8 * & S,trigger_data & Object)4077 inline void StreamToTrigData(uint8* &S, trigger_data& Object)
4078 {
4079 StreamToValue(S,Object.state);
4080 StreamToValue(S,Object.phase);
4081 StreamToValue(S,Object.rounds_loaded);
4082 StreamToValue(S,Object.shots_fired);
4083 StreamToValue(S,Object.shots_hit);
4084 StreamToValue(S,Object.ticks_since_last_shot);
4085 StreamToValue(S,Object.ticks_firing);
4086 StreamToValue(S,Object.sequence);
4087 }
4088
TrigDataToStream(uint8 * & S,trigger_data & Object)4089 inline void TrigDataToStream(uint8* &S, trigger_data& Object)
4090 {
4091 ValueToStream(S,Object.state);
4092 ValueToStream(S,Object.phase);
4093 ValueToStream(S,Object.rounds_loaded);
4094 ValueToStream(S,Object.shots_fired);
4095 ValueToStream(S,Object.shots_hit);
4096 ValueToStream(S,Object.ticks_since_last_shot);
4097 ValueToStream(S,Object.ticks_firing);
4098 ValueToStream(S,Object.sequence);
4099 }
4100
4101
StreamToWeapData(uint8 * & S,weapon_data & Object)4102 inline void StreamToWeapData(uint8* &S, weapon_data& Object)
4103 {
4104 StreamToValue(S,Object.weapon_type);
4105 StreamToValue(S,Object.flags);
4106 StreamToValue(S,Object.unused);
4107 for (int k=0; k<NUMBER_OF_TRIGGERS; k++)
4108 StreamToTrigData(S,Object.triggers[k]);
4109 }
4110
WeapDataToStream(uint8 * & S,weapon_data & Object)4111 inline void WeapDataToStream(uint8* &S, weapon_data& Object)
4112 {
4113 ValueToStream(S,Object.weapon_type);
4114 ValueToStream(S,Object.flags);
4115 ValueToStream(S,Object.unused);
4116 for (int k=0; k<NUMBER_OF_TRIGGERS; k++)
4117 TrigDataToStream(S,Object.triggers[k]);
4118 }
4119
4120
StreamToShellData(uint8 * & S,shell_casing_data & Object)4121 inline void StreamToShellData(uint8* &S, shell_casing_data& Object)
4122 {
4123 StreamToValue(S,Object.type);
4124 StreamToValue(S,Object.frame);
4125
4126 StreamToValue(S,Object.flags);
4127
4128 StreamToValue(S,Object.x);
4129 StreamToValue(S,Object.y);
4130 StreamToValue(S,Object.vx);
4131 StreamToValue(S,Object.vy);
4132 }
4133
ShellDataToStream(uint8 * & S,shell_casing_data & Object)4134 inline void ShellDataToStream(uint8* &S, shell_casing_data& Object)
4135 {
4136 ValueToStream(S,Object.type);
4137 ValueToStream(S,Object.frame);
4138
4139 ValueToStream(S,Object.flags);
4140
4141 ValueToStream(S,Object.x);
4142 ValueToStream(S,Object.y);
4143 ValueToStream(S,Object.vx);
4144 ValueToStream(S,Object.vy);
4145 }
4146
4147
unpack_player_weapon_data(uint8 * Stream,size_t Count)4148 uint8 *unpack_player_weapon_data(uint8 *Stream, size_t Count)
4149 {
4150 uint8* S = Stream;
4151 player_weapon_data* ObjPtr = player_weapons_array;
4152
4153 for (size_t k = 0; k < Count; k++, ObjPtr++)
4154 {
4155 StreamToValue(S,ObjPtr->current_weapon);
4156 StreamToValue(S,ObjPtr->desired_weapon);
4157 for (unsigned m=0; m<NUMBER_OF_WEAPONS; m++)
4158 StreamToWeapData(S,ObjPtr->weapons[m]);
4159 for (unsigned m=0; m<MAXIMUM_SHELL_CASINGS; m++)
4160 StreamToShellData(S,ObjPtr->shell_casings[m]);
4161 }
4162 assert((S - Stream) == static_cast<ptrdiff_t>(Count*SIZEOF_player_weapon_data));
4163 return S;
4164 }
4165
pack_player_weapon_data(uint8 * Stream,size_t Count)4166 uint8 *pack_player_weapon_data(uint8 *Stream, size_t Count)
4167 {
4168 uint8* S = Stream;
4169 player_weapon_data* ObjPtr = player_weapons_array;
4170
4171 for (size_t k = 0; k < Count; k++, ObjPtr++)
4172 {
4173 ValueToStream(S,ObjPtr->current_weapon);
4174 ValueToStream(S,ObjPtr->desired_weapon);
4175 for (size_t m=0; m<NUMBER_OF_WEAPONS; m++)
4176 WeapDataToStream(S,ObjPtr->weapons[m]);
4177 for (size_t m=0; m<MAXIMUM_SHELL_CASINGS; m++)
4178 ShellDataToStream(S,ObjPtr->shell_casings[m]);
4179 }
4180 assert((S - Stream) == static_cast<ptrdiff_t>(Count*SIZEOF_player_weapon_data));
4181 return S;
4182 }
4183
StreamToTrigDefData(uint8 * & S,trigger_definition & Object)4184 inline void StreamToTrigDefData(uint8* &S, trigger_definition& Object)
4185 {
4186 StreamToValue(S,Object.rounds_per_magazine);
4187 StreamToValue(S,Object.ammunition_type);
4188 StreamToValue(S,Object.ticks_per_round);
4189 StreamToValue(S,Object.recovery_ticks);
4190 StreamToValue(S,Object.charging_ticks);
4191 StreamToValue(S,Object.recoil_magnitude);
4192 StreamToValue(S,Object.firing_sound);
4193 StreamToValue(S,Object.click_sound);
4194 StreamToValue(S,Object.charging_sound);
4195 StreamToValue(S,Object.shell_casing_sound);
4196 StreamToValue(S,Object.reloading_sound);
4197 StreamToValue(S,Object.charged_sound);
4198 StreamToValue(S,Object.projectile_type);
4199 StreamToValue(S,Object.theta_error);
4200 StreamToValue(S,Object.dx);
4201 StreamToValue(S,Object.dz);
4202 StreamToValue(S,Object.shell_casing_type);
4203 StreamToValue(S,Object.burst_count);
4204 Object.sound_activation_range = 0;
4205 }
4206
TrigDefDataToStream(uint8 * & S,trigger_definition & Object)4207 inline void TrigDefDataToStream(uint8* &S, trigger_definition& Object)
4208 {
4209 ValueToStream(S,Object.rounds_per_magazine);
4210 ValueToStream(S,Object.ammunition_type);
4211 ValueToStream(S,Object.ticks_per_round);
4212 ValueToStream(S,Object.recovery_ticks);
4213 ValueToStream(S,Object.charging_ticks);
4214 ValueToStream(S,Object.recoil_magnitude);
4215 ValueToStream(S,Object.firing_sound);
4216 ValueToStream(S,Object.click_sound);
4217 ValueToStream(S,Object.charging_sound);
4218 ValueToStream(S,Object.shell_casing_sound);
4219 ValueToStream(S,Object.reloading_sound);
4220 ValueToStream(S,Object.charged_sound);
4221 ValueToStream(S,Object.projectile_type);
4222 ValueToStream(S,Object.theta_error);
4223 ValueToStream(S,Object.dx);
4224 ValueToStream(S,Object.dz);
4225 ValueToStream(S,Object.shell_casing_type);
4226 ValueToStream(S,Object.burst_count);
4227 }
4228
4229
unpack_weapon_definition(uint8 * Stream,size_t Count)4230 uint8 *unpack_weapon_definition(uint8 *Stream, size_t Count)
4231 {
4232 return unpack_weapon_definition(Stream,weapon_definitions,Count);
4233 }
4234
unpack_weapon_definition(uint8 * Stream,weapon_definition * Objects,size_t Count)4235 uint8 *unpack_weapon_definition(uint8 *Stream, weapon_definition *Objects, size_t Count)
4236 {
4237 uint8* S = Stream;
4238 weapon_definition* ObjPtr = Objects;
4239
4240 for (size_t k = 0; k < Count; k++, ObjPtr++)
4241 {
4242 StreamToValue(S,ObjPtr->item_type);
4243 StreamToValue(S,ObjPtr->powerup_type);
4244 StreamToValue(S,ObjPtr->weapon_class);
4245 StreamToValue(S,ObjPtr->flags);
4246
4247 StreamToValue(S,ObjPtr->firing_light_intensity);
4248 StreamToValue(S,ObjPtr->firing_intensity_decay_ticks);
4249
4250 StreamToValue(S,ObjPtr->idle_height);
4251 StreamToValue(S,ObjPtr->bob_amplitude);
4252 StreamToValue(S,ObjPtr->kick_height);
4253 StreamToValue(S,ObjPtr->reload_height);
4254 StreamToValue(S,ObjPtr->idle_width);
4255 StreamToValue(S,ObjPtr->horizontal_amplitude);
4256
4257 StreamToValue(S,ObjPtr->collection);
4258 StreamToValue(S,ObjPtr->idle_shape);
4259 StreamToValue(S,ObjPtr->firing_shape);
4260 StreamToValue(S,ObjPtr->reloading_shape);
4261 StreamToValue(S,ObjPtr->unused);
4262 StreamToValue(S,ObjPtr->charging_shape);
4263 StreamToValue(S,ObjPtr->charged_shape);
4264
4265 StreamToValue(S,ObjPtr->ready_ticks);
4266 StreamToValue(S,ObjPtr->await_reload_ticks);
4267 StreamToValue(S,ObjPtr->loading_ticks);
4268 StreamToValue(S,ObjPtr->finish_loading_ticks);
4269 StreamToValue(S,ObjPtr->powerup_ticks);
4270
4271 for (int m=0; m<NUMBER_OF_TRIGGERS; m++)
4272 StreamToTrigDefData(S,ObjPtr->weapons_by_trigger[m]);
4273 }
4274 assert((S - Stream) == static_cast<ptrdiff_t>(Count*SIZEOF_weapon_definition));
4275 return S;
4276 }
4277
unpack_m1_weapon_definition(uint8 * Stream,size_t Count)4278 uint8* unpack_m1_weapon_definition(uint8* Stream, size_t Count)
4279 {
4280 uint8* S = Stream;
4281 weapon_definition* ObjPtr = weapon_definitions;
4282
4283 for (size_t k = 0; k < Count; k++, ObjPtr++)
4284 {
4285 StreamToValue(S,ObjPtr->item_type);
4286 ObjPtr->powerup_type = NONE;
4287 StreamToValue(S,ObjPtr->weapon_class);
4288 StreamToValue(S,ObjPtr->flags);
4289
4290 trigger_definition& Trigger0 = ObjPtr->weapons_by_trigger[0];
4291 trigger_definition& Trigger1 = ObjPtr->weapons_by_trigger[1];
4292
4293 StreamToValue(S, Trigger0.ammunition_type);
4294 StreamToValue(S, Trigger0.rounds_per_magazine);
4295 StreamToValue(S, Trigger1.ammunition_type);
4296 StreamToValue(S, Trigger1.rounds_per_magazine);
4297
4298 StreamToValue(S,ObjPtr->firing_light_intensity);
4299 StreamToValue(S,ObjPtr->firing_intensity_decay_ticks);
4300
4301 StreamToValue(S,ObjPtr->idle_height);
4302 StreamToValue(S,ObjPtr->bob_amplitude);
4303 StreamToValue(S,ObjPtr->kick_height);
4304 StreamToValue(S,ObjPtr->reload_height);
4305 StreamToValue(S,ObjPtr->idle_width);
4306 StreamToValue(S,ObjPtr->horizontal_amplitude);
4307
4308 StreamToValue(S,ObjPtr->collection);
4309 StreamToValue(S,ObjPtr->idle_shape);
4310 StreamToValue(S,ObjPtr->firing_shape);
4311 StreamToValue(S,ObjPtr->reloading_shape);
4312 StreamToValue(S, ObjPtr->unused);
4313 StreamToValue(S,ObjPtr->charging_shape);
4314 StreamToValue(S,ObjPtr->charged_shape);
4315
4316 StreamToValue(S, Trigger0.ticks_per_round);
4317 StreamToValue(S, Trigger1.ticks_per_round);
4318
4319 StreamToValue(S,ObjPtr->await_reload_ticks);
4320 StreamToValue(S,ObjPtr->ready_ticks);
4321 ObjPtr->loading_ticks = 0;
4322 ObjPtr->finish_loading_ticks = 0;
4323
4324 StreamToValue(S, Trigger0.recovery_ticks);
4325 StreamToValue(S, Trigger1.recovery_ticks);
4326 StreamToValue(S, Trigger0.charging_ticks);
4327 StreamToValue(S, Trigger1.charging_ticks);
4328
4329 StreamToValue(S, Trigger0.recoil_magnitude);
4330 StreamToValue(S, Trigger1.recoil_magnitude);
4331
4332 StreamToValue(S, Trigger0.firing_sound);
4333 StreamToValue(S, Trigger1.firing_sound);
4334 StreamToValue(S, Trigger0.click_sound);
4335 StreamToValue(S, Trigger1.click_sound);
4336
4337 StreamToValue(S, Trigger0.reloading_sound);
4338 Trigger1.reloading_sound = NONE;
4339
4340 StreamToValue(S, Trigger0.charging_sound);
4341 Trigger1.charging_sound = Trigger0.charging_sound;
4342
4343 StreamToValue(S, Trigger0.shell_casing_sound);
4344 StreamToValue(S, Trigger1.shell_casing_sound);
4345
4346 StreamToValue(S, Trigger0.sound_activation_range);
4347 StreamToValue(S, Trigger1.sound_activation_range);
4348
4349 StreamToValue(S, Trigger0.projectile_type);
4350 StreamToValue(S, Trigger1.projectile_type);
4351
4352 StreamToValue(S, Trigger0.theta_error);
4353 StreamToValue(S, Trigger1.theta_error);
4354
4355 StreamToValue(S, Trigger0.dx);
4356 StreamToValue(S, Trigger0.dz);
4357 StreamToValue(S, Trigger1.dx);
4358 StreamToValue(S, Trigger1.dz);
4359
4360 StreamToValue(S, Trigger0.burst_count);
4361 StreamToValue(S, Trigger1.burst_count);
4362
4363 S += 2; // instant reload tick
4364
4365 Trigger0.charged_sound = NONE;
4366 Trigger1.charged_sound = NONE;
4367 Trigger0.shell_casing_type = NONE;
4368 Trigger1.shell_casing_type = NONE;
4369
4370 if (ObjPtr->flags & _weapon_disappears_after_use_m1) {
4371 ObjPtr->flags |= _weapon_disappears_after_use;
4372 ObjPtr->flags &= ~_weapon_disappears_after_use_m1;
4373 }
4374
4375 if (ObjPtr->weapon_class == _twofisted_pistol_class)
4376 {
4377 // Marathon's settings for trigger 1 are mostly empty
4378 ObjPtr->flags |= _weapon_fires_out_of_phase;
4379 int16 dx = Trigger1.dx;
4380 int16 dz = Trigger1.dz;
4381 Trigger1 = Trigger0;
4382 Trigger1.dx = dx;
4383 Trigger1.dz = dz;
4384 }
4385 else if (ObjPtr->weapon_class == _dual_function_class)
4386 {
4387 // triggers share ammo must have been
4388 // hard-coded for dual function weapons in
4389 // Marathon; also, Marathon 2 expects rounds
4390 // per magazine and ammunition type to match
4391 ObjPtr->flags |= _weapon_triggers_share_ammo;
4392 Trigger1.rounds_per_magazine = Trigger0.rounds_per_magazine;
4393 Trigger1.ammunition_type = Trigger0.ammunition_type;
4394
4395 }
4396
4397 // automatic weapons in Marathon flutter while firing
4398 if (ObjPtr->flags & _weapon_is_automatic)
4399 {
4400 ObjPtr->flags |= _weapon_flutters_while_firing;
4401 }
4402
4403 // this makes the TOZT render correctly, but we don't
4404 // want it to flutter so apply after the above statement
4405 if (Trigger0.recovery_ticks == 0)
4406 {
4407 ObjPtr->flags |= _weapon_is_automatic;
4408 }
4409
4410 // SPNKR doesn't have a firing shape, just use idle
4411 if (ObjPtr->firing_shape == NONE)
4412 {
4413 ObjPtr->firing_shape = ObjPtr->idle_shape;
4414 }
4415
4416 if (k == _weapon_alien_shotgun) {
4417 // is there a better way?
4418 ObjPtr->flags |= _weapon_has_random_ammo_on_pickup;
4419 }
4420
4421 ObjPtr->flags |= _weapon_is_marathon_1;
4422 }
4423 return S;
4424 }
4425
4426
pack_weapon_definition(uint8 * Stream,size_t Count)4427 uint8 *pack_weapon_definition(uint8 *Stream, size_t Count)
4428 {
4429 return pack_weapon_definition(Stream,weapon_definitions,Count);
4430 }
4431
pack_weapon_definition(uint8 * Stream,weapon_definition * Objects,size_t Count)4432 uint8 *pack_weapon_definition(uint8 *Stream, weapon_definition *Objects, size_t Count)
4433 {
4434 uint8* S = Stream;
4435 weapon_definition* ObjPtr = Objects;
4436
4437 for (size_t k = 0; k < Count; k++, ObjPtr++)
4438 {
4439 ValueToStream(S,ObjPtr->item_type);
4440 ValueToStream(S,ObjPtr->powerup_type);
4441 ValueToStream(S,ObjPtr->weapon_class);
4442 ValueToStream(S,ObjPtr->flags);
4443
4444 ValueToStream(S,ObjPtr->firing_light_intensity);
4445 ValueToStream(S,ObjPtr->firing_intensity_decay_ticks);
4446
4447 ValueToStream(S,ObjPtr->idle_height);
4448 ValueToStream(S,ObjPtr->bob_amplitude);
4449 ValueToStream(S,ObjPtr->kick_height);
4450 ValueToStream(S,ObjPtr->reload_height);
4451 ValueToStream(S,ObjPtr->idle_width);
4452 ValueToStream(S,ObjPtr->horizontal_amplitude);
4453
4454 ValueToStream(S,ObjPtr->collection);
4455 ValueToStream(S,ObjPtr->idle_shape);
4456 ValueToStream(S,ObjPtr->firing_shape);
4457 ValueToStream(S,ObjPtr->reloading_shape);
4458 ValueToStream(S,ObjPtr->unused);
4459 ValueToStream(S,ObjPtr->charging_shape);
4460 ValueToStream(S,ObjPtr->charged_shape);
4461
4462 ValueToStream(S,ObjPtr->ready_ticks);
4463 ValueToStream(S,ObjPtr->await_reload_ticks);
4464 ValueToStream(S,ObjPtr->loading_ticks);
4465 ValueToStream(S,ObjPtr->finish_loading_ticks);
4466 ValueToStream(S,ObjPtr->powerup_ticks);
4467
4468 for (int m=0; m<NUMBER_OF_TRIGGERS; m++)
4469 TrigDefDataToStream(S,ObjPtr->weapons_by_trigger[m]);
4470 }
4471 assert((S - Stream) == static_cast<ptrdiff_t>(Count*SIZEOF_weapon_definition));
4472 return S;
4473 }
4474
init_weapon_definitions()4475 void init_weapon_definitions()
4476 {
4477 memcpy(weapon_definitions, original_weapon_definitions, sizeof(weapon_definitions));
4478 }
4479
4480 // LP additions: get weapon-definition size and number of weapon types
get_number_of_weapon_types()4481 size_t get_number_of_weapon_types() {return NUMBER_OF_WEAPONS;}
4482
4483
4484 struct shell_casing_definition *original_shell_casing_definitions = NULL;
4485 int16 *original_weapon_ordering_array = NULL;
4486
reset_mml_weapons()4487 void reset_mml_weapons()
4488 {
4489 if (original_shell_casing_definitions) {
4490 for (unsigned i = 0; i < NUMBER_OF_SHELL_CASING_TYPES; i++)
4491 shell_casing_definitions[i] = original_shell_casing_definitions[i];
4492 free(original_shell_casing_definitions);
4493 original_shell_casing_definitions = NULL;
4494 }
4495
4496 if (original_weapon_ordering_array) {
4497 for (unsigned i = 0; i < NUMBER_OF_WEAPONS; i++)
4498 weapon_ordering_array[i] = original_weapon_ordering_array[i];
4499 free(original_weapon_ordering_array);
4500 original_weapon_ordering_array = NULL;
4501 }
4502 }
4503
parse_mml_weapons(const InfoTree & root)4504 void parse_mml_weapons(const InfoTree& root)
4505 {
4506 // back up old values first
4507 if (!original_shell_casing_definitions) {
4508 original_shell_casing_definitions = (struct shell_casing_definition *) malloc(sizeof(struct shell_casing_definition) * NUMBER_OF_SHELL_CASING_TYPES);
4509 assert(original_shell_casing_definitions);
4510 for (unsigned i = 0; i < NUMBER_OF_SHELL_CASING_TYPES; i++)
4511 original_shell_casing_definitions[i] = shell_casing_definitions[i];
4512 }
4513
4514 if (!original_weapon_ordering_array) {
4515 original_weapon_ordering_array = (int16 *) malloc(sizeof(int16) * NUMBER_OF_WEAPONS);
4516 assert(original_weapon_ordering_array);
4517 for (unsigned i = 0; i < NUMBER_OF_WEAPONS; i++)
4518 original_weapon_ordering_array[i] = weapon_ordering_array[i];
4519 }
4520
4521 BOOST_FOREACH(InfoTree casing, root.children_named("shell_casings"))
4522 {
4523 int16 index;
4524 if (!casing.read_indexed("index", index, NUMBER_OF_SHELL_CASING_TYPES))
4525 continue;
4526 shell_casing_definition& def = shell_casing_definitions[index];
4527
4528 casing.read_indexed("coll", def.collection, MAXIMUM_COLLECTIONS);
4529 casing.read_indexed("seq", def.shape, MAXIMUM_SHAPES_PER_COLLECTION);
4530 casing.read_fixed("x0", def.x0);
4531 casing.read_fixed("y0", def.y0);
4532 casing.read_fixed("vx0", def.vx0);
4533 casing.read_fixed("vy0", def.vy0);
4534 casing.read_fixed("dvx", def.dvx);
4535 casing.read_fixed("dvy", def.dvy);
4536 }
4537
4538 BOOST_FOREACH(InfoTree order, root.children_named("order"))
4539 {
4540 int16 index;
4541 if (!order.read_indexed("index", index, NUMBER_OF_WEAPONS))
4542 continue;
4543 order.read_indexed("weapon", weapon_ordering_array[index], NUMBER_OF_WEAPONS);
4544 }
4545 }
4546