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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 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 "keys.h"
29 #include "names2.h"
30 #include "panel.h"
31 #include "game.h"
32 #include "tags.h"
33 #include "ai.h"
34 #include "pal.h"
35 #include "actor.h"
36 #include "sprite.h"
37 #include "track.h"
38 
39 ANIMATOR InitRipperHang;
40 ANIMATOR DoActorMoveJump;
41 ANIMATOR DoRipperMoveJump;
42 ANIMATOR DoRipperHangJF;
43 ANIMATOR DoRipperQuickJump;
44 
45 DECISION RipperBattle[] =
46 {
47     {748, InitActorMoveCloser},
48     {750, InitActorAlertNoise},
49 //    {900, InitRipperHang},
50     {755, InitActorAttackNoise},
51     {1024, InitActorAttack}
52 };
53 
54 DECISION RipperOffense[] =
55 {
56     {700, InitActorMoveCloser},
57     {710, InitActorAlertNoise},
58     {1024, InitActorAttack}
59 };
60 
61 DECISION RipperBroadcast[] =
62 {
63     {3, InitActorAlertNoise},
64     {6, InitActorAmbientNoise},
65     {1024, InitActorDecide}
66 };
67 
68 DECISION RipperSurprised[] =
69 {
70     {30, InitRipperHang},
71     {701, InitActorMoveCloser},
72     {1024, InitActorDecide}
73 };
74 
75 DECISION RipperEvasive[] =
76 {
77     {6, InitRipperHang},
78     {1024, NULL}
79 };
80 
81 DECISION RipperLostTarget[] =
82 {
83     {980, InitActorFindPlayer},
84     {1024, InitActorWanderAround}
85 };
86 
87 DECISION RipperCloseRange[] =
88 {
89     {900,   InitActorAttack             },
90     {1024,  InitActorReposition         }
91 };
92 
93 PERSONALITY RipperPersonality =
94 {
95     RipperBattle,
96     RipperOffense,
97     RipperBroadcast,
98     RipperSurprised,
99     RipperEvasive,
100     RipperLostTarget,
101     RipperCloseRange,
102     RipperCloseRange
103 };
104 
105 ATTRIBUTE RipperAttrib =
106 {
107     {200, 220, 240, 280},               // Speeds
108     {5, 0, -2, -4},                     // Tic Adjusts
109     3,                                  // MaxWeapons;
110     {
111         DIGI_RIPPERAMBIENT, DIGI_RIPPERALERT, DIGI_RIPPERATTACK,
112         DIGI_RIPPERPAIN, DIGI_RIPPERSCREAM, DIGI_RIPPERHEARTOUT,
113         0,0,0,0
114     }
115 };
116 
117 //////////////////////
118 //
119 // RIPPER RUN
120 //
121 //////////////////////
122 
123 #define RIPPER_RUN_RATE 16
124 
125 ANIMATOR DoRipperMove, NullRipper, DoActorDebris;
126 
127 STATE s_RipperRun[5][4] =
128 {
129     {
130         {RIPPER_RUN_R0 + 0, RIPPER_RUN_RATE | SF_TIC_ADJUST, DoRipperMove, &s_RipperRun[0][1]},
131         {RIPPER_RUN_R0 + 1, RIPPER_RUN_RATE | SF_TIC_ADJUST, DoRipperMove, &s_RipperRun[0][2]},
132         {RIPPER_RUN_R0 + 2, RIPPER_RUN_RATE | SF_TIC_ADJUST, DoRipperMove, &s_RipperRun[0][3]},
133         {RIPPER_RUN_R0 + 3, RIPPER_RUN_RATE | SF_TIC_ADJUST, DoRipperMove, &s_RipperRun[0][0]},
134     },
135     {
136         {RIPPER_RUN_R1 + 0, RIPPER_RUN_RATE | SF_TIC_ADJUST, DoRipperMove, &s_RipperRun[1][1]},
137         {RIPPER_RUN_R1 + 1, RIPPER_RUN_RATE | SF_TIC_ADJUST, DoRipperMove, &s_RipperRun[1][2]},
138         {RIPPER_RUN_R1 + 2, RIPPER_RUN_RATE | SF_TIC_ADJUST, DoRipperMove, &s_RipperRun[1][3]},
139         {RIPPER_RUN_R1 + 3, RIPPER_RUN_RATE | SF_TIC_ADJUST, DoRipperMove, &s_RipperRun[1][0]},
140     },
141     {
142         {RIPPER_RUN_R2 + 0, RIPPER_RUN_RATE | SF_TIC_ADJUST, DoRipperMove, &s_RipperRun[2][1]},
143         {RIPPER_RUN_R2 + 1, RIPPER_RUN_RATE | SF_TIC_ADJUST, DoRipperMove, &s_RipperRun[2][2]},
144         {RIPPER_RUN_R2 + 2, RIPPER_RUN_RATE | SF_TIC_ADJUST, DoRipperMove, &s_RipperRun[2][3]},
145         {RIPPER_RUN_R2 + 3, RIPPER_RUN_RATE | SF_TIC_ADJUST, DoRipperMove, &s_RipperRun[2][0]},
146     },
147     {
148         {RIPPER_RUN_R3 + 0, RIPPER_RUN_RATE | SF_TIC_ADJUST, DoRipperMove, &s_RipperRun[3][1]},
149         {RIPPER_RUN_R3 + 1, RIPPER_RUN_RATE | SF_TIC_ADJUST, DoRipperMove, &s_RipperRun[3][2]},
150         {RIPPER_RUN_R3 + 2, RIPPER_RUN_RATE | SF_TIC_ADJUST, DoRipperMove, &s_RipperRun[3][3]},
151         {RIPPER_RUN_R3 + 3, RIPPER_RUN_RATE | SF_TIC_ADJUST, DoRipperMove, &s_RipperRun[3][0]},
152     },
153     {
154         {RIPPER_RUN_R4 + 0, RIPPER_RUN_RATE | SF_TIC_ADJUST, DoRipperMove, &s_RipperRun[4][1]},
155         {RIPPER_RUN_R4 + 1, RIPPER_RUN_RATE | SF_TIC_ADJUST, DoRipperMove, &s_RipperRun[4][2]},
156         {RIPPER_RUN_R4 + 2, RIPPER_RUN_RATE | SF_TIC_ADJUST, DoRipperMove, &s_RipperRun[4][3]},
157         {RIPPER_RUN_R4 + 3, RIPPER_RUN_RATE | SF_TIC_ADJUST, DoRipperMove, &s_RipperRun[4][0]},
158     }
159 };
160 
161 
162 STATEp sg_RipperRun[] =
163 {
164     &s_RipperRun[0][0],
165     &s_RipperRun[1][0],
166     &s_RipperRun[2][0],
167     &s_RipperRun[3][0],
168     &s_RipperRun[4][0]
169 };
170 
171 //////////////////////
172 //
173 // RIPPER STAND
174 //
175 //////////////////////
176 
177 #define RIPPER_STAND_RATE 12
178 
179 STATE s_RipperStand[5][1] =
180 {
181     {
182         {RIPPER_STAND_R0 + 0, RIPPER_STAND_RATE, DoRipperMove, &s_RipperStand[0][0]},
183     },
184     {
185         {RIPPER_STAND_R1 + 0, RIPPER_STAND_RATE, DoRipperMove, &s_RipperStand[1][0]},
186     },
187     {
188         {RIPPER_STAND_R2 + 0, RIPPER_STAND_RATE, DoRipperMove, &s_RipperStand[2][0]},
189     },
190     {
191         {RIPPER_STAND_R3 + 0, RIPPER_STAND_RATE, DoRipperMove, &s_RipperStand[3][0]},
192     },
193     {
194         {RIPPER_STAND_R4 + 0, RIPPER_STAND_RATE, DoRipperMove, &s_RipperStand[4][0]},
195     },
196 };
197 
198 
199 STATEp sg_RipperStand[] =
200 {
201     s_RipperStand[0],
202     s_RipperStand[1],
203     s_RipperStand[2],
204     s_RipperStand[3],
205     s_RipperStand[4]
206 };
207 
208 //////////////////////
209 //
210 // RIPPER SWIPE
211 //
212 //////////////////////
213 
214 #define RIPPER_SWIPE_RATE 8
215 ANIMATOR InitActorDecide;
216 ANIMATOR InitRipperSlash;
217 
218 STATE s_RipperSwipe[5][8] =
219 {
220     {
221         {RIPPER_SWIPE_R0 + 0, RIPPER_SWIPE_RATE, NullRipper, &s_RipperSwipe[0][1]},
222         {RIPPER_SWIPE_R0 + 1, RIPPER_SWIPE_RATE, NullRipper, &s_RipperSwipe[0][2]},
223         {RIPPER_SWIPE_R0 + 1, 0 | SF_QUICK_CALL, InitRipperSlash, &s_RipperSwipe[0][3]},
224         {RIPPER_SWIPE_R0 + 2, RIPPER_SWIPE_RATE, NullRipper, &s_RipperSwipe[0][4]},
225         {RIPPER_SWIPE_R0 + 3, RIPPER_SWIPE_RATE, NullRipper, &s_RipperSwipe[0][5]},
226         {RIPPER_SWIPE_R0 + 3, 0 | SF_QUICK_CALL, InitRipperSlash, &s_RipperSwipe[0][6]},
227         {RIPPER_SWIPE_R0 + 3, 0 | SF_QUICK_CALL, InitActorDecide, &s_RipperSwipe[0][7]},
228         {RIPPER_SWIPE_R0 + 3, RIPPER_SWIPE_RATE, DoRipperMove, &s_RipperSwipe[0][7]},
229     },
230     {
231         {RIPPER_SWIPE_R1 + 0, RIPPER_SWIPE_RATE, NullRipper, &s_RipperSwipe[1][1]},
232         {RIPPER_SWIPE_R1 + 1, RIPPER_SWIPE_RATE, NullRipper, &s_RipperSwipe[1][2]},
233         {RIPPER_SWIPE_R1 + 1, 0 | SF_QUICK_CALL, InitRipperSlash, &s_RipperSwipe[1][3]},
234         {RIPPER_SWIPE_R1 + 2, RIPPER_SWIPE_RATE, NullRipper, &s_RipperSwipe[1][4]},
235         {RIPPER_SWIPE_R1 + 3, RIPPER_SWIPE_RATE, NullRipper, &s_RipperSwipe[1][5]},
236         {RIPPER_SWIPE_R1 + 3, 0 | SF_QUICK_CALL, InitRipperSlash, &s_RipperSwipe[1][6]},
237         {RIPPER_SWIPE_R1 + 3, 0 | SF_QUICK_CALL, InitActorDecide, &s_RipperSwipe[1][7]},
238         {RIPPER_SWIPE_R1 + 3, RIPPER_SWIPE_RATE, DoRipperMove, &s_RipperSwipe[1][7]},
239     },
240     {
241         {RIPPER_SWIPE_R2 + 0, RIPPER_SWIPE_RATE, NullRipper, &s_RipperSwipe[2][1]},
242         {RIPPER_SWIPE_R2 + 1, RIPPER_SWIPE_RATE, NullRipper, &s_RipperSwipe[2][2]},
243         {RIPPER_SWIPE_R2 + 1, 0 | SF_QUICK_CALL, InitRipperSlash, &s_RipperSwipe[2][3]},
244         {RIPPER_SWIPE_R2 + 2, RIPPER_SWIPE_RATE, NullRipper, &s_RipperSwipe[2][4]},
245         {RIPPER_SWIPE_R2 + 3, RIPPER_SWIPE_RATE, NullRipper, &s_RipperSwipe[2][5]},
246         {RIPPER_SWIPE_R2 + 3, 0 | SF_QUICK_CALL, InitRipperSlash, &s_RipperSwipe[2][6]},
247         {RIPPER_SWIPE_R2 + 3, 0 | SF_QUICK_CALL, InitActorDecide, &s_RipperSwipe[2][7]},
248         {RIPPER_SWIPE_R2 + 3, RIPPER_SWIPE_RATE, DoRipperMove, &s_RipperSwipe[2][7]},
249     },
250     {
251         {RIPPER_SWIPE_R3 + 0, RIPPER_SWIPE_RATE, NullRipper, &s_RipperSwipe[3][1]},
252         {RIPPER_SWIPE_R3 + 1, RIPPER_SWIPE_RATE, NullRipper, &s_RipperSwipe[3][2]},
253         {RIPPER_SWIPE_R3 + 1, 0 | SF_QUICK_CALL, InitRipperSlash, &s_RipperSwipe[3][3]},
254         {RIPPER_SWIPE_R3 + 2, RIPPER_SWIPE_RATE, NullRipper, &s_RipperSwipe[3][4]},
255         {RIPPER_SWIPE_R3 + 3, RIPPER_SWIPE_RATE, NullRipper, &s_RipperSwipe[3][5]},
256         {RIPPER_SWIPE_R3 + 3, 0 | SF_QUICK_CALL, InitRipperSlash, &s_RipperSwipe[3][6]},
257         {RIPPER_SWIPE_R3 + 3, 0 | SF_QUICK_CALL, InitActorDecide, &s_RipperSwipe[3][7]},
258         {RIPPER_SWIPE_R3 + 3, RIPPER_SWIPE_RATE, DoRipperMove, &s_RipperSwipe[3][7]},
259     },
260     {
261         {RIPPER_SWIPE_R4 + 0, RIPPER_SWIPE_RATE, NullRipper, &s_RipperSwipe[4][1]},
262         {RIPPER_SWIPE_R4 + 1, RIPPER_SWIPE_RATE, NullRipper, &s_RipperSwipe[4][2]},
263         {RIPPER_SWIPE_R4 + 1, 0 | SF_QUICK_CALL, InitRipperSlash, &s_RipperSwipe[4][3]},
264         {RIPPER_SWIPE_R4 + 2, RIPPER_SWIPE_RATE, NullRipper, &s_RipperSwipe[4][4]},
265         {RIPPER_SWIPE_R4 + 3, RIPPER_SWIPE_RATE, NullRipper, &s_RipperSwipe[4][5]},
266         {RIPPER_SWIPE_R4 + 3, 0 | SF_QUICK_CALL, InitRipperSlash, &s_RipperSwipe[4][6]},
267         {RIPPER_SWIPE_R4 + 3, 0 | SF_QUICK_CALL, InitActorDecide, &s_RipperSwipe[4][7]},
268         {RIPPER_SWIPE_R4 + 3, RIPPER_SWIPE_RATE, DoRipperMove, &s_RipperSwipe[4][7]},
269     }
270 };
271 
272 
273 STATEp sg_RipperSwipe[] =
274 {
275     &s_RipperSwipe[0][0],
276     &s_RipperSwipe[1][0],
277     &s_RipperSwipe[2][0],
278     &s_RipperSwipe[3][0],
279     &s_RipperSwipe[4][0]
280 };
281 
282 
283 //////////////////////
284 //
285 // RIPPER SPEW
286 //
287 //////////////////////
288 
289 #define RIPPER_SPEW_RATE 8
290 ANIMATOR InitActorDecide;
291 ANIMATOR InitCoolgFire;
292 
293 STATE s_RipperSpew[5][7] =
294 {
295     {
296         {RIPPER_SWIPE_R0 + 0, RIPPER_SPEW_RATE, NullRipper, &s_RipperSpew[0][1]},
297         {RIPPER_SWIPE_R0 + 1, RIPPER_SPEW_RATE, NullRipper, &s_RipperSpew[0][2]},
298         {RIPPER_SWIPE_R0 + 1, 0 | SF_QUICK_CALL, InitCoolgFire, &s_RipperSpew[0][3]},
299         {RIPPER_SWIPE_R0 + 2, RIPPER_SPEW_RATE, NullRipper, &s_RipperSpew[0][4]},
300         {RIPPER_SWIPE_R0 + 3, RIPPER_SPEW_RATE, NullRipper, &s_RipperSpew[0][5]},
301         {RIPPER_SWIPE_R0 + 3, 0 | SF_QUICK_CALL, InitActorDecide, &s_RipperSpew[0][6]},
302         {RIPPER_SWIPE_R0 + 3, RIPPER_SPEW_RATE, DoRipperMove, &s_RipperSpew[0][6]},
303     },
304     {
305         {RIPPER_SWIPE_R1 + 0, RIPPER_SPEW_RATE, NullRipper, &s_RipperSpew[1][1]},
306         {RIPPER_SWIPE_R1 + 1, RIPPER_SPEW_RATE, NullRipper, &s_RipperSpew[1][2]},
307         {RIPPER_SWIPE_R1 + 1, 0 | SF_QUICK_CALL, InitCoolgFire, &s_RipperSpew[1][3]},
308         {RIPPER_SWIPE_R1 + 2, RIPPER_SPEW_RATE, NullRipper, &s_RipperSpew[1][4]},
309         {RIPPER_SWIPE_R1 + 3, RIPPER_SPEW_RATE, NullRipper, &s_RipperSpew[1][5]},
310         {RIPPER_SWIPE_R1 + 3, 0 | SF_QUICK_CALL, InitActorDecide, &s_RipperSpew[1][6]},
311         {RIPPER_SWIPE_R1 + 3, RIPPER_SPEW_RATE, DoRipperMove, &s_RipperSpew[1][6]},
312     },
313     {
314         {RIPPER_SWIPE_R2 + 0, RIPPER_SPEW_RATE, NullRipper, &s_RipperSpew[2][1]},
315         {RIPPER_SWIPE_R2 + 1, RIPPER_SPEW_RATE, NullRipper, &s_RipperSpew[2][2]},
316         {RIPPER_SWIPE_R2 + 1, 0 | SF_QUICK_CALL, InitCoolgFire, &s_RipperSpew[2][3]},
317         {RIPPER_SWIPE_R2 + 2, RIPPER_SPEW_RATE, NullRipper, &s_RipperSpew[2][4]},
318         {RIPPER_SWIPE_R2 + 3, RIPPER_SPEW_RATE, NullRipper, &s_RipperSpew[2][5]},
319         {RIPPER_SWIPE_R2 + 3, 0 | SF_QUICK_CALL, InitActorDecide, &s_RipperSpew[2][6]},
320         {RIPPER_SWIPE_R2 + 3, RIPPER_SPEW_RATE, DoRipperMove, &s_RipperSpew[2][6]},
321     },
322     {
323         {RIPPER_SWIPE_R3 + 0, RIPPER_SPEW_RATE, NullRipper, &s_RipperSpew[3][1]},
324         {RIPPER_SWIPE_R3 + 1, RIPPER_SPEW_RATE, NullRipper, &s_RipperSpew[3][2]},
325         {RIPPER_SWIPE_R3 + 1, 0 | SF_QUICK_CALL, InitCoolgFire, &s_RipperSpew[3][3]},
326         {RIPPER_SWIPE_R3 + 2, RIPPER_SPEW_RATE, NullRipper, &s_RipperSpew[3][4]},
327         {RIPPER_SWIPE_R3 + 3, RIPPER_SPEW_RATE, NullRipper, &s_RipperSpew[3][5]},
328         {RIPPER_SWIPE_R3 + 3, 0 | SF_QUICK_CALL, InitActorDecide, &s_RipperSpew[3][6]},
329         {RIPPER_SWIPE_R3 + 3, RIPPER_SPEW_RATE, DoRipperMove, &s_RipperSpew[3][6]},
330     },
331     {
332         {RIPPER_SWIPE_R4 + 0, RIPPER_SPEW_RATE, NullRipper, &s_RipperSpew[4][1]},
333         {RIPPER_SWIPE_R4 + 1, RIPPER_SPEW_RATE, NullRipper, &s_RipperSpew[4][2]},
334         {RIPPER_SWIPE_R4 + 1, 0 | SF_QUICK_CALL, InitCoolgFire, &s_RipperSpew[4][3]},
335         {RIPPER_SWIPE_R4 + 2, RIPPER_SPEW_RATE, NullRipper, &s_RipperSpew[4][4]},
336         {RIPPER_SWIPE_R4 + 3, RIPPER_SPEW_RATE, NullRipper, &s_RipperSpew[4][5]},
337         {RIPPER_SWIPE_R4 + 3, 0 | SF_QUICK_CALL, InitActorDecide, &s_RipperSpew[4][6]},
338         {RIPPER_SWIPE_R4 + 3, RIPPER_SPEW_RATE, DoRipperMove, &s_RipperSpew[4][6]},
339     }
340 };
341 
342 
343 STATEp sg_RipperSpew[] =
344 {
345     &s_RipperSpew[0][0],
346     &s_RipperSpew[1][0],
347     &s_RipperSpew[2][0],
348     &s_RipperSpew[3][0],
349     &s_RipperSpew[4][0]
350 };
351 
352 
353 //////////////////////
354 //
355 // RIPPER HEART - show players heart
356 //
357 //////////////////////
358 
359 #define RIPPER_HEART_RATE 14
360 ANIMATOR DoRipperStandHeart;
361 
362 STATE s_RipperHeart[5][4] =
363 {
364     {
365         {RIPPER_HEART_R0 + 0, RIPPER_HEART_RATE, DoRipperStandHeart, &s_RipperHeart[0][0]},
366     },
367     {
368         {RIPPER_HEART_R1 + 0, RIPPER_HEART_RATE, DoRipperStandHeart, &s_RipperHeart[1][0]},
369     },
370     {
371         {RIPPER_HEART_R2 + 0, RIPPER_HEART_RATE, DoRipperStandHeart, &s_RipperHeart[2][0]},
372     },
373     {
374         {RIPPER_HEART_R3 + 0, RIPPER_HEART_RATE, DoRipperStandHeart, &s_RipperHeart[3][0]},
375     },
376     {
377         {RIPPER_HEART_R4 + 0, RIPPER_HEART_RATE, DoRipperStandHeart, &s_RipperHeart[4][0]},
378     }
379 };
380 
381 STATEp sg_RipperHeart[] =
382 {
383     &s_RipperHeart[0][0],
384     &s_RipperHeart[1][0],
385     &s_RipperHeart[2][0],
386     &s_RipperHeart[3][0],
387     &s_RipperHeart[4][0]
388 };
389 
390 //////////////////////
391 //
392 // RIPPER HANG
393 //
394 //////////////////////
395 
396 #define RIPPER_HANG_RATE 14
397 ANIMATOR DoRipperHang;
398 
399 STATE s_RipperHang[5][4] =
400 {
401     {
402         {RIPPER_HANG_R0 + 0, RIPPER_HANG_RATE, DoRipperHang, &s_RipperHang[0][0]},
403     },
404     {
405         {RIPPER_HANG_R1 + 0, RIPPER_HANG_RATE, DoRipperHang, &s_RipperHang[1][0]},
406     },
407     {
408         {RIPPER_HANG_R2 + 0, RIPPER_HANG_RATE, DoRipperHang, &s_RipperHang[2][0]},
409     },
410     {
411         {RIPPER_HANG_R3 + 0, RIPPER_HANG_RATE, DoRipperHang, &s_RipperHang[3][0]},
412     },
413     {
414         {RIPPER_HANG_R4 + 0, RIPPER_HANG_RATE, DoRipperHang, &s_RipperHang[4][0]},
415     }
416 };
417 
418 
419 STATEp sg_RipperHang[] =
420 {
421     &s_RipperHang[0][0],
422     &s_RipperHang[1][0],
423     &s_RipperHang[2][0],
424     &s_RipperHang[3][0],
425     &s_RipperHang[4][0]
426 };
427 
428 
429 //////////////////////
430 //
431 // RIPPER PAIN
432 //
433 //////////////////////
434 
435 #define RIPPER_PAIN_RATE 38
436 ANIMATOR DoRipperPain;
437 
438 STATE s_RipperPain[5][1] =
439 {
440     {
441         {RIPPER_JUMP_R0 + 0, RIPPER_PAIN_RATE, DoRipperPain, &s_RipperPain[0][0]},
442     },
443     {
444         {RIPPER_JUMP_R0 + 0, RIPPER_PAIN_RATE, DoRipperPain, &s_RipperPain[1][0]},
445     },
446     {
447         {RIPPER_JUMP_R0 + 0, RIPPER_PAIN_RATE, DoRipperPain, &s_RipperPain[2][0]},
448     },
449     {
450         {RIPPER_JUMP_R0 + 0, RIPPER_PAIN_RATE, DoRipperPain, &s_RipperPain[3][0]},
451     },
452     {
453         {RIPPER_JUMP_R0 + 0, RIPPER_PAIN_RATE, DoRipperPain, &s_RipperPain[4][0]},
454     }
455 };
456 
457 STATEp sg_RipperPain[] =
458 {
459     &s_RipperPain[0][0],
460     &s_RipperPain[1][0],
461     &s_RipperPain[2][0],
462     &s_RipperPain[3][0],
463     &s_RipperPain[4][0]
464 };
465 
466 //////////////////////
467 //
468 // RIPPER JUMP
469 //
470 //////////////////////
471 
472 #define RIPPER_JUMP_RATE 25
473 
474 STATE s_RipperJump[5][6] =
475 {
476     {
477         {RIPPER_JUMP_R0 + 0, RIPPER_JUMP_RATE, NullRipper, &s_RipperJump[0][1]},
478         {RIPPER_JUMP_R0 + 1, RIPPER_JUMP_RATE, DoRipperMoveJump, &s_RipperJump[0][1]},
479     },
480     {
481         {RIPPER_JUMP_R1 + 0, RIPPER_JUMP_RATE, NullRipper, &s_RipperJump[1][1]},
482         {RIPPER_JUMP_R1 + 1, RIPPER_JUMP_RATE, DoRipperMoveJump, &s_RipperJump[1][1]},
483     },
484     {
485         {RIPPER_JUMP_R2 + 0, RIPPER_JUMP_RATE, NullRipper, &s_RipperJump[2][1]},
486         {RIPPER_JUMP_R2 + 1, RIPPER_JUMP_RATE, DoRipperMoveJump, &s_RipperJump[2][1]},
487     },
488     {
489         {RIPPER_JUMP_R3 + 0, RIPPER_JUMP_RATE, NullRipper, &s_RipperJump[3][1]},
490         {RIPPER_JUMP_R3 + 1, RIPPER_JUMP_RATE, DoRipperMoveJump, &s_RipperJump[3][1]},
491     },
492     {
493         {RIPPER_JUMP_R4 + 0, RIPPER_JUMP_RATE, NullRipper, &s_RipperJump[4][1]},
494         {RIPPER_JUMP_R4 + 1, RIPPER_JUMP_RATE, DoRipperMoveJump, &s_RipperJump[4][1]},
495     }
496 };
497 
498 
499 STATEp sg_RipperJump[] =
500 {
501     &s_RipperJump[0][0],
502     &s_RipperJump[1][0],
503     &s_RipperJump[2][0],
504     &s_RipperJump[3][0],
505     &s_RipperJump[4][0]
506 };
507 
508 
509 //////////////////////
510 //
511 // RIPPER FALL
512 //
513 //////////////////////
514 
515 #define RIPPER_FALL_RATE 25
516 
517 STATE s_RipperFall[5][6] =
518 {
519     {
520         {RIPPER_FALL_R0 + 0, RIPPER_FALL_RATE, DoRipperMoveJump, &s_RipperFall[0][0]},
521     },
522     {
523         {RIPPER_FALL_R1 + 0, RIPPER_FALL_RATE, DoRipperMoveJump, &s_RipperFall[1][0]},
524     },
525     {
526         {RIPPER_FALL_R2 + 0, RIPPER_FALL_RATE, DoRipperMoveJump, &s_RipperFall[2][0]},
527     },
528     {
529         {RIPPER_FALL_R3 + 0, RIPPER_FALL_RATE, DoRipperMoveJump, &s_RipperFall[3][0]},
530     },
531     {
532         {RIPPER_FALL_R4 + 0, RIPPER_FALL_RATE, DoRipperMoveJump, &s_RipperFall[4][0]},
533     }
534 };
535 
536 
537 STATEp sg_RipperFall[] =
538 {
539     &s_RipperFall[0][0],
540     &s_RipperFall[1][0],
541     &s_RipperFall[2][0],
542     &s_RipperFall[3][0],
543     &s_RipperFall[4][0]
544 };
545 
546 
547 //////////////////////
548 //
549 // RIPPER JUMP ATTACK
550 //
551 //////////////////////
552 
553 #define RIPPER_JUMP_ATTACK_RATE 35
554 int DoRipperBeginJumpAttack(short SpriteNum);
555 
556 STATE s_RipperJumpAttack[5][6] =
557 {
558     {
559         {RIPPER_JUMP_R0 + 0, RIPPER_JUMP_ATTACK_RATE, NullRipper, &s_RipperJumpAttack[0][1]},
560         {RIPPER_JUMP_R0 + 0, 0 | SF_QUICK_CALL, DoRipperBeginJumpAttack, &s_RipperJumpAttack[0][2]},
561         {RIPPER_JUMP_R0 + 1, RIPPER_JUMP_ATTACK_RATE, DoRipperMoveJump, &s_RipperJumpAttack[0][2]},
562     },
563     {
564         {RIPPER_JUMP_R1 + 0, RIPPER_JUMP_ATTACK_RATE, NullRipper, &s_RipperJumpAttack[1][1]},
565         {RIPPER_JUMP_R1 + 0, 0 | SF_QUICK_CALL, DoRipperBeginJumpAttack, &s_RipperJumpAttack[1][2]},
566         {RIPPER_JUMP_R1 + 1, RIPPER_JUMP_ATTACK_RATE, DoRipperMoveJump, &s_RipperJumpAttack[1][2]},
567     },
568     {
569         {RIPPER_JUMP_R2 + 0, RIPPER_JUMP_ATTACK_RATE, NullRipper, &s_RipperJumpAttack[2][1]},
570         {RIPPER_JUMP_R2 + 0, 0 | SF_QUICK_CALL, DoRipperBeginJumpAttack, &s_RipperJumpAttack[2][2]},
571         {RIPPER_JUMP_R2 + 1, RIPPER_JUMP_ATTACK_RATE, DoRipperMoveJump, &s_RipperJumpAttack[2][2]},
572     },
573     {
574         {RIPPER_JUMP_R3 + 0, RIPPER_JUMP_ATTACK_RATE, NullRipper, &s_RipperJumpAttack[3][1]},
575         {RIPPER_JUMP_R3 + 0, 0 | SF_QUICK_CALL, DoRipperBeginJumpAttack, &s_RipperJumpAttack[3][2]},
576         {RIPPER_JUMP_R3 + 1, RIPPER_JUMP_ATTACK_RATE, DoRipperMoveJump, &s_RipperJumpAttack[3][2]},
577     },
578     {
579         {RIPPER_JUMP_R4 + 0, RIPPER_JUMP_ATTACK_RATE, NullRipper, &s_RipperJumpAttack[4][1]},
580         {RIPPER_JUMP_R4 + 0, 0 | SF_QUICK_CALL, DoRipperBeginJumpAttack, &s_RipperJumpAttack[4][2]},
581         {RIPPER_JUMP_R4 + 1, RIPPER_JUMP_ATTACK_RATE, DoRipperMoveJump, &s_RipperJumpAttack[4][2]},
582     }
583 };
584 
585 
586 STATEp sg_RipperJumpAttack[] =
587 {
588     &s_RipperJumpAttack[0][0],
589     &s_RipperJumpAttack[1][0],
590     &s_RipperJumpAttack[2][0],
591     &s_RipperJumpAttack[3][0],
592     &s_RipperJumpAttack[4][0]
593 };
594 
595 
596 //////////////////////
597 //
598 // RIPPER HANG_JUMP
599 //
600 //////////////////////
601 
602 #define RIPPER_HANG_JUMP_RATE 20
603 
604 STATE s_RipperHangJump[5][6] =
605 {
606     {
607         {RIPPER_JUMP_R0 + 0, RIPPER_HANG_JUMP_RATE, NullRipper, &s_RipperHangJump[0][1]},
608         {RIPPER_JUMP_R0 + 1, RIPPER_HANG_JUMP_RATE, DoRipperHangJF, &s_RipperHangJump[0][1]},
609     },
610     {
611         {RIPPER_JUMP_R1 + 0, RIPPER_HANG_JUMP_RATE, NullRipper, &s_RipperHangJump[1][1]},
612         {RIPPER_JUMP_R1 + 1, RIPPER_HANG_JUMP_RATE, DoRipperHangJF, &s_RipperHangJump[1][1]},
613     },
614     {
615         {RIPPER_JUMP_R2 + 0, RIPPER_HANG_JUMP_RATE, NullRipper, &s_RipperHangJump[2][1]},
616         {RIPPER_JUMP_R2 + 1, RIPPER_HANG_JUMP_RATE, DoRipperHangJF, &s_RipperHangJump[2][1]},
617     },
618     {
619         {RIPPER_JUMP_R3 + 0, RIPPER_HANG_JUMP_RATE, NullRipper, &s_RipperHangJump[3][1]},
620         {RIPPER_JUMP_R3 + 1, RIPPER_HANG_JUMP_RATE, DoRipperHangJF, &s_RipperHangJump[3][1]},
621     },
622     {
623         {RIPPER_JUMP_R4 + 0, RIPPER_HANG_JUMP_RATE, NullRipper, &s_RipperHangJump[4][1]},
624         {RIPPER_JUMP_R4 + 1, RIPPER_HANG_JUMP_RATE, DoRipperHangJF, &s_RipperHangJump[4][1]},
625     }
626 };
627 
628 
629 STATEp sg_RipperHangJump[] =
630 {
631     &s_RipperHangJump[0][0],
632     &s_RipperHangJump[1][0],
633     &s_RipperHangJump[2][0],
634     &s_RipperHangJump[3][0],
635     &s_RipperHangJump[4][0]
636 };
637 
638 //////////////////////
639 //
640 // RIPPER HANG_FALL
641 //
642 //////////////////////
643 
644 #define RIPPER_FALL_RATE 25
645 
646 STATE s_RipperHangFall[5][6] =
647 {
648     {
649         {RIPPER_FALL_R0 + 0, RIPPER_FALL_RATE, DoRipperHangJF, &s_RipperHangFall[0][0]},
650     },
651     {
652         {RIPPER_FALL_R1 + 0, RIPPER_FALL_RATE, DoRipperHangJF, &s_RipperHangFall[1][0]},
653     },
654     {
655         {RIPPER_FALL_R2 + 0, RIPPER_FALL_RATE, DoRipperHangJF, &s_RipperHangFall[2][0]},
656     },
657     {
658         {RIPPER_FALL_R3 + 0, RIPPER_FALL_RATE, DoRipperHangJF, &s_RipperHangFall[3][0]},
659     },
660     {
661         {RIPPER_FALL_R4 + 0, RIPPER_FALL_RATE, DoRipperHangJF, &s_RipperHangFall[4][0]},
662     }
663 };
664 
665 
666 STATEp sg_RipperHangFall[] =
667 {
668     &s_RipperHangFall[0][0],
669     &s_RipperHangFall[1][0],
670     &s_RipperHangFall[2][0],
671     &s_RipperHangFall[3][0],
672     &s_RipperHangFall[4][0]
673 };
674 
675 
676 
677 //////////////////////
678 //
679 // RIPPER DIE
680 //
681 //////////////////////
682 
683 #define RIPPER_DIE_RATE 16
684 
685 STATE s_RipperDie[] =
686 {
687     {RIPPER_DIE + 0, RIPPER_DIE_RATE, NullRipper, &s_RipperDie[1]},
688     {RIPPER_DIE + 1, RIPPER_DIE_RATE, NullRipper, &s_RipperDie[2]},
689     {RIPPER_DIE + 2, RIPPER_DIE_RATE, NullRipper, &s_RipperDie[3]},
690     {RIPPER_DIE + 3, RIPPER_DIE_RATE, NullRipper, &s_RipperDie[4]},
691     {RIPPER_DEAD, RIPPER_DIE_RATE, DoActorDebris, &s_RipperDie[4]},
692 };
693 
694 #define RIPPER_DEAD_RATE 8
695 
696 STATE s_RipperDead[] =
697 {
698     {RIPPER_DIE + 2, RIPPER_DEAD_RATE, NullAnimator, &s_RipperDead[1]},
699     {RIPPER_DIE + 3, RIPPER_DEAD_RATE, NullAnimator, &s_RipperDead[2]},
700     {RIPPER_DEAD, SF_QUICK_CALL, QueueFloorBlood, &s_RipperDead[3]},
701     {RIPPER_DEAD, RIPPER_DEAD_RATE, DoActorDebris, &s_RipperDead[3]},
702 };
703 
704 STATEp sg_RipperDie[] =
705 {
706     s_RipperDie
707 };
708 
709 STATEp sg_RipperDead[] =
710 {
711     s_RipperDead
712 };
713 
714 STATE s_RipperDeathJump[] =
715 {
716     {RIPPER_DIE + 0, RIPPER_DIE_RATE, DoActorDeathMove, &s_RipperDeathJump[0]}
717 };
718 
719 STATE s_RipperDeathFall[] =
720 {
721     {RIPPER_DIE + 1, RIPPER_DIE_RATE, DoActorDeathMove, &s_RipperDeathFall[0]}
722 };
723 
724 
725 STATEp sg_RipperDeathJump[] =
726 {
727     s_RipperDeathJump
728 };
729 
730 STATEp sg_RipperDeathFall[] =
731 {
732     s_RipperDeathFall
733 };
734 
735 
736 /*
737 STATEp *Stand[MAX_WEAPONS];
738 STATEp *Run;
739 STATEp *Jump;
740 STATEp *Fall;
741 STATEp *Crawl;
742 STATEp *Swim;
743 STATEp *Fly;
744 STATEp *Rise;
745 STATEp *Sit;
746 STATEp *Look;
747 STATEp *Climb;
748 STATEp *Pain;
749 STATEp *Death1;
750 STATEp *Death2;
751 STATEp *Dead;
752 STATEp *DeathJump;
753 STATEp *DeathFall;
754 STATEp *CloseAttack[2];
755 STATEp *Attack[6];
756 STATEp *Special[2];
757 */
758 
759 
760 ACTOR_ACTION_SET RipperActionSet =
761 {
762     sg_RipperStand,
763     sg_RipperRun,
764     sg_RipperJump,
765     sg_RipperFall,
766     NULL,                               // sg_RipperCrawl,
767     NULL,                               // sg_RipperSwim,
768     NULL,                               // sg_RipperFly,
769     NULL,                               // sg_RipperRise,
770     NULL,                               // sg_RipperSit,
771     NULL,                               // sg_RipperLook,
772     NULL,                               // climb
773     sg_RipperPain,
774     sg_RipperDie,
775     NULL,                               // sg_RipperHariKari,
776     sg_RipperDead,
777     sg_RipperDeathJump,
778     sg_RipperDeathFall,
779     {sg_RipperSwipe,sg_RipperSpew},
780     {800,1024},
781     {sg_RipperJumpAttack, sg_RipperSpew},
782     {400, 1024},
783     {sg_RipperHeart, sg_RipperHang},
784     NULL,
785     NULL
786 };
787 
788 ACTOR_ACTION_SET RipperBrownActionSet =
789 {
790     sg_RipperStand,
791     sg_RipperRun,
792     sg_RipperJump,
793     sg_RipperFall,
794     NULL,                               // sg_RipperCrawl,
795     NULL,                               // sg_RipperSwim,
796     NULL,                               // sg_RipperFly,
797     NULL,                               // sg_RipperRise,
798     NULL,                               // sg_RipperSit,
799     NULL,                               // sg_RipperLook,
800     NULL,                               // climb
801     sg_RipperPain,                      // pain
802     sg_RipperDie,
803     NULL,                               // sg_RipperHariKari,
804     sg_RipperDead,
805     sg_RipperDeathJump,
806     sg_RipperDeathFall,
807     {sg_RipperSwipe},
808     {1024},
809     {sg_RipperJumpAttack, sg_RipperSwipe},
810     {800, 1024},
811     {sg_RipperHeart, sg_RipperHang},
812     NULL,
813     NULL
814 };
815 
816 int
SetupRipper(short SpriteNum)817 SetupRipper(short SpriteNum)
818 {
819     SPRITEp sp = &sprite[SpriteNum];
820     USERp u;
821     ANIMATOR DoActorDecide;
822 
823     if (TEST(sp->cstat, CSTAT_SPRITE_RESTORE))
824     {
825         u = User[SpriteNum];
826         ASSERT(u);
827     }
828     else
829     {
830         User[SpriteNum] = u = SpawnUser(SpriteNum, RIPPER_RUN_R0, s_RipperRun[0]);
831         u->Health = HEALTH_RIPPER/2; // Baby rippers are weaker
832     }
833 
834     ChangeState(SpriteNum, s_RipperRun[0]);
835     u->Attrib = &RipperAttrib;
836     DoActorSetSpeed(SpriteNum, FAST_SPEED);
837     u->StateEnd = s_RipperDie;
838     u->Rot = sg_RipperRun;
839     sp->xrepeat = 64;
840     sp->yrepeat = 64;
841 
842     if (sp->pal == PALETTE_BROWN_RIPPER)
843     {
844         EnemyDefaults(SpriteNum, &RipperBrownActionSet, &RipperPersonality);
845         sp->xrepeat = 106;
846         sp->yrepeat = 90;
847 
848         if (!TEST(sp->cstat, CSTAT_SPRITE_RESTORE))
849             u->Health = HEALTH_MOMMA_RIPPER;
850 
851         sp->clipdist += 128 >> 2;
852     }
853     else
854     {
855         EnemyDefaults(SpriteNum, &RipperActionSet, &RipperPersonality);
856     }
857 
858     SET(u->Flags, SPR_XFLIP_TOGGLE);
859 
860     return 0;
861 }
862 
863 int
GetJumpHeight(short jump_speed,short jump_grav)864 GetJumpHeight(short jump_speed, short jump_grav)
865 {
866     int jump_iterations;
867     int height;
868 
869     jump_speed = labs(jump_speed);
870 
871     jump_iterations = jump_speed / (jump_grav * ACTORMOVETICS);
872 
873     height = jump_speed * jump_iterations * ACTORMOVETICS;
874 
875     height = DIV256(height);
876 
877     return DIV2(height);
878 }
879 
880 int
PickJumpSpeed(short SpriteNum,int pix_height)881 PickJumpSpeed(short SpriteNum, int pix_height)
882 {
883     USERp u = User[SpriteNum];
884 
885     //ASSERT(pix_height < 128);
886 
887     u->jump_speed = -600;
888     u->jump_grav = 8;
889 
890     while (TRUE)
891     {
892         if (GetJumpHeight(u->jump_speed, u->jump_grav) > pix_height + 20)
893             break;
894 
895         u->jump_speed -= 100;
896 
897         ASSERT(u->jump_speed > -3000);
898     }
899 
900     return u->jump_speed;
901 }
902 
903 
904 int
PickJumpMaxSpeed(short SpriteNum,short max_speed)905 PickJumpMaxSpeed(short SpriteNum, short max_speed)
906 {
907     SPRITEp sp = &sprite[SpriteNum];
908     USERp u = User[SpriteNum];
909     int zh;
910 
911     ASSERT(max_speed < 0);
912 
913     u->jump_speed = max_speed;
914     u->jump_grav = 8;
915 
916     zh = SPRITEp_TOS(sp);
917 
918     while (TRUE)
919     {
920         if (zh - Z(GetJumpHeight(u->jump_speed, u->jump_grav)) - Z(16) > u->hiz)
921             break;
922 
923         u->jump_speed += 100;
924 
925         if (u->jump_speed > -200)
926             break;
927     }
928 
929     return u->jump_speed;
930 }
931 
932 
933 //
934 // HANGING - Jumping/Falling/Stationary
935 //
936 
937 int
InitRipperHang(short SpriteNum)938 InitRipperHang(short SpriteNum)
939 {
940     SPRITEp sp = &sprite[SpriteNum];
941     USERp u = User[SpriteNum];
942     int dist;
943 
944     hitdata_t hitinfo = { { 0, 0, 0 }, -2, 0, -2 };
945 
946     SWBOOL Found = FALSE;
947     short dang, tang;
948 
949     for (dang = 0; dang < 2048; dang += 128)
950     {
951         tang = NORM_ANGLE(sp->ang + dang);
952 
953         FAFhitscan(sp->x, sp->y, sp->z - SPRITEp_SIZE_Z(sp), sp->sectnum,  // Start position
954                    sintable[NORM_ANGLE(tang + 512)],   // X vector of 3D ang
955                    sintable[tang],             // Y vector of 3D ang
956                    0,                          // Z vector of 3D ang
957                    &hitinfo, CLIPMASK_MISSILE);
958 
959         //ASSERT(hitinfo.sect >= 0);
960         if (hitinfo.sect < 0)
961             continue;
962 
963         dist = Distance(sp->x, sp->y, hitinfo.pos.x, hitinfo.pos.y);
964 
965         if (hitinfo.wall < 0 || dist < 2000 || dist > 7000)
966         {
967             continue;
968         }
969 
970         Found = TRUE;
971         sp->ang = tang;
972         break;
973     }
974 
975     if (!Found)
976     {
977         InitActorDecide(SpriteNum);
978         return 0;
979     }
980 
981     NewStateGroup(SpriteNum, sg_RipperHangJump);
982     u->StateFallOverride = sg_RipperHangFall;
983     DoActorSetSpeed(SpriteNum, FAST_SPEED);
984 
985     //u->jump_speed = -800;
986     PickJumpMaxSpeed(SpriteNum, -800);
987 
988     SET(u->Flags, SPR_JUMPING);
989     RESET(u->Flags, SPR_FALLING);
990 
991     // set up individual actor jump gravity
992     u->jump_grav = 8;
993 
994     DoJump(SpriteNum);
995 
996     return 0;
997 }
998 
999 int
DoRipperHang(short SpriteNum)1000 DoRipperHang(short SpriteNum)
1001 {
1002     USERp u = User[SpriteNum];
1003 
1004     if ((u->WaitTics -= ACTORMOVETICS) > 0)
1005         return 0;
1006 
1007     NewStateGroup(SpriteNum, sg_RipperJumpAttack);
1008     // move to the 2nd frame - past the pause frame
1009     u->Tics += u->State->Tics;
1010     return 0;
1011 }
1012 
1013 int
DoRipperMoveHang(short SpriteNum)1014 DoRipperMoveHang(short SpriteNum)
1015 {
1016     SPRITEp sp = &sprite[SpriteNum];
1017     USERp u = User[SpriteNum];
1018     int nx, ny;
1019 
1020     // Move while jumping
1021     nx = sp->xvel * (int) sintable[NORM_ANGLE(sp->ang + 512)] >> 14;
1022     ny = sp->xvel * (int) sintable[sp->ang] >> 14;
1023 
1024     // if cannot move the sprite
1025     if (!move_actor(SpriteNum, nx, ny, 0L))
1026     {
1027         switch (TEST(u->ret, HIT_MASK))
1028         {
1029         case HIT_WALL:
1030         {
1031             short hit_wall;
1032             short w, nw;
1033 
1034             hit_wall = NORM_WALL(u->ret);
1035 
1036             NewStateGroup(SpriteNum, u->ActorActionSet->Special[1]);
1037             u->WaitTics = 2 + ((RANDOM_P2(4 << 8) >> 8) * 120);
1038 
1039             // hang flush with the wall
1040             w = hit_wall;
1041             nw = wall[w].point2;
1042             sp->ang = NORM_ANGLE(getangle(wall[nw].x - wall[w].x, wall[nw].y - wall[w].y) - 512);
1043 
1044             return 0;
1045         }
1046         }
1047     }
1048 
1049     return 0;
1050 }
1051 
1052 
1053 int
DoRipperHangJF(short SpriteNum)1054 DoRipperHangJF(short SpriteNum)
1055 {
1056     USERp u = User[SpriteNum];
1057 
1058     if (TEST(u->Flags, SPR_JUMPING | SPR_FALLING))
1059     {
1060         if (TEST(u->Flags, SPR_JUMPING))
1061             DoJump(SpriteNum);
1062         else
1063             DoFall(SpriteNum);
1064     }
1065 
1066     if (!TEST(u->Flags, SPR_JUMPING | SPR_FALLING))
1067     {
1068         if (DoRipperQuickJump(SpriteNum))
1069             return 0;
1070 
1071         InitActorDecide(SpriteNum);
1072     }
1073 
1074     DoRipperMoveHang(SpriteNum);
1075 
1076     return 0;
1077 
1078 }
1079 
1080 //
1081 // JUMP ATTACK
1082 //
1083 
1084 int
DoRipperBeginJumpAttack(short SpriteNum)1085 DoRipperBeginJumpAttack(short SpriteNum)
1086 {
1087     SPRITEp sp = &sprite[SpriteNum];
1088     USERp u = User[SpriteNum];
1089     SPRITEp psp = User[SpriteNum]->tgt_sp;
1090     int CanSeePlayer(short SpriteNum);
1091     short tang;
1092 
1093     tang = getangle(psp->x - sp->x, psp->y - sp->y);
1094 
1095     if (move_sprite(SpriteNum, sintable[NORM_ANGLE(tang+512)] >> 7, sintable[tang] >> 7,
1096                     0L, u->ceiling_dist, u->floor_dist, CLIPMASK_ACTOR, ACTORMOVETICS))
1097         sp->ang = NORM_ANGLE((sp->ang + 1024) + (RANDOM_NEG(256, 6) >> 6));
1098     else
1099         sp->ang = NORM_ANGLE(tang + (RANDOM_NEG(256, 6) >> 6));
1100 
1101     DoActorSetSpeed(SpriteNum, FAST_SPEED);
1102 
1103     //u->jump_speed = -800;
1104     PickJumpMaxSpeed(SpriteNum, -400); // was -800
1105 
1106     SET(u->Flags, SPR_JUMPING);
1107     RESET(u->Flags, SPR_FALLING);
1108 
1109     // set up individual actor jump gravity
1110     u->jump_grav = 17; // was 8
1111 
1112     // if I didn't do this here they get stuck in the air sometimes
1113     DoActorZrange(SpriteNum);
1114 
1115     DoJump(SpriteNum);
1116 
1117     return 0;
1118 }
1119 
1120 int
DoRipperMoveJump(short SpriteNum)1121 DoRipperMoveJump(short SpriteNum)
1122 {
1123     USERp u = User[SpriteNum];
1124 
1125     if (TEST(u->Flags, SPR_JUMPING | SPR_FALLING))
1126     {
1127         if (TEST(u->Flags, SPR_JUMPING))
1128             DoJump(SpriteNum);
1129         else
1130             DoFall(SpriteNum);
1131     }
1132 
1133     if (!TEST(u->Flags, SPR_JUMPING | SPR_FALLING))
1134     {
1135         if (DoRipperQuickJump(SpriteNum))
1136             return 0;
1137 
1138         InitActorDecide(SpriteNum);
1139     }
1140 
1141     DoRipperMoveHang(SpriteNum);
1142     return 0;
1143 }
1144 
1145 //
1146 // STD MOVEMENT
1147 //
1148 
1149 int
DoRipperQuickJump(short SpriteNum)1150 DoRipperQuickJump(short SpriteNum)
1151 {
1152     USERp u = User[SpriteNum];
1153 
1154     // Tests to see if ripper is on top of a player/enemy and then immediatly
1155     // does another jump
1156 
1157     if (u->lo_sp)
1158     {
1159         SPRITEp tsp = u->lo_sp;
1160 
1161         if (TEST(tsp->extra, SPRX_PLAYER_OR_ENEMY))
1162         {
1163             NewStateGroup(SpriteNum, sg_RipperJumpAttack);
1164             // move past the first state
1165             u->Tics = 30;
1166             return TRUE;
1167         }
1168     }
1169 
1170     return FALSE;
1171 }
1172 
1173 
1174 int
NullRipper(short SpriteNum)1175 NullRipper(short SpriteNum)
1176 {
1177     USERp u = User[SpriteNum];
1178 
1179     if (TEST(u->Flags,SPR_SLIDING))
1180         DoActorSlide(SpriteNum);
1181 
1182     DoActorSectorDamage(SpriteNum);
1183 
1184     return 0;
1185 }
1186 
1187 
DoRipperPain(short SpriteNum)1188 int DoRipperPain(short SpriteNum)
1189 {
1190     USERp u = User[SpriteNum];
1191 
1192     NullRipper(SpriteNum);
1193 
1194     if ((u->WaitTics -= ACTORMOVETICS) <= 0)
1195         InitActorDecide(SpriteNum);
1196     return 0;
1197 }
1198 
1199 
1200 // CTW MODIFICATION
1201 //int DoRipperRipHeart(SpriteNum)
DoRipperRipHeart(short SpriteNum)1202 int DoRipperRipHeart(short SpriteNum)
1203 // CTW MODIFICATION END
1204 {
1205     SPRITEp sp = &sprite[SpriteNum];
1206     USERp u = User[SpriteNum];
1207 
1208     SPRITEp tsp = u->tgt_sp;
1209 
1210     NewStateGroup(SpriteNum, sg_RipperHeart);
1211     u->WaitTics = 6 * 120;
1212 
1213     // player face ripper
1214     tsp->ang = getangle(sp->x - tsp->x, sp->y - tsp->y);
1215     return 0;
1216 }
1217 
1218 // CTW MODIFICATION
1219 //int DoRipperStandHeart(SpriteNum)
DoRipperStandHeart(short SpriteNum)1220 int DoRipperStandHeart(short SpriteNum)
1221 // CTW MODIFICATION END
1222 {
1223     USERp u = User[SpriteNum];
1224 
1225     NullRipper(SpriteNum);
1226 
1227     if ((u->WaitTics -= ACTORMOVETICS) <= 0)
1228         NewStateGroup(SpriteNum, sg_RipperRun);
1229     return 0;
1230 }
1231 
RipperHatch(short Weapon)1232 void RipperHatch(short Weapon)
1233 {
1234     SPRITEp wp = &sprite[Weapon];
1235 
1236     short New,i;
1237     SPRITEp np;
1238     USERp nu;
1239 #define MAX_RIPPERS 1
1240     short rip_ang[MAX_RIPPERS];
1241 
1242     rip_ang[0] = RANDOM_P2(2048);
1243     // rip_ang[1] = NORM_ANGLE(rip_ang[0] + 1024 + (RANDOM_P2(512) - 256));
1244 
1245     for (i = 0; i < MAX_RIPPERS; i++)
1246     {
1247         New = COVERinsertsprite(wp->sectnum, STAT_DEFAULT);
1248         np = &sprite[New];
1249         memset(np,0,sizeof(SPRITE));
1250         np->sectnum = wp->sectnum;
1251         np->statnum = STAT_DEFAULT;
1252         np->x = wp->x;
1253         np->y = wp->y;
1254         np->z = wp->z;
1255         np->owner = -1;
1256         //np->xrepeat = np->yrepeat = 36;
1257         np->xrepeat = np->yrepeat = 64;
1258         np->ang = rip_ang[i];
1259         np->pal = 0;
1260         SetupRipper(New);
1261         nu = User[New];
1262 
1263         // make immediately active
1264         SET(nu->Flags, SPR_ACTIVE);
1265 
1266         NewStateGroup(New, nu->ActorActionSet->Jump);
1267         nu->ActorActionFunc = DoActorMoveJump;
1268         DoActorSetSpeed(New, FAST_SPEED);
1269         PickJumpMaxSpeed(New, -600);
1270 
1271         SET(nu->Flags, SPR_JUMPING);
1272         RESET(nu->Flags, SPR_FALLING);
1273 
1274         nu->jump_grav = 8;
1275 
1276         // if I didn't do this here they get stuck in the air sometimes
1277         DoActorZrange(New);
1278 
1279         DoJump(New);
1280     }
1281 }
1282 
1283 int
DoRipperMove(short SpriteNum)1284 DoRipperMove(short SpriteNum)
1285 {
1286     USERp u = User[SpriteNum];
1287 
1288     if (u->scale_speed)
1289     {
1290         DoScaleSprite(SpriteNum);
1291     }
1292 
1293     if (TEST(u->Flags, SPR_JUMPING | SPR_FALLING))
1294     {
1295         if (TEST(u->Flags, SPR_JUMPING))
1296             DoJump(SpriteNum);
1297         else
1298             DoFall(SpriteNum);
1299     }
1300 
1301     // if on a player/enemy sprite jump quickly
1302     if (!TEST(u->Flags, SPR_JUMPING | SPR_FALLING))
1303     {
1304         if (DoRipperQuickJump(SpriteNum))
1305             return 0;
1306 
1307         KeepActorOnFloor(SpriteNum);
1308     }
1309 
1310     if (TEST(u->Flags, SPR_SLIDING))
1311         DoActorSlide(SpriteNum);
1312 
1313     if (u->track >= 0)
1314         ActorFollowTrack(SpriteNum, ACTORMOVETICS);
1315     else
1316         (*u->ActorActionFunc)(SpriteNum);
1317 
1318     DoActorSectorDamage(SpriteNum);
1319     return 0;
1320 }
1321 
1322 
1323 #include "saveable.h"
1324 
1325 static saveable_code saveable_ripper_code[] =
1326 {
1327     SAVE_CODE(SetupRipper),
1328     SAVE_CODE(GetJumpHeight),
1329     SAVE_CODE(PickJumpSpeed),
1330     SAVE_CODE(PickJumpMaxSpeed),
1331 
1332     SAVE_CODE(InitRipperHang),
1333     SAVE_CODE(DoRipperHang),
1334     SAVE_CODE(DoRipperMoveHang),
1335     SAVE_CODE(DoRipperHangJF),
1336 
1337     SAVE_CODE(DoRipperBeginJumpAttack),
1338     SAVE_CODE(DoRipperMoveJump),
1339 
1340     SAVE_CODE(DoRipperQuickJump),
1341     SAVE_CODE(NullRipper),
1342     SAVE_CODE(DoRipperPain),
1343     SAVE_CODE(DoRipperRipHeart),
1344     SAVE_CODE(DoRipperStandHeart),
1345     SAVE_CODE(RipperHatch),
1346     SAVE_CODE(DoRipperMove),
1347 };
1348 
1349 static saveable_data saveable_ripper_data[] =
1350 {
1351     SAVE_DATA(RipperBattle),
1352     SAVE_DATA(RipperOffense),
1353     SAVE_DATA(RipperBroadcast),
1354     SAVE_DATA(RipperSurprised),
1355     SAVE_DATA(RipperEvasive),
1356     SAVE_DATA(RipperLostTarget),
1357     SAVE_DATA(RipperCloseRange),
1358 
1359     SAVE_DATA(RipperPersonality),
1360 
1361     SAVE_DATA(RipperAttrib),
1362 
1363     SAVE_DATA(s_RipperRun),
1364     SAVE_DATA(sg_RipperRun),
1365     SAVE_DATA(s_RipperStand),
1366     SAVE_DATA(sg_RipperStand),
1367     SAVE_DATA(s_RipperSwipe),
1368     SAVE_DATA(sg_RipperSwipe),
1369     SAVE_DATA(s_RipperSpew),
1370     SAVE_DATA(sg_RipperSpew),
1371     SAVE_DATA(s_RipperHeart),
1372     SAVE_DATA(sg_RipperHeart),
1373     SAVE_DATA(s_RipperHang),
1374     SAVE_DATA(sg_RipperHang),
1375     SAVE_DATA(s_RipperPain),
1376     SAVE_DATA(sg_RipperPain),
1377     SAVE_DATA(s_RipperJump),
1378     SAVE_DATA(sg_RipperJump),
1379     SAVE_DATA(s_RipperFall),
1380     SAVE_DATA(sg_RipperFall),
1381     SAVE_DATA(s_RipperJumpAttack),
1382     SAVE_DATA(sg_RipperJumpAttack),
1383     SAVE_DATA(s_RipperHangJump),
1384     SAVE_DATA(sg_RipperHangJump),
1385     SAVE_DATA(s_RipperHangFall),
1386     SAVE_DATA(sg_RipperHangFall),
1387     SAVE_DATA(s_RipperDie),
1388     SAVE_DATA(s_RipperDead),
1389     SAVE_DATA(sg_RipperDie),
1390     SAVE_DATA(sg_RipperDead),
1391     SAVE_DATA(s_RipperDeathJump),
1392     SAVE_DATA(s_RipperDeathFall),
1393     SAVE_DATA(sg_RipperDeathJump),
1394     SAVE_DATA(sg_RipperDeathFall),
1395 
1396     SAVE_DATA(RipperActionSet),
1397     SAVE_DATA(RipperBrownActionSet),
1398 };
1399 
1400 saveable_module saveable_ripper =
1401 {
1402     // code
1403     saveable_ripper_code,
1404     SIZ(saveable_ripper_code),
1405 
1406     // data
1407     saveable_ripper_data,
1408     SIZ(saveable_ripper_data)
1409 };
1410