1use std::{borrow::Cow, fmt, slice::Iter};
3
4use enum_iterator::Sequence;
5use js_sys::JsString;
6use num_derive::FromPrimitive;
7use num_traits::FromPrimitive;
8use serde::{
9 de::{Error as _, Unexpected},
10 Deserialize, Serialize,
11};
12use serde_repr::{Deserialize_repr, Serialize_repr};
13use wasm_bindgen::prelude::*;
14
15use super::{macros::named_enum_serialize_deserialize, InvalidConstantString};
16use crate::{
17 constants::find::{Exit, Find},
18 prelude::*,
19};
20
21#[derive(
23 Debug, PartialEq, Eq, Clone, Copy, Hash, FromPrimitive, Deserialize_repr, Serialize_repr,
24)]
25#[repr(i8)]
26pub enum ErrorCode {
27 NotOwner = -1,
28 NoPath = -2,
29 NameExists = -3,
30 Busy = -4,
31 NotFound = -5,
32 NotEnough = -6,
33 InvalidTarget = -7,
34 Full = -8,
35 NotInRange = -9,
36 InvalidArgs = -10,
37 Tired = -11,
38 NoBodypart = -12,
39 RclNotEnough = -14,
40 GclNotEnough = -15,
41}
42
43impl FromReturnCode for ErrorCode {
44 type Error = Self;
45
46 fn result_from_i8(val: i8) -> Result<(), Self::Error> {
47 match val {
48 0 => Ok(()),
49 -1 => Err(ErrorCode::NotOwner),
50 -2 => Err(ErrorCode::NoPath),
51 -3 => Err(ErrorCode::NameExists),
52 -4 => Err(ErrorCode::Busy),
53 -5 => Err(ErrorCode::NotFound),
54 -6 => Err(ErrorCode::NotEnough),
55 -7 => Err(ErrorCode::InvalidTarget),
56 -8 => Err(ErrorCode::Full),
57 -9 => Err(ErrorCode::NotInRange),
58 -10 => Err(ErrorCode::InvalidArgs),
59 -11 => Err(ErrorCode::Tired),
60 -12 => Err(ErrorCode::NoBodypart),
61 -14 => Err(ErrorCode::RclNotEnough),
62 -15 => Err(ErrorCode::GclNotEnough),
63 #[cfg(feature = "unsafe-return-conversion")]
65 _ => unsafe { std::hint::unreachable_unchecked() },
66 #[cfg(not(feature = "unsafe-return-conversion"))]
67 _ => unreachable!(),
68 }
69 }
70
71 fn try_result_from_i8(val: i8) -> Option<Result<(), Self::Error>> {
72 match val {
73 0 => Some(Ok(())),
74 -1 => Some(Err(ErrorCode::NotOwner)),
75 -2 => Some(Err(ErrorCode::NoPath)),
76 -3 => Some(Err(ErrorCode::NameExists)),
77 -4 => Some(Err(ErrorCode::Busy)),
78 -5 => Some(Err(ErrorCode::NotFound)),
79 -6 => Some(Err(ErrorCode::NotEnough)),
80 -7 => Some(Err(ErrorCode::InvalidTarget)),
81 -8 => Some(Err(ErrorCode::Full)),
82 -9 => Some(Err(ErrorCode::NotInRange)),
83 -10 => Some(Err(ErrorCode::InvalidArgs)),
84 -11 => Some(Err(ErrorCode::Tired)),
85 -12 => Some(Err(ErrorCode::NoBodypart)),
86 -14 => Some(Err(ErrorCode::RclNotEnough)),
87 -15 => Some(Err(ErrorCode::GclNotEnough)),
88 _ => None,
89 }
90 }
91}
92
93#[wasm_bindgen]
95#[derive(
96 Debug,
97 PartialEq,
98 Eq,
99 Clone,
100 Copy,
101 Hash,
102 FromPrimitive,
103 Serialize_repr,
104 Deserialize_repr,
105 Sequence,
106)]
107#[repr(u8)]
108pub enum Direction {
109 Top = 1,
110 TopRight = 2,
111 Right = 3,
112 BottomRight = 4,
113 Bottom = 5,
114 BottomLeft = 6,
115 Left = 7,
116 TopLeft = 8,
117}
118
119impl Direction {
120 pub fn is_orthogonal(self) -> bool {
131 use Direction::*;
132
133 matches!(self, Top | Right | Bottom | Left)
134 }
135
136 pub fn is_diagonal(self) -> bool {
147 !self.is_orthogonal()
148 }
149
150 pub fn multi_rot(self, times: i8) -> Self {
165 let raw_dir = ((self as u8) - 1).wrapping_add_signed(times) % 8 + 1;
166 Self::from_u8(raw_dir).unwrap()
169 }
170
171 pub fn rot_cw(self) -> Self {
181 self.multi_rot(1)
182 }
183
184 pub fn rot_ccw(self) -> Self {
194 self.multi_rot(-1)
195 }
196
197 pub fn iter() -> Iter<'static, Direction> {
225 use crate::Direction::*;
226 static DIRECTIONS: [Direction; 8] = [
227 Top,
228 TopRight,
229 Right,
230 BottomRight,
231 Bottom,
232 BottomLeft,
233 Left,
234 TopLeft,
235 ];
236 DIRECTIONS.iter()
237 }
238}
239
240impl JsCollectionIntoValue for Direction {
241 fn into_value(self) -> JsValue {
242 (self as u8).into()
243 }
244}
245
246impl JsCollectionFromValue for Direction {
247 fn from_value(val: JsValue) -> Direction {
248 let n = if let Some(val) = val.as_string() {
249 val.parse::<u8>().expect("expected parseable u8 string")
250 } else {
251 val.as_f64().expect("expected number value") as u8
252 };
253
254 Self::from_u8(n).expect("unknown direction")
255 }
256}
257
258impl From<Direction> for (i32, i32) {
259 #[inline]
261 fn from(direction: Direction) -> (i32, i32) {
262 match direction {
263 Direction::Top => (0, -1),
264 Direction::TopRight => (1, -1),
265 Direction::Right => (1, 0),
266 Direction::BottomRight => (1, 1),
267 Direction::Bottom => (0, 1),
268 Direction::BottomLeft => (-1, 1),
269 Direction::Left => (-1, 0),
270 Direction::TopLeft => (-1, -1),
271 }
272 }
273}
274
275impl ::std::ops::Neg for Direction {
276 type Output = Direction;
277
278 #[inline]
291 fn neg(self) -> Direction {
292 use Direction::*;
293
294 match self {
295 Top => Bottom,
296 TopRight => BottomLeft,
297 Right => Left,
298 BottomRight => TopLeft,
299 Bottom => Top,
300 BottomLeft => TopRight,
301 Left => Right,
302 TopLeft => BottomRight,
303 }
304 }
305}
306
307impl fmt::Display for Direction {
308 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
309 let ch = match *self {
310 Direction::Top => "↑",
311 Direction::TopRight => "↗",
312 Direction::Right => "→",
313 Direction::BottomRight => "↘",
314 Direction::Bottom => "↓",
315 Direction::BottomLeft => "↙",
316 Direction::Left => "←",
317 Direction::TopLeft => "↖",
318 };
319 f.write_str(ch)
320 }
321}
322
323#[wasm_bindgen]
334#[derive(
335 Debug,
336 PartialEq,
337 Eq,
338 Clone,
339 Copy,
340 Hash,
341 FromPrimitive,
342 Serialize_repr,
343 Deserialize_repr,
344 Sequence,
345)]
346#[repr(u8)]
347pub enum ExitDirection {
348 Top = 1,
349 Right = 3,
350 Bottom = 5,
351 Left = 7,
352}
353
354impl From<ExitDirection> for Find {
355 #[inline]
356 fn from(dir: ExitDirection) -> Self {
357 match dir {
358 ExitDirection::Top => Find::ExitTop,
359 ExitDirection::Right => Find::ExitRight,
360 ExitDirection::Bottom => Find::ExitBottom,
361 ExitDirection::Left => Find::ExitLeft,
362 }
363 }
364}
365
366impl From<ExitDirection> for Direction {
367 #[inline]
368 fn from(dir: ExitDirection) -> Self {
369 match dir {
370 ExitDirection::Top => Direction::Top,
371 ExitDirection::Right => Direction::Right,
372 ExitDirection::Bottom => Direction::Bottom,
373 ExitDirection::Left => Direction::Left,
374 }
375 }
376}
377
378impl From<ExitDirection> for Exit {
379 fn from(value: ExitDirection) -> Self {
380 match value {
381 ExitDirection::Top => Exit::Top,
382 ExitDirection::Right => Exit::Right,
383 ExitDirection::Bottom => Exit::Bottom,
384 ExitDirection::Left => Exit::Left,
385 }
386 }
387}
388
389#[wasm_bindgen]
391#[derive(
392 Debug,
393 PartialEq,
394 Eq,
395 Clone,
396 Copy,
397 FromPrimitive,
398 Hash,
399 Deserialize_repr,
400 Serialize_repr,
401 Sequence,
402)]
403#[repr(u8)]
404pub enum Color {
405 Red = 1,
406 Purple = 2,
407 Blue = 3,
408 Cyan = 4,
409 Green = 5,
410 Yellow = 6,
411 Orange = 7,
412 Brown = 8,
413 Grey = 9,
414 White = 10,
415}
416
417#[wasm_bindgen]
419#[derive(
420 Debug,
421 PartialEq,
422 Eq,
423 Clone,
424 Copy,
425 Hash,
426 FromPrimitive,
427 Serialize_repr,
428 Deserialize_repr,
429 Sequence,
430)]
431#[repr(u8)]
432pub enum Terrain {
433 Plain = 0,
435 Wall = 1,
437 Swamp = 2,
439 }
442
443impl Terrain {
444 pub fn from_look_constant_str(terrain_look_str: &str) -> Self {
448 match terrain_look_str {
449 "wall" => Terrain::Wall,
450 "swamp" => Terrain::Swamp,
451 "plain" => Terrain::Plain,
452 _ => Terrain::Plain,
453 }
454 }
455
456 pub fn from_look_constant_jsvalue(terrain_look_jsvalue: JsValue) -> Self {
457 let terrain_look_string: String = JsString::from(terrain_look_jsvalue).into();
458 Self::from_look_constant_str(&terrain_look_string)
459 }
460}
461
462#[wasm_bindgen]
464#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Sequence)]
465pub enum Part {
466 Move = "move",
467 Work = "work",
468 Carry = "carry",
469 Attack = "attack",
470 RangedAttack = "ranged_attack",
471 Tough = "tough",
472 Heal = "heal",
473 Claim = "claim",
474}
475
476named_enum_serialize_deserialize!(Part);
477
478impl Part {
479 #[inline]
481 pub const fn cost(self) -> u32 {
482 match self {
483 Part::Move => 50,
484 Part::Work => 100,
485 Part::Carry => 50,
486 Part::Attack => 80,
487 Part::RangedAttack => 150,
488 Part::Tough => 10,
489 Part::Heal => 250,
490 Part::Claim => 600,
491 _ => 0,
494 }
495 }
496}
497
498#[wasm_bindgen]
500#[derive(
501 Debug,
502 PartialEq,
503 Eq,
504 Clone,
505 Copy,
506 FromPrimitive,
507 Hash,
508 Serialize_repr,
509 Deserialize_repr,
510 Sequence,
511)]
512#[repr(u8)]
513pub enum Density {
514 Low = 1,
515 Moderate = 2,
516 High = 3,
517 Ultra = 4,
518}
519
520impl Density {
521 #[inline]
524 pub const fn amount(self) -> u32 {
525 match self {
526 Density::Low => 15_000,
527 Density::Moderate => 35_000,
528 Density::High => 70_000,
529 Density::Ultra => 100_000,
530 }
531 }
532
533 #[inline]
551 pub const fn probability(self) -> f32 {
552 match self {
553 Density::Low => 0.1,
554 Density::Moderate => 0.5,
555 Density::High => 0.9,
556 Density::Ultra => 1.0,
557 }
558 }
559}
560
561#[wasm_bindgen]
563#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Sequence)]
564pub enum OrderType {
565 Sell = "sell",
566 Buy = "buy",
567}