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 = &sector[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 = &sector[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 = &sector[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, &sectnum);
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, &sectnum);
2744         if (sectnum < 0)
2745             {
2746             sectnum = pp->cursectnum;
2747             COVERupdatesector(pp->posx, pp->posy, &sectnum);
2748             }
2749         ASSERT(sectnum >= 0);
2750         }
2751     else
2752     if (FAF_ConnectArea(sectnum))
2753         {
2754         updatesectorz(pp->posx, pp->posy, pp->posz, &sectnum);
2755         if (sectnum < 0)
2756             {
2757             sectnum = pp->cursectnum;
2758             COVERupdatesector(pp->posx, pp->posy, &sectnum);
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), &sectnum);
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 = &sector[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 == &sector[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 = &sector[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), &sectnum);
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), &sectnum);
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 = &sector[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, &sectnum);
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