diff --git a/assets/voxygen/voxel/sprite/door/door-1.vox b/assets/voxygen/voxel/sprite/door/door-1.vox new file mode 100644 index 0000000000..3f2626b045 --- /dev/null +++ b/assets/voxygen/voxel/sprite/door/door-1.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c133a9aac9f1ad5f5543730b93ad07ab861b91cb456e6f47d0625925e7176377 +size 30287 diff --git a/assets/voxygen/voxel/sprite/door/door-2.vox b/assets/voxygen/voxel/sprite/door/door-2.vox new file mode 100644 index 0000000000..315667ec78 --- /dev/null +++ b/assets/voxygen/voxel/sprite/door/door-2.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a744ae72c131593c2995eb15ae483a0027b0812bd4c9b3fe0405cae1ba085138 +size 30287 diff --git a/client/src/lib.rs b/client/src/lib.rs index 329faaa51a..8eef870cb4 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -545,6 +545,14 @@ impl Client { .unwrap(); } + pub fn interact_with_door(&mut self, pos: Vec3) { + self.singleton_stream + .send(ClientMsg::ControlEvent(ControlEvent::InventoryManip( + InventoryManip::DoorInteraction(pos), + ))) + .unwrap(); + } + pub fn collect_block(&mut self, pos: Vec3) { self.singleton_stream .send(ClientMsg::ControlEvent(ControlEvent::InventoryManip( diff --git a/common/src/comp/controller.rs b/common/src/comp/controller.rs index ca8bcda1b0..b4c0eb04cb 100644 --- a/common/src/comp/controller.rs +++ b/common/src/comp/controller.rs @@ -12,6 +12,7 @@ pub const DEFAULT_HOLD_DURATION: Duration = Duration::from_millis(200); pub enum InventoryManip { Pickup(Uid), Collect(Vec3), + DoorInteraction(Vec3), Use(Slot), Swap(Slot, Slot), Drop(Slot), @@ -153,6 +154,7 @@ pub struct ControllerInputs { pub secondary: Input, pub ability3: Input, pub jump: Input, + pub interact: Input, pub roll: Input, pub glide: Input, pub wall_leap: Input, @@ -178,6 +180,7 @@ impl ControllerInputs { self.secondary.tick(dt); self.ability3.tick(dt); self.jump.tick(dt); + self.interact.tick(dt); self.roll.tick(dt); self.glide.tick(dt); self.wall_leap.tick(dt); @@ -190,6 +193,7 @@ impl ControllerInputs { self.secondary.tick_freshness(); self.ability3.tick_freshness(); self.jump.tick_freshness(); + self.interact.tick_freshness(); self.roll.tick_freshness(); self.glide.tick_freshness(); self.wall_leap.tick_freshness(); @@ -203,6 +207,7 @@ impl ControllerInputs { self.secondary.update_with_new(new.secondary); self.ability3.update_with_new(new.ability3); self.jump.update_with_new(new.jump); + self.interact.update_with_new(new.interact); self.roll.update_with_new(new.roll); self.glide.update_with_new(new.glide); self.wall_leap.update_with_new(new.wall_leap); diff --git a/common/src/terrain/block.rs b/common/src/terrain/block.rs index 6c69a9ee35..6502f715c0 100644 --- a/common/src/terrain/block.rs +++ b/common/src/terrain/block.rs @@ -61,6 +61,8 @@ pub enum BlockKind { StreetLamp, StreetLampTall, Door, + DoorOpen1, + DoorOpen2, Bed, Bench, ChairSingle, @@ -95,6 +97,13 @@ impl BlockKind { } } + pub fn is_tangible2(&self) -> bool { + match self { + BlockKind::Air => false, + kind => !kind.is_fluid(), + } + } + pub fn is_air(&self) -> bool { match self { BlockKind::Air => true, @@ -146,6 +155,8 @@ impl BlockKind { BlockKind::StreetLamp => true, BlockKind::StreetLampTall => true, BlockKind::Door => false, + BlockKind::DoorOpen1 => false, + BlockKind::DoorOpen2 => false, BlockKind::Bed => false, BlockKind::Bench => false, BlockKind::ChairSingle => false, @@ -230,6 +241,8 @@ impl BlockKind { BlockKind::StreetLamp => false, BlockKind::StreetLampTall => false, BlockKind::Door => false, + BlockKind::DoorOpen1 => false, + BlockKind::DoorOpen2 => false, BlockKind::Bed => false, BlockKind::Bench => false, BlockKind::ChairSingle => false, @@ -301,7 +314,9 @@ impl BlockKind { BlockKind::Scarecrow => true, BlockKind::StreetLamp => true, BlockKind::StreetLampTall => true, - BlockKind::Door => false, + BlockKind::Door => true, + BlockKind::DoorOpen1 => false, + BlockKind::DoorOpen2 => false, BlockKind::Bed => true, BlockKind::Bench => true, BlockKind::ChairSingle => true, @@ -350,6 +365,8 @@ impl BlockKind { BlockKind::Carrot => 0.18, BlockKind::Radish => 0.18, BlockKind::Door => 3.0, + BlockKind::DoorOpen1 => 3.0, + BlockKind::DoorOpen2 => 3.0, BlockKind::Bed => 1.54, BlockKind::Bench => 1.45, BlockKind::ChairSingle => 1.36, @@ -389,6 +406,18 @@ impl BlockKind { BlockKind::VeloriteFrag => true, BlockKind::Chest => true, BlockKind::Coconut => true, + BlockKind::Door => false, + BlockKind::DoorOpen1 => false, + BlockKind::DoorOpen2 => false, + _ => false, + } + } + + pub fn is_interactable_terrain(&self) -> bool { + match self { + BlockKind::Door => true, + BlockKind::DoorOpen1 => true, + BlockKind::DoorOpen2 => true, _ => false, } } @@ -423,6 +452,8 @@ impl Block { | BlockKind::Window2 | BlockKind::Window3 | BlockKind::Window4 + | BlockKind::DoorOpen1 + | BlockKind::DoorOpen2 | BlockKind::Door => Some(self.color[0] & 0b111), _ => None, } diff --git a/server/src/events/inventory_manip.rs b/server/src/events/inventory_manip.rs index b33a170e0b..25638bb13d 100644 --- a/server/src/events/inventory_manip.rs +++ b/server/src/events/inventory_manip.rs @@ -6,7 +6,7 @@ use common::{ Pos, MAX_PICKUP_RANGE_SQR, }, sync::{Uid, WorldSyncExt}, - terrain::block::Block, + terrain::{Block, BlockKind}, vol::{ReadVol, Vox}, }; use rand::Rng; @@ -92,6 +92,83 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv state.write_component(entity, event); }, + // the interaction of opening and closing doors + // this might be better off in a different class + comp::InventoryManip::DoorInteraction(pos) => { + let first_door = state.terrain().get(pos).ok().copied(); + + if let Some(first_door) = first_door { + // check for block that is supported by this interaction (in case this method gets extended) + if first_door.is_interactable_terrain() { + + if first_door.kind() == BlockKind::Door { + + let ori = first_door.get_ori().unwrap(); + let color = first_door.get_color().unwrap(); + + // the orientation of doors is saved in the first 'color' as the rgb color is not needed + // the orientation is a value between 0 and 7, the function get ori retrieves a value modulo 8 automatically + // the left and right closed doors facing in the same direction have different orientation so we add the difference (difference of 4, modulo 8) + let rgb = [ori + 4, color[1], color[2]].into(); + state.try_set_block(pos, Block::new(BlockKind::DoorOpen2, rgb)); + + // TODO add a sound effect for 'opening' doors here + + // calculate where to look for a second door + let mut pos2 = pos.clone(); + if ori == 0 { pos2 += (1,0,0); } + else if ori == 2 { pos2 += (0,1,0); } + else if ori == 4 { pos2 += (-1,0,0); } + else if ori == 6 { pos2 += (0,-1,0); } + + let second_door = state.terrain().get(pos2).ok().copied().unwrap(); + + // check if there is a fitting door there + if second_door.kind() == BlockKind::Door { + if second_door.get_ori().unwrap() == (ori + 4) & 0b111 { + state.try_set_block(pos2, Block::new(BlockKind::DoorOpen1, rgb)); + } + } + } else if first_door.kind() == BlockKind::DoorOpen1 || first_door.kind() == BlockKind::DoorOpen2 { + + let ori = first_door.get_ori().unwrap(); + let color = first_door.get_color().unwrap(); + + // same as above, but only needed for open door 2 + let rgb = [ori + 4, color[1], color[2]].into(); + + if first_door.kind() == BlockKind::DoorOpen1 { + state.try_set_block(pos, Block::new(BlockKind::Door, color)); + }else{ + state.try_set_block(pos, Block::new(BlockKind::Door, rgb)); + } + + // TODO add a sound effect for 'closing' doors here + + // calculate where to look for a second door + // (cant think of a smarter way to do this for the case of closing doors. kind and ori is not enough anymore to differentiate left and right) + let positions = [(1,0,0),(0,1,0),(-1,0,0),(0,-1,0)]; + + for i in 0..4 { + let pos2 = pos.clone() + positions[i]; + let second_door = state.terrain().get(pos2).ok().copied().unwrap(); + + //check if there is a fitting door there + if second_door.kind() == BlockKind::DoorOpen1 || second_door.kind() == BlockKind::DoorOpen2 { + if second_door.kind() != first_door.kind() { + if second_door.kind() == BlockKind::DoorOpen1 { + state.try_set_block(pos2, Block::new(BlockKind::Door, color)); + }else{ + state.try_set_block(pos2, Block::new(BlockKind::Door, rgb)); + } + } + } + } + } + } + } + }, + comp::InventoryManip::Collect(pos) => { let block = state.terrain().get(pos).ok().copied(); diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index e40810d398..512e1f10f3 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -254,6 +254,14 @@ fn sprite_config_for(kind: BlockKind) -> Option { variations: 1, wind_sway: 0.0, }), + BlockKind::DoorOpen1 => Some(SpriteConfig { + variations: 1, + wind_sway: 0.0, + }), + BlockKind::DoorOpen2 => Some(SpriteConfig { + variations: 1, + wind_sway: 0.0, + }), BlockKind::Bed => Some(SpriteConfig { variations: 1, wind_sway: 0.0, @@ -2178,6 +2186,22 @@ impl Terrain { Vec3::one(), ), ), + ( + (BlockKind::DoorOpen1, 0), + make_models( + "voxygen.voxel.sprite.door.door-1", + Vec3::new(-5.5, -5.5, 0.0), + Vec3::one(), + ), + ), + ( + (BlockKind::DoorOpen2, 0), + make_models( + "voxygen.voxel.sprite.door.door-2", + Vec3::new(-5.5, -5.5, 0.0), + Vec3::one(), + ), + ), // Bed ( (BlockKind::Bed, 0), diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index ea83cf918c..52e2f3bd7a 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -268,7 +268,7 @@ impl PlayState for SessionState { .state() .terrain() .get(*sp) - .map(|b| b.is_collectible() || can_build) + .map(|b| b.is_collectible() || can_build || b.is_interactable_terrain()) .unwrap_or(false) })); @@ -453,9 +453,13 @@ impl PlayState for SessionState { }, Event::InputUpdate(GameInput::Interact, state) => { let mut client = self.client.borrow_mut(); + self.inputs.interact.set_state(state); // Collect terrain sprites if let Some(select_pos) = self.scene.select_pos() { + if self.inputs.interact.is_just_pressed() { + client.interact_with_door(select_pos); + } client.collect_block(select_pos); }