1use super::makelong;
10use bitflags::bitflags;
11use num::ToPrimitive;
12use num_derive::{FromPrimitive, ToPrimitive};
13
14bitflags! {
15 pub struct StatusField:i32 {
16 const CONNECTED = 1;
17 }
18}
19
20bitflags! {
23 pub struct EngineWarnings:i32 {
24 const WATER_TEMP_WARNING = 0x01;
25 const FUEL_PRESSURE_WARNING = 0x02;
26 const OIL_PRESSURE_WARNING = 0x04;
27 const ENGINE_STALLED = 0x08;
28 const PIT_SPEED_LIMITER = 0x10;
29 const REV_LIMITER_ACTIVE = 0x20;
30 const OIL_TEMP_WARNING = 0x40;
31 }
32}
33
34bitflags! {
35 pub struct Flags:u32 {
38 const CHECKERED = 0x00000001;
40 const WHITE = 0x00000002;
41 const GREEN = 0x00000004;
42 const YELLOW = 0x00000008;
43 const RED = 0x00000010;
44 const BLUE = 0x00000020;
45 const DEBRIS = 0x00000040;
46 const CROSSED = 0x00000080;
47 const YELLOW_WAVING = 0x00000100;
48 const ONE_TO_GREEN = 0x00000200;
49 const GREEN_HELD = 0x00000400;
50 const LAPS_10_TO_GO = 0x00000800;
51 const LAPS_5_TO_GO = 0x00001000;
52 const RANDOM_WAVING = 0x00002000;
53 const CAUTION = 0x00004000;
54 const CAUTION_WAVING= 0x00008000;
55
56 const BLACK = 0x00010000;
58 const DISQUALIFY = 0x00020000;
59 const SERVICABLE = 0x00040000; const FURLED = 0x00080000;
61 const REPAIR = 0x00100000;
62
63 const START_HIDDEN = 0x10000000;
65 const START_READY = 0x20000000;
66 const START_SET = 0x40000000;
67 const START_GO = 0x80000000;
68 }
69}
70
71#[derive(Clone, Copy, Debug, PartialEq, FromPrimitive)]
72pub enum TrackLocation {
73 NotInWorld = -1,
74 OffTrack,
75 InPitStall,
76 ApproachingPits,
77 OnTrack,
78}
79
80#[derive(Clone, Copy, Debug, PartialEq, FromPrimitive)]
81pub enum TrackSurface {
82 SurfaceNotInWorld = -1,
83 UndefinedMaterial = 0,
84
85 Asphalt1Material,
86 Asphalt2Material,
87 Asphalt3Material,
88 Asphalt4Material,
89 Concrete1Material,
90 Concrete2Material,
91 RacingDirt1Material,
92 RacingDirt2Material,
93 Paint1Material,
94 Paint2Material,
95 Rumble1Material,
96 Rumble2Material,
97 Rumble3Material,
98 Rumble4Material,
99
100 Grass1Material,
101 Grass2Material,
102 Grass3Material,
103 Grass4Material,
104 Dirt1Material,
105 Dirt2Material,
106 Dirt3Material,
107 Dirt4Material,
108 SandMaterial,
109 Gravel1Material,
110 Gravel2Material,
111 GrasscreteMaterial,
112 AstroturfMaterial,
113}
114
115#[derive(Clone, Copy, Debug, PartialEq, FromPrimitive)]
116pub enum SessionState {
117 Invalid,
118 GetInCar,
119 Warmup,
120 ParadeLaps,
121 Racing,
122 Checkered,
123 CoolDown,
124}
125
126#[allow(clippy::enum_variant_names)]
127#[derive(Clone, Copy, Debug, PartialEq, FromPrimitive)]
128pub enum CarLeftRight {
129 Off,
130 Clear,
132 CarLeft,
134 CarRight,
136 CarLeftRight,
138 TwoCarsLeft,
140 TwoCarsRight,
142}
143
144bitflags! {
145 pub struct CameraState:i32 {
146 const IS_SESSION_SCREEN = 0x0001;
148 const IS_SCENIC_ACTIVE = 0x0002;
150
151 const CAM_TOOL_ACTIVE = 0x0004;
153 const UI_HIDDEN = 0x0008;
154 const USE_AUTO_SHOT_SELECTION = 0x0010;
155 const USE_TEMPORARY_EDITS = 0x0020;
156 const USE_KEY_ACCELERATION = 0x0040;
157 const USE_KEY_10X_ACCELERATION = 0x0080;
158 const USE_MOUSE_AIM_MODE = 0x0100;
159 }
160}
161impl CameraState {
162 pub fn params(&self) -> i32 {
163 self.bits()
164 }
165}
166bitflags! {
167 pub struct PitSvcFlags:i32 {
168 const LF_TIRE_CHANGE = 0x0001;
169 const RF_TIRE_CHANGE = 0x0002;
170 const LR_TIRE_CHANGE = 0x0004;
171 const RR_TIRE_CHANGE = 0x0008;
172
173 const FUEL_FILL = 0x0010;
174 const WINDSHIELD_TEAROFF= 0x0020;
175 const FAST_REPAIR = 0x0040;
176 }
177}
178
179#[derive(Clone, Copy, Debug, PartialEq, FromPrimitive)]
180pub enum PitSvcStatus {
181 None = 0,
183 InProgress,
184 Complete,
185
186 TooFarLeft = 100,
188 TooFarRight,
189 TooFarForward,
190 TooFarBack,
191 BadAngle,
192 CantFixThat,
193}
194
195#[derive(Clone, Copy, Debug, PartialEq, FromPrimitive)]
196pub enum PaceMode {
197 SingleFileStart = 0,
198 DoubleFileStart,
199 SingleFileRestart,
200 DoubleFileRestart,
201 NotPacing,
202}
203
204bitflags! {
205 pub struct PaceFlags:i32 {
206 const END_OF_LINE = 0x01;
207 const FREE_PASS = 0x02;
208 const WAVED_AROUND = 0x04;
209 }
210}
211
212#[derive(Debug)]
219pub enum BroadcastMsg {
220 CamSwitchPos(CameraFocus, i16, i16),
222 CamSwitchNum(CameraFocus, i16, i16),
224 CamSetState(CameraState),
226 ReplaySetPlaySpeed(i16, bool),
228 ReplaySetPlayPosition(ReplayPos, i32),
230 ReplaySearch(ReplaySearch),
232 ReplaySetState(ReplayState),
234 ReloadTextures(ReloadTextures),
236 ChatComand(ChatCommand),
238 PitCommand(PitCommand),
240 TelemCommand(TelemCommand),
242 FFBCommand(FFBCommand),
244 ReplaySearchSessionTime(i16, std::time::Duration),
246 VideoCapture(VideoCapture),
248}
249impl BroadcastMsg {
250 pub fn params(&self) -> (i16, (i16, isize)) {
251 match self {
252 BroadcastMsg::CamSwitchPos(car, group, cam) => {
253 (0, (car.params(), makelong(*group, *cam)))
254 }
255 BroadcastMsg::CamSwitchNum(car, group, cam) => {
256 (1, (car.params(), makelong(*group, *cam)))
257 }
258 BroadcastMsg::CamSetState(cs) => (2, (cs.params() as i16, 0)), BroadcastMsg::ReplaySetPlaySpeed(speed, slow) => {
260 (3, (*speed, if *slow { 1 } else { 0 }))
261 }
262 BroadcastMsg::ReplaySetPlayPosition(pos, frame) => (4, (pos.params(), *frame as isize)),
263 BroadcastMsg::ReplaySearch(s) => (5, (s.parms(), 0)),
264 BroadcastMsg::ReplaySetState(s) => (6, (s.params(), 0)),
265 BroadcastMsg::ReloadTextures(r) => (7, (r.params())),
266 BroadcastMsg::ChatComand(c) => (8, (c.params())),
267 BroadcastMsg::PitCommand(c) => (9, c.params()),
268 BroadcastMsg::TelemCommand(t) => (10, (t.params(), 0)),
269 BroadcastMsg::FFBCommand(f) => (11, f.params()),
270 BroadcastMsg::ReplaySearchSessionTime(ses, tm) => (12, (*ses, tm.as_millis() as isize)),
271 BroadcastMsg::VideoCapture(v) => (13, (v.params(), 0)),
272 }
273 }
274}
275
276#[derive(Debug)]
279pub enum CameraFocus {
280 Incident,
281 Leader,
282 Exciting,
283 Driver(i16),
285}
286impl CameraFocus {
287 fn params(&self) -> i16 {
288 match self {
289 CameraFocus::Incident => -3,
290 CameraFocus::Leader => -2,
291 CameraFocus::Exciting => -1,
292 CameraFocus::Driver(d) => *d,
293 }
294 }
295}
296
297#[derive(Debug, ToPrimitive)]
298pub enum ReplayPos {
299 Begin = 0,
300 Current,
301 End,
302}
303impl ReplayPos {
304 fn params(&self) -> i16 {
305 self.to_i16().unwrap()
306 }
307}
308
309#[derive(Debug, ToPrimitive)]
310pub enum ReplaySearch {
311 ToStart = 0,
312 ToEnd,
313 PrevSession,
314 NextSession,
315 PrevLap,
316 NextLap,
317 PrevFrame,
318 NextFrame,
319 PrevIncident,
320 NextIncident,
321}
322impl ReplaySearch {
323 fn parms(&self) -> i16 {
324 self.to_i16().unwrap()
325 }
326}
327
328#[derive(Debug, ToPrimitive)]
329pub enum ReplayState {
330 EraseTape = 0,
332}
333impl ReplayState {
334 fn params(&self) -> i16 {
335 self.to_i16().unwrap()
336 }
337}
338
339#[derive(Debug)]
340pub enum ReloadTextures {
341 All,
343 CarIdx(i16),
345}
346impl ReloadTextures {
347 fn params(&self) -> (i16, isize) {
348 match self {
349 ReloadTextures::All => (0, 0),
350 ReloadTextures::CarIdx(i) => (1, *i as isize),
351 }
352 }
353}
354
355#[derive(Debug)]
356pub enum ChatCommand {
357 Macro(u8),
359 BeginChat,
361 Reply,
363 Cancel,
365}
366impl ChatCommand {
367 fn params(&self) -> (i16, isize) {
368 match self {
369 ChatCommand::Macro(m) => (0, *m as isize),
370 ChatCommand::BeginChat => (1, 0),
371 ChatCommand::Reply => (2, 0),
372 ChatCommand::Cancel => (3, 0),
373 }
374 }
375}
376
377#[derive(Debug)]
379pub enum PitCommand {
380 Clear,
382 TearOff,
384 Fuel(Option<i16>),
386 LF(Option<i16>),
388 RF(Option<i16>),
390 LR(Option<i16>),
392 RR(Option<i16>),
394 ClearTires,
396 FastRepair,
398 ClearWS,
400 ClearFR,
402 ClearFuel,
404}
405impl PitCommand {
406 fn params(&self) -> (i16, isize) {
407 match self {
408 PitCommand::Clear => (0, 0),
409 PitCommand::TearOff => (1, 0),
410 PitCommand::Fuel(l) => (2, pit_amt(l)),
411 PitCommand::LF(p) => (3, pit_amt(p)),
412 PitCommand::RF(p) => (4, pit_amt(p)),
413 PitCommand::LR(p) => (5, pit_amt(p)),
414 PitCommand::RR(p) => (6, pit_amt(p)),
415 PitCommand::ClearTires => (7, 0),
416 PitCommand::FastRepair => (8, 0),
417 PitCommand::ClearWS => (9, 0),
418 PitCommand::ClearFR => (10, 0),
419 PitCommand::ClearFuel => (11, 0),
420 }
421 }
422}
423fn pit_amt(a: &Option<i16>) -> isize {
424 match a {
425 Some(l) => *l as isize,
426 None => 0,
427 }
428}
429
430#[derive(Debug, ToPrimitive)]
432pub enum TelemCommand {
433 Stop = 0,
435 Start,
437 Restart,
439}
440impl TelemCommand {
441 fn params(&self) -> i16 {
442 self.to_i16().unwrap()
443 }
444}
445
446#[derive(Debug)]
448pub enum FFBCommand {
449 MaxForce(f32),
451}
452impl FFBCommand {
453 fn params(&self) -> (i16, isize) {
454 match self {
455 FFBCommand::MaxForce(f) => {
456 (0, (((*f * 65536.0) as isize) & 0x00000000FFFFFFFF))
461 }
462 }
463 }
464}
465
466#[derive(Debug, ToPrimitive)]
467pub enum VideoCapture {
468 TriggerScreenShot = 0,
470 Start,
472 End,
474 Toggle,
476 ShowVideoTimer,
478 HideVideoTimer,
480}
481impl VideoCapture {
482 fn params(&self) -> i16 {
483 self.to_i16().unwrap()
484 }
485}
486
487#[cfg(test)]
488mod tests {
489
490 use super::*;
491
492 #[test]
493 fn test_pitcommand() {
494 assert_eq!(PitCommand::Fuel(Some(12)).params(), (2, 12));
495 assert_eq!(PitCommand::Fuel(None).params(), (2, 0));
496 }
497
498 #[test]
499 fn test_ffb() {
500 assert_eq!(FFBCommand::MaxForce(50.0).params(), (0, 0x320000));
501 assert_eq!(FFBCommand::MaxForce(0.0).params(), (0, 0x00000000));
502 assert_eq!(FFBCommand::MaxForce(42.42).params(), (0, 0x2a6b85));
503 assert_eq!(FFBCommand::MaxForce(-1.0).params(), (0, 0xffff0000));
504 }
505 #[test]
506 fn test_bcast_msg() {
507 assert_eq!(
508 BroadcastMsg::PitCommand(PitCommand::LF(Some(140))).params(),
509 (9, (3, 140))
510 )
511 }
512}