rpg_stat/
special.rs

1/*!
2# Special
3
4Special moves used by:
5 * `rpgstat::creatures::*;`
6 * `rpg_stat::stats::*;`
7*/
8
9// * `rpg_stat::weapons*;
10
11use std::fmt;
12use std::fmt::Debug;
13use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign};
14extern crate num;
15use serde::{Deserialize, Serialize};
16
17#[cfg(feature = "fltkform")]
18use fltk::{prelude::*, *};
19#[cfg(feature = "fltkform")]
20use fltk_form_derive::*;
21#[cfg(feature = "fltkform")]
22use fltk_form::FltkForm;
23
24use crate::random::*;
25use crate::types::Normal as Type;
26use crate::types::Compare;
27use crate::attributes::Value;
28
29use std::path::Path;
30
31/*
32
33*/
34#[derive(Debug, Default, Clone, Copy, PartialEq, Deserialize, Serialize)]
35#[cfg_attr(feature = "fltkform", derive(FltkForm))]
36pub struct ManaMoves {
37    /// The first move
38    pub zero:Normal,
39    /// The first move's `rpg_stat::type::Normal` type
40    pub mana_zero:Type,
41    /// The second move
42    pub one:Normal,
43    /// The second move's `rpg_stat::type::Normal` type
44    pub mana_one:Type,
45    /// The third move
46    pub two:Normal,
47    /// The third move's `rpg_stat::type::Normal` type
48    pub mana_two:Type,
49    /// The fourth move
50    pub three:Normal,
51    /// The fourth move's `rpg_stat::type::Normal` type
52    pub mana_three:Type,
53    /// the total tech points
54    pub mp:f64,
55}
56impl ManaMoves {
57    #[allow(unused)]
58    /// Make a new move set
59    pub fn new() -> Self {
60        Self::default()
61    }
62    #[allow(unused)]
63    /// Read in a move set from a file
64    pub fn read<P: AsRef<Path>>(filename:P) -> Self {
65        if let Ok(file_string) = std::fs::read_to_string(filename) {
66            let decoded:ManaMoves = match toml::from_str(file_string.as_str()) {
67                Ok(decoded) => decoded,
68                Err(e) => {
69                    println!("Moves::read()->toml::from_str() Error:{}",e);
70                    return Self::default()
71                },
72            };
73            return decoded;
74        }
75        Self::default()
76    }
77/*
78
79
80*/
81   #[allow(unused)]
82   pub fn use_move(&mut self, move_number:u32, level:f64, enemy_type:Type) -> f64{
83        let mut dmg:f64 = 0.0;
84        let mut cost:f64 = 0.0;
85        let mut total = 0.0;
86        match move_number {
87            0  => {
88                cost = self.zero.mp_cost(0.0);
89                dmg = self.zero.damage(level);
90                total = self.mana_zero.effectiveness(enemy_type).value(dmg);
91            },
92            1 => {
93                cost = self.one.mp_cost(0.0);
94                dmg = self.one.damage(level);
95                total = self.mana_one.effectiveness(enemy_type).value(dmg);
96            },
97            2 => {
98                cost = self.two.mp_cost(0.0);
99                dmg = self.two.damage(level);
100                total = self.mana_two.effectiveness(enemy_type).value(dmg);
101            },
102            _=> {
103                cost = self.three.mp_cost(0.0);
104                dmg = self.three.damage(level);
105                total = self.mana_three.effectiveness(enemy_type).value(dmg);
106            },
107        }
108        total
109    }
110}
111
112#[derive(Debug, Default, Clone, Copy, PartialEq, Deserialize, Serialize)]
113#[cfg_attr(feature = "fltkform", derive(FltkForm))]
114pub struct Moves {
115    /// The first move
116    pub one:Normal,
117    /// The second move
118    pub two:Normal,
119    /// The third move
120    pub three:Normal,
121    /// The fourth move
122    pub four:Normal,
123    /// the total tech points
124    pub tp:f64,
125}
126impl Moves {
127    #[allow(unused)]
128    /// Make a new move set
129    pub fn new() -> Self {
130        Self::default()
131    }
132    #[allow(unused)]
133    pub fn read<P: AsRef<Path>>(filename:P) -> Self {
134        if let Ok(file_string) = std::fs::read_to_string(filename) {
135            let decoded:Moves = match toml::from_str(file_string.as_str()) {
136                Ok(decoded) => decoded,
137                Err(e) => {
138                    println!("Moves::read()->toml::from_str() Error:{}",e);
139                    return Self::default()
140                },
141            };
142            return decoded;
143        }
144        Self::default()
145    }
146}
147/*
148# Tech Point Moves
149The four move setup
150*/
151#[derive(Debug, Default, Clone, Copy, PartialEq, Deserialize, Serialize)]
152#[cfg_attr(feature = "fltkform", derive(FltkForm))]
153pub struct TpMoves {
154    /// The first move
155    pub one:Normal,
156    /// The first move's tech points.  This is the **remaining** number of times it can be used.
157    pub tp_one:f64,
158    /// The second move
159    pub two:Normal,
160    /// The second move's tech points.  This is the **remaining** number of times it can be used.
161    pub tp_two:f64,
162    /// The third move
163    pub three:Normal,
164    /// The third move's tech points.  This is the **remaining** number of times it can be used.
165    pub tp_three:f64,
166    /// The fourth move
167    pub four:Normal,
168    /// The fourth move's tech points.  This is the **remaining** number of times it can be used.
169    pub tp_four:f64,
170}
171impl TpMoves {
172    #[allow(unused)]
173    /// Make a new move set
174    pub fn new() -> Self {
175        Self::default()
176    }
177    #[allow(unused)]
178    pub fn read<P: AsRef<Path>>(filename:P) -> Self {
179        if let Ok(file_string) = std::fs::read_to_string(filename) {
180            let decoded:TpMoves = match toml::from_str(file_string.as_str()) {
181                Ok(decoded) => decoded,
182                Err(e) => {
183                    println!("Moves::read()->toml::from_str() Error:{}",e);
184                    return Self::default()
185                },
186            };
187            return decoded;
188        }
189        Self::default()
190    }
191}
192
193#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
194/*
195# Basic Special
196This is quite versitle as it is similar to `Option<String>` being either `None` or `Some(String)`
197
198*/
199pub enum Basic {
200    None,
201    Some(String),
202}
203impl Random for Basic {
204    type Type = Basic;
205    fn random_type(&self) -> Self::Type {
206        if self.half() {
207            return Basic::None
208        }
209        if self.half() {
210            return Basic::Some(random_character_name())
211        }
212        Basic::Some(random_creature_name())
213    }
214}impl Default for Basic {
215    fn default() -> Self {
216        Self::None
217    }
218}
219impl fmt::Display for Basic {
220    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
221        let mut v:String;
222        match &*self {
223            Basic::None => v = String::from("None"),
224            Basic::Some(thing) =>{
225                v = String::from("Some(");
226                v.push_str(thing.to_owned().as_str());
227                v.push(')');
228            },
229        }
230        write!(f, "{}", v.as_str())
231    }
232}
233
234#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
235#[cfg_attr(feature = "fltkform", derive(FltkForm))]
236/// Specials are just types of attack, coupled with the `Element`
237/// These enums are used in determining the effects of the attack and which animations to use
238pub enum Normal {
239    /// The generic wrestling attack
240    Tackle,
241    /// Picking up and throwing an enemy a short distance
242    Toss,
243    /// Picking up and throwing an enemy very hard
244    Throw,
245    /// using claws, beaks or other sharp objects
246    Slash,
247    /// Reducing an enemy's core temperature and effecting their skin
248    Freeze,
249    /// Increasing an enemy's core temperature and effecting their skin
250    Burn,
251    /// Much more intensity than burn
252    Melt,
253    /// more intensity than tackle
254    Crush,
255    /// WAY more intensity than crush
256    Grind,
257    /// generic physical hit
258    Hit,
259    // not as powerful as Hit
260    Slap,
261    /// almost as powerful as Hit
262    Smack,
263    /// More powerful than Hit 
264    Whip,
265    /// More powerful than Slash
266    Slice,
267    /// disorienting attack
268    Spin,
269    /// more powerful than Spin
270    Blur,
271    /// Similar in power to Whip
272    Strike,
273    /// Much less powerful than Freeze
274    Splash,
275    /// None
276    None,
277}
278impl Random for Normal {
279    type Type = Normal;
280    fn random_type(&self) -> Self::Type {
281        let max = 18;
282        let val = self.random_rate(max);
283        match val {
284            0 => Normal::Tackle,
285            1 => Normal::Toss,
286            2 => Normal::Throw,
287            3 => Normal::Slash,
288            4 => Normal::Freeze,
289            5 => Normal::Burn,
290            6 => Normal::Melt,
291            7 => Normal::Crush,
292            8 => Normal::Grind,
293            9 => Normal::Hit,
294            10 => Normal::Slap,
295            11 => Normal::Smack,
296            12 => Normal::Whip,
297            13 => Normal::Slice,
298            14 => Normal::Spin,
299            15 => Normal::Blur,
300            16 => Normal::Strike,
301            17 => Normal::Splash,
302            _=> Normal::None,
303        }
304    }
305}
306impl Default for Normal {
307    /// Default to empty
308    fn default() -> Self {
309        Self::None
310    }
311}
312impl fmt::Display for Normal {
313    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
314        let v:String;
315        match *self {
316            Normal::Toss => v = "Toss".to_string(),
317            Normal::Throw => v = "Throw".to_string(),
318            Normal::Slash => v = "Slash".to_string(),
319            Normal::Freeze => v = "Freeze".to_string(),
320            Normal::Burn => v = "Burn".to_string(),
321            Normal::Melt => v = "Melt".to_string(),
322            Normal::Crush => v = "Crush".to_string(),
323            Normal::Grind => v = "Grind".to_string(),
324            Normal::Hit => v = "Hit".to_string(),
325            Normal::Slap => v = "Slap".to_string(),
326            Normal::Smack => v = "Smack".to_string(),
327            Normal::Whip => v = "whip".to_string(),
328            Normal::Slice => v = "Slice".to_string(),
329            Normal::Tackle => v = "Tackle".to_string(),
330            Normal::Spin => v = "Spin".to_string(),
331            Normal::Blur => v = "Blur".to_string(),
332            Normal::Strike => v = "Strike".to_string(),
333            Normal::Splash => v = "Splash".to_string(),
334            Normal::None => v = "None".to_string(),
335            // Normal:: => v = "".to_string(),
336        }
337        write!(f, "{}", v.as_str())
338    }
339}
340impl<T:Copy 
341    + Default
342    + AddAssign
343    + Add<Output = T>
344    + Div<Output = T>
345    + DivAssign
346    + Mul<Output = T>
347    + MulAssign
348    + Neg<Output = T>
349    + Rem<Output = T>
350    + RemAssign
351    + Sub<Output = T>
352    + SubAssign
353    + std::cmp::PartialOrd
354    + num::NumCast> SpecialMove<T> for Normal{
355    fn damage(&self, level:T) -> T {
356        let one:T = num::cast(1).unwrap();
357        let five:T = num::cast(5).unwrap();
358        let seven:T = num::cast(7).unwrap();
359        let empty:T = num::cast(0).unwrap();
360        match self {
361            Normal::Toss => one * level,
362            Normal::Throw => one * level,
363            Normal::Strike => one * level,
364            Normal::Tackle => one * level,
365            Normal::Spin => one * level,
366
367            Normal::Slash =>  five * level,
368            Normal::Burn =>  five * level,
369            Normal::Blur => five * level,
370            Normal::Splash =>  five * level,
371            Normal::Crush =>  five * level,
372            Normal::Hit =>  five * level,
373            Normal::Slap =>  five * level,
374            Normal::Whip =>  five * level,
375
376            Normal::Grind =>  seven * level,
377            Normal::Smack =>  seven * level,
378            Normal::Melt =>  seven * level,
379            Normal::Slice =>  seven * level,
380            Normal::Freeze => seven * level,
381            Normal::None => empty * level,
382            // Normal:: => one,
383        }
384    }
385    fn mp_total(&self, _input:T) -> T {
386        let thirty:T = num::cast(30).unwrap();
387        let twenty:T = num::cast(20).unwrap();
388        let ten:T = num::cast(10).unwrap();
389        let empty:T = num::cast(0).unwrap();
390        match self {
391            Normal::Toss => thirty,
392            Normal::Throw => thirty,
393            Normal::Strike => thirty,
394            Normal::Tackle => thirty,
395            Normal::Spin => thirty,
396
397            Normal::Slash =>  twenty,
398            Normal::Burn =>  twenty,
399            Normal::Blur => twenty,
400            Normal::Splash =>  twenty,
401            Normal::Crush =>  twenty,
402            Normal::Hit =>  twenty,
403            Normal::Slap =>  twenty,
404            Normal::Whip =>  twenty,
405
406            Normal::Grind =>  ten,
407            Normal::Smack =>  ten,
408            Normal::Melt =>  ten,
409            Normal::Slice =>  ten,
410            Normal::Freeze => ten,
411            Normal::None => empty,
412            // Normal:: => one,
413        }
414    }
415    fn mp_cost(&self, _input:T) -> T {
416        let fifteen:T = num::cast(15).unwrap();
417        let five:T = num::cast(5).unwrap();
418        let ten:T = num::cast(10).unwrap();
419        let empty:T = num::cast(0).unwrap();
420        match self {
421            Normal::Toss => five,
422            Normal::Throw => five,
423            Normal::Strike => five,
424            Normal::Tackle => five,
425            Normal::Spin => five,
426
427            Normal::Slash =>  ten,
428            Normal::Burn =>  ten,
429            Normal::Blur => ten,
430            Normal::Splash =>  ten,
431            Normal::Crush =>  ten,
432            Normal::Hit =>  ten,
433            Normal::Slap =>  ten,
434            Normal::Whip =>  ten,
435
436            Normal::Grind =>  fifteen,
437            Normal::Smack =>  fifteen,
438            Normal::Melt =>  fifteen,
439            Normal::Slice =>  fifteen,
440            Normal::Freeze => fifteen,
441            Normal::None => empty,
442            // Normal:: => one,
443        }
444    }
445}
446
447/*
448# Advanced 
449
450*/
451//TODO more specials
452#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
453#[cfg_attr(feature = "fltkform", derive(FltkForm))]
454pub enum Advanced {
455    /// 
456    /// None
457    None,
458}
459impl Random for Advanced {
460    type Type = Advanced;
461    fn random_type(&self) -> Self::Type {
462        /*let max = 18;
463        let val = self.random_rate(max);
464        match val {
465            _=> Advanced::None,
466        }*/
467        Advanced::None
468    }
469}
470impl Default for Advanced {
471    fn default() -> Self {
472        Self::None
473    }
474}
475impl fmt::Display for Advanced {
476    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
477        let v:String;
478        match *self {
479            Advanced::None => v = "None".to_string(),
480            //Advanced:: => v = String::from(""),
481        }
482        write!(f, "{}", v.as_str())
483    }
484}
485/*
486# Mana Cost
487
488This is to allow a unified set of terms to use for mana/tech related costs, totals and damage
489*/
490pub trait SpecialMove <T:Copy 
491                      + Default
492                      + AddAssign
493                      + Add<Output = T>
494                      + Div<Output = T>
495                      + DivAssign
496                      + Mul<Output = T>
497                      + MulAssign
498                      + Neg<Output = T>
499                      + Rem<Output = T>
500                      + RemAssign
501                      + Sub<Output = T>
502                      + SubAssign
503                      + std::cmp::PartialOrd
504                      + num::NumCast> {
505    fn damage(&self, level:T) -> T;
506    fn mp_total(&self, _input:T) -> T;
507    fn mp_cost(&self, _input:T) -> T;
508    fn tp_cost(&self, input:T) -> T {
509        self.mp_cost(input)
510    }
511    fn tp_total(&self, input:T) -> T{
512        self.mp_total(input)
513    }
514}