Added function to automatically generate a combat rating. Currently, it is used to calculate exp.

This commit is contained in:
Sam 2021-01-07 00:23:24 -05:00
parent 933a413879
commit d904e20ffa
6 changed files with 61 additions and 11 deletions

2
Cargo.lock generated
View File

@ -5995,6 +5995,7 @@ dependencies = [
"hashbrown 0.9.1", "hashbrown 0.9.1",
"image", "image",
"indexmap", "indexmap",
"inline_tweak",
"lazy_static", "lazy_static",
"num-derive", "num-derive",
"num-traits 0.2.14", "num-traits 0.2.14",
@ -6099,6 +6100,7 @@ dependencies = [
"futures-timer 3.0.2", "futures-timer 3.0.2",
"futures-util", "futures-util",
"hashbrown 0.9.1", "hashbrown 0.9.1",
"inline_tweak",
"itertools", "itertools",
"lazy_static", "lazy_static",
"libsqlite3-sys", "libsqlite3-sys",

View File

@ -28,6 +28,7 @@ spin_sleep = "1.0"
tracing = { version = "0.1", default-features = false } tracing = { version = "0.1", default-features = false }
vek = { version = "0.12.0", features = ["serde"] } vek = { version = "0.12.0", features = ["serde"] }
uuid = { version = "0.8.1", default-features = false, features = ["serde", "v4"] } uuid = { version = "0.8.1", default-features = false, features = ["serde", "v4"] }
inline_tweak = "1.0.2"
# Assets # Assets
assets_manager = {version = "0.4.2", features = ["bincode", "ron", "json", "hot-reloading"]} assets_manager = {version = "0.4.2", features = ["bincode", "ron", "json", "hot-reloading"]}

View File

@ -1,11 +1,12 @@
use crate::{ use crate::{
comp::{ comp::{
inventory::{item::{armor::Protection, tool::ToolKind, ItemKind}, slot::EquipSlot}, inventory::{item::{armor::Protection, tool::ToolKind, ItemKind}, slot::EquipSlot},
BuffKind, HealthChange, HealthSource, Inventory, Body, BuffKind, Health, HealthChange, HealthSource, Inventory,
}, },
uid::Uid, uid::Uid,
util::Dir, util::Dir,
}; };
use inline_tweak::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use vek::*; use vek::*;
@ -224,4 +225,37 @@ pub fn get_weapons(inv: &Inventory) -> (Option<ToolKind>, Option<ToolKind>) {
}), }),
) )
} }
pub fn get_weapon_damage(inv: &Inventory) -> f32 {
let active_power = inv.equipped(EquipSlot::Mainhand).map_or(0.0, |i| {
if let ItemKind::Tool(tool) = &i.kind() {
tool.base_power() * tool.base_speed()
} else {
0.0
}
});
let second_power = inv.equipped(EquipSlot::Offhand).map_or(0.0, |i| {
if let ItemKind::Tool(tool) = &i.kind() {
tool.base_power() * tool.base_speed()
} else {
0.0
}
});
active_power.max(second_power).max(0.1)
}
pub fn combat_rating(inventory: &Inventory, health: &Health, body: &Body) -> f32 {
let defensive_weighting = tweak!(1.0);
let offensive_weighting = tweak!(1.0);
let defensive_rating = health.maximum() as f32 / (1.0 - Damage::compute_damage_reduction(inventory)) / 100.0;
let offensive_rating = get_weapon_damage(inventory);
//let combined_rating = 2.0 / ((1.0 / offensive_rating) + (1.0 /
// defensive_rating)); let combined_rating = offensive_rating *
// defensive_rating / (offensive_rating + defensive_rating);
let combined_rating = (offensive_rating * offensive_weighting
+ defensive_rating * defensive_weighting)
/ (2.0 * offensive_weighting.max(defensive_weighting));
combined_rating * body.combat_multiplier()
}

View File

@ -425,6 +425,11 @@ impl Body {
} }
} }
/// Returns a multiplier representing increased difficulty not accounted for
/// due to AI or not using an actual weapon
// TODO: Match on species
pub fn combat_multiplier(&self) -> f32 { 1.0 }
#[allow(unreachable_patterns)] #[allow(unreachable_patterns)]
pub fn base_exp(&self) -> u32 { pub fn base_exp(&self) -> u32 {
match self { match self {

View File

@ -49,6 +49,7 @@ diesel_migrations = "1.4.0"
dotenv = "0.15.0" dotenv = "0.15.0"
slab = "0.4" slab = "0.4"
const-tweaker = {version = "0.3.1", optional = true} const-tweaker = {version = "0.3.1", optional = true}
inline_tweak = "1.0.2"
# Plugins # Plugins
plugin-api = { package = "veloren-plugin-api", path = "../plugin/api"} plugin-api = { package = "veloren-plugin-api", path = "../plugin/api"}

View File

@ -29,6 +29,7 @@ use common_net::{msg::ServerGeneral, sync::WorldSyncExt};
use common_sys::state::BlockChange; use common_sys::state::BlockChange;
use comp::item::Reagent; use comp::item::Reagent;
use hashbrown::HashSet; use hashbrown::HashSet;
use inline_tweak::*;
use rand::prelude::*; use rand::prelude::*;
use specs::{join::Join, saveload::MarkerAllocator, Entity as EcsEntity, WorldExt}; use specs::{join::Join, saveload::MarkerAllocator, Entity as EcsEntity, WorldExt};
use tracing::error; use tracing::error;
@ -162,6 +163,7 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
(|| { (|| {
let mut stats = state.ecs().write_storage::<Stats>(); let mut stats = state.ecs().write_storage::<Stats>();
let healths = state.ecs().read_storage::<Health>(); let healths = state.ecs().read_storage::<Health>();
let inventories = state.ecs().read_storage::<Inventory>();
let by = if let HealthSource::Damage { by: Some(by), .. } = cause { let by = if let HealthSource::Damage { by: Some(by), .. } = cause {
by by
} else { } else {
@ -172,13 +174,14 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
} else { } else {
return; return;
}; };
let (entity_stats, entity_health) = if let (Some(entity_stats), Some(entity_health)) = let (entity_stats, entity_health, entity_inventory) =
(stats.get(entity), healths.get(entity)) if let (Some(entity_stats), Some(entity_health), Some(entity_inventory)) =
{ (stats.get(entity), healths.get(entity), inventories.get(entity))
(entity_stats, entity_health) {
} else { (entity_stats, entity_health, entity_inventory)
return; } else {
}; return;
};
let groups = state.ecs().read_storage::<Group>(); let groups = state.ecs().read_storage::<Group>();
let attacker_group = groups.get(attacker); let attacker_group = groups.get(attacker);
@ -194,8 +197,12 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
const ATTACKER_EXP_WEIGHT: f32 = 1.0; const ATTACKER_EXP_WEIGHT: f32 = 1.0;
// TODO: Scale xp from skillset rather than health, when NPCs have their own // TODO: Scale xp from skillset rather than health, when NPCs have their own
// skillsets // skillsets
let mut exp_reward = entity_stats.body_type.base_exp() as f32 /*let mut exp_reward = entity_stats.body_type.base_exp() as f32
* (entity_health.maximum() as f32 / entity_stats.body_type.base_health() as f32); * (entity_health.maximum() as f32 / entity_stats.body_type.base_health() as
* f32); */
let mut exp_reward =
combat::combat_rating(entity_inventory, entity_health, &entity_stats.body_type)
* tweak!(2.5);
// Distribute EXP to group // Distribute EXP to group
let positions = state.ecs().read_storage::<Pos>(); let positions = state.ecs().read_storage::<Pos>();