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