1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 2010-2019 EDuke32 developers and contributors
4 Copyright (C) 2019 Nuke.YKT
5
6 This file is part of NBlood.
7
8 NBlood is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License version 2
10 as published by the Free Software Foundation.
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.
15
16 See the GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22 //-------------------------------------------------------------------------
23 #include <stdlib.h>
24 #include <string.h>
25 #include "compat.h"
26 #include "build.h"
27 #include "mmulti.h"
28 #include "actor.h"
29 #include "blood.h"
30 #include "callback.h"
31 #include "config.h"
32 #include "controls.h"
33 #include "demo.h"
34 #include "eventq.h"
35 #include "fx.h"
36 #include "gib.h"
37 #include "globals.h"
38 #include "levels.h"
39 #include "loadsave.h"
40 #include "map2d.h"
41 #include "network.h"
42 #include "player.h"
43 #include "seq.h"
44 #include "sfx.h"
45 #include "sound.h"
46 #include "tile.h"
47 #include "triggers.h"
48 #include "trig.h"
49 #include "view.h"
50 #include "warp.h"
51 #include "weapon.h"
52 #include "common_game.h"
53 #include "messages.h"
54 #ifdef NOONE_EXTENSIONS
55 #include "nnexts.h"
56 #endif
57
58 PROFILE gProfile[kMaxPlayers];
59
60 PLAYER gPlayer[kMaxPlayers];
61 PLAYER *gMe, *gView;
62
63 bool gBlueFlagDropped = false;
64 bool gRedFlagDropped = false;
65
66 // V = has effect in game, X = no effect in game
67 POWERUPINFO gPowerUpInfo[kMaxPowerUps] = {
68 { -1, 1, 1, 1 }, // 00: V keys
69 { -1, 1, 1, 1 }, // 01: V keys
70 { -1, 1, 1, 1 }, // 02: V keys
71 { -1, 1, 1, 1 }, // 03: V keys
72 { -1, 1, 1, 1 }, // 04: V keys
73 { -1, 1, 1, 1 }, // 05: V keys
74 { -1, 1, 1, 1 }, // 06: V keys
75 { -1, 0, 100, 100 }, // 07: V doctor's bag
76 { -1, 0, 50, 100 }, // 08: V medicine pouch
77 { -1, 0, 20, 100 }, // 09: V life essense
78 { -1, 0, 100, 200 }, // 10: V life seed
79 { -1, 0, 2, 200 }, // 11: V red potion
80 { 783, 0, 3600, 432000 }, // 12: V feather fall
81 { 896, 0, 3600, 432000 }, // 13: V cloak of invisibility
82 { 825, 1, 3600, 432000 }, // 14: V death mask (invulnerability)
83 { 827, 0, 3600, 432000 }, // 15: V jump boots
84 { 828, 0, 3600, 432000 }, // 16: X raven flight
85 { 829, 0, 3600, 1728000 }, // 17: V guns akimbo
86 { 830, 0, 3600, 432000 }, // 18: V diving suit
87 { 831, 0, 3600, 432000 }, // 19: V gas mask
88 { -1, 0, 3600, 432000 }, // 20: X clone
89 { 2566, 0, 3600, 432000 }, // 21: V crystal ball
90 { 836, 0, 3600, 432000 }, // 22: X decoy
91 { 853, 0, 3600, 432000 }, // 23: V doppleganger
92 { 2428, 0, 3600, 432000 }, // 24: V reflective shots
93 { 839, 0, 3600, 432000 }, // 25: V beast vision
94 { 768, 0, 3600, 432000 }, // 26: X cloak of shadow (useless)
95 { 840, 0, 3600, 432000 }, // 27: X rage shroom
96 { 841, 0, 900, 432000 }, // 28: V delirium shroom
97 { 842, 0, 3600, 432000 }, // 29: V grow shroom (gModernMap only)
98 { 843, 0, 3600, 432000 }, // 30: V shrink shroom (gModernMap only)
99 { -1, 0, 3600, 432000 }, // 31: X death mask (useless)
100 { -1, 0, 3600, 432000 }, // 32: X wine goblet
101 { -1, 0, 3600, 432000 }, // 33: X wine bottle
102 { -1, 0, 3600, 432000 }, // 34: X skull grail
103 { -1, 0, 3600, 432000 }, // 35: X silver grail
104 { -1, 0, 3600, 432000 }, // 36: X tome
105 { -1, 0, 3600, 432000 }, // 37: X black chest
106 { -1, 0, 3600, 432000 }, // 38: X wooden chest
107 { 837, 1, 3600, 432000 }, // 39: V asbestos armor
108 { -1, 0, 1, 432000 }, // 40: V basic armor
109 { -1, 0, 1, 432000 }, // 41: V body armor
110 { -1, 0, 1, 432000 }, // 42: V fire armor
111 { -1, 0, 1, 432000 }, // 43: V spirit armor
112 { -1, 0, 1, 432000 }, // 44: V super armor
113 { 0, 0, 0, 0 }, // 45: ? unknown
114 { 0, 0, 0, 0 }, // 46: ? unknown
115 { 0, 0, 0, 0 }, // 47: ? unknown
116 { 0, 0, 0, 0 }, // 48: ? unknown
117 { 0, 0, 0, 0 }, // 49: X dummy
118 { 833, 1, 1, 1 } // 50: V kModernItemLevelMap (gModernMap only)
119 };
120
121 int Handicap[] = {
122 144, 208, 256, 304, 368
123 };
124
125 POSTURE gPostureDefaults[kModeMax][kPostureMax] = {
126
127 // normal human
128 {
129 { 0x4000, 0x4000, 0x4000, 14, 17, 24, 16, 32, 80, 0x1600, 0x1200, 0xc00, 0x90, -0xbaaaa, -0x175555 },
130 { 0x1200, 0x1200, 0x1200, 14, 17, 24, 16, 32, 80, 0x1400, 0x1000, -0x600, 0xb0, 0x5b05, 0 },
131 { 0x2000, 0x2000, 0x2000, 22, 28, 24, 16, 16, 40, 0x800, 0x600, -0x600, 0xb0, 0, 0 },
132 },
133
134 // normal beast
135 {
136 { 0x4000, 0x4000, 0x4000, 14, 17, 24, 16, 32, 80, 0x1600, 0x1200, 0xc00, 0x90, -0xbaaaa, -0x175555 },
137 { 0x1200, 0x1200, 0x1200, 14, 17, 24, 16, 32, 80, 0x1400, 0x1000, -0x600, 0xb0, 0x5b05, 0 },
138 { 0x2000, 0x2000, 0x2000, 22, 28, 24, 16, 16, 40, 0x800, 0x600, -0x600, 0xb0, 0, 0 },
139 },
140
141 // shrink human
142 {
143 { 10384, 10384, 10384, 14, 17, 24, 16, 32, 80, 5632, 4608, 3072, 144, -564586, -1329173 },
144 { 2108, 2108, 2108, 14, 17, 24, 16, 32, 80, 5120, 4096, -1536, 176, 0x5b05, 0 },
145 { 2192, 2192, 2192, 22, 28, 24, 16, 16, 40, 2048, 1536, -1536, 176, 0, 0 },
146 },
147
148 // grown human
149 {
150 { 19384, 19384, 19384, 14, 17, 24, 16, 32, 80, 5632, 4608, 3072, 144, -1014586, -1779173 },
151 { 5608, 5608, 5608, 14, 17, 24, 16, 32, 80, 5120, 4096, -1536, 176, 0x5b05, 0 },
152 { 11192, 11192, 11192, 22, 28, 24, 16, 16, 40, 2048, 1536, -1536, 176, 0, 0 },
153 },
154 };
155
156 AMMOINFO gAmmoInfo[] = {
157 { 0, -1 },
158 { 100, -1 },
159 { 100, 4 },
160 { 500, 5 },
161 { 100, -1 },
162 { 50, -1 },
163 { 2880, -1 },
164 { 250, -1 },
165 { 100, -1 },
166 { 100, -1 },
167 { 50, -1 },
168 { 50, -1 },
169 };
170
171 struct ARMORDATA {
172 int at0;
173 int at4;
174 int at8;
175 int atc;
176 int at10;
177 int at14;
178 };
179 ARMORDATA armorData[5] = {
180 { 0x320, 0x640, 0x320, 0x640, 0x320, 0x640 },
181 { 0x640, 0x640, 0, 0x640, 0, 0x640 },
182 { 0, 0x640, 0x640, 0x640, 0, 0x640 },
183 { 0, 0x640, 0, 0x640, 0x640, 0x640 },
184 { 0xc80, 0xc80, 0xc80, 0xc80, 0xc80, 0xc80 }
185 };
186
187 void PlayerSurvive(int, int);
188 void PlayerKneelsOver(int, int);
189
190 int nPlayerSurviveClient = seqRegisterClient(PlayerSurvive);
191 int nPlayerKneelClient = seqRegisterClient(PlayerKneelsOver);
192
193 struct VICTORY {
194 const char *at0;
195 int at4;
196 };
197
198 VICTORY gVictory[] = {
199 { "%s boned %s like a fish", 4100 },
200 { "%s castrated %s", 4101 },
201 { "%s creamed %s", 4102 },
202 { "%s destroyed %s", 4103 },
203 { "%s diced %s", 4104 },
204 { "%s disemboweled %s", 4105 },
205 { "%s flattened %s", 4106 },
206 { "%s gave %s Anal Justice", 4107 },
207 { "%s gave AnAl MaDnEsS to %s", 4108 },
208 { "%s hurt %s real bad", 4109 },
209 { "%s killed %s", 4110 },
210 { "%s made mincemeat out of %s", 4111 },
211 { "%s massacred %s", 4112 },
212 { "%s mutilated %s", 4113 },
213 { "%s reamed %s", 4114 },
214 { "%s ripped %s a new orifice", 4115 },
215 { "%s slaughtered %s", 4116 },
216 { "%s sliced %s", 4117 },
217 { "%s smashed %s", 4118 },
218 { "%s sodomized %s", 4119 },
219 { "%s splattered %s", 4120 },
220 { "%s squashed %s", 4121 },
221 { "%s throttled %s", 4122 },
222 { "%s wasted %s", 4123 },
223 { "%s body bagged %s", 4124 },
224 };
225
226 struct SUICIDE {
227 const char *at0;
228 int at4;
229 };
230
231 SUICIDE gSuicide[] = {
232 { "%s is excrement", 4202 },
233 { "%s is hamburger", 4203 },
234 { "%s suffered scrotum separation", 4204 },
235 { "%s volunteered for population control", 4206 },
236 { "%s has suicided", 4207 },
237 };
238
239 struct DAMAGEINFO {
240 int at0;
241 int at4[3];
242 int at10[3];
243 };
244
245 DAMAGEINFO damageInfo[7] = {
246 { -1, 731, 732, 733, 710, 710, 710 },
247 { 1, 742, 743, 744, 711, 711, 711 },
248 { 0, 731, 732, 733, 712, 712, 712 },
249 { 1, 731, 732, 733, 713, 713, 713 },
250 { -1, 724, 724, 724, 714, 714, 714 },
251 { 2, 731, 732, 733, 715, 715, 715 },
252 { 0, 0, 0, 0, 0, 0, 0 }
253 };
254
powerupCheck(PLAYER * pPlayer,int nPowerUp)255 int powerupCheck(PLAYER *pPlayer, int nPowerUp)
256 {
257 dassert(pPlayer != NULL);
258 dassert(nPowerUp >= 0 && nPowerUp < kMaxPowerUps);
259 int nPack = powerupToPackItem(nPowerUp);
260 if (nPack >= 0 && !packItemActive(pPlayer, nPack))
261 return 0;
262 return pPlayer->pwUpTime[nPowerUp];
263 }
264
265
powerupActivate(PLAYER * pPlayer,int nPowerUp)266 char powerupActivate(PLAYER *pPlayer, int nPowerUp)
267 {
268 if (powerupCheck(pPlayer, nPowerUp) > 0 && gPowerUpInfo[nPowerUp].pickupOnce)
269 return 0;
270 if (!pPlayer->pwUpTime[nPowerUp])
271 pPlayer->pwUpTime[nPowerUp] = gPowerUpInfo[nPowerUp].bonusTime;
272 int nPack = powerupToPackItem(nPowerUp);
273 if (nPack >= 0)
274 pPlayer->packSlots[nPack].isActive = 1;
275
276 switch (nPowerUp + kItemBase) {
277 #ifdef NOONE_EXTENSIONS
278 case kItemModernMapLevel:
279 if (gModernMap) gFullMap = true;
280 break;
281 case kItemShroomShrink:
282 if (!gModernMap) break;
283 else if (isGrown(pPlayer->pSprite)) playerDeactivateShrooms(pPlayer);
284 else playerSizeShrink(pPlayer, 2);
285 break;
286 case kItemShroomGrow:
287 if (!gModernMap) break;
288 else if (isShrinked(pPlayer->pSprite)) playerDeactivateShrooms(pPlayer);
289 else {
290 playerSizeGrow(pPlayer, 2);
291 if (powerupCheck(&gPlayer[pPlayer->pSprite->type - kDudePlayer1], kPwUpShadowCloak) > 0) {
292 powerupDeactivate(pPlayer, kPwUpShadowCloak);
293 pPlayer->pwUpTime[kPwUpShadowCloak] = 0;
294 }
295
296 if (ceilIsTooLow(pPlayer->pSprite))
297 actDamageSprite(pPlayer->pSprite->index, pPlayer->pSprite, kDamageExplode, 65535);
298 }
299 break;
300 #endif
301 case kItemFeatherFall:
302 case kItemJumpBoots:
303 pPlayer->damageControl[0]++;
304 break;
305 case kItemReflectShots: // reflective shots
306 if (pPlayer == gMe && gGameOptions.nGameType == 0)
307 sfxSetReverb2(1);
308 break;
309 case kItemDeathMask:
310 for (int i = 0; i < 7; i++)
311 pPlayer->damageControl[i]++;
312 break;
313 case kItemDivingSuit: // diving suit
314 pPlayer->damageControl[4]++;
315 if (pPlayer == gMe && gGameOptions.nGameType == 0)
316 sfxSetReverb(1);
317 break;
318 case kItemGasMask:
319 pPlayer->damageControl[4]++;
320 break;
321 case kItemArmorAsbest:
322 pPlayer->damageControl[1]++;
323 break;
324 case kItemTwoGuns:
325 pPlayer->input.newWeapon = pPlayer->curWeapon;
326 WeaponRaise(pPlayer);
327 break;
328 }
329 sfxPlay3DSound(pPlayer->pSprite, 776, -1, 0);
330 return 1;
331 }
332
powerupDeactivate(PLAYER * pPlayer,int nPowerUp)333 void powerupDeactivate(PLAYER *pPlayer, int nPowerUp)
334 {
335 int nPack = powerupToPackItem(nPowerUp);
336 if (nPack >= 0)
337 pPlayer->packSlots[nPack].isActive = 0;
338
339 switch (nPowerUp + kItemBase) {
340 #ifdef NOONE_EXTENSIONS
341 case kItemShroomShrink:
342 if (gModernMap) {
343 playerSizeReset(pPlayer);
344 if (ceilIsTooLow(pPlayer->pSprite))
345 actDamageSprite(pPlayer->pSprite->index, pPlayer->pSprite, kDamageExplode, 65535);
346 }
347 break;
348 case kItemShroomGrow:
349 if (gModernMap) playerSizeReset(pPlayer);
350 break;
351 #endif
352 case kItemFeatherFall:
353 case kItemJumpBoots:
354 pPlayer->damageControl[0]--;
355 break;
356 case kItemDeathMask:
357 for (int i = 0; i < 7; i++)
358 pPlayer->damageControl[i]--;
359 break;
360 case kItemDivingSuit:
361 pPlayer->damageControl[4]--;
362 if (pPlayer == gMe && VanillaMode() ? true : pPlayer->pwUpTime[24] == 0)
363 sfxSetReverb(0);
364 break;
365 case kItemReflectShots:
366 if (pPlayer == gMe && VanillaMode() ? true : pPlayer->packSlots[1].isActive == 0)
367 sfxSetReverb(0);
368 break;
369 case kItemGasMask:
370 pPlayer->damageControl[4]--;
371 break;
372 case kItemArmorAsbest:
373 pPlayer->damageControl[1]--;
374 break;
375 case kItemTwoGuns:
376 pPlayer->input.newWeapon = pPlayer->curWeapon;
377 WeaponRaise(pPlayer);
378 break;
379 }
380 }
381
powerupSetState(PLAYER * pPlayer,int nPowerUp,char bState)382 void powerupSetState(PLAYER *pPlayer, int nPowerUp, char bState)
383 {
384 if (!bState)
385 powerupActivate(pPlayer, nPowerUp);
386 else
387 powerupDeactivate(pPlayer, nPowerUp);
388 }
389
powerupProcess(PLAYER * pPlayer)390 void powerupProcess(PLAYER *pPlayer)
391 {
392 pPlayer->packItemTime = ClipLow(pPlayer->packItemTime-4, 0);
393 for (int i = kMaxPowerUps-1; i >= 0; i--)
394 {
395 int nPack = powerupToPackItem(i);
396 if (nPack >= 0)
397 {
398 if (pPlayer->packSlots[nPack].isActive)
399 {
400 pPlayer->pwUpTime[i] = ClipLow(pPlayer->pwUpTime[i]-4, 0);
401 if (pPlayer->pwUpTime[i])
402 pPlayer->packSlots[nPack].curAmount = (100*pPlayer->pwUpTime[i])/gPowerUpInfo[i].bonusTime;
403 else
404 {
405 powerupDeactivate(pPlayer, i);
406 if (pPlayer->packItemId == nPack)
407 pPlayer->packItemId = 0;
408 }
409 }
410 }
411 else if (pPlayer->pwUpTime[i] > 0)
412 {
413 pPlayer->pwUpTime[i] = ClipLow(pPlayer->pwUpTime[i]-4, 0);
414 if (!pPlayer->pwUpTime[i])
415 powerupDeactivate(pPlayer, i);
416 }
417 }
418 }
419
powerupClear(PLAYER * pPlayer)420 void powerupClear(PLAYER *pPlayer)
421 {
422 for (int i = kMaxPowerUps-1; i >= 0; i--)
423 {
424 pPlayer->pwUpTime[i] = 0;
425 }
426 }
427
powerupInit(void)428 void powerupInit(void)
429 {
430 }
431
packItemToPowerup(int nPack)432 int packItemToPowerup(int nPack)
433 {
434 int nPowerUp = -1;
435 switch (nPack) {
436 case 0:
437 break;
438 case 1:
439 nPowerUp = kPwUpDivingSuit;
440 break;
441 case 2:
442 nPowerUp = kPwUpCrystalBall;
443 break;
444 case 3:
445 nPowerUp = kPwUpBeastVision;
446 break;
447 case 4:
448 nPowerUp = kPwUpJumpBoots;
449 break;
450 default:
451 ThrowError("Unhandled pack item %d", nPack);
452 break;
453 }
454 return nPowerUp;
455 }
456
powerupToPackItem(int nPowerUp)457 int powerupToPackItem(int nPowerUp)
458 {
459 switch (nPowerUp) {
460 case kPwUpDivingSuit:
461 return 1;
462 case kPwUpCrystalBall:
463 return 2;
464 case kPwUpBeastVision:
465 return 3;
466 case kPwUpJumpBoots:
467 return 4;
468 }
469 return -1;
470 }
471
packAddItem(PLAYER * pPlayer,unsigned int nPack)472 char packAddItem(PLAYER *pPlayer, unsigned int nPack)
473 {
474 if (nPack <= 4)
475 {
476 if (pPlayer->packSlots[nPack].curAmount >= 100)
477 return 0;
478 pPlayer->packSlots[nPack].curAmount = 100;
479 int nPowerUp = packItemToPowerup(nPack);
480 if (nPowerUp >= 0)
481 pPlayer->pwUpTime[nPowerUp] = gPowerUpInfo[nPowerUp].bonusTime;
482 if (pPlayer->packItemId == -1)
483 pPlayer->packItemId = nPack;
484 if (!pPlayer->packSlots[pPlayer->packItemId].curAmount)
485 pPlayer->packItemId = nPack;
486 }
487 else
488 ThrowError("Unhandled pack item %d", nPack);
489 return 1;
490 }
491
packCheckItem(PLAYER * pPlayer,int nPack)492 int packCheckItem(PLAYER *pPlayer, int nPack)
493 {
494 return pPlayer->packSlots[nPack].curAmount;
495 }
496
packItemActive(PLAYER * pPlayer,int nPack)497 char packItemActive(PLAYER *pPlayer, int nPack)
498 {
499 return pPlayer->packSlots[nPack].isActive;
500 }
501
packUseItem(PLAYER * pPlayer,int nPack)502 void packUseItem(PLAYER *pPlayer, int nPack)
503 {
504 char v4 = 0;
505 int nPowerUp = -1;
506 if (pPlayer->packSlots[nPack].curAmount > 0)
507 {
508 switch (nPack)
509 {
510 case 0:
511 {
512 XSPRITE *pXSprite = pPlayer->pXSprite;
513 unsigned int health = pXSprite->health>>4;
514 if (health < 100)
515 {
516 int heal = ClipHigh(100-health, pPlayer->packSlots[0].curAmount);
517 actHealDude(pXSprite, heal, 100);
518 pPlayer->packSlots[0].curAmount -= heal;
519 }
520 break;
521 }
522 case 1:
523 v4 = 1;
524 nPowerUp = kPwUpDivingSuit;
525 break;
526 case 2:
527 v4 = 1;
528 nPowerUp = kPwUpCrystalBall;
529 break;
530 case 3:
531 v4 = 1;
532 nPowerUp = kPwUpBeastVision;
533 break;
534 case 4:
535 v4 = 1;
536 nPowerUp = kPwUpJumpBoots;
537 break;
538 default:
539 ThrowError("Unhandled pack item %d", nPack);
540 return;
541 }
542 }
543 pPlayer->packItemTime = 0;
544 if (v4)
545 powerupSetState(pPlayer, nPowerUp, pPlayer->packSlots[nPack].isActive);
546 }
547
packPrevItem(PLAYER * pPlayer)548 void packPrevItem(PLAYER *pPlayer)
549 {
550 if (pPlayer->packItemTime > 0)
551 {
552 for (int nPrev = ClipLow(pPlayer->packItemId-1,0); nPrev >= 0; nPrev--)
553 {
554 if (pPlayer->packSlots[nPrev].curAmount)
555 {
556 pPlayer->packItemId = nPrev;
557 break;
558 }
559 }
560 }
561 pPlayer->packItemTime = 600;
562 }
563
packNextItem(PLAYER * pPlayer)564 void packNextItem(PLAYER *pPlayer)
565 {
566 if (pPlayer->packItemTime > 0)
567 {
568 for (int nNext = ClipHigh(pPlayer->packItemId+1,5); nNext < 5; nNext++)
569 {
570 if (pPlayer->packSlots[nNext].curAmount)
571 {
572 pPlayer->packItemId = nNext;
573 break;
574 }
575 }
576 }
577 pPlayer->packItemTime = 600;
578 }
579
playerSeqPlaying(PLAYER * pPlayer,int nSeq)580 char playerSeqPlaying(PLAYER * pPlayer, int nSeq)
581 {
582 int nCurSeq = seqGetID(3, pPlayer->pSprite->extra);
583 if (pPlayer->pDudeInfo->seqStartID+nSeq == nCurSeq && seqGetStatus(3,pPlayer->pSprite->extra) >= 0)
584 return 1;
585 return 0;
586 }
587
playerSetRace(PLAYER * pPlayer,int nLifeMode)588 void playerSetRace(PLAYER *pPlayer, int nLifeMode)
589 {
590 dassert(nLifeMode >= kModeHuman && nLifeMode <= kModeHumanGrown);
591 DUDEINFO *pDudeInfo = pPlayer->pDudeInfo;
592 *pDudeInfo = gPlayerTemplate[nLifeMode];
593 pPlayer->lifeMode = nLifeMode;
594
595 // By NoOne: don't forget to change clipdist for grow and shrink modes
596 pPlayer->pSprite->clipdist = pDudeInfo->clipdist;
597
598 for (int i = 0; i < 7; i++)
599 pDudeInfo->at70[i] = mulscale8(Handicap[gProfile[pPlayer->nPlayer].skill], pDudeInfo->startDamage[i]);
600 }
601
playerSetGodMode(PLAYER * pPlayer,char bGodMode)602 void playerSetGodMode(PLAYER *pPlayer, char bGodMode)
603 {
604 if (bGodMode)
605 {
606 for (int i = 0; i < 7; i++)
607 pPlayer->damageControl[i]++;
608 }
609 else
610 {
611 for (int i = 0; i < 7; i++)
612 pPlayer->damageControl[i]--;
613 }
614 pPlayer->godMode = bGodMode;
615 }
616
playerResetInertia(PLAYER * pPlayer)617 void playerResetInertia(PLAYER *pPlayer)
618 {
619 POSTURE *pPosture = &pPlayer->pPosture[pPlayer->lifeMode][pPlayer->posture];
620 pPlayer->zView = pPlayer->pSprite->z-pPosture->eyeAboveZ;
621 pPlayer->zWeapon = pPlayer->pSprite->z-pPosture->weaponAboveZ;
622 viewBackupView(pPlayer->nPlayer);
623 }
624
playerCorrectInertia(PLAYER * pPlayer,vec3_t const * oldpos)625 void playerCorrectInertia(PLAYER* pPlayer, vec3_t const *oldpos)
626 {
627 pPlayer->zView += pPlayer->pSprite->z-oldpos->z;
628 pPlayer->zWeapon += pPlayer->pSprite->z-oldpos->z;
629 viewCorrectViewOffsets(pPlayer->nPlayer, oldpos);
630 }
631
playerResetPowerUps(PLAYER * pPlayer)632 void playerResetPowerUps(PLAYER* pPlayer)
633 {
634 for (int i = 0; i < kMaxPowerUps; i++) {
635 if (!VanillaMode() && (i == kPwUpJumpBoots || i == kPwUpDivingSuit || i == kPwUpCrystalBall || i == kPwUpBeastVision))
636 continue;
637 pPlayer->pwUpTime[i] = 0;
638 }
639 }
640
playerResetPosture(PLAYER * pPlayer)641 void playerResetPosture(PLAYER* pPlayer) {
642 memcpy(pPlayer->pPosture, gPostureDefaults, sizeof(gPostureDefaults));
643 }
644
playerStart(int nPlayer,int bNewLevel)645 void playerStart(int nPlayer, int bNewLevel)
646 {
647 PLAYER* pPlayer = &gPlayer[nPlayer];
648 GINPUT* pInput = &pPlayer->input;
649 ZONE* pStartZone = NULL;
650
651 // normal start position
652 if (gGameOptions.nGameType <= 1)
653 pStartZone = &gStartZone[nPlayer];
654
655 #ifdef NOONE_EXTENSIONS
656 // let's check if there is positions of teams is specified
657 // if no, pick position randomly, just like it works in vanilla.
658 else if (gModernMap && gGameOptions.nGameType == 3 && gTeamsSpawnUsed == true) {
659 int maxRetries = 5;
660 while (maxRetries-- > 0) {
661 if (pPlayer->teamId == 0) pStartZone = &gStartZoneTeam1[Random(3)];
662 else pStartZone = &gStartZoneTeam2[Random(3)];
663
664 if (maxRetries != 0) {
665 // check if there is no spawned player in selected zone
666 for (int i = headspritesect[pStartZone->sectnum]; i >= 0; i = nextspritesect[i]) {
667 spritetype* pSprite = &sprite[i];
668 if (pStartZone->x == pSprite->x && pStartZone->y == pSprite->y && IsPlayerSprite(pSprite)) {
669 pStartZone = NULL;
670 break;
671 }
672 }
673 }
674
675 if (pStartZone != NULL)
676 break;
677 }
678
679 }
680 #endif
681 else {
682 pStartZone = &gStartZone[Random(8)];
683 }
684
685 if (!VanillaMode())
686 sfxKillSpriteSounds(pPlayer->pSprite);
687
688 spritetype *pSprite = actSpawnSprite(pStartZone->sectnum, pStartZone->x, pStartZone->y, pStartZone->z, 6, 1);
689 dassert(pSprite->extra > 0 && pSprite->extra < kMaxXSprites);
690 XSPRITE *pXSprite = &xsprite[pSprite->extra];
691 pPlayer->pSprite = pSprite;
692 pPlayer->pXSprite = pXSprite;
693 pPlayer->nSprite = pSprite->index;
694 DUDEINFO *pDudeInfo = &dudeInfo[kDudePlayer1 + nPlayer - kDudeBase];
695 pPlayer->pDudeInfo = pDudeInfo;
696 playerSetRace(pPlayer, kModeHuman);
697 playerResetPosture(pPlayer);
698 seqSpawn(pDudeInfo->seqStartID, 3, pSprite->extra, -1);
699 if (pPlayer == gMe)
700 SetBitString(show2dsprite, pSprite->index);
701 int top, bottom;
702 GetSpriteExtents(pSprite, &top, &bottom);
703 pSprite->z -= bottom - pSprite->z;
704 pSprite->pal = 11+(pPlayer->teamId&3);
705 pPlayer->angold = pSprite->ang = pStartZone->ang;
706 pPlayer->q16ang = fix16_from_int(pSprite->ang);
707 pSprite->type = kDudePlayer1+nPlayer;
708 pSprite->clipdist = pDudeInfo->clipdist;
709 pSprite->flags = 15;
710 pXSprite->burnTime = 0;
711 pXSprite->burnSource = -1;
712 pPlayer->pXSprite->health = pDudeInfo->startHealth<<4;
713 pPlayer->pSprite->cstat &= (unsigned short)~32768;
714 pPlayer->bloodlust = 0;
715 pPlayer->q16horiz = 0;
716 pPlayer->q16slopehoriz = 0;
717 pPlayer->q16look = 0;
718 pPlayer->slope = 0;
719 pPlayer->fraggerId = -1;
720 pPlayer->underwaterTime = 1200;
721 pPlayer->bloodTime = 0;
722 pPlayer->gooTime = 0;
723 pPlayer->wetTime = 0;
724 pPlayer->bubbleTime = 0;
725 pPlayer->at306 = 0;
726 pPlayer->restTime = 0;
727 pPlayer->kickPower = 0;
728 pPlayer->laughCount = 0;
729 pPlayer->spin = 0;
730 pPlayer->posture = 0;
731 pPlayer->voodooTarget = -1;
732 pPlayer->voodooTargets = 0;
733 pPlayer->voodooVar1 = 0;
734 pPlayer->vodooVar2 = 0;
735 playerResetInertia(pPlayer);
736 pPlayer->zWeaponVel = 0;
737 pPlayer->relAim.dx = 0x4000;
738 pPlayer->relAim.dy = 0;
739 pPlayer->relAim.dz = 0;
740 pPlayer->aimTarget = -1;
741 pPlayer->zViewVel = pPlayer->zWeaponVel;
742 if (!(gGameOptions.nGameType == 1 && gGameOptions.bKeepKeysOnRespawn && !bNewLevel))
743 for (int i = 0; i < 8; i++)
744 pPlayer->hasKey[i] = gGameOptions.nGameType >= 2;
745 pPlayer->hasFlag = 0;
746 for (int i = 0; i < 8; i++)
747 pPlayer->used2[i] = -1;
748 for (int i = 0; i < 7; i++)
749 pPlayer->damageControl[i] = 0;
750 if (pPlayer->godMode)
751 playerSetGodMode(pPlayer, 1);
752 gInfiniteAmmo = 0;
753 gFullMap = 0;
754 pPlayer->throwPower = 0;
755 pPlayer->deathTime = 0;
756 pPlayer->nextWeapon = 0;
757 xvel[pSprite->index] = yvel[pSprite->index] = zvel[pSprite->index] = 0;
758 pInput->q16turn = 0;
759 pInput->keyFlags.word = 0;
760 pInput->forward = 0;
761 pInput->strafe = 0;
762 pInput->q16mlook = 0;
763 pInput->buttonFlags.byte = 0;
764 pInput->useFlags.byte = 0;
765 pPlayer->flickerEffect = 0;
766 pPlayer->quakeEffect = 0;
767 pPlayer->tiltEffect = 0;
768 pPlayer->visibility = 0;
769 pPlayer->painEffect = 0;
770 pPlayer->blindEffect = 0;
771 pPlayer->chokeEffect = 0;
772 pPlayer->handTime = 0;
773 pPlayer->weaponTimer = 0;
774 pPlayer->weaponState = 0;
775 pPlayer->weaponQav = -1;
776 #ifdef NOONE_EXTENSIONS
777 playerQavSceneReset(pPlayer); // reset qav scene
778
779 // assign or update player's sprite index for conditions
780 if (gModernMap) {
781
782 for (int nSprite = headspritestat[kStatModernPlayerLinker]; nSprite >= 0; nSprite = nextspritestat[nSprite]) {
783 XSPRITE* pXCtrl = &xsprite[sprite[nSprite].extra];
784 if (pXCtrl->data1 == pPlayer->nPlayer + 1) {
785 int nSpriteOld = pXCtrl->sysData1;
786 trPlayerCtrlLink(pXCtrl, pPlayer, (nSpriteOld < 0) ? true : false);
787 if (nSpriteOld > 0)
788 condUpdateObjectIndex(OBJ_SPRITE, nSpriteOld, pXCtrl->sysData1);
789 }
790 }
791
792 }
793
794 #endif
795 pPlayer->hand = 0;
796 pPlayer->nWaterPal = 0;
797 playerResetPowerUps(pPlayer);
798
799 if (pPlayer == gMe)
800 {
801 viewInitializePrediction();
802 gViewLook = pPlayer->q16look;
803 gViewAngle = pPlayer->q16ang;
804 gViewMap.x = pPlayer->pSprite->x;
805 gViewMap.y = pPlayer->pSprite->y;
806 gViewMap.angle = pPlayer->pSprite->ang;
807 }
808 if (IsUnderwaterSector(pSprite->sectnum))
809 {
810 pPlayer->posture = 1;
811 pPlayer->pXSprite->medium = kMediumWater;
812 }
813 }
814
playerReset(PLAYER * pPlayer)815 void playerReset(PLAYER *pPlayer)
816 {
817 static int dword_136400[] = {
818 3, 4, 2, 8, 9, 10, 7, 1, 1, 1, 1, 1, 1, 1
819 };
820 static int dword_136438[] = {
821 3, 4, 2, 8, 9, 10, 7, 1, 1, 1, 1, 1, 1, 1
822 };
823 dassert(pPlayer != NULL);
824 for (int i = 0; i < 14; i++)
825 {
826 pPlayer->hasWeapon[i] = gInfiniteAmmo;
827 pPlayer->weaponMode[i] = 0;
828 }
829 pPlayer->hasWeapon[1] = 1;
830 pPlayer->curWeapon = 0;
831 pPlayer->qavCallback = -1;
832 pPlayer->input.newWeapon = 1;
833 for (int i = 0; i < 14; i++)
834 {
835 pPlayer->weaponOrder[0][i] = dword_136400[i];
836 pPlayer->weaponOrder[1][i] = dword_136438[i];
837 }
838 for (int i = 0; i < 12; i++)
839 {
840 if (gInfiniteAmmo)
841 pPlayer->ammoCount[i] = gAmmoInfo[i].max;
842 else
843 pPlayer->ammoCount[i] = 0;
844 }
845 for (int i = 0; i < 3; i++)
846 pPlayer->armor[i] = 0;
847 pPlayer->weaponTimer = 0;
848 pPlayer->weaponState = 0;
849 pPlayer->weaponQav = -1;
850 pPlayer->qavLoop = 0;
851 pPlayer->packItemId = -1;
852
853 for (int i = 0; i < 5; i++) {
854 pPlayer->packSlots[i].isActive = 0;
855 pPlayer->packSlots[i].curAmount = 0;
856 }
857 #ifdef NOONE_EXTENSIONS
858 playerQavSceneReset(pPlayer);
859 #endif
860 // reset posture (mainly required for resetting movement speed and jump height)
861 playerResetPosture(pPlayer);
862
863 }
864
865 int dword_21EFB0[8];
866 ClockTicks dword_21EFD0[8];
867
playerInit(int nPlayer,unsigned int a2)868 void playerInit(int nPlayer, unsigned int a2)
869 {
870 PLAYER *pPlayer = &gPlayer[nPlayer];
871 if (!(a2&1))
872 memset(pPlayer, 0, sizeof(PLAYER));
873 pPlayer->nPlayer = nPlayer;
874 pPlayer->teamId = nPlayer;
875 if (gGameOptions.nGameType == 3)
876 pPlayer->teamId = nPlayer&1;
877 pPlayer->fragCount = 0;
878 memset(dword_21EFB0, 0, sizeof(dword_21EFB0));
879 memset(dword_21EFD0, 0, sizeof(dword_21EFD0));
880 memset(pPlayer->fragInfo, 0, sizeof(pPlayer->fragInfo));
881
882 if (!(a2&1))
883 playerReset(pPlayer);
884 }
885
sub_3A158(PLAYER * a1,spritetype * a2)886 char sub_3A158(PLAYER *a1, spritetype *a2)
887 {
888 for (int nSprite = headspritestat[kStatThing]; nSprite >= 0; nSprite = nextspritestat[nSprite])
889 {
890 if (a2 && a2->index == nSprite)
891 continue;
892 spritetype *pSprite = &sprite[nSprite];
893 if (pSprite->type == kThingDroppedLifeLeech && actOwnerIdToSpriteId(pSprite->owner) == a1->nSprite)
894 return 1;
895 }
896 return 0;
897 }
898
PickupItem(PLAYER * pPlayer,spritetype * pItem)899 char PickupItem(PLAYER *pPlayer, spritetype *pItem) {
900
901 spritetype *pSprite = pPlayer->pSprite; XSPRITE *pXSprite = pPlayer->pXSprite;
902 char buffer[80]; int pickupSnd = 775; int nType = pItem->type - kItemBase;
903
904 switch (pItem->type) {
905 case kItemShadowCloak:
906 #ifdef NOONE_EXTENSIONS
907 if (isGrown(pPlayer->pSprite) || !powerupActivate(pPlayer, nType)) return false;
908 #else
909 if (!powerupActivate(pPlayer, nType)) return false;
910 #endif
911 break;
912 #ifdef NOONE_EXTENSIONS
913 case kItemShroomShrink:
914 case kItemShroomGrow:
915
916 if (gModernMap) {
917 switch (pItem->type) {
918 case kItemShroomShrink:
919 if (isShrinked(pSprite)) return false;
920 break;
921 case kItemShroomGrow:
922 if (isGrown(pSprite)) return false;
923 break;
924 }
925
926 powerupActivate(pPlayer, nType);
927 }
928
929 break;
930 #endif
931 case kItemFlagABase:
932 case kItemFlagBBase: {
933 if (gGameOptions.nGameType != 3 || pItem->extra <= 0) return 0;
934 XSPRITE * pXItem = &xsprite[pItem->extra];
935 if (pItem->type == kItemFlagABase) {
936 if (pPlayer->teamId == 1) {
937 if ((pPlayer->hasFlag & 1) == 0 && pXItem->state) {
938 pPlayer->hasFlag |= 1;
939 pPlayer->used2[0] = pItem->index;
940 trTriggerSprite(pItem->index, pXItem, kCmdOff);
941 sprintf(buffer, "%s stole Blue Flag", gProfile[pPlayer->nPlayer].name);
942 sndStartSample(8007, 255, 2, 0);
943 viewSetMessage(buffer);
944 }
945 }
946
947 if (pPlayer->teamId == 0) {
948
949 if ((pPlayer->hasFlag & 1) != 0 && !pXItem->state) {
950 pPlayer->hasFlag &= ~1;
951 pPlayer->used2[0] = -1;
952 trTriggerSprite(pItem->index, pXItem, kCmdOn);
953 sprintf(buffer, "%s returned Blue Flag", gProfile[pPlayer->nPlayer].name);
954 sndStartSample(8003, 255, 2, 0);
955 viewSetMessage(buffer);
956 }
957
958 if ((pPlayer->hasFlag & 2) != 0 && pXItem->state) {
959 pPlayer->hasFlag &= ~2;
960 pPlayer->used2[1] = -1;
961 dword_21EFB0[pPlayer->teamId] += 10;
962 dword_21EFD0[pPlayer->teamId] += 240;
963 evSend(0, 0, 81, kCmdOn);
964 sprintf(buffer, "%s captured Red Flag!", gProfile[pPlayer->nPlayer].name);
965 sndStartSample(8001, 255, 2, 0);
966 viewSetMessage(buffer);
967 #if 0
968 if (dword_28E3D4 == 3 && myconnectindex == connecthead)
969 {
970 sprintf(buffer, "frag A killed B\n");
971 sub_7AC28(buffer);
972 }
973 #endif
974 }
975 }
976
977 }
978 else if (pItem->type == kItemFlagBBase) {
979
980 if (pPlayer->teamId == 0) {
981 if ((pPlayer->hasFlag & 2) == 0 && pXItem->state) {
982 pPlayer->hasFlag |= 2;
983 pPlayer->used2[1] = pItem->index;
984 trTriggerSprite(pItem->index, pXItem, kCmdOff);
985 sprintf(buffer, "%s stole Red Flag", gProfile[pPlayer->nPlayer].name);
986 sndStartSample(8006, 255, 2, 0);
987 viewSetMessage(buffer);
988 }
989 }
990
991 if (pPlayer->teamId == 1) {
992 if ((pPlayer->hasFlag & 2) != 0 && !pXItem->state)
993 {
994 pPlayer->hasFlag &= ~2;
995 pPlayer->used2[1] = -1;
996 trTriggerSprite(pItem->index, pXItem, kCmdOn);
997 sprintf(buffer, "%s returned Red Flag", gProfile[pPlayer->nPlayer].name);
998 sndStartSample(8002, 255, 2, 0);
999 viewSetMessage(buffer);
1000 }
1001 if ((pPlayer->hasFlag & 1) != 0 && pXItem->state)
1002 {
1003 pPlayer->hasFlag &= ~1;
1004 pPlayer->used2[0] = -1;
1005 dword_21EFB0[pPlayer->teamId] += 10;
1006 dword_21EFD0[pPlayer->teamId] += 240;
1007 evSend(0, 0, 80, kCmdOn);
1008 sprintf(buffer, "%s captured Blue Flag!", gProfile[pPlayer->nPlayer].name);
1009 sndStartSample(8000, 255, 2, 0);
1010 viewSetMessage(buffer);
1011 #if 0
1012 if (dword_28E3D4 == 3 && myconnectindex == connecthead)
1013 {
1014 sprintf(buffer, "frag B killed A\n");
1015 sub_7AC28(buffer);
1016 }
1017 #endif
1018 }
1019 }
1020 }
1021 }
1022 return 0;
1023 case kItemFlagA:
1024 if (gGameOptions.nGameType != 3) return 0;
1025 evKill(pItem->index, 3, kCallbackReturnFlag);
1026 pPlayer->hasFlag |= 1;
1027 pPlayer->used2[0] = pItem->index;
1028 gBlueFlagDropped = false;
1029 break;
1030 case kItemFlagB:
1031 if (gGameOptions.nGameType != 3) return 0;
1032 evKill(pItem->index, 3, kCallbackReturnFlag);
1033 pPlayer->hasFlag |= 2;
1034 pPlayer->used2[1] = pItem->index;
1035 gRedFlagDropped = false;
1036 break;
1037 case kItemArmorBasic:
1038 case kItemArmorBody:
1039 case kItemArmorFire:
1040 case kItemArmorSpirit:
1041 case kItemArmorSuper: {
1042 ARMORDATA *pArmorData = &armorData[pItem->type - kItemArmorBasic]; bool pickedUp = false;
1043 if (pPlayer->armor[1] < pArmorData->atc) {
1044 pPlayer->armor[1] = ClipHigh(pPlayer->armor[1]+pArmorData->at8, pArmorData->atc);
1045 pickedUp = true;
1046 }
1047
1048 if (pPlayer->armor[0] < pArmorData->at4) {
1049 pPlayer->armor[0] = ClipHigh(pPlayer->armor[0]+pArmorData->at0, pArmorData->at4);
1050 pickedUp = true;
1051 }
1052
1053 if (pPlayer->armor[2] < pArmorData->at14) {
1054 pPlayer->armor[2] = ClipHigh(pPlayer->armor[2]+pArmorData->at10, pArmorData->at14);
1055 pickedUp = true;
1056 }
1057
1058 if (!pickedUp) return 0;
1059 pickupSnd = 779;
1060 break;
1061 }
1062 case kItemCrystalBall:
1063 if (gGameOptions.nGameType == 0 || !packAddItem(pPlayer, gItemData[nType].packSlot)) return 0;
1064 break;
1065 case kItemKeySkull:
1066 case kItemKeyEye:
1067 case kItemKeyFire:
1068 case kItemKeyDagger:
1069 case kItemKeySpider:
1070 case kItemKeyMoon:
1071 case kItemKeyKey7:
1072 if (pPlayer->hasKey[pItem->type-99]) return 0;
1073 pPlayer->hasKey[pItem->type-99] = 1;
1074 pickupSnd = 781;
1075 break;
1076 case kItemHealthMedPouch:
1077 case kItemHealthLifeEssense:
1078 case kItemHealthLifeSeed:
1079 case kItemHealthRedPotion: {
1080 int addPower = gPowerUpInfo[nType].bonusTime;
1081 #ifdef NOONE_EXTENSIONS
1082 // allow custom amount for item
1083 if (gModernMap && sprite[pItem->index].extra >= 0 && xsprite[sprite[pItem->index].extra].data1 > 0)
1084 addPower = xsprite[sprite[pItem->index].extra].data1;
1085 #endif
1086
1087 if (!actHealDude(pXSprite, addPower, gPowerUpInfo[nType].maxTime)) return 0;
1088 return 1;
1089 }
1090 case kItemHealthDoctorBag:
1091 case kItemJumpBoots:
1092 case kItemDivingSuit:
1093 case kItemBeastVision:
1094 if (!packAddItem(pPlayer, gItemData[nType].packSlot)) return 0;
1095 break;
1096 default:
1097 if (!powerupActivate(pPlayer, nType)) return 0;
1098 return 1;
1099 }
1100
1101 sfxPlay3DSound(pSprite->x, pSprite->y, pSprite->z, pickupSnd, pSprite->sectnum);
1102 return 1;
1103 }
1104
PickupAmmo(PLAYER * pPlayer,spritetype * pAmmo)1105 char PickupAmmo(PLAYER* pPlayer, spritetype* pAmmo) {
1106 AMMOITEMDATA* pAmmoItemData = &gAmmoItemData[pAmmo->type - kItemAmmoBase];
1107 int nAmmoType = pAmmoItemData->type;
1108
1109 if (pPlayer->ammoCount[nAmmoType] >= gAmmoInfo[nAmmoType].max) return 0;
1110 #ifdef NOONE_EXTENSIONS
1111 else if (gModernMap && pAmmo->extra >= 0 && xsprite[pAmmo->extra].data1 > 0) // allow custom amount for item
1112 pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + xsprite[pAmmo->extra].data1, gAmmoInfo[nAmmoType].max);
1113 #endif
1114 else
1115 pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType]+pAmmoItemData->count, gAmmoInfo[nAmmoType].max);
1116
1117 if (pAmmoItemData->weaponType) pPlayer->hasWeapon[pAmmoItemData->weaponType] = 1;
1118 sfxPlay3DSound(pPlayer->pSprite, 782, -1, 0);
1119 return 1;
1120 }
1121
PickupWeapon(PLAYER * pPlayer,spritetype * pWeapon)1122 char PickupWeapon(PLAYER *pPlayer, spritetype *pWeapon) {
1123 WEAPONITEMDATA *pWeaponItemData = &gWeaponItemData[pWeapon->type - kItemWeaponBase];
1124 int nWeaponType = pWeaponItemData->type;
1125 int nAmmoType = pWeaponItemData->ammoType;
1126 if (!pPlayer->hasWeapon[nWeaponType] || gGameOptions.nWeaponSettings == 2 || gGameOptions.nWeaponSettings == 3) {
1127 if (pWeapon->type == kItemWeaponLifeLeech && gGameOptions.nGameType > 1 && sub_3A158(pPlayer, NULL))
1128 return 0;
1129 pPlayer->hasWeapon[nWeaponType] = 1;
1130 if (nAmmoType == -1) return 0;
1131 // allow to set custom ammo count for weapon pickups
1132 #ifdef NOONE_EXTENSIONS
1133 else if (gModernMap && pWeapon->extra >= 0 && xsprite[pWeapon->extra].data1 > 0)
1134 pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + xsprite[pWeapon->extra].data1, gAmmoInfo[nAmmoType].max);
1135 #endif
1136 else
1137 pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + pWeaponItemData->count, gAmmoInfo[nAmmoType].max);
1138
1139 int nNewWeapon = WeaponUpgrade(pPlayer, nWeaponType);
1140 if (nNewWeapon != pPlayer->curWeapon) {
1141 pPlayer->weaponState = 0;
1142 pPlayer->nextWeapon = nNewWeapon;
1143 }
1144 sfxPlay3DSound(pPlayer->pSprite, 777, -1, 0);
1145 return 1;
1146 }
1147
1148 if (!actGetRespawnTime(pWeapon) || nAmmoType == -1 || pPlayer->ammoCount[nAmmoType] >= gAmmoInfo[nAmmoType].max) return 0;
1149 #ifdef NOONE_EXTENSIONS
1150 else if (gModernMap && pWeapon->extra >= 0 && xsprite[pWeapon->extra].data1 > 0)
1151 pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + xsprite[pWeapon->extra].data1, gAmmoInfo[nAmmoType].max);
1152 #endif
1153 else
1154 pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType]+pWeaponItemData->count, gAmmoInfo[nAmmoType].max);
1155
1156 sfxPlay3DSound(pPlayer->pSprite, 777, -1, 0);
1157 return 1;
1158 }
1159
PickUp(PLAYER * pPlayer,spritetype * pSprite)1160 void PickUp(PLAYER *pPlayer, spritetype *pSprite)
1161 {
1162 char buffer[80];
1163 int nType = pSprite->type;
1164 char pickedUp = 0;
1165 int customMsg = -1;
1166 #ifdef NOONE_EXTENSIONS
1167 if (gModernMap) { // allow custom INI message instead "Picked up"
1168 XSPRITE* pXSprite = (pSprite->extra >= 0) ? &xsprite[pSprite->extra] : NULL;
1169 if (pXSprite != NULL && pXSprite->txID != 3 && pXSprite->lockMsg > 0)
1170 customMsg = pXSprite->lockMsg;
1171 }
1172 #endif
1173
1174 if (nType >= kItemBase && nType <= kItemMax) {
1175 pickedUp = PickupItem(pPlayer, pSprite);
1176 if (pickedUp && customMsg == -1) sprintf(buffer, "Picked up %s", gItemText[nType - kItemBase]);
1177
1178 } else if (nType >= kItemAmmoBase && nType < kItemAmmoMax) {
1179 pickedUp = PickupAmmo(pPlayer, pSprite);
1180 if (pickedUp && customMsg == -1) sprintf(buffer, "Picked up %s", gAmmoText[nType - kItemAmmoBase]);
1181
1182 } else if (nType >= kItemWeaponBase && nType < kItemWeaponMax) {
1183 pickedUp = PickupWeapon(pPlayer, pSprite);
1184 if (pickedUp && customMsg == -1) sprintf(buffer, "Picked up %s", gWeaponText[nType - kItemWeaponBase]);
1185 }
1186
1187 if (!pickedUp) return;
1188 else if (pSprite->extra > 0) {
1189 XSPRITE *pXSprite = &xsprite[pSprite->extra];
1190 if (pXSprite->Pickup)
1191 trTriggerSprite(pSprite->index, pXSprite, kCmdSpritePickup);
1192 }
1193
1194 if (!actCheckRespawn(pSprite))
1195 actPostSprite(pSprite->index, kStatFree);
1196
1197 pPlayer->pickupEffect = 30;
1198 if (pPlayer == gMe) {
1199 if (customMsg > 0) trTextOver(customMsg - 1);
1200 else viewSetMessage(buffer, 0, MESSAGE_PRIORITY_PICKUP);
1201 }
1202 }
1203
CheckPickUp(PLAYER * pPlayer)1204 void CheckPickUp(PLAYER *pPlayer)
1205 {
1206 spritetype *pSprite = pPlayer->pSprite;
1207 int x = pSprite->x;
1208 int y = pSprite->y;
1209 int z = pSprite->z;
1210 int nSector = pSprite->sectnum;
1211 int nNextSprite;
1212 for (int nSprite = headspritestat[kStatItem]; nSprite >= 0; nSprite = nNextSprite) {
1213 spritetype *pItem = &sprite[nSprite];
1214 nNextSprite = nextspritestat[nSprite];
1215 if (pItem->flags&32)
1216 continue;
1217 int dx = klabs(x-pItem->x)>>4;
1218 if (dx > 48)
1219 continue;
1220 int dy = klabs(y-pItem->y)>>4;
1221 if (dy > 48)
1222 continue;
1223 int top, bottom;
1224 GetSpriteExtents(pSprite, &top, &bottom);
1225 int vb = 0;
1226 if (pItem->z < top)
1227 vb = (top-pItem->z)>>8;
1228 else if (pItem->z > bottom)
1229 vb = (pItem->z-bottom)>>8;
1230 if (vb > 32)
1231 continue;
1232 if (approxDist(dx,dy) > 48)
1233 continue;
1234 GetSpriteExtents(pItem, &top, &bottom);
1235 if (cansee(x, y, z, nSector, pItem->x, pItem->y, pItem->z, pItem->sectnum)
1236 || cansee(x, y, z, nSector, pItem->x, pItem->y, top, pItem->sectnum)
1237 || cansee(x, y, z, nSector, pItem->x, pItem->y, bottom, pItem->sectnum))
1238 PickUp(pPlayer, pItem);
1239 }
1240 }
1241
ActionScan(PLAYER * pPlayer,int * a2,int * a3)1242 int ActionScan(PLAYER *pPlayer, int *a2, int *a3)
1243 {
1244 *a2 = 0;
1245 *a3 = 0;
1246 spritetype *pSprite = pPlayer->pSprite;
1247 int x = Cos(pSprite->ang)>>16;
1248 int y = Sin(pSprite->ang)>>16;
1249 int z = pPlayer->slope;
1250 int hit = HitScan(pSprite, pPlayer->zView, x, y, z, 0x10000040, 128);
1251 int hitDist = approxDist(pSprite->x-gHitInfo.hitx, pSprite->y-gHitInfo.hity)>>4;
1252 if (hitDist < 64)
1253 {
1254 switch (hit)
1255 {
1256 case 3:
1257 *a2 = gHitInfo.hitsprite;
1258 *a3 = sprite[*a2].extra;
1259 if (*a3 > 0 && sprite[*a2].statnum == kStatThing)
1260 {
1261 spritetype *pSprite = &sprite[*a2];
1262 XSPRITE *pXSprite = &xsprite[*a3];
1263 if (pSprite->type == kThingDroppedLifeLeech)
1264 {
1265 if (gGameOptions.nGameType > 1 && sub_3A158(pPlayer, pSprite))
1266 return -1;
1267 pXSprite->data4 = pPlayer->nPlayer;
1268 pXSprite->isTriggered = 0;
1269 }
1270 }
1271 if (*a3 > 0 && xsprite[*a3].Push)
1272 return 3;
1273 if (sprite[*a2].statnum == kStatDude)
1274 {
1275 spritetype *pSprite = &sprite[*a2];
1276 XSPRITE *pXSprite = &xsprite[*a3];
1277 int nMass = getDudeInfo(pSprite->type)->mass;
1278 if (nMass)
1279 {
1280 int t2 = divscale(0xccccc, nMass, 8);
1281 xvel[*a2] += mulscale16(x, t2);
1282 yvel[*a2] += mulscale16(y, t2);
1283 zvel[*a2] += mulscale16(z, t2);
1284 }
1285 if (pXSprite->Push && !pXSprite->state && !pXSprite->isTriggered)
1286 trTriggerSprite(*a2, pXSprite, kCmdSpritePush);
1287 }
1288 break;
1289 case 0:
1290 case 4:
1291 *a2 = gHitInfo.hitwall;
1292 *a3 = wall[*a2].extra;
1293 if (*a3 > 0 && xwall[*a3].triggerPush)
1294 return 0;
1295 if (wall[*a2].nextsector >= 0)
1296 {
1297 *a2 = wall[*a2].nextsector;
1298 *a3 = sector[*a2].extra;
1299 if (*a3 > 0 && xsector[*a3].Wallpush)
1300 return 6;
1301 }
1302 break;
1303 case 1:
1304 case 2:
1305 *a2 = gHitInfo.hitsect;
1306 *a3 = sector[*a2].extra;
1307 if (*a3 > 0 && xsector[*a3].Push)
1308 return 6;
1309 break;
1310 }
1311 }
1312 *a2 = pSprite->sectnum;
1313 *a3 = sector[*a2].extra;
1314 if (*a3 > 0 && xsector[*a3].Push)
1315 return 6;
1316 return -1;
1317 }
1318
ProcessInput(PLAYER * pPlayer)1319 void ProcessInput(PLAYER *pPlayer)
1320 {
1321 spritetype *pSprite = pPlayer->pSprite;
1322 XSPRITE *pXSprite = pPlayer->pXSprite;
1323 int nSprite = pPlayer->nSprite;
1324 POSTURE *pPosture = &pPlayer->pPosture[pPlayer->lifeMode][pPlayer->posture];
1325 GINPUT *pInput = &pPlayer->input;
1326
1327 if (pPlayer == gMe && numplayers == 1)
1328 {
1329 gViewAngleAdjust = 0.f;
1330 gViewLookRecenter = false;
1331 gViewLookAdjust = 0.f;
1332 }
1333
1334 pPlayer->isRunning = pInput->syncFlags.run;
1335 if (pInput->buttonFlags.byte || pInput->forward || pInput->strafe || pInput->q16turn)
1336 pPlayer->restTime = 0;
1337 else if (pPlayer->restTime >= 0)
1338 pPlayer->restTime += 4;
1339 WeaponProcess(pPlayer);
1340 if (pXSprite->health == 0)
1341 {
1342 char bSeqStat = playerSeqPlaying(pPlayer, 16);
1343 if (pPlayer->fraggerId != -1)
1344 {
1345 pPlayer->angold = pSprite->ang = getangle(sprite[pPlayer->fraggerId].x - pSprite->x, sprite[pPlayer->fraggerId].y - pSprite->y);
1346 pPlayer->q16ang = fix16_from_int(pSprite->ang);
1347 }
1348 pPlayer->deathTime += 4;
1349 if (!bSeqStat)
1350 {
1351 if (bVanilla)
1352 pPlayer->q16horiz = fix16_from_int(mulscale16(0x8000-(Cos(ClipHigh(pPlayer->deathTime*8, 1024))>>15), 120));
1353 else
1354 pPlayer->q16horiz = mulscale16(0x8000-(Cos(ClipHigh(pPlayer->deathTime*8, 1024))>>15), F16(120));
1355 }
1356 if (pPlayer->curWeapon)
1357 pInput->newWeapon = pPlayer->curWeapon;
1358 if (pInput->keyFlags.action)
1359 {
1360 if (bSeqStat)
1361 {
1362 if (pPlayer->deathTime > 360)
1363 seqSpawn(pPlayer->pDudeInfo->seqStartID+14, 3, pPlayer->pSprite->extra, nPlayerSurviveClient);
1364 }
1365 else if (seqGetStatus(3, pPlayer->pSprite->extra) < 0)
1366 {
1367 if (pPlayer->pSprite)
1368 pPlayer->pSprite->type = kThingBloodChunks;
1369 actPostSprite(pPlayer->nSprite, kStatThing);
1370 seqSpawn(pPlayer->pDudeInfo->seqStartID+15, 3, pPlayer->pSprite->extra, -1);
1371 playerReset(pPlayer);
1372 if (gGameOptions.nGameType == 0 && numplayers == 1)
1373 {
1374 if (gDemo.at0)
1375 gDemo.Close();
1376 pInput->keyFlags.restart = 1;
1377 }
1378 else
1379 playerStart(pPlayer->nPlayer);
1380 }
1381 pInput->keyFlags.action = 0;
1382 }
1383 return;
1384 }
1385 if (pPlayer->posture == 1)
1386 {
1387 int x = Cos(pSprite->ang);
1388 int y = Sin(pSprite->ang);
1389 if (pInput->forward)
1390 {
1391 int forward = pInput->forward;
1392 if (forward > 0)
1393 forward = mulscale8(pPosture->frontAccel, forward);
1394 else
1395 forward = mulscale8(pPosture->backAccel, forward);
1396 xvel[nSprite] += mulscale30(forward, x);
1397 yvel[nSprite] += mulscale30(forward, y);
1398 }
1399 if (pInput->strafe)
1400 {
1401 int strafe = pInput->strafe;
1402 strafe = mulscale8(pPosture->sideAccel, strafe);
1403 xvel[nSprite] += mulscale30(strafe, y);
1404 yvel[nSprite] -= mulscale30(strafe, x);
1405 }
1406 }
1407 else if (pXSprite->height < 256)
1408 {
1409 int speed = 0x10000;
1410 if (pXSprite->height > 0)
1411 speed -= divscale16(pXSprite->height, 256);
1412 int x = Cos(pSprite->ang);
1413 int y = Sin(pSprite->ang);
1414 if (pInput->forward)
1415 {
1416 int forward = pInput->forward;
1417 if (forward > 0)
1418 forward = mulscale8(pPosture->frontAccel, forward);
1419 else
1420 forward = mulscale8(pPosture->backAccel, forward);
1421 if (pXSprite->height)
1422 forward = mulscale16(forward, speed);
1423 xvel[nSprite] += mulscale30(forward, x);
1424 yvel[nSprite] += mulscale30(forward, y);
1425 }
1426 if (pInput->strafe)
1427 {
1428 int strafe = pInput->strafe;
1429 strafe = mulscale8(pPosture->sideAccel, strafe);
1430 if (pXSprite->height)
1431 strafe = mulscale16(strafe, speed);
1432 xvel[nSprite] += mulscale30(strafe, y);
1433 yvel[nSprite] -= mulscale30(strafe, x);
1434 }
1435 }
1436 if (pInput->q16turn)
1437 pPlayer->q16ang = (pPlayer->q16ang+pInput->q16turn)&0x7ffffff;
1438 if (pInput->keyFlags.spin180)
1439 {
1440 if (!pPlayer->spin)
1441 pPlayer->spin = -1024;
1442 pInput->keyFlags.spin180 = 0;
1443 }
1444 if (pPlayer->spin < 0)
1445 {
1446 int speed;
1447 if (pPlayer->posture == 1)
1448 speed = 64;
1449 else
1450 speed = 128;
1451 pPlayer->spin = min(pPlayer->spin+speed, 0);
1452 pPlayer->q16ang += fix16_from_int(speed);
1453 if (pPlayer == gMe && numplayers == 1)
1454 gViewAngleAdjust += float(speed);
1455 }
1456 if (pPlayer == gMe && numplayers == 1)
1457 gViewAngleAdjust += float(pSprite->ang - pPlayer->angold);
1458 pPlayer->q16ang = (pPlayer->q16ang+fix16_from_int(pSprite->ang-pPlayer->angold))&0x7ffffff;
1459 pPlayer->angold = pSprite->ang = fix16_to_int(pPlayer->q16ang);
1460 if (!pInput->buttonFlags.jump)
1461 pPlayer->cantJump = 0;
1462
1463 switch (pPlayer->posture) {
1464 case 1:
1465 if (pInput->buttonFlags.jump)
1466 zvel[nSprite] -= pPosture->normalJumpZ;//0x5b05;
1467 if (pInput->buttonFlags.crouch)
1468 zvel[nSprite] += pPosture->normalJumpZ;//0x5b05;
1469 break;
1470 case 2:
1471 if (!pInput->buttonFlags.crouch)
1472 pPlayer->posture = 0;
1473 break;
1474 default:
1475 if (!pPlayer->cantJump && pInput->buttonFlags.jump && pXSprite->height == 0) {
1476 #ifdef NOONE_EXTENSIONS
1477 if ((packItemActive(pPlayer, 4) && pPosture->pwupJumpZ != 0) || pPosture->normalJumpZ != 0)
1478 #endif
1479 sfxPlay3DSound(pSprite, 700, 0, 0);
1480
1481 if (packItemActive(pPlayer, 4)) zvel[nSprite] = pPosture->pwupJumpZ; //-0x175555;
1482 else zvel[nSprite] = pPosture->normalJumpZ; //-0xbaaaa;
1483 pPlayer->cantJump = 1;
1484 }
1485
1486 if (pInput->buttonFlags.crouch)
1487 pPlayer->posture = 2;
1488 break;
1489 }
1490 if (pInput->keyFlags.action)
1491 {
1492 int a2, a3;
1493 int hit = ActionScan(pPlayer, &a2, &a3);
1494 switch (hit)
1495 {
1496 case 6:
1497 if (a3 > 0 && a3 < kMaxXSectors)
1498 {
1499 XSECTOR *pXSector = &xsector[a3];
1500 int key = pXSector->Key;
1501 if (pXSector->locked && pPlayer == gMe)
1502 {
1503 viewSetMessage("It's locked");
1504 sndStartSample(3062, 255, 2, 0);
1505 }
1506 if (!key || pPlayer->hasKey[key])
1507 trTriggerSector(a2, pXSector, kCmdSpritePush);
1508 else if (pPlayer == gMe)
1509 {
1510 viewSetMessage("That requires a key.");
1511 sndStartSample(3063, 255, 2, 0);
1512 }
1513 }
1514 break;
1515 case 0:
1516 {
1517 XWALL *pXWall = &xwall[a3];
1518 int key = pXWall->key;
1519 if (pXWall->locked && pPlayer == gMe)
1520 {
1521 viewSetMessage("It's locked");
1522 sndStartSample(3062, 255, 2, 0);
1523 }
1524 if (!key || pPlayer->hasKey[key])
1525 trTriggerWall(a2, pXWall, kCmdWallPush);
1526 else if (pPlayer == gMe)
1527 {
1528 viewSetMessage("That requires a key.");
1529 sndStartSample(3063, 255, 2, 0);
1530 }
1531 break;
1532 }
1533 case 3:
1534 {
1535 XSPRITE *pXSprite = &xsprite[a3];
1536 int key = pXSprite->key;
1537 if (pXSprite->locked && pPlayer == gMe && pXSprite->lockMsg)
1538 trTextOver(pXSprite->lockMsg);
1539 if (!key || pPlayer->hasKey[key])
1540 trTriggerSprite(a2, pXSprite, kCmdSpritePush);
1541 else if (pPlayer == gMe)
1542 {
1543 viewSetMessage("That requires a key.");
1544 sndStartSample(3063, 255, 2, 0);
1545 }
1546 break;
1547 }
1548 }
1549 if (pPlayer->handTime > 0)
1550 pPlayer->handTime = ClipLow(pPlayer->handTime-4*(6-gGameOptions.nDifficulty), 0);
1551 if (pPlayer->handTime <= 0 && pPlayer->hand)
1552 {
1553 spritetype *pSprite2 = actSpawnDude(pPlayer->pSprite, kDudeHand, pPlayer->pSprite->clipdist<<1, 0);
1554 pSprite2->ang = (pPlayer->pSprite->ang+1024)&2047;
1555 int nSprite = pPlayer->pSprite->index;
1556 int x = Cos(pPlayer->pSprite->ang)>>16;
1557 int y = Sin(pPlayer->pSprite->ang)>>16;
1558 xvel[pSprite2->index] = xvel[nSprite] + mulscale14(0x155555, x);
1559 yvel[pSprite2->index] = yvel[nSprite] + mulscale14(0x155555, y);
1560 zvel[pSprite2->index] = zvel[nSprite];
1561 pPlayer->hand = 0;
1562 }
1563 pInput->keyFlags.action = 0;
1564 }
1565 if (bVanilla)
1566 {
1567 if (pInput->keyFlags.lookCenter && !pInput->buttonFlags.lookUp && !pInput->buttonFlags.lookDown)
1568 {
1569 if (pPlayer->q16look < 0)
1570 pPlayer->q16look = fix16_min(pPlayer->q16look+F16(4), F16(0));
1571 if (pPlayer->q16look > 0)
1572 pPlayer->q16look = fix16_max(pPlayer->q16look-F16(4), F16(0));
1573 if (!pPlayer->q16look)
1574 pInput->keyFlags.lookCenter = 0;
1575 }
1576 else
1577 {
1578 if (pInput->buttonFlags.lookUp)
1579 pPlayer->q16look = fix16_min(pPlayer->q16look+F16(4), F16(60));
1580 if (pInput->buttonFlags.lookDown)
1581 pPlayer->q16look = fix16_max(pPlayer->q16look-F16(4), F16(-60));
1582 }
1583 pPlayer->q16look = fix16_clamp(pPlayer->q16look+pInput->q16mlook, F16(-60), F16(60));
1584 if (pPlayer->q16look > 0)
1585 pPlayer->q16horiz = fix16_from_int(mulscale30(120, Sin(fix16_to_int(pPlayer->q16look)<<3)));
1586 else if (pPlayer->q16look < 0)
1587 pPlayer->q16horiz = fix16_from_int(mulscale30(180, Sin(fix16_to_int(pPlayer->q16look)<<3)));
1588 else
1589 pPlayer->q16horiz = 0;
1590 }
1591 else
1592 {
1593 CONSTEXPR int upAngle = 289;
1594 CONSTEXPR int downAngle = -347;
1595 CONSTEXPR double lookStepUp = 4.0*upAngle/60.0;
1596 CONSTEXPR double lookStepDown = -4.0*downAngle/60.0;
1597 if (pInput->keyFlags.lookCenter && !pInput->buttonFlags.lookUp && !pInput->buttonFlags.lookDown)
1598 {
1599 if (pPlayer->q16look < 0)
1600 pPlayer->q16look = fix16_min(pPlayer->q16look+F16(lookStepDown), F16(0));
1601 if (pPlayer->q16look > 0)
1602 pPlayer->q16look = fix16_max(pPlayer->q16look-F16(lookStepUp), F16(0));
1603 if (!pPlayer->q16look)
1604 pInput->keyFlags.lookCenter = 0;
1605 }
1606 else
1607 {
1608 if (pInput->buttonFlags.lookUp)
1609 pPlayer->q16look = fix16_min(pPlayer->q16look+F16(lookStepUp), F16(upAngle));
1610 if (pInput->buttonFlags.lookDown)
1611 pPlayer->q16look = fix16_max(pPlayer->q16look-F16(lookStepDown), F16(downAngle));
1612 }
1613 if (pPlayer == gMe && numplayers == 1)
1614 {
1615 if (pInput->buttonFlags.lookUp)
1616 {
1617 gViewLookAdjust += float(lookStepUp);
1618 }
1619 if (pInput->buttonFlags.lookDown)
1620 {
1621 gViewLookAdjust -= float(lookStepDown);
1622 }
1623 gViewLookRecenter = pInput->keyFlags.lookCenter && !pInput->buttonFlags.lookUp && !pInput->buttonFlags.lookDown;
1624 }
1625 pPlayer->q16look = fix16_clamp(pPlayer->q16look+(pInput->q16mlook<<3), F16(downAngle), F16(upAngle));
1626 pPlayer->q16horiz = fix16_from_float(100.f*tanf(fix16_to_float(pPlayer->q16look)*fPI/1024.f));
1627 }
1628 int nSector = pSprite->sectnum;
1629 int florhit = gSpriteHit[pSprite->extra].florhit & 0xc000;
1630 char va;
1631 if (pXSprite->height < 16 && (florhit == 0x4000 || florhit == 0))
1632 va = 1;
1633 else
1634 va = 0;
1635 if (va && (sector[nSector].floorstat&2))
1636 {
1637 int z1 = getflorzofslope(nSector, pSprite->x, pSprite->y);
1638 int x2 = pSprite->x+mulscale30(64, Cos(pSprite->ang));
1639 int y2 = pSprite->y+mulscale30(64, Sin(pSprite->ang));
1640 short nSector2 = nSector;
1641 updatesector(x2, y2, &nSector2);
1642 if (nSector2 == nSector)
1643 {
1644 int z2 = getflorzofslope(nSector2, x2, y2);
1645 pPlayer->q16slopehoriz = interpolate(pPlayer->q16slopehoriz, fix16_from_int(z1-z2)>>3, 0x4000);
1646 }
1647 }
1648 else
1649 {
1650 pPlayer->q16slopehoriz = interpolate(pPlayer->q16slopehoriz, F16(0), 0x4000);
1651 if (klabs(pPlayer->q16slopehoriz) < 4)
1652 pPlayer->q16slopehoriz = 0;
1653 }
1654 pPlayer->slope = (-fix16_to_int(pPlayer->q16horiz))<<7;
1655 if (pInput->keyFlags.prevItem)
1656 {
1657 pInput->keyFlags.prevItem = 0;
1658 packPrevItem(pPlayer);
1659 }
1660 if (pInput->keyFlags.nextItem)
1661 {
1662 pInput->keyFlags.nextItem = 0;
1663 packNextItem(pPlayer);
1664 }
1665 if (pInput->keyFlags.useItem)
1666 {
1667 pInput->keyFlags.useItem = 0;
1668 if (pPlayer->packSlots[pPlayer->packItemId].curAmount > 0)
1669 packUseItem(pPlayer, pPlayer->packItemId);
1670 }
1671 if (pInput->useFlags.useBeastVision)
1672 {
1673 pInput->useFlags.useBeastVision = 0;
1674 if (pPlayer->packSlots[3].curAmount > 0)
1675 packUseItem(pPlayer, 3);
1676 }
1677 if (pInput->useFlags.useCrystalBall)
1678 {
1679 pInput->useFlags.useCrystalBall = 0;
1680 if (pPlayer->packSlots[2].curAmount > 0)
1681 packUseItem(pPlayer, 2);
1682 }
1683 if (pInput->useFlags.useJumpBoots)
1684 {
1685 pInput->useFlags.useJumpBoots = 0;
1686 if (pPlayer->packSlots[4].curAmount > 0)
1687 packUseItem(pPlayer, 4);
1688 }
1689 if (pInput->useFlags.useMedKit)
1690 {
1691 pInput->useFlags.useMedKit = 0;
1692 if (pPlayer->packSlots[0].curAmount > 0)
1693 packUseItem(pPlayer, 0);
1694 }
1695 if (pInput->keyFlags.holsterWeapon)
1696 {
1697 pInput->keyFlags.holsterWeapon = 0;
1698 if (pPlayer->curWeapon)
1699 {
1700 WeaponLower(pPlayer);
1701 viewSetMessage("Holstering weapon");
1702 }
1703 }
1704 CheckPickUp(pPlayer);
1705 }
1706
playerProcess(PLAYER * pPlayer)1707 void playerProcess(PLAYER *pPlayer)
1708 {
1709 spritetype *pSprite = pPlayer->pSprite;
1710 int nSprite = pPlayer->nSprite;
1711 int nXSprite = pSprite->extra;
1712 XSPRITE *pXSprite = pPlayer->pXSprite;
1713 POSTURE* pPosture = &pPlayer->pPosture[pPlayer->lifeMode][pPlayer->posture];
1714 powerupProcess(pPlayer);
1715 int top, bottom;
1716 GetSpriteExtents(pSprite, &top, &bottom);
1717 int dzb = (bottom-pSprite->z)/4;
1718 int dzt = (pSprite->z-top)/4;
1719 int dw = pSprite->clipdist<<2;
1720 if (!gNoClip)
1721 {
1722 short nSector = pSprite->sectnum;
1723 if (pushmove_old(&pSprite->x, &pSprite->y, &pSprite->z, &nSector, dw, dzt, dzb, CLIPMASK0) == -1)
1724 actDamageSprite(nSprite, pSprite, kDamageFall, 500<<4);
1725 if (pSprite->sectnum != nSector)
1726 {
1727 if (nSector == -1)
1728 {
1729 nSector = pSprite->sectnum;
1730 actDamageSprite(nSprite, pSprite, kDamageFall, 500<<4);
1731 }
1732 dassert(nSector >= 0 && nSector < kMaxSectors);
1733 ChangeSpriteSect(nSprite, nSector);
1734 }
1735 }
1736 ProcessInput(pPlayer);
1737 int nSpeed = approxDist(xvel[nSprite], yvel[nSprite]);
1738 pPlayer->zViewVel = interpolate(pPlayer->zViewVel, zvel[nSprite], 0x7000);
1739 int dz = pPlayer->pSprite->z-pPosture->eyeAboveZ-pPlayer->zView;
1740 if (dz > 0)
1741 pPlayer->zViewVel += mulscale16(dz<<8, 0xa000);
1742 else
1743 pPlayer->zViewVel += mulscale16(dz<<8, 0x1800);
1744 pPlayer->zView += pPlayer->zViewVel>>8;
1745 pPlayer->zWeaponVel = interpolate(pPlayer->zWeaponVel, zvel[nSprite], 0x5000);
1746 dz = pPlayer->pSprite->z-pPosture->weaponAboveZ-pPlayer->zWeapon;
1747 if (dz > 0)
1748 pPlayer->zWeaponVel += mulscale16(dz<<8, 0x8000);
1749 else
1750 pPlayer->zWeaponVel += mulscale16(dz<<8, 0xc00);
1751 pPlayer->zWeapon += pPlayer->zWeaponVel>>8;
1752 pPlayer->bobPhase = ClipLow(pPlayer->bobPhase-4, 0);
1753 nSpeed >>= 16;
1754 if (pPlayer->posture == 1)
1755 {
1756 pPlayer->bobAmp = (pPlayer->bobAmp+17)&2047;
1757 pPlayer->swayAmp = (pPlayer->swayAmp+17)&2047;
1758 pPlayer->bobHeight = mulscale30(pPosture->bobV*10, Sin(pPlayer->bobAmp*2));
1759 pPlayer->bobWidth = mulscale30(pPosture->bobH*pPlayer->bobPhase, Sin(pPlayer->bobAmp-256));
1760 pPlayer->swayHeight = mulscale30(pPosture->swayV*pPlayer->bobPhase, Sin(pPlayer->swayAmp*2));
1761 pPlayer->swayWidth = mulscale30(pPosture->swayH*pPlayer->bobPhase, Sin(pPlayer->swayAmp-0x155));
1762 }
1763 else
1764 {
1765 if (pXSprite->height < 256)
1766 {
1767 pPlayer->bobAmp = (pPlayer->bobAmp+pPosture->pace[pPlayer->isRunning]*4) & 2047;
1768 pPlayer->swayAmp = (pPlayer->swayAmp+(pPosture->pace[pPlayer->isRunning]*4)/2) & 2047;
1769 if (pPlayer->isRunning)
1770 {
1771 if (pPlayer->bobPhase < 60)
1772 pPlayer->bobPhase = ClipHigh(pPlayer->bobPhase+nSpeed, 60);
1773 }
1774 else
1775 {
1776 if (pPlayer->bobPhase < 30)
1777 pPlayer->bobPhase = ClipHigh(pPlayer->bobPhase+nSpeed, 30);
1778 }
1779 }
1780 pPlayer->bobHeight = mulscale30(pPosture->bobV*pPlayer->bobPhase, Sin(pPlayer->bobAmp*2));
1781 pPlayer->bobWidth = mulscale30(pPosture->bobH*pPlayer->bobPhase, Sin(pPlayer->bobAmp-256));
1782 pPlayer->swayHeight = mulscale30(pPosture->swayV*pPlayer->bobPhase, Sin(pPlayer->swayAmp*2));
1783 pPlayer->swayWidth = mulscale30(pPosture->swayH*pPlayer->bobPhase, Sin(pPlayer->swayAmp-0x155));
1784 }
1785 pPlayer->flickerEffect = 0;
1786 pPlayer->quakeEffect = ClipLow(pPlayer->quakeEffect-4, 0);
1787 pPlayer->tiltEffect = ClipLow(pPlayer->tiltEffect-4, 0);
1788 pPlayer->visibility = ClipLow(pPlayer->visibility-4, 0);
1789 pPlayer->painEffect = ClipLow(pPlayer->painEffect-4, 0);
1790 pPlayer->blindEffect = ClipLow(pPlayer->blindEffect-4, 0);
1791 pPlayer->pickupEffect = ClipLow(pPlayer->pickupEffect-4, 0);
1792 if (pPlayer == gMe && gMe->pXSprite->health == 0)
1793 pPlayer->hand = 0;
1794 if (!pXSprite->health)
1795 return;
1796 pPlayer->isUnderwater = 0;
1797 if (pPlayer->posture == 1)
1798 {
1799 pPlayer->isUnderwater = 1;
1800 int nSector = pSprite->sectnum;
1801 int nLink = gLowerLink[nSector];
1802 if (nLink > 0 && (sprite[nLink].type == kMarkerLowGoo || sprite[nLink].type == kMarkerLowWater))
1803 {
1804 if (getceilzofslope(nSector, pSprite->x, pSprite->y) > pPlayer->zView)
1805 pPlayer->isUnderwater = 0;
1806 }
1807 }
1808 if (!pPlayer->isUnderwater)
1809 {
1810 pPlayer->underwaterTime = 1200;
1811 pPlayer->chokeEffect = 0;
1812 if (packItemActive(pPlayer, 1))
1813 packUseItem(pPlayer, 1);
1814 }
1815 int nType = kDudePlayer1-kDudeBase;
1816 switch (pPlayer->posture)
1817 {
1818 case 1:
1819 seqSpawn(dudeInfo[nType].seqStartID+9, 3, nXSprite, -1);
1820 break;
1821 case 2:
1822 seqSpawn(dudeInfo[nType].seqStartID+10, 3, nXSprite, -1);
1823 break;
1824 default:
1825 if (!nSpeed)
1826 seqSpawn(dudeInfo[nType].seqStartID, 3, nXSprite, -1);
1827 else
1828 seqSpawn(dudeInfo[nType].seqStartID+8, 3, nXSprite, -1);
1829 break;
1830 }
1831 }
1832
playerFireMissile(PLAYER * pPlayer,int a2,int a3,int a4,int a5,int a6)1833 spritetype *playerFireMissile(PLAYER *pPlayer, int a2, int a3, int a4, int a5, int a6)
1834 {
1835 return actFireMissile(pPlayer->pSprite, a2, pPlayer->zWeapon-pPlayer->pSprite->z, a3, a4, a5, a6);
1836 }
1837
playerFireThing(PLAYER * pPlayer,int a2,int a3,int thingType,int a5)1838 spritetype * playerFireThing(PLAYER *pPlayer, int a2, int a3, int thingType, int a5)
1839 {
1840 dassert(thingType >= kThingBase && thingType < kThingMax);
1841 return actFireThing(pPlayer->pSprite, a2, pPlayer->zWeapon-pPlayer->pSprite->z, pPlayer->slope+a3, thingType, a5);
1842 }
1843
playerFrag(PLAYER * pKiller,PLAYER * pVictim)1844 void playerFrag(PLAYER *pKiller, PLAYER *pVictim)
1845 {
1846 dassert(pKiller != NULL);
1847 dassert(pVictim != NULL);
1848
1849 char buffer[128] = "";
1850 int nKiller = pKiller->pSprite->type-kDudePlayer1;
1851 dassert(nKiller >= 0 && nKiller < kMaxPlayers);
1852 int nVictim = pVictim->pSprite->type-kDudePlayer1;
1853 dassert(nVictim >= 0 && nVictim < kMaxPlayers);
1854 if (myconnectindex == connecthead)
1855 {
1856 sprintf(buffer, "frag %d killed %d\n", pKiller->nPlayer+1, pVictim->nPlayer+1);
1857 sub_7AC28(buffer);
1858 buffer[0] = 0;
1859 }
1860 if (nKiller == nVictim)
1861 {
1862 pVictim->fraggerId = -1;
1863 if (VanillaMode() || gGameOptions.nGameType != 1)
1864 {
1865 pVictim->fragCount--;
1866 pVictim->fragInfo[nVictim]--;
1867 }
1868 if (gGameOptions.nGameType == 3)
1869 dword_21EFB0[pVictim->teamId]--;
1870 int nMessage = Random(5);
1871 int nSound = gSuicide[nMessage].at4;
1872 if (pVictim == gMe && gMe->handTime <= 0)
1873 {
1874 sprintf(buffer, "You killed yourself!");
1875 if (gGameOptions.nGameType > 0 && nSound >= 0)
1876 sndStartSample(nSound, 255, 2, 0);
1877 }
1878 else
1879 {
1880 sprintf(buffer, gSuicide[nMessage].at0, gProfile[nVictim].name);
1881 }
1882 }
1883 else
1884 {
1885 if (VanillaMode() || gGameOptions.nGameType != 1)
1886 {
1887 pKiller->fragCount++;
1888 pKiller->fragInfo[nKiller]++;
1889 }
1890 if (gGameOptions.nGameType == 3)
1891 {
1892 if (pKiller->teamId == pVictim->teamId)
1893 dword_21EFB0[pKiller->teamId]--;
1894 else
1895 {
1896 dword_21EFB0[pKiller->teamId]++;
1897 dword_21EFD0[pKiller->teamId]+=120;
1898 }
1899 }
1900 int nMessage = Random(25);
1901 int nSound = gVictory[nMessage].at4;
1902 const char* pzMessage = gVictory[nMessage].at0;
1903 sprintf(buffer, pzMessage, gProfile[nKiller].name, gProfile[nVictim].name);
1904 if (gGameOptions.nGameType > 0 && nSound >= 0 && pKiller == gMe)
1905 sndStartSample(nSound, 255, 2, 0);
1906 }
1907 viewSetMessage(buffer);
1908 }
1909
FragPlayer(PLAYER * pPlayer,int nSprite)1910 void FragPlayer(PLAYER *pPlayer, int nSprite)
1911 {
1912 spritetype *pSprite = NULL;
1913 if (nSprite >= 0)
1914 pSprite = &sprite[nSprite];
1915 if (pSprite && IsPlayerSprite(pSprite))
1916 {
1917 PLAYER *pKiller = &gPlayer[pSprite->type - kDudePlayer1];
1918 playerFrag(pKiller, pPlayer);
1919 int nTeam1 = pKiller->teamId&1;
1920 int nTeam2 = pPlayer->teamId&1;
1921 if (nTeam1 == 0)
1922 {
1923 if (nTeam1 != nTeam2)
1924 evSend(0, 0, 15, kCmdToggle);
1925 else
1926 evSend(0, 0, 16, kCmdToggle);
1927 }
1928 else
1929 {
1930 if (nTeam1 == nTeam2)
1931 evSend(0, 0, 16, kCmdToggle);
1932 else
1933 evSend(0, 0, 15, kCmdToggle);
1934 }
1935 }
1936 }
1937
playerDamageArmor(PLAYER * pPlayer,DAMAGE_TYPE nType,int nDamage)1938 int playerDamageArmor(PLAYER *pPlayer, DAMAGE_TYPE nType, int nDamage)
1939 {
1940 DAMAGEINFO *pDamageInfo = &damageInfo[nType];
1941 int nArmorType = pDamageInfo->at0;
1942 if (nArmorType >= 0 && pPlayer->armor[nArmorType])
1943 {
1944 #if 0
1945 int vbp = (nDamage*7)/8-nDamage/4;
1946 int v8 = pPlayer->at33e[nArmorType];
1947 int t = nDamage/4 + vbp * v8 / 3200;
1948 v8 -= t;
1949 #endif
1950 int v8 = pPlayer->armor[nArmorType];
1951 int t = scale(v8, 0, 3200, nDamage/4, (nDamage*7)/8);
1952 v8 -= t;
1953 nDamage -= t;
1954 pPlayer->armor[nArmorType] = ClipLow(v8, 0);
1955 }
1956 return nDamage;
1957 }
1958
sub_40A94(PLAYER * pPlayer,int a2)1959 spritetype *sub_40A94(PLAYER *pPlayer, int a2)
1960 {
1961 char buffer[80];
1962 spritetype *pSprite = NULL;
1963 switch (a2)
1964 {
1965 case kItemFlagA:
1966 pPlayer->hasFlag &= ~1;
1967 pSprite = actDropObject(pPlayer->pSprite, kItemFlagA);
1968 if (pSprite)
1969 pSprite->owner = pPlayer->used2[0];
1970 gBlueFlagDropped = true;
1971 sprintf(buffer, "%s dropped Blue Flag", gProfile[pPlayer->nPlayer].name);
1972 sndStartSample(8005, 255, 2, 0);
1973 viewSetMessage(buffer);
1974 break;
1975 case kItemFlagB:
1976 pPlayer->hasFlag &= ~2;
1977 pSprite = actDropObject(pPlayer->pSprite, kItemFlagB);
1978 if (pSprite)
1979 pSprite->owner = pPlayer->used2[1];
1980 gRedFlagDropped = true;
1981 sprintf(buffer, "%s dropped Red Flag", gProfile[pPlayer->nPlayer].name);
1982 sndStartSample(8004, 255, 2, 0);
1983 viewSetMessage(buffer);
1984 break;
1985 }
1986 return pSprite;
1987 }
1988
playerDamageSprite(int nSource,PLAYER * pPlayer,DAMAGE_TYPE nDamageType,int nDamage)1989 int playerDamageSprite(int nSource, PLAYER *pPlayer, DAMAGE_TYPE nDamageType, int nDamage)
1990 {
1991 dassert(nSource < kMaxSprites);
1992 dassert(pPlayer != NULL);
1993 if (pPlayer->damageControl[nDamageType])
1994 return 0;
1995 nDamage = playerDamageArmor(pPlayer, nDamageType, nDamage);
1996 pPlayer->painEffect = ClipHigh(pPlayer->painEffect+(nDamage>>3), 600);
1997
1998 spritetype *pSprite = pPlayer->pSprite;
1999 XSPRITE *pXSprite = pPlayer->pXSprite;
2000 int nXSprite = pSprite->extra;
2001 int nXSector = sector[pSprite->sectnum].extra;
2002 DUDEINFO *pDudeInfo = getDudeInfo(pSprite->type);
2003 int nDeathSeqID = -1;
2004 int nKneelingPlayer = -1;
2005 int nSprite = pSprite->index;
2006 char va = playerSeqPlaying(pPlayer, 16);
2007 if (!pXSprite->health)
2008 {
2009 if (va)
2010 {
2011 switch (nDamageType)
2012 {
2013 case kDamageSpirit:
2014 nDeathSeqID = 18;
2015 sfxPlay3DSound(pSprite, 716, 0, 0);
2016 break;
2017 case kDamageExplode:
2018 GibSprite(pSprite, GIBTYPE_7, NULL, NULL);
2019 GibSprite(pSprite, GIBTYPE_15, NULL, NULL);
2020 pPlayer->pSprite->cstat |= 32768;
2021 nDeathSeqID = 17;
2022 break;
2023 default:
2024 {
2025 int top, bottom;
2026 GetSpriteExtents(pSprite, &top, &bottom);
2027 CGibPosition gibPos(pSprite->x, pSprite->y, top);
2028 CGibVelocity gibVel(xvel[pSprite->index]>>1, yvel[pSprite->index]>>1, -0xccccc);
2029 GibSprite(pSprite, GIBTYPE_27, &gibPos, &gibVel);
2030 GibSprite(pSprite, GIBTYPE_7, NULL, NULL);
2031 fxSpawnBlood(pSprite, nDamage<<4);
2032 fxSpawnBlood(pSprite, nDamage<<4);
2033 nDeathSeqID = 17;
2034 break;
2035 }
2036 }
2037 }
2038 }
2039 else
2040 {
2041 int nHealth = pXSprite->health-nDamage;
2042 pXSprite->health = ClipLow(nHealth, 0);
2043 if (pXSprite->health > 0 && pXSprite->health < 16)
2044 {
2045 nDamageType = kDamageBullet;
2046 pXSprite->health = 0;
2047 nHealth = -25;
2048 }
2049 if (pXSprite->health > 0)
2050 {
2051 DAMAGEINFO *pDamageInfo = &damageInfo[nDamageType];
2052 int nSound;
2053 if (nDamage >= (10<<4))
2054 nSound = pDamageInfo->at4[0];
2055 else
2056 nSound = pDamageInfo->at4[Random(3)];
2057 if (nDamageType == kDamageDrown && pXSprite->medium == kMediumWater && !pPlayer->hand)
2058 nSound = 714;
2059 sfxPlay3DSound(pSprite, nSound, 0, 6);
2060 return nDamage;
2061 }
2062 sfxKill3DSound(pPlayer->pSprite, -1, 441);
2063 if (gGameOptions.nGameType == 3 && pPlayer->hasFlag) {
2064 if (pPlayer->hasFlag&1) sub_40A94(pPlayer, kItemFlagA);
2065 if (pPlayer->hasFlag&2) sub_40A94(pPlayer, kItemFlagB);
2066 }
2067 pPlayer->deathTime = 0;
2068 pPlayer->qavLoop = 0;
2069 pPlayer->curWeapon = 0;
2070 pPlayer->fraggerId = nSource;
2071 pPlayer->voodooTargets = 0;
2072 if (nDamageType == kDamageExplode && nDamage < (9<<4))
2073 nDamageType = kDamageFall;
2074 switch (nDamageType)
2075 {
2076 case kDamageExplode:
2077 sfxPlay3DSound(pSprite, 717, 0, 0);
2078 GibSprite(pSprite, GIBTYPE_7, NULL, NULL);
2079 GibSprite(pSprite, GIBTYPE_15, NULL, NULL);
2080 pPlayer->pSprite->cstat |= 32768;
2081 nDeathSeqID = 2;
2082 break;
2083 case kDamageBurn:
2084 sfxPlay3DSound(pSprite, 718, 0, 0);
2085 nDeathSeqID = 3;
2086 break;
2087 case kDamageDrown:
2088 nDeathSeqID = 1;
2089 break;
2090 default:
2091 if (nHealth < -20 && gGameOptions.nGameType >= 2 && Chance(0x4000))
2092 {
2093 DAMAGEINFO *pDamageInfo = &damageInfo[nDamageType];
2094 sfxPlay3DSound(pSprite, pDamageInfo->at10[0], 0, 2);
2095 nDeathSeqID = 16;
2096 nKneelingPlayer = nPlayerKneelClient;
2097 powerupActivate(pPlayer, kPwUpDeliriumShroom);
2098 pXSprite->target = nSource;
2099 evPost(pSprite->index, 3, 15, kCallbackFinishHim);
2100 }
2101 else
2102 {
2103 sfxPlay3DSound(pSprite, 716, 0, 0);
2104 nDeathSeqID = 1;
2105 }
2106 break;
2107 }
2108 }
2109 if (nDeathSeqID < 0)
2110 return nDamage;
2111 if (nDeathSeqID != 16)
2112 {
2113 powerupClear(pPlayer);
2114 if (nXSector > 0 && xsector[nXSector].Exit)
2115 trTriggerSector(pSprite->sectnum, &xsector[nXSector], kCmdSectorExit);
2116 pSprite->flags |= 7;
2117 for (int p = connecthead; p >= 0; p = connectpoint2[p])
2118 {
2119 if (gPlayer[p].fraggerId == nSprite && gPlayer[p].deathTime > 0)
2120 gPlayer[p].fraggerId = -1;
2121 }
2122 FragPlayer(pPlayer, nSource);
2123 trTriggerSprite(nSprite, pXSprite, kCmdOff);
2124
2125 #ifdef NOONE_EXTENSIONS
2126 // allow drop items and keys in multiplayer
2127 if (gModernMap && gGameOptions.nGameType != 0 && pPlayer->pXSprite->health <= 0) {
2128
2129 spritetype* pItem = NULL;
2130 if (pPlayer->pXSprite->dropMsg && (pItem = actDropItem(pPlayer->pSprite, pPlayer->pXSprite->dropMsg)) != NULL)
2131 evPost(pItem->index, OBJ_SPRITE, 500, kCallbackRemove);
2132
2133 if (pPlayer->pXSprite->key) {
2134
2135 int i; // if all players have this key, don't drop it
2136 for (i = connecthead; i >= 0; i = connectpoint2[i]) {
2137 if (!gPlayer[i].hasKey[pPlayer->pXSprite->key])
2138 break;
2139 }
2140
2141 if (i == 0 && (pItem = actDropKey(pPlayer->pSprite, (pPlayer->pXSprite->key + kItemKeyBase) - 1)) != NULL)
2142 evPost(pItem->index, OBJ_SPRITE, 500, kCallbackRemove);
2143
2144 }
2145
2146
2147 }
2148 #endif
2149
2150 }
2151 dassert(gSysRes.Lookup(pDudeInfo->seqStartID + nDeathSeqID, "SEQ") != NULL);
2152 seqSpawn(pDudeInfo->seqStartID+nDeathSeqID, 3, nXSprite, nKneelingPlayer);
2153 return nDamage;
2154 }
2155
UseAmmo(PLAYER * pPlayer,int nAmmoType,int nDec)2156 int UseAmmo(PLAYER *pPlayer, int nAmmoType, int nDec)
2157 {
2158 if (gInfiniteAmmo)
2159 return 9999;
2160 if (nAmmoType == -1)
2161 return 9999;
2162 pPlayer->ammoCount[nAmmoType] = ClipLow(pPlayer->ammoCount[nAmmoType]-nDec, 0);
2163 return pPlayer->ammoCount[nAmmoType];
2164 }
2165
sub_41250(PLAYER * pPlayer)2166 void sub_41250(PLAYER *pPlayer)
2167 {
2168 int v4 = pPlayer->aim.dz;
2169 int dz = pPlayer->zWeapon-pPlayer->pSprite->z;
2170 if (UseAmmo(pPlayer, 9, 0) < 8)
2171 {
2172 pPlayer->voodooTargets = 0;
2173 return;
2174 }
2175 for (int i = 0; i < 4; i++)
2176 {
2177 int ang1 = (pPlayer->voodooVar1+pPlayer->vodooVar2)&2047;
2178 actFireVector(pPlayer->pSprite, 0, dz, Cos(ang1)>>16, Sin(ang1)>>16, v4, kVectorVoodoo10);
2179 int ang2 = (pPlayer->voodooVar1+2048-pPlayer->vodooVar2)&2047;
2180 actFireVector(pPlayer->pSprite, 0, dz, Cos(ang2)>>16, Sin(ang2)>>16, v4, kVectorVoodoo10);
2181 }
2182 pPlayer->voodooTargets = ClipLow(pPlayer->voodooTargets-1, 0);
2183 }
2184
playerLandingSound(PLAYER * pPlayer)2185 void playerLandingSound(PLAYER *pPlayer)
2186 {
2187 static int surfaceSound[] = {
2188 -1,
2189 600,
2190 601,
2191 602,
2192 603,
2193 604,
2194 605,
2195 605,
2196 605,
2197 600,
2198 605,
2199 605,
2200 605,
2201 604,
2202 603
2203 };
2204 spritetype *pSprite = pPlayer->pSprite;
2205 SPRITEHIT *pHit = &gSpriteHit[pSprite->extra];
2206 if (pHit->florhit)
2207 {
2208 if (!gGameOptions.bFriendlyFire && IsTargetTeammate(pPlayer, &sprite[pHit->florhit & 0x3fff]))
2209 return;
2210 char nSurf = tileGetSurfType(pHit->florhit);
2211 if (nSurf)
2212 sfxPlay3DSound(pSprite, surfaceSound[nSurf], -1, 0);
2213 }
2214 }
2215
PlayerSurvive(int,int nXSprite)2216 void PlayerSurvive(int, int nXSprite)
2217 {
2218 char buffer[80];
2219 XSPRITE *pXSprite = &xsprite[nXSprite];
2220 int nSprite = pXSprite->reference;
2221 spritetype *pSprite = &sprite[nSprite];
2222 actHealDude(pXSprite, 1, 2);
2223 if (gGameOptions.nGameType > 0 && numplayers > 1)
2224 {
2225 sfxPlay3DSound(pSprite, 3009, 0, 6);
2226 if (IsPlayerSprite(pSprite))
2227 {
2228 PLAYER *pPlayer = &gPlayer[pSprite->type-kDudePlayer1];
2229 if (pPlayer == gMe)
2230 viewSetMessage("I LIVE...AGAIN!!");
2231 else
2232 {
2233 sprintf(buffer, "%s lives again!", gProfile[pPlayer->nPlayer].name);
2234 viewSetMessage(buffer);
2235 }
2236 pPlayer->input.newWeapon = 1;
2237 }
2238 }
2239 }
2240
PlayerKneelsOver(int,int nXSprite)2241 void PlayerKneelsOver(int, int nXSprite)
2242 {
2243 XSPRITE *pXSprite = &xsprite[nXSprite];
2244 for (int p = connecthead; p >= 0; p = connectpoint2[p])
2245 {
2246 if (gPlayer[p].pXSprite == pXSprite)
2247 {
2248 PLAYER *pPlayer = &gPlayer[p];
2249 playerDamageSprite(pPlayer->fraggerId, pPlayer, kDamageSpirit, 500<<4);
2250 return;
2251 }
2252 }
2253 }
2254
2255 class PlayerLoadSave : public LoadSave
2256 {
2257 public:
2258 virtual void Load(void);
2259 virtual void Save(void);
2260 };
2261
Load(void)2262 void PlayerLoadSave::Load(void)
2263 {
2264
2265 Read(dword_21EFB0, sizeof(dword_21EFB0));
2266 Read(&gNetPlayers, sizeof(gNetPlayers));
2267 Read(&gProfile, sizeof(gProfile));
2268 Read(&gPlayer, sizeof(gPlayer));
2269 #ifdef NOONE_EXTENSIONS
2270 Read(&gPlayerCtrl, sizeof(gPlayerCtrl));
2271 #endif
2272 for (int i = 0; i < gNetPlayers; i++) {
2273 gPlayer[i].pSprite = &sprite[gPlayer[i].nSprite];
2274 gPlayer[i].pXSprite = &xsprite[gPlayer[i].pSprite->extra];
2275 gPlayer[i].pDudeInfo = &dudeInfo[gPlayer[i].pSprite->type-kDudeBase];
2276
2277 #ifdef NOONE_EXTENSIONS
2278 // load qav scene
2279 if (gPlayer[i].sceneQav != -1) {
2280 if (gPlayerCtrl[i].qavScene.qavResrc == NULL)
2281 gPlayer[i].sceneQav = -1;
2282 else {
2283 QAV* pQav = playerQavSceneLoad(gPlayer[i].sceneQav);
2284 if (pQav) {
2285 gPlayerCtrl[i].qavScene.qavResrc = pQav;
2286 gPlayerCtrl[i].qavScene.qavResrc->Preload();
2287 } else {
2288 gPlayer[i].sceneQav = -1;
2289 }
2290 }
2291 }
2292 #endif
2293
2294 }
2295 }
2296
Save(void)2297 void PlayerLoadSave::Save(void)
2298 {
2299 Write(dword_21EFB0, sizeof(dword_21EFB0));
2300 Write(&gNetPlayers, sizeof(gNetPlayers));
2301 Write(&gProfile, sizeof(gProfile));
2302 Write(&gPlayer, sizeof(gPlayer));
2303
2304 #ifdef NOONE_EXTENSIONS
2305 Write(&gPlayerCtrl, sizeof(gPlayerCtrl));
2306 #endif
2307 }
2308
2309 static PlayerLoadSave *myLoadSave;
2310
PlayerLoadSaveConstruct(void)2311 void PlayerLoadSaveConstruct(void)
2312 {
2313 myLoadSave = new PlayerLoadSave();
2314 }
2315