diff options
Diffstat (limited to 'src/p_pspr.c')
-rw-r--r-- | src/p_pspr.c | 829 |
1 files changed, 829 insertions, 0 deletions
diff --git a/src/p_pspr.c b/src/p_pspr.c new file mode 100644 index 0000000..afac1fc --- /dev/null +++ b/src/p_pspr.c | |||
@@ -0,0 +1,829 @@ | |||
1 | /* Emacs style mode select -*- C++ -*- | ||
2 | *----------------------------------------------------------------------------- | ||
3 | * | ||
4 | * | ||
5 | * PrBoom: a Doom port merged with LxDoom and LSDLDoom | ||
6 | * based on BOOM, a modified and improved DOOM engine | ||
7 | * Copyright (C) 1999 by | ||
8 | * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman | ||
9 | * Copyright (C) 1999-2000 by | ||
10 | * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze | ||
11 | * Copyright 2005, 2006 by | ||
12 | * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||
27 | * 02111-1307, USA. | ||
28 | * | ||
29 | * DESCRIPTION: | ||
30 | * Weapon sprite animation, weapon objects. | ||
31 | * Action functions for weapons. | ||
32 | * | ||
33 | *-----------------------------------------------------------------------------*/ | ||
34 | |||
35 | #include "doomstat.h" | ||
36 | #include "r_main.h" | ||
37 | #include "p_map.h" | ||
38 | #include "p_inter.h" | ||
39 | #include "p_pspr.h" | ||
40 | #include "p_enemy.h" | ||
41 | #include "m_random.h" | ||
42 | #include "s_sound.h" | ||
43 | #include "sounds.h" | ||
44 | #include "d_event.h" | ||
45 | #include "r_demo.h" | ||
46 | |||
47 | #define LOWERSPEED (FRACUNIT*6) | ||
48 | #define RAISESPEED (FRACUNIT*6) | ||
49 | #define WEAPONBOTTOM (FRACUNIT*128) | ||
50 | #define WEAPONTOP (FRACUNIT*32) | ||
51 | |||
52 | #define BFGCELLS bfgcells /* Ty 03/09/98 externalized in p_inter.c */ | ||
53 | |||
54 | extern void P_Thrust(player_t *, angle_t, fixed_t); | ||
55 | |||
56 | // The following array holds the recoil values // phares | ||
57 | |||
58 | static const int recoil_values[] = { // phares | ||
59 | 10, // wp_fist | ||
60 | 10, // wp_pistol | ||
61 | 30, // wp_shotgun | ||
62 | 10, // wp_chaingun | ||
63 | 100,// wp_missile | ||
64 | 20, // wp_plasma | ||
65 | 100,// wp_bfg | ||
66 | 0, // wp_chainsaw | ||
67 | 80 // wp_supershotgun | ||
68 | }; | ||
69 | |||
70 | // | ||
71 | // P_SetPsprite | ||
72 | // | ||
73 | |||
74 | static void P_SetPsprite(player_t *player, int position, statenum_t stnum) | ||
75 | { | ||
76 | pspdef_t *psp = &player->psprites[position]; | ||
77 | |||
78 | do | ||
79 | { | ||
80 | state_t *state; | ||
81 | |||
82 | if (!stnum) | ||
83 | { | ||
84 | // object removed itself | ||
85 | psp->state = NULL; | ||
86 | break; | ||
87 | } | ||
88 | |||
89 | state = &states[stnum]; | ||
90 | psp->state = state; | ||
91 | psp->tics = state->tics; // could be 0 | ||
92 | |||
93 | if (state->misc1) | ||
94 | { | ||
95 | // coordinate set | ||
96 | psp->sx = state->misc1 << FRACBITS; | ||
97 | psp->sy = state->misc2 << FRACBITS; | ||
98 | } | ||
99 | |||
100 | // Call action routine. | ||
101 | // Modified handling. | ||
102 | if (state->action) | ||
103 | { | ||
104 | state->action(player, psp); | ||
105 | if (!psp->state) | ||
106 | break; | ||
107 | } | ||
108 | stnum = psp->state->nextstate; | ||
109 | } | ||
110 | while (!psp->tics); // an initial state of 0 could cycle through | ||
111 | } | ||
112 | |||
113 | // | ||
114 | // P_BringUpWeapon | ||
115 | // Starts bringing the pending weapon up | ||
116 | // from the bottom of the screen. | ||
117 | // Uses player | ||
118 | // | ||
119 | |||
120 | static void P_BringUpWeapon(player_t *player) | ||
121 | { | ||
122 | statenum_t newstate; | ||
123 | |||
124 | if (player->pendingweapon == wp_nochange) | ||
125 | player->pendingweapon = player->readyweapon; | ||
126 | |||
127 | if (player->pendingweapon == wp_chainsaw) | ||
128 | S_StartSound (player->mo, sfx_sawup); | ||
129 | |||
130 | newstate = weaponinfo[player->pendingweapon].upstate; | ||
131 | |||
132 | player->pendingweapon = wp_nochange; | ||
133 | // killough 12/98: prevent pistol from starting visibly at bottom of screen: | ||
134 | player->psprites[ps_weapon].sy = | ||
135 | mbf_features ? WEAPONBOTTOM+FRACUNIT*2 : WEAPONBOTTOM; | ||
136 | |||
137 | P_SetPsprite(player, ps_weapon, newstate); | ||
138 | } | ||
139 | |||
140 | // The first set is where the weapon preferences from // killough, | ||
141 | // default.cfg are stored. These values represent the keys used // phares | ||
142 | // in DOOM2 to bring up the weapon, i.e. 6 = plasma gun. These // | | ||
143 | // are NOT the wp_* constants. // V | ||
144 | |||
145 | int weapon_preferences[2][NUMWEAPONS+1] = { | ||
146 | {6, 9, 4, 3, 2, 8, 5, 7, 1, 0}, // !compatibility preferences | ||
147 | {6, 9, 4, 3, 2, 8, 5, 7, 1, 0}, // compatibility preferences | ||
148 | }; | ||
149 | |||
150 | // P_SwitchWeapon checks current ammo levels and gives you the | ||
151 | // most preferred weapon with ammo. It will not pick the currently | ||
152 | // raised weapon. When called from P_CheckAmmo this won't matter, | ||
153 | // because the raised weapon has no ammo anyway. When called from | ||
154 | // G_BuildTiccmd you want to toggle to a different weapon regardless. | ||
155 | |||
156 | int P_SwitchWeapon(player_t *player) | ||
157 | { | ||
158 | int *prefer = weapon_preferences[demo_compatibility!=0]; // killough 3/22/98 | ||
159 | int currentweapon = player->readyweapon; | ||
160 | int newweapon = currentweapon; | ||
161 | int i = NUMWEAPONS+1; // killough 5/2/98 | ||
162 | |||
163 | // killough 2/8/98: follow preferences and fix BFG/SSG bugs | ||
164 | |||
165 | do | ||
166 | switch (*prefer++) | ||
167 | { | ||
168 | case 1: | ||
169 | if (!player->powers[pw_strength]) // allow chainsaw override | ||
170 | break; | ||
171 | case 0: | ||
172 | newweapon = wp_fist; | ||
173 | break; | ||
174 | case 2: | ||
175 | if (player->ammo[am_clip]) | ||
176 | newweapon = wp_pistol; | ||
177 | break; | ||
178 | case 3: | ||
179 | if (player->weaponowned[wp_shotgun] && player->ammo[am_shell]) | ||
180 | newweapon = wp_shotgun; | ||
181 | break; | ||
182 | case 4: | ||
183 | if (player->weaponowned[wp_chaingun] && player->ammo[am_clip]) | ||
184 | newweapon = wp_chaingun; | ||
185 | break; | ||
186 | case 5: | ||
187 | if (player->weaponowned[wp_missile] && player->ammo[am_misl]) | ||
188 | newweapon = wp_missile; | ||
189 | break; | ||
190 | case 6: | ||
191 | if (player->weaponowned[wp_plasma] && player->ammo[am_cell] && | ||
192 | gamemode != shareware) | ||
193 | newweapon = wp_plasma; | ||
194 | break; | ||
195 | case 7: | ||
196 | if (player->weaponowned[wp_bfg] && gamemode != shareware && | ||
197 | player->ammo[am_cell] >= (demo_compatibility ? 41 : 40)) | ||
198 | newweapon = wp_bfg; | ||
199 | break; | ||
200 | case 8: | ||
201 | if (player->weaponowned[wp_chainsaw]) | ||
202 | newweapon = wp_chainsaw; | ||
203 | break; | ||
204 | case 9: | ||
205 | if (player->weaponowned[wp_supershotgun] && gamemode == commercial && | ||
206 | player->ammo[am_shell] >= (demo_compatibility ? 3 : 2)) | ||
207 | newweapon = wp_supershotgun; | ||
208 | break; | ||
209 | } | ||
210 | while (newweapon==currentweapon && --i); // killough 5/2/98 | ||
211 | return newweapon; | ||
212 | } | ||
213 | |||
214 | // killough 5/2/98: whether consoleplayer prefers weapon w1 over weapon w2. | ||
215 | int P_WeaponPreferred(int w1, int w2) | ||
216 | { | ||
217 | return | ||
218 | (weapon_preferences[0][0] != ++w2 && (weapon_preferences[0][0] == ++w1 || | ||
219 | (weapon_preferences[0][1] != w2 && (weapon_preferences[0][1] == w1 || | ||
220 | (weapon_preferences[0][2] != w2 && (weapon_preferences[0][2] == w1 || | ||
221 | (weapon_preferences[0][3] != w2 && (weapon_preferences[0][3] == w1 || | ||
222 | (weapon_preferences[0][4] != w2 && (weapon_preferences[0][4] == w1 || | ||
223 | (weapon_preferences[0][5] != w2 && (weapon_preferences[0][5] == w1 || | ||
224 | (weapon_preferences[0][6] != w2 && (weapon_preferences[0][6] == w1 || | ||
225 | (weapon_preferences[0][7] != w2 && (weapon_preferences[0][7] == w1 | ||
226 | )))))))))))))))); | ||
227 | } | ||
228 | |||
229 | // | ||
230 | // P_CheckAmmo | ||
231 | // Returns true if there is enough ammo to shoot. | ||
232 | // If not, selects the next weapon to use. | ||
233 | // (only in demo_compatibility mode -- killough 3/22/98) | ||
234 | // | ||
235 | |||
236 | boolean P_CheckAmmo(player_t *player) | ||
237 | { | ||
238 | ammotype_t ammo = weaponinfo[player->readyweapon].ammo; | ||
239 | int count = 1; // Regular | ||
240 | |||
241 | if (player->readyweapon == wp_bfg) // Minimal amount for one shot varies. | ||
242 | count = BFGCELLS; | ||
243 | else | ||
244 | if (player->readyweapon == wp_supershotgun) // Double barrel. | ||
245 | count = 2; | ||
246 | |||
247 | // Some do not need ammunition anyway. | ||
248 | // Return if current ammunition sufficient. | ||
249 | |||
250 | if (ammo == am_noammo || player->ammo[ammo] >= count) | ||
251 | return true; | ||
252 | |||
253 | // Out of ammo, pick a weapon to change to. | ||
254 | // | ||
255 | // killough 3/22/98: for old demos we do the switch here and now; | ||
256 | // for Boom games we cannot do this, and have different player | ||
257 | // preferences across demos or networks, so we have to use the | ||
258 | // G_BuildTiccmd() interface instead of making the switch here. | ||
259 | |||
260 | if (demo_compatibility) | ||
261 | { | ||
262 | player->pendingweapon = P_SwitchWeapon(player); // phares | ||
263 | // Now set appropriate weapon overlay. | ||
264 | P_SetPsprite(player,ps_weapon,weaponinfo[player->readyweapon].downstate); | ||
265 | } | ||
266 | |||
267 | return false; | ||
268 | } | ||
269 | |||
270 | // | ||
271 | // P_FireWeapon. | ||
272 | // | ||
273 | |||
274 | static void P_FireWeapon(player_t *player) | ||
275 | { | ||
276 | statenum_t newstate; | ||
277 | |||
278 | if (!P_CheckAmmo(player)) | ||
279 | return; | ||
280 | |||
281 | P_SetMobjState(player->mo, S_PLAY_ATK1); | ||
282 | newstate = weaponinfo[player->readyweapon].atkstate; | ||
283 | P_SetPsprite(player, ps_weapon, newstate); | ||
284 | P_NoiseAlert(player->mo, player->mo); | ||
285 | } | ||
286 | |||
287 | // | ||
288 | // P_DropWeapon | ||
289 | // Player died, so put the weapon away. | ||
290 | // | ||
291 | |||
292 | void P_DropWeapon(player_t *player) | ||
293 | { | ||
294 | P_SetPsprite(player, ps_weapon, weaponinfo[player->readyweapon].downstate); | ||
295 | } | ||
296 | |||
297 | // | ||
298 | // A_WeaponReady | ||
299 | // The player can fire the weapon | ||
300 | // or change to another weapon at this time. | ||
301 | // Follows after getting weapon up, | ||
302 | // or after previous attack/fire sequence. | ||
303 | // | ||
304 | |||
305 | void A_WeaponReady(player_t *player, pspdef_t *psp) | ||
306 | { | ||
307 | // get out of attack state | ||
308 | if (player->mo->state == &states[S_PLAY_ATK1] | ||
309 | || player->mo->state == &states[S_PLAY_ATK2] ) | ||
310 | P_SetMobjState(player->mo, S_PLAY); | ||
311 | |||
312 | if (player->readyweapon == wp_chainsaw && psp->state == &states[S_SAW]) | ||
313 | S_StartSound(player->mo, sfx_sawidl); | ||
314 | |||
315 | // check for change | ||
316 | // if player is dead, put the weapon away | ||
317 | |||
318 | if (player->pendingweapon != wp_nochange || !player->health) | ||
319 | { | ||
320 | // change weapon (pending weapon should already be validated) | ||
321 | statenum_t newstate = weaponinfo[player->readyweapon].downstate; | ||
322 | P_SetPsprite(player, ps_weapon, newstate); | ||
323 | return; | ||
324 | } | ||
325 | |||
326 | // check for fire | ||
327 | // the missile launcher and bfg do not auto fire | ||
328 | |||
329 | if (player->cmd.buttons & BT_ATTACK) | ||
330 | { | ||
331 | if (!player->attackdown || (player->readyweapon != wp_missile && | ||
332 | player->readyweapon != wp_bfg)) | ||
333 | { | ||
334 | player->attackdown = true; | ||
335 | P_FireWeapon(player); | ||
336 | return; | ||
337 | } | ||
338 | } | ||
339 | else | ||
340 | player->attackdown = false; | ||
341 | |||
342 | // bob the weapon based on movement speed | ||
343 | { | ||
344 | int angle = (128*leveltime) & FINEMASK; | ||
345 | psp->sx = FRACUNIT + FixedMul(player->bob, finecosine[angle]); | ||
346 | angle &= FINEANGLES/2-1; | ||
347 | psp->sy = WEAPONTOP + FixedMul(player->bob, finesine[angle]); | ||
348 | } | ||
349 | } | ||
350 | |||
351 | // | ||
352 | // A_ReFire | ||
353 | // The player can re-fire the weapon | ||
354 | // without lowering it entirely. | ||
355 | // | ||
356 | |||
357 | void A_ReFire(player_t *player, pspdef_t *psp) | ||
358 | { | ||
359 | // check for fire | ||
360 | // (if a weaponchange is pending, let it go through instead) | ||
361 | |||
362 | if ( (player->cmd.buttons & BT_ATTACK) | ||
363 | && player->pendingweapon == wp_nochange && player->health) | ||
364 | { | ||
365 | player->refire++; | ||
366 | P_FireWeapon(player); | ||
367 | } | ||
368 | else | ||
369 | { | ||
370 | player->refire = 0; | ||
371 | P_CheckAmmo(player); | ||
372 | } | ||
373 | } | ||
374 | |||
375 | void A_CheckReload(player_t *player, pspdef_t *psp) | ||
376 | { | ||
377 | if (!P_CheckAmmo(player) && compatibility_level >= prboom_4_compatibility) { | ||
378 | /* cph 2002/08/08 - In old Doom, P_CheckAmmo would start the weapon lowering | ||
379 | * immediately. This was lost in Boom when the weapon switching logic was | ||
380 | * rewritten. But we must tell Doom that we don't need to complete the | ||
381 | * reload frames for the weapon here. G_BuildTiccmd will set ->pendingweapon | ||
382 | * for us later on. */ | ||
383 | P_SetPsprite(player,ps_weapon,weaponinfo[player->readyweapon].downstate); | ||
384 | } | ||
385 | } | ||
386 | |||
387 | // | ||
388 | // A_Lower | ||
389 | // Lowers current weapon, | ||
390 | // and changes weapon at bottom. | ||
391 | // | ||
392 | |||
393 | void A_Lower(player_t *player, pspdef_t *psp) | ||
394 | { | ||
395 | psp->sy += LOWERSPEED; | ||
396 | |||
397 | // Is already down. | ||
398 | if (psp->sy < WEAPONBOTTOM) | ||
399 | return; | ||
400 | |||
401 | // Player is dead. | ||
402 | if (player->playerstate == PST_DEAD) | ||
403 | { | ||
404 | psp->sy = WEAPONBOTTOM; | ||
405 | return; // don't bring weapon back up | ||
406 | } | ||
407 | |||
408 | // The old weapon has been lowered off the screen, | ||
409 | // so change the weapon and start raising it | ||
410 | |||
411 | if (!player->health) | ||
412 | { // Player is dead, so keep the weapon off screen. | ||
413 | P_SetPsprite(player, ps_weapon, S_NULL); | ||
414 | return; | ||
415 | } | ||
416 | |||
417 | player->readyweapon = player->pendingweapon; | ||
418 | |||
419 | P_BringUpWeapon(player); | ||
420 | } | ||
421 | |||
422 | // | ||
423 | // A_Raise | ||
424 | // | ||
425 | |||
426 | void A_Raise(player_t *player, pspdef_t *psp) | ||
427 | { | ||
428 | statenum_t newstate; | ||
429 | |||
430 | psp->sy -= RAISESPEED; | ||
431 | |||
432 | if (psp->sy > WEAPONTOP) | ||
433 | return; | ||
434 | |||
435 | psp->sy = WEAPONTOP; | ||
436 | |||
437 | // The weapon has been raised all the way, | ||
438 | // so change to the ready state. | ||
439 | |||
440 | newstate = weaponinfo[player->readyweapon].readystate; | ||
441 | |||
442 | P_SetPsprite(player, ps_weapon, newstate); | ||
443 | } | ||
444 | |||
445 | |||
446 | // Weapons now recoil, amount depending on the weapon. // phares | ||
447 | // // | | ||
448 | // The P_SetPsprite call in each of the weapon firing routines // V | ||
449 | // was moved here so the recoil could be synched with the | ||
450 | // muzzle flash, rather than the pressing of the trigger. | ||
451 | // The BFG delay caused this to be necessary. | ||
452 | |||
453 | static void A_FireSomething(player_t* player,int adder) | ||
454 | { | ||
455 | P_SetPsprite(player, ps_flash, | ||
456 | weaponinfo[player->readyweapon].flashstate+adder); | ||
457 | |||
458 | // killough 3/27/98: prevent recoil in no-clipping mode | ||
459 | if (!(player->mo->flags & MF_NOCLIP)) | ||
460 | if (!compatibility && weapon_recoil) | ||
461 | P_Thrust(player, | ||
462 | ANG180+player->mo->angle, // ^ | ||
463 | 2048*recoil_values[player->readyweapon]); // | | ||
464 | } // phares | ||
465 | |||
466 | // | ||
467 | // A_GunFlash | ||
468 | // | ||
469 | |||
470 | void A_GunFlash(player_t *player, pspdef_t *psp) | ||
471 | { | ||
472 | P_SetMobjState(player->mo, S_PLAY_ATK2); | ||
473 | |||
474 | A_FireSomething(player,0); // phares | ||
475 | } | ||
476 | |||
477 | // | ||
478 | // WEAPON ATTACKS | ||
479 | // | ||
480 | |||
481 | // | ||
482 | // A_Punch | ||
483 | // | ||
484 | |||
485 | void A_Punch(player_t *player, pspdef_t *psp) | ||
486 | { | ||
487 | angle_t angle; | ||
488 | int t, slope, damage = (P_Random(pr_punch)%10+1)<<1; | ||
489 | |||
490 | if (player->powers[pw_strength]) | ||
491 | damage *= 10; | ||
492 | |||
493 | angle = player->mo->angle; | ||
494 | |||
495 | // killough 5/5/98: remove dependence on order of evaluation: | ||
496 | t = P_Random(pr_punchangle); | ||
497 | angle += (t - P_Random(pr_punchangle))<<18; | ||
498 | |||
499 | /* killough 8/2/98: make autoaiming prefer enemies */ | ||
500 | if (!mbf_features || | ||
501 | (slope = P_AimLineAttack(player->mo, angle, MELEERANGE, MF_FRIEND), | ||
502 | !linetarget)) | ||
503 | slope = P_AimLineAttack(player->mo, angle, MELEERANGE, 0); | ||
504 | |||
505 | P_LineAttack(player->mo, angle, MELEERANGE, slope, damage); | ||
506 | |||
507 | if (!linetarget) | ||
508 | return; | ||
509 | |||
510 | S_StartSound(player->mo, sfx_punch); | ||
511 | |||
512 | // turn to face target | ||
513 | |||
514 | player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, | ||
515 | linetarget->x, linetarget->y); | ||
516 | R_SmoothPlaying_Reset(player); // e6y | ||
517 | } | ||
518 | |||
519 | // | ||
520 | // A_Saw | ||
521 | // | ||
522 | |||
523 | void A_Saw(player_t *player, pspdef_t *psp) | ||
524 | { | ||
525 | int slope, damage = 2*(P_Random(pr_saw)%10+1); | ||
526 | angle_t angle = player->mo->angle; | ||
527 | // killough 5/5/98: remove dependence on order of evaluation: | ||
528 | int t = P_Random(pr_saw); | ||
529 | angle += (t - P_Random(pr_saw))<<18; | ||
530 | |||
531 | /* Use meleerange + 1 so that the puff doesn't skip the flash | ||
532 | * killough 8/2/98: make autoaiming prefer enemies */ | ||
533 | if (!mbf_features || | ||
534 | (slope = P_AimLineAttack(player->mo, angle, MELEERANGE+1, MF_FRIEND), | ||
535 | !linetarget)) | ||
536 | slope = P_AimLineAttack(player->mo, angle, MELEERANGE+1, 0); | ||
537 | |||
538 | P_LineAttack(player->mo, angle, MELEERANGE+1, slope, damage); | ||
539 | |||
540 | if (!linetarget) | ||
541 | { | ||
542 | S_StartSound(player->mo, sfx_sawful); | ||
543 | return; | ||
544 | } | ||
545 | |||
546 | S_StartSound(player->mo, sfx_sawhit); | ||
547 | |||
548 | // turn to face target | ||
549 | angle = R_PointToAngle2(player->mo->x, player->mo->y, | ||
550 | linetarget->x, linetarget->y); | ||
551 | |||
552 | if (angle - player->mo->angle > ANG180) { | ||
553 | if (angle - player->mo->angle < -ANG90/20) | ||
554 | player->mo->angle = angle + ANG90/21; | ||
555 | else | ||
556 | player->mo->angle -= ANG90/20; | ||
557 | } else { | ||
558 | if (angle - player->mo->angle > ANG90/20) | ||
559 | player->mo->angle = angle - ANG90/21; | ||
560 | else | ||
561 | player->mo->angle += ANG90/20; | ||
562 | } | ||
563 | |||
564 | player->mo->flags |= MF_JUSTATTACKED; | ||
565 | R_SmoothPlaying_Reset(player); // e6y | ||
566 | } | ||
567 | |||
568 | // | ||
569 | // A_FireMissile | ||
570 | // | ||
571 | |||
572 | void A_FireMissile(player_t *player, pspdef_t *psp) | ||
573 | { | ||
574 | player->ammo[weaponinfo[player->readyweapon].ammo]--; | ||
575 | P_SpawnPlayerMissile(player->mo, MT_ROCKET); | ||
576 | } | ||
577 | |||
578 | // | ||
579 | // A_FireBFG | ||
580 | // | ||
581 | |||
582 | void A_FireBFG(player_t *player, pspdef_t *psp) | ||
583 | { | ||
584 | player->ammo[weaponinfo[player->readyweapon].ammo] -= BFGCELLS; | ||
585 | P_SpawnPlayerMissile(player->mo, MT_BFG); | ||
586 | } | ||
587 | |||
588 | // | ||
589 | // A_FirePlasma | ||
590 | // | ||
591 | |||
592 | void A_FirePlasma(player_t *player, pspdef_t *psp) | ||
593 | { | ||
594 | player->ammo[weaponinfo[player->readyweapon].ammo]--; | ||
595 | |||
596 | A_FireSomething(player,P_Random(pr_plasma)&1); // phares | ||
597 | P_SpawnPlayerMissile(player->mo, MT_PLASMA); | ||
598 | } | ||
599 | |||
600 | // | ||
601 | // P_BulletSlope | ||
602 | // Sets a slope so a near miss is at aproximately | ||
603 | // the height of the intended target | ||
604 | // | ||
605 | |||
606 | static fixed_t bulletslope; | ||
607 | |||
608 | static void P_BulletSlope(mobj_t *mo) | ||
609 | { | ||
610 | angle_t an = mo->angle; // see which target is to be aimed at | ||
611 | |||
612 | /* killough 8/2/98: make autoaiming prefer enemies */ | ||
613 | uint_64_t mask = mbf_features ? MF_FRIEND : 0; | ||
614 | |||
615 | do | ||
616 | { | ||
617 | bulletslope = P_AimLineAttack(mo, an, 16*64*FRACUNIT, mask); | ||
618 | if (!linetarget) | ||
619 | bulletslope = P_AimLineAttack(mo, an += 1<<26, 16*64*FRACUNIT, mask); | ||
620 | if (!linetarget) | ||
621 | bulletslope = P_AimLineAttack(mo, an -= 2<<26, 16*64*FRACUNIT, mask); | ||
622 | } | ||
623 | while (mask && (mask=0, !linetarget)); /* killough 8/2/98 */ | ||
624 | } | ||
625 | |||
626 | // | ||
627 | // P_GunShot | ||
628 | // | ||
629 | |||
630 | static void P_GunShot(mobj_t *mo, boolean accurate) | ||
631 | { | ||
632 | int damage = 5*(P_Random(pr_gunshot)%3+1); | ||
633 | angle_t angle = mo->angle; | ||
634 | |||
635 | if (!accurate) | ||
636 | { // killough 5/5/98: remove dependence on order of evaluation: | ||
637 | int t = P_Random(pr_misfire); | ||
638 | angle += (t - P_Random(pr_misfire))<<18; | ||
639 | } | ||
640 | |||
641 | P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage); | ||
642 | } | ||
643 | |||
644 | // | ||
645 | // A_FirePistol | ||
646 | // | ||
647 | |||
648 | void A_FirePistol(player_t *player, pspdef_t *psp) | ||
649 | { | ||
650 | S_StartSound(player->mo, sfx_pistol); | ||
651 | |||
652 | P_SetMobjState(player->mo, S_PLAY_ATK2); | ||
653 | player->ammo[weaponinfo[player->readyweapon].ammo]--; | ||
654 | |||
655 | A_FireSomething(player,0); // phares | ||
656 | P_BulletSlope(player->mo); | ||
657 | P_GunShot(player->mo, !player->refire); | ||
658 | } | ||
659 | |||
660 | // | ||
661 | // A_FireShotgun | ||
662 | // | ||
663 | |||
664 | void A_FireShotgun(player_t *player, pspdef_t *psp) | ||
665 | { | ||
666 | int i; | ||
667 | |||
668 | S_StartSound(player->mo, sfx_shotgn); | ||
669 | P_SetMobjState(player->mo, S_PLAY_ATK2); | ||
670 | |||
671 | player->ammo[weaponinfo[player->readyweapon].ammo]--; | ||
672 | |||
673 | A_FireSomething(player,0); // phares | ||
674 | |||
675 | P_BulletSlope(player->mo); | ||
676 | |||
677 | for (i=0; i<7; i++) | ||
678 | P_GunShot(player->mo, false); | ||
679 | } | ||
680 | |||
681 | // | ||
682 | // A_FireShotgun2 | ||
683 | // | ||
684 | |||
685 | void A_FireShotgun2(player_t *player, pspdef_t *psp) | ||
686 | { | ||
687 | int i; | ||
688 | |||
689 | S_StartSound(player->mo, sfx_dshtgn); | ||
690 | P_SetMobjState(player->mo, S_PLAY_ATK2); | ||
691 | player->ammo[weaponinfo[player->readyweapon].ammo] -= 2; | ||
692 | |||
693 | A_FireSomething(player,0); // phares | ||
694 | |||
695 | P_BulletSlope(player->mo); | ||
696 | |||
697 | for (i=0; i<20; i++) | ||
698 | { | ||
699 | int damage = 5*(P_Random(pr_shotgun)%3+1); | ||
700 | angle_t angle = player->mo->angle; | ||
701 | // killough 5/5/98: remove dependence on order of evaluation: | ||
702 | int t = P_Random(pr_shotgun); | ||
703 | angle += (t - P_Random(pr_shotgun))<<19; | ||
704 | t = P_Random(pr_shotgun); | ||
705 | P_LineAttack(player->mo, angle, MISSILERANGE, bulletslope + | ||
706 | ((t - P_Random(pr_shotgun))<<5), damage); | ||
707 | } | ||
708 | } | ||
709 | |||
710 | // | ||
711 | // A_FireCGun | ||
712 | // | ||
713 | |||
714 | void A_FireCGun(player_t *player, pspdef_t *psp) | ||
715 | { | ||
716 | if (player->ammo[weaponinfo[player->readyweapon].ammo] || comp[comp_sound]) | ||
717 | S_StartSound(player->mo, sfx_pistol); | ||
718 | |||
719 | if (!player->ammo[weaponinfo[player->readyweapon].ammo]) | ||
720 | return; | ||
721 | |||
722 | P_SetMobjState(player->mo, S_PLAY_ATK2); | ||
723 | player->ammo[weaponinfo[player->readyweapon].ammo]--; | ||
724 | |||
725 | A_FireSomething(player,psp->state - &states[S_CHAIN1]); // phares | ||
726 | |||
727 | P_BulletSlope(player->mo); | ||
728 | |||
729 | P_GunShot(player->mo, !player->refire); | ||
730 | } | ||
731 | |||
732 | void A_Light0(player_t *player, pspdef_t *psp) | ||
733 | { | ||
734 | player->extralight = 0; | ||
735 | } | ||
736 | |||
737 | void A_Light1 (player_t *player, pspdef_t *psp) | ||
738 | { | ||
739 | player->extralight = 1; | ||
740 | } | ||
741 | |||
742 | void A_Light2 (player_t *player, pspdef_t *psp) | ||
743 | { | ||
744 | player->extralight = 2; | ||
745 | } | ||
746 | |||
747 | // | ||
748 | // A_BFGSpray | ||
749 | // Spawn a BFG explosion on every monster in view | ||
750 | // | ||
751 | |||
752 | void A_BFGSpray(mobj_t *mo) | ||
753 | { | ||
754 | int i; | ||
755 | |||
756 | for (i=0 ; i<40 ; i++) // offset angles from its attack angle | ||
757 | { | ||
758 | int j, damage; | ||
759 | angle_t an = mo->angle - ANG90/2 + ANG90/40*i; | ||
760 | |||
761 | // mo->target is the originator (player) of the missile | ||
762 | |||
763 | // killough 8/2/98: make autoaiming prefer enemies | ||
764 | if (!mbf_features || | ||
765 | (P_AimLineAttack(mo->target, an, 16*64*FRACUNIT, MF_FRIEND), | ||
766 | !linetarget)) | ||
767 | P_AimLineAttack(mo->target, an, 16*64*FRACUNIT, 0); | ||
768 | |||
769 | if (!linetarget) | ||
770 | continue; | ||
771 | |||
772 | P_SpawnMobj(linetarget->x, linetarget->y, | ||
773 | linetarget->z + (linetarget->height>>2), MT_EXTRABFG); | ||
774 | |||
775 | for (damage=j=0; j<15; j++) | ||
776 | damage += (P_Random(pr_bfg)&7) + 1; | ||
777 | |||
778 | P_DamageMobj(linetarget, mo->target, mo->target, damage); | ||
779 | } | ||
780 | } | ||
781 | |||
782 | // | ||
783 | // A_BFGsound | ||
784 | // | ||
785 | |||
786 | void A_BFGsound(player_t *player, pspdef_t *psp) | ||
787 | { | ||
788 | S_StartSound(player->mo, sfx_bfg); | ||
789 | } | ||
790 | |||
791 | // | ||
792 | // P_SetupPsprites | ||
793 | // Called at start of level for each player. | ||
794 | // | ||
795 | |||
796 | void P_SetupPsprites(player_t *player) | ||
797 | { | ||
798 | int i; | ||
799 | |||
800 | // remove all psprites | ||
801 | for (i=0; i<NUMPSPRITES; i++) | ||
802 | player->psprites[i].state = NULL; | ||
803 | |||
804 | // spawn the gun | ||
805 | player->pendingweapon = player->readyweapon; | ||
806 | P_BringUpWeapon(player); | ||
807 | } | ||
808 | |||
809 | // | ||
810 | // P_MovePsprites | ||
811 | // Called every tic by player thinking routine. | ||
812 | // | ||
813 | |||
814 | void P_MovePsprites(player_t *player) | ||
815 | { | ||
816 | pspdef_t *psp = player->psprites; | ||
817 | int i; | ||
818 | |||
819 | // a null state means not active | ||
820 | // drop tic count and possibly change state | ||
821 | // a -1 tic count never changes | ||
822 | |||
823 | for (i=0; i<NUMPSPRITES; i++, psp++) | ||
824 | if (psp->state && psp->tics != -1 && !--psp->tics) | ||
825 | P_SetPsprite(player, i, psp->state->nextstate); | ||
826 | |||
827 | player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx; | ||
828 | player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy; | ||
829 | } | ||