1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 1997, 2005 - 3D Realms Entertainment
4
5 This file is part of Shadow Warrior version 1.2
6
7 Shadow Warrior is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
22 Original Source: 1997 - Frank Maddin and Jim Norwood
23 Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
24 */
25 //-------------------------------------------------------------------------
26 #include "build.h"
27
28 #include "mytypes.h"
29 #include "keys.h"
30 #include "names2.h"
31 #include "panel.h"
32 #include "game.h"
33 #include "tags.h"
34 #include "player.h"
35 #include "lists.h"
36 #include "warp.h"
37 #include "quake.h"
38 #include "text.h"
39
40 #include "mathutil.h"
41 #include "function.h"
42 #include "control.h"
43 #include "trigger.h"
44
45 #include "menus.h"
46 #include "net.h"
47 #include "pal.h"
48 #include "demo.h"
49 #include "mclip.h"
50 #include "fx_man.h"
51
52 #include "sprite.h"
53 #include "weapon.h"
54 #include "ninja.h"
55 #include "break.h"
56 #include "jsector.h"
57 #include "sector.h"
58 #include "actor.h"
59 #include "colormap.h"
60 #include "music.h"
61 #include "vis.h"
62 #include "track.h"
63 #include "interp.h"
64
65
66 #define SO_DRIVE_SOUND 2
67 #define SO_IDLE_SOUND 1
68
69 extern BOOL NoMeters;
70 extern int Follow_posx,Follow_posy;
71
72 #define TEST_UNDERWATER(pp) (TEST(sector[(pp)->cursectnum].extra, SECTFX_UNDERWATER))
73 extern unsigned char palette_data[256][3]; // Global palette array
74
75 //#define PLAYER_MIN_HEIGHT (Z(30))
76 //#define PLAYER_MIN_HEIGHT_JUMP (Z(20))
77 #define PLAYER_MIN_HEIGHT (Z(20))
78 #define PLAYER_CRAWL_WADE_DEPTH (30)
79
80 USER puser[MAX_SW_PLAYERS_REG];
81
82 //SHORT gNet.MultiGameType = MULTI_GAME_NONE;
83 BOOL NightVision = FALSE;
84 extern BOOL FinishedLevel;
85
86 //#define PLAYER_TURN_SCALE (8)
87 #define PLAYER_TURN_SCALE (12)
88
89 // the smaller the number the slower the going
90 #define PLAYER_RUN_FRICTION (50000L)
91 //#define PLAYER_RUN_FRICTION 0xcb00
92 #define PLAYER_JUMP_FRICTION PLAYER_RUN_FRICTION
93 #define PLAYER_FALL_FRICTION PLAYER_RUN_FRICTION
94
95 #define PLAYER_WADE_FRICTION PLAYER_RUN_FRICTION
96 #define PLAYER_FLY_FRICTION (55808L)
97
98 #define PLAYER_CRAWL_FRICTION (45056L)
99 #define PLAYER_SWIM_FRICTION (49152L)
100 #define PLAYER_DIVE_FRICTION (49152L)
101
102 // only for z direction climbing
103 #define PLAYER_CLIMB_FRICTION (45056L)
104
105 //#define BOAT_FRICTION 0xd000
106 #define BOAT_FRICTION 0xcb00
107 //#define TANK_FRICTION 0xcb00
108 #define TANK_FRICTION (53248L)
109 #define PLAYER_SLIDE_FRICTION (53248L)
110
111 #define PLAYER_RUN_LOCK(pp) \
112 if (TEST_SYNC_KEY((pp), SK_RUN_LOCK)) \
113 { \
114 if (FLAG_KEY_PRESSED((pp), SK_RUN_LOCK)) \
115 { \
116 FLAG_KEY_RELEASE((pp), SK_RUN_LOCK); \
117 FLIP((pp)->Flags, PF_LOCK_RUN); \
118 gs.AutoRun = !!TEST((pp)->Flags, PF_LOCK_RUN); \
119 sprintf(ds, "Run mode %s", TEST((pp)->Flags, PF_LOCK_RUN) ? "ON" : "OFF"); \
120 PutStringInfo((pp), ds); \
121 } \
122 } \
123 else \
124 FLAG_KEY_RESET((pp), SK_RUN_LOCK) \
125
126 #define JUMP_STUFF 4
127
128 // just like 2 except can jump higher - less gravity
129 // goes better with slightly slower run speed than I had it at
130 #if JUMP_STUFF == 4
131 #define PLAYER_JUMP_GRAV 24
132 #define PLAYER_JUMP_AMT (-650)
133 #define PLAYER_CLIMB_JUMP_AMT (-1100)
134 #define MAX_JUMP_DURATION 12
135 char PlayerGravity = PLAYER_JUMP_GRAV;
136 #endif
137
138 int vel, svel, angvel;
139 extern char tempbuf[];
140 extern BOOL DebugOperate;
141
142 //unsigned char synctics, lastsynctics;
143
144 int dimensionmode, zoom;
145
146 PLAYER Player[MAX_SW_PLAYERS_REG + 1];
147
148 //short snum = 0;
149
150 // These are a bunch of kens variables for the player
151
152 short NormalVisibility;
153
154 static short oldmousebstatus = 0;
155 static short mousx, mousy, mousz, bstatus;
156
157 int InitBloodSpray(SHORT SpriteNum, BOOL dogib, short velocity);
158
159 SPRITEp FindNearSprite(SPRITEp sp, short stat);
160 BOOL PlayerOnLadder(PLAYERp pp);
161 VOID DoPlayerSlide(PLAYERp pp);
162 VOID DoPlayerBeginSwim(PLAYERp pp);
163 VOID DoPlayerSwim(PLAYERp pp);
164 VOID DoPlayerWade(PLAYERp pp);
165 VOID DoPlayerBeginWade(PLAYERp pp);
166 VOID DoPlayerBeginCrawl(PLAYERp pp);
167 VOID DoPlayerCrawl(PLAYERp pp);
168 VOID DoPlayerRun(PLAYERp pp);
169 VOID DoPlayerBeginRun(PLAYERp pp);
170 VOID DoPlayerFall(PLAYERp pp);
171 VOID DoPlayerBeginFall(PLAYERp pp);
172 VOID DoPlayerJump(PLAYERp pp);
173 VOID DoPlayerBeginJump(PLAYERp pp);
174 VOID DoPlayerForceJump(PLAYERp pp);
175 VOID DoPlayerBeginFly(PLAYERp pp);
176 VOID DoPlayerFly(PLAYERp pp);
177 VOID DoPlayerBeginClimb(PLAYERp pp);
178 VOID DoPlayerClimb(PLAYERp pp);
179 VOID DoPlayerBeginDie(PLAYERp pp);
180 VOID DoPlayerDie(PLAYERp pp);
181 VOID DoPlayerBeginOperateBoat(PLAYERp pp);
182 VOID DoPlayerBeginOperateTank(PLAYERp pp);
183 VOID DoPlayerBeginOperate(PLAYERp pp);
184 VOID DoPlayerOperateBoat(PLAYERp pp);
185 VOID DoPlayerOperateTank(PLAYERp pp);
186 VOID DoPlayerOperateTurret(PLAYERp pp);
187 VOID DoPlayerBeginDive(PLAYERp pp);
188 VOID DoPlayerDive(PLAYERp pp);
189 VOID DoPlayerTeleportPause(PLAYERp pp);
190 BOOL PlayerFlyKey(PLAYERp pp);
191 VOID OperateSectorObject(SECTOR_OBJECTp sop, short newang, int newx, int newy);
192 VOID CheckFootPrints(PLAYERp pp);
193 BOOL DoPlayerTestCrawl(PLAYERp pp);
194 VOID DoPlayerDeathFlip(PLAYERp pp);
195 VOID DoPlayerDeathCrumble(PLAYERp pp);
196 VOID DoPlayerDeathExplode(PLAYERp pp);
197 VOID DoPlayerDeathFall(PLAYERp pp);
198
199 void PlayerCheckValidMove(PLAYERp pp);
200 void PlayerWarpUpdatePos(PLAYERp pp);
201 void DoPlayerBeginDiveNoWarp(PLAYERp pp);
202 int PlayerCanDiveNoWarp(PLAYERp pp);
203 void DoPlayerCurrent(PLAYERp pp);
204 int GetOverlapSector2(int x, int y, short *over, short *under);
205 void PlayerToRemote(PLAYERp pp);
206 void PlayerRemoteInit(PLAYERp pp);
207 void PlayerSpawnPosition(PLAYERp pp);
208
209 extern short target_ang;
210
211 //////////////////////
212 //
213 // PLAYER SPECIFIC
214 //
215 //////////////////////
216
217 #if 1
218 #define PLAYER_NINJA_RATE 14
219
220 int DoFootPrints(short SpriteNum);
221
222 STATE s_PlayerNinjaRun[5][6] =
223 {
224
225 {
226 {PLAYER_NINJA_RUN_R0 + 0, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[0][1]},
227 {PLAYER_NINJA_RUN_R0 + 1, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[0][2]},
228 {PLAYER_NINJA_RUN_R0 + 1, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaRun[0][3]},
229 {PLAYER_NINJA_RUN_R0 + 2, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[0][4]},
230 {PLAYER_NINJA_RUN_R0 + 3, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[0][5]},
231 {PLAYER_NINJA_RUN_R0 + 3, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaRun[0][0]},
232 },
233 {
234 {PLAYER_NINJA_RUN_R1 + 0, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[1][1]},
235 {PLAYER_NINJA_RUN_R1 + 1, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[1][2]},
236 {PLAYER_NINJA_RUN_R1 + 1, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaRun[1][3]},
237 {PLAYER_NINJA_RUN_R1 + 2, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[1][4]},
238 {PLAYER_NINJA_RUN_R1 + 3, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[1][5]},
239 {PLAYER_NINJA_RUN_R1 + 3, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaRun[1][0]},
240 },
241 {
242 {PLAYER_NINJA_RUN_R2 + 0, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[2][1]},
243 {PLAYER_NINJA_RUN_R2 + 1, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[2][2]},
244 {PLAYER_NINJA_RUN_R2 + 1, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaRun[2][3]},
245 {PLAYER_NINJA_RUN_R2 + 2, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[2][4]},
246 {PLAYER_NINJA_RUN_R2 + 3, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[2][5]},
247 {PLAYER_NINJA_RUN_R2 + 3, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaRun[2][0]},
248 },
249 {
250 {PLAYER_NINJA_RUN_R3 + 0, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[3][1]},
251 {PLAYER_NINJA_RUN_R3 + 1, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[3][2]},
252 {PLAYER_NINJA_RUN_R3 + 1, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaRun[3][3]},
253 {PLAYER_NINJA_RUN_R3 + 2, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[3][4]},
254 {PLAYER_NINJA_RUN_R3 + 3, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[3][5]},
255 {PLAYER_NINJA_RUN_R3 + 3, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaRun[3][0]},
256 },
257 {
258 {PLAYER_NINJA_RUN_R4 + 0, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[4][1]},
259 {PLAYER_NINJA_RUN_R4 + 1, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[4][2]},
260 {PLAYER_NINJA_RUN_R4 + 1, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaRun[4][3]},
261 {PLAYER_NINJA_RUN_R4 + 2, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[4][4]},
262 {PLAYER_NINJA_RUN_R4 + 3, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[4][5]},
263 {PLAYER_NINJA_RUN_R4 + 3, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaRun[4][0]},
264 },
265
266 };
267
268 STATEp sg_PlayerNinjaRun[] =
269 {
270 s_PlayerNinjaRun[0],
271 s_PlayerNinjaRun[1],
272 s_PlayerNinjaRun[2],
273 s_PlayerNinjaRun[3],
274 s_PlayerNinjaRun[4]
275 };
276 #else
277 #define PLAYER_NINJA_RATE 10
278
279 STATE s_PlayerNinjaRun[5][8] =
280 {
281
282 {
283 {PLAYER_NINJA_RUN_R0 + 0, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[0][1]},
284 {PLAYER_NINJA_RUN_R0 + 0, PLAYER_NINJA_RATE | SF_PLAYER_FUNC,DoFootPrints, &s_PlayerNinjaRun[0][2]},
285 {PLAYER_NINJA_RUN_R0 + 1, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[0][3]},
286 {PLAYER_NINJA_RUN_R0 + 2, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[0][4]},
287 {PLAYER_NINJA_RUN_R0 + 3, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[0][5]},
288 {PLAYER_NINJA_RUN_R0 + 4, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[0][6]},
289 {PLAYER_NINJA_RUN_R0 + 5, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[0][7]},
290 {PLAYER_NINJA_RUN_R0 + 5, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaRun[0][0]},
291 },
292 {
293 {PLAYER_NINJA_RUN_R1 + 0, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[1][1]},
294 {PLAYER_NINJA_RUN_R1 + 0, PLAYER_NINJA_RATE | SF_PLAYER_FUNC,DoFootPrints, &s_PlayerNinjaRun[1][2]},
295 {PLAYER_NINJA_RUN_R1 + 1, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[1][3]},
296 {PLAYER_NINJA_RUN_R1 + 2, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[1][4]},
297 {PLAYER_NINJA_RUN_R1 + 3, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[1][5]},
298 {PLAYER_NINJA_RUN_R1 + 4, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[1][6]},
299 {PLAYER_NINJA_RUN_R1 + 5, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[1][7]},
300 {PLAYER_NINJA_RUN_R1 + 5, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaRun[1][0]},
301 },
302 {
303 {PLAYER_NINJA_RUN_R2 + 0, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[2][1]},
304 {PLAYER_NINJA_RUN_R2 + 0, PLAYER_NINJA_RATE | SF_PLAYER_FUNC,DoFootPrints, &s_PlayerNinjaRun[2][2]},
305 {PLAYER_NINJA_RUN_R2 + 1, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[2][3]},
306 {PLAYER_NINJA_RUN_R2 + 2, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[2][4]},
307 {PLAYER_NINJA_RUN_R2 + 3, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[2][5]},
308 {PLAYER_NINJA_RUN_R2 + 4, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[2][6]},
309 {PLAYER_NINJA_RUN_R2 + 5, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[2][7]},
310 {PLAYER_NINJA_RUN_R2 + 5, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaRun[2][0]},
311 },
312 {
313 {PLAYER_NINJA_RUN_R3 + 0, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[3][1]},
314 {PLAYER_NINJA_RUN_R3 + 0, PLAYER_NINJA_RATE | SF_PLAYER_FUNC,DoFootPrints, &s_PlayerNinjaRun[3][2]},
315 {PLAYER_NINJA_RUN_R3 + 1, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[3][3]},
316 {PLAYER_NINJA_RUN_R3 + 2, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[3][4]},
317 {PLAYER_NINJA_RUN_R3 + 3, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[3][5]},
318 {PLAYER_NINJA_RUN_R3 + 4, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[3][6]},
319 {PLAYER_NINJA_RUN_R3 + 5, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[3][7]},
320 {PLAYER_NINJA_RUN_R3 + 5, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaRun[3][0]},
321 },
322 {
323 {PLAYER_NINJA_RUN_R4 + 0, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[4][1]},
324 {PLAYER_NINJA_RUN_R4 + 0, PLAYER_NINJA_RATE | SF_PLAYER_FUNC,DoFootPrints, &s_PlayerNinjaRun[4][2]},
325 {PLAYER_NINJA_RUN_R4 + 1, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[4][3]},
326 {PLAYER_NINJA_RUN_R4 + 2, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[4][4]},
327 {PLAYER_NINJA_RUN_R4 + 3, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[4][5]},
328 {PLAYER_NINJA_RUN_R4 + 4, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[4][6]},
329 {PLAYER_NINJA_RUN_R4 + 5, PLAYER_NINJA_RATE | SF_TIC_ADJUST, NullAnimator, &s_PlayerNinjaRun[4][7]},
330 {PLAYER_NINJA_RUN_R4 + 5, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaRun[4][0]},
331 }
332 };
333
334 STATEp sg_PlayerNinjaRun[] =
335 {
336 s_PlayerNinjaRun[0],
337 s_PlayerNinjaRun[1],
338 s_PlayerNinjaRun[2],
339 s_PlayerNinjaRun[3],
340 s_PlayerNinjaRun[4]
341 };
342 #endif
343
344 //////////////////////
345 //
346 // PLAYER_NINJA STAND
347 //
348 //////////////////////
349
350 #define PLAYER_NINJA_STAND_RATE 10
351
352 STATE s_PlayerNinjaStand[5][1] =
353 {
354 {
355 {PLAYER_NINJA_STAND_R0 + 0, PLAYER_NINJA_STAND_RATE, NullAnimator, &s_PlayerNinjaStand[0][0]},
356 },
357 {
358 {PLAYER_NINJA_STAND_R1 + 0, PLAYER_NINJA_STAND_RATE, NullAnimator, &s_PlayerNinjaStand[1][0]},
359 },
360 {
361 {PLAYER_NINJA_STAND_R2 + 0, PLAYER_NINJA_STAND_RATE, NullAnimator, &s_PlayerNinjaStand[2][0]},
362 },
363 {
364 {PLAYER_NINJA_STAND_R3 + 0, PLAYER_NINJA_STAND_RATE, NullAnimator, &s_PlayerNinjaStand[3][0]},
365 },
366 {
367 {PLAYER_NINJA_STAND_R4 + 0, PLAYER_NINJA_STAND_RATE, NullAnimator, &s_PlayerNinjaStand[4][0]},
368 },
369 };
370 STATEp sg_PlayerNinjaStand[] =
371 {
372 s_PlayerNinjaStand[0],
373 s_PlayerNinjaStand[1],
374 s_PlayerNinjaStand[2],
375 s_PlayerNinjaStand[3],
376 s_PlayerNinjaStand[4]
377 };
378
379
380 #define NINJA_STAR_RATE 12
381
382 extern STATEp sg_NinjaRun[];
383 int DoPlayerSpriteReset(short SpriteNum);
384
385 #if 0
386 STATE s_PlayerNinjaThrow[5][4] =
387 {
388 {
389 {PLAYER_SHOOT_R0 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[0][1]},
390 {PLAYER_SHOOT_R0 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[0][2]},
391 {PLAYER_SHOOT_R0 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[0][3]},
392 {PLAYER_SHOOT_R0 + 0, NINJA_STAR_RATE | SF_PLAYER_FUNC, DoPlayerSpriteReset, &s_PlayerNinjaThrow[0][3]},
393 },
394 {
395 {PLAYER_SHOOT_R1 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[1][1]},
396 {PLAYER_SHOOT_R1 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[1][2]},
397 {PLAYER_SHOOT_R1 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[1][3]},
398 {PLAYER_SHOOT_R1 + 0, NINJA_STAR_RATE | SF_PLAYER_FUNC, DoPlayerSpriteReset, &s_PlayerNinjaThrow[0][3]},
399 },
400 {
401 {PLAYER_SHOOT_R2 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[2][1]},
402 {PLAYER_SHOOT_R2 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[2][2]},
403 {PLAYER_SHOOT_R2 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[2][3]},
404 {PLAYER_SHOOT_R2 + 0, NINJA_STAR_RATE | SF_PLAYER_FUNC, DoPlayerSpriteReset, &s_PlayerNinjaThrow[0][3]},
405 },
406 {
407 {PLAYER_SHOOT_R3 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[3][1]},
408 {PLAYER_SHOOT_R3 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[3][2]},
409 {PLAYER_SHOOT_R3 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[3][3]},
410 {PLAYER_SHOOT_R3 + 0, NINJA_STAR_RATE | SF_PLAYER_FUNC, DoPlayerSpriteReset, &s_PlayerNinjaThrow[0][3]},
411 },
412 {
413 {PLAYER_SHOOT_R4 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[4][1]},
414 {PLAYER_SHOOT_R4 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[4][2]},
415 {PLAYER_SHOOT_R4 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[4][3]},
416 {PLAYER_SHOOT_R4 + 0, NINJA_STAR_RATE | SF_PLAYER_FUNC, DoPlayerSpriteReset, &s_PlayerNinjaThrow[0][3]},
417 },
418 };
419 #endif
420
421 #if 1
422 STATE s_PlayerNinjaThrow[5][4] =
423 {
424 {
425 {PLAYER_NINJA_SHOOT_R0 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[0][1]},
426 {PLAYER_NINJA_SHOOT_R0 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[0][2]},
427 {PLAYER_NINJA_SHOOT_R0 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[0][3]},
428 {PLAYER_NINJA_SHOOT_R0 + 0, NINJA_STAR_RATE | SF_PLAYER_FUNC, DoPlayerSpriteReset, &s_PlayerNinjaThrow[0][3]},
429 },
430 {
431 {PLAYER_NINJA_SHOOT_R1 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[1][1]},
432 {PLAYER_NINJA_SHOOT_R1 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[1][2]},
433 {PLAYER_NINJA_SHOOT_R1 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[1][3]},
434 {PLAYER_NINJA_SHOOT_R1 + 0, NINJA_STAR_RATE | SF_PLAYER_FUNC, DoPlayerSpriteReset, &s_PlayerNinjaThrow[0][3]},
435 },
436 {
437 {PLAYER_NINJA_SHOOT_R2 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[2][1]},
438 {PLAYER_NINJA_SHOOT_R2 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[2][2]},
439 {PLAYER_NINJA_SHOOT_R2 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[2][3]},
440 {PLAYER_NINJA_SHOOT_R2 + 0, NINJA_STAR_RATE | SF_PLAYER_FUNC, DoPlayerSpriteReset, &s_PlayerNinjaThrow[0][3]},
441 },
442 {
443 {PLAYER_NINJA_SHOOT_R3 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[3][1]},
444 {PLAYER_NINJA_SHOOT_R3 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[3][2]},
445 {PLAYER_NINJA_SHOOT_R3 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[3][3]},
446 {PLAYER_NINJA_SHOOT_R3 + 0, NINJA_STAR_RATE | SF_PLAYER_FUNC, DoPlayerSpriteReset, &s_PlayerNinjaThrow[0][3]},
447 },
448 {
449 {PLAYER_NINJA_SHOOT_R4 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[4][1]},
450 {PLAYER_NINJA_SHOOT_R4 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[4][2]},
451 {PLAYER_NINJA_SHOOT_R4 + 0, NINJA_STAR_RATE, NullAnimator, &s_PlayerNinjaThrow[4][3]},
452 {PLAYER_NINJA_SHOOT_R4 + 0, NINJA_STAR_RATE | SF_PLAYER_FUNC, DoPlayerSpriteReset, &s_PlayerNinjaThrow[0][3]},
453 },
454 };
455 #endif
456
457 STATEp sg_PlayerNinjaThrow[] =
458 {
459 s_PlayerNinjaThrow[0],
460 s_PlayerNinjaThrow[1],
461 s_PlayerNinjaThrow[2],
462 s_PlayerNinjaThrow[3],
463 s_PlayerNinjaThrow[4]
464 };
465
466 //////////////////////
467 //
468 // PLAYER_NINJA JUMP
469 //
470 //////////////////////
471
472 #define PLAYER_NINJA_JUMP_RATE 24
473
474 STATE s_PlayerNinjaJump[5][4] =
475 {
476 {
477 {PLAYER_NINJA_JUMP_R0 + 0, PLAYER_NINJA_JUMP_RATE, NullAnimator, &s_PlayerNinjaJump[0][1]},
478 {PLAYER_NINJA_JUMP_R0 + 1, PLAYER_NINJA_JUMP_RATE, NullAnimator, &s_PlayerNinjaJump[0][2]},
479 {PLAYER_NINJA_JUMP_R0 + 2, PLAYER_NINJA_JUMP_RATE, NullAnimator, &s_PlayerNinjaJump[0][3]},
480 {PLAYER_NINJA_JUMP_R0 + 3, PLAYER_NINJA_JUMP_RATE, NullAnimator, &s_PlayerNinjaJump[0][3]},
481 },
482 {
483 {PLAYER_NINJA_JUMP_R1 + 0, PLAYER_NINJA_JUMP_RATE, NullAnimator, &s_PlayerNinjaJump[1][1]},
484 {PLAYER_NINJA_JUMP_R1 + 1, PLAYER_NINJA_JUMP_RATE, NullAnimator, &s_PlayerNinjaJump[1][2]},
485 {PLAYER_NINJA_JUMP_R1 + 2, PLAYER_NINJA_JUMP_RATE, NullAnimator, &s_PlayerNinjaJump[1][3]},
486 {PLAYER_NINJA_JUMP_R1 + 3, PLAYER_NINJA_JUMP_RATE, NullAnimator, &s_PlayerNinjaJump[1][3]},
487 },
488 {
489 {PLAYER_NINJA_JUMP_R2 + 0, PLAYER_NINJA_JUMP_RATE, NullAnimator, &s_PlayerNinjaJump[2][1]},
490 {PLAYER_NINJA_JUMP_R2 + 1, PLAYER_NINJA_JUMP_RATE, NullAnimator, &s_PlayerNinjaJump[2][2]},
491 {PLAYER_NINJA_JUMP_R2 + 2, PLAYER_NINJA_JUMP_RATE, NullAnimator, &s_PlayerNinjaJump[2][3]},
492 {PLAYER_NINJA_JUMP_R2 + 3, PLAYER_NINJA_JUMP_RATE, NullAnimator, &s_PlayerNinjaJump[2][3]},
493 },
494 {
495 {PLAYER_NINJA_JUMP_R3 + 0, PLAYER_NINJA_JUMP_RATE, NullAnimator, &s_PlayerNinjaJump[3][1]},
496 {PLAYER_NINJA_JUMP_R3 + 1, PLAYER_NINJA_JUMP_RATE, NullAnimator, &s_PlayerNinjaJump[3][2]},
497 {PLAYER_NINJA_JUMP_R3 + 2, PLAYER_NINJA_JUMP_RATE, NullAnimator, &s_PlayerNinjaJump[3][3]},
498 {PLAYER_NINJA_JUMP_R3 + 3, PLAYER_NINJA_JUMP_RATE, NullAnimator, &s_PlayerNinjaJump[3][3]},
499 },
500 {
501 {PLAYER_NINJA_JUMP_R4 + 0, PLAYER_NINJA_JUMP_RATE, NullAnimator, &s_PlayerNinjaJump[4][1]},
502 {PLAYER_NINJA_JUMP_R4 + 1, PLAYER_NINJA_JUMP_RATE, NullAnimator, &s_PlayerNinjaJump[4][2]},
503 {PLAYER_NINJA_JUMP_R4 + 2, PLAYER_NINJA_JUMP_RATE, NullAnimator, &s_PlayerNinjaJump[4][3]},
504 {PLAYER_NINJA_JUMP_R4 + 3, PLAYER_NINJA_JUMP_RATE, NullAnimator, &s_PlayerNinjaJump[4][3]},
505 },
506 };
507
508
509 STATEp sg_PlayerNinjaJump[] =
510 {
511 s_PlayerNinjaJump[0],
512 s_PlayerNinjaJump[1],
513 s_PlayerNinjaJump[2],
514 s_PlayerNinjaJump[3],
515 s_PlayerNinjaJump[4]
516 };
517
518
519 //////////////////////
520 //
521 // PLAYER_NINJA FALL
522 //
523 //////////////////////
524
525 #define PLAYER_NINJA_FALL_RATE 16
526
527 STATE s_PlayerNinjaFall[5][2] =
528 {
529 {
530 {PLAYER_NINJA_JUMP_R0 + 1, PLAYER_NINJA_FALL_RATE, NullAnimator, &s_PlayerNinjaFall[0][1]},
531 {PLAYER_NINJA_JUMP_R0 + 2, PLAYER_NINJA_FALL_RATE, NullAnimator, &s_PlayerNinjaFall[0][1]},
532 },
533 {
534 {PLAYER_NINJA_JUMP_R1 + 1, PLAYER_NINJA_FALL_RATE, NullAnimator, &s_PlayerNinjaFall[1][1]},
535 {PLAYER_NINJA_JUMP_R1 + 2, PLAYER_NINJA_FALL_RATE, NullAnimator, &s_PlayerNinjaFall[1][1]},
536 },
537 {
538 {PLAYER_NINJA_JUMP_R2 + 1, PLAYER_NINJA_FALL_RATE, NullAnimator, &s_PlayerNinjaFall[2][1]},
539 {PLAYER_NINJA_JUMP_R2 + 2, PLAYER_NINJA_FALL_RATE, NullAnimator, &s_PlayerNinjaFall[2][1]},
540 },
541 {
542 {PLAYER_NINJA_JUMP_R3 + 1, PLAYER_NINJA_FALL_RATE, NullAnimator, &s_PlayerNinjaFall[3][1]},
543 {PLAYER_NINJA_JUMP_R3 + 2, PLAYER_NINJA_FALL_RATE, NullAnimator, &s_PlayerNinjaFall[3][1]},
544 },
545 {
546 {PLAYER_NINJA_JUMP_R4 + 1, PLAYER_NINJA_FALL_RATE, NullAnimator, &s_PlayerNinjaFall[4][1]},
547 {PLAYER_NINJA_JUMP_R4 + 2, PLAYER_NINJA_FALL_RATE, NullAnimator, &s_PlayerNinjaFall[4][1]},
548 },
549 };
550
551
552 STATEp sg_PlayerNinjaFall[] =
553 {
554 s_PlayerNinjaFall[0],
555 s_PlayerNinjaFall[1],
556 s_PlayerNinjaFall[2],
557 s_PlayerNinjaFall[3],
558 s_PlayerNinjaFall[4]
559 };
560
561 //////////////////////
562 //
563 // PLAYER_NINJA CLIMB
564 //
565 //////////////////////
566
567
568 #define PLAYER_NINJA_CLIMB_RATE 20
569 STATE s_PlayerNinjaClimb[5][4] =
570 {
571 {
572 {PLAYER_NINJA_CLIMB_R0 + 0, PLAYER_NINJA_CLIMB_RATE, NullAnimator, &s_PlayerNinjaClimb[0][1]},
573 {PLAYER_NINJA_CLIMB_R0 + 1, PLAYER_NINJA_CLIMB_RATE, NullAnimator, &s_PlayerNinjaClimb[0][2]},
574 {PLAYER_NINJA_CLIMB_R0 + 2, PLAYER_NINJA_CLIMB_RATE, NullAnimator, &s_PlayerNinjaClimb[0][3]},
575 {PLAYER_NINJA_CLIMB_R0 + 3, PLAYER_NINJA_CLIMB_RATE, NullAnimator, &s_PlayerNinjaClimb[0][0]},
576 },
577 {
578 {PLAYER_NINJA_CLIMB_R1 + 0, PLAYER_NINJA_CLIMB_RATE, NullAnimator, &s_PlayerNinjaClimb[1][1]},
579 {PLAYER_NINJA_CLIMB_R1 + 1, PLAYER_NINJA_CLIMB_RATE, NullAnimator, &s_PlayerNinjaClimb[1][2]},
580 {PLAYER_NINJA_CLIMB_R1 + 2, PLAYER_NINJA_CLIMB_RATE, NullAnimator, &s_PlayerNinjaClimb[1][3]},
581 {PLAYER_NINJA_CLIMB_R1 + 3, PLAYER_NINJA_CLIMB_RATE, NullAnimator, &s_PlayerNinjaClimb[1][0]},
582 },
583 {
584 {PLAYER_NINJA_CLIMB_R2 + 0, PLAYER_NINJA_CLIMB_RATE, NullAnimator, &s_PlayerNinjaClimb[2][1]},
585 {PLAYER_NINJA_CLIMB_R2 + 1, PLAYER_NINJA_CLIMB_RATE, NullAnimator, &s_PlayerNinjaClimb[2][2]},
586 {PLAYER_NINJA_CLIMB_R2 + 2, PLAYER_NINJA_CLIMB_RATE, NullAnimator, &s_PlayerNinjaClimb[2][3]},
587 {PLAYER_NINJA_CLIMB_R2 + 3, PLAYER_NINJA_CLIMB_RATE, NullAnimator, &s_PlayerNinjaClimb[2][0]},
588 },
589 {
590 {PLAYER_NINJA_CLIMB_R3 + 0, PLAYER_NINJA_CLIMB_RATE, NullAnimator, &s_PlayerNinjaClimb[3][1]},
591 {PLAYER_NINJA_CLIMB_R3 + 1, PLAYER_NINJA_CLIMB_RATE, NullAnimator, &s_PlayerNinjaClimb[3][2]},
592 {PLAYER_NINJA_CLIMB_R3 + 2, PLAYER_NINJA_CLIMB_RATE, NullAnimator, &s_PlayerNinjaClimb[3][3]},
593 {PLAYER_NINJA_CLIMB_R3 + 3, PLAYER_NINJA_CLIMB_RATE, NullAnimator, &s_PlayerNinjaClimb[3][0]},
594 },
595 {
596 {PLAYER_NINJA_CLIMB_R4 + 0, PLAYER_NINJA_CLIMB_RATE, NullAnimator, &s_PlayerNinjaClimb[4][1]},
597 {PLAYER_NINJA_CLIMB_R4 + 1, PLAYER_NINJA_CLIMB_RATE, NullAnimator, &s_PlayerNinjaClimb[4][2]},
598 {PLAYER_NINJA_CLIMB_R4 + 2, PLAYER_NINJA_CLIMB_RATE, NullAnimator, &s_PlayerNinjaClimb[4][3]},
599 {PLAYER_NINJA_CLIMB_R4 + 3, PLAYER_NINJA_CLIMB_RATE, NullAnimator, &s_PlayerNinjaClimb[4][0]},
600 },
601 };
602
603 STATEp sg_PlayerNinjaClimb[] =
604 {
605 s_PlayerNinjaClimb[0],
606 s_PlayerNinjaClimb[1],
607 s_PlayerNinjaClimb[2],
608 s_PlayerNinjaClimb[3],
609 s_PlayerNinjaClimb[4]
610 };
611
612 //////////////////////
613 //
614 // PLAYER_NINJA CRAWL
615 //
616 //////////////////////
617
618
619 #define PLAYER_NINJA_CRAWL_RATE 14
620 STATE s_PlayerNinjaCrawl[5][6] =
621 {
622 {
623 {PLAYER_NINJA_CRAWL_R0 + 0, PLAYER_NINJA_CRAWL_RATE, NullAnimator, &s_PlayerNinjaCrawl[0][1]},
624 {PLAYER_NINJA_CRAWL_R0 + 1, PLAYER_NINJA_CRAWL_RATE, NullAnimator, &s_PlayerNinjaCrawl[0][2]},
625 {PLAYER_NINJA_CRAWL_R0 + 1, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaCrawl[0][3]},
626 {PLAYER_NINJA_CRAWL_R0 + 2, PLAYER_NINJA_CRAWL_RATE, NullAnimator, &s_PlayerNinjaCrawl[0][4]},
627 {PLAYER_NINJA_CRAWL_R0 + 1, PLAYER_NINJA_CRAWL_RATE, NullAnimator, &s_PlayerNinjaCrawl[0][5]},
628 {PLAYER_NINJA_CRAWL_R0 + 1, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaCrawl[0][0]},
629 },
630 {
631 {PLAYER_NINJA_CRAWL_R1 + 0, PLAYER_NINJA_CRAWL_RATE, NullAnimator, &s_PlayerNinjaCrawl[1][1]},
632 {PLAYER_NINJA_CRAWL_R1 + 1, PLAYER_NINJA_CRAWL_RATE, NullAnimator, &s_PlayerNinjaCrawl[1][2]},
633 {PLAYER_NINJA_CRAWL_R1 + 1, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaCrawl[1][3]},
634 {PLAYER_NINJA_CRAWL_R1 + 2, PLAYER_NINJA_CRAWL_RATE, NullAnimator, &s_PlayerNinjaCrawl[1][4]},
635 {PLAYER_NINJA_CRAWL_R1 + 1, PLAYER_NINJA_CRAWL_RATE, NullAnimator, &s_PlayerNinjaCrawl[1][5]},
636 {PLAYER_NINJA_CRAWL_R1 + 1, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaCrawl[1][0]},
637 },
638 {
639 {PLAYER_NINJA_CRAWL_R2 + 0, PLAYER_NINJA_CRAWL_RATE, NullAnimator, &s_PlayerNinjaCrawl[2][1]},
640 {PLAYER_NINJA_CRAWL_R2 + 1, PLAYER_NINJA_CRAWL_RATE, NullAnimator, &s_PlayerNinjaCrawl[2][2]},
641 {PLAYER_NINJA_CRAWL_R2 + 1, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaCrawl[2][3]},
642 {PLAYER_NINJA_CRAWL_R2 + 2, PLAYER_NINJA_CRAWL_RATE, NullAnimator, &s_PlayerNinjaCrawl[2][4]},
643 {PLAYER_NINJA_CRAWL_R2 + 1, PLAYER_NINJA_CRAWL_RATE, NullAnimator, &s_PlayerNinjaCrawl[2][5]},
644 {PLAYER_NINJA_CRAWL_R2 + 1, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaCrawl[2][0]},
645 },
646 {
647 {PLAYER_NINJA_CRAWL_R3 + 0, PLAYER_NINJA_CRAWL_RATE, NullAnimator, &s_PlayerNinjaCrawl[3][1]},
648 {PLAYER_NINJA_CRAWL_R3 + 1, PLAYER_NINJA_CRAWL_RATE, NullAnimator, &s_PlayerNinjaCrawl[3][2]},
649 {PLAYER_NINJA_CRAWL_R3 + 1, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaCrawl[3][3]},
650 {PLAYER_NINJA_CRAWL_R3 + 2, PLAYER_NINJA_CRAWL_RATE, NullAnimator, &s_PlayerNinjaCrawl[3][4]},
651 {PLAYER_NINJA_CRAWL_R3 + 1, PLAYER_NINJA_CRAWL_RATE, NullAnimator, &s_PlayerNinjaCrawl[3][5]},
652 {PLAYER_NINJA_CRAWL_R3 + 1, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaCrawl[3][0]},
653 },
654 {
655 {PLAYER_NINJA_CRAWL_R4 + 0, PLAYER_NINJA_CRAWL_RATE, NullAnimator, &s_PlayerNinjaCrawl[4][1]},
656 {PLAYER_NINJA_CRAWL_R4 + 1, PLAYER_NINJA_CRAWL_RATE, NullAnimator, &s_PlayerNinjaCrawl[4][2]},
657 {PLAYER_NINJA_CRAWL_R4 + 1, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaCrawl[4][3]},
658 {PLAYER_NINJA_CRAWL_R4 + 2, PLAYER_NINJA_CRAWL_RATE, NullAnimator, &s_PlayerNinjaCrawl[4][4]},
659 {PLAYER_NINJA_CRAWL_R4 + 1, PLAYER_NINJA_CRAWL_RATE, NullAnimator, &s_PlayerNinjaCrawl[4][5]},
660 {PLAYER_NINJA_CRAWL_R4 + 1, 0 | SF_QUICK_CALL, DoFootPrints, &s_PlayerNinjaCrawl[4][0]},
661 },
662 };
663
664
665 STATEp sg_PlayerNinjaCrawl[] =
666 {
667 s_PlayerNinjaCrawl[0],
668 s_PlayerNinjaCrawl[1],
669 s_PlayerNinjaCrawl[2],
670 s_PlayerNinjaCrawl[3],
671 s_PlayerNinjaCrawl[4]
672 };
673
674 //////////////////////
675 //
676 // PLAYER NINJA SWIM
677 //
678 //////////////////////
679
680
681 #define PLAYER_NINJA_SWIM_RATE 22 // Was 18
682 STATE s_PlayerNinjaSwim[5][4] =
683 {
684 {
685 {PLAYER_NINJA_SWIM_R0 + 0, PLAYER_NINJA_SWIM_RATE, NullAnimator, &s_PlayerNinjaSwim[0][1]},
686 {PLAYER_NINJA_SWIM_R0 + 1, PLAYER_NINJA_SWIM_RATE, NullAnimator, &s_PlayerNinjaSwim[0][2]},
687 {PLAYER_NINJA_SWIM_R0 + 2, PLAYER_NINJA_SWIM_RATE, NullAnimator, &s_PlayerNinjaSwim[0][3]},
688 {PLAYER_NINJA_SWIM_R0 + 3, PLAYER_NINJA_SWIM_RATE, NullAnimator, &s_PlayerNinjaSwim[0][0]},
689 },
690 {
691 {PLAYER_NINJA_SWIM_R1 + 0, PLAYER_NINJA_SWIM_RATE, NullAnimator, &s_PlayerNinjaSwim[1][1]},
692 {PLAYER_NINJA_SWIM_R1 + 1, PLAYER_NINJA_SWIM_RATE, NullAnimator, &s_PlayerNinjaSwim[1][2]},
693 {PLAYER_NINJA_SWIM_R1 + 2, PLAYER_NINJA_SWIM_RATE, NullAnimator, &s_PlayerNinjaSwim[1][3]},
694 {PLAYER_NINJA_SWIM_R1 + 3, PLAYER_NINJA_SWIM_RATE, NullAnimator, &s_PlayerNinjaSwim[1][0]},
695 },
696 {
697 {PLAYER_NINJA_SWIM_R2 + 0, PLAYER_NINJA_SWIM_RATE, NullAnimator, &s_PlayerNinjaSwim[2][1]},
698 {PLAYER_NINJA_SWIM_R2 + 1, PLAYER_NINJA_SWIM_RATE, NullAnimator, &s_PlayerNinjaSwim[2][2]},
699 {PLAYER_NINJA_SWIM_R2 + 2, PLAYER_NINJA_SWIM_RATE, NullAnimator, &s_PlayerNinjaSwim[2][3]},
700 {PLAYER_NINJA_SWIM_R2 + 3, PLAYER_NINJA_SWIM_RATE, NullAnimator, &s_PlayerNinjaSwim[2][0]},
701 },
702 {
703 {PLAYER_NINJA_SWIM_R3 + 0, PLAYER_NINJA_SWIM_RATE, NullAnimator, &s_PlayerNinjaSwim[3][1]},
704 {PLAYER_NINJA_SWIM_R3 + 1, PLAYER_NINJA_SWIM_RATE, NullAnimator, &s_PlayerNinjaSwim[3][2]},
705 {PLAYER_NINJA_SWIM_R3 + 2, PLAYER_NINJA_SWIM_RATE, NullAnimator, &s_PlayerNinjaSwim[3][3]},
706 {PLAYER_NINJA_SWIM_R3 + 3, PLAYER_NINJA_SWIM_RATE, NullAnimator, &s_PlayerNinjaSwim[3][0]},
707 },
708 {
709 {PLAYER_NINJA_SWIM_R4 + 0, PLAYER_NINJA_SWIM_RATE, NullAnimator, &s_PlayerNinjaSwim[4][1]},
710 {PLAYER_NINJA_SWIM_R4 + 1, PLAYER_NINJA_SWIM_RATE, NullAnimator, &s_PlayerNinjaSwim[4][2]},
711 {PLAYER_NINJA_SWIM_R4 + 2, PLAYER_NINJA_SWIM_RATE, NullAnimator, &s_PlayerNinjaSwim[4][3]},
712 {PLAYER_NINJA_SWIM_R4 + 3, PLAYER_NINJA_SWIM_RATE, NullAnimator, &s_PlayerNinjaSwim[4][0]},
713 },
714 };
715
716
717 STATEp sg_PlayerNinjaSwim[] =
718 {
719 s_PlayerNinjaSwim[0],
720 s_PlayerNinjaSwim[1],
721 s_PlayerNinjaSwim[2],
722 s_PlayerNinjaSwim[3],
723 s_PlayerNinjaSwim[4]
724 };
725
726
727 #define NINJA_HeadHurl_RATE 16
728 #define NINJA_Head_RATE 16
729 #define NINJA_HeadFly 1134
730 #define NINJA_HeadFly_RATE 16
731
732 STATE s_PlayerHeadFly[5][8] =
733 {
734 {
735 {NINJA_HeadFly + 0, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[0][1]},
736 {NINJA_HeadFly + 1, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[0][2]},
737 {NINJA_HeadFly + 2, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[0][3]},
738 {NINJA_HeadFly + 3, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[0][4]},
739 {NINJA_HeadFly + 4, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[0][5]},
740 {NINJA_HeadFly + 5, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[0][6]},
741 {NINJA_HeadFly + 6, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[0][7]},
742 {NINJA_HeadFly + 7, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[0][0]}
743 },
744 {
745 {NINJA_HeadFly + 0, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[1][1]},
746 {NINJA_HeadFly + 1, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[1][2]},
747 {NINJA_HeadFly + 2, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[1][3]},
748 {NINJA_HeadFly + 3, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[1][4]},
749 {NINJA_HeadFly + 4, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[1][5]},
750 {NINJA_HeadFly + 5, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[1][6]},
751 {NINJA_HeadFly + 6, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[1][7]},
752 {NINJA_HeadFly + 7, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[1][0]}
753 },
754 {
755 {NINJA_HeadFly + 0, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[2][1]},
756 {NINJA_HeadFly + 1, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[2][2]},
757 {NINJA_HeadFly + 2, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[2][3]},
758 {NINJA_HeadFly + 3, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[2][4]},
759 {NINJA_HeadFly + 4, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[2][5]},
760 {NINJA_HeadFly + 5, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[2][6]},
761 {NINJA_HeadFly + 6, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[2][7]},
762 {NINJA_HeadFly + 7, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[2][0]}
763 },
764 {
765 {NINJA_HeadFly + 0, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[3][1]},
766 {NINJA_HeadFly + 1, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[3][2]},
767 {NINJA_HeadFly + 2, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[3][3]},
768 {NINJA_HeadFly + 3, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[3][4]},
769 {NINJA_HeadFly + 4, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[3][5]},
770 {NINJA_HeadFly + 5, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[3][6]},
771 {NINJA_HeadFly + 6, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[3][7]},
772 {NINJA_HeadFly + 7, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[3][0]}
773 },
774 {
775 {NINJA_HeadFly + 0, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[4][1]},
776 {NINJA_HeadFly + 1, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[4][2]},
777 {NINJA_HeadFly + 2, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[4][3]},
778 {NINJA_HeadFly + 3, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[4][4]},
779 {NINJA_HeadFly + 4, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[4][5]},
780 {NINJA_HeadFly + 5, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[4][6]},
781 {NINJA_HeadFly + 6, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[4][7]},
782 {NINJA_HeadFly + 7, NINJA_HeadFly_RATE, NullAnimator, &s_PlayerHeadFly[4][0]}
783 },
784 };
785
786 STATEp sg_PlayerHeadFly[] =
787 {
788 s_PlayerHeadFly[0],
789 s_PlayerHeadFly[1],
790 s_PlayerHeadFly[2],
791 s_PlayerHeadFly[3],
792 s_PlayerHeadFly[4]
793 };
794
795 //#define NINJA_Head_FRAMES 1
796 //#define NINJA_Head_R0 1142
797 //#define NINJA_Head_R1 NINJA_Head_R0 + (NINJA_Head_FRAMES * 1)
798 //#define NINJA_Head_R2 NINJA_Head_R0 + (NINJA_Head_FRAMES * 2)
799 //#define NINJA_Head_R3 NINJA_Head_R0 + (NINJA_Head_FRAMES * 3)
800 //#define NINJA_Head_R4 NINJA_Head_R0 + (NINJA_Head_FRAMES * 4)
801
802 STATE s_PlayerHead[5][1] =
803 {
804 {
805 {NINJA_Head_R0 + 0, NINJA_Head_RATE, NullAnimator, &s_PlayerHead[0][0]},
806 },
807 {
808 {NINJA_Head_R1 + 0, NINJA_Head_RATE, NullAnimator, &s_PlayerHead[1][0]},
809 },
810 {
811 {NINJA_Head_R2 + 0, NINJA_Head_RATE, NullAnimator, &s_PlayerHead[2][0]},
812 },
813 {
814 {NINJA_Head_R3 + 0, NINJA_Head_RATE, NullAnimator, &s_PlayerHead[3][0]},
815 },
816 {
817 {NINJA_Head_R4 + 0, NINJA_Head_RATE, NullAnimator, &s_PlayerHead[4][0]},
818 },
819 };
820
821 STATEp sg_PlayerHead[] =
822 {
823 s_PlayerHead[0],
824 s_PlayerHead[1],
825 s_PlayerHead[2],
826 s_PlayerHead[3],
827 s_PlayerHead[4]
828 };
829
830 #define NINJA_HeadHurl_FRAMES 1
831 #define NINJA_HeadHurl_R0 1147
832 #define NINJA_HeadHurl_R1 NINJA_HeadHurl_R0 + (NINJA_HeadHurl_FRAMES * 1)
833 #define NINJA_HeadHurl_R2 NINJA_HeadHurl_R0 + (NINJA_HeadHurl_FRAMES * 2)
834 #define NINJA_HeadHurl_R3 NINJA_HeadHurl_R0 + (NINJA_HeadHurl_FRAMES * 3)
835 #define NINJA_HeadHurl_R4 NINJA_HeadHurl_R0 + (NINJA_HeadHurl_FRAMES * 4)
836
837 STATE s_PlayerHeadHurl[5][1] =
838 {
839 {
840 {NINJA_HeadHurl_R0 + 0, NINJA_HeadHurl_RATE, NullAnimator, &s_PlayerHeadHurl[0][0]},
841 },
842 {
843 {NINJA_HeadHurl_R1 + 0, NINJA_HeadHurl_RATE, NullAnimator, &s_PlayerHeadHurl[1][0]},
844 },
845 {
846 {NINJA_HeadHurl_R2 + 0, NINJA_HeadHurl_RATE, NullAnimator, &s_PlayerHeadHurl[2][0]},
847 },
848 {
849 {NINJA_HeadHurl_R3 + 0, NINJA_HeadHurl_RATE, NullAnimator, &s_PlayerHeadHurl[3][0]},
850 },
851 {
852 {NINJA_HeadHurl_R4 + 0, NINJA_HeadHurl_RATE, NullAnimator, &s_PlayerHeadHurl[4][0]},
853 },
854 };
855
856 STATEp sg_PlayerHeadHurl[] =
857 {
858 s_PlayerHeadHurl[0],
859 s_PlayerHeadHurl[1],
860 s_PlayerHeadHurl[2],
861 s_PlayerHeadHurl[3],
862 s_PlayerHeadHurl[4]
863 };
864
865 #define NINJA_DIE_RATE 22
866
867 STATE s_PlayerDeath[5][10] =
868 {
869 {
870 {PLAYER_NINJA_DIE + 0, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[0][1]},
871 {PLAYER_NINJA_DIE + 1, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[0][2]},
872 {PLAYER_NINJA_DIE + 2, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[0][3]},
873 {PLAYER_NINJA_DIE + 3, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[0][4]},
874 {PLAYER_NINJA_DIE + 4, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[0][5]},
875 {PLAYER_NINJA_DIE + 5, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[0][6]},
876 {PLAYER_NINJA_DIE + 6, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[0][7]},
877 {PLAYER_NINJA_DIE + 7, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[0][8]},
878 {PLAYER_NINJA_DIE + 8, 0 | SF_QUICK_CALL , QueueFloorBlood, &s_PlayerDeath[0][9]},
879 {PLAYER_NINJA_DIE + 8, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[0][9]},
880 },
881 {
882 {PLAYER_NINJA_DIE + 0, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[1][1]},
883 {PLAYER_NINJA_DIE + 1, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[1][2]},
884 {PLAYER_NINJA_DIE + 2, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[1][3]},
885 {PLAYER_NINJA_DIE + 3, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[1][4]},
886 {PLAYER_NINJA_DIE + 4, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[1][5]},
887 {PLAYER_NINJA_DIE + 5, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[1][6]},
888 {PLAYER_NINJA_DIE + 6, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[1][7]},
889 {PLAYER_NINJA_DIE + 7, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[1][8]},
890 {PLAYER_NINJA_DIE + 8, 0 | SF_QUICK_CALL , QueueFloorBlood, &s_PlayerDeath[1][9]},
891 {PLAYER_NINJA_DIE + 8, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[1][9]},
892 },
893 {
894 {PLAYER_NINJA_DIE + 0, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[2][1]},
895 {PLAYER_NINJA_DIE + 1, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[2][2]},
896 {PLAYER_NINJA_DIE + 2, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[2][3]},
897 {PLAYER_NINJA_DIE + 3, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[2][4]},
898 {PLAYER_NINJA_DIE + 4, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[2][5]},
899 {PLAYER_NINJA_DIE + 5, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[2][6]},
900 {PLAYER_NINJA_DIE + 6, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[2][7]},
901 {PLAYER_NINJA_DIE + 7, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[2][8]},
902 {PLAYER_NINJA_DIE + 8, 0 | SF_QUICK_CALL , QueueFloorBlood, &s_PlayerDeath[2][9]},
903 {PLAYER_NINJA_DIE + 8, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[2][9]},
904 },
905 {
906 {PLAYER_NINJA_DIE + 0, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[3][1]},
907 {PLAYER_NINJA_DIE + 1, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[3][2]},
908 {PLAYER_NINJA_DIE + 2, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[3][3]},
909 {PLAYER_NINJA_DIE + 3, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[3][4]},
910 {PLAYER_NINJA_DIE + 4, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[3][5]},
911 {PLAYER_NINJA_DIE + 5, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[3][6]},
912 {PLAYER_NINJA_DIE + 6, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[3][7]},
913 {PLAYER_NINJA_DIE + 7, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[3][8]},
914 {PLAYER_NINJA_DIE + 8, 0 | SF_QUICK_CALL , QueueFloorBlood, &s_PlayerDeath[3][9]},
915 {PLAYER_NINJA_DIE + 8, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[3][9]},
916 },
917 {
918 {PLAYER_NINJA_DIE + 0, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[4][1]},
919 {PLAYER_NINJA_DIE + 1, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[4][2]},
920 {PLAYER_NINJA_DIE + 2, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[4][3]},
921 {PLAYER_NINJA_DIE + 3, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[4][4]},
922 {PLAYER_NINJA_DIE + 4, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[4][5]},
923 {PLAYER_NINJA_DIE + 5, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[4][6]},
924 {PLAYER_NINJA_DIE + 6, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[4][7]},
925 {PLAYER_NINJA_DIE + 7, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[4][8]},
926 {PLAYER_NINJA_DIE + 8, 0 | SF_QUICK_CALL , QueueFloorBlood, &s_PlayerDeath[4][9]},
927 {PLAYER_NINJA_DIE + 8, NINJA_DIE_RATE, NullAnimator, &s_PlayerDeath[4][9]},
928 },
929 };
930
931 STATEp sg_PlayerDeath[] =
932 {
933 s_PlayerDeath[0],
934 s_PlayerDeath[1],
935 s_PlayerDeath[2],
936 s_PlayerDeath[3],
937 s_PlayerDeath[4]
938 };
939
940 //////////////////////
941 //
942 // PLAYER NINJA SWORD
943 //
944 //////////////////////
945
946
947 #define PLAYER_NINJA_SWORD_RATE 12
948 STATE s_PlayerNinjaSword[5][4] =
949 {
950 {
951 {PLAYER_NINJA_SWORD_R0 + 0, PLAYER_NINJA_SWORD_RATE, NullAnimator, &s_PlayerNinjaSword[0][1]},
952 {PLAYER_NINJA_SWORD_R0 + 1, PLAYER_NINJA_SWORD_RATE, NullAnimator, &s_PlayerNinjaSword[0][2]},
953 {PLAYER_NINJA_SWORD_R0 + 2, PLAYER_NINJA_SWORD_RATE, NullAnimator, &s_PlayerNinjaSword[0][3]},
954 {PLAYER_NINJA_SWORD_R0 + 2, PLAYER_NINJA_SWORD_RATE | SF_PLAYER_FUNC, DoPlayerSpriteReset, &s_PlayerNinjaSword[0][0]},
955 },
956 {
957 {PLAYER_NINJA_SWORD_R1 + 0, PLAYER_NINJA_SWORD_RATE, NullAnimator, &s_PlayerNinjaSword[1][1]},
958 {PLAYER_NINJA_SWORD_R1 + 1, PLAYER_NINJA_SWORD_RATE, NullAnimator, &s_PlayerNinjaSword[1][2]},
959 {PLAYER_NINJA_SWORD_R1 + 2, PLAYER_NINJA_SWORD_RATE, NullAnimator, &s_PlayerNinjaSword[1][3]},
960 {PLAYER_NINJA_SWORD_R1 + 2, PLAYER_NINJA_SWORD_RATE | SF_PLAYER_FUNC, DoPlayerSpriteReset, &s_PlayerNinjaSword[1][0]},
961 },
962 {
963 {PLAYER_NINJA_SWORD_R2 + 0, PLAYER_NINJA_SWORD_RATE, NullAnimator, &s_PlayerNinjaSword[2][1]},
964 {PLAYER_NINJA_SWORD_R2 + 1, PLAYER_NINJA_SWORD_RATE, NullAnimator, &s_PlayerNinjaSword[2][2]},
965 {PLAYER_NINJA_SWORD_R2 + 2, PLAYER_NINJA_SWORD_RATE, NullAnimator, &s_PlayerNinjaSword[2][3]},
966 {PLAYER_NINJA_SWORD_R2 + 2, PLAYER_NINJA_SWORD_RATE | SF_PLAYER_FUNC, DoPlayerSpriteReset, &s_PlayerNinjaSword[2][0]},
967 },
968 {
969 {PLAYER_NINJA_SWORD_R3 + 0, PLAYER_NINJA_SWORD_RATE, NullAnimator, &s_PlayerNinjaSword[3][1]},
970 {PLAYER_NINJA_SWORD_R3 + 1, PLAYER_NINJA_SWORD_RATE, NullAnimator, &s_PlayerNinjaSword[3][2]},
971 {PLAYER_NINJA_SWORD_R3 + 2, PLAYER_NINJA_SWORD_RATE, NullAnimator, &s_PlayerNinjaSword[3][3]},
972 {PLAYER_NINJA_SWORD_R3 + 2, PLAYER_NINJA_SWORD_RATE | SF_PLAYER_FUNC, DoPlayerSpriteReset, &s_PlayerNinjaSword[3][0]},
973 },
974 {
975 {PLAYER_NINJA_SWORD_R4 + 0, PLAYER_NINJA_SWORD_RATE, NullAnimator, &s_PlayerNinjaSword[4][1]},
976 {PLAYER_NINJA_SWORD_R4 + 1, PLAYER_NINJA_SWORD_RATE, NullAnimator, &s_PlayerNinjaSword[4][2]},
977 {PLAYER_NINJA_SWORD_R4 + 2, PLAYER_NINJA_SWORD_RATE, NullAnimator, &s_PlayerNinjaSword[4][3]},
978 {PLAYER_NINJA_SWORD_R4 + 2, PLAYER_NINJA_SWORD_RATE | SF_PLAYER_FUNC, DoPlayerSpriteReset, &s_PlayerNinjaSword[4][0]},
979 },
980 };
981
982
983 STATEp sg_PlayerNinjaSword[] =
984 {
985 s_PlayerNinjaSword[0],
986 s_PlayerNinjaSword[1],
987 s_PlayerNinjaSword[2],
988 s_PlayerNinjaSword[3],
989 s_PlayerNinjaSword[4]
990 };
991
992 //////////////////////
993 //
994 // PLAYER NINJA PUNCH
995 //
996 //////////////////////
997
998
999 #define PLAYER_NINJA_PUNCH_RATE 15
1000 STATE s_PlayerNinjaPunch[5][4] =
1001 {
1002 {
1003 {PLAYER_NINJA_PUNCH_R0 + 0, PLAYER_NINJA_PUNCH_RATE, NullAnimator, &s_PlayerNinjaPunch[0][1]},
1004 {PLAYER_NINJA_PUNCH_R0 + 1, PLAYER_NINJA_PUNCH_RATE, NullAnimator, &s_PlayerNinjaPunch[0][2]},
1005 {PLAYER_NINJA_PUNCH_R0 + 1, PLAYER_NINJA_PUNCH_RATE | SF_PLAYER_FUNC, DoPlayerSpriteReset, &s_PlayerNinjaPunch[0][2]},
1006 },
1007 {
1008 {PLAYER_NINJA_PUNCH_R1 + 0, PLAYER_NINJA_PUNCH_RATE, NullAnimator, &s_PlayerNinjaPunch[1][1]},
1009 {PLAYER_NINJA_PUNCH_R1 + 1, PLAYER_NINJA_PUNCH_RATE, NullAnimator, &s_PlayerNinjaPunch[1][2]},
1010 {PLAYER_NINJA_PUNCH_R1 + 1, PLAYER_NINJA_PUNCH_RATE | SF_PLAYER_FUNC, DoPlayerSpriteReset, &s_PlayerNinjaPunch[1][2]},
1011 },
1012 {
1013 {PLAYER_NINJA_PUNCH_R2 + 0, PLAYER_NINJA_PUNCH_RATE, NullAnimator, &s_PlayerNinjaPunch[2][1]},
1014 {PLAYER_NINJA_PUNCH_R2 + 1, PLAYER_NINJA_PUNCH_RATE, NullAnimator, &s_PlayerNinjaPunch[2][2]},
1015 {PLAYER_NINJA_PUNCH_R2 + 1, PLAYER_NINJA_PUNCH_RATE | SF_PLAYER_FUNC, DoPlayerSpriteReset, &s_PlayerNinjaPunch[2][2]},
1016 },
1017 {
1018 {PLAYER_NINJA_PUNCH_R3 + 0, PLAYER_NINJA_PUNCH_RATE, NullAnimator, &s_PlayerNinjaPunch[3][1]},
1019 {PLAYER_NINJA_PUNCH_R3 + 1, PLAYER_NINJA_PUNCH_RATE, NullAnimator, &s_PlayerNinjaPunch[3][2]},
1020 {PLAYER_NINJA_PUNCH_R3 + 1, PLAYER_NINJA_PUNCH_RATE | SF_PLAYER_FUNC, DoPlayerSpriteReset, &s_PlayerNinjaPunch[3][2]},
1021 },
1022 {
1023 {PLAYER_NINJA_PUNCH_R4 + 0, PLAYER_NINJA_PUNCH_RATE, NullAnimator, &s_PlayerNinjaPunch[4][1]},
1024 {PLAYER_NINJA_PUNCH_R4 + 1, PLAYER_NINJA_PUNCH_RATE, NullAnimator, &s_PlayerNinjaPunch[4][2]},
1025 {PLAYER_NINJA_PUNCH_R4 + 1, PLAYER_NINJA_PUNCH_RATE | SF_PLAYER_FUNC, DoPlayerSpriteReset, &s_PlayerNinjaPunch[4][2]},
1026 },
1027 };
1028
1029
1030 STATEp sg_PlayerNinjaPunch[] =
1031 {
1032 s_PlayerNinjaPunch[0],
1033 s_PlayerNinjaPunch[1],
1034 s_PlayerNinjaPunch[2],
1035 s_PlayerNinjaPunch[3],
1036 s_PlayerNinjaPunch[4]
1037 };
1038
1039 //////////////////////
1040 //
1041 // PLAYER NINJA FLY
1042 //
1043 //////////////////////
1044
1045
1046 #define PLAYER_NINJA_FLY_RATE 15
1047 #define PLAYER_NINJA_FLY_R0 1200
1048 #define PLAYER_NINJA_FLY_R1 1200
1049 #define PLAYER_NINJA_FLY_R2 1200
1050 #define PLAYER_NINJA_FLY_R3 1200
1051 #define PLAYER_NINJA_FLY_R4 1200
1052
1053 STATE s_PlayerNinjaFly[5][4] =
1054 {
1055 {
1056 {PLAYER_NINJA_FLY_R0 + 0, PLAYER_NINJA_FLY_RATE, NullAnimator, &s_PlayerNinjaFly[0][0]},
1057 },
1058 {
1059 {PLAYER_NINJA_FLY_R1 + 0, PLAYER_NINJA_FLY_RATE, NullAnimator, &s_PlayerNinjaFly[1][0]},
1060 },
1061 {
1062 {PLAYER_NINJA_FLY_R2 + 0, PLAYER_NINJA_FLY_RATE, NullAnimator, &s_PlayerNinjaFly[2][0]},
1063 },
1064 {
1065 {PLAYER_NINJA_FLY_R3 + 0, PLAYER_NINJA_FLY_RATE, NullAnimator, &s_PlayerNinjaFly[3][0]},
1066 },
1067 {
1068 {PLAYER_NINJA_FLY_R4 + 0, PLAYER_NINJA_FLY_RATE, NullAnimator, &s_PlayerNinjaFly[4][0]},
1069 },
1070 };
1071
1072
1073 STATEp sg_PlayerNinjaFly[] =
1074 {
1075 s_PlayerNinjaFly[0],
1076 s_PlayerNinjaFly[1],
1077 s_PlayerNinjaFly[2],
1078 s_PlayerNinjaFly[3],
1079 s_PlayerNinjaFly[4]
1080 };
1081
1082 /////////////////////////////////////////////////////////////////////////////
1083
1084 VOID
DoPlayerSpriteThrow(PLAYERp pp)1085 DoPlayerSpriteThrow(PLAYERp pp)
1086 {
1087 if (!TEST(pp->Flags, PF_DIVING|PF_FLYING|PF_CRAWLING))
1088 {
1089 if (pp->CurWpn == pp->Wpn[WPN_SWORD] && User[pp->PlayerSprite]->Rot != sg_PlayerNinjaSword)
1090 NewStateGroup(pp->PlayerSprite, sg_PlayerNinjaSword);
1091 else
1092 //if (pp->CurWpn == pp->Wpn[WPN_FIST] && User[pp->PlayerSprite]->Rot != sg_PlayerNinjaPunch)
1093 NewStateGroup(pp->PlayerSprite, sg_PlayerNinjaPunch);
1094 //else
1095 // NewStateGroup(pp->PlayerSprite, sg_PlayerNinjaThrow);
1096 }
1097 }
1098
1099 int
DoPlayerSpriteReset(short SpriteNum)1100 DoPlayerSpriteReset(short SpriteNum)
1101 {
1102 SPRITEp sp = &sprite[SpriteNum];
1103 USERp u = User[SpriteNum];
1104 PLAYERp pp;
1105
1106 if (!u->PlayerP)
1107 return (0);
1108
1109 pp = u->PlayerP;
1110
1111 // need to figure out what frames to put sprite into
1112 if (pp->DoPlayerAction == DoPlayerCrawl)
1113 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Crawl);
1114 else
1115 {
1116 if (TEST(pp->Flags, PF_PLAYER_MOVED))
1117 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Run);
1118 else
1119 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Stand);
1120 }
1121
1122 return (0);
1123 }
1124
1125 int
SetVisHigh(void)1126 SetVisHigh(void)
1127 {
1128 // visibility = NormalVisibility>>1;
1129 return (0);
1130 }
1131
1132 int
SetVisNorm(void)1133 SetVisNorm(void)
1134 {
1135 // visibility = NormalVisibility;
1136 return (0);
1137 }
1138
pSetVisNorm(PANEL_SPRITEp UNUSED (psp))1139 void pSetVisNorm(PANEL_SPRITEp UNUSED(psp))
1140 {
1141 // SetVisNorm();
1142 }
1143
1144 short
GetDeltaAngle(short ang1,short ang2)1145 GetDeltaAngle(short ang1, short ang2)
1146 {
1147 // Look at the smaller angle if > 1024 (180 degrees)
1148 if (labs(ang1 - ang2) > 1024)
1149 {
1150 if (ang1 <= 1024)
1151 ang1 += 2048;
1152
1153 if (ang2 <= 1024)
1154 ang2 += 2048;
1155 }
1156
1157 //if (ang1 - ang2 == -1024)
1158 // return(1024);
1159
1160 return (ang1 - ang2);
1161
1162 }
1163
1164 TARGET_SORT TargetSort[MAX_TARGET_SORT];
1165 unsigned TargetSortCount;
1166
CompareTarget(TARGET_SORTp tgt1,TARGET_SORTp tgt2)1167 int CompareTarget(TARGET_SORTp tgt1, TARGET_SORTp tgt2)
1168 {
1169 // will return a number less than 0 if tgt1 < tgt2
1170 return(tgt2->weight - tgt1->weight);
1171 }
1172
1173 BOOL
1174 FAFcansee(LONG xs, LONG ys, LONG zs, SHORT sects,
1175 LONG xe, LONG ye, LONG ze, SHORT secte);
1176
1177 int
DoPickTarget(SPRITEp sp,WORD max_delta_ang,BOOL skip_targets)1178 DoPickTarget(SPRITEp sp, WORD max_delta_ang, BOOL skip_targets)
1179 {
1180 #define PICK_DIST 40000L
1181
1182 short i, nexti, angle2, delta_ang;
1183 int dist, zh;
1184 SPRITEp ep;
1185 USERp eu;
1186 SHORTp shp;
1187 USERp u = User[sp - sprite];
1188 int ezh, ezhl, ezhm;
1189 unsigned ndx;
1190 TARGET_SORTp ts;
1191 int ang_weight, dist_weight;
1192
1193 // !JIM! Watch out for max_delta_ang of zero!
1194 if(max_delta_ang == 0) max_delta_ang = 1;
1195
1196 TargetSortCount = 0;
1197 TargetSort[0].sprite_num = -1;
1198
1199 for (shp = StatDamageList; shp < &StatDamageList[SIZ(StatDamageList)]; shp++)
1200 {
1201 TRAVERSE_SPRITE_STAT(headspritestat[*shp], i, nexti)
1202 {
1203 ep = &sprite[i];
1204 eu = User[i];
1205
1206 // don't pick yourself
1207 if (i == (sp - sprite))
1208 continue;
1209
1210 if(skip_targets != 2) // Used for spriteinfo mode
1211 {
1212 if (skip_targets && TEST(eu->Flags, SPR_TARGETED))
1213 continue;
1214
1215 // don't pick a dead player
1216 if (eu->PlayerP && TEST(eu->PlayerP->Flags, PF_DEAD))
1217 continue;
1218 }
1219
1220 // Only look at closest ones
1221 //if ((dist = Distance(sp->x, sp->y, ep->x, ep->y)) > PICK_DIST)
1222 if ( (dist = FindDistance3D(sp->x - ep->x, sp->y - ep->y, (sp->z - ep->z)>>4) ) > PICK_DIST)
1223 continue;
1224
1225 if(skip_targets != 2) // Used for spriteinfo mode
1226 {
1227 // don't set off mine
1228 if (!TEST(ep->extra, SPRX_PLAYER_OR_ENEMY))
1229 continue;
1230 }
1231
1232 // Get the angle to the player
1233 angle2 = NORM_ANGLE(getangle(ep->x - sp->x, ep->y - sp->y));
1234
1235 // Get the angle difference
1236 // delta_ang = labs(pp->pang - angle2);
1237
1238 delta_ang = labs(GetDeltaAngle(sp->ang, angle2));
1239
1240 // If delta_ang not in the range skip this one
1241 if (delta_ang > (int)max_delta_ang)
1242 continue;
1243
1244 if (u && u->PlayerP)
1245 zh = u->PlayerP->posz;
1246 else
1247 zh = SPRITEp_TOS(sp) + DIV4(SPRITEp_SIZE_Z(sp));
1248
1249 ezh = SPRITEp_TOS(ep) + DIV4(SPRITEp_SIZE_Z(ep));
1250 ezhm = SPRITEp_TOS(ep) + DIV2(SPRITEp_SIZE_Z(ep));
1251 ezhl = SPRITEp_BOS(ep) - DIV4(SPRITEp_SIZE_Z(ep));
1252
1253 // If you can't see 'em you can't shoot 'em
1254 if (!FAFcansee(sp->x, sp->y, zh, sp->sectnum, ep->x, ep->y, ezh, ep->sectnum) &&
1255 !FAFcansee(sp->x, sp->y, zh, sp->sectnum, ep->x, ep->y, ezhm, ep->sectnum) &&
1256 !FAFcansee(sp->x, sp->y, zh, sp->sectnum, ep->x, ep->y, ezhl, ep->sectnum)
1257 )
1258 continue;
1259
1260 // get ndx - there is only room for 15
1261 if (TargetSortCount > SIZ(TargetSort)-1)
1262 {
1263 for (ndx = 0; ndx < SIZ(TargetSort); ndx++)
1264 {
1265 if (dist < TargetSort[ndx].dist)
1266 break;
1267 }
1268
1269 if (ndx == SIZ(TargetSort))
1270 continue;
1271 }
1272 else
1273 {
1274 ndx = TargetSortCount;
1275 }
1276
1277 ts = &TargetSort[ndx];
1278 ts->sprite_num = i;
1279 ts->dang = delta_ang;
1280 ts->dist = dist;
1281 // gives a value between 0 and 65535
1282 ang_weight = ((max_delta_ang - ts->dang)<<16)/max_delta_ang;
1283 // gives a value between 0 and 65535
1284 dist_weight = ((DIV2(PICK_DIST) - DIV2(ts->dist))<<16)/DIV2(PICK_DIST);
1285 //weighted average
1286 ts->weight = (ang_weight + dist_weight*4)/5;
1287
1288 TargetSortCount++;
1289 if (TargetSortCount >= SIZ(TargetSort))
1290 TargetSortCount = SIZ(TargetSort);
1291 }
1292 }
1293
1294 if (TargetSortCount > 1)
1295 qsort(&TargetSort,TargetSortCount,sizeof(TARGET_SORT),(int(*)(const void*,const void*))CompareTarget);
1296
1297 return(TargetSort[0].sprite_num);
1298 }
1299
1300 void
DoPlayerResetMovement(PLAYERp pp)1301 DoPlayerResetMovement(PLAYERp pp)
1302 {
1303 pp->xvect = pp->oxvect = 0;
1304 pp->yvect = pp->oxvect = 0;
1305 pp->slide_xvect = 0;
1306 pp->slide_yvect = 0;
1307 pp->drive_angvel = 0;
1308 pp->drive_oangvel = 0;
1309 RESET(pp->Flags, PF_PLAYER_MOVED);
1310 }
1311
1312 void
DoPlayerTeleportPause(PLAYERp pp)1313 DoPlayerTeleportPause(PLAYERp pp)
1314 {
1315 USERp u = User[pp->PlayerSprite];
1316 SPRITEp sp = pp->SpriteP;
1317
1318 // set this so we don't get stuck in teleporting loop
1319 pp->lastcursectnum = pp->cursectnum;
1320
1321 if ((u->WaitTics-=synctics) <= 0)
1322 {
1323 //RESET(sp->cstat, CSTAT_SPRITE_TRANSLUCENT);
1324 RESET(pp->Flags2, PF2_TELEPORTED);
1325 DoPlayerResetMovement(pp);
1326 DoPlayerBeginRun(pp);
1327 return;
1328 }
1329
1330 //sp->shade -= 2;
1331 //if (sp->shade <= 0)
1332 // sp->shade = 0;
1333
1334 //DoPlayerBob(pp);
1335 }
1336
1337 VOID
DoPlayerTeleportToSprite(PLAYERp pp,SPRITEp sp)1338 DoPlayerTeleportToSprite(PLAYERp pp, SPRITEp sp)
1339 {
1340 int cz, fz;
1341
1342 pp->pang = pp->oang = sp->ang;
1343 pp->posx = pp->oposx = pp->oldposx = sp->x;
1344 pp->posy = pp->oposy = pp->oldposy = sp->y;
1345
1346 //getzsofslope(sp->sectnum, pp->posx, pp->posy, &cz, &fz);
1347 //pp->posz = pp->oposz = fz - PLAYER_HEIGHT;
1348
1349 pp->posz = pp->oposz = sp->z - PLAYER_HEIGHT;
1350
1351 COVERupdatesector(pp->posx, pp->posy, &pp->cursectnum);
1352 //pp->lastcursectnum = pp->cursectnum;
1353 SET(pp->Flags2, PF2_TELEPORTED);
1354 }
1355
1356 VOID
DoPlayerTeleportToOffset(PLAYERp pp)1357 DoPlayerTeleportToOffset(PLAYERp pp)
1358 {
1359 int fz,cz;
1360
1361 pp->oposx = pp->oldposx = pp->posx;
1362 pp->oposy = pp->oldposy = pp->posy;
1363
1364 COVERupdatesector(pp->posx, pp->posy, &pp->cursectnum);
1365 //pp->lastcursectnum = pp->cursectnum;
1366 SET(pp->Flags2, PF2_TELEPORTED);
1367 }
1368
1369 VOID
DoSpawnTeleporterEffect(SPRITEp sp)1370 DoSpawnTeleporterEffect(SPRITEp sp)
1371 {
1372 extern STATE s_TeleportEffect[];
1373 short effect;
1374 USERp eu;
1375 int nx, ny;
1376 SPRITEp ep;
1377
1378 nx = MOVEx(512L, sp->ang);
1379 ny = MOVEy(512L, sp->ang);
1380
1381 nx += sp->x;
1382 ny += sp->y;
1383
1384 effect = SpawnSprite(STAT_MISSILE, 0, s_TeleportEffect, sp->sectnum,
1385 nx, ny, SPRITEp_TOS(sp) + Z(16),
1386 sp->ang, 0);
1387
1388 ep = &sprite[effect];
1389 eu = User[effect];
1390
1391 setspritez(effect, ep->x, ep->y, ep->z);
1392
1393 ep->shade = -40;
1394 ep->xrepeat = ep->yrepeat = 42;
1395 SET(ep->cstat, CSTAT_SPRITE_YCENTER);
1396 RESET(ep->cstat, CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_BLOCK_HITSCAN);
1397
1398 SET(ep->cstat, CSTAT_SPRITE_WALL);
1399 //ep->ang = NORM_ANGLE(ep->ang + 512);
1400 }
1401
1402 VOID
DoSpawnTeleporterEffectPlace(SPRITEp sp)1403 DoSpawnTeleporterEffectPlace(SPRITEp sp)
1404 {
1405 extern STATE s_TeleportEffect[];
1406 short effect;
1407 USERp eu;
1408 int nx, ny;
1409 SPRITEp ep;
1410
1411 effect = SpawnSprite(STAT_MISSILE, 0, s_TeleportEffect, sp->sectnum,
1412 sp->x, sp->y, SPRITEp_TOS(sp) + Z(16),
1413 sp->ang, 0);
1414
1415 ep = &sprite[effect];
1416 eu = User[effect];
1417
1418 setspritez(effect, ep->x, ep->y, ep->z);
1419
1420 ep->shade = -40;
1421 ep->xrepeat = ep->yrepeat = 42;
1422 SET(ep->cstat, CSTAT_SPRITE_YCENTER);
1423 RESET(ep->cstat, CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_BLOCK_HITSCAN);
1424
1425 SET(ep->cstat, CSTAT_SPRITE_WALL);
1426 }
1427
1428 VOID
DoPlayerWarpTeleporter(PLAYERp pp)1429 DoPlayerWarpTeleporter(PLAYERp pp)
1430 {
1431 USERp u = User[pp->PlayerSprite], eu;
1432 SPRITEp sp = pp->SpriteP, ep;
1433 short pnum;
1434 SPRITEp sp_warp;
1435
1436 #if 0
1437 TAG 2 = match
1438 TAG 3 = Type
1439 Sprite - 0,32 always teleports you to the center at the angle the sprite is facing
1440 Offset - 1 always teleports you by the offset. Does not touch the angle
1441 TAG 4 = angle
1442 TAG 5 to 8 = random match locations
1443 #endif
1444
1445
1446 if ((sp_warp = Warp(&pp->posx, &pp->posy, &pp->posz, &pp->cursectnum)) == NULL)
1447 return;
1448
1449 switch (SP_TAG3(sp_warp))
1450 {
1451 case 1:
1452 DoPlayerTeleportToOffset(pp);
1453 UpdatePlayerSprite(pp);
1454 break;
1455 default:
1456 DoPlayerTeleportToSprite(pp, sp_warp);
1457
1458 PlaySound(DIGI_TELEPORT, &pp->posx, &pp->posy, &pp->posz, v3df_none);
1459
1460 DoPlayerResetMovement(pp);
1461
1462 u->WaitTics = 30;
1463 //sp->shade =
1464 //SET(sp->cstat, CSTAT_SPRITE_TRANSLUCENT);
1465 DoPlayerBeginRun(pp);
1466 //DoPlayerStand(pp);
1467 pp->DoPlayerAction = DoPlayerTeleportPause;
1468
1469 NewStateGroup(pp->PlayerSprite, User[pp->PlayerSprite]->ActorActionSet->Stand);
1470
1471 UpdatePlayerSprite(pp);
1472 DoSpawnTeleporterEffect(sp);
1473
1474 TRAVERSE_CONNECT(pnum)
1475 {
1476 if (pnum != pp - Player)
1477 {
1478 PLAYERp npp = &Player[pnum];
1479
1480 // if someone already standing there
1481 if (npp->cursectnum == pp->cursectnum)
1482 {
1483 PlayerUpdateHealth(npp, -User[npp->PlayerSprite]->Health); // Make sure he dies!
1484 // telefraged by teleporting player
1485 //PlayerCheckDeath(npp, npp->PlayerSprite);
1486 PlayerCheckDeath(npp, pp->PlayerSprite);
1487 }
1488 }
1489 }
1490
1491 break;
1492 }
1493
1494 u->ox = sp->x;
1495 u->oy = sp->y;
1496 u->oz = sp->z;
1497 }
1498
1499 VOID
DoPlayerSetWadeDepth(PLAYERp pp)1500 DoPlayerSetWadeDepth(PLAYERp pp)
1501 {
1502 SECTORp sectp;
1503
1504 pp->WadeDepth = 0;
1505
1506 if (pp->lo_sectp)
1507 sectp = pp->lo_sectp;
1508 else
1509 return;
1510
1511 if (TEST(sectp->extra, SECTFX_SINK))
1512 {
1513 // make sure your even in the water
1514 if (pp->posz + PLAYER_HEIGHT > pp->lo_sectp->floorz - Z(SectUser[pp->lo_sectp - sector]->depth))
1515 pp->WadeDepth = SectUser[pp->lo_sectp - sector]->depth;
1516 }
1517 }
1518
1519
1520 VOID
DoPlayerHeight(PLAYERp pp)1521 DoPlayerHeight(PLAYERp pp)
1522 {
1523 int diff;
1524
1525 diff = pp->posz - (pp->loz - PLAYER_HEIGHT);
1526
1527 pp->posz = pp->posz - (DIV4(diff) + DIV8(diff));
1528 }
1529
1530 VOID
DoPlayerJumpHeight(PLAYERp pp)1531 DoPlayerJumpHeight(PLAYERp pp)
1532 {
1533 if (pp->lo_sectp && TEST(pp->lo_sectp->extra, SECTFX_DYNAMIC_AREA))
1534 {
1535 if (pp->posz + PLAYER_HEIGHT > pp->loz)
1536 {
1537 pp->posz = pp->loz - PLAYER_HEIGHT;
1538 DoPlayerBeginRun(pp);
1539 }
1540 }
1541 }
1542
1543 VOID
DoPlayerCrawlHeight(PLAYERp pp)1544 DoPlayerCrawlHeight(PLAYERp pp)
1545 {
1546 int diff;
1547
1548 diff = pp->posz - (pp->loz - PLAYER_CRAWL_HEIGHT);
1549 pp->posz = pp->posz - (DIV4(diff) + DIV8(diff));
1550 }
1551
1552 VOID
DoPlayerTurn(PLAYERp pp)1553 DoPlayerTurn(PLAYERp pp)
1554 {
1555 int doubvel;
1556 short angvel;
1557
1558 #define TURN_SHIFT 2
1559
1560 if (!TEST(pp->Flags, PF_TURN_180))
1561 {
1562 if (TEST_SYNC_KEY(pp, SK_TURN_180))
1563 {
1564 if (FLAG_KEY_PRESSED(pp, SK_TURN_180))
1565 {
1566 short delta_ang;
1567
1568 FLAG_KEY_RELEASE(pp, SK_TURN_180);
1569
1570 pp->turn180_target = NORM_ANGLE(pp->pang + 1024);
1571
1572 // make the first turn in the clockwise direction
1573 // the rest will follow
1574 delta_ang = GetDeltaAngle(pp->turn180_target, pp->pang);
1575 pp->pang = NORM_ANGLE(pp->pang + (labs(delta_ang) >> TURN_SHIFT));
1576
1577 SET(pp->Flags, PF_TURN_180);
1578 }
1579 }
1580 else
1581 {
1582 FLAG_KEY_RESET(pp, SK_TURN_180);
1583 }
1584 }
1585
1586 if (TEST(pp->Flags, PF_TURN_180))
1587 {
1588 short delta_ang;
1589
1590 delta_ang = GetDeltaAngle(pp->turn180_target, pp->pang);
1591 pp->pang = NORM_ANGLE(pp->pang + (delta_ang >> TURN_SHIFT));
1592
1593 sprite[pp->PlayerSprite].ang = pp->pang;
1594 if (!Prediction)
1595 {
1596 if (pp->PlayerUnderSprite >= 0)
1597 sprite[pp->PlayerUnderSprite].ang = pp->pang;
1598 }
1599
1600 // get new delta to see how close we are
1601 delta_ang = GetDeltaAngle(pp->turn180_target, pp->pang);
1602
1603 if (labs(delta_ang) < (3<<TURN_SHIFT))
1604 {
1605 pp->pang = pp->turn180_target;
1606 RESET(pp->Flags, PF_TURN_180);
1607 }
1608 else
1609 return;
1610 }
1611
1612 angvel = pp->input.angvel * PLAYER_TURN_SCALE;
1613
1614 if (angvel != 0)
1615 {
1616 // running is not handled here now
1617 angvel += DIV4(angvel);
1618
1619 pp->pang += DIV32(angvel * synctics);
1620 pp->pang = NORM_ANGLE(pp->pang);
1621
1622 // update players sprite angle
1623 // NOTE: It's also updated in UpdatePlayerSprite, but needs to be
1624 // here to cover
1625 // all cases.
1626 sprite[pp->PlayerSprite].ang = pp->pang;
1627 if (!Prediction)
1628 {
1629 if (pp->PlayerUnderSprite >= 0)
1630 sprite[pp->PlayerUnderSprite].ang = pp->pang;
1631 }
1632
1633 }
1634 }
1635
1636 VOID
DoPlayerTurnBoat(PLAYERp pp)1637 DoPlayerTurnBoat(PLAYERp pp)
1638 {
1639 int angvel;
1640 int angslide;
1641 SECTOR_OBJECTp sop = pp->sop;
1642
1643 if (sop->drive_angspeed)
1644 {
1645 pp->drive_oangvel = pp->drive_angvel;
1646 pp->drive_angvel = mulscale16(pp->input.angvel, sop->drive_angspeed);
1647
1648 angslide = sop->drive_angslide;
1649 pp->drive_angvel = (pp->drive_angvel + (pp->drive_oangvel*(angslide-1)))/angslide;
1650
1651 angvel = pp->drive_angvel;
1652 }
1653 else
1654 {
1655 angvel = pp->input.angvel * PLAYER_TURN_SCALE;
1656 angvel += angvel - DIV4(angvel);
1657 angvel = DIV32(angvel * synctics);
1658 }
1659
1660 if (angvel != 0)
1661 {
1662 pp->pang = NORM_ANGLE(pp->pang + angvel);
1663 sprite[pp->PlayerSprite].ang = pp->pang;
1664 }
1665 }
1666
1667 VOID
DoPlayerTurnTank(PLAYERp pp,int z,int floor_dist)1668 DoPlayerTurnTank(PLAYERp pp, int z, int floor_dist)
1669 {
1670 int angvel;
1671 SECTOR_OBJECTp sop = pp->sop;
1672
1673 if (sop->drive_angspeed)
1674 {
1675 int angslide;
1676
1677 pp->drive_oangvel = pp->drive_angvel;
1678 pp->drive_angvel = mulscale16(pp->input.angvel, sop->drive_angspeed);
1679
1680 angslide = sop->drive_angslide;
1681 pp->drive_angvel = (pp->drive_angvel + (pp->drive_oangvel*(angslide-1)))/angslide;
1682
1683 angvel = pp->drive_angvel;
1684 }
1685 else
1686 {
1687 angvel = DIV8(pp->input.angvel * synctics);
1688 }
1689
1690 if (angvel != 0)
1691 {
1692 if (MultiClipTurn(pp, NORM_ANGLE(pp->pang + angvel), z, floor_dist))
1693 {
1694 pp->pang = NORM_ANGLE(pp->pang + angvel);
1695 sprite[pp->PlayerSprite].ang = pp->pang;
1696 }
1697 }
1698 }
1699
1700 VOID
DoPlayerTurnTankRect(PLAYERp pp,int * x,int * y,int * ox,int * oy)1701 DoPlayerTurnTankRect(PLAYERp pp, int *x, int *y, int *ox, int *oy)
1702 {
1703 int angvel;
1704 SECTOR_OBJECTp sop = pp->sop;
1705
1706 if (sop->drive_angspeed)
1707 {
1708 int angslide;
1709
1710 pp->drive_oangvel = pp->drive_angvel;
1711 pp->drive_angvel = mulscale16(pp->input.angvel, sop->drive_angspeed);
1712
1713 angslide = sop->drive_angslide;
1714 pp->drive_angvel = (pp->drive_angvel + (pp->drive_oangvel*(angslide-1)))/angslide;
1715
1716 angvel = pp->drive_angvel;
1717 }
1718 else
1719 {
1720 angvel = DIV8(pp->input.angvel * synctics);
1721 }
1722
1723 if (angvel != 0)
1724 {
1725 if (RectClipTurn(pp, NORM_ANGLE(pp->pang + angvel), x, y, ox, oy))
1726 {
1727 pp->pang = NORM_ANGLE(pp->pang + angvel);
1728 sprite[pp->PlayerSprite].ang = pp->pang;
1729 }
1730 }
1731 }
1732
1733 VOID
DoPlayerTurnTurret(PLAYERp pp)1734 DoPlayerTurnTurret(PLAYERp pp)
1735 {
1736 int angvel;
1737 short new_ang;
1738 short diff;
1739 SECTOR_OBJECTp sop = pp->sop;
1740 SW_PACKET last_input;
1741 int fifo_ndx;
1742
1743 if (!Prediction)
1744 {
1745 // this code looks at the fifo to get the last value for comparison
1746 fifo_ndx = (movefifoplc-2) & (MOVEFIFOSIZ - 1);
1747 last_input = pp->inputfifo[fifo_ndx];
1748
1749 if (pp->input.angvel && !last_input.angvel)
1750 PlaySOsound(pp->sop->mid_sector, SO_DRIVE_SOUND);
1751 else
1752 if (!pp->input.angvel && last_input.angvel)
1753 PlaySOsound(pp->sop->mid_sector, SO_IDLE_SOUND);
1754 }
1755
1756 if (sop->drive_angspeed)
1757 {
1758 int angslide;
1759
1760 pp->drive_oangvel = pp->drive_angvel;
1761 pp->drive_angvel = mulscale16(pp->input.angvel, sop->drive_angspeed);
1762
1763 angslide = sop->drive_angslide;
1764 pp->drive_angvel = (pp->drive_angvel + (pp->drive_oangvel*(angslide-1)))/angslide;
1765
1766 angvel = pp->drive_angvel;
1767 }
1768 else
1769 {
1770 angvel = DIV4(pp->input.angvel * synctics);
1771 }
1772
1773 if (angvel != 0)
1774 {
1775 new_ang = NORM_ANGLE(pp->pang + angvel);
1776
1777 if (sop->limit_ang_center >= 0)
1778 {
1779 diff = GetDeltaAngle(new_ang, sop->limit_ang_center);
1780
1781 if (labs(diff) >= sop->limit_ang_delta)
1782 {
1783 if (diff < 0)
1784 new_ang = sop->limit_ang_center - sop->limit_ang_delta;
1785 else
1786 new_ang = sop->limit_ang_center + sop->limit_ang_delta;
1787
1788 }
1789 }
1790
1791 pp->pang = new_ang;
1792 sprite[pp->PlayerSprite].ang = pp->pang;
1793 }
1794 }
1795
SlipSlope(PLAYERp pp)1796 void SlipSlope(PLAYERp pp)
1797 {
1798 short wallptr = sector[pp->cursectnum].wallptr;
1799 short ang;
1800 SECT_USERp sectu = SectUser[pp->cursectnum];
1801
1802 if (!sectu || !TEST(sectu->flags, SECTFU_SLIDE_SECTOR) || !TEST(sector[pp->cursectnum].floorstat, FLOOR_STAT_SLOPE))
1803 return;
1804
1805 ang = getangle(wall[wall[wallptr].point2].x - wall[wallptr].x, wall[wall[wallptr].point2].y - wall[wallptr].y);
1806
1807 ang = NORM_ANGLE(ang + 512);
1808
1809 pp->xvect += mulscale(sintable[NORM_ANGLE(ang + 512)], sector[pp->cursectnum].floorheinum, sectu->speed);
1810 pp->yvect += mulscale(sintable[ang], sector[pp->cursectnum].floorheinum, sectu->speed);
1811 }
1812
1813 VOID
PlayerAutoLook(PLAYERp pp)1814 PlayerAutoLook(PLAYERp pp)
1815 {
1816 int x,y,k,j;
1817 short tempsect;
1818
1819
1820 if (!TEST(pp->Flags, PF_FLYING|PF_SWIMMING|PF_DIVING|PF_CLIMBING|PF_JUMPING|PF_FALLING))
1821 {
1822 if (!TEST(pp->Flags, PF_MOUSE_AIMING_ON) && TEST(sector[pp->cursectnum].floorstat, FLOOR_STAT_SLOPE)) // If the floor is sloped
1823 {
1824 // Get a point, 512 units ahead of player's position
1825 x = pp->posx + (sintable[(pp->pang + 512) & 2047] >> 5);
1826 y = pp->posy + (sintable[pp->pang & 2047] >> 5);
1827 tempsect = pp->cursectnum;
1828 COVERupdatesector(x, y, &tempsect);
1829
1830 if (tempsect >= 0) // If the new point is inside a valid
1831 // sector...
1832 {
1833 // Get the floorz as if the new (x,y) point was still in
1834 // your sector
1835 j = getflorzofslope(pp->cursectnum, pp->posx, pp->posy);
1836 k = getflorzofslope(pp->cursectnum, x, y);
1837
1838 // If extended point is in same sector as you or the slopes
1839 // of the sector of the extended point and your sector match
1840 // closely (to avoid accidently looking straight out when
1841 // you're at the edge of a sector line) then adjust horizon
1842 // accordingly
1843 if ((pp->cursectnum == tempsect) ||
1844 (klabs(getflorzofslope(tempsect, x, y) - k) <= (4 << 8)))
1845 {
1846 pp->horizoff += (((j - k) * 160) >> 16);
1847 }
1848 }
1849 }
1850 }
1851
1852 if (TEST(pp->Flags, PF_CLIMBING))
1853 {
1854 // tilt when climbing but you can't even really tell it
1855 if (pp->horizoff < 100)
1856 pp->horizoff += (((100 - pp->horizoff) >> 3) + 1);
1857 }
1858 else
1859 {
1860 // Make horizoff grow towards 0 since horizoff is not modified when
1861 // you're not on a slope
1862 if (pp->horizoff > 0)
1863 pp->horizoff -= ((pp->horizoff >> 3) + 1);
1864 if (pp->horizoff < 0)
1865 pp->horizoff += (((-pp->horizoff) >> 3) + 1);
1866 }
1867 }
1868
1869 extern int PlaxCeilGlobZadjust, PlaxFloorGlobZadjust;
1870 VOID
DoPlayerHorizon(PLAYERp pp)1871 DoPlayerHorizon(PLAYERp pp)
1872 {
1873 int i;
1874 #define HORIZ_SPEED (16)
1875
1876 // //DSPRINTF(ds,"pp->horizoff, %d", pp->horizoff);
1877 // MONO_PRINT(ds);
1878
1879 PlayerAutoLook(pp);
1880
1881 if (pp->input.aimvel)
1882 {
1883 pp->horizbase += pp->input.aimvel;
1884 SET(pp->Flags, PF_LOCK_HORIZ | PF_LOOKING);
1885 }
1886
1887 if (TEST_SYNC_KEY(pp, SK_CENTER_VIEW))
1888 {
1889 // if (TEST(pp->Flags, PF_MOUSE_AIMING_ON))
1890 {
1891 pp->horiz = pp->horizbase = 100;
1892 pp->horizoff = 0;
1893 }
1894 // else
1895 {
1896 //gs.MouseAimingOn = FALSE;
1897 // RESET(pp->Flags, PF_LOCK_HORIZ);
1898 // SET(pp->Flags, PF_LOOKING);
1899 }
1900 }
1901
1902 // this is the locked type
1903 if (TEST_SYNC_KEY(pp, SK_SNAP_UP) || TEST_SYNC_KEY(pp, SK_SNAP_DOWN))
1904 {
1905 // set looking because player is manually looking
1906 SET(pp->Flags, PF_LOCK_HORIZ | PF_LOOKING);
1907
1908 // adjust pp->horizon negative
1909 if (TEST_SYNC_KEY(pp, SK_SNAP_DOWN))
1910 pp->horizbase -= (HORIZ_SPEED/2);
1911
1912 // adjust pp->horizon positive
1913 if (TEST_SYNC_KEY(pp, SK_SNAP_UP))
1914 pp->horizbase += (HORIZ_SPEED/2);
1915 }
1916
1917
1918 // this is the unlocked type
1919 if (TEST_SYNC_KEY(pp, SK_LOOK_UP) || TEST_SYNC_KEY(pp, SK_LOOK_DOWN))
1920 {
1921 RESET(pp->Flags, PF_LOCK_HORIZ);
1922 SET(pp->Flags, PF_LOOKING);
1923
1924 // adjust pp->horizon negative
1925 if (TEST_SYNC_KEY(pp, SK_LOOK_DOWN))
1926 pp->horizbase -= HORIZ_SPEED;
1927
1928 // adjust pp->horizon positive
1929 if (TEST_SYNC_KEY(pp, SK_LOOK_UP))
1930 pp->horizbase += HORIZ_SPEED;
1931 }
1932
1933
1934 if (!TEST(pp->Flags, PF_LOCK_HORIZ))
1935 {
1936 if (!(TEST_SYNC_KEY(pp, SK_LOOK_UP) || TEST_SYNC_KEY(pp, SK_LOOK_DOWN)))
1937 {
1938 // not pressing the pp->horiz keys
1939 if (pp->horizbase != 100)
1940 {
1941
1942 // move pp->horiz back to 100
1943 for (i = 1; i; i--)
1944 {
1945 // this formula does not work for pp->horiz = 101-103
1946 pp->horizbase += 25 - (pp->horizbase >> 2);
1947 }
1948 }
1949 else
1950 {
1951 // not looking anymore because pp->horiz is back at 100
1952 RESET(pp->Flags, PF_LOOKING);
1953 }
1954 }
1955 }
1956
1957 #if 1
1958 // bound the base
1959 pp->horizbase = max(pp->horizbase, PLAYER_HORIZ_MIN);
1960 pp->horizbase = min(pp->horizbase, PLAYER_HORIZ_MAX);
1961
1962 // bound adjust horizoff
1963 if (pp->horizbase + pp->horizoff < PLAYER_HORIZ_MIN)
1964 pp->horizoff = PLAYER_HORIZ_MIN - pp->horizbase;
1965 else
1966 if (pp->horizbase + pp->horizoff > PLAYER_HORIZ_MAX)
1967 pp->horizoff = PLAYER_HORIZ_MAX - pp->horizbase;
1968
1969 ////DSPRINTF(ds,"base %d, off %d, base + off %d",pp->horizbase, pp->horizoff, pp->horizbase + pp->horizoff);
1970 //MONO_PRINT(ds);
1971
1972 // add base and offsets
1973 pp->horiz = pp->horizbase + pp->horizoff;
1974 #else
1975 if (pp->horizbase + pp->horizoff < PLAYER_HORIZ_MIN)
1976 pp->horizbase += HORIZ_SPEED;
1977 else
1978 if (pp->horizbase + pp->horizoff > PLAYER_HORIZ_MAX)
1979 pp->horizbase -= HORIZ_SPEED;
1980
1981 pp->horiz = pp->horizbase + pp->horizoff;
1982 #endif
1983
1984 }
1985
1986 VOID
DoPlayerBob(PLAYERp pp)1987 DoPlayerBob(PLAYERp pp)
1988 {
1989 extern ULONG MoveThingsCount;
1990 int dist;
1991 int amt;
1992
1993 dist = 0;
1994
1995 dist = Distance(pp->posx, pp->posy, pp->oldposx, pp->oldposy);
1996
1997 if (dist > 512)
1998 dist = 0;
1999
2000 // if running make a longer stride
2001 if (TEST_SYNC_KEY(pp, SK_RUN) || TEST(pp->Flags, PF_LOCK_RUN))
2002 {
2003 //amt = 10;
2004 amt = 12;
2005 amt = mulscale16(amt, dist<<8);
2006
2007 dist = mulscale16(dist, 26000);
2008 // controls how fast you move through the sin table
2009 pp->bcnt += dist;
2010
2011 // wrap bcnt
2012 pp->bcnt &= 2047;
2013
2014 // move pp->horiz up and down from 100 using sintable
2015 //pp->bob_z = Z((8 * sintable[pp->bcnt]) >> 14);
2016 pp->bob_z = mulscale14(Z(amt),sintable[pp->bcnt]);
2017 }
2018 else
2019 {
2020 amt = 5;
2021 amt = mulscale16(amt, dist<<9);
2022
2023 dist = mulscale16(dist, 32000);
2024 // controls how fast you move through the sin table
2025 pp->bcnt += dist;
2026
2027 // wrap bcnt
2028 pp->bcnt &= 2047;
2029
2030 // move pp->horiz up and down from 100 using sintable
2031 //pp->bob_z = Z((4 * sintable[pp->bcnt]) >> 14);
2032 pp->bob_z = mulscale14(Z(amt),sintable[pp->bcnt]);
2033 }
2034 }
2035
2036 VOID
DoPlayerBeginRecoil(PLAYERp pp,short pix_amt)2037 DoPlayerBeginRecoil(PLAYERp pp, short pix_amt)
2038 {
2039 #if 0
2040 return;
2041 #else
2042 SET(pp->Flags, PF_RECOIL);
2043
2044 pp->recoil_amt = pix_amt;
2045 pp->recoil_speed = 80;
2046 pp->recoil_ndx = 0;
2047 pp->recoil_horizoff = 0;
2048 #endif
2049 }
2050
2051 VOID
DoPlayerRecoil(PLAYERp pp)2052 DoPlayerRecoil(PLAYERp pp)
2053 {
2054 int dist;
2055
2056 // controls how fast you move through the sin table
2057 pp->recoil_ndx += pp->recoil_speed;
2058
2059 if (sintable[pp->recoil_ndx] < 0)
2060 {
2061 RESET(pp->Flags, PF_RECOIL);
2062 pp->recoil_horizoff = 0;
2063 return;
2064 }
2065
2066 // move pp->horiz up and down
2067 pp->recoil_horizoff = ((pp->recoil_amt * sintable[pp->recoil_ndx]) >> 14);
2068 }
2069
2070
2071
2072 // for wading
2073 VOID
DoPlayerSpriteBob(PLAYERp pp,short player_height,short bob_amt,short bob_speed)2074 DoPlayerSpriteBob(PLAYERp pp, short player_height, short bob_amt, short bob_speed)
2075 {
2076 USERp u = User[pp->PlayerSprite];
2077 SPRITEp sp = pp->SpriteP;
2078
2079 pp->bob_ndx = (pp->bob_ndx + (synctics << bob_speed)) & 2047;
2080
2081 pp->bob_amt = ((bob_amt * (int) sintable[pp->bob_ndx]) >> 14);
2082
2083 sp->z = (pp->posz + player_height) + pp->bob_amt;
2084 }
2085
2086 VOID
UpdatePlayerUnderSprite(PLAYERp pp)2087 UpdatePlayerUnderSprite(PLAYERp pp)
2088 {
2089 SPRITEp over_sp = pp->SpriteP;
2090 USERp over_u = User[pp->PlayerSprite];
2091
2092 SPRITEp sp;
2093 USERp u;
2094 short SpriteNum;
2095
2096 int water_level_z, zdiff;
2097 BOOL above_water, in_dive_area;
2098
2099 if (Prediction)
2100 return;
2101
2102 ASSERT(over_sp);
2103 ASSERT(over_u);
2104
2105 // dont bother spawning if you ain't really in the water
2106 //water_level_z = sector[over_sp->sectnum].floorz - Z(pp->WadeDepth);
2107 water_level_z = sector[over_sp->sectnum].floorz;// - Z(pp->WadeDepth);
2108
2109 // if not below water
2110 above_water = (SPRITEp_BOS(over_sp) <= water_level_z);
2111 in_dive_area = SpriteInDiveArea(over_sp);
2112
2113 // if not in dive area OR (in dive area AND above the water) - Kill it
2114 if (!in_dive_area || (in_dive_area && above_water))
2115 {
2116
2117 // if under sprite exists and not in a dive area - Kill it
2118 if (pp->PlayerUnderSprite >= 0)
2119 {
2120 KillSprite(pp->PlayerUnderSprite);
2121 pp->PlayerUnderSprite = -1;
2122 pp->UnderSpriteP = NULL;
2123 }
2124 return;
2125 }
2126 else
2127 {
2128 // if in a dive area and a under sprite does not exist - create it
2129 if (pp->PlayerUnderSprite < 0)
2130 {
2131 SpawnPlayerUnderSprite(pp);
2132 }
2133 }
2134
2135 sp = pp->UnderSpriteP;
2136 u = User[pp->PlayerUnderSprite];
2137
2138 SpriteNum = pp->PlayerUnderSprite;
2139
2140 sp->x = over_sp->x;
2141 sp->y = over_sp->y;
2142 sp->z = over_sp->z;
2143 changespritesect(SpriteNum, over_sp->sectnum);
2144
2145 SpriteWarpToUnderwater(sp);
2146
2147 // find z water level of the top sector
2148 // diff between the bottom of the upper sprite and the water level
2149 zdiff = SPRITEp_BOS(over_sp) - water_level_z;
2150
2151 // add diff to ceiling
2152 sp->z = sector[sp->sectnum].ceilingz + zdiff;
2153
2154 u->State = over_u->State;
2155 u->Rot = over_u->Rot;
2156 u->StateStart = over_u->StateStart;
2157
2158 sp->picnum = over_sp->picnum;
2159 }
2160
2161
2162 VOID
UpdatePlayerSprite(PLAYERp pp)2163 UpdatePlayerSprite(PLAYERp pp)
2164 {
2165 SPRITEp sp = pp->SpriteP;
2166
2167 // Update sprite representation of player
2168
2169 sp->x = pp->posx;
2170 sp->y = pp->posy;
2171
2172 // there are multiple death functions
2173 if (TEST(pp->Flags, PF_DEAD))
2174 {
2175 changespritesect(pp->PlayerSprite, pp->cursectnum);
2176 sprite[pp->PlayerSprite].ang = pp->pang;
2177 UpdatePlayerUnderSprite(pp);
2178 return;
2179 }
2180
2181 if (pp->sop_control)
2182 {
2183 sp->z = sector[pp->cursectnum].floorz;
2184 changespritesect(pp->PlayerSprite, pp->cursectnum);
2185 }
2186 else
2187 if (pp->DoPlayerAction == DoPlayerCrawl)
2188 {
2189 sp->z = pp->posz + PLAYER_CRAWL_HEIGHT;
2190 changespritesect(pp->PlayerSprite, pp->cursectnum);
2191 }
2192 #if 0
2193 else if (pp->DoPlayerAction == DoPlayerSwim)
2194 {
2195 sp->z = pp->loz - Z(pp->WadeDepth) + Z(1);
2196 changespritesect(pp->PlayerSprite, pp->cursectnum);
2197 }
2198 #endif
2199 else if (pp->DoPlayerAction == DoPlayerWade)
2200 {
2201 sp->z = pp->posz + PLAYER_HEIGHT;
2202 changespritesect(pp->PlayerSprite, pp->cursectnum);
2203
2204 if (pp->WadeDepth > Z(29))
2205 {
2206 DoPlayerSpriteBob(pp, PLAYER_HEIGHT, Z(3), 3);
2207 }
2208 }
2209 else if (pp->DoPlayerAction == DoPlayerDive)
2210 {
2211 // bobbing and sprite position taken care of in DoPlayerDive
2212 sp->z = pp->posz + Z(10);
2213 changespritesect(pp->PlayerSprite, pp->cursectnum);
2214 }
2215 else if (pp->DoPlayerAction == DoPlayerClimb)
2216 {
2217 sp->z = pp->posz + Z(17);
2218
2219 // move it forward a bit to look like its on the ladder
2220 //sp->x += MOVEx(256+64, sp->ang);
2221 //sp->y += MOVEy(256+64, sp->ang);
2222
2223 changespritesect(pp->PlayerSprite, pp->cursectnum);
2224 }
2225 else if (pp->DoPlayerAction == DoPlayerFly)
2226 {
2227 // sp->z = pp->posz + PLAYER_HEIGHT;
2228 // bobbing and sprite position taken care of in DoPlayerFly
2229 //sp->z = pp->posz + PLAYER_HEIGHT;
2230 //DoPlayerSpriteBob(pp, PLAYER_HEIGHT, PLAYER_FLY_BOB_AMT, 3);
2231 DoPlayerSpriteBob(pp, PLAYER_HEIGHT, Z(6), 3);
2232 changespritesect(pp->PlayerSprite, pp->cursectnum);
2233 }
2234 else if (pp->DoPlayerAction == DoPlayerJump || pp->DoPlayerAction == DoPlayerFall || pp->DoPlayerAction == DoPlayerForceJump)
2235 {
2236 sp->z = pp->posz + PLAYER_HEIGHT;
2237 changespritesect(pp->PlayerSprite, pp->cursectnum);
2238 }
2239 else if (pp->DoPlayerAction == DoPlayerTeleportPause)
2240 {
2241 sp->z = pp->posz + PLAYER_HEIGHT;
2242 changespritesect(pp->PlayerSprite, pp->cursectnum);
2243 }
2244 else
2245 {
2246 sp->z = pp->loz;
2247 changespritesect(pp->PlayerSprite, pp->cursectnum);
2248 }
2249
2250 UpdatePlayerUnderSprite(pp);
2251
2252 sprite[pp->PlayerSprite].ang = pp->pang;
2253 }
2254
2255 VOID
DoPlayerZrange(PLAYERp pp)2256 DoPlayerZrange(PLAYERp pp)
2257 {
2258 int ceilhit, florhit;
2259 short bakcstat;
2260
2261 // Don't let you fall if you're just slightly over a cliff
2262 // This function returns the highest and lowest z's
2263 // for an entire box, NOT just a point. -Useful for clipping
2264 bakcstat = pp->SpriteP->cstat;
2265 RESET(pp->SpriteP->cstat, CSTAT_SPRITE_BLOCK);
2266 FAFgetzrange(pp->posx, pp->posy, pp->posz + Z(8), pp->cursectnum, &pp->hiz, &ceilhit, &pp->loz, &florhit, ((int)pp->SpriteP->clipdist<<2) - GETZRANGE_CLIP_ADJ, CLIPMASK_PLAYER);
2267 pp->SpriteP->cstat = bakcstat;
2268
2269 // 16384+sector (sector first touched) or
2270 // 49152+spritenum (sprite first touched)
2271
2272 pp->lo_sectp = pp->hi_sectp = NULL;
2273 pp->lo_sp = pp->hi_sp = NULL;
2274
2275 if (TEST(ceilhit, 0xc000) == 49152)
2276 {
2277 pp->hi_sp = &sprite[ceilhit & 4095];
2278 }
2279 else
2280 {
2281 pp->hi_sectp = §or[ceilhit & 4095];
2282 }
2283
2284 if (TEST(florhit, 0xc000) == 49152)
2285 {
2286 pp->lo_sp = &sprite[florhit & 4095];
2287
2288 // prevent player from standing on Zombies
2289 if (pp->lo_sp->statnum == STAT_ENEMY && User[pp->lo_sp - sprite]->ID == ZOMBIE_RUN_R0)
2290 {
2291 pp->lo_sectp = §or[pp->lo_sp->sectnum];
2292 pp->loz = pp->lo_sp->z;
2293 pp->lo_sp = NULL;
2294 }
2295 }
2296 else
2297 {
2298 pp->lo_sectp = §or[florhit & 4095];
2299 }
2300 }
2301
2302 VOID
DoPlayerSlide(PLAYERp pp)2303 DoPlayerSlide(PLAYERp pp)
2304 {
2305 USERp u = User[pp->PlayerSprite];
2306 int ret;
2307 int push_ret;
2308
2309 if ((pp->slide_xvect|pp->slide_yvect) == 0)
2310 return;
2311
2312 if (pp->sop)
2313 return;
2314
2315 pp->slide_xvect = mulscale(pp->slide_xvect, PLAYER_SLIDE_FRICTION,16);
2316 pp->slide_yvect = mulscale(pp->slide_yvect, PLAYER_SLIDE_FRICTION,16);
2317
2318 if( labs(pp->slide_xvect) < 12800 && labs(pp->slide_yvect) < 12800 )
2319 pp->slide_xvect = pp->slide_yvect = 0;
2320
2321 push_ret = pushmove(&pp->posx, &pp->posy, &pp->posz, &pp->cursectnum, ((int)pp->SpriteP->clipdist<<2), pp->ceiling_dist, pp->floor_dist, CLIPMASK_PLAYER);
2322 if (push_ret < 0)
2323 {
2324 if (!TEST(pp->Flags, PF_DEAD))
2325 {
2326 PlayerUpdateHealth(pp, -u->Health); // Make sure he dies!
2327 PlayerCheckDeath(pp, -1);
2328
2329 if (TEST(pp->Flags, PF_DEAD))
2330 return;
2331 }
2332 return;
2333 }
2334 ret = clipmove(&pp->posx, &pp->posy, &pp->posz, &pp->cursectnum, pp->slide_xvect, pp->slide_yvect, ((int)pp->SpriteP->clipdist<<2), pp->ceiling_dist, pp->floor_dist, CLIPMASK_PLAYER);
2335 PlayerCheckValidMove(pp);
2336 push_ret = pushmove(&pp->posx, &pp->posy, &pp->posz, &pp->cursectnum, ((int)pp->SpriteP->clipdist<<2), pp->ceiling_dist, pp->floor_dist, CLIPMASK_PLAYER);
2337 if (push_ret < 0)
2338 {
2339 if (!TEST(pp->Flags, PF_DEAD))
2340 {
2341 PlayerUpdateHealth(pp, -u->Health); // Make sure he dies!
2342 PlayerCheckDeath(pp, -1);
2343
2344 if (TEST(pp->Flags, PF_DEAD))
2345 return;
2346 }
2347 return;
2348 }
2349 }
2350
PlayerMoveHitDebug(short ret)2351 VOID PlayerMoveHitDebug(short ret)
2352 {
2353 SPRITEp sp;
2354 extern BOOL DebugActor;
2355
2356 switch (TEST(ret, HIT_MASK))
2357 {
2358 case HIT_SPRITE:
2359 sp = &sprite[NORM_SPRITE(ret)];
2360 //DSPRINTF(ds, "Hit a Sprite %d, stat %d ", sp-sprite, (short)sp->statnum);
2361 if (sp->statnum == STAT_MISSILE)
2362 {
2363 //DSPRINTF(ds, "Monster hit bullet %d, stat %d ", sp-sprite, (short)sp->statnum);
2364 }
2365 else
2366 {
2367 //DSPRINTF(ds, "Hit a Sprite %d, stat %d ", sp-sprite, (short)sp->statnum);
2368 }
2369 break;
2370 case HIT_WALL:
2371 //DSPRINTF(ds, "Hit a Wall %d ", NORM_WALL(ret));
2372 break;
2373 case HIT_SECTOR:
2374 //DSPRINTF(ds, "Hit a Sector %d ", NORM_SECTOR(ret));
2375 break;
2376 }
2377
2378 MONO_PRINT(ds);
2379 }
2380
PlayerCheckValidMove(PLAYERp pp)2381 VOID PlayerCheckValidMove(PLAYERp pp)
2382 {
2383 if (pp->cursectnum == -1)
2384 {
2385 static int count = 0;
2386
2387 #if DEBUG
2388 //DSPRINTF(ds,"PROBLEM!!!!! Player %d is not in a sector", pp - Player);
2389 MONO_PRINT(ds);
2390 #endif
2391
2392 pp->posx = pp->oldposx;
2393 pp->posy = pp->oldposy;
2394 pp->posz = pp->oldposz;
2395 pp->cursectnum = pp->lastcursectnum;
2396
2397 // if stuck here for more than 10 seconds
2398 if (count++ > 40 * 10)
2399 {
2400 ASSERT(TRUE == FALSE);
2401 }
2402 }
2403 }
2404
2405 VOID
MoveScrollMode2D(PLAYERp pp)2406 MoveScrollMode2D(PLAYERp pp)
2407 {
2408 #define TURBOTURNTIME (120/8)
2409 #define NORMALTURN (12+6)
2410 #define RUNTURN (28)
2411 #define PREAMBLETURN 3
2412 #define NORMALKEYMOVE 35
2413 #define MAXVEL ((NORMALKEYMOVE*2)+10)
2414 #define MAXSVEL ((NORMALKEYMOVE*2)+10)
2415 #define MAXANGVEL 100
2416
2417 ControlInfo scrl_input;
2418 boolean running;
2419 int32 keymove;
2420 int32 momx, momy;
2421 static int mfvel=0, mfsvel=0;
2422 extern BOOL HelpInputMode, ScrollMode2D;
2423
2424
2425 CONTROL_GetInput(&scrl_input);
2426
2427 mfsvel = mfvel = 0;
2428
2429 if (MenuInputMode || UsingMenus)
2430 return;
2431
2432 // Recenter view if told
2433 if (BUTTON(gamefunc_Center_View))
2434 {
2435 Follow_posx = pp->posx;
2436 Follow_posy = pp->posy;
2437 }
2438
2439 // Toggle follow map mode on/off
2440 if (BUTTON(gamefunc_Map_Follow_Mode) && !BUTTONHELD(gamefunc_Map_Follow_Mode))
2441 {
2442 ScrollMode2D = !ScrollMode2D;
2443 // Reset coords
2444 Follow_posx = pp->posx;
2445 Follow_posy = pp->posy;
2446 }
2447
2448 running = BUTTON(gamefunc_Run) || TEST(pp->Flags, PF_LOCK_RUN);
2449
2450 if (BUTTON(gamefunc_Strafe))
2451 mfsvel -= scrl_input.dyaw>>2;
2452 mfsvel -= scrl_input.dx>>2;
2453 mfvel = -scrl_input.dz>>2;
2454
2455 if (running)
2456 {
2457 //keymove = NORMALKEYMOVE << 1;
2458 keymove = NORMALKEYMOVE;
2459 }
2460 else
2461 {
2462 keymove = NORMALKEYMOVE;
2463 }
2464
2465 if (!HelpInputMode && !ConPanel)
2466 {
2467 if (BUTTON(gamefunc_Turn_Left))
2468 {
2469 mfsvel -= -keymove;
2470 }
2471 if (BUTTON(gamefunc_Turn_Right))
2472 {
2473 mfsvel -= keymove;
2474 }
2475 }
2476
2477 if (!InputMode && !ConPanel)
2478 {
2479 if (BUTTON(gamefunc_Strafe_Left))
2480 {
2481 mfsvel += keymove;
2482 }
2483
2484 if (BUTTON(gamefunc_Strafe_Right))
2485 {
2486 mfsvel += -keymove;
2487 }
2488 }
2489
2490 if(!UsingMenus && !HelpInputMode && !ConPanel)
2491 {
2492 if (BUTTON(gamefunc_Move_Forward))
2493 {
2494 mfvel += keymove;
2495 }
2496
2497 if (BUTTON(gamefunc_Move_Backward))
2498 {
2499 mfvel += -keymove;
2500 }
2501 }
2502
2503 if (mfvel < -MAXVEL)
2504 mfvel = -MAXVEL;
2505 if (mfvel > MAXVEL)
2506 mfvel = MAXVEL;
2507 if (mfsvel < -MAXSVEL)
2508 mfsvel = -MAXSVEL;
2509 if (mfsvel > MAXSVEL)
2510 mfsvel = MAXSVEL;
2511
2512 momx = mulscale(mfvel, sintable[NORM_ANGLE(pp->pang + 512)], 9);
2513 momy = mulscale(mfvel, sintable[NORM_ANGLE(pp->pang)], 9);
2514
2515 momx += mulscale(mfsvel, sintable[NORM_ANGLE(pp->pang)], 9);
2516 momy += mulscale(mfsvel, sintable[NORM_ANGLE(pp->pang + 1536)], 9);
2517
2518 //mfvel = momx;
2519 //mfsvel = momy;
2520
2521 Follow_posx += momx;
2522 Follow_posy += momy;
2523
2524 Follow_posx = max(Follow_posx, x_min_bound);
2525 Follow_posy = max(Follow_posy, y_min_bound);
2526 Follow_posx = min(Follow_posx, x_max_bound);
2527 Follow_posy = min(Follow_posy, y_max_bound);
2528
2529 }
2530
2531 VOID
DoPlayerMenuKeys(PLAYERp pp)2532 DoPlayerMenuKeys(PLAYERp pp)
2533 {
2534 if (!CommEnabled)
2535 {
2536 if (TEST_SYNC_KEY((pp), SK_AUTO_AIM))
2537 {
2538 if (FLAG_KEY_PRESSED(pp, SK_AUTO_AIM))
2539 {
2540 FLAG_KEY_RELEASE(pp, SK_AUTO_AIM);
2541 FLIP(pp->Flags, PF_AUTO_AIM);
2542 }
2543 }
2544 else
2545 FLAG_KEY_RESET(pp, SK_AUTO_AIM);
2546 }
2547 }
2548
PlayerSectorBound(PLAYERp pp,int amt)2549 VOID PlayerSectorBound(PLAYERp pp, int amt)
2550 {
2551 int cz,fz;
2552
2553 // player should never go into a sector
2554
2555 // was getting some problems with this
2556 // when jumping onto hight sloped sectors
2557
2558 // call this routine to make sure he doesn't
2559 // called from DoPlayerMove() but can be called
2560 // from anywhere it is needed
2561
2562 getzsofslope(pp->cursectnum, pp->posx, pp->posy, &cz, &fz);
2563
2564 if (pp->posz > fz - amt)
2565 pp->posz = fz - amt;
2566
2567 if (pp->posz < cz + amt)
2568 pp->posz = cz + amt;
2569
2570 }
2571
2572 VOID
DoPlayerMove(PLAYERp pp)2573 DoPlayerMove(PLAYERp pp)
2574 {
2575 int i, ceilhit, florhit;
2576 short nvel,svel;
2577 int ret = 0;
2578 BOOL slow = FALSE;
2579 USERp u = User[pp->PlayerSprite];
2580 int friction;
2581 int oposz;
2582 int save_cstat;
2583 int push_ret = 0;
2584 void SlipSlope(PLAYERp pp);
2585
2586 SlipSlope(pp);
2587
2588 PLAYER_RUN_LOCK(pp);
2589
2590 DoPlayerTurn(pp);
2591
2592 pp->oldposx = pp->posx;
2593 pp->oldposy = pp->posy;
2594 pp->oldposz = pp->posz;
2595 pp->lastcursectnum = pp->cursectnum;
2596
2597 if (PLAYER_MOVING(pp) == 0)
2598 RESET(pp->Flags, PF_PLAYER_MOVED);
2599 else
2600 SET(pp->Flags, PF_PLAYER_MOVED);
2601
2602 DoPlayerSlide(pp);
2603
2604 pp->oxvect = pp->xvect;
2605 pp->oyvect = pp->yvect;
2606
2607 pp->xvect += ((pp->input.vel*synctics*2)<<6);
2608 pp->yvect += ((pp->input.svel*synctics*2)<<6);
2609
2610 friction = pp->friction;
2611 if (!TEST(pp->Flags, PF_SWIMMING) && pp->WadeDepth)
2612 {
2613 friction -= pp->WadeDepth * 100L;
2614 }
2615
2616 pp->xvect = mulscale(pp->xvect,friction,16);
2617 pp->yvect = mulscale(pp->yvect,friction,16);
2618
2619 if (TEST(pp->Flags, PF_FLYING))
2620 {
2621 // do a bit of weighted averaging
2622 pp->xvect = (pp->xvect + (pp->oxvect*1))/2;
2623 pp->yvect = (pp->yvect + (pp->oyvect*1))/2;
2624 }
2625 else
2626 if (TEST(pp->Flags, PF_DIVING))
2627 {
2628 // do a bit of weighted averaging
2629 pp->xvect = (pp->xvect + (pp->oxvect*2))/3;
2630 pp->yvect = (pp->yvect + (pp->oyvect*2))/3;
2631 }
2632
2633 if( labs(pp->xvect) < 12800 && labs(pp->yvect) < 12800 )
2634 pp->xvect = pp->yvect = 0;
2635
2636 pp->SpriteP->xvel = FindDistance2D(pp->xvect,pp->yvect)>>14;
2637
2638 if(TEST(pp->Flags, PF_CLIP_CHEAT))
2639 {
2640 short sectnum=pp->cursectnum;
2641 pp->posx += pp->xvect >> 14;
2642 pp->posy += pp->yvect >> 14;
2643 COVERupdatesector(pp->posx, pp->posy, §num);
2644 if (sectnum != -1)
2645 pp->cursectnum = sectnum;
2646 }
2647 else
2648 {
2649 push_ret = pushmove(&pp->posx, &pp->posy, &pp->posz, &pp->cursectnum, ((int)pp->SpriteP->clipdist<<2), pp->ceiling_dist, pp->floor_dist - Z(16), CLIPMASK_PLAYER);
2650
2651 if (push_ret < 0)
2652 {
2653 if (!TEST(pp->Flags, PF_DEAD))
2654 {
2655 PlayerUpdateHealth(pp, -u->Health); // Make sure he dies!
2656 PlayerCheckDeath(pp, -1);
2657
2658 if (TEST(pp->Flags, PF_DEAD))
2659 return;
2660 }
2661 }
2662
2663 save_cstat = pp->SpriteP->cstat;
2664 RESET(pp->SpriteP->cstat, CSTAT_SPRITE_BLOCK);
2665 COVERupdatesector(pp->posx, pp->posy, &pp->cursectnum);
2666 ret = clipmove(&pp->posx, &pp->posy, &pp->posz, &pp->cursectnum, pp->xvect, pp->yvect, ((int)pp->SpriteP->clipdist<<2), pp->ceiling_dist, pp->floor_dist, CLIPMASK_PLAYER);
2667 pp->SpriteP->cstat = save_cstat;
2668 PlayerCheckValidMove(pp);
2669
2670 push_ret = pushmove(&pp->posx, &pp->posy, &pp->posz, &pp->cursectnum, ((int)pp->SpriteP->clipdist<<2), pp->ceiling_dist, pp->floor_dist - Z(16), CLIPMASK_PLAYER);
2671 if (push_ret < 0)
2672 {
2673
2674 if (!TEST(pp->Flags, PF_DEAD))
2675 {
2676 PlayerUpdateHealth(pp, -u->Health); // Make sure he dies!
2677 PlayerCheckDeath(pp, -1);
2678
2679 if (TEST(pp->Flags, PF_DEAD))
2680 return;
2681 }
2682 }
2683 }
2684
2685 // check for warp - probably can remove from CeilingHit
2686 if (WarpPlane(&pp->posx, &pp->posy, &pp->posz, &pp->cursectnum))
2687 PlayerWarpUpdatePos(pp);
2688
2689 DoPlayerZrange(pp);
2690
2691 //PlayerSectorBound(pp, Z(1));
2692
2693 DoPlayerSetWadeDepth(pp);
2694
2695 DoPlayerHorizon(pp);
2696
2697 if (TEST(sector[pp->cursectnum].extra, SECTFX_DYNAMIC_AREA))
2698 {
2699 if (TEST(pp->Flags, PF_FLYING|PF_JUMPING|PF_FALLING))
2700 {
2701 if (pp->posz > pp->loz)
2702 pp->posz = pp->loz - PLAYER_HEIGHT;
2703
2704 if (pp->posz < pp->hiz)
2705 pp->posz = pp->hiz + PLAYER_HEIGHT;
2706 }
2707 else
2708 if (TEST(pp->Flags, PF_SWIMMING|PF_DIVING))
2709 {
2710 if (pp->posz > pp->loz)
2711 pp->posz = pp->loz - PLAYER_SWIM_HEIGHT;
2712
2713 if (pp->posz < pp->hiz)
2714 pp->posz = pp->hiz + PLAYER_SWIM_HEIGHT;
2715 }
2716 // moved to crawling and running respectively
2717 #if 0
2718 else
2719 if (TEST(pp->Flags, PF_CRAWLING))
2720 {
2721 pp->posz = pp->loz - PLAYER_CRAWL_HEIGHT;
2722 }
2723 else
2724 {
2725 if (pp->posz > pp->loz)
2726 pp->posz = pp->loz - PLAYER_HEIGHT;
2727
2728 if (pp->posz < pp->hiz)
2729 pp->posz = pp->hiz + PLAYER_HEIGHT;
2730 pp->posz = pp->loz - PLAYER_HEIGHT;
2731 }
2732 #endif
2733 }
2734 }
2735
2736 VOID
DoPlayerSectorUpdatePreMove(PLAYERp pp)2737 DoPlayerSectorUpdatePreMove(PLAYERp pp)
2738 {
2739 short sectnum = pp->cursectnum;
2740
2741 if (TEST(sector[pp->cursectnum].extra, SECTFX_DYNAMIC_AREA))
2742 {
2743 updatesectorz(pp->posx, pp->posy, pp->posz, §num);
2744 if (sectnum < 0)
2745 {
2746 sectnum = pp->cursectnum;
2747 COVERupdatesector(pp->posx, pp->posy, §num);
2748 }
2749 ASSERT(sectnum >= 0);
2750 }
2751 else
2752 if (FAF_ConnectArea(sectnum))
2753 {
2754 updatesectorz(pp->posx, pp->posy, pp->posz, §num);
2755 if (sectnum < 0)
2756 {
2757 sectnum = pp->cursectnum;
2758 COVERupdatesector(pp->posx, pp->posy, §num);
2759 }
2760 ASSERT(sectnum >= 0);
2761 }
2762
2763 pp->cursectnum = sectnum;
2764 }
2765
2766 VOID
DoPlayerSectorUpdatePostMove(PLAYERp pp)2767 DoPlayerSectorUpdatePostMove(PLAYERp pp)
2768 {
2769 short sectnum;
2770 int fz,cz;
2771
2772 // need to do updatesectorz if in connect area
2773 if (FAF_ConnectArea(pp->cursectnum))
2774 {
2775 sectnum = pp->cursectnum;
2776 updatesectorz(pp->posx, pp->posy, pp->posz, &pp->cursectnum);
2777
2778 // can mess up if below
2779 if (pp->cursectnum < 0)
2780 {
2781 pp->cursectnum = sectnum;
2782
2783 // adjust the posz to be in a sector
2784 getzsofslope(pp->cursectnum, pp->posx, pp->posy, &cz, &fz);
2785 if (pp->posz > fz)
2786 pp->posz = fz;
2787
2788 if (pp->posz < cz)
2789 pp->posz = cz;
2790
2791 // try again
2792 updatesectorz(pp->posx, pp->posy, pp->posz, &pp->cursectnum);
2793 ASSERT(pp->cursectnum >= 0);
2794 }
2795 }
2796 else
2797 {
2798 PlayerSectorBound(pp, Z(1));
2799 }
2800
2801 }
2802
PlaySOsound(short sectnum,short sound_num)2803 VOID PlaySOsound(short sectnum, short sound_num)
2804 {
2805 short i,nexti;
2806
2807 // play idle sound - sound 1
2808 TRAVERSE_SPRITE_SECT(headspritesect[sectnum], i, nexti)
2809 {
2810 if (sprite[i].statnum == STAT_SOUND_SPOT)
2811 {
2812 DoSoundSpotStopSound(sprite[i].lotag);
2813 DoSoundSpotMatch(sprite[i].lotag, sound_num, 0);
2814 }
2815 }
2816 }
2817
StopSOsound(short sectnum)2818 VOID StopSOsound(short sectnum)
2819 {
2820 short i,nexti;
2821
2822 // play idle sound - sound 1
2823 TRAVERSE_SPRITE_SECT(headspritesect[sectnum], i, nexti)
2824 {
2825 if (sprite[i].statnum == STAT_SOUND_SPOT)
2826 DoSoundSpotStopSound(sprite[i].lotag);
2827 }
2828 }
2829
2830 VOID
DoPlayerMoveBoat(PLAYERp pp)2831 DoPlayerMoveBoat(PLAYERp pp)
2832 {
2833 int xvect, yvect, z;
2834 int floor_dist;
2835 int ret;
2836 short save_sectnum;
2837 USERp u = User[pp->PlayerSprite];
2838 SECTOR_OBJECTp sop = pp->sop;
2839
2840 SW_PACKET last_input;
2841 int fifo_ndx;
2842
2843 if (Prediction)
2844 return;
2845
2846 if (!Prediction)
2847 {
2848 // this code looks at the fifo to get the last value for comparison
2849 fifo_ndx = (movefifoplc-2) & (MOVEFIFOSIZ - 1);
2850 last_input = pp->inputfifo[fifo_ndx];
2851
2852 if (labs(pp->input.vel|pp->input.svel) && !labs(last_input.vel|last_input.svel))
2853 PlaySOsound(pp->sop->mid_sector,SO_DRIVE_SOUND);
2854 else
2855 if (!labs(pp->input.vel|pp->input.svel) && labs(last_input.vel|last_input.svel))
2856 PlaySOsound(pp->sop->mid_sector,SO_IDLE_SOUND);
2857 }
2858
2859 PLAYER_RUN_LOCK(pp);
2860
2861 DoPlayerTurnBoat(pp);
2862
2863 if (PLAYER_MOVING(pp) == 0)
2864 RESET(pp->Flags, PF_PLAYER_MOVED);
2865 else
2866 SET(pp->Flags, PF_PLAYER_MOVED);
2867
2868 pp->oxvect = pp->xvect;
2869 pp->oyvect = pp->yvect;
2870
2871 if (sop->drive_speed)
2872 {
2873 pp->xvect = mulscale6(pp->input.vel, sop->drive_speed);
2874 pp->yvect = mulscale6(pp->input.svel, sop->drive_speed);
2875
2876 // does sliding/momentum
2877 pp->xvect = (pp->xvect + (pp->oxvect*(sop->drive_slide-1)))/sop->drive_slide;
2878 pp->yvect = (pp->yvect + (pp->oyvect*(sop->drive_slide-1)))/sop->drive_slide;
2879 }
2880 else
2881 {
2882 pp->xvect += ((pp->input.vel*synctics*2)<<6);
2883 pp->yvect += ((pp->input.svel*synctics*2)<<6);
2884
2885 pp->xvect = mulscale(pp->xvect,BOAT_FRICTION,16);
2886 pp->yvect = mulscale(pp->yvect,BOAT_FRICTION,16);
2887
2888 // does sliding/momentum
2889 pp->xvect = (pp->xvect + (pp->oxvect*5))/6;
2890 pp->yvect = (pp->yvect + (pp->oyvect*5))/6;
2891 }
2892
2893 if( labs(pp->xvect) < 12800 && labs(pp->yvect) < 12800 )
2894 pp->xvect = pp->yvect = 0;
2895
2896 pp->lastcursectnum = pp->cursectnum;
2897 z = pp->posz + Z(10);
2898
2899 save_sectnum = pp->cursectnum;
2900 OperateSectorObject(pp->sop, pp->pang, MAXSO, MAXSO);
2901 pp->cursectnum = pp->sop->op_main_sector; // for speed
2902
2903 floor_dist = labs(z - pp->sop->floor_loz);
2904 ret = clipmove(&pp->posx, &pp->posy, &z, &pp->cursectnum, pp->xvect, pp->yvect, (int)pp->sop->clipdist, Z(4), floor_dist, CLIPMASK_PLAYER);
2905
2906 OperateSectorObject(pp->sop, pp->pang, pp->posx, pp->posy);
2907 pp->cursectnum = save_sectnum; // for speed
2908
2909 DoPlayerHorizon(pp);
2910 }
2911
2912 #if 0
2913 STATE s_TankTreadMove[] =
2914 {
2915 {755, 6|SF_WALL_ANIM, NULL, s_TankTreadMove[1]},
2916 {756, 6|SF_WALL_ANIM, NULL, s_TankTreadMove[0]},
2917 };
2918
2919 STATE s_TankTreadStill[] =
2920 {
2921 {755, 6|SF_WALL_ANIM, NULL, s_TankTreadMove[0]},
2922 };
2923 #endif
2924
DoTankTreads(PLAYERp pp)2925 VOID DoTankTreads(PLAYERp pp)
2926 {
2927 SPRITEp sp;
2928 short i,nexti;
2929 int vel;
2930 SECTORp *sectp;
2931 int j;
2932 int dot;
2933 BOOL reverse = FALSE;
2934 WALLp wp;
2935 short startwall,endwall;
2936 int k;
2937
2938 if (Prediction)
2939 return;
2940
2941 vel = FindDistance2D(pp->xvect>>8, pp->yvect>>8);
2942 dot = DOT_PRODUCT_2D(pp->xvect, pp->yvect, sintable[NORM_ANGLE(pp->pang+512)], sintable[pp->pang]);
2943 if (dot < 0)
2944 reverse = TRUE;
2945
2946 for (sectp = pp->sop->sectp, j = 0; *sectp; sectp++, j++)
2947 {
2948 TRAVERSE_SPRITE_SECT(headspritesect[*sectp - sector], i, nexti)
2949 {
2950 sp = &sprite[i];
2951
2952 // BOOL1 is set only if pans with SO
2953 if (!TEST_BOOL1(sp))
2954 continue;
2955
2956 #if 0
2957 if (sp->statnum == STAT_WALL_ANIM)
2958 {
2959 if (SP_TAG3(sp) == TANK_TREAD_WALL_ANIM)
2960 {
2961 if (vel)
2962 {
2963 if (u->StateStart != s_TankTreadMove)
2964 ChangeState(i, s_TankTreadMove);
2965 }
2966 else
2967 {
2968 if (u->StateStart != s_TankTreadStill)
2969 ChangeState(i, s_TankTreadStill);
2970 }
2971 }
2972 }
2973 else
2974 #endif
2975 if (sp->statnum == STAT_WALL_PAN)
2976 {
2977 if (reverse)
2978 {
2979 if (!TEST_BOOL2(sp))
2980 {
2981 SET_BOOL2(sp);
2982 sp->ang = NORM_ANGLE(sp->ang + 1024);
2983 }
2984 }
2985 else
2986 {
2987 if (TEST_BOOL2(sp))
2988 {
2989 RESET_BOOL2(sp);
2990 sp->ang = NORM_ANGLE(sp->ang + 1024);
2991 }
2992 }
2993
2994 SP_TAG5(sp) = vel;
2995 }
2996 else
2997 if (sp->statnum == STAT_FLOOR_PAN)
2998 {
2999 sp = &sprite[i];
3000
3001 if (reverse)
3002 {
3003 if (!TEST_BOOL2(sp))
3004 {
3005 SET_BOOL2(sp);
3006 sp->ang = NORM_ANGLE(sp->ang + 1024);
3007 }
3008 }
3009 else
3010 {
3011 if (TEST_BOOL2(sp))
3012 {
3013 RESET_BOOL2(sp);
3014 sp->ang = NORM_ANGLE(sp->ang + 1024);
3015 }
3016 }
3017
3018 SP_TAG5(sp) = vel;
3019 }
3020 else
3021 if (sp->statnum == STAT_CEILING_PAN)
3022 {
3023 sp = &sprite[i];
3024
3025 if (reverse)
3026 {
3027 if (!TEST_BOOL2(sp))
3028 {
3029 SET_BOOL2(sp);
3030 sp->ang = NORM_ANGLE(sp->ang + 1024);
3031 }
3032 }
3033 else
3034 {
3035 if (TEST_BOOL2(sp))
3036 {
3037 RESET_BOOL2(sp);
3038 sp->ang = NORM_ANGLE(sp->ang + 1024);
3039 }
3040 }
3041
3042 SP_TAG5(sp) = vel;
3043 }
3044 }
3045 }
3046
3047
3048 }
3049
3050 VOID
SetupDriveCrush(PLAYERp pp,int * x,int * y)3051 SetupDriveCrush(PLAYERp pp, int *x, int *y)
3052 {
3053 int radius = pp->sop_control->clipdist;
3054
3055 x[0] = pp->posx - radius;
3056 y[0] = pp->posy - radius;
3057
3058 x[1] = pp->posx + radius;
3059 y[1] = pp->posy - radius;
3060
3061 x[2] = pp->posx + radius;
3062 y[2] = pp->posy + radius;
3063
3064 x[3] = pp->posx - radius;
3065 y[3] = pp->posy + radius;
3066 }
3067
3068 VOID
DriveCrush(PLAYERp pp,int * x,int * y)3069 DriveCrush(PLAYERp pp, int *x, int *y)
3070 {
3071 int testpointinquad(int x, int y, int *qx, int *qy);
3072
3073 SECTOR_OBJECTp sop = pp->sop_control;
3074 int radius;
3075 SPRITEp sp;
3076 USERp u;
3077 int i,nexti;
3078 short stat;
3079 int dot;
3080 SECTORp *sectp;
3081
3082 if (MoveSkip4 == 0)
3083 return;
3084
3085 // not moving - don't crush
3086 if ((pp->xvect|pp->yvect) == 0 && pp->input.angvel == 0)
3087 return;
3088
3089 radius = sop->clipdist;
3090
3091 // main sector
3092 TRAVERSE_SPRITE_SECT(headspritesect[sop->op_main_sector], i, nexti)
3093 {
3094 sp = &sprite[i];
3095 u = User[i];
3096
3097 if (testpointinquad(sp->x, sp->y, x, y))
3098 {
3099 if (TEST(sp->extra, SPRX_BREAKABLE) && HitBreakSprite(i,0))
3100 continue;
3101
3102 if (sp->statnum == STAT_MISSILE)
3103 continue;
3104
3105 if (sp->picnum == ST1)
3106 continue;
3107
3108 if (TEST(sp->extra, SPRX_PLAYER_OR_ENEMY))
3109 {
3110 if (!TEST(u->Flags, SPR_DEAD) && !TEST(sp->extra, SPRX_BREAKABLE))
3111 continue;
3112 }
3113
3114 if (TEST(sp->cstat, CSTAT_SPRITE_INVISIBLE))
3115 continue;
3116
3117 if (sp->statnum > STAT_DONT_DRAW)
3118 continue;
3119
3120 if (sp->z < sop->crush_z)
3121 continue;
3122
3123 SpriteQueueDelete(i);
3124 KillSprite(i);
3125 }
3126 }
3127
3128 // all enemys
3129 TRAVERSE_SPRITE_STAT(headspritestat[STAT_ENEMY], i, nexti)
3130 {
3131 sp = &sprite[i];
3132
3133 if (testpointinquad(sp->x, sp->y, x, y))
3134 {
3135 //if (sp->z < pp->posz)
3136 if (sp->z < sop->crush_z)
3137 continue;
3138
3139 vel = FindDistance2D(pp->xvect>>8, pp->yvect>>8);
3140 if (vel < 9000)
3141 {
3142 DoActorBeginSlide(i, getangle(pp->xvect, pp->yvect), vel/8, 5);
3143 if (DoActorSlide(i))
3144 continue;
3145 }
3146
3147 UpdateSinglePlayKills(i);
3148
3149 if (SpawnShrap(i, -99))
3150 SetSuicide(i);
3151 else
3152 KillSprite(i);
3153 }
3154 }
3155
3156 // all dead actors
3157 TRAVERSE_SPRITE_STAT(headspritestat[STAT_DEAD_ACTOR], i, nexti)
3158 {
3159 sp = &sprite[i];
3160
3161 if (testpointinquad(sp->x, sp->y, x, y))
3162 {
3163 if (sp->z < sop->crush_z)
3164 continue;
3165
3166 SpriteQueueDelete(i);
3167 KillSprite(i);
3168 }
3169 }
3170
3171 // all players
3172 for (stat = 0; stat < MAX_SW_PLAYERS; stat++)
3173 {
3174 i = headspritestat[STAT_PLAYER0 + stat];
3175
3176 if (i < 0)
3177 continue;
3178
3179 sp = &sprite[i];
3180 u = User[i];
3181
3182 if (u->PlayerP == pp)
3183 continue;
3184
3185 if (testpointinquad(sp->x, sp->y, x, y))
3186 {
3187 int damage;
3188
3189 //if (sp->z < pp->posz)
3190 if (sp->z < sop->crush_z)
3191 continue;
3192
3193 damage = -(u->Health + 100);
3194 PlayerDamageSlide(u->PlayerP, damage, pp->pang);
3195 PlayerUpdateHealth(u->PlayerP, damage);
3196 //PlayerCheckDeath(u->PlayerP, -1);
3197 PlayerCheckDeath(u->PlayerP, pp->PlayerSprite);
3198 }
3199 }
3200
3201
3202 // if it ends up actually in the drivable sector kill it
3203 for (sectp = sop->sectp; *sectp; sectp++)
3204 {
3205 TRAVERSE_SPRITE_SECT(headspritesect[(*sectp) - sector], i, nexti)
3206 {
3207 sp = &sprite[i];
3208 u = User[i];
3209
3210 // give some extra buffer
3211 if (sp->z < sop->crush_z + Z(40))
3212 continue;
3213
3214 if (TEST(sp->extra, SPRX_PLAYER_OR_ENEMY))
3215 {
3216 if (sp->statnum == STAT_ENEMY)
3217 {
3218 if (SpawnShrap(i, -99))
3219 SetSuicide(i);
3220 else
3221 KillSprite(i);
3222 }
3223 }
3224 }
3225 }
3226 }
3227
3228 VOID
DoPlayerMoveTank(PLAYERp pp)3229 DoPlayerMoveTank(PLAYERp pp)
3230 {
3231 int xvect, yvect, z;
3232 int floor_dist;
3233 int ret;
3234 short save_sectnum;
3235 SPRITEp sp = pp->sop->sp_child;
3236 USERp u = User[sp - sprite];
3237 int save_cstat;
3238 int angvel;
3239 int x[4], y[4], ox[4], oy[4];
3240 int wallcount;
3241 int count=0;
3242
3243 SECTORp *sectp;
3244 SECTOR_OBJECTp sop = pp->sop;
3245 WALLp wp;
3246 int j,k;
3247 short startwall,endwall;
3248
3249 SW_PACKET last_input;
3250 int fifo_ndx;
3251 BOOL RectClip = !!TEST(sop->flags, SOBJ_RECT_CLIP);
3252
3253 if (Prediction)
3254 return;
3255
3256 if (!Prediction)
3257 {
3258 // this code looks at the fifo to get the last value for comparison
3259 fifo_ndx = (movefifoplc-2) & (MOVEFIFOSIZ - 1);
3260 last_input = pp->inputfifo[fifo_ndx];
3261
3262 if (labs(pp->input.vel|pp->input.svel) && !labs(last_input.vel|last_input.svel))
3263 PlaySOsound(pp->sop->mid_sector,SO_DRIVE_SOUND);
3264 else
3265 if (!labs(pp->input.vel|pp->input.svel) && labs(last_input.vel|last_input.svel))
3266 PlaySOsound(pp->sop->mid_sector,SO_IDLE_SOUND);
3267 }
3268
3269 PLAYER_RUN_LOCK(pp);
3270
3271 if (PLAYER_MOVING(pp) == 0)
3272 RESET(pp->Flags, PF_PLAYER_MOVED);
3273 else
3274 SET(pp->Flags, PF_PLAYER_MOVED);
3275
3276 pp->oxvect = pp->xvect;
3277 pp->oyvect = pp->yvect;
3278
3279 if (sop->drive_speed)
3280 {
3281 pp->xvect = mulscale6(pp->input.vel, sop->drive_speed);
3282 pp->yvect = mulscale6(pp->input.svel, sop->drive_speed);
3283
3284 // does sliding/momentum
3285 pp->xvect = (pp->xvect + (pp->oxvect*(sop->drive_slide-1)))/sop->drive_slide;
3286 pp->yvect = (pp->yvect + (pp->oyvect*(sop->drive_slide-1)))/sop->drive_slide;
3287 }
3288 else
3289 {
3290 pp->xvect += ((pp->input.vel*synctics*2)<<6);
3291 pp->yvect += ((pp->input.svel*synctics*2)<<6);
3292
3293 pp->xvect = mulscale(pp->xvect,TANK_FRICTION,16);
3294 pp->yvect = mulscale(pp->yvect,TANK_FRICTION,16);
3295
3296 pp->xvect = (pp->xvect + (pp->oxvect*1))/2;
3297 pp->yvect = (pp->yvect + (pp->oyvect*1))/2;
3298 }
3299
3300 if( labs(pp->xvect) < 12800 && labs(pp->yvect) < 12800 )
3301 pp->xvect = pp->yvect = 0;
3302
3303 pp->lastcursectnum = pp->cursectnum;
3304 z = pp->posz + Z(10);
3305
3306 if (RectClip)
3307 {
3308 for (sectp = sop->sectp, wallcount = 0, j = 0; *sectp; sectp++, j++)
3309 {
3310 startwall = (*sectp)->wallptr;
3311 endwall = startwall + (*sectp)->wallnum - 1;
3312
3313 for (wp = &wall[startwall], k = startwall; k <= endwall; wp++, k++)
3314 {
3315 if (wp->extra && TEST(wp->extra, WALLFX_LOOP_OUTER|WALLFX_LOOP_OUTER_SECONDARY) == WALLFX_LOOP_OUTER)
3316 {
3317 x[count] = wp->x;
3318 y[count] = wp->y;
3319
3320 ox[count] = sop->xmid - sop->xorig[wallcount];
3321 oy[count] = sop->ymid - sop->yorig[wallcount];
3322
3323 count++;
3324 }
3325
3326 wallcount++;
3327 }
3328 }
3329
3330 PRODUCTION_ASSERT(count == 4);
3331 }
3332
3333 save_sectnum = pp->cursectnum;
3334 OperateSectorObject(pp->sop, pp->pang, MAXSO, MAXSO);
3335 pp->cursectnum = pp->sop->op_main_sector; // for speed
3336
3337 floor_dist = labs(z - pp->sop->floor_loz);
3338
3339
3340 if (RectClip)
3341 {
3342 int nx,ny;
3343 int hitx,hity,hitz;
3344 short hitsect, hitwall, hitsprite;
3345 int vel;
3346 int ret;
3347
3348 save_cstat = pp->SpriteP->cstat;
3349 RESET(pp->SpriteP->cstat, CSTAT_SPRITE_BLOCK);
3350 DoPlayerTurnTankRect(pp, x, y, ox, oy);
3351
3352 ret = RectClipMove(pp, x, y);
3353 DriveCrush(pp, x, y);
3354 pp->SpriteP->cstat = save_cstat;
3355
3356 if (!ret)
3357 {
3358 vel = FindDistance2D(pp->xvect>>8, pp->yvect>>8);
3359
3360 if (vel > 13000)
3361 {
3362 nx = DIV2(x[0] + x[1]);
3363 ny = DIV2(y[0] + y[1]);
3364
3365 hitscan( nx, ny, sector[pp->cursectnum].floorz - Z(10), pp->cursectnum,
3366 //pp->xvect, pp->yvect, 0,
3367 MOVEx(256, pp->pang), MOVEy(256, pp->pang), 0,
3368 &hitsect, &hitwall, &hitsprite, &hitx, &hity, &hitz, CLIPMASK_PLAYER);
3369
3370 ////DSPRINTF(ds,"hitsect %d, hitwall %d, hitx %d, hity %d, hitz %d",hitsect, hitwall, hitx, hity, hitz);
3371 //MONO_PRINT(ds);
3372
3373 if (FindDistance2D(hitx - nx, hity - ny) < 800)
3374 {
3375 if (hitwall >= 0)
3376 u->ret = hitwall|HIT_WALL;
3377 else
3378 if (hitsprite >= 0)
3379 u->ret = hitsprite|HIT_SPRITE;
3380 else
3381 u->ret = 0;
3382
3383 VehicleMoveHit(sp - sprite);
3384 }
3385
3386 if (!TEST(sop->flags, SOBJ_NO_QUAKE))
3387 {
3388 SetPlayerQuake(pp);
3389 }
3390 }
3391
3392 if (vel > 12000)
3393 {
3394 pp->xvect = pp->yvect = pp->oxvect = pp->oyvect = 0;
3395 }
3396 }
3397 }
3398 else
3399 {
3400 DoPlayerTurnTank(pp, z, floor_dist);
3401
3402 save_cstat = pp->SpriteP->cstat;
3403 RESET(pp->SpriteP->cstat, CSTAT_SPRITE_BLOCK);
3404 if (pp->sop->clipdist)
3405 u->ret = clipmove(&pp->posx, &pp->posy, &z, &pp->cursectnum, pp->xvect, pp->yvect, (int)pp->sop->clipdist, Z(4), floor_dist, CLIPMASK_PLAYER);
3406 else
3407 u->ret = MultiClipMove(pp, z, floor_dist);
3408 pp->SpriteP->cstat = save_cstat;
3409
3410 //SetupDriveCrush(pp, x, y);
3411 //DriveCrush(pp, x, y);
3412
3413 if (u->ret)
3414 {
3415 int vel;
3416
3417 vel = FindDistance2D(pp->xvect>>8, pp->yvect>>8);
3418
3419 if (vel > 13000)
3420 {
3421 VehicleMoveHit(sp - sprite);
3422 pp->slide_xvect = -pp->xvect<<1;
3423 pp->slide_yvect = -pp->yvect<<1;
3424 if (!TEST(sop->flags, SOBJ_NO_QUAKE))
3425 SetPlayerQuake(pp);
3426 }
3427
3428 if (vel > 12000)
3429 {
3430 pp->xvect = pp->yvect = pp->oxvect = pp->oyvect = 0;
3431 }
3432 }
3433 }
3434
3435 OperateSectorObject(pp->sop, pp->pang, pp->posx, pp->posy);
3436 pp->cursectnum = save_sectnum; // for speed
3437
3438 DoPlayerHorizon(pp);
3439
3440 DoTankTreads(pp);
3441 }
3442
3443 VOID
DoPlayerMoveTurret(PLAYERp pp)3444 DoPlayerMoveTurret(PLAYERp pp)
3445 {
3446 int xvect, yvect, z;
3447 int floor_dist;
3448 int ret;
3449 short save_sectnum;
3450 USERp u = User[pp->PlayerSprite];
3451
3452 PLAYER_RUN_LOCK(pp);
3453
3454 DoPlayerTurnTurret(pp);
3455
3456 if (PLAYER_MOVING(pp) == 0)
3457 RESET(pp->Flags, PF_PLAYER_MOVED);
3458 else
3459 SET(pp->Flags, PF_PLAYER_MOVED);
3460
3461 OperateSectorObject(pp->sop, pp->pang, pp->sop->xmid, pp->sop->ymid);
3462
3463 DoPlayerHorizon(pp);
3464 }
3465
3466 VOID
DoPlayerBeginJump(PLAYERp pp)3467 DoPlayerBeginJump(PLAYERp pp)
3468 {
3469 USERp u = User[pp->PlayerSprite];
3470
3471 SET(pp->Flags, PF_JUMPING);
3472 RESET(pp->Flags, PF_FALLING);
3473 RESET(pp->Flags, PF_CRAWLING);
3474 RESET(pp->Flags, PF_LOCK_CRAWL);
3475
3476 pp->floor_dist = PLAYER_JUMP_FLOOR_DIST;
3477 pp->ceiling_dist = PLAYER_JUMP_CEILING_DIST;
3478 pp->friction = PLAYER_JUMP_FRICTION;
3479
3480 PlayerGravity = PLAYER_JUMP_GRAV;
3481
3482 pp->jump_speed = PLAYER_JUMP_AMT + pp->WadeDepth * 4;
3483
3484 if (DoPlayerWadeSuperJump(pp))
3485 {
3486 pp->jump_speed = PLAYER_JUMP_AMT - pp->WadeDepth * 5;
3487 }
3488
3489 pp->JumpDuration = MAX_JUMP_DURATION;
3490 pp->DoPlayerAction = DoPlayerJump;
3491
3492 ///DamageData[u->WeaponNum].Init(pp);
3493
3494 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Jump);
3495 }
3496
3497 VOID
DoPlayerBeginForceJump(PLAYERp pp)3498 DoPlayerBeginForceJump(PLAYERp pp)
3499 {
3500 USERp u = User[pp->PlayerSprite];
3501
3502 SET(pp->Flags, PF_JUMPING);
3503 RESET(pp->Flags, PF_FALLING|PF_CRAWLING|PF_CLIMBING|PF_LOCK_CRAWL);
3504
3505 pp->JumpDuration = MAX_JUMP_DURATION;
3506 pp->DoPlayerAction = DoPlayerForceJump;
3507
3508 pp->floor_dist = PLAYER_JUMP_FLOOR_DIST;
3509 pp->ceiling_dist = PLAYER_JUMP_CEILING_DIST;
3510 pp->friction = PLAYER_JUMP_FRICTION;
3511
3512 PlayerGravity = PLAYER_JUMP_GRAV;
3513
3514 ///DamageData[u->WeaponNum].Init(pp);
3515
3516 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Jump);
3517 }
3518
3519 VOID
DoPlayerJump(PLAYERp pp)3520 DoPlayerJump(PLAYERp pp)
3521 {
3522 short i;
3523
3524 // reset flag key for double jumps
3525 if (!TEST_SYNC_KEY(pp, SK_JUMP))
3526 {
3527 FLAG_KEY_RESET(pp, SK_JUMP);
3528 }
3529
3530 // instead of multiplying by synctics, use a loop for greater accuracy
3531 for (i = 0; i < synctics; i++)
3532 {
3533 // PlayerGravity += synctics; // See how increase gravity as we go?
3534 if (TEST_SYNC_KEY(pp, SK_JUMP))
3535 {
3536 if (pp->JumpDuration > 0)
3537 {
3538 pp->jump_speed -= PlayerGravity;
3539 pp->JumpDuration--;
3540 }
3541 }
3542
3543 // adjust jump speed by gravity - if jump speed greater than 0 player
3544 // have started falling
3545 if ((pp->jump_speed += PlayerGravity) > 0)
3546 {
3547 DoPlayerBeginFall(pp);
3548 DoPlayerFall(pp);
3549 return;
3550 }
3551
3552 // adjust height by jump speed
3553 pp->posz += pp->jump_speed;
3554
3555 // if player gets to close the ceiling while jumping
3556 //if (pp->posz < pp->hiz + Z(4))
3557 if (PlayerCeilingHit(pp, pp->hiz + Z(4)))
3558 {
3559 // put player at the ceiling
3560 pp->posz = pp->hiz + Z(4);
3561
3562 // reverse your speed to falling
3563 pp->jump_speed = -pp->jump_speed;
3564
3565 // start falling
3566 DoPlayerBeginFall(pp);
3567 DoPlayerFall(pp);
3568 return;
3569 }
3570
3571 // added this because jumping up to slopes or jumping on steep slopes
3572 // sometimes caused the view to go into the slope
3573 // if player gets to close the floor while jumping
3574 if (PlayerFloorHit(pp, pp->loz - pp->floor_dist))
3575 {
3576 pp->posz = pp->loz - pp->floor_dist;
3577
3578 pp->jump_speed = 0;
3579 PlayerSectorBound(pp, Z(1));
3580 DoPlayerBeginRun(pp);
3581 DoPlayerHeight(pp);
3582 return;
3583 }
3584 }
3585
3586 if (PlayerFlyKey(pp))
3587 {
3588 DoPlayerBeginFly(pp);
3589 return;
3590 }
3591
3592 // If moving forward and tag is a ladder start climbing
3593 if (PlayerOnLadder(pp))
3594 {
3595 DoPlayerBeginClimb(pp);
3596 return;
3597 }
3598
3599 DoPlayerMove(pp);
3600
3601 DoPlayerJumpHeight(pp);
3602 }
3603
3604
3605 VOID
DoPlayerForceJump(PLAYERp pp)3606 DoPlayerForceJump(PLAYERp pp)
3607 {
3608 short i;
3609
3610 // instead of multiplying by synctics, use a loop for greater accuracy
3611 for (i = 0; i < synctics; i++)
3612 {
3613 // adjust jump speed by gravity - if jump speed greater than 0 player
3614 // have started falling
3615 if ((pp->jump_speed += PlayerGravity) > 0)
3616 {
3617 DoPlayerBeginFall(pp);
3618 DoPlayerFall(pp);
3619 return;
3620 }
3621
3622 // adjust height by jump speed
3623 pp->posz += pp->jump_speed;
3624
3625 // if player gets to close the ceiling while jumping
3626 //if (pp->posz < pp->hiz + Z(4))
3627 if (PlayerCeilingHit(pp, pp->hiz + Z(4)))
3628 {
3629 // put player at the ceiling
3630 pp->posz = pp->hiz + Z(4);
3631
3632 // reverse your speed to falling
3633 pp->jump_speed = -pp->jump_speed;
3634
3635 // start falling
3636 DoPlayerBeginFall(pp);
3637 DoPlayerFall(pp);
3638 return;
3639 }
3640 }
3641
3642 DoPlayerMove(pp);
3643 }
3644
3645 VOID
DoPlayerBeginFall(PLAYERp pp)3646 DoPlayerBeginFall(PLAYERp pp)
3647 {
3648 USERp u = User[pp->PlayerSprite];
3649
3650 SET(pp->Flags, PF_FALLING);
3651 RESET(pp->Flags, PF_JUMPING);
3652 RESET(pp->Flags, PF_CRAWLING);
3653 RESET(pp->Flags, PF_LOCK_CRAWL);
3654
3655 pp->floor_dist = PLAYER_FALL_FLOOR_DIST;
3656 pp->ceiling_dist = PLAYER_FALL_CEILING_DIST;
3657 pp->DoPlayerAction = DoPlayerFall;
3658 pp->friction = PLAYER_FALL_FRICTION;
3659
3660 // Only change to falling frame if you were in the jump frame
3661 // Otherwise an animation may be messed up such as Running Jump Kick
3662 if (u->Rot == u->ActorActionSet->Jump)
3663 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Fall);
3664 }
3665
StackedWaterSplash(PLAYERp pp)3666 void StackedWaterSplash(PLAYERp pp)
3667 {
3668 if (FAF_ConnectArea(pp->cursectnum))
3669 {
3670 short sectnum = pp->cursectnum;
3671
3672 updatesectorz(pp->posx, pp->posy, SPRITEp_BOS(pp->SpriteP), §num);
3673
3674 if (SectorIsUnderwaterArea(sectnum))
3675 {
3676 PlaySound(DIGI_SPLASH1, &pp->posx, &pp->posy, &pp->posz, v3df_dontpan);
3677 }
3678 }
3679 }
3680
3681 VOID
DoPlayerFall(PLAYERp pp)3682 DoPlayerFall(PLAYERp pp)
3683 {
3684 short i;
3685 int recoil_amt;
3686 int depth;
3687 static int handle=0;
3688
3689 // reset flag key for double jumps
3690 if (!TEST_SYNC_KEY(pp, SK_JUMP))
3691 {
3692 FLAG_KEY_RESET(pp, SK_JUMP);
3693 }
3694
3695 if (SectorIsUnderwaterArea(pp->cursectnum))
3696 {
3697 StackedWaterSplash(pp);
3698 DoPlayerBeginDiveNoWarp(pp);
3699 return;
3700 }
3701
3702 for (i = 0; i < synctics; i++)
3703 {
3704 // adjust jump speed by gravity
3705 pp->jump_speed += PlayerGravity;
3706 if(pp->jump_speed > 4100)
3707 pp->jump_speed = 4100;
3708
3709 // adjust player height by jump speed
3710 pp->posz += pp->jump_speed;
3711
3712 ////DSPRINTF(ds,"Fall velocity = %d",pp->jump_speed);
3713 //MONO_PRINT(ds);
3714
3715 if(pp->jump_speed > 2000)
3716 {
3717 PlayerSound(DIGI_FALLSCREAM, &pp->posx, &pp->posy, &pp->posz,
3718 v3df_dontpan|v3df_doppler|v3df_follow,pp);
3719 handle = pp->TalkVocHandle; // Save id for later
3720 }
3721 else
3722 if(pp->jump_speed > 1300)
3723 {
3724 if (TEST(pp->Flags, PF_LOCK_HORIZ))
3725 {
3726 RESET(pp->Flags, PF_LOCK_HORIZ);
3727 SET(pp->Flags, PF_LOOKING);
3728 }
3729 }
3730
3731
3732
3733 depth = GetZadjustment(pp->cursectnum, FLOOR_Z_ADJUST)>>8;
3734 if (depth == 0)
3735 depth = pp->WadeDepth;
3736
3737 if (depth > 20)
3738 recoil_amt = 0;
3739 else
3740 recoil_amt = min(pp->jump_speed*6,Z(35));
3741
3742 // need a test for head hits a sloped ceiling while falling
3743 // if player gets to close the Ceiling while Falling
3744 if (PlayerCeilingHit(pp, pp->hiz + pp->ceiling_dist))
3745 {
3746 // put player at the ceiling
3747 pp->posz = pp->hiz + pp->ceiling_dist;
3748 // don't return or anything - allow to fall until
3749 // hit floor
3750 }
3751
3752 if (PlayerFloorHit(pp, pp->loz - PLAYER_HEIGHT + recoil_amt))
3753 {
3754 SECT_USERp sectu = SectUser[pp->cursectnum];
3755 SECTORp sectp = §or[pp->cursectnum];
3756
3757 PlayerSectorBound(pp, Z(1));
3758
3759 if (sectu && (TEST(sectp->extra, SECTFX_LIQUID_MASK) != SECTFX_LIQUID_NONE))
3760 {
3761 PlaySound(DIGI_SPLASH1, &pp->posx, &pp->posy, &pp->posz, v3df_dontpan);
3762 }
3763 else
3764 {
3765 if(pp->jump_speed > 1020)
3766 // Feet hitting ground sound
3767 PlaySound(DIGI_HITGROUND, &pp->posx, &pp->posy, &pp->posz, v3df_follow|v3df_dontpan);
3768 }
3769
3770 if(handle && FX_SoundActive(handle))
3771 {
3772 // My sound code will detect the sound has stopped and clean up
3773 // for you.
3774 FX_StopSound(handle);
3775 pp->PlayerTalking = FALSE;
3776 handle = 0;
3777 }
3778
3779 // i any kind of crawl key get rid of recoil
3780 if (DoPlayerTestCrawl(pp) || TEST_SYNC_KEY(pp, SK_CRAWL))
3781 {
3782 pp->posz = pp->loz - PLAYER_CRAWL_HEIGHT;
3783 }
3784 else
3785 {
3786 // this was causing the z to snap immediately
3787 // changed it so it stays gradual
3788
3789 //pp->posz = pp->loz - PLAYER_HEIGHT + recoil_amt;
3790
3791 pp->posz += recoil_amt;
3792 DoPlayerHeight(pp);
3793 }
3794
3795 // do some damage
3796 if (pp->jump_speed > 1700 && depth == 0)
3797 {
3798
3799 PlayerSound(DIGI_PLAYERPAIN2, &pp->posx, &pp->posy, &pp->posz, v3df_follow|v3df_dontpan,pp);
3800 // PlayerUpdateHealth(pp, -RANDOM_RANGE(PLAYER_FALL_DAMAGE_AMOUNT) - 2);
3801
3802 if(pp->jump_speed > 1700 && pp->jump_speed < 4000)
3803 {
3804 if(pp->jump_speed > 0)
3805 PlayerUpdateHealth(pp, -((pp->jump_speed-1700)/40));
3806 }
3807 else
3808 if(pp->jump_speed >= 4000)
3809 {
3810 USERp u = User[pp->PlayerSprite];
3811 PlayerUpdateHealth(pp, -u->Health); // Make sure he dies!
3812 u->Health = 0;
3813 }
3814
3815 PlayerCheckDeath(pp, -1);
3816
3817 if (TEST(pp->Flags, PF_DEAD))
3818 return;
3819 }
3820
3821 if (TEST_SYNC_KEY(pp, SK_CRAWL))
3822 {
3823 StackedWaterSplash(pp);
3824 DoPlayerBeginCrawl(pp);
3825 return;
3826 }
3827
3828 if (PlayerCanDiveNoWarp(pp))
3829 {
3830 DoPlayerBeginDiveNoWarp(pp);
3831 return;
3832 }
3833
3834 StackedWaterSplash(pp);
3835 DoPlayerBeginRun(pp);
3836 return;
3837 }
3838 }
3839
3840 if (PlayerFlyKey(pp))
3841 {
3842 DoPlayerBeginFly(pp);
3843 return;
3844 }
3845
3846 // If moving forward and tag is a ladder start climbing
3847 if (PlayerOnLadder(pp))
3848 {
3849 DoPlayerBeginClimb(pp);
3850 return;
3851 }
3852
3853 DoPlayerMove(pp);
3854 }
3855
3856 VOID
DoPlayerBeginClimb(PLAYERp pp)3857 DoPlayerBeginClimb(PLAYERp pp)
3858 {
3859 USERp u = User[pp->PlayerSprite];
3860 SPRITEp sp = pp->SpriteP;
3861
3862 RESET(pp->Flags, PF_JUMPING|PF_FALLING);
3863 RESET(pp->Flags, PF_CRAWLING);
3864 RESET(pp->Flags, PF_LOCK_CRAWL);
3865
3866 pp->DoPlayerAction = DoPlayerClimb;
3867
3868 SET(pp->Flags, PF_CLIMBING|PF_WEAPON_DOWN);
3869 SET(sp->cstat, CSTAT_SPRITE_YCENTER);
3870
3871 //DamageData[u->WeaponNum].Init(pp);
3872
3873 //NewStateGroup(pp->PlayerSprite, User[pp->PlayerSprite]->ActorActionSet->Climb);
3874 NewStateGroup(pp->PlayerSprite, sg_PlayerNinjaClimb);
3875 }
3876
3877
3878 VOID
DoPlayerClimb(PLAYERp pp)3879 DoPlayerClimb(PLAYERp pp)
3880 {
3881 USERp u = User[pp->PlayerSprite];
3882 int climb_amt;
3883 char i;
3884 short oldang, delta_ang;
3885 SPRITEp sp = pp->SpriteP;
3886 int climbvel;
3887 int dot;
3888 short sec,wal,spr;
3889 int dist;
3890 short lastsectnum;
3891 BOOL LadderUpdate = FALSE;
3892
3893 if (Prediction)
3894 return;
3895
3896 pp->xvect += ((pp->input.vel*synctics*2)<<6);
3897 pp->yvect += ((pp->input.svel*synctics*2)<<6);
3898 pp->xvect = mulscale(pp->xvect,PLAYER_CLIMB_FRICTION,16);
3899 pp->yvect = mulscale(pp->yvect,PLAYER_CLIMB_FRICTION,16);
3900 if( labs(pp->xvect) < 12800 && labs(pp->yvect) < 12800 )
3901 pp->xvect = pp->yvect = 0;
3902
3903 climbvel = FindDistance2D(pp->xvect, pp->yvect)>>9;
3904 dot = DOT_PRODUCT_2D(pp->xvect, pp->yvect, sintable[NORM_ANGLE(pp->pang+512)], sintable[pp->pang]);
3905 if (dot < 0)
3906 climbvel = -climbvel;
3907
3908 // Run lock - routine doesn't call DoPlayerMove
3909 PLAYER_RUN_LOCK(pp);
3910
3911 // need to rewrite this for FAF stuff
3912
3913 // Jump off of the ladder
3914 if (TEST_SYNC_KEY(pp, SK_JUMP))
3915 {
3916 RESET(pp->Flags, PF_CLIMBING|PF_WEAPON_DOWN);
3917 RESET(sp->cstat, CSTAT_SPRITE_YCENTER);
3918 DoPlayerBeginJump(pp);
3919 return;
3920 }
3921
3922 if (climbvel != 0)
3923 {
3924 // move player to center of ladder
3925 for (i = synctics; i; i--)
3926 {
3927 #define ADJ_AMT 8
3928
3929 // player
3930 if (pp->posx != pp->lx)
3931 {
3932 if (pp->posx < pp->lx)
3933 pp->posx += ADJ_AMT;
3934 else if (pp->posx > pp->lx)
3935 pp->posx -= ADJ_AMT;
3936
3937 if (labs(pp->posx - pp->lx) <= ADJ_AMT)
3938 pp->posx = pp->lx;
3939 }
3940
3941 if (pp->posy != pp->ly)
3942 {
3943 if (pp->posy < pp->ly)
3944 pp->posy += ADJ_AMT;
3945 else if (pp->posy > pp->ly)
3946 pp->posy -= ADJ_AMT;
3947
3948 if (labs(pp->posy - pp->ly) <= ADJ_AMT)
3949 pp->posy = pp->ly;
3950 }
3951
3952 // sprite
3953 if (sp->x != u->sx)
3954 {
3955 if (sp->x < u->sx)
3956 sp->x += ADJ_AMT;
3957 else if (sp->x > u->sx)
3958 sp->x -= ADJ_AMT;
3959
3960 if (labs(sp->x - u->sx) <= ADJ_AMT)
3961 sp->x = u->sx;
3962 }
3963
3964 if (sp->y != u->sy)
3965 {
3966 if (sp->y < u->sy)
3967 sp->y += ADJ_AMT;
3968 else if (sp->y > u->sy)
3969 sp->y -= ADJ_AMT;
3970
3971 if (labs(sp->y - u->sy) <= ADJ_AMT)
3972 sp->y = u->sy;
3973 }
3974 }
3975 }
3976
3977 DoPlayerZrange(pp);
3978
3979 ASSERT(pp->LadderSector >= 0 && pp->LadderSector <= MAXSECTORS);
3980
3981 // moving UP
3982 if (climbvel > 0)
3983 {
3984 // pp->climb_ndx += climb_rate * synctics;
3985 climb_amt = (climbvel>>4) * 8;
3986
3987 pp->climb_ndx &= 1023;
3988
3989 pp->posz -= climb_amt;
3990
3991 // if player gets to close the ceiling while climbing
3992 if (PlayerCeilingHit(pp, pp->hiz))
3993 {
3994 // put player at the hiz
3995 pp->posz = pp->hiz;
3996 NewStateGroup(pp->PlayerSprite, sg_PlayerNinjaClimb);
3997 }
3998
3999 // if player gets to close the ceiling while climbing
4000 if (PlayerCeilingHit(pp, pp->hiz + Z(4)))
4001 {
4002 // put player at the ceiling
4003 pp->posz = sector[pp->LadderSector].ceilingz + Z(4);
4004 NewStateGroup(pp->PlayerSprite, sg_PlayerNinjaClimb);
4005 }
4006
4007 // if floor is ABOVE you && your head goes above it, do a jump up to
4008 // terrace
4009
4010 if (pp->posz < sector[pp->LadderSector].floorz - Z(6))
4011 {
4012 pp->jump_speed = PLAYER_CLIMB_JUMP_AMT;
4013 RESET(pp->Flags, PF_CLIMBING|PF_WEAPON_DOWN);
4014 RESET(sp->cstat, CSTAT_SPRITE_YCENTER);
4015 DoPlayerBeginForceJump(pp);
4016 }
4017 }
4018 else
4019 // move DOWN
4020 if (climbvel < 0)
4021 {
4022 // pp->climb_ndx += climb_rate * synctics;
4023 climb_amt = -(climbvel>>4) * 8;
4024
4025 pp->climb_ndx &= 1023;
4026
4027 // pp->posz += (climb_amt * sintable[pp->climb_ndx]) >> 14;
4028 pp->posz += climb_amt;
4029
4030 // if you are touching the floor
4031 //if (pp->posz >= pp->loz - Z(4) - PLAYER_HEIGHT)
4032 if (PlayerFloorHit(pp, pp->loz - Z(4) - PLAYER_HEIGHT))
4033 {
4034 // stand on floor
4035 pp->posz = pp->loz - Z(4) - PLAYER_HEIGHT;
4036
4037 // if moving backwards start running
4038 if (climbvel < 0)
4039 {
4040 RESET(pp->Flags, PF_CLIMBING|PF_WEAPON_DOWN);
4041 RESET(sp->cstat, CSTAT_SPRITE_YCENTER);
4042 DoPlayerBeginRun(pp);
4043 return;
4044 }
4045 }
4046 }
4047 else
4048 {
4049 NewStateGroup(pp->PlayerSprite, sg_PlayerNinjaClimb);
4050 }
4051
4052 // setsprite to players location
4053 sp->z = pp->posz + PLAYER_HEIGHT;
4054 changespritesect(pp->PlayerSprite, pp->cursectnum);
4055
4056 DoPlayerHorizon(pp);
4057
4058 if (FAF_ConnectArea(pp->cursectnum))
4059 {
4060 updatesectorz(pp->posx, pp->posy, pp->posz, &pp->cursectnum);
4061 LadderUpdate = TRUE;
4062 }
4063
4064 if (WarpPlane(&pp->posx, &pp->posy, &pp->posz, &pp->cursectnum))
4065 {
4066 PlayerWarpUpdatePos(pp);
4067 LadderUpdate = TRUE;
4068 }
4069
4070 if (LadderUpdate)
4071 {
4072 SPRITEp lsp;
4073 int nx,ny;
4074
4075 // constantly look for new ladder sector because of warping at any time
4076 neartag(pp->posx, pp->posy, pp->posz,
4077 pp->cursectnum, pp->pang,
4078 &sec, &wal, &spr,
4079 &dist, 800L, NTAG_SEARCH_LO_HI);
4080
4081 if (wal >= 0)
4082 {
4083 pp->LadderSector = wall[wal].nextsector;
4084
4085 lsp = FindNearSprite(pp->SpriteP, STAT_CLIMB_MARKER);
4086
4087 // determine where the player is supposed to be in relation to the ladder
4088 // move out in front of the ladder
4089 nx = MOVEx(100, lsp->ang);
4090 ny = MOVEy(100, lsp->ang);
4091
4092 // set angle player is supposed to face.
4093 pp->LadderAngle = NORM_ANGLE(lsp->ang + 1024);
4094 pp->LadderSector = wall[wal].nextsector;
4095
4096 // set players "view" distance from the ladder - needs to be farther than
4097 // the sprite
4098
4099 pp->lx = lsp->x + nx * 5;
4100 pp->ly = lsp->y + ny * 5;
4101
4102 pp->pang = pp->LadderAngle;
4103 }
4104 }
4105 }
4106
4107
4108 int
DoPlayerWadeSuperJump(PLAYERp pp)4109 DoPlayerWadeSuperJump(PLAYERp pp)
4110 {
4111 int hitx, hity, hitz;
4112 short hitsect, hitwall, hitsprite;
4113 USERp u = User[pp->PlayerSprite];
4114 unsigned i;
4115 //short angs[3];
4116 static short angs[3] = {0, 0, 0};
4117 int zh = sector[pp->cursectnum].floorz - Z(pp->WadeDepth) - Z(2);
4118
4119 if (Prediction) return(FALSE); // !JIM! 8/5/97 Teleporter FAFhitscan SuperJump bug.
4120
4121 for (i = 0; i < SIZ(angs); i++)
4122 {
4123 FAFhitscan(pp->posx, pp->posy, zh, pp->cursectnum, // Start position
4124 sintable[NORM_ANGLE(pp->pang + angs[i] + 512)], // X vector of 3D ang
4125 sintable[NORM_ANGLE(pp->pang + angs[i])], // Y vector of 3D ang
4126 0, // Z vector of 3D ang
4127 &hitsect, &hitwall, &hitsprite, &hitx, &hity, &hitz, CLIPMASK_MISSILE);
4128
4129 if (hitwall >= 0 && hitsect >= 0)
4130 {
4131 hitsect = wall[hitwall].nextsector;
4132
4133 if (labs(sector[hitsect].floorz - pp->posz) < Z(50))
4134 {
4135 if (Distance(pp->posx, pp->posy, hitx, hity) < ((((int)pp->SpriteP->clipdist)<<2) + 256))
4136 return (TRUE);
4137 }
4138 }
4139 }
4140
4141 return (FALSE);
4142 }
4143
PlayerFlyKey(PLAYERp UNUSED (pp))4144 BOOL PlayerFlyKey(PLAYERp UNUSED(pp))
4145 {
4146 BOOL key;
4147
4148 if (!GodMode)
4149 return(FALSE);
4150
4151 if (InputMode)
4152 return(FALSE);
4153
4154 key = KEY_PRESSED(KEYSC_J);
4155
4156 if (key)
4157 KEY_PRESSED(KEYSC_J) = 0;
4158
4159 return(key);
4160 }
4161
4162 #if 0
4163 VOID
4164 DoPlayerBeginSwim(PLAYERp pp)
4165 {
4166 USERp u = User[pp->PlayerSprite];
4167 SPRITEp sp = &sprite[pp->PlayerSprite];
4168
4169 RESET(pp->Flags, PF_FALLING | PF_JUMPING);
4170 SET(pp->Flags, PF_SWIMMING);
4171
4172 // reset because of bobbing when wading
4173 pp->SpriteP->z = pp->posz + PLAYER_SWIM_HEIGHT;
4174
4175 pp->friction = PLAYER_SWIM_FRICTION;
4176 pp->floor_dist = PLAYER_SWIM_FLOOR_DIST;
4177 pp->ceiling_dist = PLAYER_SWIM_CEILING_DIST;
4178 pp->DoPlayerAction = DoPlayerSwim;
4179
4180 //DamageData[u->WeaponNum].Init(pp);
4181
4182 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Swim);
4183
4184 SET(sp->cstat, CSTAT_SPRITE_YCENTER);
4185 }
4186
4187
4188 VOID
4189 DoPlayerSwim(PLAYERp pp)
4190 {
4191 USERp u = User[pp->PlayerSprite];
4192 SPRITEp sp = &sprite[pp->PlayerSprite];
4193
4194 // Jump to get up
4195 if (TEST_SYNC_KEY(pp, SK_JUMP))
4196 {
4197 if (FLAG_KEY_PRESSED(pp, SK_JUMP))
4198 {
4199 FLAG_KEY_RELEASE(pp, SK_JUMP);
4200 RESET(sp->cstat, CSTAT_SPRITE_YCENTER);
4201 RESET(pp->Flags, PF_SWIMMING);
4202 DoPlayerBeginJump(pp);
4203 // return;
4204 }
4205 }
4206 else
4207 {
4208 FLAG_KEY_RESET(pp, SK_JUMP);
4209 }
4210
4211 // If too shallow to swim or stopped the "RUN" key
4212 if (pp->WadeDepth < MIN_SWIM_DEPTH || !(TEST_SYNC_KEY(pp, SK_RUN) || TEST(pp->Flags, PF_LOCK_RUN)))
4213 {
4214 RESET(sp->cstat, CSTAT_SPRITE_YCENTER);
4215 RESET(pp->Flags, PF_SWIMMING);
4216 DoPlayerBeginRun(pp);
4217 // smooth the transition by updating the sprite now
4218 //UpdatePlayerSprite(pp);
4219 return;
4220 }
4221
4222 // Move around
4223 DoPlayerMove(pp);
4224
4225 if (PlayerCanDive(pp))
4226 return;
4227
4228 if (!TEST(pp->Flags, PF_PLAYER_MOVED))
4229 {
4230 RESET(sp->cstat, CSTAT_SPRITE_YCENTER);
4231 RESET(pp->Flags, PF_SWIMMING);
4232 DoPlayerBeginWade(pp);
4233 DoPlayerWade(pp);
4234 return;
4235 }
4236 }
4237 #endif
4238
4239 VOID
DoPlayerBeginCrawl(PLAYERp pp)4240 DoPlayerBeginCrawl(PLAYERp pp)
4241 {
4242 USERp u = User[pp->PlayerSprite];
4243
4244 RESET(pp->Flags, PF_FALLING | PF_JUMPING);
4245 SET(pp->Flags, PF_CRAWLING);
4246
4247 pp->friction = PLAYER_CRAWL_FRICTION;
4248 pp->floor_dist = PLAYER_CRAWL_FLOOR_DIST;
4249 pp->ceiling_dist = PLAYER_CRAWL_CEILING_DIST;
4250 pp->DoPlayerAction = DoPlayerCrawl;
4251
4252 //pp->posz = pp->loz - PLAYER_CRAWL_HEIGHT;
4253
4254 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Crawl);
4255 }
4256
PlayerFallTest(PLAYERp pp,int player_height)4257 BOOL PlayerFallTest(PLAYERp pp, int player_height)
4258 {
4259 // If the floor is far below you, fall hard instead of adjusting height
4260 if (labs(pp->posz - pp->loz) > player_height + PLAYER_FALL_HEIGHT)
4261 {
4262 // if on a STEEP slope sector and you have not moved off of the sector
4263 if (pp->lo_sectp &&
4264 labs(pp->lo_sectp->floorheinum) > 3000 &&
4265 TEST(pp->lo_sectp->floorstat, FLOOR_STAT_SLOPE) &&
4266 pp->lo_sectp == §or[pp->lastcursectnum])
4267 {
4268 return(FALSE);
4269 }
4270 else
4271 {
4272 return(TRUE);
4273 }
4274 }
4275
4276 return(FALSE);
4277 }
4278
4279 VOID
DoPlayerCrawl(PLAYERp pp)4280 DoPlayerCrawl(PLAYERp pp)
4281 {
4282 USERp u = User[pp->PlayerSprite];
4283
4284 if (SectorIsUnderwaterArea(pp->cursectnum))
4285 {
4286 // if stacked water - which it should be
4287 if (FAF_ConnectArea(pp->cursectnum))
4288 {
4289 // adjust the z
4290 pp->posz = sector[pp->cursectnum].ceilingz + Z(12);
4291 }
4292
4293 DoPlayerBeginDiveNoWarp(pp);
4294 return;
4295 }
4296
4297 // Current Z position, adjust down to the floor, adjust to player height,
4298 // adjust for "bump head"
4299 //#define PLAYER_STANDING_ROOM(pp) ((pp)->posz + PLAYER_CRAWL_HEIGHT - PLAYER_HEIGHT - PLAYER_RUN_CEILING_DIST)
4300 #define PLAYER_STANDING_ROOM Z(68)
4301
4302 if (TEST(pp->Flags, PF_LOCK_CRAWL))
4303 {
4304 if (TEST_SYNC_KEY(pp, SK_CRAWL_LOCK))
4305 {
4306 if (FLAG_KEY_PRESSED(pp, SK_CRAWL_LOCK))
4307 {
4308 //if (pp->hiz < PLAYER_STANDING_ROOM(pp))
4309 if (labs(pp->loz - pp->hiz) >= PLAYER_STANDING_ROOM)
4310 {
4311 FLAG_KEY_RELEASE(pp, SK_CRAWL_LOCK);
4312
4313 RESET(pp->Flags, PF_CRAWLING);
4314 DoPlayerBeginRun(pp);
4315 return;
4316 }
4317 }
4318 }
4319 else
4320 {
4321 FLAG_KEY_RESET(pp, SK_CRAWL_LOCK);
4322 }
4323
4324 // Jump to get up
4325 if (TEST_SYNC_KEY(pp, SK_JUMP))
4326 {
4327 if (labs(pp->loz - pp->hiz) >= PLAYER_STANDING_ROOM)
4328 {
4329 //pp->posz = pp->loz - PLAYER_HEIGHT;
4330
4331 RESET(pp->Flags, PF_CRAWLING);
4332 DoPlayerBeginRun(pp);
4333 return;
4334 }
4335 }
4336
4337 }
4338 else
4339 {
4340 // Let off of crawl to get up
4341 if (!TEST_SYNC_KEY(pp, SK_CRAWL))
4342 {
4343 if (labs(pp->loz - pp->hiz) >= PLAYER_STANDING_ROOM)
4344 {
4345 RESET(pp->Flags, PF_CRAWLING);
4346 DoPlayerBeginRun(pp);
4347 return;
4348 }
4349 }
4350 }
4351
4352 if (pp->lo_sectp && TEST(pp->lo_sectp->extra, SECTFX_CURRENT))
4353 {
4354 DoPlayerCurrent(pp);
4355 }
4356
4357 // Move around
4358 DoPlayerMove(pp);
4359
4360 if (pp->WadeDepth > PLAYER_CRAWL_WADE_DEPTH)
4361 {
4362 RESET(pp->Flags, PF_CRAWLING);
4363 DoPlayerBeginRun(pp);
4364 return;
4365 }
4366
4367 if (!TEST(pp->Flags, PF_PLAYER_MOVED))
4368 {
4369 extern STATEp sg_NinjaCrawl[];
4370
4371 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Crawl);
4372 }
4373
4374 // If the floor is far below you, fall hard instead of adjusting height
4375 //if (labs(pp->posz - pp->loz) > PLAYER_CRAWL_HEIGHT + PLAYER_FALL_HEIGHT)
4376 if (PlayerFallTest(pp, PLAYER_CRAWL_HEIGHT))
4377 {
4378 pp->jump_speed = Z(1);
4379 //pp->posz -= PLAYER_HEIGHT - PLAYER_CRAWL_HEIGHT;
4380 RESET(pp->Flags, PF_CRAWLING);
4381 DoPlayerBeginFall(pp);
4382 // call PlayerFall now seems to iron out a hitch before falling
4383 DoPlayerFall(pp);
4384 return;
4385 }
4386
4387 if (TEST(sector[pp->cursectnum].extra, SECTFX_DYNAMIC_AREA))
4388 {
4389 pp->posz = pp->loz - PLAYER_CRAWL_HEIGHT;
4390 }
4391
4392 DoPlayerBob(pp);
4393 DoPlayerCrawlHeight(pp);
4394 }
4395
4396 VOID
DoPlayerBeginFly(PLAYERp pp)4397 DoPlayerBeginFly(PLAYERp pp)
4398 {
4399 USERp u = User[pp->PlayerSprite];
4400 extern STATEp sg_NinjaFly[];
4401
4402 RESET(pp->Flags, PF_FALLING | PF_JUMPING | PF_CRAWLING);
4403 SET(pp->Flags, PF_FLYING);
4404
4405 pp->friction = PLAYER_FLY_FRICTION;
4406 pp->floor_dist = PLAYER_RUN_FLOOR_DIST;
4407 pp->ceiling_dist = PLAYER_RUN_CEILING_DIST;
4408 pp->DoPlayerAction = DoPlayerFly;
4409
4410 pp->z_speed = -Z(10);
4411 pp->jump_speed = 0;
4412 pp->bob_amt = 0;
4413 pp->bob_ndx = 1024;
4414
4415 ///DamageData[u->WeaponNum].Init(pp);
4416
4417 NewStateGroup(pp->PlayerSprite, sg_PlayerNinjaFly);
4418 }
4419
GetSinNdx(int range,int bob_amt)4420 int GetSinNdx(int range, int bob_amt)
4421 {
4422 int amt;
4423
4424 amt = Z(512) / range;
4425
4426 return (bob_amt * amt);
4427 }
4428
PlayerWarpUpdatePos(PLAYERp pp)4429 VOID PlayerWarpUpdatePos(PLAYERp pp)
4430 {
4431 SPRITEp sp = pp->SpriteP;
4432 USERp u = User[pp->PlayerSprite];
4433
4434 if (Prediction)
4435 return;
4436
4437 pp->oposx = pp->posx;
4438 pp->oposy = pp->posy;
4439 pp->oposz = pp->posz;
4440 DoPlayerZrange(pp);
4441 UpdatePlayerSprite(pp);
4442 }
4443
PlayerCeilingHit(PLAYERp pp,int zlimit)4444 BOOL PlayerCeilingHit(PLAYERp pp, int zlimit)
4445 {
4446 if (pp->posz < zlimit)
4447 {
4448 return(TRUE);
4449 }
4450
4451 return(FALSE);
4452 }
4453
PlayerFloorHit(PLAYERp pp,int zlimit)4454 BOOL PlayerFloorHit(PLAYERp pp, int zlimit)
4455 {
4456 if (pp->posz > zlimit)
4457 {
4458 return(TRUE);
4459 }
4460
4461 return(FALSE);
4462 }
4463
4464 VOID
DoPlayerFly(PLAYERp pp)4465 DoPlayerFly(PLAYERp pp)
4466 {
4467 USERp u = User[pp->PlayerSprite];
4468
4469 if (SectorIsUnderwaterArea(pp->cursectnum))
4470 {
4471 DoPlayerBeginDiveNoWarp(pp);
4472 return;
4473 }
4474
4475 if (TEST_SYNC_KEY(pp, SK_CRAWL))
4476 {
4477 pp->z_speed += PLAYER_FLY_INC;
4478
4479 if (pp->z_speed > PLAYER_FLY_MAX_SPEED)
4480 pp->z_speed = PLAYER_FLY_MAX_SPEED;
4481 }
4482
4483 if (TEST_SYNC_KEY(pp, SK_JUMP))
4484 {
4485 pp->z_speed -= PLAYER_FLY_INC;
4486
4487 if (pp->z_speed < -PLAYER_FLY_MAX_SPEED)
4488 pp->z_speed = -PLAYER_FLY_MAX_SPEED;
4489 }
4490
4491 pp->z_speed = mulscale16(pp->z_speed, 58000);
4492
4493 pp->posz += pp->z_speed;
4494
4495 // Make the min distance from the ceiling/floor match bobbing amount
4496 // so the player never goes into the ceiling/floor
4497
4498 // Only get so close to the ceiling
4499 if (PlayerCeilingHit(pp, pp->hiz + PLAYER_FLY_BOB_AMT + Z(8)))
4500 {
4501 pp->posz = pp->hiz + PLAYER_FLY_BOB_AMT + Z(8);
4502 pp->z_speed = 0;
4503 }
4504
4505 // Only get so close to the floor
4506 if (PlayerFloorHit(pp, pp->loz - PLAYER_HEIGHT - PLAYER_FLY_BOB_AMT))
4507 {
4508 pp->posz = pp->loz - PLAYER_HEIGHT - PLAYER_FLY_BOB_AMT;
4509 pp->z_speed = 0;
4510 }
4511
4512 if (PlayerFlyKey(pp))
4513 {
4514 RESET(pp->Flags, PF_FLYING);
4515 pp->bob_amt = 0;
4516 pp->bob_ndx = 0;
4517 DoPlayerBeginFall(pp);
4518 DoPlayerFall(pp);
4519 return;
4520 }
4521
4522 DoPlayerMove(pp);
4523 }
4524
4525
4526 SPRITEp
FindNearSprite(SPRITEp sp,short stat)4527 FindNearSprite(SPRITEp sp, short stat)
4528 {
4529 short fs, next_fs;
4530 int dist, near_dist = 15000;
4531 SPRITEp fp, near_fp = NULL;
4532
4533
4534 TRAVERSE_SPRITE_STAT(headspritestat[stat], fs, next_fs)
4535 {
4536 fp = &sprite[fs];
4537
4538 dist = Distance(sp->x, sp->y, fp->x, fp->y);
4539
4540 if (dist < near_dist)
4541 {
4542 near_dist = dist;
4543 near_fp = fp;
4544 }
4545 }
4546
4547 return (near_fp);
4548 }
4549
4550 BOOL
PlayerOnLadder(PLAYERp pp)4551 PlayerOnLadder(PLAYERp pp)
4552 {
4553 short sec, wal, spr;
4554 int dist, nx, ny;
4555 unsigned i;
4556 USERp u = User[pp->PlayerSprite];
4557 SPRITEp lsp;
4558 int hitx,hity,hitz;
4559 short hitsprite,hitsect,hitwall;
4560 int dir;
4561
4562 int neartaghitdist;
4563 short neartagsector, neartagwall, neartagsprite;
4564
4565 static short angles[] =
4566 {
4567 30, -30
4568 };
4569
4570 if (Prediction)
4571 return(0);
4572
4573 neartag(pp->posx, pp->posy, pp->posz, pp->cursectnum, pp->pang,
4574 &neartagsector, &neartagwall, &neartagsprite,
4575 &neartaghitdist, 1024L+768L, NTAG_SEARCH_LO_HI);
4576
4577 dir = DOT_PRODUCT_2D(pp->xvect, pp->yvect, sintable[NORM_ANGLE(pp->pang+512)], sintable[pp->pang]);
4578
4579 if (dir < 0)
4580 return(FALSE);
4581
4582 if (neartagwall < 0 || wall[neartagwall].lotag != TAG_WALL_CLIMB)
4583 return (FALSE);
4584
4585 for (i = 0; i < SIZ(angles); i++)
4586 {
4587 neartag(pp->posx, pp->posy, pp->posz, pp->cursectnum, NORM_ANGLE(pp->pang + angles[i]),
4588 &sec, &wal, &spr,
4589 &dist, 600L, NTAG_SEARCH_LO_HI);
4590
4591 if (wal < 0 || dist < 100 || wall[wal].lotag != TAG_WALL_CLIMB)
4592 return (FALSE);
4593
4594 FAFhitscan(pp->posx, pp->posy, pp->posz, pp->cursectnum,
4595 sintable[NORM_ANGLE(pp->pang + angles[i] + 512)],
4596 sintable[NORM_ANGLE(pp->pang + angles[i])],
4597 0,
4598 &hitsect, &hitwall, &hitsprite, &hitx, &hity, &hitz, CLIPMASK_MISSILE);
4599
4600 dist = DIST(pp->posx, pp->posy, hitx, hity);
4601
4602 if (hitsprite >= 0)
4603 {
4604 // if the sprite blocking you hit is not a wall sprite there is something between
4605 // you and the ladder
4606 if (TEST(sprite[hitsprite].cstat, CSTAT_SPRITE_BLOCK) &&
4607 !TEST(sprite[hitsprite].cstat, CSTAT_SPRITE_WALL))
4608 {
4609 return(FALSE);
4610 }
4611 }
4612 else
4613 {
4614 // if you hit a wall and it is not a climb wall - forget it
4615 if (hitwall >= 0 && wall[hitwall].lotag != TAG_WALL_CLIMB)
4616 return(FALSE);
4617 }
4618 }
4619
4620
4621 lsp = FindNearSprite(pp->SpriteP, STAT_CLIMB_MARKER);
4622
4623 if (!lsp)
4624 return (FALSE);
4625
4626 // determine where the player is supposed to be in relation to the ladder
4627 // move out in front of the ladder
4628 nx = MOVEx(100, lsp->ang);
4629 ny = MOVEy(100, lsp->ang);
4630
4631 // set angle player is supposed to face.
4632 pp->LadderAngle = NORM_ANGLE(lsp->ang + 1024);
4633
4634 #if DEBUG
4635 if (wall[wal].nextsector < 0)
4636 {
4637 TerminateGame();
4638 printf("Take out white wall ladder x = %d, y = %d",wall[wal].x, wall[wal].y);
4639 exit(0);
4640 }
4641 #endif
4642
4643 pp->LadderSector = wall[wal].nextsector;
4644 //DSPRINTF(ds, "Ladder Sector %d", pp->LadderSector);
4645 MONO_PRINT(ds);
4646
4647 // set players "view" distance from the ladder - needs to be farther than
4648 // the sprite
4649
4650 pp->lx = lsp->x + nx * 5;
4651 pp->ly = lsp->y + ny * 5;
4652
4653 pp->pang = pp->LadderAngle;
4654
4655 return (TRUE);
4656 }
4657
DoPlayerTestCrawl(PLAYERp pp)4658 BOOL DoPlayerTestCrawl(PLAYERp pp)
4659 {
4660 if (labs(pp->loz - pp->hiz) < PLAYER_STANDING_ROOM)
4661 return(TRUE);
4662
4663 return(FALSE);
4664 }
4665
4666 int
PlayerInDiveArea(PLAYERp pp)4667 PlayerInDiveArea(PLAYERp pp)
4668 {
4669 SECTORp sectp;
4670 BOOL InMasked=FALSE;
4671
4672 if (pp->lo_sectp)
4673 {
4674 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
4675 //Attention: This changed on 07/29/97
4676 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
4677 sectp = §or[pp->cursectnum];
4678 //sectp = pp->lo_sectp;
4679 }
4680 else
4681 return (FALSE);
4682
4683 if (TEST(sectp->extra, SECTFX_DIVE_AREA))
4684 {
4685 CheckFootPrints(pp);
4686 return (TRUE);
4687 }
4688
4689 return (FALSE);
4690 }
4691
4692 int
PlayerCanDive(PLAYERp pp)4693 PlayerCanDive(PLAYERp pp)
4694 {
4695 if (Prediction)
4696 return(FALSE);
4697
4698 // Crawl - check for diving
4699 if (TEST_SYNC_KEY(pp, SK_CRAWL) || pp->jump_speed > 0)
4700 {
4701 if (PlayerInDiveArea(pp))
4702 {
4703 pp->posz += Z(20);
4704 pp->z_speed = Z(20);
4705 pp->jump_speed = 0;
4706
4707 if (pp->posz > pp->loz - Z(pp->WadeDepth) - Z(2))
4708 {
4709 DoPlayerBeginDive(pp);
4710 }
4711
4712 return (TRUE);
4713 }
4714 }
4715
4716 return (FALSE);
4717 }
4718
4719 int
PlayerCanDiveNoWarp(PLAYERp pp)4720 PlayerCanDiveNoWarp(PLAYERp pp)
4721 {
4722 if (Prediction)
4723 return(FALSE);
4724
4725 // check for diving
4726 if (pp->jump_speed > 1400)
4727 {
4728 if (FAF_ConnectArea(pp->cursectnum))
4729 {
4730 short sectnum = pp->cursectnum;
4731
4732 updatesectorz(pp->posx, pp->posy, SPRITEp_BOS(pp->SpriteP), §num);
4733
4734 if (SectorIsUnderwaterArea(sectnum))
4735 {
4736 pp->cursectnum = sectnum;
4737 pp->posz = sector[sectnum].ceilingz;
4738
4739 pp->posz += Z(20);
4740 pp->z_speed = Z(20);
4741 pp->jump_speed = 0;
4742
4743 PlaySound(DIGI_SPLASH1, &pp->posx, &pp->posy, &pp->posz, v3df_dontpan);
4744 DoPlayerBeginDiveNoWarp(pp);
4745 return (TRUE);
4746 }
4747 }
4748 }
4749
4750 return (FALSE);
4751 }
4752
4753
4754 int
GetOverlapSector(int x,int y,short * over,short * under)4755 GetOverlapSector(int x, int y, short *over, short *under)
4756 {
4757 int i, found = 0;
4758 short sf[2]={0,0}; // sectors found
4759
4760 if ((SectUser[*under] && SectUser[*under]->number >= 30000) || (SectUser[*over] && SectUser[*over]->number >= 30000))
4761 return(GetOverlapSector2(x,y,over,under));
4762
4763 // instead of check ALL sectors, just check the two most likely first
4764 if (inside(x, y, *over))
4765 {
4766 sf[found] = *over;
4767 found++;
4768 }
4769
4770 if (inside(x, y, *under))
4771 {
4772 sf[found] = *under;
4773 found++;
4774 }
4775
4776 // if nothing was found, check them all
4777 if (found == 0)
4778 {
4779 for (found = 0, i = 0; i < numsectors; i++)
4780 {
4781 if (inside(x, y, i))
4782 {
4783 sf[found] = i;
4784 found++;
4785 PRODUCTION_ASSERT(found <= 2);
4786 }
4787 }
4788 }
4789
4790 if (!found)
4791 {
4792 TerminateGame();
4793 printf("GetOverlapSector x = %d, y = %d, over %d, under %d", x, y, *over, *under);
4794 exit(0);
4795 }
4796
4797 PRODUCTION_ASSERT(found != 0);
4798 PRODUCTION_ASSERT(found <= 2);
4799
4800 // the are overlaping - check the z coord
4801 if (found == 2)
4802 {
4803 if (sector[sf[0]].floorz > sector[sf[1]].floorz)
4804 {
4805 *under = sf[0];
4806 *over = sf[1];
4807 }
4808 else
4809 {
4810 *under = sf[1];
4811 *over = sf[0];
4812 }
4813 }
4814 else
4815 // the are NOT overlaping
4816 {
4817 *over = sf[0];
4818 *under = -1;
4819 }
4820
4821 return (found);
4822 }
4823
4824 int
GetOverlapSector2(int x,int y,short * over,short * under)4825 GetOverlapSector2(int x, int y, short *over, short *under)
4826 {
4827 int i, nexti, found = 0;
4828 short sf[2]={0,0}; // sectors found
4829
4830 unsigned stat;
4831 static short UnderStatList[] = {STAT_UNDERWATER, STAT_UNDERWATER2};
4832
4833 // NOTE: For certain heavily overlapped areas in $seabase this is a better
4834 // method.
4835
4836 // instead of check ALL sectors, just check the two most likely first
4837 if (inside(x, y, *over))
4838 {
4839 sf[found] = *over;
4840 found++;
4841 }
4842
4843 if (inside(x, y, *under))
4844 {
4845 sf[found] = *under;
4846 found++;
4847 }
4848
4849 // if nothing was found, check them all
4850 if (found == 0)
4851 {
4852 TRAVERSE_SPRITE_STAT(headspritestat[STAT_DIVE_AREA],i,nexti)
4853 {
4854 if (inside(x, y, sprite[i].sectnum))
4855 {
4856 sf[found] = sprite[i].sectnum;
4857 found++;
4858 PRODUCTION_ASSERT(found <= 2);
4859 }
4860 }
4861
4862 for (stat = 0; stat < SIZ(UnderStatList); stat++)
4863 {
4864 TRAVERSE_SPRITE_STAT(headspritestat[UnderStatList[stat]],i,nexti)
4865 {
4866 // ignore underwater areas with lotag of 0
4867 if (sprite[i].lotag == 0)
4868 continue;
4869
4870 if (inside(x, y, sprite[i].sectnum))
4871 {
4872 sf[found] = sprite[i].sectnum;
4873 found++;
4874 PRODUCTION_ASSERT(found <= 2);
4875 }
4876 }
4877 }
4878 }
4879
4880 if (!found)
4881 {
4882 TerminateGame();
4883 printf("GetOverlapSector x = %d, y = %d, over %d, under %d", x, y, *over, *under);
4884 exit(0);
4885 }
4886
4887 PRODUCTION_ASSERT(found != 0);
4888 PRODUCTION_ASSERT(found <= 2);
4889
4890 // the are overlaping - check the z coord
4891 if (found == 2)
4892 {
4893 if (sector[sf[0]].floorz > sector[sf[1]].floorz)
4894 {
4895 *under = sf[0];
4896 *over = sf[1];
4897 }
4898 else
4899 {
4900 *under = sf[1];
4901 *over = sf[0];
4902 }
4903 }
4904 else
4905 // the are NOT overlaping
4906 {
4907 *over = sf[0];
4908 *under = -1;
4909 }
4910
4911 return (found);
4912 }
4913
4914
4915 VOID
DoPlayerWarpToUnderwater(PLAYERp pp)4916 DoPlayerWarpToUnderwater(PLAYERp pp)
4917 {
4918 USERp u = User[pp->PlayerSprite];
4919 SPRITEp sp = &sprite[pp->PlayerSprite];
4920 short i, nexti;
4921 SECT_USERp sectu = SectUser[pp->cursectnum];
4922 SPRITEp under_sp = NULL, over_sp = NULL;
4923 char Found = FALSE;
4924 short over, under;
4925
4926 if (Prediction)
4927 return;
4928
4929
4930 // search for DIVE_AREA "over" sprite for reference point
4931 TRAVERSE_SPRITE_STAT(headspritestat[STAT_DIVE_AREA], i, nexti)
4932 {
4933 over_sp = &sprite[i];
4934
4935 if (TEST(sector[over_sp->sectnum].extra, SECTFX_DIVE_AREA) &&
4936 SectUser[over_sp->sectnum] &&
4937 SectUser[over_sp->sectnum]->number == sectu->number)
4938 {
4939 Found = TRUE;
4940 break;
4941 }
4942 }
4943
4944 PRODUCTION_ASSERT(Found == TRUE);
4945 Found = FALSE;
4946
4947 // search for UNDERWATER "under" sprite for reference point
4948 TRAVERSE_SPRITE_STAT(headspritestat[STAT_UNDERWATER], i, nexti)
4949 {
4950 under_sp = &sprite[i];
4951
4952 if (TEST(sector[under_sp->sectnum].extra, SECTFX_UNDERWATER) &&
4953 SectUser[under_sp->sectnum] &&
4954 SectUser[under_sp->sectnum]->number == sectu->number)
4955 {
4956 Found = TRUE;
4957 break;
4958 }
4959 }
4960
4961 PRODUCTION_ASSERT(Found == TRUE);
4962
4963 // get the offset from the sprite
4964 u->sx = over_sp->x - pp->posx;
4965 u->sy = over_sp->y - pp->posy;
4966
4967 // update to the new x y position
4968 pp->posx = under_sp->x - u->sx;
4969 pp->posy = under_sp->y - u->sy;
4970
4971 over = over_sp->sectnum;
4972 under = under_sp->sectnum;
4973
4974 if (GetOverlapSector(pp->posx, pp->posy, &over, &under) == 2)
4975 {
4976 pp->cursectnum = under;
4977 }
4978 else
4979 pp->cursectnum = over;
4980
4981 pp->posz = sector[under_sp->sectnum].ceilingz + Z(6);
4982
4983 pp->oposx = pp->posx;
4984 pp->oposy = pp->posy;
4985 pp->oposz = pp->posz;
4986
4987 DoPlayerZrange(pp);
4988 return;
4989 }
4990
4991 VOID
DoPlayerWarpToSurface(PLAYERp pp)4992 DoPlayerWarpToSurface(PLAYERp pp)
4993 {
4994 USERp u = User[pp->PlayerSprite];
4995 SPRITEp sp = &sprite[pp->PlayerSprite];
4996 short i, nexti;
4997 SECT_USERp sectu = SectUser[pp->cursectnum];
4998 short over, under;
4999
5000 SPRITEp under_sp = NULL, over_sp = NULL;
5001 char Found = FALSE;
5002
5003 if (Prediction)
5004 return;
5005
5006 // search for UNDERWATER "under" sprite for reference point
5007 TRAVERSE_SPRITE_STAT(headspritestat[STAT_UNDERWATER], i, nexti)
5008 {
5009 under_sp = &sprite[i];
5010
5011 if (TEST(sector[under_sp->sectnum].extra, SECTFX_UNDERWATER) &&
5012 SectUser[under_sp->sectnum] &&
5013 SectUser[under_sp->sectnum]->number == sectu->number)
5014 {
5015 Found = TRUE;
5016 break;
5017 }
5018 }
5019
5020 PRODUCTION_ASSERT(Found == TRUE);
5021 Found = FALSE;
5022
5023 // search for DIVE_AREA "over" sprite for reference point
5024 TRAVERSE_SPRITE_STAT(headspritestat[STAT_DIVE_AREA], i, nexti)
5025 {
5026 over_sp = &sprite[i];
5027
5028 if (TEST(sector[over_sp->sectnum].extra, SECTFX_DIVE_AREA) &&
5029 SectUser[over_sp->sectnum] &&
5030 SectUser[over_sp->sectnum]->number == sectu->number)
5031 {
5032 Found = TRUE;
5033 break;
5034 }
5035 }
5036
5037 PRODUCTION_ASSERT(Found == TRUE);
5038
5039 // get the offset from the under sprite
5040 u->sx = under_sp->x - pp->posx;
5041 u->sy = under_sp->y - pp->posy;
5042
5043 // update to the new x y position
5044 pp->posx = over_sp->x - u->sx;
5045 pp->posy = over_sp->y - u->sy;
5046
5047 over = over_sp->sectnum;
5048 under = under_sp->sectnum;
5049
5050 if (GetOverlapSector(pp->posx, pp->posy, &over, &under))
5051 {
5052 pp->cursectnum = over;
5053 }
5054
5055 pp->posz = sector[over_sp->sectnum].floorz - Z(2);
5056
5057 // set z range and wade depth so we know how high to set view
5058 DoPlayerZrange(pp);
5059 DoPlayerSetWadeDepth(pp);
5060
5061 pp->posz -= Z(pp->WadeDepth);
5062
5063 pp->oposx = pp->posx;
5064 pp->oposy = pp->posy;
5065 pp->oposz = pp->posz;
5066
5067 return;
5068 }
5069
5070
5071 #if 1
5072 VOID
DoPlayerDivePalette(PLAYERp pp)5073 DoPlayerDivePalette(PLAYERp pp)
5074 {
5075 extern char DefaultPalette[];
5076
5077 if (pp != Player + screenpeek) return;
5078
5079 if ((pp->DeathType == PLAYER_DEATH_DROWN || TEST((Player+screenpeek)->Flags, PF_DIVING)) && !TEST(pp->Flags, PF_DIVING_IN_LAVA))
5080 {
5081 SetFadeAmt(pp,-1005,210); // Dive color , org color 208
5082 } else
5083 {
5084 // Put it all back to normal
5085 if(pp->StartColor == 210)
5086 {
5087 memcpy(pp->temp_pal, palette_data, sizeof(palette_data));
5088 memcpy(palookup[PALETTE_DEFAULT], DefaultPalette, 256 * 32);
5089 #if USE_POLYMOST && USE_OPENGL
5090 if (getrendermode() >= 3)
5091 {
5092 setpalettefade(0,0,0,0);
5093 }
5094 else
5095 #endif
5096 {
5097 COVERsetbrightness(gs.Brightness, &palette_data[0][0]);
5098 }
5099 pp->FadeAmt = 0;
5100 }
5101 }
5102 }
5103 #endif
5104
5105
5106 VOID
DoPlayerBeginDive(PLAYERp pp)5107 DoPlayerBeginDive(PLAYERp pp)
5108 {
5109 SPRITEp sp = &sprite[pp->PlayerSprite];
5110 USERp u = User[pp->PlayerSprite];
5111
5112 if (Prediction)
5113 return;
5114
5115 if(pp->Bloody) pp->Bloody = FALSE; // Water washes away the blood
5116
5117 SET(pp->Flags, PF_DIVING);
5118 DoPlayerDivePalette(pp);
5119 DoPlayerNightVisionPalette(pp);
5120
5121 if(pp == Player + screenpeek)
5122 {
5123 COVER_SetReverb(140); // Underwater echo
5124 pp->Reverb = 140;
5125 }
5126
5127 SpawnSplash(pp->PlayerSprite);
5128
5129 DoPlayerWarpToUnderwater(pp);
5130 OperateTripTrigger(pp);
5131
5132 RESET(pp->Flags, PF_JUMPING | PF_FALLING);
5133 RESET(pp->Flags, PF_CRAWLING);
5134 RESET(pp->Flags, PF_LOCK_CRAWL);
5135
5136 pp->friction = PLAYER_DIVE_FRICTION;
5137 pp->ceiling_dist = PLAYER_DIVE_CEILING_DIST;
5138 pp->floor_dist = PLAYER_DIVE_FLOOR_DIST;
5139 SET(sp->cstat, CSTAT_SPRITE_YCENTER);
5140 pp->DoPlayerAction = DoPlayerDive;
5141
5142 //pp->z_speed = 0;
5143
5144 pp->DiveTics = PLAYER_DIVE_TIME;
5145 pp->DiveDamageTics = 0;
5146
5147 DoPlayerMove(pp); // needs to be called to reset the pp->loz/hiz variable
5148 ///DamageData[u->WeaponNum].Init(pp);
5149
5150 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Dive);
5151
5152 DoPlayerDive(pp);
5153 }
5154
DoPlayerBeginDiveNoWarp(PLAYERp pp)5155 void DoPlayerBeginDiveNoWarp(PLAYERp pp)
5156 {
5157 SPRITEp sp = &sprite[pp->PlayerSprite];
5158 USERp u = User[pp->PlayerSprite];
5159
5160 if (Prediction)
5161 return;
5162
5163 if (!SectorIsUnderwaterArea(pp->cursectnum))
5164 return;
5165
5166 if(pp->Bloody) pp->Bloody = FALSE; // Water washes away the blood
5167
5168 if(pp == Player + screenpeek)
5169 {
5170 COVER_SetReverb(140); // Underwater echo
5171 pp->Reverb = 140;
5172 }
5173
5174 CheckFootPrints(pp);
5175
5176 if (TEST(pp->lo_sectp->extra, SECTFX_LIQUID_MASK) == SECTFX_LIQUID_LAVA)
5177 {
5178 SET(pp->Flags, PF_DIVING_IN_LAVA);
5179 u->DamageTics = 0;
5180 }
5181
5182 SET(pp->Flags, PF_DIVING);
5183 DoPlayerDivePalette(pp);
5184 DoPlayerNightVisionPalette(pp);
5185
5186 RESET(pp->Flags, PF_JUMPING | PF_FALLING);
5187
5188 pp->friction = PLAYER_DIVE_FRICTION;
5189 pp->ceiling_dist = PLAYER_DIVE_CEILING_DIST;
5190 pp->floor_dist = PLAYER_DIVE_FLOOR_DIST;
5191 SET(sp->cstat, CSTAT_SPRITE_YCENTER);
5192 pp->DoPlayerAction = DoPlayerDive;
5193 pp->z_speed = 0;
5194 pp->DiveTics = PLAYER_DIVE_TIME;
5195 pp->DiveDamageTics = 0;
5196 DoPlayerMove(pp); // needs to be called to reset the pp->loz/hiz variable
5197 ///DamageData[u->WeaponNum].Init(pp);
5198 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Dive);
5199 DoPlayerDive(pp);
5200 }
5201
5202 VOID
DoPlayerStopDiveNoWarp(PLAYERp pp)5203 DoPlayerStopDiveNoWarp(PLAYERp pp)
5204 {
5205 SPRITEp sp = &sprite[pp->PlayerSprite];
5206 USERp u = User[pp->PlayerSprite];
5207
5208 if (Prediction)
5209 return;
5210
5211 if (!NoMeters) SetRedrawScreen(pp);
5212
5213 if(pp->TalkVocHandle && FX_SoundActive(pp->TalkVocHandle))
5214 {
5215 FX_StopSound(pp->TalkVocHandle);
5216 pp->PlayerTalking = FALSE;
5217 }
5218
5219 // stop diving no warp
5220 PlayerSound(DIGI_SURFACE,&pp->posx,&pp->posy,&pp->posz,v3df_dontpan|v3df_follow|v3df_doppler,pp);
5221
5222 pp->bob_amt = 0;
5223
5224 RESET(pp->Flags, PF_DIVING|PF_DIVING_IN_LAVA);
5225 DoPlayerDivePalette(pp);
5226 DoPlayerNightVisionPalette(pp);
5227 RESET(pp->SpriteP->cstat, CSTAT_SPRITE_YCENTER);
5228 if(pp == Player + screenpeek)
5229 {
5230 COVER_SetReverb(0);
5231 pp->Reverb = 0;
5232 }
5233
5234 DoPlayerZrange(pp);
5235 }
5236
5237 VOID
DoPlayerStopDive(PLAYERp pp)5238 DoPlayerStopDive(PLAYERp pp)
5239 {
5240 USERp u = User[pp->PlayerSprite];
5241 SPRITEp sp = &sprite[pp->PlayerSprite];
5242 extern char DefaultPalette[];
5243
5244 if (Prediction)
5245 return;
5246
5247 if (!NoMeters) SetRedrawScreen(pp);
5248
5249 if(pp->TalkVocHandle && FX_SoundActive(pp->TalkVocHandle))
5250 {
5251 FX_StopSound(pp->TalkVocHandle);
5252 pp->PlayerTalking = FALSE;
5253 }
5254
5255 // stop diving with warp
5256 PlayerSound(DIGI_SURFACE,&pp->posx,&pp->posy,&pp->posz,v3df_dontpan|v3df_follow|v3df_doppler,pp);
5257
5258 pp->bob_amt = 0;
5259 DoPlayerWarpToSurface(pp);
5260 DoPlayerBeginWade(pp);
5261 RESET(pp->Flags, PF_DIVING|PF_DIVING_IN_LAVA);
5262
5263 DoPlayerDivePalette(pp);
5264 DoPlayerNightVisionPalette(pp);
5265 RESET(sp->cstat, CSTAT_SPRITE_YCENTER);
5266 if(pp == Player + screenpeek)
5267 {
5268 COVER_SetReverb(0);
5269 pp->Reverb = 0;
5270 }
5271 }
5272
5273 VOID
DoPlayerDiveMeter(PLAYERp pp)5274 DoPlayerDiveMeter(PLAYERp pp)
5275 {
5276 short color=0,i=0,metertics,meterunit;
5277 int y;
5278 extern char buffer[];
5279
5280
5281 if (NoMeters) return;
5282
5283 // Don't draw bar from other players
5284 if (pp != Player+myconnectindex) return;
5285
5286 if (!TEST(pp->Flags, PF_DIVING|PF_DIVING_IN_LAVA)) return;
5287
5288 meterunit = PLAYER_DIVE_TIME / 30;
5289 if (meterunit > 0)
5290 metertics = pp->DiveTics / meterunit;
5291 else
5292 return;
5293
5294 if (metertics <= 0 && !TEST(pp->Flags, PF_DIVING|PF_DIVING_IN_LAVA))
5295 {
5296 SetRedrawScreen(pp);
5297 return;
5298 }
5299
5300 if (metertics <= 0) return;
5301
5302 if (CommPlayers < 2) y = 10;
5303 else
5304 if (CommPlayers >=2 && CommPlayers <= 4) y = 20;
5305 else
5306 y = 30;
5307
5308 if(metertics <= 12 && metertics > 6)
5309 color = 20;
5310 else
5311 if (metertics <= 6)
5312 color = 25;
5313 else
5314 color = 22;
5315
5316 rotatesprite((200+8)<<16,y<<16,65536L,0,5408,1,1,
5317 (ROTATE_SPRITE_SCREEN_CLIP),0,0,xdim-1,ydim-1);
5318
5319 rotatesprite((218+47)<<16,y<<16,65536L,0,5406-metertics,1,color,
5320 (ROTATE_SPRITE_SCREEN_CLIP),0,0,xdim-1,ydim-1);
5321 }
5322
5323 VOID
DoPlayerDive(PLAYERp pp)5324 DoPlayerDive(PLAYERp pp)
5325 {
5326 USERp u = User[pp->PlayerSprite];
5327 SECT_USERp sectu = SectUser[pp->cursectnum];
5328
5329 // whenever your view is not in a water area
5330 if (!SectorIsUnderwaterArea(pp->cursectnum))
5331 {
5332 DoPlayerStopDiveNoWarp(pp);
5333 DoPlayerBeginRun(pp);
5334 return;
5335 }
5336
5337 if ((pp->DiveTics -= synctics) < 0)
5338 {
5339 if ((pp->DiveDamageTics -= synctics) < 0)
5340 {
5341 pp->DiveDamageTics = PLAYER_DIVE_DAMAGE_TIME;
5342 //PlayerUpdateHealth(pp, PLAYER_DIVE_DAMAGE_AMOUNT);
5343 PlayerSound(DIGI_WANGDROWNING, &pp->posx, &pp->posy, &pp->posz, v3df_dontpan|v3df_follow, pp);
5344 PlayerUpdateHealth(pp, -3 -(RANDOM_RANGE(7<<8)>>8));
5345 PlayerCheckDeath(pp, -1);
5346 if (TEST(pp->Flags, PF_DEAD))
5347 return;
5348 }
5349 }
5350
5351 // underwater current
5352 if (pp->lo_sectp && TEST(pp->lo_sectp->extra, SECTFX_CURRENT))
5353 {
5354 DoPlayerCurrent(pp);
5355 }
5356
5357 // while diving in lava
5358 // every DamageTics time take some damage
5359 if (TEST(pp->Flags, PF_DIVING_IN_LAVA))
5360 {
5361 if ((u->DamageTics -= synctics) < 0)
5362 {
5363 u->DamageTics = 30; // !JIM! Was DAMAGE_TIME
5364
5365 PlayerUpdateHealth(pp, -40);
5366 }
5367 }
5368
5369 if (TEST_SYNC_KEY(pp, SK_CRAWL))
5370 {
5371 pp->z_speed += PLAYER_DIVE_INC;
5372
5373 if (pp->z_speed > PLAYER_DIVE_MAX_SPEED)
5374 pp->z_speed = PLAYER_DIVE_MAX_SPEED;
5375 }
5376
5377 if (TEST_SYNC_KEY(pp, SK_JUMP))
5378 {
5379 pp->z_speed -= PLAYER_DIVE_INC;
5380
5381 if (pp->z_speed < -PLAYER_DIVE_MAX_SPEED)
5382 pp->z_speed = -PLAYER_DIVE_MAX_SPEED;
5383 }
5384
5385 pp->z_speed = mulscale16(pp->z_speed, 58000);
5386
5387 if (labs(pp->z_speed) < 16)
5388 pp->z_speed = 0;
5389
5390 pp->posz += pp->z_speed;
5391
5392 if (pp->z_speed < 0 && FAF_ConnectArea(pp->cursectnum))
5393 {
5394 if (pp->posz < sector[pp->cursectnum].ceilingz + Z(10))
5395 {
5396 short sectnum = pp->cursectnum;
5397
5398 // check for sector above to see if it is an underwater sector also
5399 updatesectorz(pp->posx, pp->posy, sector[pp->cursectnum].ceilingz - Z(8), §num);
5400
5401 if (sectnum >= 0 && !SectorIsUnderwaterArea(sectnum))
5402 {
5403 // if not underwater sector we must surface
5404 // force into above sector
5405 pp->posz = sector[pp->cursectnum].ceilingz - Z(8);
5406 pp->cursectnum = sectnum;
5407 DoPlayerStopDiveNoWarp(pp);
5408 DoPlayerBeginRun(pp);
5409 return;
5410 }
5411 }
5412 }
5413
5414
5415 // Only get so close to the ceiling
5416 // if its a dive sector without a match or a UNDER2 sector with CANT_SURFACE set
5417 if (sectu && (sectu->number == 0 || TEST(sectu->flags, SECTFU_CANT_SURFACE)))
5418 {
5419 // for room over room water the hiz will be the top rooms ceiling
5420 if (pp->posz < pp->hiz + pp->ceiling_dist)
5421 {
5422 pp->posz = pp->hiz + pp->ceiling_dist;
5423 }
5424 }
5425 else
5426 {
5427 // close to a warping sector - stop diveing with a warp to surface
5428 // !JIM! FRANK - I added !pp->hi_sp so that you don't warp to surface when
5429 // there is a sprite above you since getzrange returns a hiz < ceiling height
5430 // if you are clipping into a sprite and not the ceiling.
5431 if (pp->posz < pp->hiz + Z(4) && !pp->hi_sp)
5432 {
5433 DoPlayerStopDive(pp);
5434 return;
5435 }
5436 }
5437
5438 // Only get so close to the floor
5439 if (pp->posz >= pp->loz - PLAYER_DIVE_HEIGHT)
5440 {
5441 pp->posz = pp->loz - PLAYER_DIVE_HEIGHT;
5442 }
5443
5444 // make player bob if sitting still
5445 if (!PLAYER_MOVING(pp) && pp->z_speed == 0 && pp->up_speed == 0)
5446 {
5447 DoPlayerSpriteBob(pp, PLAYER_DIVE_HEIGHT, PLAYER_DIVE_BOB_AMT, 3);
5448 }
5449 // player is moving
5450 else
5451 {
5452 // if bob_amt is approx 0
5453 if (labs(pp->bob_amt) < Z(1))
5454 {
5455 pp->bob_amt = 0;
5456 pp->bob_ndx = 0;
5457 }
5458 // else keep bobbing until its back close to 0
5459 else
5460 {
5461 DoPlayerSpriteBob(pp, PLAYER_DIVE_HEIGHT, PLAYER_DIVE_BOB_AMT, 3);
5462 }
5463 }
5464
5465 // Reverse bobbing when getting close to the floor
5466 if (pp->posz + pp->bob_amt >= pp->loz - PLAYER_DIVE_HEIGHT)
5467 {
5468 pp->bob_ndx = NORM_ANGLE(pp->bob_ndx + ((1024 + 512) - pp->bob_ndx) * 2);
5469 DoPlayerSpriteBob(pp, PLAYER_DIVE_HEIGHT, PLAYER_DIVE_BOB_AMT, 3);
5470 }
5471 // Reverse bobbing when getting close to the ceiling
5472 if (pp->posz + pp->bob_amt < pp->hiz + pp->ceiling_dist)
5473 {
5474 pp->bob_ndx = NORM_ANGLE(pp->bob_ndx + ((512) - pp->bob_ndx) * 2);
5475 DoPlayerSpriteBob(pp, PLAYER_DIVE_HEIGHT, PLAYER_DIVE_BOB_AMT, 3);
5476 }
5477
5478 DoPlayerMove(pp);
5479
5480 // Random bubble sounds
5481 // if((RANDOM_RANGE(1000<<5)>>5) < 100)
5482 // PlaySound(DIGI_BUBBLES, &pp->posx, &pp->posy, &pp->posz, v3df_dontpan|v3df_follow);
5483
5484 if ((!Prediction && pp->z_speed && ((RANDOM_P2(1024<<5)>>5) < 64)) ||
5485 (PLAYER_MOVING(pp) && (RANDOM_P2(1024<<5)>>5) < 64))
5486 {
5487 short bubble;
5488 USERp bu;
5489 SPRITEp bp;
5490 int nx,ny;
5491
5492 PlaySound(DIGI_BUBBLES, &pp->posx, &pp->posy, &pp->posz, v3df_none);
5493 bubble = SpawnBubble(pp->SpriteP - sprite);
5494 if (bubble >= 0)
5495 {
5496 bu = User[bubble];
5497 bp = &sprite[bubble];
5498
5499 // back it up a bit to get it out of your face
5500 nx = MOVEx((128+64), NORM_ANGLE(bp->ang + 1024));
5501 ny = MOVEy((128+64), NORM_ANGLE(bp->ang + 1024));
5502
5503 move_sprite(bubble, nx, ny, 0L, u->ceiling_dist, u->floor_dist, 0, synctics);
5504 }
5505 }
5506 }
5507
5508 int
DoPlayerTestPlaxDeath(PLAYERp pp)5509 DoPlayerTestPlaxDeath(PLAYERp pp)
5510 {
5511 USERp u = User[pp->PlayerSprite];
5512
5513 // landed on a paralax floor
5514 if (pp->lo_sectp && TEST(pp->lo_sectp->floorstat, FLOOR_STAT_PLAX))
5515 {
5516 PlayerUpdateHealth(pp, -u->Health);
5517 PlayerCheckDeath(pp, -1);
5518 return(TRUE);
5519 }
5520
5521 return(FALSE);
5522 }
5523
5524 VOID
DoPlayerCurrent(PLAYERp pp)5525 DoPlayerCurrent(PLAYERp pp)
5526 {
5527 int xvect, yvect;
5528 SECT_USERp sectu = SectUser[pp->cursectnum];
5529 int push_ret;
5530
5531 if (!sectu)
5532 return;
5533
5534 xvect = sectu->speed * synctics * (int) sintable[NORM_ANGLE(sectu->ang + 512)] >> 4;
5535 yvect = sectu->speed * synctics * (int) sintable[sectu->ang] >> 4;
5536
5537 push_ret = pushmove(&pp->posx, &pp->posy, &pp->posz, &pp->cursectnum, ((int)pp->SpriteP->clipdist<<2), pp->ceiling_dist, pp->floor_dist, CLIPMASK_PLAYER);
5538 if (push_ret < 0)
5539 {
5540 if (!TEST(pp->Flags, PF_DEAD))
5541 {
5542 USERp u = User[pp->PlayerSprite];
5543
5544 PlayerUpdateHealth(pp, -u->Health); // Make sure he dies!
5545 PlayerCheckDeath(pp, -1);
5546
5547 if (TEST(pp->Flags, PF_DEAD))
5548 return;
5549 }
5550 return;
5551 }
5552 clipmove(&pp->posx, &pp->posy, &pp->posz, &pp->cursectnum, xvect, yvect, ((int)pp->SpriteP->clipdist<<2), pp->ceiling_dist, pp->floor_dist, CLIPMASK_PLAYER);
5553 PlayerCheckValidMove(pp);
5554 pushmove(&pp->posx, &pp->posy, &pp->posz, &pp->cursectnum, ((int)pp->SpriteP->clipdist<<2), pp->ceiling_dist, pp->floor_dist, CLIPMASK_PLAYER);
5555 if (push_ret < 0)
5556 {
5557 if (!TEST(pp->Flags, PF_DEAD))
5558 {
5559 USERp u = User[pp->PlayerSprite];
5560
5561 PlayerUpdateHealth(pp, -u->Health); // Make sure he dies!
5562 PlayerCheckDeath(pp, -1);
5563
5564 if (TEST(pp->Flags, PF_DEAD))
5565 return;
5566 }
5567 return;
5568 }
5569 }
5570
5571 VOID
DoPlayerFireOutWater(PLAYERp pp)5572 DoPlayerFireOutWater(PLAYERp pp)
5573 {
5574 USERp u = User[pp->PlayerSprite];
5575
5576 if (Prediction)
5577 return;
5578
5579 if (pp->WadeDepth > 20)
5580 {
5581 if (u->flame >= 0)
5582 SetSuicide(u->flame);
5583 u->flame = -2;
5584 }
5585 }
5586
5587 VOID
DoPlayerFireOutDeath(PLAYERp pp)5588 DoPlayerFireOutDeath(PLAYERp pp)
5589 {
5590 USERp u = User[pp->PlayerSprite];
5591
5592 if (Prediction)
5593 return;
5594
5595 if (u->flame >= 0)
5596 SetSuicide(u->flame);
5597
5598 u->flame = -2;
5599 }
5600
5601 VOID
DoPlayerBeginWade(PLAYERp pp)5602 DoPlayerBeginWade(PLAYERp pp)
5603 {
5604 USERp u = User[pp->PlayerSprite];
5605
5606 // landed on a paralax floor?
5607 if (DoPlayerTestPlaxDeath(pp))
5608 return;
5609
5610 RESET(pp->Flags, PF_JUMPING | PF_FALLING);
5611 RESET(pp->Flags, PF_CRAWLING);
5612
5613 pp->friction = PLAYER_WADE_FRICTION;
5614 pp->floor_dist = PLAYER_WADE_FLOOR_DIST;
5615 pp->ceiling_dist = PLAYER_WADE_CEILING_DIST;
5616 pp->DoPlayerAction = DoPlayerWade;
5617
5618 DoPlayerFireOutWater(pp);
5619
5620 if (pp->jump_speed > 100)
5621 SpawnSplash(pp->PlayerSprite);
5622
5623 // fix it so that you won't go under water unless you hit the water at a
5624 // certain speed
5625 if (pp->jump_speed > 0 && pp->jump_speed < 1300)
5626 pp->jump_speed = 0;
5627
5628 ASSERT(u->ActorActionSet->Run);
5629
5630 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Run);
5631 }
5632
5633
5634 VOID
DoPlayerWade(PLAYERp pp)5635 DoPlayerWade(PLAYERp pp)
5636 {
5637 USERp u = User[pp->PlayerSprite];
5638 int dot;
5639 int wadedir = 0;
5640
5641 DoPlayerFireOutWater(pp);
5642
5643 dot = DOT_PRODUCT_2D(pp->xvect, pp->yvect, sintable[NORM_ANGLE(pp->pang+512)], sintable[pp->pang]);
5644
5645 if (dot < 0)
5646 wadedir = -2;
5647 else
5648 if (dot > 0)
5649 wadedir = 2;
5650
5651 if (DebugOperate)
5652 {
5653 if (TEST_SYNC_KEY(pp, SK_OPERATE))
5654 {
5655 if (FLAG_KEY_PRESSED(pp, SK_OPERATE))
5656 {
5657 if (TEST(sector[pp->cursectnum].extra, SECTFX_OPERATIONAL))
5658 {
5659 FLAG_KEY_RELEASE(pp, SK_OPERATE);
5660 DoPlayerBeginOperate(pp);
5661 pp->bob_amt = 0;
5662 pp->bob_ndx = 0;
5663 return;
5664 }
5665 }
5666 }
5667 else
5668 {
5669 FLAG_KEY_RESET(pp, SK_OPERATE);
5670 }
5671 }
5672
5673 // Crawl if in small area automatically
5674 if (DoPlayerTestCrawl(pp) && pp->WadeDepth <= PLAYER_CRAWL_WADE_DEPTH)
5675 {
5676 DoPlayerBeginCrawl(pp);
5677 return;
5678 }
5679
5680 // Crawl Commanded
5681 if (TEST_SYNC_KEY(pp, SK_CRAWL) && pp->WadeDepth <= PLAYER_CRAWL_WADE_DEPTH)
5682 {
5683 DoPlayerBeginCrawl(pp);
5684 return;
5685 }
5686
5687 if (TEST_SYNC_KEY(pp, SK_JUMP))
5688 {
5689 if (FLAG_KEY_PRESSED(pp, SK_JUMP))
5690 {
5691 FLAG_KEY_RELEASE(pp, SK_JUMP);
5692 //DoPlayerHeight(pp);
5693 //DoPlayerHeight(pp);
5694 //DoPlayerHeight(pp);
5695 //DoPlayerHeight(pp);
5696 DoPlayerBeginJump(pp);
5697 pp->bob_amt = 0;
5698 pp->bob_ndx = 0;
5699 return;
5700 }
5701 }
5702 else
5703 {
5704 FLAG_KEY_RESET(pp, SK_JUMP);
5705 }
5706
5707 if (PlayerFlyKey(pp))
5708 {
5709 //pp->InventoryTics[INVENTORY_FLY] = -99;
5710 DoPlayerBeginFly(pp);
5711 pp->bob_amt = 0;
5712 pp->bob_ndx = 0;
5713 return;
5714 }
5715
5716 // If moving forward and tag is a ladder start climbing
5717 if (PlayerOnLadder(pp))
5718 {
5719 DoPlayerBeginClimb(pp);
5720 return;
5721 }
5722
5723 if (pp->lo_sectp && TEST(pp->lo_sectp->extra, SECTFX_CURRENT))
5724 {
5725 DoPlayerCurrent(pp);
5726 }
5727
5728 // Move about
5729 DoPlayerMove(pp);
5730
5731 if (TEST(pp->Flags, PF_PLAYER_MOVED))
5732 {
5733 if (u->Rot != u->ActorActionSet->Run)
5734 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Run);
5735 }
5736 else
5737 {
5738 if (u->Rot != u->ActorActionSet->Stand)
5739 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Stand);
5740 }
5741
5742 // If the floor is far below you, fall hard instead of adjusting height
5743 if (labs(pp->posz - pp->loz) > PLAYER_HEIGHT + PLAYER_FALL_HEIGHT)
5744 {
5745 pp->jump_speed = Z(1);
5746 DoPlayerBeginFall(pp);
5747 // call PlayerFall now seems to iron out a hitch before falling
5748 DoPlayerFall(pp);
5749 return;
5750 }
5751
5752 if (PlayerCanDive(pp))
5753 {
5754 pp->bob_amt = 0;
5755 pp->bob_ndx = 0;
5756 return;
5757 }
5758
5759 // If the floor is far below you, fall hard instead of adjusting height
5760 if (labs(pp->posz - pp->loz) > PLAYER_HEIGHT + PLAYER_FALL_HEIGHT)
5761 {
5762 pp->jump_speed = Z(1);
5763 DoPlayerBeginFall(pp);
5764 // call PlayerFall now seems to iron out a hitch before falling
5765 DoPlayerFall(pp);
5766 pp->bob_amt = 0;
5767 pp->bob_ndx = 0;
5768 return;
5769 }
5770
5771
5772 DoPlayerBob(pp);
5773
5774 // Adjust height moving up and down sectors
5775 DoPlayerHeight(pp);
5776
5777 #if 0
5778 if ((TEST_SYNC_KEY(pp, SK_RUN) || TEST(pp->Flags, PF_LOCK_RUN)) && PlayerInDiveArea(pp))
5779 {
5780 DoPlayerBeginSwim(pp);
5781 pp->bob_amt = 0;
5782 pp->bob_ndx = 0;
5783 return;
5784 }
5785 #endif
5786
5787 if (!pp->WadeDepth)
5788 {
5789 DoPlayerBeginRun(pp);
5790 return;
5791 }
5792 }
5793
5794
5795 VOID
DoPlayerBeginOperateBoat(PLAYERp pp)5796 DoPlayerBeginOperateBoat(PLAYERp pp)
5797 {
5798 USERp u = User[pp->PlayerSprite];
5799
5800 pp->floor_dist = PLAYER_RUN_FLOOR_DIST;
5801 pp->ceiling_dist = PLAYER_RUN_CEILING_DIST;
5802 pp->DoPlayerAction = DoPlayerOperateBoat;
5803
5804 // temporary set to get weapons down
5805 if (TEST(pp->sop->flags, SOBJ_HAS_WEAPON))
5806 SET(pp->Flags, PF_WEAPON_DOWN);
5807
5808 ///DamageData[u->WeaponNum].Init(pp);
5809
5810 ASSERT(u->ActorActionSet->Run);
5811
5812 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Run);
5813 }
5814
5815 VOID
DoPlayerBeginOperateTank(PLAYERp pp)5816 DoPlayerBeginOperateTank(PLAYERp pp)
5817 {
5818 USERp u = User[pp->PlayerSprite];
5819
5820 pp->floor_dist = PLAYER_RUN_FLOOR_DIST;
5821 pp->ceiling_dist = PLAYER_RUN_CEILING_DIST;
5822 pp->DoPlayerAction = DoPlayerOperateTank;
5823
5824 // temporary set to get weapons down
5825 if (TEST(pp->sop->flags, SOBJ_HAS_WEAPON))
5826 SET(pp->Flags, PF_WEAPON_DOWN);
5827
5828 ///DamageData[u->WeaponNum].Init(pp);
5829
5830 ASSERT(u->ActorActionSet->Stand);
5831
5832 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Stand);
5833 }
5834
5835 VOID
DoPlayerBeginOperateTurret(PLAYERp pp)5836 DoPlayerBeginOperateTurret(PLAYERp pp)
5837 {
5838 USERp u = User[pp->PlayerSprite];
5839
5840 pp->floor_dist = PLAYER_RUN_FLOOR_DIST;
5841 pp->ceiling_dist = PLAYER_RUN_CEILING_DIST;
5842 pp->DoPlayerAction = DoPlayerOperateTurret;
5843
5844 // temporary set to get weapons down
5845 if (TEST(pp->sop->flags, SOBJ_HAS_WEAPON))
5846 SET(pp->Flags, PF_WEAPON_DOWN);
5847
5848 ///DamageData[u->WeaponNum].Init(pp);
5849
5850 ASSERT(u->ActorActionSet->Stand);
5851
5852 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Stand);
5853 }
5854
FindMainSector(SECTOR_OBJECTp sop)5855 VOID FindMainSector(SECTOR_OBJECTp sop)
5856 {
5857 // find the main sector - only do this once for each sector object
5858 if (sop->op_main_sector < 0)
5859 {
5860 int sx = sop->xmid;
5861 int sy = sop->ymid;
5862
5863 PlaceSectorObject(sop, sop->ang, MAXSO, MAXSO);
5864
5865 // set it to something valid
5866 sop->op_main_sector = 0;
5867
5868 //COVERupdatesector(sx, sy, &sop->op_main_sector);
5869 //updatesectorz(sx, sy, sop->zmid - Z(8), &sop->op_main_sector);
5870
5871 updatesectorz(sx, sy, sop->zmid, &sop->op_main_sector);
5872
5873 //COVERupdatesector(sx, sy, &sop->op_main_sector);
5874
5875 ////DSPRINTF(ds,"main sector %d, zmid %d",sop->op_main_sector, sop->zmid);
5876 //MONO_PRINT(ds);
5877
5878 PlaceSectorObject(sop, sop->ang, sx, sy);
5879 }
5880 }
5881
DoPlayerOperateMatch(PLAYERp pp,BOOL starting)5882 VOID DoPlayerOperateMatch(PLAYERp pp, BOOL starting)
5883 {
5884 SPRITEp sp;
5885 short i,nexti;
5886
5887 if (!pp->sop)
5888 return;
5889
5890 TRAVERSE_SPRITE_SECT(headspritesect[pp->sop->mid_sector], i, nexti)
5891 {
5892 sp = &sprite[i];
5893
5894 if (sp->statnum == STAT_ST1 && sp->hitag == SO_DRIVABLE_ATTRIB)
5895 {
5896 if (starting)
5897 {
5898 if (SP_TAG5(sp))
5899 DoMatchEverything(pp, SP_TAG5(sp), -1);
5900 }
5901 else
5902 {
5903 if (TEST_BOOL2(sp) && SP_TAG5(sp))
5904 DoMatchEverything(pp, SP_TAG5(sp)+1, -1);
5905 }
5906 break;
5907 }
5908 }
5909 }
5910
5911 VOID
DoPlayerBeginOperate(PLAYERp pp)5912 DoPlayerBeginOperate(PLAYERp pp)
5913 {
5914 SECTOR_OBJECTp PlayerOnObject(short sectnum_match);
5915 SECTOR_OBJECTp sop;
5916 SPRITEp sp = pp->SpriteP;
5917 USERp u = User[pp->PlayerSprite];
5918 int cz, fz;
5919 int i;
5920
5921 sop = PlayerOnObject(pp->cursectnum);
5922
5923 // if someone already controlling it
5924 if (sop->controller)
5925 return;
5926
5927 if (TEST(sop->flags, SOBJ_REMOTE_ONLY))
5928 return;
5929
5930 if (!sop)
5931 {
5932 DoPlayerBeginRun(pp);
5933 return;
5934 }
5935
5936 // won't operate - broken
5937 if (sop->max_damage != -9999 && sop->max_damage <= 0)
5938 {
5939 if (pp->InventoryAmount[INVENTORY_REPAIR_KIT])
5940 {
5941 UseInventoryRepairKit(pp);
5942 sop->max_damage = User[sop->sp_child - sprite]->MaxHealth;
5943 VehicleSetSmoke(sop, NULL);
5944 RESET(sop->flags, SOBJ_BROKEN);
5945 }
5946 else
5947 {
5948 PlayerSound(DIGI_USEBROKENVEHICLE, &pp->posx, &pp->posy, &pp->posz, v3df_follow|v3df_dontpan,pp);
5949 return;
5950 }
5951 }
5952
5953 pp->sop = pp->sop_control = sop;
5954 sop->controller = pp->SpriteP;
5955
5956 pp->pang = sop->ang;
5957 pp->posx = sop->xmid;
5958 pp->posy = sop->ymid;
5959 COVERupdatesector(pp->posx, pp->posy, &pp->cursectnum);
5960 getzsofslope(pp->cursectnum, pp->posx, pp->posy, &cz, &fz);
5961 pp->posz = fz - PLAYER_HEIGHT;
5962
5963 RESET(pp->Flags, PF_CRAWLING|PF_JUMPING|PF_FALLING|PF_LOCK_CRAWL);
5964
5965 DoPlayerOperateMatch(pp, TRUE);
5966
5967 // look for gun before trying to using it
5968 for (i = 0; sop->sp_num[i] != -1; i++)
5969 {
5970 if (sprite[sop->sp_num[i]].statnum == STAT_SO_SHOOT_POINT)
5971 {
5972 SET(sop->flags, SOBJ_HAS_WEAPON);
5973 break;
5974 }
5975 }
5976
5977 DoPlayerResetMovement(pp);
5978
5979 switch (sop->track)
5980 {
5981 case SO_TANK:
5982 if (pp->input.vel|pp->input.svel)
5983 PlaySOsound(pp->sop->mid_sector, SO_DRIVE_SOUND);
5984 else
5985 PlaySOsound(pp->sop->mid_sector, SO_IDLE_SOUND);
5986 pp->posz = fz - PLAYER_HEIGHT;
5987 DoPlayerBeginOperateTank(pp);
5988 break;
5989 case SO_TURRET_MGUN:
5990 case SO_TURRET:
5991 if (pp->input.angvel)
5992 PlaySOsound(pp->sop->mid_sector, SO_DRIVE_SOUND);
5993 else
5994 PlaySOsound(pp->sop->mid_sector, SO_IDLE_SOUND);
5995 pp->posz = fz - PLAYER_HEIGHT;
5996 DoPlayerBeginOperateTurret(pp);
5997 break;
5998 case SO_SPEED_BOAT:
5999 if (pp->input.vel|pp->input.svel)
6000 PlaySOsound(pp->sop->mid_sector, SO_DRIVE_SOUND);
6001 else
6002 PlaySOsound(pp->sop->mid_sector, SO_IDLE_SOUND);
6003 pp->posz = fz - PLAYER_HEIGHT;
6004 DoPlayerBeginOperateBoat(pp);
6005 break;
6006 default:
6007 return;
6008 }
6009
6010 }
6011
6012 VOID
DoPlayerBeginRemoteOperate(PLAYERp pp,SECTOR_OBJECTp sop)6013 DoPlayerBeginRemoteOperate(PLAYERp pp, SECTOR_OBJECTp sop)
6014 {
6015 SECTOR_OBJECTp PlayerOnObject(short sectnum_match);
6016 SPRITEp sp = pp->SpriteP;
6017 USERp u = User[pp->PlayerSprite];
6018 int cz, fz;
6019 int i;
6020 short save_sectnum;
6021 void PlayerRemoteReset(PLAYERp pp, short sectnum);
6022
6023 pp->sop_remote = pp->sop = pp->sop_control = sop;
6024 sop->controller = pp->SpriteP;
6025
6026 // won't operate - broken
6027 if (sop->max_damage != -9999 && sop->max_damage <= 0)
6028 {
6029 if (pp->InventoryAmount[INVENTORY_REPAIR_KIT])
6030 {
6031 UseInventoryRepairKit(pp);
6032 sop->max_damage = User[sop->sp_child - sprite]->MaxHealth;
6033 VehicleSetSmoke(sop, NULL);
6034 RESET(sop->flags, SOBJ_BROKEN);
6035 }
6036 else
6037 {
6038 PlayerSound(DIGI_USEBROKENVEHICLE, &pp->posx, &pp->posy, &pp->posz, v3df_follow|v3df_dontpan,pp);
6039 return;
6040 }
6041 }
6042
6043 save_sectnum = pp->cursectnum;
6044
6045 pp->pang = sop->ang;
6046 pp->posx = sop->xmid;
6047 pp->posy = sop->ymid;
6048 COVERupdatesector(pp->posx, pp->posy, &pp->cursectnum);
6049 getzsofslope(pp->cursectnum, pp->posx, pp->posy, &cz, &fz);
6050 pp->posz = fz - PLAYER_HEIGHT;
6051
6052 RESET(pp->Flags, PF_CRAWLING|PF_JUMPING|PF_FALLING|PF_LOCK_CRAWL);
6053
6054 DoPlayerOperateMatch(pp, TRUE);
6055
6056 // look for gun before trying to using it
6057 for (i = 0; sop->sp_num[i] != -1; i++)
6058 {
6059 if (sprite[sop->sp_num[i]].statnum == STAT_SO_SHOOT_POINT)
6060 {
6061 SET(sop->flags, SOBJ_HAS_WEAPON);
6062 break;
6063 }
6064 }
6065
6066 DoPlayerResetMovement(pp);
6067
6068 PlayerToRemote(pp);
6069 PlayerRemoteInit(pp);
6070
6071 switch (sop->track)
6072 {
6073 case SO_TANK:
6074 if (pp->input.vel|pp->input.svel)
6075 PlaySOsound(pp->sop->mid_sector, SO_DRIVE_SOUND);
6076 else
6077 PlaySOsound(pp->sop->mid_sector, SO_IDLE_SOUND);
6078 pp->posz = fz - PLAYER_HEIGHT;
6079 DoPlayerBeginOperateTank(pp);
6080 break;
6081 case SO_TURRET_MGUN:
6082 case SO_TURRET:
6083 if (pp->input.angvel)
6084 PlaySOsound(pp->sop->mid_sector, SO_DRIVE_SOUND);
6085 else
6086 PlaySOsound(pp->sop->mid_sector, SO_IDLE_SOUND);
6087 pp->posz = fz - PLAYER_HEIGHT;
6088 DoPlayerBeginOperateTurret(pp);
6089 break;
6090 case SO_SPEED_BOAT:
6091 if (pp->input.vel|pp->input.svel)
6092 PlaySOsound(pp->sop->mid_sector, SO_DRIVE_SOUND);
6093 else
6094 PlaySOsound(pp->sop->mid_sector, SO_IDLE_SOUND);
6095 pp->posz = fz - PLAYER_HEIGHT;
6096 DoPlayerBeginOperateBoat(pp);
6097 break;
6098 default:
6099 return;
6100 }
6101
6102 PlayerRemoteReset(pp, save_sectnum);
6103 }
6104
PlayerToRemote(PLAYERp pp)6105 void PlayerToRemote(PLAYERp pp)
6106 {
6107 pp->remote.cursectnum = pp->cursectnum;
6108 pp->remote.lastcursectnum = pp->lastcursectnum;
6109
6110 pp->remote.posx = pp->posx;
6111 pp->remote.posy = pp->posy;
6112 pp->remote.posz = pp->posz;
6113
6114 pp->remote.xvect = pp->xvect;
6115 pp->remote.yvect = pp->yvect;
6116 pp->remote.oxvect = pp->oxvect;
6117 pp->remote.oyvect = pp->oyvect;
6118 pp->remote.slide_xvect = pp->slide_xvect;
6119 pp->remote.slide_yvect = pp->slide_yvect;
6120 }
6121
RemoteToPlayer(PLAYERp pp)6122 void RemoteToPlayer(PLAYERp pp)
6123 {
6124 pp->cursectnum = pp->remote.cursectnum;
6125 pp->lastcursectnum = pp->remote.lastcursectnum;
6126
6127 pp->posx = pp->remote.posx;
6128 pp->posy = pp->remote.posy;
6129 pp->posz = pp->remote.posz;
6130
6131 pp->xvect = pp->remote.xvect;
6132 pp->yvect = pp->remote.yvect;
6133 pp->oxvect = pp->remote.oxvect;
6134 pp->oyvect = pp->remote.oyvect;
6135 pp->slide_xvect = pp->remote.slide_xvect;
6136 pp->slide_yvect = pp->remote.slide_yvect;
6137 }
6138
PlayerRemoteReset(PLAYERp pp,short sectnum)6139 void PlayerRemoteReset(PLAYERp pp, short sectnum)
6140 {
6141 pp->cursectnum = pp->lastcursectnum = sectnum;
6142
6143 pp->posx = pp->remote_sprite->x;
6144 pp->posy = pp->remote_sprite->y;
6145 pp->posz = sector[sectnum].floorz - PLAYER_HEIGHT;
6146
6147 pp->xvect = pp->yvect = pp->oxvect = pp->oyvect = pp->slide_xvect = pp->slide_yvect = 0;
6148
6149 UpdatePlayerSprite(pp);
6150 }
6151
PlayerRemoteInit(PLAYERp pp)6152 void PlayerRemoteInit(PLAYERp pp)
6153 {
6154 pp->remote.xvect = 0;
6155 pp->remote.yvect = 0;
6156 pp->remote.oxvect = 0;
6157 pp->remote.oyvect = 0;
6158 pp->remote.slide_xvect = 0;
6159 pp->remote.slide_yvect = 0;
6160 }
6161
6162 VOID
DoPlayerStopOperate(PLAYERp pp)6163 DoPlayerStopOperate(PLAYERp pp)
6164 {
6165 RESET(pp->Flags, PF_WEAPON_DOWN);
6166 DoPlayerResetMovement(pp);
6167 DoTankTreads(pp);
6168 DoPlayerOperateMatch(pp, FALSE);
6169 StopSOsound(pp->sop->mid_sector);
6170
6171 if (pp->sop_remote)
6172 {
6173 if (TEST_BOOL1(pp->remote_sprite))
6174 pp->pang = pp->oang = pp->remote_sprite->ang;
6175 else
6176 pp->pang = pp->oang = getangle(pp->sop_remote->xmid - pp->posx, pp->sop_remote->ymid - pp->posy);
6177 }
6178
6179 if (pp->sop_control)
6180 {
6181 pp->sop_control->controller = NULL;
6182 }
6183 pp->sop_control = NULL;
6184 pp->sop_riding = NULL;
6185 pp->sop_remote = NULL;
6186 pp->sop = NULL;
6187 DoPlayerBeginRun(pp);
6188 }
6189
6190 VOID
DoPlayerOperateTurret(PLAYERp pp)6191 DoPlayerOperateTurret(PLAYERp pp)
6192 {
6193 short oldang;
6194 short save_sectnum;
6195
6196 if (TEST_SYNC_KEY(pp, SK_OPERATE))
6197 {
6198 if (FLAG_KEY_PRESSED(pp, SK_OPERATE))
6199 {
6200 FLAG_KEY_RELEASE(pp, SK_OPERATE);
6201 DoPlayerStopOperate(pp);
6202 return;
6203 }
6204 }
6205 else
6206 {
6207 FLAG_KEY_RESET(pp, SK_OPERATE);
6208 }
6209
6210 if (pp->sop->max_damage != -9999 && pp->sop->max_damage <= 0)
6211 {
6212 DoPlayerStopOperate(pp);
6213 return;
6214 }
6215
6216 save_sectnum = pp->cursectnum;
6217
6218 if (pp->sop_remote)
6219 RemoteToPlayer(pp);
6220
6221 DoPlayerMoveTurret(pp);
6222
6223 if (pp->sop_remote)
6224 {
6225 PlayerToRemote(pp);
6226 PlayerRemoteReset(pp, save_sectnum);
6227 }
6228 }
6229
6230
6231 VOID
DoPlayerOperateBoat(PLAYERp pp)6232 DoPlayerOperateBoat(PLAYERp pp)
6233 {
6234 short oldang;
6235 short save_sectnum;
6236
6237 if (TEST_SYNC_KEY(pp, SK_OPERATE))
6238 {
6239 if (FLAG_KEY_PRESSED(pp, SK_OPERATE))
6240 {
6241 FLAG_KEY_RELEASE(pp, SK_OPERATE);
6242 DoPlayerStopOperate(pp);
6243 return;
6244 }
6245 }
6246 else
6247 {
6248 FLAG_KEY_RESET(pp, SK_OPERATE);
6249 }
6250
6251 if (pp->sop->max_damage != -9999 && pp->sop->max_damage <= 0)
6252 {
6253 DoPlayerStopOperate(pp);
6254 return;
6255 }
6256
6257 save_sectnum = pp->cursectnum;
6258
6259 if (pp->sop_remote)
6260 RemoteToPlayer(pp);
6261
6262 DoPlayerMoveBoat(pp);
6263
6264 if (pp->sop_remote)
6265 {
6266 PlayerToRemote(pp);
6267 PlayerRemoteReset(pp, save_sectnum);
6268 }
6269 }
6270
6271 VOID
DoPlayerOperateTank(PLAYERp pp)6272 DoPlayerOperateTank(PLAYERp pp)
6273 {
6274 short oldang;
6275 short save_sectnum;
6276
6277 //ASSERT(!TEST_SYNC_KEY(pp, SK_OPERATE));
6278 if (TEST_SYNC_KEY(pp, SK_OPERATE))
6279 {
6280 if (FLAG_KEY_PRESSED(pp, SK_OPERATE))
6281 {
6282 FLAG_KEY_RELEASE(pp, SK_OPERATE);
6283 DoPlayerStopOperate(pp);
6284 return;
6285 }
6286 }
6287 else
6288 {
6289 FLAG_KEY_RESET(pp, SK_OPERATE);
6290 }
6291
6292 if (pp->sop->max_damage != -9999 && pp->sop->max_damage <= 0)
6293 {
6294 DoPlayerStopOperate(pp);
6295 return;
6296 }
6297
6298 save_sectnum = pp->cursectnum;
6299
6300 if (pp->sop_remote)
6301 RemoteToPlayer(pp);
6302
6303 DoPlayerMoveTank(pp);
6304
6305 if (pp->sop_remote)
6306 {
6307 PlayerToRemote(pp);
6308 PlayerRemoteReset(pp, save_sectnum);
6309 }
6310 }
6311
6312 VOID
DoPlayerDeathJump(PLAYERp pp)6313 DoPlayerDeathJump(PLAYERp pp)
6314 {
6315 short i;
6316
6317 #define PLAYER_DEATH_GRAV 8
6318
6319 // instead of multiplying by synctics, use a loop for greater accuracy
6320 for (i = 0; i < synctics; i++)
6321 {
6322 // adjust jump speed by gravity - if jump speed greater than 0 player
6323 // have started falling
6324 if ((pp->jump_speed += PLAYER_DEATH_GRAV) > 0)
6325 {
6326 RESET(pp->Flags, PF_JUMPING);
6327 SET(pp->Flags, PF_FALLING);
6328 DoPlayerDeathFall(pp);
6329 return;
6330 }
6331
6332 // adjust height by jump speed
6333 pp->posz += pp->jump_speed;
6334
6335 // if player gets to close the ceiling while jumping
6336 //if (pp->posz < pp->hiz + Z(4))
6337 if (PlayerCeilingHit(pp, pp->hiz + Z(4)))
6338 {
6339 // put player at the ceiling
6340 pp->posz = pp->hiz + Z(4);
6341
6342 // reverse your speed to falling
6343 pp->jump_speed = -pp->jump_speed;
6344
6345 // start falling
6346 RESET(pp->Flags, PF_JUMPING);
6347 SET(pp->Flags, PF_FALLING);
6348 DoPlayerDeathFall(pp);
6349 return;
6350 }
6351 }
6352 }
6353
6354 VOID
DoPlayerDeathFall(PLAYERp pp)6355 DoPlayerDeathFall(PLAYERp pp)
6356 {
6357 short i;
6358 int loz;
6359
6360 for (i = 0; i < synctics; i++)
6361 {
6362 // adjust jump speed by gravity
6363 pp->jump_speed += PLAYER_DEATH_GRAV;
6364
6365 // adjust player height by jump speed
6366 pp->posz += pp->jump_speed;
6367
6368 #if 0
6369 if (pp->lo_sectp && TEST(pp->lo_sectp->extra, SECTFX_SINK))
6370 {
6371 loz = pp->lo_sectp->floorz - Z(SectUser[pp->lo_sectp - sector]->depth);
6372 }
6373 else
6374 loz = pp->loz;
6375 #else
6376 if (pp->lo_sectp && TEST(pp->lo_sectp->extra, SECTFX_SINK))
6377 {
6378 loz = pp->lo_sectp->floorz;
6379 }
6380 else
6381 loz = pp->loz;
6382 #endif
6383
6384 if (PlayerFloorHit(pp, loz - PLAYER_DEATH_HEIGHT))
6385 //if (pp->posz > loz - PLAYER_DEATH_HEIGHT)
6386 {
6387 if (loz != pp->loz)
6388 SpawnSplash(pp->PlayerSprite);
6389
6390 if(RANDOM_RANGE(1000) > 500)
6391 PlaySound(DIGI_BODYFALL1, &pp->posx, &pp->posy, &pp->posz, v3df_dontpan);
6392 else
6393 PlaySound(DIGI_BODYFALL2, &pp->posx, &pp->posy, &pp->posz, v3df_dontpan);
6394
6395 pp->posz = loz - PLAYER_DEATH_HEIGHT;
6396 RESET(pp->Flags, PF_FALLING);
6397 }
6398 }
6399 }
6400
6401 #define MAX_SUICIDE 11
6402 char *SuicideNote[MAX_SUICIDE] = {
6403 "decided to do the graveyard tour.",
6404 "had enough and checked out.",
6405 "didn't fear the Reaper.",
6406 "dialed the 1-800-CYANIDE line.",
6407 "wasted himself.",
6408 "kicked his own ass.",
6409 "went out in blaze of his own glory.",
6410 "killed himself before anyone else could.",
6411 "needs shooting lessons.",
6412 "blew his head off.",
6413 "did everyone a favor and offed himself."
6414 };
6415
KilledPlayerMessage(PLAYERp pp,PLAYERp killer)6416 char *KilledPlayerMessage(PLAYERp pp, PLAYERp killer)
6417 {
6418 #define MAX_KILL_NOTES 16
6419 short rnd = STD_RANDOM_RANGE(MAX_KILL_NOTES);
6420 char *p1 = pp->PlayerName;
6421 char *p2 = killer->PlayerName;
6422
6423 extern char *DeathString(short SpriteNum);
6424
6425 if (pp->HitBy == killer->PlayerSprite)
6426 {
6427 sprintf(ds,"%s was killed by %s.",p1,p2);
6428 return(ds);
6429 } else
6430 switch (rnd)
6431 {
6432 case 0:
6433 sprintf(ds,"%s was wasted by %s's %s.",p1,p2,DeathString(pp->HitBy));
6434 return(ds);
6435 case 1:
6436 sprintf(ds,"%s got his ass kicked by %s's %s.",p1,p2,DeathString(pp->HitBy));
6437 return(ds);
6438 case 2:
6439 sprintf(ds,"%s bows down before the mighty power of %s.",p1,p2);
6440 return(ds);
6441 case 3:
6442 sprintf(ds,"%s was killed by %s's %s.",p1,p2,DeathString(pp->HitBy));
6443 return(ds);
6444 case 4:
6445 sprintf(ds,"%s got slapped down hard by %s's %s.",p1,p2,DeathString(pp->HitBy));
6446 return(ds);
6447 case 5:
6448 sprintf(ds,"%s got on his knees before %s.",p1,p2);
6449 return(ds);
6450 case 6:
6451 sprintf(ds,"%s was totally out classed by %s's %s.",p1,p2,DeathString(pp->HitBy));
6452 return(ds);
6453 case 7:
6454 sprintf(ds,"%s got chewed apart by %s's %s.",p1,p2,DeathString(pp->HitBy));
6455 return(ds);
6456 case 8:
6457 sprintf(ds,"%s was retired by %s's %s.",p1,p2,DeathString(pp->HitBy));
6458 return(ds);
6459 case 9:
6460 sprintf(ds,"%s was greased by %s's %s.",p1,p2,DeathString(pp->HitBy));
6461 return(ds);
6462 case 10:
6463 sprintf(ds,"%s was humbled lower than dirt by %s.",p1,p2);
6464 return(ds);
6465 case 11:
6466 sprintf(ds,"%s beats %s like a red headed step child.",p2,p1);
6467 return(ds);
6468 case 12:
6469 sprintf(ds,"%s begs for mercy as %s terminates him with extreme prejudice.",p1,p2);
6470 return(ds);
6471 case 13:
6472 sprintf(ds,"%s falls before the superior skills of %s.",p1,p2);
6473 return(ds);
6474 case 14:
6475 sprintf(ds,"%s gives %s a beating he'll never forget.",p2,p1);
6476 return(ds);
6477 case 15:
6478 sprintf(ds,"%s puts the Smack Dab on %s with his %s.",p2,p1,DeathString(pp->HitBy));
6479 return(ds);
6480 }
6481 return(NULL);
6482 };
6483
6484 VOID
DoPlayerDeathMessage(PLAYERp pp,PLAYERp killer)6485 DoPlayerDeathMessage(PLAYERp pp, PLAYERp killer)
6486 {
6487 int pnum;
6488 short i;
6489 BOOL SEND_OK = FALSE;
6490
6491 killer->KilledPlayer[pp-Player]++;
6492
6493 if (pp == killer && pp == Player + myconnectindex)
6494 {
6495 sprintf(ds,"%s %s",pp->PlayerName,SuicideNote[STD_RANDOM_RANGE(MAX_SUICIDE)]);
6496 SEND_OK = TRUE;
6497 } else
6498 // I am being killed
6499 if (killer == Player + myconnectindex)
6500 {
6501 sprintf(ds,"%s",KilledPlayerMessage(pp,killer));
6502 SEND_OK = TRUE;
6503 }
6504
6505 if (SEND_OK)
6506 {
6507 TRAVERSE_CONNECT(pnum)
6508 {
6509 if (pnum == myconnectindex)
6510 adduserquote(ds);
6511 else
6512 SendMessage(pnum, ds);
6513 }
6514 }
6515
6516 }
6517
6518
6519 VOID
DoPlayerBeginDie(PLAYERp pp)6520 DoPlayerBeginDie(PLAYERp pp)
6521 {
6522 extern BOOL ReloadPrompt;
6523 VOID KillAllPanelInv(PLAYERp pp);
6524 VOID DoPlayerDeathDrown(PLAYERp pp);
6525 VOID pWeaponForceRest(PLAYERp pp);
6526 short bak;
6527 int choosesnd = 0;
6528 extern short GlobInfoStringTime;
6529 extern short QuickLoadNum;
6530
6531 USERp u = User[pp->PlayerSprite];
6532
6533 static VOID (*PlayerDeathFunc[MAX_PLAYER_DEATHS])(PLAYERp) =
6534 {
6535 DoPlayerDeathFlip,
6536 DoPlayerDeathCrumble,
6537 DoPlayerDeathExplode,
6538 DoPlayerDeathFlip,
6539 DoPlayerDeathExplode,
6540 DoPlayerDeathDrown,
6541 };
6542
6543 short random;
6544
6545 #define PLAYER_DEATH_TILT_VALUE (32)
6546 #define PLAYER_DEATH_HORIZ_UP_VALUE (165)
6547 #define PLAYER_DEATH_HORIZ_JUMP_VALUE (150)
6548 #define PLAYER_DEATH_HORIZ_FALL_VALUE (50)
6549
6550 if (Prediction)
6551 return;
6552
6553 if (GodMode)
6554 return;
6555
6556 // Override any previous talking, death scream has precedance
6557 if (pp->PlayerTalking)
6558 {
6559 if (FX_SoundActive(pp->TalkVocHandle))
6560 FX_StopSound(pp->TalkVocHandle);
6561 pp->PlayerTalking = FALSE;
6562 pp->TalkVocnum = -1;
6563 pp->TalkVocHandle = -1;
6564 }
6565
6566 // Do the death scream
6567 choosesnd = RANDOM_RANGE(MAX_PAIN);
6568
6569 PlayerSound(PlayerLowHealthPainVocs[choosesnd],&pp->posx,
6570 &pp->posy,&pp->posy,v3df_dontpan|v3df_doppler|v3df_follow,pp);
6571
6572 if (!CommEnabled && CommPlayers <= 1 && QuickLoadNum >= 0)
6573 {
6574 ReloadPrompt = TRUE;
6575 }
6576 else
6577 {
6578 bak = GlobInfoStringTime;
6579 GlobInfoStringTime = 999;
6580 PutStringInfo(pp, "Press SPACE to restart");
6581 GlobInfoStringTime = bak;
6582 }
6583
6584 FLAG_KEY_RELEASE(pp, SK_SPACE_BAR);
6585
6586 if (pp->sop_control)
6587 DoPlayerStopOperate(pp);
6588
6589 // if diving force death to drown type
6590 if (TEST(pp->Flags, PF_DIVING))
6591 pp->DeathType = PLAYER_DEATH_DROWN;
6592
6593 RESET(pp->Flags, PF_JUMPING|PF_FALLING|PF_DIVING|PF_FLYING|PF_CLIMBING|PF_CRAWLING|PF_LOCK_CRAWL);
6594
6595 #if 0
6596 // get tilt value
6597 random = RANDOM_P2(1024);
6598 if (random < 128)
6599 pp->tilt_dest = 0;
6600 else
6601 if (random < 512+64)
6602 pp->tilt_dest = PLAYER_DEATH_TILT_VALUE;
6603 else
6604 pp->tilt_dest = -PLAYER_DEATH_TILT_VALUE;
6605 #else
6606 pp->tilt_dest = 0;
6607 #endif
6608
6609 ActorCoughItem(pp->PlayerSprite);
6610
6611 if (CommPlayers > 1)
6612 {
6613 // Give kill credit to player if necessary
6614 if (pp->Killer >= 0)
6615 {
6616 USERp ku = User[pp->Killer];
6617
6618 ASSERT(ku);
6619
6620 if (ku && ku->PlayerP)
6621 {
6622 if (pp == ku->PlayerP)
6623 {
6624 // Killed yourself
6625 PlayerUpdateKills(pp, -1);
6626 DoPlayerDeathMessage(pp, pp);
6627 }
6628 else
6629 {
6630 // someone else killed you
6631 if (gNet.TeamPlay)
6632 {
6633 // playing team play
6634 if (User[pp->PlayerSprite]->spal == ku->spal)
6635 {
6636 // Killed your team member
6637 PlayerUpdateKills(pp, -1);
6638 DoPlayerDeathMessage(pp, ku->PlayerP);
6639 }
6640 else
6641 {
6642 // killed another team member
6643 PlayerUpdateKills(ku->PlayerP, 1);
6644 DoPlayerDeathMessage(pp, ku->PlayerP);
6645 }
6646 }
6647 else
6648 {
6649 // not playing team play
6650 PlayerUpdateKills(ku->PlayerP, 1);
6651 DoPlayerDeathMessage(pp, ku->PlayerP);
6652 }
6653 }
6654 }
6655 }
6656 else
6657 {
6658 // Killed by some hazard - negative frag
6659 PlayerUpdateKills(pp, -1);
6660 DoPlayerDeathMessage(pp, pp);
6661 }
6662 }
6663
6664
6665 // Get rid of all panel spells that are currently working
6666 KillAllPanelInv(pp);
6667
6668 SET(pp->Flags, PF_LOCK_HORIZ);
6669
6670 pp->friction = PLAYER_RUN_FRICTION;
6671 pp->slide_xvect = pp->slide_yvect = 0;
6672 pp->floor_dist = PLAYER_WADE_FLOOR_DIST;
6673 pp->ceiling_dist = PLAYER_WADE_CEILING_DIST;
6674 ASSERT(pp->DeathType < SIZ(PlayerDeathFunc));
6675 pp->DoPlayerAction = PlayerDeathFunc[pp->DeathType];
6676 pp->sop_control = NULL;
6677 pp->sop_remote = NULL;
6678 pp->sop_riding = NULL;
6679 pp->sop = NULL;
6680 RESET(pp->Flags, PF_TWO_UZI);
6681
6682 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Run);
6683 pWeaponForceRest(pp);
6684
6685 switch (pp->DeathType)
6686 {
6687 case PLAYER_DEATH_DROWN:
6688 {
6689 SET(pp->Flags, PF_JUMPING);
6690 u->ID = NINJA_DEAD;
6691 pp->jump_speed = -200;
6692 NewStateGroup(pp->PlayerSprite, sg_PlayerDeath);
6693 DoFindGround(pp->PlayerSprite);
6694 DoBeginJump(pp->PlayerSprite);
6695 u->jump_speed = -300;
6696 break;
6697 }
6698 case PLAYER_DEATH_FLIP:
6699 case PLAYER_DEATH_RIPPER:
6700
6701 //PlaySound(DIGI_SCREAM1, &pp->posx, &pp->posy, &pp->posz, v3df_dontpan|v3df_follow);
6702
6703 SET(pp->Flags, PF_JUMPING);
6704 u->ID = NINJA_DEAD;
6705 pp->jump_speed = -300;
6706 NewStateGroup(pp->PlayerSprite, sg_PlayerDeath);
6707 //pp->ceiling_dist = Z(0);
6708 //pp->floor_dist = Z(0);
6709
6710 RESET(pp->SpriteP->cstat, CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_BLOCK_HITSCAN);
6711 u->ceiling_dist = Z(10);
6712 u->floor_dist = Z(0);
6713 DoFindGround(pp->PlayerSprite);
6714 DoBeginJump(pp->PlayerSprite);
6715 u->jump_speed = -400;
6716 break;
6717 case PLAYER_DEATH_CRUMBLE:
6718
6719 PlaySound(DIGI_BODYSQUISH1, &pp->posx, &pp->posy, &pp->posz, v3df_dontpan);
6720
6721 SET(pp->Flags, PF_DEAD_HEAD | PF_JUMPING);
6722 pp->jump_speed = -300;
6723 u->slide_vel = 0;
6724 SpawnShrap(pp->PlayerSprite,-1);
6725 SET(pp->SpriteP->cstat, CSTAT_SPRITE_YCENTER);
6726 NewStateGroup(pp->PlayerSprite, sg_PlayerHeadFly);
6727 u->ID = NINJA_Head_R0;
6728 pp->SpriteP->xrepeat = 48;
6729 pp->SpriteP->yrepeat = 48;
6730 // Blood fountains
6731 InitBloodSpray(pp->PlayerSprite,TRUE,105);
6732 break;
6733 case PLAYER_DEATH_EXPLODE:
6734
6735 PlaySound(DIGI_BODYSQUISH1, &pp->posx, &pp->posy, &pp->posz, v3df_dontpan);
6736
6737 SET(pp->Flags, PF_DEAD_HEAD | PF_JUMPING);
6738 pp->jump_speed = -650;
6739 SpawnShrap(pp->PlayerSprite,-1);
6740 SET(pp->SpriteP->cstat, CSTAT_SPRITE_YCENTER);
6741 NewStateGroup(pp->PlayerSprite, sg_PlayerHeadFly);
6742 u->ID = NINJA_Head_R0;
6743 pp->SpriteP->xrepeat = 48;
6744 pp->SpriteP->yrepeat = 48;
6745 // Blood fountains
6746 InitBloodSpray(pp->PlayerSprite,TRUE,-1);
6747 InitBloodSpray(pp->PlayerSprite,TRUE,-1);
6748 InitBloodSpray(pp->PlayerSprite,TRUE,-1);
6749 break;
6750 case PLAYER_DEATH_SQUISH:
6751
6752 PlaySound(DIGI_BODYCRUSHED1, &pp->posx, &pp->posy, &pp->posz, v3df_dontpan);
6753
6754 SET(pp->Flags, PF_DEAD_HEAD | PF_JUMPING);
6755 pp->jump_speed = 200;
6756 u->slide_vel = 800;
6757 SpawnShrap(pp->PlayerSprite, -1);
6758 SET(pp->SpriteP->cstat, CSTAT_SPRITE_YCENTER);
6759 NewStateGroup(pp->PlayerSprite, sg_PlayerHeadFly);
6760 u->ID = NINJA_Head_R0;
6761 pp->SpriteP->xrepeat = 48;
6762 pp->SpriteP->yrepeat = 48;
6763 // Blood fountains
6764 InitBloodSpray(pp->PlayerSprite,TRUE,105);
6765 break;
6766
6767 }
6768
6769 SET(pp->Flags, PF_DEAD);
6770 RESET(u->Flags,SPR_BOUNCE);
6771 RESET(pp->Flags, PF_HEAD_CONTROL);
6772 }
6773
6774 int
DoPlayerDeathHoriz(PLAYERp pp,short target,short speed)6775 DoPlayerDeathHoriz(PLAYERp pp, short target, short speed)
6776 {
6777 if (pp->horiz > target)
6778 {
6779 pp->horiz -= speed;
6780 if (pp->horiz <= target)
6781 pp->horiz = target;
6782 }
6783
6784 if (pp->horiz < target)
6785 {
6786 pp->horiz += speed;
6787 if (pp->horiz >= target)
6788 pp->horiz = target;
6789 }
6790
6791 return(pp->horiz == target);
6792 }
6793
6794 int
DoPlayerDeathTilt(PLAYERp pp,short target,short speed)6795 DoPlayerDeathTilt(PLAYERp pp, short target, short speed)
6796 {
6797 if (pp->tilt > target)
6798 {
6799 pp->tilt -= speed;
6800 if (pp->tilt <= target)
6801 pp->tilt = target;
6802 }
6803
6804 if (pp->tilt < target)
6805 {
6806 pp->tilt += speed;
6807 if (pp->tilt >= target)
6808 pp->tilt = target;
6809 }
6810
6811 return(pp->tilt == target);
6812 }
6813
6814
6815 VOID
DoPlayerDeathZrange(PLAYERp pp)6816 DoPlayerDeathZrange(PLAYERp pp)
6817 {
6818 SPRITEp sp = pp->SpriteP;
6819 USERp u = User[pp->PlayerSprite];
6820
6821 // make sure we don't land on a regular sprite
6822 DoFindGround(pp->PlayerSprite);
6823
6824 // update player values with results from DoFindGround
6825 // pp->hiz = u->hiz;
6826 pp->loz = u->loz;
6827 pp->lo_sp = u->lo_sp;
6828 //pp->hi_sp = u->hi_sp;
6829 pp->lo_sectp = u->lo_sectp;
6830 //pp->hi_sectp = u->hi_sectp;
6831 }
6832
DoPlayerDeathHurl(PLAYERp pp)6833 VOID DoPlayerDeathHurl(PLAYERp pp)
6834 {
6835 SPRITEp sp = pp->SpriteP;
6836 USERp u = User[pp->PlayerSprite];
6837
6838 if (CommPlayers > 1)
6839 {
6840 if (TEST_SYNC_KEY(pp, SK_SHOOT))
6841 {
6842 if (FLAG_KEY_PRESSED(pp, SK_SHOOT))
6843 {
6844
6845
6846 SET(pp->Flags, PF_HEAD_CONTROL);
6847 NewStateGroup(pp->PlayerSprite, sg_PlayerHeadHurl);
6848 if (MoveSkip4 == 0)
6849 {
6850 SpawnShrap(pp->PlayerSprite, -1);
6851 if(RANDOM_RANGE(1000) > 400)
6852 PlayerSound(DIGI_DHVOMIT, &pp->posx, &pp->posy, &pp->posz, v3df_dontpan|v3df_follow,pp);
6853 }
6854 return;
6855 }
6856 }
6857 }
6858
6859 if (!TEST(pp->Flags, PF_JUMPING|PF_FALLING))
6860 NewStateGroup(pp->PlayerSprite, sg_PlayerHead);
6861 }
6862
6863
DoPlayerDeathFollowKiller(PLAYERp pp)6864 VOID DoPlayerDeathFollowKiller(PLAYERp pp)
6865 {
6866 SPRITEp sp = pp->SpriteP;
6867 USERp u = User[pp->PlayerSprite];
6868
6869 // if it didn't make it to this angle because of a low ceiling or something
6870 // continue on to it
6871 DoPlayerDeathHoriz(pp, PLAYER_DEATH_HORIZ_UP_VALUE, 4);
6872 //DoPlayerDeathTilt(pp, pp->tilt_dest, 4 * synctics);
6873
6874 // allow turning
6875 if ((TEST(pp->Flags, PF_DEAD_HEAD) && pp->input.angvel != 0) || TEST(pp->Flags, PF_HEAD_CONTROL))
6876 {
6877 // Allow them to turn fast
6878 PLAYER_RUN_LOCK(pp);
6879
6880 DoPlayerTurn(pp);
6881 return;
6882 }
6883
6884 // follow what killed you if its available
6885 if (pp->Killer > -1)
6886 {
6887 SPRITEp kp = &sprite[pp->Killer];
6888 short ang2,delta_ang;
6889
6890 if (FAFcansee(kp->x, kp->y, SPRITEp_TOS(kp), kp->sectnum,
6891 pp->posx, pp->posy, pp->posz, pp->cursectnum))
6892 {
6893 ang2 = getangle(kp->x - pp->posx, kp->y - pp->posy);
6894
6895 delta_ang = GetDeltaAngle(ang2, pp->pang);
6896 pp->pang = NORM_ANGLE(pp->pang + (delta_ang >> 4));
6897 }
6898 }
6899 }
6900
DoPlayerDeathCheckKeys(PLAYERp pp)6901 VOID DoPlayerDeathCheckKeys(PLAYERp pp)
6902 {
6903 SPRITEp sp = pp->SpriteP;
6904 USERp u = User[pp->PlayerSprite];
6905 extern BOOL DemoMode,DemoDone;
6906 extern BOOL InputMode;
6907
6908 //if (TEST_SYNC_KEY(pp, SK_OPERATE))
6909 if (!TEST_SYNC_KEY(pp, SK_SPACE_BAR))
6910 FLAG_KEY_RESET(pp, SK_SPACE_BAR);
6911 else
6912 if (FLAG_KEY_PRESSED(pp, SK_SPACE_BAR))
6913 {
6914 FLAG_KEY_RELEASE(pp, SK_SPACE_BAR);
6915
6916 // Spawn a dead LoWang body for non-head deaths
6917 // Hey Frank, if you think of a better check, go ahead and put it in.
6918 if (PlayerFloorHit(pp, pp->loz - PLAYER_HEIGHT))
6919 {
6920 if(pp->DeathType == PLAYER_DEATH_FLIP || pp->DeathType == PLAYER_DEATH_RIPPER)
6921 QueueLoWangs(pp->PlayerSprite);
6922 } else
6923 { // If he's not on the floor, then gib like a mo-fo!
6924 InitBloodSpray(pp->PlayerSprite,TRUE,-1);
6925 InitBloodSpray(pp->PlayerSprite,TRUE,-1);
6926 InitBloodSpray(pp->PlayerSprite,TRUE,-1);
6927 }
6928
6929 pClearTextLine(pp, TEXT_INFO_LINE(0));
6930
6931 PlayerSpawnPosition(pp);
6932
6933 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Stand);
6934 pp->SpriteP->picnum = u->State->Pic;
6935 pp->SpriteP->xrepeat = pp->SpriteP->yrepeat = PLAYER_NINJA_XREPEAT;
6936 RESET(pp->SpriteP->cstat, CSTAT_SPRITE_YCENTER);
6937 pp->SpriteP->x = pp->posx;
6938 pp->SpriteP->y = pp->posy;
6939 pp->SpriteP->z = pp->posz+PLAYER_HEIGHT;
6940 pp->SpriteP->ang = pp->pang;
6941
6942 DoSpawnTeleporterEffect(pp->SpriteP);
6943 PlaySound(DIGI_TELEPORT, &pp->posx, &pp->posy, &pp->posz, v3df_none);
6944
6945 DoPlayerZrange(pp);
6946
6947 pp->sop_control = NULL;
6948 pp->sop_remote = NULL;
6949 pp->sop_riding = NULL;
6950 pp->sop = NULL;
6951
6952 RESET(pp->Flags, PF_WEAPON_DOWN|PF_WEAPON_RETRACT);
6953 RESET(pp->Flags, PF_DEAD);
6954 RESET(pp->Flags, PF_LOCK_HORIZ);
6955 RESET(sp->cstat, CSTAT_SPRITE_YCENTER);
6956 SET(sp->cstat, CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_BLOCK_HITSCAN);
6957 sp->xrepeat = PLAYER_NINJA_XREPEAT;
6958 sp->yrepeat = PLAYER_NINJA_YREPEAT;
6959
6960 //pp->tilt = 0;
6961 pp->horiz = pp->horizbase = 100;
6962 DoPlayerResetMovement(pp);
6963 u->ID = NINJA_RUN_R0;
6964 PlayerDeathReset(pp);
6965
6966 if(pp == Player + screenpeek)
6967 {
6968 #if USE_POLYMOST && USE_OPENGL
6969 if (getrendermode() >= 3)
6970 {
6971 setpalettefade(0,0,0,0);
6972 }
6973 else
6974 #endif
6975 {
6976 COVERsetbrightness(gs.Brightness,&palette_data[0][0]);
6977 }
6978 //memcpy(&palette_data[0][0],&palette_data[0][0],768);
6979 memcpy(&pp->temp_pal[0],&palette_data[0][0],768);
6980 }
6981
6982 pp->NightVision = FALSE;
6983 pp->FadeAmt = 0;
6984 DoPlayerDivePalette(pp);
6985 DoPlayerNightVisionPalette(pp);
6986
6987 if (CommPlayers > 1)
6988 {
6989 // need to call this routine BEFORE resetting DEATH flag
6990 DoPlayerBeginRun(pp);
6991 }
6992 else
6993 {
6994 // restart the level in single play
6995 if (DemoMode)
6996 DemoDone = TRUE;
6997 else
6998 ExitLevel = TRUE;
6999 }
7000
7001 DoPlayerFireOutDeath(pp);
7002 }
7003 }
7004
7005 VOID
DoPlayerHeadDebris(PLAYERp pp)7006 DoPlayerHeadDebris(PLAYERp pp)
7007 {
7008 SECTORp sectp = §or[pp->cursectnum];
7009
7010 if (TEST(sectp->extra, SECTFX_SINK))
7011 {
7012 DoPlayerSpriteBob(pp, Z(8), Z(4), 3);
7013 }
7014 else
7015 {
7016 pp->bob_amt = 0;
7017 }
7018 }
7019
DoPlayerDeathCheckKick(PLAYERp pp)7020 SPRITEp DoPlayerDeathCheckKick(PLAYERp pp)
7021 {
7022 SPRITEp sp = pp->SpriteP, hp;
7023 USERp u = User[pp->PlayerSprite], hu;
7024 short i,nexti;
7025 unsigned stat,dist;
7026 int a,b,c;
7027
7028 for (stat = 0; stat < SIZ(StatDamageList); stat++)
7029 {
7030 TRAVERSE_SPRITE_STAT(headspritestat[StatDamageList[stat]], i, nexti)
7031 {
7032 hp = &sprite[i];
7033 hu = User[i];
7034
7035 if (i == pp->PlayerSprite)
7036 break;
7037
7038 // don't set off mine
7039 if (!TEST(hp->extra, SPRX_PLAYER_OR_ENEMY))
7040 continue;
7041
7042 DISTANCE(hp->x, hp->y, sp->x, sp->y, dist, a, b, c);
7043
7044 if (dist < hu->Radius + 100)
7045 {
7046 pp->Killer = i;
7047
7048 u->slide_ang = getangle(sp->x - hp->x, sp->y - hp->y);
7049 u->slide_ang = NORM_ANGLE(u->slide_ang + (RANDOM_P2(128<<5)>>5) - 64);
7050
7051 u->slide_vel = hp->xvel<<1;
7052 RESET(u->Flags,SPR_BOUNCE);
7053 pp->jump_speed = -500;
7054 NewStateGroup(pp->PlayerSprite, sg_PlayerHeadFly);
7055 SET(pp->Flags, PF_JUMPING);
7056 SpawnShrap(pp->PlayerSprite, -1);
7057 return(hp);
7058 }
7059 }
7060 }
7061
7062 DoPlayerZrange(pp);
7063
7064 // sector stomper kick
7065 if (labs(pp->loz - pp->hiz) < SPRITEp_SIZE_Z(pp->SpriteP) - Z(8))
7066 {
7067 u->slide_ang = RANDOM_P2(2048);
7068 u->slide_vel = 1000;
7069 RESET(u->Flags,SPR_BOUNCE);
7070 pp->jump_speed = -100;
7071 NewStateGroup(pp->PlayerSprite, sg_PlayerHeadFly);
7072 SET(pp->Flags, PF_JUMPING);
7073 SpawnShrap(pp->PlayerSprite, -1);
7074 return(NULL);
7075 }
7076
7077 return(NULL);
7078 }
7079
7080
DoPlayerDeathMoveHead(PLAYERp pp)7081 void DoPlayerDeathMoveHead(PLAYERp pp)
7082 {
7083 SPRITEp sp = pp->SpriteP, hp;
7084 USERp u = User[pp->PlayerSprite], hu;
7085 int dax,day;
7086 short sectnum;
7087
7088 dax = MOVEx(u->slide_vel, u->slide_ang);
7089 day = MOVEy(u->slide_vel, u->slide_ang);
7090
7091 if ((u->ret = move_sprite(pp->PlayerSprite, dax, day, 0, Z(16), Z(16), 1, synctics)))
7092 {
7093 switch (TEST(u->ret, HIT_MASK))
7094 {
7095 case HIT_SPRITE:
7096 {
7097 short wall_ang, dang;
7098 short hitsprite = -2;
7099 SPRITEp hsp;
7100
7101 //PlaySound(DIGI_DHCLUNK, &pp->posx, &pp->posy, &pp->posz, v3df_dontpan);
7102
7103 hitsprite = NORM_SPRITE(u->ret);
7104 hsp = &sprite[hitsprite];
7105
7106 if (!TEST(hsp->cstat, CSTAT_SPRITE_WALL))
7107 break;
7108
7109
7110 wall_ang = NORM_ANGLE(hsp->ang);
7111 dang = GetDeltaAngle(u->slide_ang, wall_ang);
7112 u->slide_ang = NORM_ANGLE(wall_ang + 1024 - dang);
7113
7114 SpawnShrap(pp->PlayerSprite, -1);
7115 break;
7116 }
7117 case HIT_WALL:
7118 {
7119 short hitwall,w,nw,wall_ang,dang;
7120
7121 //PlaySound(DIGI_DHCLUNK, &pp->posx, &pp->posy, &pp->posz, v3df_dontpan);
7122
7123 hitwall = NORM_WALL(u->ret);
7124
7125 w = hitwall;
7126 nw = wall[w].point2;
7127 wall_ang = NORM_ANGLE(getangle(wall[nw].x - wall[w].x, wall[nw].y - wall[w].y)-512);
7128
7129 dang = GetDeltaAngle(u->slide_ang, wall_ang);
7130 u->slide_ang = NORM_ANGLE(wall_ang + 1024 - dang);
7131
7132 SpawnShrap(pp->PlayerSprite, -1);
7133 break;
7134 }
7135 }
7136 }
7137
7138 pp->posx = sp->x;
7139 pp->posy = sp->y;
7140 pp->cursectnum = sp->sectnum;
7141
7142 // try to stay in valid area - death sometimes throws you out of the map
7143 sectnum = pp->cursectnum;
7144 COVERupdatesector(pp->posx, pp->posy, §num);
7145 if (sectnum < 0)
7146 {
7147 pp->cursectnum = pp->lv_sectnum;
7148 changespritesect(pp->PlayerSprite, pp->lv_sectnum);
7149 pp->posx = sp->x = pp->lv_x;
7150 pp->posy = sp->y = pp->lv_y;
7151 }
7152 else
7153 {
7154 pp->lv_sectnum = sectnum;
7155 pp->lv_x = pp->posx;
7156 pp->lv_y = pp->posy;
7157 }
7158 }
7159
DoPlayerDeathFlip(PLAYERp pp)7160 VOID DoPlayerDeathFlip(PLAYERp pp)
7161 {
7162 SPRITEp sp = pp->SpriteP;
7163 USERp u = User[pp->PlayerSprite];
7164
7165 if (Prediction)
7166 return;
7167
7168 DoPlayerDeathZrange(pp);
7169
7170 if (TEST(pp->Flags,PF_JUMPING|PF_FALLING))
7171 {
7172 if (TEST(pp->Flags,PF_JUMPING))
7173 {
7174 DoPlayerDeathJump(pp);
7175 DoPlayerDeathHoriz(pp, PLAYER_DEATH_HORIZ_UP_VALUE, 2);
7176 if (MoveSkip2 == 0)
7177 DoJump(pp->PlayerSprite);
7178 }
7179
7180 if (TEST(pp->Flags,PF_FALLING))
7181 {
7182 DoPlayerDeathFall(pp);
7183 DoPlayerDeathHoriz(pp, PLAYER_DEATH_HORIZ_UP_VALUE, 4);
7184 if (MoveSkip2 == 0)
7185 DoFall(pp->PlayerSprite);
7186 }
7187 }
7188 else
7189 {
7190 DoPlayerDeathFollowKiller(pp);
7191 }
7192
7193 DoPlayerDeathCheckKeys(pp);
7194 }
7195
7196
7197
DoPlayerDeathDrown(PLAYERp pp)7198 VOID DoPlayerDeathDrown(PLAYERp pp)
7199 {
7200 SPRITEp sp = pp->SpriteP;
7201 USERp u = User[pp->PlayerSprite];
7202
7203 if (Prediction)
7204 return;
7205
7206 DoPlayerDeathZrange(pp);
7207
7208 if (TEST(pp->Flags,PF_JUMPING|PF_FALLING))
7209 {
7210 if (TEST(pp->Flags,PF_JUMPING))
7211 {
7212 DoPlayerDeathJump(pp);
7213 DoPlayerDeathHoriz(pp, PLAYER_DEATH_HORIZ_UP_VALUE, 2);
7214 if (MoveSkip2 == 0)
7215 DoJump(pp->PlayerSprite);
7216 }
7217
7218 if (TEST(pp->Flags,PF_FALLING))
7219 {
7220 pp->posz += Z(2);
7221 if (MoveSkip2 == 0)
7222 sp->z += Z(4);
7223
7224 // Stick like glue when you hit the ground
7225 if (pp->posz > pp->loz - PLAYER_DEATH_HEIGHT)
7226 {
7227 pp->posz = pp->loz - PLAYER_DEATH_HEIGHT;
7228 RESET(pp->Flags, PF_FALLING);
7229 }
7230 }
7231 }
7232
7233 DoPlayerDeathFollowKiller(pp);
7234 DoPlayerDeathCheckKeys(pp);
7235 }
7236
7237
DoPlayerDeathBounce(PLAYERp pp)7238 VOID DoPlayerDeathBounce(PLAYERp pp)
7239 {
7240 SPRITEp sp = pp->SpriteP;
7241 USERp u = User[pp->PlayerSprite];
7242
7243 if (Prediction)
7244 return;
7245
7246 if (pp->lo_sectp && TEST(pp->lo_sectp->extra, SECTFX_SINK))
7247 {
7248 int loz;
7249
7250 RESET(sp->cstat, CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_BLOCK_HITSCAN);
7251 NewStateGroup(pp->PlayerSprite, sg_PlayerHead);
7252 u->slide_vel = 0;
7253 SET(u->Flags, SPR_BOUNCE);
7254
7255 if (pp->lo_sectp && TEST(pp->lo_sectp->extra, SECTFX_SINK))
7256 {
7257 loz = pp->lo_sectp->floorz - Z(SectUser[pp->lo_sectp - sector]->depth);
7258 }
7259 else
7260 loz = pp->loz;
7261
7262
7263 return;
7264 }
7265
7266 SET(u->Flags, SPR_BOUNCE);
7267 pp->jump_speed = -300;
7268 u->slide_vel >>= 2;
7269 u->slide_ang = NORM_ANGLE((RANDOM_P2(64<<8)>>8) - 32);
7270 SET(pp->Flags, PF_JUMPING);
7271 SpawnShrap(pp->PlayerSprite, -1);
7272 }
7273
7274
7275
7276
DoPlayerDeathCrumble(PLAYERp pp)7277 VOID DoPlayerDeathCrumble(PLAYERp pp)
7278 {
7279 SPRITEp sp = pp->SpriteP;
7280 USERp u = User[pp->PlayerSprite];
7281
7282 if (Prediction)
7283 return;
7284
7285 DoPlayerDeathZrange(pp);
7286
7287 if (TEST(pp->Flags,PF_JUMPING|PF_FALLING))
7288 {
7289 if (TEST(pp->Flags,PF_JUMPING))
7290 {
7291 DoPlayerDeathJump(pp);
7292 DoPlayerDeathHoriz(pp, PLAYER_DEATH_HORIZ_JUMP_VALUE, 4);
7293 }
7294
7295 if (TEST(pp->Flags,PF_FALLING))
7296 {
7297 DoPlayerDeathFall(pp);
7298 DoPlayerDeathHoriz(pp, PLAYER_DEATH_HORIZ_FALL_VALUE, 3);
7299 }
7300
7301 if (!TEST(pp->Flags,PF_JUMPING|PF_FALLING))
7302 {
7303 if (!TEST(u->Flags, SPR_BOUNCE))
7304 {
7305 DoPlayerDeathBounce(pp);
7306 return;
7307 }
7308
7309 RESET(sp->cstat, CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_BLOCK_HITSCAN);
7310 NewStateGroup(pp->PlayerSprite, sg_PlayerHead);
7311 }
7312 else
7313 {
7314 DoPlayerDeathMoveHead(pp);
7315 }
7316 }
7317 else
7318 {
7319 DoPlayerDeathCheckKick(pp);
7320 DoPlayerDeathHurl(pp);
7321 DoPlayerDeathFollowKiller(pp);
7322 //pp->posz = pp->loz - PLAYER_DEATH_HEIGHT;
7323 }
7324
7325 DoPlayerDeathCheckKeys(pp);
7326 sp->z = pp->posz+PLAYER_DEAD_HEAD_FLOORZ_OFFSET;
7327 DoPlayerHeadDebris(pp);
7328 }
7329
DoPlayerDeathExplode(PLAYERp pp)7330 VOID DoPlayerDeathExplode(PLAYERp pp)
7331 {
7332 SPRITEp sp = pp->SpriteP;
7333 USERp u = User[pp->PlayerSprite];
7334
7335 if (Prediction)
7336 return;
7337
7338 DoPlayerDeathZrange(pp);
7339
7340 if (TEST(pp->Flags,PF_JUMPING|PF_FALLING))
7341 {
7342 if (TEST(pp->Flags,PF_JUMPING))
7343 {
7344 DoPlayerDeathJump(pp);
7345 DoPlayerDeathHoriz(pp, PLAYER_DEATH_HORIZ_JUMP_VALUE, 4);
7346 }
7347
7348 if (TEST(pp->Flags,PF_FALLING))
7349 {
7350 DoPlayerDeathFall(pp);
7351 DoPlayerDeathHoriz(pp, PLAYER_DEATH_HORIZ_JUMP_VALUE, 3);
7352 }
7353
7354 if (!TEST(pp->Flags,PF_JUMPING|PF_FALLING))
7355 {
7356 if (!TEST(u->Flags, SPR_BOUNCE))
7357 {
7358 DoPlayerDeathBounce(pp);
7359 return;
7360 }
7361
7362 RESET(sp->cstat, CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_BLOCK_HITSCAN);
7363 NewStateGroup(pp->PlayerSprite, sg_PlayerHead);
7364 }
7365 else
7366 {
7367 DoPlayerDeathMoveHead(pp);
7368 }
7369 }
7370 else
7371 {
7372 // special line for amoeba
7373 //COVERupdatesector(pp->posx, pp->posy, &pp->cursectnum);
7374
7375 DoPlayerDeathCheckKick(pp);
7376 DoPlayerDeathHurl(pp);
7377 DoPlayerDeathFollowKiller(pp);
7378 //pp->posz = pp->loz - PLAYER_DEATH_HEIGHT;
7379 }
7380
7381 DoPlayerDeathCheckKeys(pp);
7382 sp->z = pp->posz+PLAYER_DEAD_HEAD_FLOORZ_OFFSET;
7383 DoPlayerHeadDebris(pp);
7384 }
7385
7386 VOID
DoPlayerBeginRun(PLAYERp pp)7387 DoPlayerBeginRun(PLAYERp pp)
7388 {
7389 USERp u = User[pp->PlayerSprite];
7390
7391 // Crawl if in small aread automatically
7392 if (DoPlayerTestCrawl(pp))
7393 {
7394 DoPlayerBeginCrawl(pp);
7395 return;
7396 }
7397
7398 RESET(pp->Flags, PF_CRAWLING|PF_JUMPING|PF_FALLING|PF_LOCK_CRAWL|PF_CLIMBING);
7399
7400 if (pp->WadeDepth)
7401 {
7402 DoPlayerBeginWade(pp);
7403 return;
7404 }
7405
7406 pp->friction = PLAYER_RUN_FRICTION;
7407 pp->floor_dist = PLAYER_RUN_FLOOR_DIST;
7408 pp->ceiling_dist = PLAYER_RUN_CEILING_DIST;
7409 pp->DoPlayerAction = DoPlayerRun;
7410
7411 ///DamageData[u->WeaponNum].Init(pp);
7412
7413 ASSERT(u->ActorActionSet->Run);
7414
7415 if (TEST(pp->Flags, PF_PLAYER_MOVED))
7416 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Run);
7417 else
7418 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Stand);
7419 }
7420
7421 VOID
DoPlayerRun(PLAYERp pp)7422 DoPlayerRun(PLAYERp pp)
7423 {
7424 USERp u = User[pp->PlayerSprite];
7425
7426 if (SectorIsUnderwaterArea(pp->cursectnum))
7427 {
7428 DoPlayerBeginDiveNoWarp(pp);
7429 return;
7430 }
7431
7432 // Crawl if in small aread automatically
7433 if (DoPlayerTestCrawl(pp))
7434 {
7435 DoPlayerBeginCrawl(pp);
7436 return;
7437 }
7438
7439 // Crawl Commanded
7440 if (TEST_SYNC_KEY(pp, SK_CRAWL))
7441 {
7442 DoPlayerBeginCrawl(pp);
7443 return;
7444 }
7445
7446 // Jump
7447 if (TEST_SYNC_KEY(pp, SK_JUMP))
7448 {
7449 if (FLAG_KEY_PRESSED(pp, SK_JUMP))
7450 {
7451 FLAG_KEY_RELEASE(pp, SK_JUMP);
7452 // make sure you stand at full heights for jumps/double jumps
7453 //DoPlayerHeight(pp);
7454 //DoPlayerHeight(pp);
7455 //DoPlayerHeight(pp);
7456 //DoPlayerHeight(pp);
7457 //DoPlayerHeight(pp);
7458 pp->posz = pp->loz - PLAYER_HEIGHT;
7459 DoPlayerBeginJump(pp);
7460 return;
7461 }
7462 }
7463 else
7464 {
7465 FLAG_KEY_RESET(pp, SK_JUMP);
7466 }
7467
7468 // Crawl lock
7469 // if (KEY_PRESSED(KEYSC_NUM))
7470 if (TEST_SYNC_KEY(pp, SK_CRAWL_LOCK))
7471 {
7472 if (FLAG_KEY_PRESSED(pp, SK_CRAWL_LOCK))
7473 {
7474 FLAG_KEY_RELEASE(pp, SK_CRAWL_LOCK);
7475 SET(pp->Flags, PF_LOCK_CRAWL);
7476 DoPlayerBeginCrawl(pp);
7477 return;
7478 }
7479 }
7480 else
7481 {
7482 FLAG_KEY_RESET(pp, SK_CRAWL_LOCK);
7483 }
7484
7485 if (PlayerFlyKey(pp))
7486 {
7487 //pp->InventoryTics[INVENTORY_FLY] = -99;
7488 DoPlayerBeginFly(pp);
7489 return;
7490 }
7491
7492 if (DebugOperate)
7493 {
7494 if (!TEST(pp->Flags, PF_DEAD) && !Prediction)
7495 {
7496 if (TEST_SYNC_KEY(pp, SK_OPERATE))
7497 {
7498 if (FLAG_KEY_PRESSED(pp, SK_OPERATE))
7499 {
7500 if (TEST(sector[pp->cursectnum].extra, SECTFX_OPERATIONAL))
7501 {
7502 FLAG_KEY_RELEASE(pp, SK_OPERATE);
7503 DoPlayerBeginOperate(pp);
7504 return;
7505 }
7506 else
7507 if (TEST(sector[pp->cursectnum].extra, SECTFX_TRIGGER))
7508 {
7509 SPRITEp sp;
7510
7511 sp = FindNearSprite(pp->SpriteP, STAT_TRIGGER);
7512 if (sp && SP_TAG5(sp) == TRIGGER_TYPE_REMOTE_SO)
7513 {
7514 pp->remote_sprite = sp;
7515 FLAG_KEY_RELEASE(pp, SK_OPERATE);
7516 ASSERT(pp->remote_sprite);
7517 DoPlayerBeginRemoteOperate(pp, &SectorObject[SP_TAG7(pp->remote_sprite)]);
7518 return;
7519 }
7520 }
7521 }
7522 }
7523 else
7524 {
7525 FLAG_KEY_RESET(pp, SK_OPERATE);
7526 }
7527 }
7528 }
7529
7530 DoPlayerBob(pp);
7531
7532 if (pp->WadeDepth)
7533 {
7534 DoPlayerBeginWade(pp);
7535 return;
7536 }
7537
7538
7539 // If moving forward and tag is a ladder start climbing
7540 if (PlayerOnLadder(pp))
7541 {
7542 DoPlayerBeginClimb(pp);
7543 return;
7544 }
7545
7546 // Move about
7547 DoPlayerMove(pp);
7548
7549 if (u->Rot != sg_PlayerNinjaSword && u->Rot != sg_PlayerNinjaPunch)
7550 {
7551 if (TEST(pp->Flags, PF_PLAYER_MOVED))
7552 {
7553 if (u->Rot != u->ActorActionSet->Run)
7554 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Run);
7555 }
7556 else
7557 {
7558 if (u->Rot != u->ActorActionSet->Stand)
7559 NewStateGroup(pp->PlayerSprite, u->ActorActionSet->Stand);
7560 }
7561 }
7562
7563 // If the floor is far below you, fall hard instead of adjusting height
7564 if (PlayerFallTest(pp, PLAYER_HEIGHT))
7565 {
7566 pp->jump_speed = Z(1);
7567 DoPlayerBeginFall(pp);
7568 // call PlayerFall now seems to iron out a hitch before falling
7569 DoPlayerFall(pp);
7570 return;
7571 }
7572
7573 if (TEST(sector[pp->cursectnum].extra, SECTFX_DYNAMIC_AREA))
7574 {
7575 pp->posz = pp->loz - PLAYER_HEIGHT;
7576 }
7577
7578 // Adjust height moving up and down sectors
7579 DoPlayerHeight(pp);
7580 }
7581
7582
7583 int
PlayerStateControl(SHORT SpriteNum)7584 PlayerStateControl(SHORT SpriteNum)
7585 {
7586 USERp u;
7587
7588 // Convienience var
7589 u = User[SpriteNum];
7590
7591 u->Tics += synctics;
7592
7593 // Skip states if too much time has passed
7594 while (u->Tics >= TEST(u->State->Tics, SF_TICS_MASK))
7595 {
7596
7597 // Set Tics
7598 u->Tics -= TEST(u->State->Tics, SF_TICS_MASK);
7599
7600 // Transition to the next state
7601 u->State = u->State->NextState;
7602
7603 // !JIM! Added this so I can do quick calls in player states!
7604 // Need this in order for floor blood and footprints to not get called more than once.
7605 while (TEST(u->State->Tics, SF_QUICK_CALL))
7606 {
7607 // Call it once and go to the next state
7608 (*u->State->Animator) (SpriteNum);
7609
7610 // if still on the same QUICK_CALL should you
7611 // go to the next state.
7612 if (TEST(u->State->Tics, SF_QUICK_CALL))
7613 u->State = u->State->NextState;
7614 }
7615
7616 if (!u->State->Pic)
7617 {
7618 NewStateGroup(SpriteNum, (STATEp *) u->State->NextState);
7619 }
7620 }
7621
7622 // Set picnum to the correct pic
7623 //sprite[SpriteNum].picnum = u->State->Pic;
7624 if (u->RotNum > 1)
7625 sprite[SpriteNum].picnum = u->Rot[0]->Pic;
7626 else
7627 sprite[SpriteNum].picnum = u->State->Pic;
7628
7629 // Call the correct animator
7630 if (TEST(u->State->Tics, SF_PLAYER_FUNC))
7631 if (u->State->Animator)
7632 (*u->State->Animator) (SpriteNum);
7633
7634 return (0);
7635 }
7636
7637 VOID
MoveSkipSavePos(VOID)7638 MoveSkipSavePos(VOID)
7639 {
7640 SPRITEp sp;
7641 USERp u;
7642 short i,nexti;
7643 short pnum;
7644 PLAYERp pp;
7645
7646 MoveSkip8 = (MoveSkip8 + 1) & 7;
7647 MoveSkip4 = (MoveSkip4 + 1) & 3;
7648 MoveSkip2 ^= 1;
7649
7650 // Save off player
7651 TRAVERSE_CONNECT(pnum)
7652 {
7653 pp = Player + pnum;
7654
7655 pp->oposx = pp->posx;
7656 pp->oposy = pp->posy;
7657 pp->oposz = pp->posz;
7658 pp->oang = pp->pang;
7659 pp->ohoriz = pp->horiz;
7660 }
7661
7662 // save off stats for skip4
7663 if (MoveSkip4 == 0)
7664 {
7665 short stat;
7666
7667 for (stat = STAT_SKIP4_START; stat <= STAT_SKIP4_INTERP_END; stat++)
7668 {
7669 TRAVERSE_SPRITE_STAT(headspritestat[stat], i, nexti)
7670 {
7671 sp = &sprite[i];
7672 u = User[i];
7673
7674 u->ox = sp->x;
7675 u->oy = sp->y;
7676 u->oz = sp->z;
7677 }
7678 }
7679 }
7680
7681 // save off stats for skip2
7682 if (MoveSkip2 == 0)
7683 {
7684 short stat;
7685
7686 for (stat = STAT_SKIP2_START; stat <= STAT_SKIP2_INTERP_END; stat++)
7687 {
7688 TRAVERSE_SPRITE_STAT(headspritestat[stat], i, nexti)
7689 {
7690 sp = &sprite[i];
7691 u = User[i];
7692
7693 u->ox = sp->x;
7694 u->oy = sp->y;
7695 u->oz = sp->z;
7696 }
7697 }
7698 }
7699 }
7700
7701
PlayerTimers(PLAYERp pp)7702 VOID PlayerTimers(PLAYERp pp)
7703 {
7704 SPRITEp sp = pp->SpriteP;
7705
7706 InventoryTimer(pp);
7707 }
7708
ChopsCheck(PLAYERp pp)7709 VOID ChopsCheck(PLAYERp pp)
7710 {
7711 extern BOOL HelpInputMode;
7712 extern int ChopTics;
7713
7714 if (!UsingMenus && !HelpInputMode && !TEST(pp->Flags, PF_DEAD) && !pp->sop_riding && CommPlayers <= 1)
7715 {
7716 if ((pp->input.bits|pp->input.vel|pp->input.svel|pp->input.angvel|pp->input.aimvel) ||
7717 TEST(pp->Flags, PF_CLIMBING|PF_FALLING|PF_DIVING))
7718 {
7719 // Hit a input key or other reason to stop chops
7720 //if (pp->Chops && pp->Chops->State != pp->Chops->State->RetractState)
7721 if (pp->Chops)
7722 {
7723 if (!pp->sop_control) // specail case
7724 RESET(pp->Flags, PF_WEAPON_DOWN);
7725 ChopsSetRetract(pp);
7726 }
7727 ChopTics = 0;
7728 }
7729 else
7730 {
7731 ChopTics += synctics;
7732 if (!pp->Chops)
7733 {
7734 // Chops not up
7735 if (ChopTics > 30*120)
7736 {
7737 ChopTics = 0;
7738 // take weapon down
7739 SET(pp->Flags, PF_WEAPON_DOWN);
7740 InitChops(pp);
7741 }
7742 }
7743 else
7744 {
7745 // Chops already up
7746 if (ChopTics > 30*120)
7747 {
7748 ChopTics = 0;
7749 // bring weapon back up
7750 RESET(pp->Flags, PF_WEAPON_DOWN);
7751 ChopsSetRetract(pp);
7752 }
7753 }
7754 }
7755 }
7756 }
7757
PlayerGlobal(PLAYERp pp)7758 VOID PlayerGlobal(PLAYERp pp)
7759 {
7760 // This is the place for things that effect the player no matter what hes
7761 // doing
7762
7763
7764 PlayerTimers(pp);
7765
7766 if (TEST(pp->Flags, PF_RECOIL))
7767 DoPlayerRecoil(pp);
7768
7769 if (!TEST(pp->Flags, PF_CLIP_CHEAT))
7770 {
7771 if (pp->hi_sectp && pp->lo_sectp)
7772 {
7773 int min_height;
7774
7775 #if 0
7776 if (TEST(pp->Flags, PF_JUMPING))
7777 // this is a special case for jumping. Jumps have a very small
7778 // z height for the box so players can jump into small areas.
7779 min_height = PLAYER_MIN_HEIGHT_JUMP;
7780 else
7781 min_height = PLAYER_MIN_HEIGHT;
7782 #else
7783 // just adjusted min height to something small to take care of all cases
7784 min_height = PLAYER_MIN_HEIGHT;
7785 #endif
7786
7787 if (labs(pp->loz - pp->hiz) < min_height)
7788 {
7789 if (!TEST(pp->Flags, PF_DEAD))
7790 {
7791 ////DSPRINTF(ds,"Squish diff %d, min %d, cz %d, fz %d, lo %d, hi %d",labs(pp->loz - pp->hiz)>>8,min_height>>8, pp->ceiling_dist>>8, pp->floor_dist>>8,pp->lo_sectp-sector,pp->hi_sectp-sector);
7792 //MONO_PRINT(ds);
7793 PlayerUpdateHealth(pp, -User[pp->PlayerSprite]->Health); // Make sure he dies!
7794 PlayerCheckDeath(pp, -1);
7795
7796 if (TEST(pp->Flags, PF_DEAD))
7797 return;
7798 }
7799 }
7800 }
7801 }
7802
7803 if(pp->FadeAmt > 0 && MoveSkip4 == 0)
7804 {
7805 DoPaletteFlash( pp );
7806 }
7807
7808 // camera stuff that can't be done in drawscreen
7809 if (pp->circle_camera_dist > CIRCLE_CAMERA_DIST_MIN)
7810 pp->circle_camera_ang = NORM_ANGLE(pp->circle_camera_ang + 14);
7811
7812 if (pp->camera_check_time_delay > 0)
7813 {
7814 pp->camera_check_time_delay -= synctics;
7815 if (pp->camera_check_time_delay <= 0)
7816 pp->camera_check_time_delay = 0;
7817 }
7818 }
7819
7820
UpdateScrollingMessages(VOID)7821 VOID UpdateScrollingMessages(VOID)
7822 {
7823 short i;
7824
7825 // Update the scrolling multiplayer messages
7826 for(i=0;i<MAXUSERQUOTES;i++)
7827 {
7828 if (user_quote_time[i])
7829 {
7830 user_quote_time[i]--;
7831
7832 if (user_quote_time[i] <= 0)
7833 {
7834 SetRedrawScreen(Player + myconnectindex);
7835 user_quote_time[i] = 0;
7836 }
7837 //if (!user_quote_time[i]) pub = NUMPAGES;
7838 }
7839 }
7840
7841 if (gs.BorderNum > BORDER_BAR+1)
7842 {
7843 quotebot = quotebotgoal;
7844 }
7845 else
7846 {
7847 // if ((klabs(quotebotgoal-quotebot) <= 16) && gs.BorderNum < BORDER_NONE+2)
7848 if ((klabs(quotebotgoal-quotebot) <= 16))
7849 quotebot += ksgn(quotebotgoal-quotebot);
7850 else
7851 quotebot = quotebotgoal;
7852 }
7853 }
7854
UpdateConMessages(VOID)7855 VOID UpdateConMessages(VOID)
7856 {
7857 short i;
7858
7859 if(!ConInputMode) return;
7860
7861 if ((klabs(conbotgoal-conbot) <= 12))
7862 conbot += ksgn(conbotgoal-conbot);
7863 else
7864 conbot = conbotgoal;
7865 }
7866
MultiPlayLimits(VOID)7867 VOID MultiPlayLimits(VOID)
7868 {
7869 short pnum;
7870 PLAYERp pp;
7871 BOOL Done = FALSE;
7872
7873 if (ExitLevel)
7874 return;
7875
7876 if (gNet.MultiGameType != MULTI_GAME_COMMBAT)
7877 return;
7878
7879 if (gNet.KillLimit)
7880 {
7881 TRAVERSE_CONNECT(pnum)
7882 {
7883 pp = Player + pnum;
7884 if (pp->Kills >= gNet.KillLimit)
7885 {
7886 Done = TRUE;
7887 }
7888 }
7889 }
7890
7891 if (gNet.TimeLimit)
7892 {
7893 gNet.TimeLimitClock -= synctics;
7894
7895 if ((gNet.TimeLimitClock%120) <= 3)
7896 {
7897 PlayerUpdateTimeLimit(Player + screenpeek);
7898 }
7899
7900 if (gNet.TimeLimitClock <= 0)
7901 Done = TRUE;
7902 }
7903
7904 if (Done)
7905 {
7906 gNet.TimeLimitClock = gNet.TimeLimit;
7907
7908 // do not increment if level is 23 thru 28
7909 if (Level <= 22)
7910 Level++;
7911
7912 ExitLevel = TRUE;
7913 FinishedLevel = TRUE;
7914 }
7915 }
7916
PauseMultiPlay(void)7917 void PauseMultiPlay(void)
7918 {
7919 static BOOL SavePrediction;
7920 PLAYERp pp;
7921 short pnum,p;
7922 extern BOOL GamePaused;
7923
7924 // check for pause of multi-play game
7925 TRAVERSE_CONNECT(pnum)
7926 {
7927 pp = Player + pnum;
7928
7929 if (TEST_SYNC_KEY(pp, SK_PAUSE))
7930 {
7931 if (FLAG_KEY_PRESSED(pp, SK_PAUSE))
7932 {
7933 FLAG_KEY_RELEASE(pp, SK_PAUSE);
7934
7935 GamePaused ^= 1;
7936
7937 if (GamePaused)
7938 {
7939 short w,h;
7940 #define MSG_GAME_PAUSED "Game Paused"
7941 MNU_MeasureString(MSG_GAME_PAUSED, &w, &h);
7942
7943 TRAVERSE_CONNECT(p)
7944 PutStringTimer(Player + p, TEXT_TEST_COL(w), 100, MSG_GAME_PAUSED, 999);
7945
7946 SavePrediction = PredictionOn;
7947 PredictionOn = FALSE;
7948 PauseSong(TRUE);
7949 }
7950 else
7951 {
7952 PredictionOn = SavePrediction;
7953 PauseSong(FALSE);
7954 TRAVERSE_CONNECT(p)
7955 pClearTextLine(Player + p, 100);
7956 }
7957 }
7958 }
7959 else
7960 {
7961 FLAG_KEY_RESET(pp, SK_PAUSE);
7962 }
7963 }
7964 }
7965
7966 VOID
domovethings(VOID)7967 domovethings(VOID)
7968 {
7969 extern BOOL DebugAnim;
7970 extern BOOL DebugPanel;
7971 extern BOOL DebugActor;
7972 extern BOOL DebugSector;
7973 extern BOOL DebugActorFreeze;
7974 extern BOOL ResCheat;
7975 extern int PlayClock;
7976 short i, j, pnum, nexti;
7977 int WeaponOperate(PLAYERp pp);
7978 extern BOOL GamePaused;
7979 PLAYERp pp;
7980 USERp u;
7981 SPRITEp sp;
7982 BOOL MyCommPlayerQuit(void);
7983 extern unsigned int MoveThingsCount;
7984 extern BOOL ScrollMode2D;
7985 extern BOOL ReloadPrompt;
7986 extern int FinishTimer;
7987
7988
7989 // grab values stored in the fifo and put them in the players vars
7990 TRAVERSE_CONNECT(i)
7991 {
7992 pp = Player + i;
7993 pp->input = pp->inputfifo[movefifoplc & (MOVEFIFOSIZ - 1)];
7994 }
7995 movefifoplc++;
7996
7997 if (MyCommPlayerQuit())
7998 return;
7999
8000 UpdateScrollingMessages(); // Update the multiplayer type messages
8001 UpdateConMessages(); // Update the console messages
8002
8003 #if SYNC_TEST
8004 if (!(movefifoplc & 0x3f))
8005 getsyncstat();
8006 #ifdef DEBUG // in DEBUG mode even TEN does sync all the time
8007 else
8008 getsyncstat();
8009 #endif
8010 #endif
8011
8012 // count the number of times this loop is called and use
8013 // for things like sync testing
8014 MoveThingsCount++;
8015
8016 //RTS_Keys();
8017
8018 // recording is done here
8019 if (DemoRecording)
8020 {
8021 TRAVERSE_CONNECT(i)
8022 {
8023 pp = Player + i;
8024
8025 DemoBuffer[DemoRecCnt] = pp->input;
8026
8027 if (DemoDebugMode)
8028 {
8029 DemoRecCnt++;
8030 if (DemoRecCnt > DemoDebugBufferMax-1)
8031 {
8032 DemoDebugWrite();
8033 DemoRecCnt = 0;
8034 }
8035 }
8036 else
8037 {
8038 DemoRecCnt++;
8039 if (DemoRecCnt > DEMO_BUFFER_MAX-1)
8040 {
8041 DemoWriteBuffer();
8042 DemoRecCnt = 0;
8043 }
8044 }
8045 }
8046 }
8047
8048 totalsynctics += synctics;
8049
8050 updateinterpolations(); // Stick at beginning of domovethings
8051 short_updateinterpolations(); // Stick at beginning of domovethings
8052 MoveSkipSavePos();
8053
8054 #if 0
8055 {
8056 extern BOOL PauseKeySet;
8057 if (KEY_PRESSED(KEYSC_F5) && !(KEY_PRESSED(KEYSC_ALT) || KEY_PRESSED(KEYSC_RALT)) && !PauseKeySet)
8058 {
8059 KEY_PRESSED(KEYSC_F5) = 0;
8060 ResChange();
8061 }
8062 }
8063 #endif
8064
8065
8066 #if 0 // has been moved to draw code
8067 if (ResCheat)
8068 {
8069 ResCheat = FALSE;
8070 ResChange();
8071 }
8072 #endif
8073
8074 // check for pause of multi-play game
8075 if (CommEnabled)
8076 PauseMultiPlay();
8077
8078 TRAVERSE_CONNECT(pnum)
8079 {
8080 pp = Player + pnum;
8081 DoPlayerMenuKeys(pp);
8082 }
8083
8084 if (GamePaused)
8085 {
8086 if (!ReloadPrompt)
8087 return;
8088 }
8089
8090 PlayClock += synctics;
8091
8092 if (!DebugAnim)
8093 if (!DebugActorFreeze)
8094 DoAnim(synctics);
8095
8096 // should pass pnum and use syncbits
8097 if (!DebugSector)
8098 DoSector();
8099
8100 ProcessVisOn();
8101 if (MoveSkip4 == 0)
8102 {
8103 ProcessQuakeOn();
8104 ProcessQuakeSpot();
8105 JS_ProcessEchoSpot();
8106 }
8107
8108 FAKETIMERHANDLER();
8109
8110 SpriteControl();
8111
8112 FAKETIMERHANDLER();
8113
8114 TRAVERSE_CONNECT(pnum)
8115 {
8116 extern short screenpeek;
8117 extern BOOL PlayerTrackingMode;
8118 void pSpriteControl(PLAYERp pp);
8119 extern PLAYERp GlobPlayerP;
8120 extern BOOL ScrollMode2D;
8121
8122 pp = Player + pnum;
8123 GlobPlayerP = pp;
8124
8125 // auto tracking mode for single player multi-game
8126 if (CommPlayers <= 1 && PlayerTrackingMode && pnum == screenpeek && screenpeek != myconnectindex)
8127 {
8128 Player[screenpeek].pang = getangle(Player[myconnectindex].posx - Player[screenpeek].posx, Player[myconnectindex].posy - Player[screenpeek].posy);
8129 }
8130
8131 if (!TEST(pp->Flags, PF_DEAD))
8132 {
8133 #if DEBUG
8134 if (!DebugPanel)
8135 WeaponOperate(pp);
8136 if (!DebugSector)
8137 PlayerOperateEnv(pp);
8138 #else
8139 WeaponOperate(pp);
8140 PlayerOperateEnv(pp);
8141 #endif
8142 }
8143
8144 FAKETIMERHANDLER();
8145
8146 // do for moving sectors
8147 DoPlayerSectorUpdatePreMove(pp);
8148 ChopsCheck(pp);
8149
8150 //if (!ScrollMode2D)
8151 (*pp->DoPlayerAction) (pp);
8152
8153 UpdatePlayerSprite(pp);
8154
8155 #if DEBUG
8156 if (!DebugPanel)
8157 #endif
8158 pSpriteControl(pp);
8159
8160 PlayerStateControl(pp->PlayerSprite);
8161
8162 DoPlayerSectorUpdatePostMove(pp);
8163 PlayerGlobal(pp);
8164 }
8165
8166
8167 MultiPlayLimits();
8168
8169 if(MoveSkip8 == 0) // 8=5x 4=10x, 2=20x, 0=40x per second
8170 DoUpdateSounds3D();
8171
8172 CorrectPrediction(movefifoplc - 1);
8173
8174 if (FinishTimer)
8175 {
8176 if ((FinishTimer -= synctics) <= 0)
8177 {
8178 FinishTimer = 0;
8179 ExitLevel = TRUE;
8180 FinishedLevel = TRUE;
8181 }
8182 }
8183
8184
8185 //if (DemoSyncRecord && !DemoPlaying)
8186 // demosync_record();
8187 }
8188
8189
8190 extern unsigned char palette_data[256][3]; // Global palette array
8191
8192 VOID
InitAllPlayers(VOID)8193 InitAllPlayers(VOID)
8194 {
8195 PLAYERp pp;
8196 PLAYERp pfirst = Player;
8197 int i;
8198 extern BOOL NewGame;
8199 //int fz,cz;
8200
8201 //getzsofslope(pfirst->cursectnum, pfirst->posx, pfirst->posy, &cz, &fz);
8202 //pfirst->posz = fz - PLAYER_HEIGHT;
8203 pfirst->horiz = pfirst->horizbase = 100;
8204
8205 // Initialize all [MAX_SW_PLAYERS] arrays here!
8206 for (pp = Player; pp < &Player[MAX_SW_PLAYERS]; pp++)
8207 {
8208 pp->posx = pp->oposx = pfirst->posx;
8209 pp->posy = pp->oposy = pfirst->posy;
8210 pp->posz = pp->oposz = pfirst->posz;
8211 pp->pang = pp->oang = pfirst->pang;
8212 pp->horiz = pp->ohoriz = pfirst->horiz;
8213 pp->cursectnum = pfirst->cursectnum;
8214 // set like this so that player can trigger something on start of the level
8215 pp->lastcursectnum = pfirst->cursectnum+1;
8216
8217 //pp->MaxHealth = 100;
8218
8219 pp->horizbase = pfirst->horizbase;
8220 pp->oldposx = 0;
8221 pp->oldposy = 0;
8222 pp->climb_ndx = 10;
8223 pp->Killer = -1;
8224 pp->Kills = 0;
8225 pp->bcnt = 0;
8226 pp->UziShellLeftAlt = 0;
8227 pp->UziShellRightAlt = 0;
8228
8229 pp->ceiling_dist = PLAYER_RUN_CEILING_DIST;
8230 pp->floor_dist = PLAYER_RUN_FLOOR_DIST;
8231
8232 pp->WpnGotOnceFlags = 0;
8233 pp->DoPlayerAction = DoPlayerBeginRun;
8234 pp->KeyPressFlags = 0xFFFFFFFF;
8235 memset(pp->KilledPlayer,0,sizeof(pp->KilledPlayer));
8236
8237 if (NewGame)
8238 {
8239 for (i = 0; i < MAX_INVENTORY; i++)
8240 {
8241 //pp->InventoryAmount[i] = InventoryData[i].MaxInv = 0;
8242 pp->InventoryAmount[i] = 0;
8243 pp->InventoryPercent[i] = 0;
8244 }
8245 }
8246
8247 // My palette flashing stuff
8248 pp->FadeAmt = 0;
8249 pp->FadeTics = 0;
8250 pp->StartColor = 0;
8251 pp->horizoff = 0;
8252 memcpy(&pp->temp_pal[0],&palette_data[0][0],768);
8253
8254 INITLIST(&pp->PanelSpriteList);
8255 }
8256 }
8257
SearchSpawnPosition(PLAYERp pp)8258 int SearchSpawnPosition(PLAYERp pp)
8259 {
8260 PLAYERp opp; // other player
8261 SPRITEp sp;
8262 short pos_num;
8263 short pnum,spawn_sprite;
8264 BOOL blocked;
8265
8266 do
8267 {
8268 // get a spawn position
8269 pos_num = RANDOM_RANGE(MAX_SW_PLAYERS);
8270 spawn_sprite = headspritestat[STAT_MULTI_START + pos_num];
8271 if (spawn_sprite <= -1)
8272 return(0);
8273
8274 sp = &sprite[spawn_sprite];
8275
8276 blocked = FALSE;
8277
8278 // check to see if anyone else is blocking this spot
8279 TRAVERSE_CONNECT(pnum)
8280 {
8281 opp = &Player[pnum];
8282
8283 if (opp != pp) // don't test for yourself
8284 {
8285 if (FindDistance3D(sp->x - opp->posx, sp->y - opp->posy, (sp->z - opp->posz)>>4) < 1000)
8286 {
8287 blocked = TRUE;
8288 break;
8289 }
8290 }
8291 }
8292 }
8293 while (blocked);
8294
8295 return(pos_num);
8296 }
8297
8298 BOOL SpawnPositionUsed[MAX_SW_PLAYERS_REG+1];
8299
8300 VOID
PlayerSpawnPosition(PLAYERp pp)8301 PlayerSpawnPosition(PLAYERp pp)
8302 {
8303 SPRITEp sp;
8304 short pnum = pp - Player;
8305 short spawn_sprite = 0, pos_num = pnum;
8306 int fz,cz;
8307 int i;
8308
8309 // find the first unused spawn position
8310 // garauntees that the spawn pos 0 will be used
8311 // Note: This code is not used if the player is DEAD and respawning
8312
8313 for (i = 0; i < MAX_SW_PLAYERS; i++)
8314 {
8315 if (!SpawnPositionUsed[i])
8316 {
8317 pos_num = i;
8318 break;
8319 }
8320 }
8321
8322 // need to call this routine BEFORE resetting DEATH flag
8323
8324 switch (gNet.MultiGameType)
8325 {
8326 case MULTI_GAME_NONE:
8327 // start from the beginning
8328 spawn_sprite = headspritestat[STAT_MULTI_START + 0];
8329 break;
8330 case MULTI_GAME_COMMBAT:
8331 case MULTI_GAME_AI_BOTS:
8332 // start from random position after death
8333 if (TEST(pp->Flags, PF_DEAD))
8334 {
8335 pos_num = SearchSpawnPosition(pp);
8336 }
8337
8338 spawn_sprite = headspritestat[STAT_MULTI_START + pos_num];
8339 break;
8340 case MULTI_GAME_COOPERATIVE:
8341 // start your assigned spot
8342 spawn_sprite = headspritestat[STAT_CO_OP_START + pos_num];
8343 break;
8344 }
8345
8346 SpawnPositionUsed[pos_num] = TRUE;
8347
8348 if (spawn_sprite < 0)
8349 {
8350 spawn_sprite = headspritestat[STAT_MULTI_START + 0];
8351 //TerminateGame();
8352 //printf("Map does not contain a spawn position for Player %d.", pp - Player);
8353 //exit(0);
8354 }
8355
8356 ASSERT(spawn_sprite >= 0);
8357
8358 sp = &sprite[spawn_sprite];
8359
8360
8361 pp->posx = pp->oposx = sp->x;
8362 pp->posy = pp->oposy = sp->y;
8363 pp->posz = pp->oposz = sp->z;
8364 pp->pang = pp->oang = sp->ang;
8365 pp->cursectnum = sp->sectnum;
8366
8367 getzsofslope(pp->cursectnum, pp->posx, pp->posy, &cz, &fz);
8368 // if too close to the floor - stand up
8369 if (pp->posz > fz - PLAYER_HEIGHT)
8370 {
8371 pp->posz = pp->oposz = fz - PLAYER_HEIGHT;
8372 }
8373 }
8374
8375
8376 VOID
InitMultiPlayerInfo(VOID)8377 InitMultiPlayerInfo(VOID)
8378 {
8379 PLAYERp pp;
8380 SPRITEp sp;
8381 short pnum, start0;
8382 unsigned stat;
8383 short SpriteNum, NextSprite, tag;
8384 static short MultiStatList[] =
8385 {
8386 STAT_MULTI_START,
8387 STAT_CO_OP_START
8388 };
8389
8390 // this routine is called before SpriteSetup - process start positions NOW
8391 TRAVERSE_SPRITE_STAT(headspritestat[0], SpriteNum, NextSprite)
8392 {
8393 sp = &sprite[SpriteNum];
8394
8395 tag = sp->hitag;
8396
8397 if (sp->picnum == ST1)
8398 {
8399 switch (tag)
8400 {
8401 case MULTI_PLAYER_START:
8402 change_sprite_stat(SpriteNum, STAT_MULTI_START + sp->lotag);
8403 break;
8404 case MULTI_COOPERATIVE_START:
8405 change_sprite_stat(SpriteNum, STAT_CO_OP_START + sp->lotag);
8406 break;
8407 }
8408 }
8409 }
8410
8411 // set up the zero starting positions - its not saved in the map as a ST1 sprite
8412 // like the others
8413 pp = Player;
8414 for (stat = 0; stat < SIZ(MultiStatList); stat++)
8415 {
8416 if (gNet.MultiGameType != MULTI_GAME_NONE)
8417 {
8418 // if start position is physically set then don't spawn a new one
8419 if (headspritestat[MultiStatList[stat] + 0] >= 0)
8420 continue;
8421 }
8422
8423 start0 = SpawnSprite(MultiStatList[stat], ST1, NULL, pp->cursectnum, pp->posx, pp->posy, pp->posz, pp->pang, 0);
8424 ASSERT(start0 >= 0);
8425 if (User[start0]) {
8426 FreeMem(User[start0]);
8427 User[start0] = NULL;
8428 }
8429 sprite[start0].picnum = ST1;
8430 }
8431
8432 memset(SpawnPositionUsed,0,sizeof(SpawnPositionUsed));
8433
8434 // Initialize multi player positions here
8435 TRAVERSE_CONNECT(pnum)
8436 {
8437 pp = Player + pnum;
8438 switch (gNet.MultiGameType)
8439 {
8440 case MULTI_GAME_NONE:
8441 PlayerSpawnPosition(pp);
8442 break;
8443 //return;
8444 case MULTI_GAME_COMMBAT:
8445 case MULTI_GAME_AI_BOTS:
8446 // there are no keys in deathmatch play
8447 memset(Player[0].HasKey,0xFFFF,sizeof(Player[0].HasKey));
8448 memset(pp->HasKey,0xFFFF,sizeof(pp->HasKey));
8449 PlayerSpawnPosition(pp);
8450 break;
8451 case MULTI_GAME_COOPERATIVE:
8452 PlayerSpawnPosition(pp);
8453 break;
8454 }
8455 }
8456 }
8457
8458 // If player stepped in something gooey, track it all over the place.
8459 int
DoFootPrints(short SpriteNum)8460 DoFootPrints(short SpriteNum)
8461 {
8462 SPRITEp sp = &sprite[SpriteNum];
8463 USERp u = User[SpriteNum];
8464
8465 if (u->PlayerP)
8466 {
8467 if (FAF_ConnectArea(u->PlayerP->cursectnum))
8468 return(0);
8469
8470 if(u->PlayerP->NumFootPrints > 0)
8471 {
8472 QueueFootPrint(SpriteNum);
8473 }
8474 }
8475
8476 return(0);
8477 }
8478
CheckFootPrints(PLAYERp pp)8479 VOID CheckFootPrints(PLAYERp pp)
8480 {
8481 if(pp->NumFootPrints <= 0 || FootMode != WATER_FOOT)
8482 {
8483 // Hey, you just got your feet wet!
8484 pp->NumFootPrints = RANDOM_RANGE(10)+3;
8485 FootMode = WATER_FOOT;
8486 }
8487 }
8488
8489
8490 #include "saveable.h"
8491
8492 static saveable_code saveable_player_code[] = {
8493 SAVE_CODE(DoPlayerSlide),
8494 //SAVE_CODE(DoPlayerBeginSwim),
8495 //SAVE_CODE(DoPlayerSwim),
8496 SAVE_CODE(DoPlayerWade),
8497 SAVE_CODE(DoPlayerBeginWade),
8498 SAVE_CODE(DoPlayerBeginCrawl),
8499 SAVE_CODE(DoPlayerCrawl),
8500 SAVE_CODE(DoPlayerRun),
8501 SAVE_CODE(DoPlayerBeginRun),
8502 SAVE_CODE(DoPlayerFall),
8503 SAVE_CODE(DoPlayerBeginFall),
8504 SAVE_CODE(DoPlayerJump),
8505 SAVE_CODE(DoPlayerBeginJump),
8506 SAVE_CODE(DoPlayerForceJump),
8507 SAVE_CODE(DoPlayerBeginFly),
8508 SAVE_CODE(DoPlayerFly),
8509 SAVE_CODE(DoPlayerBeginClimb),
8510 SAVE_CODE(DoPlayerClimb),
8511 SAVE_CODE(DoPlayerBeginDie),
8512 //SAVE_CODE(DoPlayerDie),
8513 SAVE_CODE(DoPlayerBeginOperateBoat),
8514 SAVE_CODE(DoPlayerBeginOperateTank),
8515 SAVE_CODE(DoPlayerBeginOperate),
8516 SAVE_CODE(DoPlayerOperateBoat),
8517 SAVE_CODE(DoPlayerOperateTank),
8518 SAVE_CODE(DoPlayerOperateTurret),
8519 SAVE_CODE(DoPlayerBeginDive),
8520 SAVE_CODE(DoPlayerDive),
8521 SAVE_CODE(DoPlayerTeleportPause),
8522 SAVE_CODE(DoPlayerTestCrawl),
8523 SAVE_CODE(DoPlayerDeathFlip),
8524 SAVE_CODE(DoPlayerDeathCrumble),
8525 SAVE_CODE(DoPlayerDeathExplode),
8526 SAVE_CODE(DoPlayerDeathFall),
8527 SAVE_CODE(DoPlayerBeginDiveNoWarp),
8528 SAVE_CODE(DoPlayerCurrent),
8529 };
8530
8531 static saveable_data saveable_player_data[] = {
8532 SAVE_DATA(Player),
8533 SAVE_DATA(s_PlayerNinjaRun),
8534 SAVE_DATA(sg_PlayerNinjaRun),
8535 SAVE_DATA(s_PlayerNinjaStand),
8536 SAVE_DATA(sg_PlayerNinjaStand),
8537 SAVE_DATA(s_PlayerNinjaThrow),
8538 SAVE_DATA(sg_PlayerNinjaThrow),
8539 SAVE_DATA(s_PlayerNinjaJump),
8540 SAVE_DATA(sg_PlayerNinjaJump),
8541 SAVE_DATA(s_PlayerNinjaFall),
8542 SAVE_DATA(sg_PlayerNinjaFall),
8543 SAVE_DATA(s_PlayerNinjaClimb),
8544 SAVE_DATA(sg_PlayerNinjaClimb),
8545 SAVE_DATA(s_PlayerNinjaCrawl),
8546 SAVE_DATA(sg_PlayerNinjaCrawl),
8547 SAVE_DATA(s_PlayerNinjaSwim),
8548 SAVE_DATA(sg_PlayerNinjaSwim),
8549 SAVE_DATA(s_PlayerHeadFly),
8550 SAVE_DATA(sg_PlayerHeadFly),
8551 SAVE_DATA(s_PlayerHead),
8552 SAVE_DATA(sg_PlayerHead),
8553 SAVE_DATA(s_PlayerHeadHurl),
8554 SAVE_DATA(sg_PlayerHeadHurl),
8555 SAVE_DATA(s_PlayerDeath),
8556 SAVE_DATA(sg_PlayerDeath),
8557 SAVE_DATA(s_PlayerNinjaSword),
8558 SAVE_DATA(sg_PlayerNinjaSword),
8559 SAVE_DATA(s_PlayerNinjaPunch),
8560 SAVE_DATA(sg_PlayerNinjaPunch),
8561 SAVE_DATA(s_PlayerNinjaFly),
8562 SAVE_DATA(sg_PlayerNinjaFly),
8563 };
8564
8565 saveable_module saveable_player = {
8566 // code
8567 saveable_player_code,
8568 SIZ(saveable_player_code),
8569
8570 // data
8571 saveable_player_data,
8572 SIZ(saveable_player_data)
8573 };
8574