1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
//! Manual `GameState` manipulation, to be used when implementing a UI.
//!
//! For a UI implementing the use of this see the implementation of `Widgets::update()`.


use self::super::{Difficulty, GameState};
use self::super::super::util::FRUITS;
use rand::{Rng, thread_rng};
use std::mem;


/// Press the Start button in `MainMenu`, transforming it into `ChooseDifficulty`.
///
/// If the supplied argument is not `MainMenu`, it remains unchanged.
///
/// # Examples
///
/// ```
/// # use poke_a_mango::ops::{state, GameState};
/// # let start_button_pressed = true;
/// let mut state = GameState::MainMenu;
/// if start_button_pressed {
///     state::press_start(&mut state);
/// }
/// ```
pub fn press_start(s: &mut GameState) {
    if let GameState::MainMenu = *s {
        *s = GameState::ChooseDifficulty
    }
}

/// Press the Display Highscores button in `MainMenu`, transforming it into `LoadLeaderboard`.
///
/// If the supplied argument is not `MainMenu`, it remains unchanged.
///
/// # Examples
///
/// ```
/// # use poke_a_mango::ops::{state, GameState};
/// # let display_highscores_button_pressed = true;
/// let mut state = GameState::MainMenu;
/// if display_highscores_button_pressed {
///     state::press_display_highscores(&mut state);
///     // Then probably load the leaderboard
/// }
/// ```
pub fn press_display_highscores(s: &mut GameState) {
    if let GameState::MainMenu = *s {
        *s = GameState::LoadLeaderboard;
    }
}

/// Press the Exit button in `MainMenu`, transforming it into `Exit`.
///
/// If the supplied argument is not `MainMenu`, it remains unchanged.
///
/// # Examples
///
/// ```
/// # use poke_a_mango::ops::{state, GameState};
/// # let exit_button_pressed = true;
/// let mut state = GameState::MainMenu;
/// if exit_button_pressed {
///     state::press_exit(&mut state);
///     // Then probably close the window
/// }
/// ```
pub fn press_exit(s: &mut GameState) {
    if let GameState::MainMenu = *s {
        *s = GameState::Exit;
    }
}

/// Press one of the Difficulty buttons in `ChooseDifficulty`, transforming it into `Exit`.
///
/// If the supplied argument is not `ChooseDifficulty`, it remains unchanged.
///
/// # Examples
///
/// ```
/// # use poke_a_mango::ops::{state, Difficulty, GameState};
/// # let difficulty_easy_button_pressed = false;
/// # let difficulty_normal_button_pressed = true;
/// # let difficulty_hard_button_pressed = false;
/// let mut state = GameState::ChooseDifficulty;
/// if difficulty_easy_button_pressed {
///     state::select_difficulty(&mut state, Difficulty::Easy);
/// } else if difficulty_normal_button_pressed {
///     state::select_difficulty(&mut state, Difficulty::Normal);
/// } else if difficulty_hard_button_pressed {
///     state::select_difficulty(&mut state, Difficulty::Hard);
/// }
/// ```
pub fn select_difficulty(s: &mut GameState, difficulty: Difficulty) {
    if let GameState::ChooseDifficulty = *s {
        *s = GameState::Playing {
            difficulty: difficulty,
            score: 0,
            fruit: None,
        }
    }
}

/// Press the Back button in `ChooseDifficulty`, `GameOver` or `DisplayLeaderboard`, transforming them into `MainMenu`.
///
/// If the supplied argument is not `ChooseDifficulty`, `GameOver` or `DisplayLeaderboard`, it remains unchanged.
///
/// # Examples
///
/// ```
/// # use poke_a_mango::ops::{state, GameState};
/// # let back_button_pressed = false;
/// let mut state = GameState::ChooseDifficulty;
/// if back_button_pressed {
///     state::press_back(&mut state);
/// }
/// ```
pub fn press_back(s: &mut GameState) {
    match *s {
        GameState::ChooseDifficulty |
        GameState::GameOver { .. } |
        GameState::DisplayLeaderboard(_) => *s = GameState::MainMenu,
        _ => {}
    }
}

/// Tick the mango in Playing state.
///
/// Call this before displaying/updating the label of the mango button. Returns the original fruit.
///
/// If the supplied argument is not Playing, it remains unchanged.
///
/// # Examples
///
/// ```
/// # use poke_a_mango::ops::{state, Difficulty, GameState};
/// # use poke_a_mango::util::fruit_name;
/// # let mango_button = ();
/// # fn update_label(_: &(), _: &'static str) {}
/// let mut state = GameState::Playing {
///     difficulty: Difficulty::Hard,
///     score: 12,
///     fruit: None,
/// };
/// let fruit = state::tick_mango(&mut state);
/// update_label(&mango_button, fruit_name(&fruit));
/// ```
pub fn tick_mango(s: &mut GameState) -> Option<usize> {
    match *s {
        GameState::Playing { difficulty, ref mut fruit, .. } => {
            let original_fruit = *fruit;

            // Difficulty's numeric value is inverted here
            let mut rng = thread_rng();
            let change_fruit = rng.gen_weighted_bool(25 * (4 - difficulty.numeric()));
            if change_fruit {
                *fruit = if fruit.is_none() {
                    Some(rng.gen_range(0, FRUITS.len()))
                } else {
                    None
                };
            }

            original_fruit
        }
        _ => None,
    }
}

/// End the mango processing sequence, given whether it was clicked and whether it was actually a mango.
///
/// If the supplied argument is not Playing or the button wasn't clicked, it remains unchanged.
///
/// # Examples
///
/// ```
/// # use poke_a_mango::ops::{state, Difficulty, GameState};
/// # use poke_a_mango::util::fruit_name;
/// # let previous_fruit = Some(0);
/// # let mango_button_clicked = true;
/// let mut state = GameState::Playing {
///     difficulty: Difficulty::Hard,
///     score: 12,
///     fruit: None,
/// };
/// state::end_mango(&mut state, mango_button_clicked, previous_fruit.is_none());
/// ```
pub fn end_mango(s: &mut GameState, clicked: bool, was_mango: bool) {
    if !clicked {
        return;
    }

    if was_mango {
        if let GameState::Playing { ref mut score, .. } = *s {
            *score += 1
        }
    } else if let GameState::Playing { difficulty, score, .. } = *s {
        *s = GameState::GameOver {
            difficulty: difficulty,
            score: score,
            name: "Your name".to_string(),
        };
    }
}

/// Finalise name editing and sum up the score.
///
/// If the supplied argument is not `GameOver`, it remains unchanged.
///
/// # Examples
///
/// ```
/// # use poke_a_mango::ops::{state, Difficulty, GameState};
/// # struct TextEdit;
/// # impl TextEdit {
/// #     fn text(&self) -> &'static str {
/// #         "наб"
/// #     }
/// # }
/// # let name_input = TextEdit;
/// let mut state = GameState::GameOver {
///     difficulty: Difficulty::Hard,
///     score: 12,
///     name: name_input.text().to_string(),
/// };
/// state::submit_name(&mut state);
/// ```
pub fn submit_name(s: &mut GameState) {
    let args = if let GameState::GameOver { difficulty, score, ref mut name } = *s {
        Some((difficulty, score, mem::replace(name, "".to_string())))
    } else {
        None
    };
    if let Some((difficulty, score, name)) = args {
        *s = GameState::GameEnded {
            name: name,
            score: ((score as f64) * difficulty.point_weight()).floor() as u64,
        };
    }
}