Files
programmieren-in-rust/aufgaben/sheet05/sol1/src/game.rs
T
2017-02-16 15:12:56 +01:00

163 lines
4.3 KiB
Rust
Executable File

use db::types::*;
use db;
use engine::Pokemon;
use term_painter::Color::*;
use term_painter::ToStyle;
pub fn fight(mut red: Pokemon, mut blue: Pokemon) {
loop {
fn check_dead(poki: &Pokemon) -> bool {
if poki.is_alive() {
false
} else {
println!(">>>>> {} fainted!", Yellow.paint(poki.name()));
true
}
}
// Print status
println!(
">>>>> Status: {} has {} HP, {} has {} HP",
Yellow.paint(red.name()),
Red.paint(red.stats().hp),
Yellow.paint(blue.name()),
Red.paint(blue.stats().hp),
);
// Execute both attack
if red.stats().speed > blue.stats().speed {
// Red attacks blue
execute_round(&red, &mut blue);
if check_dead(&blue) {
break;
}
// BLue attacks red
execute_round(&blue, &mut red);
if check_dead(&red) {
break;
}
} else {
// BLue attacks red
execute_round(&blue, &mut red);
if check_dead(&red) {
break;
}
// Red attacks blue
execute_round(&red, &mut blue);
if check_dead(&blue) {
break;
}
}
}
}
/// Executes one round of one player:
///
/// - the player chooses one attack to execute
/// - the attack is excuted and the enemy's HP
fn execute_round(attacker: &Pokemon, defender: &mut Pokemon) {
// Tell the user to choose an attack
println!(
">>>>> {} is about to attack! Which move shall it execute?",
Yellow.paint(attacker.model().name)
);
// Print a list of available attacks
let num_attacks = attacker.model().attacks.len();
for i in 0..num_attacks {
println!(
" {}: {}",
i,
Blue.paint(attacker.model().attacks[i].name)
);
}
println!(" !!! Please give me the attack ID:");
// Read attack ID from the user
let attack_id;
loop {
let input = read_usize();
if input >= num_attacks {
println!(" !!! There is no attack with index {}!", input);
} else {
attack_id = input;
break;
}
}
// Execute attack
let attack = *attacker.model().attacks[attack_id];
defender.endure_attack(attacker, attack);
// Status update
println!(
">>>>> {} uses {}! ({} has {} HP left)",
Yellow.paint(attacker.model().name),
Blue.paint(attack.name),
Yellow.paint(defender.model().name),
Red.paint(defender.stats().hp),
);
}
/// Let's the player choose a Pokemon from the database.
pub fn choose_pokemon(player: &str) -> PokemonModel {
// Loop forever until the user has chosen a Pokemon
loop {
println!(
"{}, please choose a Pokemon (or type '?' to get a complete list)",
player,
);
let input = read_string();
if input == "?" {
print_pokemon_list();
} else {
// Try to find a Pokemon with the given name
match db::pokemon_by_name(&input) {
Some(poki) => return poki,
None => {
println!("No pokemon with the name '{}' was found!", input);
}
}
}
}
}
/// Prints a list of all Pokemon in the database.
fn print_pokemon_list() {
for poki in db::data::POKEDEX {
// This strange formatter will print the pokemon ID with three digits,
// filling in 0 from the left if necessary (#003).
println!("#{:0>3} {}", poki.id, poki.name);
}
}
/// Reads a string from the terminal/user.
fn read_string() -> String {
let mut buffer = String::new();
::std::io::stdin()
.read_line(&mut buffer)
.expect("something went horribly wrong...");
// Discard trailing newline
let new_len = buffer.trim_right().len();
buffer.truncate(new_len);
buffer
}
/// Reads a valid `usize` integer from the terminal/user.
fn read_usize() -> usize {
loop {
match read_string().parse() {
Ok(res) => return res,
Err(_) => println!("That was not an integer! Please try again!"),
}
}
}