Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions korangar-interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,10 @@ where
&self.mouse_mode
}

pub fn set_mouse_mode(&mut self, mouse_mode: MouseMode<App>) {
self.mouse_mode = mouse_mode;
}

pub fn has_focus(&self) -> bool {
self.focused_element.is_some()
}
Expand Down
12 changes: 11 additions & 1 deletion korangar-networking/src/packet_versions/version_20220406.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,17 @@ where
})?;
packet_handler.register_noop::<DisplaySpecialEffectPacket>()?;
packet_handler.register_noop::<DisplaySkillCooldownPacket>()?;
packet_handler.register_noop::<DisplaySkillEffectAndDamagePacket>()?;
packet_handler.register(|packet: DisplaySkillEffectAndDamagePacket| {
// Reuse the regular damage event so skill damage shows damage numbers
// and plays the hit animation just like auto attacks.
NetworkEvent::DamageEffect {
source_entity_id: packet.source_entity_id,
destination_entity_id: packet.destination_entity_id,
damage_amount: (packet.damage > 0).then_some(packet.damage as usize),
attack_duration: packet.destination_delay,
is_critical: false,
}
})?;
packet_handler.register(|packet: DisplaySkillEffectNoDamagePacket| NetworkEvent::HealEffect {
entity_id: packet.destination_entity_id,
heal_amount: packet.heal_amount as usize,
Expand Down
13 changes: 11 additions & 2 deletions korangar/src/input/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use korangar_debug::profiling::FrameMeasurement;
use korangar_interface::event::{ClickHandler, Event, EventQueue};
use korangar_networking::{InventoryItem, ShopItem};
use ragnarok_packets::{
AccountId, BuyOrSellOption, CharacterId, CharacterServerInformation, EntityId, HotbarSlot, ShopId, SkillId, SoldItemInformation,
StatUpType, TilePosition,
AccountId, BuyOrSellOption, CharacterId, CharacterServerInformation, EntityId, HotbarSlot, ShopId, SkillId, SkillLevel,
SoldItemInformation, StatUpType, TilePosition,
};
use rust_state::State;

Expand Down Expand Up @@ -173,6 +173,15 @@ pub enum InputEvent {
CastSkill {
/// Slot of the hotbar that the skill is bound to.
slot: HotbarSlot,
/// Level to cast the skill at.
level: SkillLevel,
},
/// Use the skill in a hotbar slot, like in the original client. Skills
/// that require a target start a target selection, self cast skills are
/// cast immediately.
UseSkillInSlot {
/// Slot of the hotbar that the skill is bound to.
slot: HotbarSlot,
},
/// Stop a skill.
StopSkill {
Expand Down
46 changes: 26 additions & 20 deletions korangar/src/input/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,28 +274,34 @@ impl InputSystem {
}
}

if self.get_key(KeyCode::KeyJ).pressed() {
events.push(InputEvent::CastSkill { slot: HotbarSlot(0) });
}

if self.get_key(KeyCode::KeyJ).released() {
events.push(InputEvent::StopSkill { slot: HotbarSlot(0) });
}

if self.get_key(KeyCode::KeyL).pressed() {
events.push(InputEvent::CastSkill { slot: HotbarSlot(1) });
}

if self.get_key(KeyCode::KeyL).released() {
events.push(InputEvent::StopSkill { slot: HotbarSlot(1) });
}
// The hotbar slots are mapped to the function keys, like in the
// original client. Pressing a function key uses the skill in that
// slot, which either casts it directly or starts a target selection.
const HOTBAR_KEYS: [KeyCode; 10] = [
KeyCode::F1,
KeyCode::F2,
KeyCode::F3,
KeyCode::F4,
KeyCode::F5,
KeyCode::F6,
KeyCode::F7,
KeyCode::F8,
KeyCode::F9,
KeyCode::F10,
];

if self.get_key(KeyCode::KeyU).pressed() {
events.push(InputEvent::CastSkill { slot: HotbarSlot(2) });
}
for (slot, key_code) in HOTBAR_KEYS.into_iter().enumerate() {
if self.get_key(key_code).pressed() {
events.push(InputEvent::UseSkillInSlot {
slot: HotbarSlot(slot as u16),
});
}

if self.get_key(KeyCode::KeyU).released() {
events.push(InputEvent::StopSkill { slot: HotbarSlot(2) });
if self.get_key(key_code).released() {
events.push(InputEvent::StopSkill {
slot: HotbarSlot(slot as u16),
});
}
}

#[cfg(feature = "debug")]
Expand Down
24 changes: 23 additions & 1 deletion korangar/src/input/mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::sync::Arc;

use korangar_interface::MouseMode;
use korangar_networking::InventoryItem;
use ragnarok_packets::TilePosition;
use ragnarok_packets::{HotbarSlot, SkillLevel, SkillType, TilePosition};

use crate::graphics::Texture;
use crate::interface::resource::{ItemSource, SkillSource};
Expand All @@ -25,6 +25,17 @@ pub enum MouseInputMode {
source: SkillSource,
skill: LearnableSkill,
},
/// The player clicked a skill in the hotbar and is now selecting a target
/// for it, like in the original client. The next left click in the world
/// casts the skill in the given slot.
TargetSkill {
slot: HotbarSlot,
skill_type: SkillType,
/// The level to cast the skill at. Starts at the level the skill was
/// placed in the hotbar with and can be adjusted with the mouse wheel
/// while selecting a target.
level: SkillLevel,
},
}

impl From<MouseInputMode> for MouseMode<ClientState> {
Expand All @@ -46,6 +57,8 @@ pub trait MouseModeExt {
fn is_grabbing(&self) -> bool;

fn grabbed(&self) -> Option<Grabbed>;

fn skill_target(&self) -> Option<(HotbarSlot, SkillType, SkillLevel)>;
}

impl MouseModeExt for MouseMode<ClientState> {
Expand Down Expand Up @@ -90,4 +103,13 @@ impl MouseModeExt for MouseMode<ClientState> {
_ => None,
}
}

fn skill_target(&self) -> Option<(HotbarSlot, SkillType, SkillLevel)> {
match self {
MouseMode::Custom {
mode: MouseInputMode::TargetSkill { slot, skill_type, level },
} => Some((*slot, *skill_type, *level)),
_ => None,
}
}
}
9 changes: 9 additions & 0 deletions korangar/src/interface/components/skill_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,15 @@ where
mode: MouseInputMode::MoveSkill { source, skill },
} = mouse_mode
{
// Dropping a hotbar skill onto its own slot is a simple click,
// which uses the skill like in the original client.
if let (SkillSource::Hotbar { slot }, SkillSource::Hotbar { slot: destination_slot }) = (*source, self.source)
&& slot == destination_slot
{
queue.queue(InputEvent::UseSkillInSlot { slot });
return;
}

queue.queue(InputEvent::MoveSkill {
source: *source,
destination: self.source,
Expand Down
5 changes: 3 additions & 2 deletions korangar/src/interface/cursor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ pub enum MouseCursorState {
Warp = 7,
NoAction = 8,
Grab = 9,
Unsure1 = 10,
/// The target selection cursor used while choosing a target for a skill.
Target = 10,
Unsure2 = 11,
WarpFast = 12,
Unsure3 = 13,
Expand Down Expand Up @@ -157,7 +158,7 @@ impl MouseCursor {

// TODO: Figure out how this is actually supposed to work
let direction = match self.cursor_state {
MouseCursorState::Default | MouseCursorState::Click | MouseCursorState::RotateCamera => 0,
MouseCursorState::Default | MouseCursorState::Click | MouseCursorState::RotateCamera | MouseCursorState::Target => 0,
_ => 7,
};

Expand Down
5 changes: 4 additions & 1 deletion korangar/src/interface/windows/skill_tree/slot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,10 @@ where
} else {
let learned_skill = state.try_get(&self.learned_skill_path);

if learned_skill.is_some_and(|skill| !skill.upgradable) {
// Only skills the player has actually learned can be picked up.
// Whether the skill can still be upgraded is irrelevant here: a
// skill at its maximum level must still be usable from the hotbar.
if learned_skill.is_none_or(|skill| skill.skill_level.0 == 0) {
return;
}

Expand Down
Loading