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 4f552a736e
commit 83fdc8806d
6 changed files with 61 additions and 11 deletions

2
Cargo.lock generated
View File

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

View File

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

View File

@ -1,11 +1,12 @@
use crate::{
comp::{
inventory::{item::{armor::Protection, tool::ToolKind, ItemKind}, slot::EquipSlot},
BuffKind, HealthChange, HealthSource, Inventory,
Body, BuffKind, Health, HealthChange, HealthSource, Inventory,
},
uid::Uid,
util::Dir,
};
use inline_tweak::*;
use serde::{Deserialize, Serialize};
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)]
pub fn base_exp(&self) -> u32 {
match self {

View File

@ -49,6 +49,7 @@ diesel_migrations = "1.4.0"
dotenv = "0.15.0"
slab = "0.4"
const-tweaker = {version = "0.3.1", optional = true}
inline_tweak = "1.0.2"
# Plugins
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 comp::item::Reagent;
use hashbrown::HashSet;
use inline_tweak::*;
use rand::prelude::*;
use specs::{join::Join, saveload::MarkerAllocator, Entity as EcsEntity, WorldExt};
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 healths = state.ecs().read_storage::<Health>();
let inventories = state.ecs().read_storage::<Inventory>();
let by = if let HealthSource::Damage { by: Some(by), .. } = cause {
by
} else {
@ -172,13 +174,14 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
} else {
return;
};
let (entity_stats, entity_health) = if let (Some(entity_stats), Some(entity_health)) =
(stats.get(entity), healths.get(entity))
{
(entity_stats, entity_health)
} else {
return;
};
let (entity_stats, entity_health, entity_inventory) =
if let (Some(entity_stats), Some(entity_health), Some(entity_inventory)) =
(stats.get(entity), healths.get(entity), inventories.get(entity))
{
(entity_stats, entity_health, entity_inventory)
} else {
return;
};
let groups = state.ecs().read_storage::<Group>();
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;
// TODO: Scale xp from skillset rather than health, when NPCs have their own
// skillsets
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);
/*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); */
let mut exp_reward =
combat::combat_rating(entity_inventory, entity_health, &entity_stats.body_type)
* tweak!(2.5);
// Distribute EXP to group
let positions = state.ecs().read_storage::<Pos>();