1 /***************************************************************************
2     Ferrari Rendering & Handling Code.
3 
4     Much of the handling code is very messy. As such, the translated code
5     isn't great as I tried to focus on accuracy rather than refactoring.
6 
7     A good example of the randomness is a routine I've named
8       do_sound_score_slip()
9     which performs everything from updating the score, setting the audio
10     engine tone, triggering smoke effects etc. in an interwoven fashion.
11 
12     The Ferrari sprite has different properties to other game objects
13     As there's only one of them, I've rolled the additional variables into
14     this class.
15 
16     Copyright Chris White.
17     See license.txt for more details.
18 ***************************************************************************/
19 
20 #pragma once
21 
22 #include "outrun.hpp"
23 
24 class OFerrari
25 {
26 public:
27     // Ferrari Sprite Object
28     oentry *spr_ferrari;
29 
30     // Passenger 1 Sprite Object
31     oentry *spr_pass1;
32 
33     // Passenger 2 Sprite Object
34     oentry *spr_pass2;
35 
36     // Ferrari Shadow Sprite Object
37     oentry *spr_shadow;
38 
39     // -------------------------------------------------------------------------
40     // Ferrari Colours
41     // -------------------------------------------------------------------------
42 
43     // Palette to use (change Ferrari colours)
44     uint16_t ferrari_pal;
45 
46     const static uint16_t PAL_RED = 2;
47     const static uint16_t PAL_BLUE = 256;
48     const static uint16_t PAL_YELLOW = 261;
49     const static uint16_t PAL_GREEN = 266;
50     const static uint16_t PAL_CYAN = 271;
51 
52 	// -------------------------------------------------------------------------
53 	// Main Switch Variables
54 	// -------------------------------------------------------------------------
55 
56     enum
57     {
58         // Initialise Intro Animation Sequences
59         FERRARI_SEQ1 = 0,
60 
61         // Tick Intro Animation Sequences
62         FERRARI_SEQ2 = 1,
63 
64         // Initialize In-Game Logic
65         FERRARI_INIT = 2,
66 
67         // Tick In-Game Logic
68         FERRARI_LOGIC = 3,
69 
70         // Ferrari End Sequence Logic
71         FERRARI_END_SEQ = 4,
72     };
73 
74     // Which routine is in use
75     uint8_t state;
76 
77     // Unused counter. Implemented on original game so could be useful for debug.
78     uint16_t counter;
79 
80     int16_t steering_old;
81     bool car_ctrl_active;
82 
83     // Car State
84     //
85     // -1 = Animation Sequence (Crash / Drive In)
86     // 0  = Normal
87     // 1  = Smoke from wheels
88     int8_t car_state;
89 
90     enum { CAR_ANIM_SEQ = -1, CAR_NORMAL = 0, CAR_SMOKE = 1};
91 
92     // Auto breaking for end sequence
93     bool auto_brake;
94 
95     // Torque table index lookup
96     //
97     // 00 = Start line only
98     // 10 = Low gear
99     // 1F = High gear
100     //
101     // Increments between the values
102     //
103     // Gets set based on what gear we're in
104     uint8_t torque_index;
105     int16_t torque;
106     int32_t revs;
107 
108     // Rev Shift Value. Normal = 1.
109     // Higher values result in reaching higher revs faster!
110     uint8_t rev_shift;
111 
112     // State of car wheels
113     //
114     // 0 = On Road
115     // 1 = Left Wheel Off-Road
116     // 2 = Right Wheel Off-Road
117     // 3 = Both Wheels Off-Road
118     uint8_t wheel_state;
119 
120     enum
121     {
122         WHEELS_ON = 0,
123         WHEELS_LEFT_OFF = 1,
124         WHEELS_RIGHT_OFF = 2,
125         WHEELS_OFF = 3
126     };
127 
128     // Wheel Traction
129     //
130     // 0 = Both Wheels Have Traction
131     // 1 = One Wheel Has Traction
132     // 2 = No Wheels Have Traction
133     uint8_t wheel_traction;
134 
135     enum
136     {
137         TRACTION_ON = 0,
138         TRACTION_HALF = 1,
139         TRACTION_OFF = 2,
140     };
141 
142     // Ferrari is slipping/skidding either after collision or round bend
143     uint16_t is_slipping;
144 
145     // Slip Command Sent To Sound Hardware
146     uint8_t slip_sound;
147 
148     // Stores previous value of car_increment
149     uint16_t car_inc_old;
150 
151     // Difference between car_x_pos and car_x_old
152     int16_t car_x_diff;
153 
154 	// -------------------------------------------------------------------------
155 	// Engine Stop Flag
156 	// -------------------------------------------------------------------------
157 
158     // Flag set when switching back to in-game engine, to be used with revs_post_stop
159     // This is used to adjust the rev boost when returning to game
160     int16_t rev_stop_flag;
161 
162     // Rev boost when we switch back to ingame engine and hand user control.
163     // Set by user being on revs before initialization.
164     int16_t revs_post_stop;
165 
166     int16_t acc_post_stop;
167 
168 	// -------------------------------------------------------------------------
169 	// Engine Sounds. Probably needs to be moved
170 	// -------------------------------------------------------------------------
171 
172     // Sound: Adjusted rev value (to be used to set pitch sound fx)
173     uint16_t rev_pitch1;
174 
175     uint16_t rev_pitch2;
176 
177 	// -------------------------------------------------------------------------
178 	// Ferrari Specific Values
179 	// -------------------------------------------------------------------------
180 
181     // *22 [Word] AI Curve Counter. Increments During Curve. Resets On Straight.
182     int16_t sprite_ai_counter;
183 
184     // *24 [Word] AI Curve Value. 0x96 - curve_next.
185     int16_t sprite_ai_curve;
186 
187     // *26 [Word] AI X Position Adjustment
188     int16_t sprite_ai_x;
189 
190     // *28 [Word] AI Steering Adjustment
191     int16_t sprite_ai_steer;
192 
193     // *2A [Word] Car X Position Backup
194     int16_t sprite_car_x_bak;
195 
196     // *2C [Word] Wheel State
197     int16_t sprite_wheel_state;
198 
199     // *2E [Word] Ferrari Slipping (Copy of slip counter)
200     int16_t sprite_slip_copy;
201 
202     // *39 [Byte] Wheel Palette Offset
203     int8_t wheel_pal;
204 
205     // *3A [Word] Passenger Y Offset
206     int16_t sprite_pass_y;
207 
208     // *3C [Word] Wheel Frame Counter Reset
209     int16_t wheel_frame_reset;
210 
211     // *3E [Word] Wheel Frame Counter Reset
212     int16_t wheel_counter;
213 
214 
215     OFerrari(void);
216     ~OFerrari(void);
217     void init(oentry*, oentry*, oentry*, oentry*);
218     void reset_car();
219     void init_ingame();
220     void tick();
221     void set_ferrari_x();
222     void set_ferrari_bounds();
223     void check_wheels();
224     void set_curve_adjust();
225     void draw_shadow();
226     void move();
227     void do_sound_score_slip();
228     void shake();
229     void do_skid();
230 
231 private:
232     // Max speed of car
233     const static uint32_t MAX_SPEED = 0x1260000;
234 
235     // Car Base Increment, For Movement
236     const static uint32_t CAR_BASE_INC = 0x12F;
237 
238     // Maximum distance to allow car to stray from road
239     const static uint16_t OFFROAD_BOUNDS = 0x1F4;
240 
241     // Used by set_car_x
242     int16_t road_width_old;
243 
244 	// -------------------------------------------------------------------------
245 	// Controls
246 	// -------------------------------------------------------------------------
247 
248     int16_t accel_value;
249     int16_t accel_value_bak;
250     int16_t brake_value;
251     bool gear_value;
252     bool gear_bak;
253 
254     // Trickle down adjusted acceleration values
255     int16_t acc_adjust1;
256     int16_t acc_adjust2;
257     int16_t acc_adjust3;
258 
259     // Trickle down brake values
260     int16_t brake_adjust1;
261     int16_t brake_adjust2;
262     int16_t brake_adjust3;
263 
264     // Calculated brake value to subtract from acc_burst.
265     int32_t brake_subtract;
266 
267     // Counter. When enabled, acceleration disabled
268     int8_t gear_counter;
269 
270     // Previous rev adjustment (stored)
271     int32_t rev_adjust;
272 
273 	// -------------------------------------------------------------------------
274 	// Smoke
275 	// -------------------------------------------------------------------------
276 
277     // Counter for smoke after changing gear. Values over 0 result in smoke
278     int16_t gear_smoke;
279 
280     // Similar to above
281     int16_t gfx_smoke;
282 
283     // Set to -1 when car sharply corners and player is steering into direction of corner
284     int8_t cornering;
285     int8_t cornering_old;
286 
287     static uint16_t torque_lookup[];
288     static const uint8_t rev_inc_lookup[];
289 
290     void logic();
291     void ferrari_normal();
292     void setup_ferrari_sprite();
293     void setup_ferrari_bonus_sprite();
294     void init_end_seq();
295     void do_end_seq();
296     void tick_engine_disabled(int32_t&);
297     void set_ferrari_palette();
298     void set_passenger_sprite(oentry*);
299     void set_passenger_frame(oentry*);
300     void car_acc_brake();
301     void do_gear_torque(int16_t&);
302     void do_gear_low(int16_t&);
303     void do_gear_high(int16_t&);
304     int32_t tick_gear_change(int16_t);
305     int32_t get_speed_inc_value(uint16_t, uint32_t);
306     int32_t get_speed_dec_value(uint16_t);
307     void set_brake_subtract();
308     void finalise_revs(int32_t&, int32_t);
309     void convert_revs_speed(int32_t, int32_t&);
310     void update_road_pos();
311     int32_t tick_smoke();
312     void set_wheels(uint8_t);
313     inline void draw_sprite(oentry*);
314 };
315 
316 extern OFerrari oferrari;