/skill_preset command

This commit is contained in:
Illia Denysenko 2021-05-08 15:47:09 +00:00 committed by Marcel
parent ad3a63fc80
commit 1c22a2b3fd
4 changed files with 225 additions and 4 deletions

View File

@ -56,6 +56,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- There's now a checkbox in the graphics tab to opt-in to receiving lossily-compressed terrain colors.
- /buff command which allows you to cast a buff on player
- Warn the user with an animated red text in the second phase of a trade in which a party is offering nothing.
- /skill_preset command which allows you to apply skill presets
### Changed

View File

@ -0,0 +1,129 @@
// NOTE: Order matters here
// (you need to unlock skillgroup to be able to unlock skills in it
({
"max": [
// General skills
(General(HealthIncrease), 10),
(General(EnergyIncrease), 5),
(Roll(Cost), 2),
(Roll(Strength), 2),
(Roll(Duration), 2),
(Climb(Cost), 2),
(Climb(Speed), 2),
(Swim(Speed), 2),
// Sword
(UnlockGroup(Weapon(Sword)), 1),
(Sword(InterruptingAttacks), 1),
(Sword(TsCombo), 1),
(Sword(TsDamage), 3),
(Sword(TsRegen), 2),
(Sword(TsSpeed), 3),
(Sword(DCost), 2),
(Sword(DDrain), 2),
(Sword(DDamage), 2),
(Sword(DScaling), 3),
(Sword(DSpeed), 1),
(Sword(DInfinite), 1),
(Sword(UnlockSpin), 1),
(Sword(SDamage), 2),
(Sword(SSpeed), 2),
(Sword(SCost), 2),
(Sword(SSpins), 2),
// Axe
(UnlockGroup(Weapon(Axe)), 1),
(Axe(DsCombo), 1),
(Axe(DsDamage), 3),
(Axe(DsRegen), 2),
(Axe(DsSpeed), 3),
(Axe(SInfinite), 1),
(Axe(SHelicopter), 1),
(Axe(SDamage), 3),
(Axe(SSpeed), 2),
(Axe(SCost), 2),
(Axe(UnlockLeap), 1),
(Axe(LDamage), 2),
(Axe(LKnockback), 2),
(Axe(LCost), 2),
(Axe(LDistance), 2),
// Hammer
(UnlockGroup(Weapon(Hammer)), 1),
(Hammer(SsKnockback), 2),
(Hammer(SsDamage), 3),
(Hammer(SsRegen), 2),
(Hammer(SsSpeed), 3),
(Hammer(CDamage), 3),
(Hammer(CKnockback), 3),
(Hammer(CDrain), 2),
(Hammer(CSpeed), 2),
(Hammer(UnlockLeap), 1),
(Hammer(LDamage), 2),
(Hammer(LCost), 2),
(Hammer(LDistance), 2),
(Hammer(LKnockback), 2),
(Hammer(LRange), 2),
// Bow
(UnlockGroup(Weapon(Bow)), 1),
(Bow(ProjSpeed), 2),
(Bow(BDamage), 3),
(Bow(BRegen), 2),
(Bow(CDamage), 3),
(Bow(CKnockback), 2),
(Bow(CProjSpeed), 2),
(Bow(CDrain), 2),
(Bow(CSpeed), 2),
(Bow(CMove), 2),
(Bow(UnlockRepeater), 1),
(Bow(RGlide), 1),
(Bow(RDamage), 2),
(Bow(RArrows), 2),
(Bow(RCost), 2),
// Staff
(UnlockGroup(Weapon(Staff)), 1),
(Staff(BDamage), 3),
(Staff(BRegen), 2),
(Staff(BRadius), 3),
(Staff(FRange), 2),
(Staff(FDamage), 3),
(Staff(FDrain), 2),
(Staff(FVelocity), 2),
(Staff(UnlockShockwave), 1),
(Staff(SDamage), 2),
(Staff(SKnockback), 2),
(Staff(SRange), 2),
(Staff(SCost), 2),
// Sceptre
(UnlockGroup(Weapon(Sceptre)), 1),
(Sceptre(LDamage), 3),
(Sceptre(LRange), 2),
(Sceptre(LLifesteal), 3),
(Sceptre(LRegen), 2),
(Sceptre(HHeal), 3),
(Sceptre(HCost), 2),
(Sceptre(HRange), 2),
(Sceptre(UnlockAura), 1),
(Sceptre(AStrength), 2),
(Sceptre(ADuration), 2),
(Sceptre(ARange), 2),
(Sceptre(ACost), 2),
],
})

View File

@ -1,6 +1,6 @@
use crate::{
assets,
comp::{self, buff::BuffKind},
comp::{self, buff::BuffKind, Skill},
npc, terrain,
};
use assets::AssetExt;
@ -92,6 +92,7 @@ pub enum ChatCommand {
SetMotd,
Site,
SkillPoint,
SkillPreset,
Spawn,
Sudo,
Tell,
@ -100,8 +101,8 @@ pub enum ChatCommand {
Unban,
Version,
Waypoint,
Wiring,
Whitelist,
Wiring,
World,
}
@ -157,6 +158,7 @@ pub static CHAT_COMMANDS: &[ChatCommand] = &[
ChatCommand::SetMotd,
ChatCommand::Site,
ChatCommand::SkillPoint,
ChatCommand::SkillPreset,
ChatCommand::Spawn,
ChatCommand::Sudo,
ChatCommand::Tell,
@ -165,8 +167,8 @@ pub static CHAT_COMMANDS: &[ChatCommand] = &[
ChatCommand::Unban,
ChatCommand::Version,
ChatCommand::Waypoint,
ChatCommand::Wiring,
ChatCommand::Whitelist,
ChatCommand::Wiring,
ChatCommand::World,
];
@ -178,6 +180,14 @@ impl assets::Asset for KitManifest {
const EXTENSION: &'static str = "ron";
}
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
pub struct SkillPresetManifest(pub HashMap<String, Vec<(Skill, u8)>>);
impl assets::Asset for SkillPresetManifest {
type Loader = assets::RonLoader;
const EXTENSION: &'static str = "ron";
}
lazy_static! {
pub static ref CHAT_SHORTCUTS: HashMap<char, ChatCommand> = [
('f', ChatCommand::Faction),
@ -290,6 +300,22 @@ lazy_static! {
Vec::new()
}
};
static ref PRESETS: HashMap<String, Vec<(Skill, u8)>> = {
if let Ok(presets) = SkillPresetManifest::load("server.manifests.presets") {
presets.read().0.clone()
} else {
warn!("Error while loading presets");
HashMap::new()
}
};
static ref PRESET_LIST: Vec<String> = {
let mut preset_list: Vec<String> = PRESETS.keys().cloned().collect();
preset_list.push("clear".to_owned());
preset_list
};
}
impl ChatCommand {
@ -543,6 +569,11 @@ impl ChatCommand {
"Give yourself skill points for a particular skill tree",
Admin,
),
ChatCommand::SkillPreset => cmd(
vec![Enum("preset_name", PRESET_LIST.to_vec(), Required)],
"Gives your character desired skills.",
Admin,
),
ChatCommand::Spawn => cmd(
vec![
Enum("alignment", ALIGNMENTS.clone(), Required),
@ -649,6 +680,7 @@ impl ChatCommand {
ChatCommand::SetMotd => "set_motd",
ChatCommand::Site => "site",
ChatCommand::SkillPoint => "skill_point",
ChatCommand::SkillPreset => "skill_preset",
ChatCommand::Spawn => "spawn",
ChatCommand::Sudo => "sudo",
ChatCommand::Tell => "tell",
@ -754,7 +786,7 @@ pub enum ArgumentSpec {
/// * suggested tab-completion
/// * whether it's optional
Float(&'static str, f32, Requirement),
/// The argument is a float. The associated values are
/// The argument is an integer. The associated values are
/// * label
/// * suggested tab-completion
/// * whether it's optional

View File

@ -143,6 +143,7 @@ fn get_handler(cmd: &ChatCommand) -> CommandHandler {
ChatCommand::SetMotd => handle_set_motd,
ChatCommand::Site => handle_site,
ChatCommand::SkillPoint => handle_skill_point,
ChatCommand::SkillPreset => handle_skill_preset,
ChatCommand::Spawn => handle_spawn,
ChatCommand::Sudo => handle_sudo,
ChatCommand::Tell => handle_tell,
@ -2714,3 +2715,61 @@ fn cast_buff(kind: &str, data: BuffData, server: &mut Server, target: EcsEntity)
}
fn parse_buffkind(buff: &str) -> Option<BuffKind> { BUFF_PARSER.get(buff).copied() }
fn handle_skill_preset(
server: &mut Server,
_client: EcsEntity,
target: EcsEntity,
args: String,
action: &ChatCommand,
) -> CmdResult<()> {
if let Some(preset) = scan_fmt_some!(&args, &action.arg_fmt(), String) {
if let Some(mut skill_set) = server
.state
.ecs_mut()
.write_storage::<comp::SkillSet>()
.get_mut(target)
{
match preset.as_str() {
"clear" => {
clear_skillset(&mut skill_set);
Ok(())
},
preset => set_skills(&mut skill_set, preset),
}
} else {
Err("Player has no stats!".into())
}
} else {
Err(action.help_string())
}
}
fn clear_skillset(skill_set: &mut comp::SkillSet) { *skill_set = comp::SkillSet::default(); }
fn set_skills(skill_set: &mut comp::SkillSet, preset: &str) -> CmdResult<()> {
let presets =
if let Ok(presets) = common::cmd::SkillPresetManifest::load("server.manifests.presets") {
presets.read().0.clone()
} else {
return Err("Error while loading presets".to_owned());
};
if let Some(preset) = presets.get(preset) {
for (skill, level) in preset {
let group = if let Some(group) = skill.skill_group_kind() {
group
} else {
warn!("Skill in preset doesn't exist in any group");
return Err("Preset is broken".to_owned());
};
for _ in 0..*level {
let cost = skill_set.skill_cost(*skill);
skill_set.add_skill_points(group, cost);
skill_set.unlock_skill(*skill);
}
}
Ok(())
} else {
Err("Such preset doesn't exist".to_owned())
}
}