Fireball constants

This commit is contained in:
Michael Smith 2021-11-13 00:44:35 +01:00
parent 2640bea49e
commit 93b270c5f3

View File

@ -53,6 +53,8 @@ const LIGHTNING_DAMAGE: i32 = 40;
const LIGHTNING_RANGE: i32 = 5;
const CONFUSE_RANGE: i32 = 8;
const CONFUSE_NUM_TURNS: i32 = 10;
const FIREBALL_RADIUS: i32 = 3;
const FIREBALL_DAMAGE: i32 = 12;
struct Tcod {
root: Root,
@ -164,6 +166,11 @@ impl Object {
}
}
}
// Return the distance to some coordinates
pub fn distance(&self, x: i32, y: i32) -> f32 {
(((x - self.x).pow(2) + (y - self.y).pow(2)) as f32).sqrt()
}
}
#[derive(Clone, Copy, Debug)]
@ -918,6 +925,44 @@ fn cast_confuse(
}
}
fn cast_fireball(
_inventory_id: usize,
tcod: &mut Tcod,
game: &mut Game,
objects: &mut [Object],
) -> UseResult {
// Ask the player for a target tile to throw a fireball at
game.messages.add(
"Left-click a target tile for the fireball, or right-click to cancel.",
LIGHT_CYAN,
);
let (x, y) = match target_tile(tcod, game, objects, None) {
Some(tile_pos) => tile_pos,
None => return UseResult::Canceled,
};
game.messages.add(
format!(
"The fireball explodes, burning everything within {} tiles!",
FIREBALL_RADIUS
),
ORANGE,
);
for obj in objects {
if obj.distance(x, y) <= FIREBALL_RADIUS as f32 && obj.fighter.is_some() {
game.messages.add(
format!(
"The {} gets burned for {} hit points.",
obj.name, FIREBALL_DAMAGE
),
ORANGE,
);
obj.take_damage(FIREBALL_DAMAGE, game);
}
}
UseResult::UsedUp
}
// Find closest enemy, up to a maximum range, and in the player's FOV
fn closest_monster(tcod: &Tcod, objects: &[Object], max_range: i32) -> Option<usize> {
let mut closest_enemy = None;
@ -942,6 +987,44 @@ fn closest_monster(tcod: &Tcod, objects: &[Object], max_range: i32) -> Option<us
closest_enemy
}
// Return the position of a tile left-clicked in player's FOV (optionally in a
// range), or (None, None) if right-clicked.
fn target_tile(
tcod: &mut Tcod,
game: &mut Game,
objects: &[Object],
max_range: Option<f32>,
) -> Option<(i32, i32)> {
use tcod::input::KeyCode::Escape;
loop {
// Render the screen. This erases the inventory and shows the names of
// objects under the mouse.
tcod.root.flush();
let event = input::check_for_event(input::KEY_PRESS | input::MOUSE).map(|e| e.1);
match event {
Some(Event::Mouse(m)) => tcod.mouse = m,
Some(Event::Key(k)) => tcod.key = k,
None => tcod.key = Default::default(),
}
render_all(tcod, game, objects, false);
let (x, y) = (tcod.mouse.cx as i32, tcod.mouse.cy as i32);
// Accept the target if the player clicked in FOV, and in case a range
// is specified, if it's in that range
let in_fov = (x < MAP_WIDTH) && (y < MAP_HEIGHT) && tcod.fov.is_in_fov(x, y);
let in_range = max_range.map_or(true, |range| objects[PLAYER].distance(x, y) <= range);
if tcod.mouse.lbutton_pressed && in_fov && in_range {
return Some((x, y));
}
if tcod.mouse.rbutton_pressed || tcod.key.code == Escape {
return None; // Cancel if the player right-clicked or pressed escape.
}
}
}
fn render_all(tcod: &mut Tcod, game: &mut Game, objects: &[Object], fov_recompute: bool) {
if fov_recompute {
let player = &objects[PLAYER];