mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Addressed MR comments.
This commit is contained in:
parent
4d3b0736d0
commit
7ae8ed09f6
@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Slashing damage now reduces target's energy by an amount equal to damage dealt to target post-mitigation
|
- Slashing damage now reduces target's energy by an amount equal to damage dealt to target post-mitigation
|
||||||
- Crushing damage now does poise damage to a target equal to the amount mitigated by armor
|
- Crushing damage now does poise damage to a target equal to the amount mitigated by armor
|
||||||
- UI to select abilities and assign to hotbar
|
- UI to select abilities and assign to hotbar
|
||||||
|
- Position of abilities on hotbar is now persisted through the server
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ macro_rules! dev_panic {
|
|||||||
if cfg!(any(debug_assertions, test)) {
|
if cfg!(any(debug_assertions, test)) {
|
||||||
panic!("{}", $msg);
|
panic!("{}", $msg);
|
||||||
} else {
|
} else {
|
||||||
tracing::warn!("{}", $msg);
|
tracing::error!("{}", $msg);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -209,7 +209,7 @@ impl ActiveAbilities {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_ability_set<'a>(
|
fn default_ability_set<'a>(
|
||||||
inv: Option<&'a Inventory>,
|
inv: Option<&'a Inventory>,
|
||||||
skill_set: Option<&'a SkillSet>,
|
skill_set: Option<&'a SkillSet>,
|
||||||
) -> [AuxiliaryAbility; MAX_ABILITIES] {
|
) -> [AuxiliaryAbility; MAX_ABILITIES] {
|
||||||
@ -220,15 +220,7 @@ impl ActiveAbilities {
|
|||||||
.map(AuxiliaryAbility::OffWeapon),
|
.map(AuxiliaryAbility::OffWeapon),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut array = [AuxiliaryAbility::Empty; MAX_ABILITIES];
|
[(); MAX_ABILITIES].map(|()| iter.next().unwrap_or(AuxiliaryAbility::Empty))
|
||||||
|
|
||||||
for ability in array.iter_mut() {
|
|
||||||
if let Some(available_ability) = iter.next() {
|
|
||||||
*ability = available_ability;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
array
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::persistence::character_updater::CharacterUpdater;
|
use crate::persistence::{character_updater::CharacterUpdater, PersistedComponents};
|
||||||
use common::{
|
use common::{
|
||||||
character::CharacterId,
|
character::CharacterId,
|
||||||
comp::{inventory::loadout_builder::LoadoutBuilder, Body, Inventory, Item, SkillSet, Stats},
|
comp::{inventory::loadout_builder::LoadoutBuilder, Body, Inventory, Item, SkillSet, Stats},
|
||||||
@ -65,20 +65,15 @@ pub fn create_character(
|
|||||||
|
|
||||||
let waypoint = None;
|
let waypoint = None;
|
||||||
|
|
||||||
character_updater.create_character(
|
character_updater.create_character(entity, player_uuid, character_alias, PersistedComponents {
|
||||||
entity,
|
|
||||||
player_uuid,
|
|
||||||
character_alias,
|
|
||||||
(
|
|
||||||
body,
|
body,
|
||||||
stats,
|
stats,
|
||||||
skill_set,
|
skill_set,
|
||||||
inventory,
|
inventory,
|
||||||
waypoint,
|
waypoint,
|
||||||
Vec::new(),
|
pets: Vec::new(),
|
||||||
Default::default(),
|
active_abilities: Default::default(),
|
||||||
),
|
});
|
||||||
);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::{client::Client, sys, Server, StateExt};
|
use crate::{client::Client, persistence::PersistedComponents, sys, Server, StateExt};
|
||||||
use common::{
|
use common::{
|
||||||
character::CharacterId,
|
character::CharacterId,
|
||||||
comp::{
|
comp::{
|
||||||
@ -35,15 +35,7 @@ pub fn handle_initialize_character(
|
|||||||
pub fn handle_loaded_character_data(
|
pub fn handle_loaded_character_data(
|
||||||
server: &mut Server,
|
server: &mut Server,
|
||||||
entity: EcsEntity,
|
entity: EcsEntity,
|
||||||
loaded_components: (
|
loaded_components: PersistedComponents,
|
||||||
comp::Body,
|
|
||||||
comp::Stats,
|
|
||||||
comp::SkillSet,
|
|
||||||
comp::Inventory,
|
|
||||||
Option<comp::Waypoint>,
|
|
||||||
Vec<(comp::Pet, comp::Body, comp::Stats)>,
|
|
||||||
comp::ActiveAbilities,
|
|
||||||
),
|
|
||||||
) {
|
) {
|
||||||
server
|
server
|
||||||
.state
|
.state
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
use crate::{events::interaction::handle_tame_pet, state_ext::StateExt, Server};
|
use crate::{
|
||||||
|
events::interaction::handle_tame_pet, persistence::PersistedComponents, state_ext::StateExt,
|
||||||
|
Server,
|
||||||
|
};
|
||||||
use common::event::{EventBus, ServerEvent};
|
use common::event::{EventBus, ServerEvent};
|
||||||
use common_base::span;
|
use common_base::span;
|
||||||
use entity_creation::{
|
use entity_creation::{
|
||||||
@ -129,6 +132,17 @@ impl Server {
|
|||||||
character_id,
|
character_id,
|
||||||
} => handle_initialize_character(self, entity, character_id),
|
} => handle_initialize_character(self, entity, character_id),
|
||||||
ServerEvent::UpdateCharacterData { entity, components } => {
|
ServerEvent::UpdateCharacterData { entity, components } => {
|
||||||
|
let (body, stats, skill_set, inventory, waypoint, pets, active_abilities) =
|
||||||
|
components;
|
||||||
|
let components = PersistedComponents {
|
||||||
|
body,
|
||||||
|
stats,
|
||||||
|
skill_set,
|
||||||
|
inventory,
|
||||||
|
waypoint,
|
||||||
|
pets,
|
||||||
|
active_abilities,
|
||||||
|
};
|
||||||
handle_loaded_character_data(self, entity, components);
|
handle_loaded_character_data(self, entity, components);
|
||||||
},
|
},
|
||||||
ServerEvent::ExitIngame { entity } => {
|
ServerEvent::ExitIngame { entity } => {
|
||||||
|
@ -55,6 +55,7 @@ use crate::{
|
|||||||
connection_handler::ConnectionHandler,
|
connection_handler::ConnectionHandler,
|
||||||
data_dir::DataDir,
|
data_dir::DataDir,
|
||||||
login_provider::LoginProvider,
|
login_provider::LoginProvider,
|
||||||
|
persistence::PersistedComponents,
|
||||||
presence::{Presence, RegionSubscription, RepositionOnChunkLoad},
|
presence::{Presence, RegionSubscription, RepositionOnChunkLoad},
|
||||||
rtsim::RtSim,
|
rtsim::RtSim,
|
||||||
state_ext::StateExt,
|
state_ext::StateExt,
|
||||||
@ -844,9 +845,29 @@ impl Server {
|
|||||||
},
|
},
|
||||||
CharacterLoaderResponseKind::CharacterData(result) => {
|
CharacterLoaderResponseKind::CharacterData(result) => {
|
||||||
let message = match *result {
|
let message = match *result {
|
||||||
Ok(character_data) => ServerEvent::UpdateCharacterData {
|
Ok(character_data) => {
|
||||||
|
let PersistedComponents {
|
||||||
|
body,
|
||||||
|
stats,
|
||||||
|
skill_set,
|
||||||
|
inventory,
|
||||||
|
waypoint,
|
||||||
|
pets,
|
||||||
|
active_abilities,
|
||||||
|
} = character_data;
|
||||||
|
let character_data = (
|
||||||
|
body,
|
||||||
|
stats,
|
||||||
|
skill_set,
|
||||||
|
inventory,
|
||||||
|
waypoint,
|
||||||
|
pets,
|
||||||
|
active_abilities,
|
||||||
|
);
|
||||||
|
ServerEvent::UpdateCharacterData {
|
||||||
entity: query_result.entity,
|
entity: query_result.entity,
|
||||||
components: character_data,
|
components: character_data,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
// We failed to load data for the character from the DB. Notify the
|
// We failed to load data for the character from the DB. Notify the
|
||||||
|
@ -248,20 +248,20 @@ pub fn load_character_data(
|
|||||||
})
|
})
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok((
|
Ok(PersistedComponents {
|
||||||
convert_body_from_database(&body_data.variant, &body_data.body_data)?,
|
body: convert_body_from_database(&body_data.variant, &body_data.body_data)?,
|
||||||
convert_stats_from_database(character_data.alias),
|
stats: convert_stats_from_database(character_data.alias),
|
||||||
convert_skill_set_from_database(&skill_group_data),
|
skill_set: convert_skill_set_from_database(&skill_group_data),
|
||||||
convert_inventory_from_database_items(
|
inventory: convert_inventory_from_database_items(
|
||||||
character_containers.inventory_container_id,
|
character_containers.inventory_container_id,
|
||||||
&inventory_items,
|
&inventory_items,
|
||||||
character_containers.loadout_container_id,
|
character_containers.loadout_container_id,
|
||||||
&loadout_items,
|
&loadout_items,
|
||||||
)?,
|
)?,
|
||||||
char_waypoint,
|
waypoint: char_waypoint,
|
||||||
pets,
|
pets,
|
||||||
convert_active_abilities_from_database(&ability_set_data),
|
active_abilities: convert_active_abilities_from_database(&ability_set_data),
|
||||||
))
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads a list of characters belonging to the player. This data is a small
|
/// Loads a list of characters belonging to the player. This data is a small
|
||||||
@ -346,7 +346,15 @@ pub fn create_character(
|
|||||||
) -> CharacterCreationResult {
|
) -> CharacterCreationResult {
|
||||||
check_character_limit(uuid, transaction)?;
|
check_character_limit(uuid, transaction)?;
|
||||||
|
|
||||||
let (body, _stats, skill_set, inventory, waypoint, _, active_abilities) = persisted_components;
|
let PersistedComponents {
|
||||||
|
body,
|
||||||
|
stats: _,
|
||||||
|
skill_set,
|
||||||
|
inventory,
|
||||||
|
waypoint,
|
||||||
|
pets: _,
|
||||||
|
active_abilities,
|
||||||
|
} = persisted_components;
|
||||||
|
|
||||||
// Fetch new entity IDs for character, inventory and loadout
|
// Fetch new entity IDs for character, inventory and loadout
|
||||||
let mut new_entity_ids = get_new_entity_ids(transaction, |next_id| next_id + 3)?;
|
let mut new_entity_ids = get_new_entity_ids(transaction, |next_id| next_id + 3)?;
|
||||||
|
@ -125,36 +125,51 @@ fn aux_ability_to_string(ability: common::comp::ability::AuxiliaryAbility) -> St
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn aux_ability_from_string(ability: String) -> common::comp::ability::AuxiliaryAbility {
|
fn aux_ability_from_string(ability: &str) -> common::comp::ability::AuxiliaryAbility {
|
||||||
use common::comp::ability::AuxiliaryAbility;
|
use common::comp::ability::AuxiliaryAbility;
|
||||||
let parts = ability
|
let mut parts = ability.split(":index:");
|
||||||
.split(":index:")
|
match parts.next() {
|
||||||
.map(String::from)
|
Some("Main Weapon") => match parts
|
||||||
.collect::<Vec<_>>();
|
.next()
|
||||||
match parts.get(0).map(|s| s.as_str()) {
|
.map(|index| index.parse::<usize>().map_err(|_| index))
|
||||||
Some("Main Weapon") => {
|
{
|
||||||
if let Some(index) = parts.get(1).and_then(|index| index.parse::<usize>().ok()) {
|
Some(Ok(index)) => AuxiliaryAbility::MainWeapon(index),
|
||||||
AuxiliaryAbility::MainWeapon(index)
|
Some(Err(error)) => {
|
||||||
} else {
|
|
||||||
dev_panic!(format!(
|
dev_panic!(format!(
|
||||||
"Converstion from databse to ability set failed. Unable to parse index for \
|
"Conversion from database to ability set failed. Unable to parse index for \
|
||||||
mainhand abilities: {:#?}",
|
mainhand abilities: {}",
|
||||||
parts.get(1)
|
error
|
||||||
));
|
));
|
||||||
AuxiliaryAbility::Empty
|
AuxiliaryAbility::Empty
|
||||||
}
|
|
||||||
},
|
},
|
||||||
Some("Off Weapon") => {
|
None => {
|
||||||
if let Some(index) = parts.get(1).and_then(|index| index.parse::<usize>().ok()) {
|
dev_panic!(String::from(
|
||||||
AuxiliaryAbility::OffWeapon(index)
|
"Conversion from database to ability set failed. Unable to find an index for \
|
||||||
} else {
|
mainhand abilities"
|
||||||
dev_panic!(format!(
|
|
||||||
"Converstion from databse to ability set failed. Unable to parse index for \
|
|
||||||
offhand abilities: {:#?}",
|
|
||||||
parts.get(1)
|
|
||||||
));
|
));
|
||||||
AuxiliaryAbility::Empty
|
AuxiliaryAbility::Empty
|
||||||
}
|
},
|
||||||
|
},
|
||||||
|
Some("Off Weapon") => match parts
|
||||||
|
.next()
|
||||||
|
.map(|index| index.parse::<usize>().map_err(|_| index))
|
||||||
|
{
|
||||||
|
Some(Ok(index)) => AuxiliaryAbility::OffWeapon(index),
|
||||||
|
Some(Err(error)) => {
|
||||||
|
dev_panic!(format!(
|
||||||
|
"Conversion from database to ability set failed. Unable to parse index for \
|
||||||
|
offhand abilities: {}",
|
||||||
|
error
|
||||||
|
));
|
||||||
|
AuxiliaryAbility::Empty
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
dev_panic!(String::from(
|
||||||
|
"Conversion from database to ability set failed. Unable to find an index for \
|
||||||
|
offhand abilities"
|
||||||
|
));
|
||||||
|
AuxiliaryAbility::Empty
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Some("Empty") => AuxiliaryAbility::Empty,
|
Some("Empty") => AuxiliaryAbility::Empty,
|
||||||
unknown => {
|
unknown => {
|
||||||
@ -182,6 +197,7 @@ fn tool_kind_to_string(tool: Option<common::comp::item::tool::ToolKind>) -> Stri
|
|||||||
Some(Blowgun) => "Blowgun",
|
Some(Blowgun) => "Blowgun",
|
||||||
Some(Pick) => "Pick",
|
Some(Pick) => "Pick",
|
||||||
|
|
||||||
|
// Toolkinds that are not anticipated to have many active aiblities (if any at all)
|
||||||
Some(Farming) => "Farming",
|
Some(Farming) => "Farming",
|
||||||
Some(Debug) => "Debug",
|
Some(Debug) => "Debug",
|
||||||
Some(Natural) => "Natural",
|
Some(Natural) => "Natural",
|
||||||
@ -251,7 +267,7 @@ pub fn active_abilities_from_db_model(
|
|||||||
let mut auxiliary_abilities =
|
let mut auxiliary_abilities =
|
||||||
[comp::ability::AuxiliaryAbility::Empty; comp::ability::MAX_ABILITIES];
|
[comp::ability::AuxiliaryAbility::Empty; comp::ability::MAX_ABILITIES];
|
||||||
for (empty, ability) in auxiliary_abilities.iter_mut().zip(abilities.into_iter()) {
|
for (empty, ability) in auxiliary_abilities.iter_mut().zip(abilities.into_iter()) {
|
||||||
*empty = aux_ability_from_string(ability);
|
*empty = aux_ability_from_string(&ability);
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
|
@ -21,16 +21,17 @@ use std::{
|
|||||||
};
|
};
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
/// A tuple of the components that are persisted to the DB for each character
|
/// A struct of the components that are persisted to the DB for each character
|
||||||
pub type PersistedComponents = (
|
#[derive(Debug)]
|
||||||
comp::Body,
|
pub struct PersistedComponents {
|
||||||
comp::Stats,
|
pub body: comp::Body,
|
||||||
comp::SkillSet,
|
pub stats: comp::Stats,
|
||||||
comp::Inventory,
|
pub skill_set: comp::SkillSet,
|
||||||
Option<comp::Waypoint>,
|
pub inventory: comp::Inventory,
|
||||||
Vec<PetPersistenceData>,
|
pub waypoint: Option<comp::Waypoint>,
|
||||||
comp::ActiveAbilities,
|
pub pets: Vec<PetPersistenceData>,
|
||||||
);
|
pub active_abilities: comp::ActiveAbilities,
|
||||||
|
}
|
||||||
|
|
||||||
pub type EditableComponents = (comp::Body,);
|
pub type EditableComponents = (comp::Body,);
|
||||||
|
|
||||||
|
@ -238,7 +238,6 @@ impl StateExt for State {
|
|||||||
.unwrap_or(0),
|
.unwrap_or(0),
|
||||||
))
|
))
|
||||||
.with(stats)
|
.with(stats)
|
||||||
// TODO: Figure out way to have this start with sane defaults
|
|
||||||
.with(comp::ActiveAbilities::default())
|
.with(comp::ActiveAbilities::default())
|
||||||
.with(skill_set)
|
.with(skill_set)
|
||||||
.maybe_with(health)
|
.maybe_with(health)
|
||||||
@ -498,7 +497,15 @@ impl StateExt for State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update_character_data(&mut self, entity: EcsEntity, components: PersistedComponents) {
|
fn update_character_data(&mut self, entity: EcsEntity, components: PersistedComponents) {
|
||||||
let (body, stats, skill_set, inventory, waypoint, pets, active_abilities) = components;
|
let PersistedComponents {
|
||||||
|
body,
|
||||||
|
stats,
|
||||||
|
skill_set,
|
||||||
|
inventory,
|
||||||
|
waypoint,
|
||||||
|
pets,
|
||||||
|
active_abilities,
|
||||||
|
} = components;
|
||||||
|
|
||||||
if let Some(player_uid) = self.read_component_copied::<Uid>(entity) {
|
if let Some(player_uid) = self.read_component_copied::<Uid>(entity) {
|
||||||
// Notify clients of a player list update
|
// Notify clients of a player list update
|
||||||
|
@ -48,7 +48,6 @@ use common::{
|
|||||||
},
|
},
|
||||||
consts::{ENERGY_PER_LEVEL, HP_PER_LEVEL},
|
consts::{ENERGY_PER_LEVEL, HP_PER_LEVEL},
|
||||||
};
|
};
|
||||||
use inline_tweak::*;
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
const ART_SIZE: [f64; 2] = [320.0, 320.0];
|
const ART_SIZE: [f64; 2] = [320.0, 320.0];
|
||||||
@ -782,12 +781,12 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
// Background Art
|
// Background Art
|
||||||
Image::new(self.imgs.book_bg)
|
Image::new(self.imgs.book_bg)
|
||||||
.w_h(299.0 * 4.0, 184.0 * 4.0)
|
.w_h(299.0 * 4.0, 184.0 * 4.0)
|
||||||
.mid_top_with_margin_on(state.ids.content_align, tweak!(4.0))
|
.mid_top_with_margin_on(state.ids.content_align, 4.0)
|
||||||
//.graphics_for(state.ids.content_align)
|
//.graphics_for(state.ids.content_align)
|
||||||
.set(state.ids.spellbook_art, ui);
|
.set(state.ids.spellbook_art, ui);
|
||||||
Image::new(self.imgs.skills_bg)
|
Image::new(self.imgs.skills_bg)
|
||||||
.w_h(240.0 * 2.0, 40.0 * 2.0)
|
.w_h(240.0 * 2.0, 40.0 * 2.0)
|
||||||
.mid_bottom_with_margin_on(state.ids.content_align, tweak!(8.0))
|
.mid_bottom_with_margin_on(state.ids.content_align, 8.0)
|
||||||
.set(state.ids.spellbook_skills_bg, ui);
|
.set(state.ids.spellbook_skills_bg, ui);
|
||||||
|
|
||||||
Rectangle::fill_with([299.0 * 2.0, 184.0 * 4.0], color::TRANSPARENT)
|
Rectangle::fill_with([299.0 * 2.0, 184.0 * 4.0], color::TRANSPARENT)
|
||||||
@ -816,7 +815,7 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
background_color: Some(UI_MAIN),
|
background_color: Some(UI_MAIN),
|
||||||
content_size: ContentSize {
|
content_size: ContentSize {
|
||||||
width_height_ratio: 1.0,
|
width_height_ratio: 1.0,
|
||||||
max_fraction: tweak!(0.9),
|
max_fraction: 0.9,
|
||||||
},
|
},
|
||||||
selected_content_scale: 1.067,
|
selected_content_scale: 1.067,
|
||||||
amount_font: self.fonts.cyri.conrod_id,
|
amount_font: self.fonts.cyri.conrod_id,
|
||||||
@ -838,11 +837,14 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
Some(self.skill_set),
|
Some(self.skill_set),
|
||||||
)
|
)
|
||||||
.ability_id(Some(self.inventory));
|
.ability_id(Some(self.inventory));
|
||||||
let (ability_title, ability_desc) =
|
let (ability_title, ability_desc) = if let Some(ability_id) = ability_id {
|
||||||
util::ability_description(ability_id.unwrap_or(""));
|
util::ability_description(ability_id)
|
||||||
|
} else {
|
||||||
|
("Drag an ability here to use it.", "")
|
||||||
|
};
|
||||||
|
|
||||||
let image_size = tweak!(80.0);
|
let image_size = 80.0;
|
||||||
let image_offsets = tweak!(92.0) * i as f64;
|
let image_offsets = 92.0 * i as f64;
|
||||||
|
|
||||||
let slot = AbilitySlot::Slot(i);
|
let slot = AbilitySlot::Slot(i);
|
||||||
let mut ability_slot = slot_maker.fabricate(slot, [image_size; 2]);
|
let mut ability_slot = slot_maker.fabricate(slot, [image_size; 2]);
|
||||||
@ -850,8 +852,8 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
if i == 0 {
|
if i == 0 {
|
||||||
ability_slot = ability_slot.top_left_with_margins_on(
|
ability_slot = ability_slot.top_left_with_margins_on(
|
||||||
state.ids.spellbook_skills_bg,
|
state.ids.spellbook_skills_bg,
|
||||||
tweak!(0.0),
|
0.0,
|
||||||
tweak!(32.0) + image_offsets,
|
32.0 + image_offsets,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
ability_slot =
|
ability_slot =
|
||||||
@ -870,52 +872,22 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
// Display Slot Keybinding
|
// Display Slot Keybinding
|
||||||
let keys = &self.global_state.settings.controls;
|
let keys = &self.global_state.settings.controls;
|
||||||
let key_layout = &self.global_state.window.key_layout;
|
let key_layout = &self.global_state.window.key_layout;
|
||||||
let ability_key: String = match i {
|
let ability_key = [
|
||||||
0 => {
|
GameInput::Slot1,
|
||||||
if let Some(key) = keys.get_binding(GameInput::Slot1) {
|
GameInput::Slot2,
|
||||||
key.display_string(key_layout)
|
GameInput::Slot3,
|
||||||
} else {
|
GameInput::Slot4,
|
||||||
String::new()
|
GameInput::Slot5,
|
||||||
}
|
]
|
||||||
},
|
.get(i)
|
||||||
1 => {
|
.and_then(|input| keys.get_binding(*input))
|
||||||
if let Some(key) = keys.get_binding(GameInput::Slot2) {
|
.map(|key| key.display_string(key_layout))
|
||||||
key.display_string(key_layout)
|
.unwrap_or_default();
|
||||||
} else {
|
|
||||||
String::new()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
2 => {
|
|
||||||
if let Some(key) = keys.get_binding(GameInput::Slot3) {
|
|
||||||
key.display_string(key_layout)
|
|
||||||
} else {
|
|
||||||
String::new()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
3 => {
|
|
||||||
if let Some(key) = keys.get_binding(GameInput::Slot4) {
|
|
||||||
key.display_string(key_layout)
|
|
||||||
} else {
|
|
||||||
String::new()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
4 => {
|
|
||||||
if let Some(key) = keys.get_binding(GameInput::Slot5) {
|
|
||||||
key.display_string(key_layout)
|
|
||||||
} else {
|
|
||||||
String::new()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => String::new(),
|
|
||||||
};
|
|
||||||
Text::new(&ability_key)
|
Text::new(&ability_key)
|
||||||
.top_left_with_margins_on(
|
.top_left_with_margins_on(state.ids.active_abilities[i], 0.0, 4.0)
|
||||||
state.ids.active_abilities[i],
|
|
||||||
tweak!(0.0),
|
|
||||||
tweak!(4.0),
|
|
||||||
)
|
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
.font_size(self.fonts.cyri.scale(tweak!(20)))
|
.font_size(self.fonts.cyri.scale(20))
|
||||||
.color(TEXT_COLOR)
|
.color(TEXT_COLOR)
|
||||||
.graphics_for(state.ids.active_abilities[i])
|
.graphics_for(state.ids.active_abilities[i])
|
||||||
.set(state.ids.active_abilities_keys[i], ui);
|
.set(state.ids.active_abilities_keys[i], ui);
|
||||||
@ -964,31 +936,30 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
state.update(|s| s.ability_page = 0);
|
state.update(|s| s.ability_page = 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
let update_length = 12;
|
|
||||||
state.update(|s| {
|
state.update(|s| {
|
||||||
s.ids
|
s.ids
|
||||||
.abilities
|
.abilities
|
||||||
.resize(update_length, &mut ui.widget_id_generator())
|
.resize(ABILITIES_PER_PAGE, &mut ui.widget_id_generator())
|
||||||
});
|
});
|
||||||
state.update(|s| {
|
state.update(|s| {
|
||||||
s.ids
|
s.ids
|
||||||
.abilities_dual
|
.abilities_dual
|
||||||
.resize(update_length, &mut ui.widget_id_generator())
|
.resize(ABILITIES_PER_PAGE, &mut ui.widget_id_generator())
|
||||||
});
|
});
|
||||||
state.update(|s| {
|
state.update(|s| {
|
||||||
s.ids
|
s.ids
|
||||||
.ability_titles
|
.ability_titles
|
||||||
.resize(update_length, &mut ui.widget_id_generator())
|
.resize(ABILITIES_PER_PAGE, &mut ui.widget_id_generator())
|
||||||
});
|
});
|
||||||
state.update(|s| {
|
state.update(|s| {
|
||||||
s.ids
|
s.ids
|
||||||
.ability_frames
|
.ability_frames
|
||||||
.resize(update_length, &mut ui.widget_id_generator())
|
.resize(ABILITIES_PER_PAGE, &mut ui.widget_id_generator())
|
||||||
});
|
});
|
||||||
state.update(|s| {
|
state.update(|s| {
|
||||||
s.ids
|
s.ids
|
||||||
.ability_descs
|
.ability_descs
|
||||||
.resize(update_length, &mut ui.widget_id_generator())
|
.resize(ABILITIES_PER_PAGE, &mut ui.widget_id_generator())
|
||||||
});
|
});
|
||||||
|
|
||||||
// Page button
|
// Page button
|
||||||
@ -998,7 +969,7 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
} else {
|
} else {
|
||||||
self.imgs.arrow_l_inactive
|
self.imgs.arrow_l_inactive
|
||||||
})
|
})
|
||||||
.bottom_left_with_margins_on(state.ids.spellbook_art, tweak!(-83.0), tweak!(10.0))
|
.bottom_left_with_margins_on(state.ids.spellbook_art, -83.0, 10.0)
|
||||||
.w_h(48.0, 55.0);
|
.w_h(48.0, 55.0);
|
||||||
// Grey out arrows when inactive
|
// Grey out arrows when inactive
|
||||||
if state.ability_page > 0 {
|
if state.ability_page > 0 {
|
||||||
@ -1019,7 +990,7 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
} else {
|
} else {
|
||||||
self.imgs.arrow_r_inactive
|
self.imgs.arrow_r_inactive
|
||||||
})
|
})
|
||||||
.bottom_right_with_margins_on(state.ids.spellbook_art, tweak!(-83.0), tweak!(10.0))
|
.bottom_right_with_margins_on(state.ids.spellbook_art, -83.0, 10.0)
|
||||||
.w_h(48.0, 55.0);
|
.w_h(48.0, 55.0);
|
||||||
if state.ability_page < page_indices {
|
if state.ability_page < page_indices {
|
||||||
// Only show right button if not on last page
|
// Only show right button if not on last page
|
||||||
@ -1036,7 +1007,6 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let ability_start = state.ability_page * ABILITIES_PER_PAGE;
|
let ability_start = state.ability_page * ABILITIES_PER_PAGE;
|
||||||
let abilities_range = ability_start..(ability_start + ABILITIES_PER_PAGE);
|
|
||||||
|
|
||||||
let mut slot_maker = SlotMaker {
|
let mut slot_maker = SlotMaker {
|
||||||
empty_slot: self.imgs.inv_slot,
|
empty_slot: self.imgs.inv_slot,
|
||||||
@ -1045,9 +1015,9 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
background_color: Some(UI_MAIN),
|
background_color: Some(UI_MAIN),
|
||||||
content_size: ContentSize {
|
content_size: ContentSize {
|
||||||
width_height_ratio: 1.0,
|
width_height_ratio: 1.0,
|
||||||
max_fraction: tweak!(1.0),
|
max_fraction: 1.0,
|
||||||
},
|
},
|
||||||
selected_content_scale: tweak!(1.067),
|
selected_content_scale: 1.067,
|
||||||
amount_font: self.fonts.cyri.conrod_id,
|
amount_font: self.fonts.cyri.conrod_id,
|
||||||
amount_margins: Vec2::new(-4.0, 0.0),
|
amount_margins: Vec2::new(-4.0, 0.0),
|
||||||
amount_font_size: self.fonts.cyri.scale(12),
|
amount_font_size: self.fonts.cyri.scale(12),
|
||||||
@ -1060,10 +1030,8 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
|
|
||||||
for (id_index, (ability_id, ability)) in abilities
|
for (id_index, (ability_id, ability)) in abilities
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.skip(ability_start)
|
||||||
.filter_map(|(i, ability_info)| {
|
.take(ABILITIES_PER_PAGE)
|
||||||
abilities_range.contains(&i).then_some(ability_info)
|
|
||||||
})
|
|
||||||
.enumerate()
|
.enumerate()
|
||||||
{
|
{
|
||||||
let (ability_title, ability_desc) =
|
let (ability_title, ability_desc) =
|
||||||
@ -1081,13 +1049,8 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
self.imgs.ability_frame
|
self.imgs.ability_frame
|
||||||
})
|
})
|
||||||
.w_h(566.0, 108.0)
|
.w_h(566.0, 108.0)
|
||||||
.top_left_with_margins_on(
|
.top_left_with_margins_on(align_state, 16.0 + image_offsets, 16.0)
|
||||||
align_state,
|
|
||||||
tweak!(16.0) + image_offsets,
|
|
||||||
tweak!(16.0),
|
|
||||||
)
|
|
||||||
.color(Some(UI_HIGHLIGHT_0))
|
.color(Some(UI_HIGHLIGHT_0))
|
||||||
//.parent(state.ids.abilities[id_index])
|
|
||||||
.set(state.ids.ability_frames[id_index], ui);
|
.set(state.ids.ability_frames[id_index], ui);
|
||||||
|
|
||||||
let slot = AbilitySlot::Ability(*ability);
|
let slot = AbilitySlot::Ability(*ability);
|
||||||
@ -1121,19 +1084,15 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
Text::new(ability_title)
|
Text::new(ability_title)
|
||||||
.top_left_with_margins_on(state.ids.abilities[id_index], 5.0, 110.0)
|
.top_left_with_margins_on(state.ids.abilities[id_index], 5.0, 110.0)
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
.font_size(self.fonts.cyri.scale(tweak!(28)))
|
.font_size(self.fonts.cyri.scale(28))
|
||||||
.color(TEXT_COLOR)
|
.color(TEXT_COLOR)
|
||||||
.w(text_width)
|
.w(text_width)
|
||||||
.graphics_for(state.ids.abilities[id_index])
|
.graphics_for(state.ids.abilities[id_index])
|
||||||
.set(state.ids.ability_titles[id_index], ui);
|
.set(state.ids.ability_titles[id_index], ui);
|
||||||
Text::new(ability_desc)
|
Text::new(ability_desc)
|
||||||
.top_left_with_margins_on(
|
.top_left_with_margins_on(state.ids.abilities[id_index], 40.0, 110.0)
|
||||||
state.ids.abilities[id_index],
|
|
||||||
tweak!(40.0),
|
|
||||||
110.0,
|
|
||||||
)
|
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
.font_size(self.fonts.cyri.scale(tweak!(18)))
|
.font_size(self.fonts.cyri.scale(18))
|
||||||
.color(TEXT_COLOR)
|
.color(TEXT_COLOR)
|
||||||
.w(text_width)
|
.w(text_width)
|
||||||
.graphics_for(state.ids.abilities[id_index])
|
.graphics_for(state.ids.abilities[id_index])
|
||||||
@ -1162,7 +1121,7 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
// Background Art
|
// Background Art
|
||||||
Image::new(self.imgs.book_bg)
|
Image::new(self.imgs.book_bg)
|
||||||
.w_h(299.0 * 4.0, 184.0 * 4.0)
|
.w_h(299.0 * 4.0, 184.0 * 4.0)
|
||||||
.mid_top_with_margin_on(state.ids.content_align, tweak!(4.0))
|
.mid_top_with_margin_on(state.ids.content_align, 4.0)
|
||||||
.set(state.ids.spellbook_art, ui);
|
.set(state.ids.spellbook_art, ui);
|
||||||
|
|
||||||
state.update(|s| {
|
state.update(|s| {
|
||||||
@ -1183,13 +1142,9 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
.color(BLACK);
|
.color(BLACK);
|
||||||
|
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
txt = txt.top_left_with_margins_on(
|
txt = txt.top_left_with_margins_on(state.ids.spellbook_art, 20.0, 20.0);
|
||||||
state.ids.spellbook_art,
|
|
||||||
tweak!(20.0),
|
|
||||||
tweak!(20.0),
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
txt = txt.down_from(state.ids.stat_names[i - 1], tweak!(10.0));
|
txt = txt.down_from(state.ids.stat_names[i - 1], 10.0);
|
||||||
};
|
};
|
||||||
txt.set(state.ids.stat_names[i], ui);
|
txt.set(state.ids.stat_names[i], ui);
|
||||||
|
|
||||||
@ -1261,7 +1216,7 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
(Some(stats), None) | (None, Some(stats)) => {
|
(Some(stats), None) | (None, Some(stats)) => {
|
||||||
format!("{}", stats.power * 10.0)
|
format!("{}", stats.power * 10.0)
|
||||||
},
|
},
|
||||||
_ => String::new(),
|
(None, None) => String::new(),
|
||||||
},
|
},
|
||||||
"Weapon Speed" => {
|
"Weapon Speed" => {
|
||||||
let spd_fmt = |sp| (sp - 1.0) * 100.0;
|
let spd_fmt = |sp| (sp - 1.0) * 100.0;
|
||||||
@ -1288,7 +1243,7 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
(Some(stats), None) | (None, Some(stats)) => {
|
(Some(stats), None) | (None, Some(stats)) => {
|
||||||
format!("{}", stats.effect_power * 10.0)
|
format!("{}", stats.effect_power * 10.0)
|
||||||
},
|
},
|
||||||
_ => String::new(),
|
(None, None) => String::new(),
|
||||||
},
|
},
|
||||||
"Weapon Crit-Chance" => {
|
"Weapon Crit-Chance" => {
|
||||||
let crit_fmt = |cc| cc * 100.0;
|
let crit_fmt = |cc| cc * 100.0;
|
||||||
@ -1301,10 +1256,10 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
(Some(stats), None) | (None, Some(stats)) => {
|
(Some(stats), None) | (None, Some(stats)) => {
|
||||||
format!("{:.1}%", crit_fmt(stats.crit_chance))
|
format!("{:.1}%", crit_fmt(stats.crit_chance))
|
||||||
},
|
},
|
||||||
_ => String::new(),
|
(None, None) => String::new(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => String::new(),
|
unknown => unreachable!(unknown),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut number = Text::new(&value)
|
let mut number = Text::new(&value)
|
||||||
@ -1313,9 +1268,9 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
.color(BLACK);
|
.color(BLACK);
|
||||||
|
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
number = number.right_from(state.ids.stat_names[i], tweak!(265.0));
|
number = number.right_from(state.ids.stat_names[i], 265.0);
|
||||||
} else {
|
} else {
|
||||||
number = number.down_from(state.ids.stat_values[i - 1], tweak!(10.0));
|
number = number.down_from(state.ids.stat_values[i - 1], 10.0);
|
||||||
};
|
};
|
||||||
number.set(state.ids.stat_values[i], ui);
|
number.set(state.ids.stat_values[i], ui);
|
||||||
}
|
}
|
||||||
|
@ -3392,7 +3392,7 @@ impl Hud {
|
|||||||
(AbilitySlot::Slot(index), _) => {
|
(AbilitySlot::Slot(index), _) => {
|
||||||
events.push(Event::ChangeAbility(index, AuxiliaryAbility::Empty));
|
events.push(Event::ChangeAbility(index, AuxiliaryAbility::Empty));
|
||||||
},
|
},
|
||||||
(_, _) => {},
|
(AbilitySlot::Ability(_), AbilitySlot::Ability(_)) => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -3494,7 +3494,7 @@ impl Hud {
|
|||||||
(AbilitySlot::Slot(index), _) => {
|
(AbilitySlot::Slot(index), _) => {
|
||||||
events.push(Event::ChangeAbility(index, AuxiliaryAbility::Empty));
|
events.push(Event::ChangeAbility(index, AuxiliaryAbility::Empty));
|
||||||
},
|
},
|
||||||
(_, _) => {},
|
(AbilitySlot::Ability(_), AbilitySlot::Ability(_)) => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -250,5 +250,10 @@ impl From<AbilitySlot> for SlotKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SumSlot for SlotKind {
|
impl SumSlot for SlotKind {
|
||||||
fn is_ability(&self) -> bool { matches!(self, Self::Ability(_)) }
|
fn drag_size(&self) -> Option<[f64; 2]> {
|
||||||
|
Some(match self {
|
||||||
|
Self::Ability(_) => [80.0; 2],
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -398,8 +398,8 @@ pub fn ability_description(ability_id: &str) -> (&str, &str) {
|
|||||||
"Protects you and your group with thorns for a short amount of time.",
|
"Protects you and your group with thorns for a short amount of time.",
|
||||||
),
|
),
|
||||||
_ => (
|
_ => (
|
||||||
"Drag an ability here to use it.",
|
"Ability has no title",
|
||||||
""
|
"Ability has no description."
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ pub trait SlotKey<C, I>: Copy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait SumSlot: Sized + PartialEq + Copy + Send + 'static {
|
pub trait SumSlot: Sized + PartialEq + Copy + Send + 'static {
|
||||||
fn is_ability(&self) -> bool;
|
fn drag_size(&self) -> Option<[f64; 2]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ContentSize {
|
pub struct ContentSize {
|
||||||
@ -219,8 +219,8 @@ where
|
|||||||
let content_img = *content_img;
|
let content_img = *content_img;
|
||||||
let drag_amount = *drag_amount;
|
let drag_amount = *drag_amount;
|
||||||
|
|
||||||
let dragged_size = if slot.is_ability() {
|
let dragged_size = if let Some(dragged_size) = slot.drag_size() {
|
||||||
[inline_tweak::tweak!(80.0); 2]
|
dragged_size
|
||||||
} else {
|
} else {
|
||||||
self.drag_img_size.map(|e| e as f64).into_array()
|
self.drag_img_size.map(|e| e as f64).into_array()
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user