diff --git a/ggwp-zscene/src/action.rs b/ggwp-zscene/src/action.rs index 94eb932b..1376af33 100644 --- a/ggwp-zscene/src/action.rs +++ b/ggwp-zscene/src/action.rs @@ -2,7 +2,7 @@ use std::{fmt::Debug, time::Duration}; pub use crate::action::{ change_color_to::ChangeColorTo, empty::Empty, fork::Fork, hide::Hide, move_by::MoveBy, - sequence::Sequence, set_color::SetColor, show::Show, sleep::Sleep, + sequence::Sequence, set_color::SetColor, set_facing::SetFacing, show::Show, sleep::Sleep, }; mod change_color_to; @@ -12,6 +12,7 @@ mod hide; mod move_by; mod sequence; mod set_color; +mod set_facing; mod show; mod sleep; diff --git a/ggwp-zscene/src/action/set_facing.rs b/ggwp-zscene/src/action/set_facing.rs new file mode 100644 index 00000000..f217333e --- /dev/null +++ b/ggwp-zscene/src/action/set_facing.rs @@ -0,0 +1,20 @@ +use crate::{Action, Facing, Sprite}; + +#[derive(Debug)] +pub struct SetFacing { + sprite: Sprite, + facing: Facing, +} + +impl SetFacing { + pub fn new(sprite: &Sprite, facing: Facing) -> Self { + let sprite = sprite.clone(); + Self { sprite, facing } + } +} + +impl Action for SetFacing { + fn begin(&mut self) { + self.sprite.set_facing(self.facing); + } +} diff --git a/ggwp-zscene/src/lib.rs b/ggwp-zscene/src/lib.rs index be562970..ec4ef836 100644 --- a/ggwp-zscene/src/lib.rs +++ b/ggwp-zscene/src/lib.rs @@ -14,7 +14,7 @@ use ggez::{Context, GameResult}; pub use crate::{ action::{Action, Boxed}, error::Error, - sprite::Sprite, + sprite::{Facing, Sprite}, }; pub mod action; diff --git a/ggwp-zscene/src/sprite.rs b/ggwp-zscene/src/sprite.rs index 79925228..42dc90f4 100644 --- a/ggwp-zscene/src/sprite.rs +++ b/ggwp-zscene/src/sprite.rs @@ -8,12 +8,19 @@ use ggez::{ use crate::{Error, Result}; +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Facing { + Left, + Right, +} + struct SpriteData { drawable: Box, dimensions: Rect, basic_scale: f32, param: graphics::DrawParam, offset: Vector2, + facing: Facing, } impl fmt::Debug for SpriteData { @@ -24,6 +31,7 @@ impl fmt::Debug for SpriteData { .field("basic_scale", &self.basic_scale) .field("param", &self.param) .field("offset", &self.offset) + .field("facing", &self.facing) .finish() } } @@ -54,6 +62,7 @@ impl Sprite { basic_scale: scale, param, offset: Vector2::new(0.0, 0.0), + facing: Facing::Right, }; let data = Rc::new(RefCell::new(data)); Ok(Self { data }) @@ -70,6 +79,24 @@ impl Sprite { // TODO: some method to change the image. + pub fn set_facing(&mut self, facing: Facing) { + if facing == self.data.borrow().facing { + return; + } + let offset; + { + let mut data = self.data.borrow_mut(); + data.facing = facing; + data.param.scale.x *= -1.0; + let mut dimensions = data.dimensions; + dimensions.scale(data.param.scale.x, data.param.scale.y); + let off_x = -data.offset.x / dimensions.w; + let off_y = -data.offset.y / dimensions.h; + offset = Vector2::new(-off_x, off_y); + } + self.set_offset(offset); + } + pub fn set_centered(&mut self, is_centered: bool) { let offset = if is_centered { Vector2::new(0.5, 0.5) diff --git a/src/geom.rs b/src/geom.rs index 9724d424..d47bf3e8 100644 --- a/src/geom.rs +++ b/src/geom.rs @@ -30,3 +30,31 @@ pub fn rand_tile_offset(size: f32, radius: f32) -> Vector2 { thread_rng().gen_range(-r, r) * FLATNESS_COEFFICIENT, ) } + +#[derive(Clone, Copy, Debug)] +pub enum Facing { + Left, + Right, +} + +impl Facing { + pub fn from_positions(tile_size: f32, from: PosHex, to: PosHex) -> Option { + if from == to { + return None; + } + let from = hex_to_point(tile_size, from); + let to = hex_to_point(tile_size, to); + Some(if to.x > from.x { + Facing::Right + } else { + Facing::Left + }) + } + + pub fn to_scene_facing(self) -> scene::Facing { + match self { + Facing::Left => scene::Facing::Left, + Facing::Right => scene::Facing::Right, + } + } +} diff --git a/src/main.rs b/src/main.rs index f1b95794..132ca957 100644 --- a/src/main.rs +++ b/src/main.rs @@ -101,7 +101,7 @@ fn main() -> ZResult { const APP_ID: &str = "zemeroth"; const APP_AUTHOR: &str = "ozkriff"; const ASSETS_DIR_NAME: &str = "assets"; - const ASSETS_HASHSUM: &str = "a9ac7e886bb9319f7ec5cdddba24731b"; + const ASSETS_HASHSUM: &str = "a42fb4a97d6529620dabec3defea8aa9"; fn enable_backtrace() { if std::env::var("RUST_BACKTRACE").is_err() { diff --git a/src/screen/battle/visualize.rs b/src/screen/battle/visualize.rs index ccc0defc..c8927f18 100644 --- a/src/screen/battle/visualize.rs +++ b/src/screen/battle/visualize.rs @@ -8,13 +8,13 @@ use ggez::{ }; use log::{debug, info}; use rand::{thread_rng, Rng}; -use scene::{action, Action, Boxed, Sprite}; +use scene::{action, Action, Boxed, Facing, Sprite}; use crate::{ core::{ battle::{ ability::Ability, - component::{ObjType, WeaponType}, + component::{Component, WeaponType}, effect::{self, Effect}, event::{self, ActiveEvent, Event}, execute::{hit_chance, ApplyPhase}, @@ -407,10 +407,10 @@ fn sprite_params(name: &str) -> SpriteInfo { "spearman" => ("/spearman.png", 0.2, 0.05, 1.0), "hammerman" => ("/hammerman.png", 0.05, 0.1, 1.0), "alchemist" => ("/alchemist.png", 0.05, 0.1, 1.0), - "imp" => ("/imp.png", -0.05, 0.15, 1.3), - "imp_toxic" => ("/imp_toxic.png", -0.05, 0.15, 1.2), - "imp_bomber" => ("/imp_bomber.png", -0.05, 0.15, 1.2), - "imp_summoner" => ("/imp_summoner.png", -0.05, 0.15, 1.3), + "imp" => ("/imp.png", 0.0, 0.15, 1.3), + "imp_toxic" => ("/imp_toxic.png", 0.0, 0.15, 1.2), + "imp_bomber" => ("/imp_bomber.png", 0.0, 0.15, 1.2), + "imp_summoner" => ("/imp_summoner.png", 0.0, 0.15, 1.3), "boulder" => ("/boulder.png", 0.0, 0.4, 2.5), "bomb_damage" => ("/bomb.png", 0.0, 0.2, 0.7), "bomb_push" => ("/bomb.png", 0.0, 0.2, 0.7), @@ -521,49 +521,6 @@ fn visualize_event( Ok(action) } -fn visualize_create( - view: &mut BattleView, - context: &mut Context, - id: ObjId, - pos: PosHex, - prototype: &ObjType, -) -> ZResult> { - // TODO: Move to some .ron config: - let SpriteInfo { - path, - offset_x, - offset_y, - shadow_size_coefficient, - } = sprite_params(prototype.0.as_str()); - let point = geom::hex_to_point(view.tile_size(), pos); - let color = [1.0, 1.0, 1.0, 1.0].into(); - let size = view.tile_size() * 2.0; - let sprite_object = { - let mut sprite = Sprite::from_path(context, path, size)?; - sprite.set_color(Color { a: 0.0, ..color }); - sprite.set_offset(Vector2::new(0.5 - offset_x, 1.0 - offset_y)); - sprite.set_pos(point); - sprite - }; - let sprite_shadow = { - let image_shadow = view.images().shadow.clone(); - let mut sprite = Sprite::from_image(context, image_shadow, size * shadow_size_coefficient)?; - sprite.set_centered(true); - sprite.set_color(Color { a: 0.0, ..color }); - sprite.set_pos(point); - sprite - }; - view.add_object(id, &sprite_object, &sprite_shadow); - let action_change_shadow_color = - action::ChangeColorTo::new(&sprite_shadow, color, time_s(0.2)).boxed(); - Ok(seq(vec![ - action::Show::new(&view.layers().shadows, &sprite_shadow).boxed(), - action::Show::new(&view.layers().objects, &sprite_object).boxed(), - fork(action_change_shadow_color), - action::ChangeColorTo::new(&sprite_object, color, time_s(0.25)).boxed(), - ])) -} - fn visualize_event_move_to( _: &State, view: &mut BattleView, @@ -583,6 +540,8 @@ fn visualize_event_move_to( for step in event.path.steps() { let from = geom::hex_to_point(view.tile_size(), step.from); let to = geom::hex_to_point(view.tile_size(), step.to); + let facing = geom::Facing::from_positions(view.tile_size(), step.from, step.to) + .expect("Bad path step"); let diff = to - from; let step_height = view.tile_size() * 0.25; let step_time = time_s(0.13); @@ -590,6 +549,7 @@ fn visualize_event_move_to( let main_move = action::MoveBy::new(&sprite, diff, move_time).boxed(); let shadow_move = action::MoveBy::new(&sprite_shadow, diff, move_time).boxed(); let action = seq(vec![ + action::SetFacing::new(&sprite, facing.to_scene_facing()).boxed(), fork(main_move), fork(shadow_move), up_and_down_move(view, &sprite, step_height, step_time), @@ -628,6 +588,9 @@ fn visualize_event_attack( let action_shadow_move_to = action::MoveBy::new(&sprite_shadow, diff, time_to).boxed(); let action_sprite_move_from = action::MoveBy::new(&sprite, -diff, time_from).boxed(); let action_shadow_move_from = action::MoveBy::new(&sprite_shadow, -diff, time_from).boxed(); + if let Some(facing) = geom::Facing::from_positions(view.tile_size(), map_from, map_to) { + actions.push(action::SetFacing::new(&sprite, facing.to_scene_facing()).boxed()); + } actions.push(fork(action_shadow_move_to)); actions.push(action_sprite_move_to); actions.push(show_weapon_flash(view, context, map_to, event.weapon_type)?); @@ -786,10 +749,14 @@ fn visualize_event_use_ability( }; let pos = state.parts().pos.get(event.id).0; let text = event.ability.to_string(); - Ok(seq(vec![ - action_main, - message(view, context, pos, &format!("<{}>", text))?, - ])) + let mut actions = Vec::new(); + if let Some(facing) = geom::Facing::from_positions(view.tile_size(), pos, event.pos) { + let sprite = view.id_to_sprite(event.id).clone(); + actions.push(action::SetFacing::new(&sprite, facing.to_scene_facing()).boxed()); + } + actions.push(action_main); + actions.push(message(view, context, pos, &format!("<{}>", text))?); + Ok(seq(actions)) } fn visualize_event_effect_tick( @@ -865,7 +832,47 @@ fn visualize_effect_create( target_id: ObjId, effect: &effect::Create, ) -> ZResult> { - visualize_create(view, context, target_id, effect.pos, &effect.prototype).map(fork) + // TODO: Move to some .ron config: + let SpriteInfo { + path, + offset_x, + offset_y, + shadow_size_coefficient, + } = sprite_params(effect.prototype.0.as_str()); + let point = geom::hex_to_point(view.tile_size(), effect.pos); + let color = [1.0, 1.0, 1.0, 1.0].into(); + let size = view.tile_size() * 2.0; + let sprite_object = { + let mut sprite = Sprite::from_path(context, path, size)?; + sprite.set_color(Color { a: 0.0, ..color }); + sprite.set_offset(Vector2::new(0.5 - offset_x, 1.0 - offset_y)); + sprite.set_pos(point); + for component in &effect.components { + if let Component::BelongsTo(belongs_to) = component { + if belongs_to.0 == PlayerId(1) { + sprite.set_facing(Facing::Left); + } + } + } + sprite + }; + let sprite_shadow = { + let image_shadow = view.images().shadow.clone(); + let mut sprite = Sprite::from_image(context, image_shadow, size * shadow_size_coefficient)?; + sprite.set_centered(true); + sprite.set_color(Color { a: 0.0, ..color }); + sprite.set_pos(point); + sprite + }; + view.add_object(target_id, &sprite_object, &sprite_shadow); + let action_change_shadow_color = + action::ChangeColorTo::new(&sprite_shadow, color, time_s(0.2)).boxed(); + Ok(fork(seq(vec![ + action::Show::new(&view.layers().shadows, &sprite_shadow).boxed(), + action::Show::new(&view.layers().objects, &sprite_object).boxed(), + fork(action_change_shadow_color), + action::ChangeColorTo::new(&sprite_object, color, time_s(0.25)).boxed(), + ]))) } fn visualize_effect_kill(