Health, energy, mass, and density to RON

This commit is contained in:
James Melkonian 2021-05-19 20:45:07 -07:00
parent 8702a5eb9a
commit 110085eacf
23 changed files with 1784 additions and 475 deletions

View File

@ -0,0 +1,204 @@
(
humanoid: (
body: 0.8,
species: (
danari: Some(0.9),
dwarf: Some(0.8),
elf: Some(0.7),
human: Some(0.6),
orc: Some(0.9),
undead: Some(0.9),
)
),
quadruped_medium: (
body: 0.6,
species: (
grolgar: Some(0.8),
saber: Some(0.8),
tuskram: Some(0.7),
lion: Some(0.8),
tarasque: Some(0.8),
tiger: Some(0.8),
wolf: Some(0.8),
frostfang: Some(0.9),
mouflon: Some(0.7),
catoblepas: Some(0.8),
bonerattler: Some(0.8),
deer: Some(0.6),
hirdrasil: Some(0.7),
roshwalr: Some(0.8),
donkey: Some(0.7),
camel: Some(0.7),
zebra: Some(0.7),
antelope: Some(0.6),
kelpie: Some(0.7),
horse: Some(0.7),
barghest: Some(0.5),
cattle: Some(0.7),
darkhound: Some(0.9),
highland: Some(0.7),
yak: Some(0.7),
panda: Some(0.7),
bear: Some(0.9),
dreadhorn: Some(0.8),
moose: Some(0.8),
snowleopard: Some(0.9),
)
),
quadruped_small: (
body: 0.0,
species: (
pig: Some(0.5),
fox: Some(0.3),
sheep: Some(0.5),
boar: Some(0.8),
jackalope: Some(0.4),
skunk: Some(0.6),
cat: Some(0.2),
batfox: Some(0.6),
raccoon: Some(0.4),
quokka: Some(0.4),
dodarock: Some(0.9),
holladon: Some(1.0),
hyena: Some(0.4),
rabbit: Some(0.1),
truffler: Some(0.8),
frog: Some(0.4),
rat: Some(0.0),
axolotl: Some(0.0),
gecko: Some(0.0),
turtle: Some(0.8),
squirrel: Some(0.1),
fungome: Some(0.0),
porcupine: Some(0.4),
beaver: Some(0.5),
hare: Some(0.3),
dog: Some(0.5),
goat: Some(0.5),
)
),
bird_medium: (
body: 0.8,
species: (
duck: Some(0.8),
chicken: Some(0.8),
goose: Some(0.8),
peacock: Some(0.8),
eagle: Some(0.8),
owl: Some(0.8),
parrot: Some(0.8),
)
),
biped_large: (
body: 1.0,
species: (
ogre: Some(1.0),
cyclops: Some(1.0),
wendigo: Some(1.0),
troll: Some(1.0),
dullahan: Some(1.0),
werewolf: Some(1.0),
saurok_occult: Some(1.0),
saurok_mighty: Some(1.0),
saurok_sly: Some(1.0),
mindflayer: Some(1.0),
minotaur: Some(1.0),
tidalwarrior: Some(1.0),
yeti: Some(1.0),
harvester: Some(1.0),
oni_blue: Some(1.0),
oni_red: Some(1.0),
)
),
golem: (
body: 1.0,
species: (
stonegolem: Some(1.0),
treant: Some(1.0),
claygolem: Some(1.0),
)
),
theropod: (
body: 1.0,
species: (
archaeos: Some(1.0),
odonto: Some(1.0),
raptor_sand: Some(1.0),
raptor_snow: Some(1.0),
raptor_wood: Some(1.0),
sunlizard: Some(1.0),
yale: Some(1.0),
ntouka: Some(1.0),
)
),
dragon: (
body: 1.0,
species: (
reddragon: Some(1.0),
)
),
object: (
body: 1.0,
species: ()
),
ship: (
body: 1.0,
species: (),
),
biped_small: (
body: 0.5,
species: (
gnome: Some(0.5),
sahagin: Some(0.5),
adlet: Some(0.5),
gnarling: Some(0.5),
mandragora: Some(0.5),
kappa: Some(0.5),
cactid: Some(0.5),
gnoll: Some(0.5),
haniwa: Some(0.5),
myrmidon: Some(0.5),
husk: Some(0.5),
)
),
fish_small: (
body: 0.0,
species: (
clownfish: Some(0.0),
piranha: Some(0.0),
)
),
fish_medium: (
body: 0.15,
species: (
marlin: Some(0.15),
icepike: Some(0.15),
)
),
bird_large: (
body: 0.9,
species: (
phoenix: Some(0.9),
cockatrice: Some(0.9),
)
),
quadruped_low: (
body: 0.6,
species: (
crocodile: Some(0.8),
alligator: Some(0.8),
salamander: Some(0.7),
monitor: Some(0.7),
asp: Some(0.9),
tortoise: Some(0.6),
rocksnapper: Some(0.8),
pangolin: Some(0.4),
maneater: Some(0.8),
sandshark: Some(0.9),
hakulaq: Some(0.9),
lavadrake: Some(0.9),
basilisk: Some(0.8),
deadwood: Some(0.6),
)
)
)

View File

@ -0,0 +1,67 @@
(
humanoid: (
body: 750,
species: (),
),
quadruped_medium: (
body: 1000,
species: (),
),
quadruped_small: (
body: 1000,
species: (),
),
bird_medium: (
body: 1000,
species: (),
),
biped_large: (
body: 3000,
species: (
dullahan: Some(4000),
)
),
golem: (
body: 1000,
species: (),
),
theropod: (
body: 1000,
species: (),
),
dragon: (
body: 1000,
species: (),
),
object: (
body: 1000,
species: ()
),
ship: (
body: 1000,
species: (),
),
biped_small: (
body: 1000,
species: (),
),
fish_small: (
body: 1000,
species: (),
),
fish_medium: (
body: 1000,
species: (),
),
bird_large: (
body: 3000,
species: (
phoenix: Some(6000),
cockatrice: Some(4000),
)
),
quadruped_low: (
body: 1000,
species: (),
)
)

View File

@ -0,0 +1,142 @@
(
humanoid: (
body: 500,
species: (),
),
quadruped_medium: (
body: 700,
species: (
grolgar: Some(900),
saber: Some(600),
tuskram: Some(900),
lion: Some(900),
tarasque: Some(1500),
tiger: Some(700),
wolf: Some(550),
frostfang: Some(400),
mouflon: Some(500),
catoblepas: Some(1000),
bonerattler: Some(500),
deer: Some(500),
roshwalr: Some(800),
donkey: Some(550),
zebra: Some(550),
antelope: Some(450),
kelpie: Some(600),
horse: Some(600),
barghest: Some(1700),
cattle: Some(1000),
highland: Some(1200),
yak: Some(1100),
panda: Some(900),
bear: Some(900),
moose: Some(800),
dreadhorn: Some(1100),
snowleopard: Some(900),
)
),
quadruped_small: (
body: 400,
species: (
boar: Some(700),
batfox: Some(400),
dodarock: Some(1000),
holladon: Some(800),
hyena: Some(450),
truffler: Some(450),
)
),
bird_medium: (
body: 250,
species: (
chicken: Some(300),
duck: Some(300),
goose: Some(300),
peacock: Some(350),
eagle: Some(450),
)
),
biped_large: (
body: 1200,
species: (
ogre: Some(3200),
cyclops: Some(3200),
wendigo: Some(2800),
troll: Some(2400),
dullahan: Some(3000),
mindflayer: Some(12500),
minotaur: Some(30000),
tidalwarrior: Some(2500),
yeti: Some(4000),
harvester: Some(3000),
oni_blue: Some(2400),
oni_red: Some(2400),
)
),
golem: (
body: 10000,
species: (
claygolem: Some(7500),
)
),
theropod: (
body: 1100,
species: (
archaeos: Some(3500),
odonto: Some(3000),
)
),
dragon: (
body: 5000,
species: (),
),
object: (
body: 10000,
species: (),
),
ship: (
body: 10000,
species: (),
),
biped_small: (
body: 600,
species: (
gnarling: Some(500),
adlet: Some(600),
sahagin: Some(800),
haniwa: Some(900),
myrmidon: Some(900),
husk: Some(200),
)
),
fish_small: (
body: 20,
species: (),
),
fish_medium: (
body: 250,
species: (),
),
bird_large: (
body: 3000,
species: (),
),
quadruped_low: (
body: 700,
species: (
crocodile: Some(900),
alligator: Some(800),
monitor: Some(600),
asp: Some(750),
tortoise: Some(900),
rocksnapper: Some(1200),
pangolin: Some(400),
maneater: Some(700),
sandshark: Some(900),
hakulaq: Some(500),
lavadrake: Some(1000),
basilisk: Some(1000),
deadwood: Some(700),
)
)
)

View File

@ -0,0 +1,114 @@
(
humanoid: (
body: 50,
species: (),
),
quadruped_medium: (
body: 20,
species: (
grolgar: Some(30),
tuskram: Some(30),
lion: Some(40),
tarasque: Some(60),
wolf: Some(20),
frostfang: Some(40),
mouflon: Some(30),
catoblepas: Some(50),
bonerattler: Some(30),
hirdrasil: Some(30),
roshwalr: Some(40),
donkey: Some(30),
camel: Some(30),
zebra: Some(30),
kelpie: Some(30),
horse: Some(30),
barghest: Some(50),
cattle: Some(30),
highland: Some(30),
yak: Some(30),
panda: Some(40),
bear: Some(40),
moose: Some(30),
dreadhorn: Some(50),
)
),
quadruped_small: (
body: 10,
species: (
boar: Some(20),
dodarock: Some(30),
holladon: Some(30),
hyena: Some(20),
truffler: Some(20),
)
),
bird_medium: (
body: 10,
species: (),
),
biped_large: (
body: 100,
species: (
ogre: Some(70),
cyclops: Some(80),
wendigo: Some(80),
troll: Some(60),
dullahan: Some(120),
tidalwarrior: Some(90),
yeti: Some(80),
harvester: Some(80),
// Boss enemies have their health set,
// not adjusted by level.
)
),
golem: (
body: 0,
species: (),
),
theropod: (
body: 20,
species: (),
),
dragon: (
body: 500,
species: (),
),
object: (
body: 10,
species: (),
),
ship: (
body: 10,
species: (),
),
biped_small: (
body: 10,
species: (),
),
fish_small: (
body: 10,
species: (),
),
fish_medium: (
body: 10,
species: (),
),
bird_large: (
body: 120,
species: (),
),
quadruped_low: (
body: 20,
species: (
salamander: Some(10),
monitor: Some(10),
asp: Some(10),
rocksnapper: Some(50),
pangolin: Some(10),
maneater: Some(30),
sandshark: Some(40),
hakulaq: Some(10),
deadwood: Some(30),
)
)
)

View File

@ -0,0 +1,62 @@
(
humanoid: (
body: 990.0,
species: (),
),
quadruped_medium: (
body: 990.0,
species: (),
),
quadruped_small: (
body: 990.0,
species: (),
),
biped_large: (
body: 990.0,
species: (),
),
golem: (
body: 2500.0,
species: (),
),
theropod: (
body: 990.0,
species: (),
),
dragon: (
body: 3700.0,
species: (),
),
object: (
body: 990.0,
species: ()
),
ship: (
body: 990.0,
species: (),
),
biped_small: (
body: 990.0,
species: (),
),
fish_small: (
body: 999.1,
species: (),
),
fish_medium: (
body: 999.1,
species: (),
),
bird_medium: (
body: 700.0,
species: (),
),
bird_large: (
body: 990.0,
species: (),
),
quadruped_low: (
body: 990.0,
species: (),
)
)

109
assets/common/body/mass.ron Normal file
View File

@ -0,0 +1,109 @@
(
humanoid: (
body: 77.0,
species: (
danari: Some(60.0),
dwarf: Some(80.0),
elf: Some(77.0),
human: Some(77.0),
orc: Some(95.0),
undead: Some(65.0),
)
),
quadruped_medium: (
body: 200.0,
species: (
saber: Some(130.0),
lion: Some(170.0),
deer: Some(80.0),
antelope: Some(120.0),
kelpie: Some(300.0),
horse: Some(300.0),
cattle: Some(575.0),
highland: Some(600.0),
yak: Some(600.0),
bear: Some(500.0),
moose: Some(500.0),
)
),
quadruped_small: (
body: 80.0,
species: (
boar: Some(80.0),
batfox: Some(50.0),
dodarock: Some(150.0),
holladon: Some(100.0),
hyena: Some(70.0),
truffler: Some(150.0),
)
),
biped_large: (
body: 400.0,
species: (
mindflayer: Some(420.0),
minotaur: Some(500.0),
)
),
golem: (
body: 1000.0,
species: (),
),
theropod: (
body: 1000.0,
species: (
archaeos: Some(10000.0),
ntouka: Some(5000.0),
odonto: Some(10000.0),
raptor_sand: Some(500.0),
raptor_snow: Some(500.0),
raptor_wood: Some(500.0),
sunlizard: Some(500.0),
)
),
dragon: (
body: 2000.0,
species: (),
),
object: (
body: 1.0,
species: ()
),
ship: (
body: 1.0,
species: (),
),
biped_small: (
body: 50.0,
species: (),
),
fish_small: (
body: 1.0,
species: (),
),
fish_medium: (
body: 2.5,
species: (),
),
bird_medium: (
body: 2.0,
species: (),
),
bird_large: (
body: 200.0,
species: (),
),
quadruped_low: (
body: 200.0,
species: (
crocodile: Some(360.0),
alligator: Some(360.0),
monitor: Some(100.0),
asp: Some(300.0),
tortoise: Some(200.0),
rocksnapper: Some(300.0),
pangolin: Some(60.0),
lavadrake: Some(500.0),
deadwood: Some(50.0),
)
)
)

View File

@ -0,0 +1,492 @@
(
humanoid: (
body: (
aggro: 0.8,
),
species: (
danari: (
aggro: 0.9,
),
dwarf: (
aggro: 0.8,
),
elf: (
aggro: 0.7,
),
human: (
aggro: 0.6,
),
orc: (
aggro: 0.9,
),
undead: (
aggro: 0.9,
)
)
),
quadruped_medium: (
body: (
aggro: 0.8,
),
species: (
grolgar: (
aggro: 0.8,
),
saber: (
aggro: 0.8,
),
tuskram: (
aggro: 0.7,
),
lion: (
aggro: 0.8,
),
tarasque: (
aggro: 0.8,
),
tiger: (
aggro: 0.8,
),
wolf: (
aggro: 0.8,
),
frostfang: (
aggro: 0.9,
),
mouflon: (
aggro: 0.7,
),
catoblepas: (
aggro: 0.8,
),
bonerattler: (
aggro: 0.8,
),
deer: (
aggro: 0.6,
),
hirdrasil: (
aggro: 0.7,
),
roshwalr: (
aggro: 0.8,
),
donkey: (
aggro: 0.7,
),
camel: (
aggro: 0.7,
),
zebra: (
aggro: 0.7,
),
antelope: (
aggro: 0.6,
),
kelpie: (
aggro: 0.7,
),
horse: (
aggro: 0.7,
),
barghest: (
aggro: 0.5,
),
cattle: (
aggro: 0.7,
),
darkhound: (
aggro: 0.9,
),
highland: (
aggro: 0.7,
),
yak: (
aggro: 0.7,
),
panda: (
aggro: 0.7,
),
bear: (
aggro: 0.9,
),
dreadhorn: (
aggro: 0.8,
),
moose: (
aggro: 0.8,
),
snowleopard: (
aggro: 0.9,
)
)
),
quadruped_small: (
body: (
aggro: 0.8,
),
species: (
pig: (
aggro: 0.5,
),
fox: (
aggro: 0.3,
),
sheep: (
aggro: 0.5,
),
boar: (
aggro: 0.8,
),
jackalope: (
aggro: 0.4,
),
skunk: (
aggro: 0.6,
),
cat: (
aggro: 0.2,
),
batfox: (
aggro: 0.6,
),
raccoon: (
aggro: 0.4,
),
quokka: (
aggro: 0.4,
),
dodarock: (
aggro: 0.9,
),
holladon: (
aggro: 1.0,
),
hyena: (
aggro: 0.4,
),
rabbit: (
aggro: 0.1,
),
truffler: (
aggro: 0.8,
),
frog: (
aggro: 0.4,
),
rat: (
aggro: 0.0,
),
axolotl: (
aggro: 0.0,
),
gecko: (
aggro: 0.0,
),
turtle: (
aggro: 0.8,
),
squirrel: (
aggro: 0.1,
),
fungome: (
aggro: 0.0,
),
porcupine: (
aggro: 0.4,
),
beaver: (
aggro: 0.5,
),
hare: (
aggro: 0.3,
),
dog: (
aggro: 0.5,
),
goat: (
aggro: 0.5,
)
)
),
bird_medium: (
body: (
aggro: 0.8,
),
species: (
duck: (
aggro: 0.8,
),
chicken: (
aggro: 0.8,
),
goose: (
aggro: 0.8,
),
peacock: (
aggro: 0.8,
),
eagle: (
aggro: 0.8,
),
owl: (
aggro: 0.8,
),
parrot: (
aggro: 0.8,
),
)
),
biped_large: (
body: (
aggro: 1.0,
),
species: (
ogre: (
aggro: 1.0,
),
cyclops: (
aggro: 1.0,
),
wendigo: (
aggro: 1.0,
),
troll: (
aggro: 1.0,
),
dullahan: (
aggro: 1.0,
),
werewolf: (
aggro: 1.0,
),
saurok_occult: (
aggro: 1.0,
),
saurok_mighty: (
aggro: 1.0,
),
saurok_sly: (
aggro: 1.0,
),
mindflayer: (
aggro: 1.0,
),
minotaur: (
aggro: 1.0,
),
tidalwarrior: (
aggro: 1.0,
),
yeti: (
aggro: 1.0,
),
harvester: (
aggro: 1.0,
),
oni_blue: (
aggro: 1.0,
),
oni_red: (
aggro: 1.0,
),
)
),
golem: (
body: (
aggro: 1.0,
),
species: (
stonegolem: (
aggro: 1.0,
),
treant: (
aggro: 1.0,
),
claygolem: (
aggro: 1.0,
)
)
),
theropod: (
body: (
aggro: 1.0,
),
species: (
archaeos: (
aggro: 1.0,
),
odonto: (
aggro: 1.0,
),
raptor_sand: (
aggro: 1.0,
),
raptor_snow: (
aggro: 1.0,
),
raptor_wood: (
aggro: 1.0,
),
sunlizard: (
aggro: 1.0,
),
yale: (
aggro: 1.0,
),
ntouka: (
aggro: 1.0,
)
)
),
dragon: (
body: (
aggro: 1.0,
),
species: (
reddragon: (
aggro: 1.0,
)
)
),
object: (
body: (
aggro: 1.0,
),
species: ()
),
ship: (
body: (
aggro: 1.0,
),
species: (),
),
biped_small: (
body: (
aggro: 0.5,
),
species: (
gnome: (
aggro: 0.5,
),
sahagin: (
aggro: 0.5,
),
adlet: (
aggro: 0.5,
),
gnarling: (
aggro: 0.5,
),
mandragora: (
aggro: 0.5,
),
kappa: (
aggro: 0.5,
),
cactid: (
aggro: 0.5,
),
gnoll: (
aggro: 0.5,
),
haniwa: (
aggro: 0.5,
),
myrmidon: (
aggro: 0.5,
),
husk: (
aggro: 0.5,
)
)
),
fish_small: (
body: (
aggro: 0.0,
),
species: (
clownfish: (
aggro: 0.0,
),
piranha: (
aggro: 0.0,
)
)
),
fish_medium: (
body: (
aggro: 0.15,
),
species: (
marlin: (
aggro: 0.15,
),
icepike: (
aggro: 0.15,
)
)
),
bird_large: (
body: (
aggro: 0.9,
),
species: (
phoenix: (
aggro: 0.9,
),
cockatrice: (
aggro: 0.9,
),
)
),
quadruped_low: (
body: (
aggro: 0.8,
),
species: (
crocodile: (
aggro: 0.8,
),
alligator: (
aggro: 0.8,
),
salamander: (
aggro: 0.7,
),
monitor: (
aggro: 0.7,
),
asp: (
aggro: 0.9,
),
tortoise: (
aggro: 0.6,
),
rocksnapper: (
aggro: 0.8,
),
pangolin: (
aggro: 0.4,
),
maneater: (
aggro: 0.8,
),
sandshark: (
aggro: 0.9,
),
hakulaq: (
aggro: 0.9,
),
lavadrake: (
aggro: 0.9,
),
basilisk: (
aggro: 0.8,
),
deadwood: (
aggro: 0.6,
),
)
)
)

View File

@ -1,5 +1,4 @@
use crate::{ use crate::{
comp::{humanoid, quadruped_low, quadruped_medium, quadruped_small, Body},
path::Chaser, path::Chaser,
rtsim::RtSimController, rtsim::RtSimController,
trade::{PendingTrade, ReducedInventory, SiteId, SitePrices, TradeId, TradeResult}, trade::{PendingTrade, ReducedInventory, SiteId, SitePrices, TradeId, TradeResult},
@ -163,80 +162,6 @@ pub struct Psyche {
pub aggro: f32, // 0.0 = always flees, 1.0 = always attacks, 0.5 = flee at 50% health pub aggro: f32, // 0.0 = always flees, 1.0 = always attacks, 0.5 = flee at 50% health
} }
impl<'a> From<&'a Body> for Psyche {
fn from(body: &'a Body) -> Self {
Self {
aggro: match body {
Body::Humanoid(humanoid) => match humanoid.species {
humanoid::Species::Danari => 0.9,
humanoid::Species::Dwarf => 0.8,
humanoid::Species::Elf => 0.7,
humanoid::Species::Human => 0.6,
humanoid::Species::Orc => 0.9,
humanoid::Species::Undead => 0.9,
},
Body::QuadrupedSmall(quadruped_small) => match quadruped_small.species {
quadruped_small::Species::Pig => 0.5,
quadruped_small::Species::Fox => 0.3,
quadruped_small::Species::Sheep => 0.5,
quadruped_small::Species::Boar => 0.8,
quadruped_small::Species::Jackalope => 0.4,
quadruped_small::Species::Skunk => 0.6,
quadruped_small::Species::Cat => 0.2,
quadruped_small::Species::Batfox => 0.6,
quadruped_small::Species::Raccoon => 0.4,
quadruped_small::Species::Quokka => 0.4,
quadruped_small::Species::Dodarock => 0.9,
quadruped_small::Species::Holladon => 1.0,
quadruped_small::Species::Hyena => 0.4,
quadruped_small::Species::Rabbit => 0.1,
quadruped_small::Species::Truffler => 0.8,
quadruped_small::Species::Frog => 0.4,
quadruped_small::Species::Hare => 0.2,
quadruped_small::Species::Goat => 0.5,
_ => 0.0,
},
Body::QuadrupedMedium(quadruped_medium) => match quadruped_medium.species {
quadruped_medium::Species::Tuskram => 0.7,
quadruped_medium::Species::Frostfang => 0.9,
quadruped_medium::Species::Mouflon => 0.7,
quadruped_medium::Species::Catoblepas => 0.8,
quadruped_medium::Species::Deer => 0.6,
quadruped_medium::Species::Hirdrasil => 0.7,
quadruped_medium::Species::Donkey => 0.7,
quadruped_medium::Species::Camel => 0.7,
quadruped_medium::Species::Zebra => 0.7,
quadruped_medium::Species::Antelope => 0.6,
quadruped_medium::Species::Horse => 0.7,
quadruped_medium::Species::Cattle => 0.7,
quadruped_medium::Species::Darkhound => 0.9,
quadruped_medium::Species::Dreadhorn => 0.8,
quadruped_medium::Species::Snowleopard => 0.7,
_ => 0.5,
},
Body::QuadrupedLow(quadruped_low) => match quadruped_low.species {
quadruped_low::Species::Salamander => 0.7,
quadruped_low::Species::Monitor => 0.7,
quadruped_low::Species::Asp => 0.9,
quadruped_low::Species::Pangolin => 0.4,
_ => 0.6,
},
Body::BipedSmall(_) => 0.5,
Body::BirdMedium(_) => 0.5,
Body::BirdLarge(_) => 0.9,
Body::FishMedium(_) => 0.15,
Body::FishSmall(_) => 0.0,
Body::BipedLarge(_) => 1.0,
Body::Object(_) => 1.0,
Body::Golem(_) => 1.0,
Body::Theropod(_) => 1.0,
Body::Dragon(_) => 1.0,
Body::Ship(_) => 1.0,
},
}
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
/// Events that affect agent behavior from other entities/players/environment /// Events that affect agent behavior from other entities/players/environment
pub enum AgentEvent { pub enum AgentEvent {
@ -338,16 +263,16 @@ impl Agent {
pub fn new( pub fn new(
patrol_origin: Option<Vec3<f32>>, patrol_origin: Option<Vec3<f32>>,
body: &Body,
behavior: Behavior, behavior: Behavior,
no_flee: bool, no_flee: bool,
aggro: f32,
) -> Self { ) -> Self {
Agent { Agent {
patrol_origin, patrol_origin,
psyche: if no_flee { psyche: if no_flee {
Psyche { aggro: 1.0 } Psyche { aggro: 1.0 }
} else { } else {
Psyche::from(body) Psyche { aggro }
}, },
behavior, behavior,
..Default::default() ..Default::default()

View File

@ -16,7 +16,6 @@ pub mod theropod;
use crate::{ use crate::{
assets::{self, Asset}, assets::{self, Asset},
consts::{HUMAN_DENSITY, WATER_DENSITY},
make_case_elim, make_case_elim,
npc::NpcKind, npc::NpcKind,
}; };
@ -146,126 +145,205 @@ impl<
const EXTENSION: &'static str = "ron"; const EXTENSION: &'static str = "ron";
} }
pub type BodyAggro = f32;
pub type SpeciesAggro = Option<f32>;
/// Type holding aggro data for bodies and species.
pub type AllBodiesAggro = AllBodies<BodyAggro, SpeciesAggro>;
pub type BodyDensity = f32;
pub type SpeciesDensity = Option<f32>;
/// Type holding density data for bodies and species.
pub type AllBodiesDensity = AllBodies<BodyDensity, SpeciesDensity>;
pub type BodyMass = f32;
pub type SpeciesMass = Option<f32>;
/// Type holding mass data for bodies and species.
pub type AllBodiesMass = AllBodies<BodyMass, SpeciesMass>;
pub type BodyBaseEnergy = u32;
pub type SpeciesBaseEnergy = Option<u32>;
/// Type holding mass data for bodies and species.
pub type AllBodiesBaseEnergy = AllBodies<BodyBaseEnergy, SpeciesBaseEnergy>;
pub type BodyBaseHealth = u32;
pub type SpeciesBaseHealth = Option<u32>;
/// Type holding mass data for bodies and species.
pub type AllBodiesBaseHealth = AllBodies<BodyBaseHealth, SpeciesBaseHealth>;
pub type BodyBaseHealthIncrease = u32;
pub type SpeciesBaseHealthIncrease = Option<u32>;
/// Type holding mass data for bodies and species.
pub type AllBodiesBaseHealthIncrease = AllBodies<BodyBaseHealthIncrease, SpeciesBaseHealthIncrease>;
#[derive(Clone, Debug, Default, Deserialize)]
pub struct BodyAttributes {
pub aggro: Option<AllBodiesAggro>,
pub density: Option<AllBodiesDensity>,
pub mass: Option<AllBodiesMass>,
pub base_energy: Option<AllBodiesBaseEnergy>,
pub base_health: Option<AllBodiesBaseHealth>,
pub base_health_increase: Option<AllBodiesBaseHealthIncrease>,
}
impl assets::Compound for BodyAttributes {
fn load<S: assets::source::Source>(
cache: &assets::AssetCache<S>,
_: &str,
) -> Result<Self, assets::Error> {
let aggro = cache.load_owned::<AllBodiesAggro>("common.body.aggro")?;
let density = cache.load_owned::<AllBodiesDensity>("common.body.density")?;
let mass = cache.load_owned::<AllBodiesMass>("common.body.mass")?;
let energy = cache.load_owned::<AllBodiesBaseEnergy>("common.body.base_energy")?;
let health = cache.load_owned::<AllBodiesBaseHealth>("common.body.base_health")?;
let health_increase =
cache.load_owned::<AllBodiesBaseHealthIncrease>("common.body.base_health_increase")?;
Ok(Self {
aggro: Some(aggro),
density: Some(density),
mass: Some(mass),
base_energy: Some(energy),
base_health: Some(health),
base_health_increase: Some(health_increase),
})
}
}
pub fn get_body_f32_attribute<
'a,
Species,
SpeciesData: for<'b> core::ops::Index<&'b Species, Output = Option<f32>>,
>(
body_data: &'a BodyData<f32, SpeciesData>,
species: Species,
) -> f32 {
body_data.species[&species].unwrap_or_else(|| body_data.body)
}
pub fn get_body_u32_attribute<
'a,
Species,
SpeciesData: for<'b> core::ops::Index<&'b Species, Output = Option<u32>>,
>(
body_data: &'a BodyData<u32, SpeciesData>,
species: Species,
) -> u32 {
body_data.species[&species].unwrap_or_else(|| body_data.body)
}
impl Body { impl Body {
pub fn is_humanoid(&self) -> bool { matches!(self, Body::Humanoid(_)) } pub fn is_humanoid(&self) -> bool { matches!(self, Body::Humanoid(_)) }
/// Average density of the body /// Average density of the body
// Units are based on kg/m³ /// Units are based on kg/m³
pub fn density(&self) -> Density { pub fn density(&self, body_densities: &AllBodiesDensity) -> Density {
let d = match self { let density_value = match self {
// based on a house sparrow (Passer domesticus) Body::BipedLarge(body) => {
Body::BirdMedium(_) => 700.0, get_body_f32_attribute(&body_densities.biped_large, body.species)
Body::BirdLarge(_) => 2_200.0, },
Body::BipedSmall(body) => {
// based on its mass divided by the volume of a bird scaled up to the size of the dragon get_body_f32_attribute(&body_densities.biped_small, body.species)
Body::Dragon(_) => 3_700.0, },
Body::BirdMedium(body) => {
Body::Golem(_) => WATER_DENSITY * 2.5, get_body_f32_attribute(&body_densities.bird_medium, body.species)
Body::Humanoid(_) => HUMAN_DENSITY, },
Body::BirdLarge(body) => {
get_body_f32_attribute(&body_densities.bird_large, body.species)
},
Body::Dragon(body) => get_body_f32_attribute(&body_densities.dragon, body.species),
Body::FishMedium(body) => {
get_body_f32_attribute(&body_densities.fish_medium, body.species)
},
Body::FishSmall(body) => {
get_body_f32_attribute(&body_densities.fish_small, body.species)
},
Body::Golem(body) => get_body_f32_attribute(&body_densities.golem, body.species),
Body::Humanoid(body) => get_body_f32_attribute(&body_densities.humanoid, body.species),
Body::QuadrupedLow(body) => {
get_body_f32_attribute(&body_densities.quadruped_low, body.species)
},
Body::QuadrupedMedium(body) => {
get_body_f32_attribute(&body_densities.quadruped_medium, body.species)
},
Body::QuadrupedSmall(body) => {
get_body_f32_attribute(&body_densities.quadruped_small, body.species)
},
Body::Theropod(body) => get_body_f32_attribute(&body_densities.theropod, body.species),
Body::Ship(ship) => ship.density().0, Body::Ship(ship) => ship.density().0,
Body::Object(object) => object.density().0, Body::Object(object) => object.density().0,
_ => HUMAN_DENSITY,
}; };
Density(d) Density(density_value)
} }
// Values marked with ~✅ are checked based on their RL equivalent. /// Units are kg
// Discrepancy in size compared to their RL equivalents has not necessarily been pub fn mass(&self, body_masses: &AllBodiesMass) -> Mass {
// taken into account.
pub fn mass(&self) -> Mass {
let m = match self { let m = match self {
Body::BipedLarge(body) => match body.species { Body::BipedLarge(body) => {
biped_large::Species::Slysaurok => 400.0, get_body_f32_attribute(&body_masses.biped_large, body.species)
biped_large::Species::Occultsaurok => 400.0,
biped_large::Species::Mightysaurok => 400.0,
biped_large::Species::Mindflayer => 420.0,
biped_large::Species::Minotaur => 500.0,
_ => 400.0,
}, },
Body::BipedSmall(_) => 50.0, Body::BipedSmall(body) => {
get_body_f32_attribute(&body_masses.biped_small, body.species)
// ravens are 0.69-2 kg, crows are 0.51 kg on average
Body::BirdMedium(_) => 1.0,
Body::BirdLarge(_) => 200.0,
Body::Dragon(_) => 20_000.0,
Body::FishMedium(_) => 2.5,
Body::FishSmall(_) => 1.0,
Body::Golem(_) => 10_000.0,
Body::Humanoid(humanoid) => {
// humanoids are quite a bit larger than in real life, so we multiply their mass
// to scale it up proportionally (remember cube law)
1.0 * match (humanoid.species, humanoid.body_type) {
(humanoid::Species::Orc, humanoid::BodyType::Male) => 120.0,
(humanoid::Species::Orc, humanoid::BodyType::Female) => 120.0,
(humanoid::Species::Human, humanoid::BodyType::Male) => 77.0, // ~✅
(humanoid::Species::Human, humanoid::BodyType::Female) => 59.0, // ~✅
(humanoid::Species::Elf, humanoid::BodyType::Male) => 77.0,
(humanoid::Species::Elf, humanoid::BodyType::Female) => 59.0,
(humanoid::Species::Dwarf, humanoid::BodyType::Male) => 70.0,
(humanoid::Species::Dwarf, humanoid::BodyType::Female) => 70.0,
(humanoid::Species::Undead, humanoid::BodyType::Male) => 70.0,
(humanoid::Species::Undead, humanoid::BodyType::Female) => 50.0,
(humanoid::Species::Danari, humanoid::BodyType::Male) => 80.0,
(humanoid::Species::Danari, humanoid::BodyType::Female) => 60.0,
}
}, },
Body::Object(obj) => obj.mass().0, Body::BirdMedium(body) => {
Body::QuadrupedLow(body) => match body.species { get_body_f32_attribute(&body_masses.bird_medium, body.species)
quadruped_low::Species::Alligator => 360.0, // ~✅
quadruped_low::Species::Asp => 300.0,
// saltwater crocodiles can weigh around 1 ton, but our version is the size of an
// alligator or smaller, so whatever
quadruped_low::Species::Crocodile => 360.0,
quadruped_low::Species::Deadwood => 400.0,
quadruped_low::Species::Lavadrake => 500.0,
quadruped_low::Species::Monitor => 100.0,
quadruped_low::Species::Pangolin => 100.0,
quadruped_low::Species::Salamander => 65.0,
quadruped_low::Species::Tortoise => 200.0,
_ => 200.0,
}, },
Body::QuadrupedMedium(body) => match body.species { Body::BirdLarge(body) => get_body_f32_attribute(&body_masses.bird_large, body.species),
quadruped_medium::Species::Bear => 500.0, // ~✅ (350-700 kg) Body::Dragon(body) => get_body_f32_attribute(&body_masses.dragon, body.species),
quadruped_medium::Species::Cattle => 575.0, // ~✅ (500-650 kg) Body::FishMedium(body) => {
quadruped_medium::Species::Deer => 80.0, get_body_f32_attribute(&body_masses.fish_medium, body.species)
quadruped_medium::Species::Donkey => 200.0,
quadruped_medium::Species::Highland => 200.0,
quadruped_medium::Species::Horse => 500.0, // ~✅
quadruped_medium::Species::Kelpie => 200.0,
quadruped_medium::Species::Lion => 170.0, // ~✅ (110-225 kg)
quadruped_medium::Species::Panda => 200.0,
quadruped_medium::Species::Saber => 130.0,
quadruped_medium::Species::Yak => 200.0,
_ => 200.0,
}, },
Body::QuadrupedSmall(body) => match body.species { Body::FishSmall(body) => get_body_f32_attribute(&body_masses.fish_small, body.species),
quadruped_small::Species::Batfox => 50.0, Body::Golem(body) => get_body_f32_attribute(&body_masses.golem, body.species),
quadruped_small::Species::Boar => 80.0, // ~✅ (60-100 kg) Body::Humanoid(body) => get_body_f32_attribute(&body_masses.humanoid, body.species),
quadruped_small::Species::Dodarock => 150.0, Body::QuadrupedLow(body) => {
quadruped_small::Species::Holladon => 150.0, get_body_f32_attribute(&body_masses.quadruped_low, body.species)
quadruped_small::Species::Hyena => 70.0, // ~✅ (vaguely)
quadruped_small::Species::Truffler => 150.0,
_ => 80.0,
}, },
Body::Theropod(body) => match body.species { Body::QuadrupedMedium(body) => {
// for reference, elephants are in the range of 2.6-6.9 tons get_body_f32_attribute(&body_masses.quadruped_medium, body.species)
// and Tyrannosaurus rex were ~8.4-14 tons
theropod::Species::Archaeos => 13_000.0,
theropod::Species::Ntouka => 13_000.0,
theropod::Species::Odonto => 13_000.0,
theropod::Species::Sandraptor => 500.0,
theropod::Species::Snowraptor => 500.0,
theropod::Species::Sunlizard => 500.0,
theropod::Species::Woodraptor => 500.0,
theropod::Species::Yale => 1_000.0,
}, },
Body::Ship(ship) => ship.mass().0, Body::QuadrupedSmall(body) => {
get_body_f32_attribute(&body_masses.quadruped_small, body.species)
},
Body::Theropod(body) => get_body_f32_attribute(&body_masses.theropod, body.species),
Body::Ship(ship) => ship.density().0,
Body::Object(object) => object.density().0,
}; };
Mass(m) Mass(m)
} }
pub fn aggro(&self, body_aggros: &AllBodiesAggro) -> f32 {
match self {
Body::BipedLarge(body) => {
get_body_f32_attribute(&body_aggros.biped_large, body.species)
},
Body::BipedSmall(body) => {
get_body_f32_attribute(&body_aggros.biped_small, body.species)
},
Body::BirdMedium(body) => {
get_body_f32_attribute(&body_aggros.bird_medium, body.species)
},
Body::BirdLarge(body) => get_body_f32_attribute(&body_aggros.bird_large, body.species),
Body::FishSmall(body) => get_body_f32_attribute(&body_aggros.fish_small, body.species),
Body::FishMedium(body) => {
get_body_f32_attribute(&body_aggros.fish_medium, body.species)
},
Body::Humanoid(body) => get_body_f32_attribute(&body_aggros.humanoid, body.species),
Body::QuadrupedMedium(body) => {
get_body_f32_attribute(&body_aggros.quadruped_medium, body.species)
},
Body::QuadrupedSmall(body) => {
get_body_f32_attribute(&body_aggros.quadruped_small, body.species)
},
Body::Theropod(body) => get_body_f32_attribute(&body_aggros.theropod, body.species),
Body::Dragon(body) => get_body_f32_attribute(&body_aggros.dragon, body.species),
Body::QuadrupedLow(body) => {
get_body_f32_attribute(&body_aggros.quadruped_low, body.species)
},
Body::Golem(body) => get_body_f32_attribute(&body_aggros.golem, body.species),
Body::Ship(_) | Body::Object(_) => 0.0,
}
}
/// The width (shoulder to shoulder), length (nose to tail) and height /// The width (shoulder to shoulder), length (nose to tail) and height
/// respectively /// respectively
pub fn dimensions(&self) -> Vec3<f32> { pub fn dimensions(&self) -> Vec3<f32> {
@ -367,226 +445,123 @@ impl Body {
pub fn height(&self) -> f32 { self.dimensions().z } pub fn height(&self) -> f32 { self.dimensions().z }
pub fn base_energy(&self) -> u32 { pub fn base_energy(&self, body_energies: &AllBodiesBaseEnergy) -> u32 {
match self { match self {
Body::BipedLarge(biped_large) => match biped_large.species { Body::BipedLarge(body) => {
biped_large::Species::Dullahan => 4000, get_body_u32_attribute(&body_energies.biped_large, body.species)
_ => 3000,
}, },
Body::BirdLarge(body) => match body.species { Body::BipedSmall(body) => {
bird_large::Species::Cockatrice => 4000, get_body_u32_attribute(&body_energies.biped_small, body.species)
bird_large::Species::Phoenix => 6000,
}, },
Body::Humanoid(_) => 750, Body::BirdMedium(body) => {
_ => 1000, get_body_u32_attribute(&body_energies.bird_medium, body.species)
},
Body::BirdLarge(body) => {
get_body_u32_attribute(&body_energies.bird_large, body.species)
},
Body::FishSmall(body) => {
get_body_u32_attribute(&body_energies.fish_small, body.species)
},
Body::FishMedium(body) => {
get_body_u32_attribute(&body_energies.fish_medium, body.species)
},
Body::Humanoid(body) => get_body_u32_attribute(&body_energies.humanoid, body.species),
Body::QuadrupedMedium(body) => {
get_body_u32_attribute(&body_energies.quadruped_medium, body.species)
},
Body::QuadrupedSmall(body) => {
get_body_u32_attribute(&body_energies.quadruped_small, body.species)
},
Body::Theropod(body) => get_body_u32_attribute(&body_energies.theropod, body.species),
Body::Dragon(body) => get_body_u32_attribute(&body_energies.dragon, body.species),
Body::QuadrupedLow(body) => {
get_body_u32_attribute(&body_energies.quadruped_low, body.species)
},
Body::Golem(body) => get_body_u32_attribute(&body_energies.golem, body.species),
Body::Ship(_) | Body::Object(_) => 1000,
} }
} }
#[allow(unreachable_patterns)] pub fn base_health(&self, body_healths: &AllBodiesBaseHealth) -> u32 {
pub fn base_health(&self) -> u32 {
match self { match self {
Body::Humanoid(_) => 500, Body::BipedLarge(body) => {
Body::QuadrupedSmall(quadruped_small) => match quadruped_small.species { get_body_u32_attribute(&body_healths.biped_large, body.species)
quadruped_small::Species::Boar => 700,
quadruped_small::Species::Batfox => 400,
quadruped_small::Species::Dodarock => 1000,
quadruped_small::Species::Holladon => 800,
quadruped_small::Species::Hyena => 450,
quadruped_small::Species::Truffler => 450,
_ => 400,
}, },
Body::QuadrupedMedium(quadruped_medium) => match quadruped_medium.species { Body::BipedSmall(body) => {
quadruped_medium::Species::Grolgar => 900, get_body_u32_attribute(&body_healths.biped_small, body.species)
quadruped_medium::Species::Saber => 600,
quadruped_medium::Species::Tiger => 700,
quadruped_medium::Species::Lion => 900,
quadruped_medium::Species::Tarasque => 1500,
quadruped_medium::Species::Wolf => 550,
quadruped_medium::Species::Frostfang => 400,
quadruped_medium::Species::Mouflon => 500,
quadruped_medium::Species::Catoblepas => 1000,
quadruped_medium::Species::Bonerattler => 500,
quadruped_medium::Species::Deer => 500,
quadruped_medium::Species::Hirdrasil => 700,
quadruped_medium::Species::Roshwalr => 800,
quadruped_medium::Species::Donkey => 550,
quadruped_medium::Species::Zebra => 550,
quadruped_medium::Species::Antelope => 450,
quadruped_medium::Species::Kelpie => 600,
quadruped_medium::Species::Horse => 600,
quadruped_medium::Species::Barghest => 1700,
quadruped_medium::Species::Cattle => 1000,
quadruped_medium::Species::Highland => 1200,
quadruped_medium::Species::Yak => 1100,
quadruped_medium::Species::Panda => 900,
quadruped_medium::Species::Bear => 900,
quadruped_medium::Species::Moose => 800,
quadruped_medium::Species::Dreadhorn => 1100,
_ => 700,
}, },
Body::BirdMedium(bird_medium) => match bird_medium.species { Body::BirdMedium(body) => {
bird_medium::Species::Chicken => 300, get_body_u32_attribute(&body_healths.bird_medium, body.species)
bird_medium::Species::Duck => 300,
bird_medium::Species::Goose => 300,
bird_medium::Species::Parrot => 250,
bird_medium::Species::Peacock => 350,
bird_medium::Species::Eagle => 450,
_ => 250,
}, },
Body::FishMedium(_) => 250, Body::BirdLarge(body) => get_body_u32_attribute(&body_healths.bird_large, body.species),
Body::Dragon(_) => 5000, Body::FishSmall(body) => get_body_u32_attribute(&body_healths.fish_small, body.species),
Body::BirdLarge(_) => 3000, Body::FishMedium(body) => {
Body::FishSmall(_) => 20, get_body_u32_attribute(&body_healths.fish_medium, body.species)
Body::BipedLarge(biped_large) => match biped_large.species {
biped_large::Species::Ogre => 3200,
biped_large::Species::Cyclops => 3200,
biped_large::Species::Wendigo => 2800,
biped_large::Species::Troll => 2400,
biped_large::Species::Dullahan => 3000,
biped_large::Species::Mindflayer => 12500,
biped_large::Species::Tidalwarrior => 2500,
biped_large::Species::Yeti => 4000,
biped_large::Species::Minotaur => 30000,
biped_large::Species::Harvester => 3000,
biped_large::Species::Blueoni => 2400,
biped_large::Species::Redoni => 2400,
_ => 1200,
}, },
Body::BipedSmall(biped_small) => match biped_small.species { Body::Humanoid(body) => get_body_u32_attribute(&body_healths.humanoid, body.species),
biped_small::Species::Gnarling => 500, Body::QuadrupedMedium(body) => {
biped_small::Species::Adlet => 600, get_body_u32_attribute(&body_healths.quadruped_medium, body.species)
biped_small::Species::Sahagin => 800,
biped_small::Species::Haniwa => 900,
biped_small::Species::Myrmidon => 900,
biped_small::Species::Husk => 200,
_ => 600,
}, },
Body::QuadrupedSmall(body) => {
get_body_u32_attribute(&body_healths.quadruped_small, body.species)
},
Body::Theropod(body) => get_body_u32_attribute(&body_healths.theropod, body.species),
Body::Dragon(body) => get_body_u32_attribute(&body_healths.dragon, body.species),
Body::QuadrupedLow(body) => {
get_body_u32_attribute(&body_healths.quadruped_low, body.species)
},
Body::Golem(body) => get_body_u32_attribute(&body_healths.golem, body.species),
Body::Ship(_) => 10000,
Body::Object(object) => match object { Body::Object(object) => match object {
object::Body::TrainingDummy => 10000, object::Body::TrainingDummy => 10000,
object::Body::Crossbow => 800, object::Body::Crossbow => 800,
object::Body::HaniwaSentry => 600, object::Body::HaniwaSentry => 600,
_ => 10000, _ => 10000,
}, },
Body::Golem(golem) => match golem.species {
golem::Species::ClayGolem => 7500,
_ => 10000,
},
Body::Theropod(theropod) => match theropod.species {
theropod::Species::Archaeos => 3500,
theropod::Species::Odonto => 3000,
_ => 1100,
},
Body::QuadrupedLow(quadruped_low) => match quadruped_low.species {
quadruped_low::Species::Crocodile => 800,
quadruped_low::Species::Alligator => 900,
quadruped_low::Species::Monitor => 600,
quadruped_low::Species::Asp => 750,
quadruped_low::Species::Tortoise => 900,
quadruped_low::Species::Rocksnapper => 1200,
quadruped_low::Species::Pangolin => 400,
quadruped_low::Species::Maneater => 700,
quadruped_low::Species::Sandshark => 900,
quadruped_low::Species::Hakulaq => 500,
quadruped_low::Species::Lavadrake => 1000,
quadruped_low::Species::Basilisk => 1000,
quadruped_low::Species::Deadwood => 700,
_ => 700,
},
Body::Ship(_) => 10000,
} }
} }
#[allow(unreachable_patterns)] pub fn base_health_increase(&self, body_health_increases: &AllBodiesBaseHealthIncrease) -> u32 {
pub fn base_health_increase(&self) -> u32 {
match self { match self {
Body::Humanoid(_) => 50, Body::BipedLarge(body) => {
Body::QuadrupedSmall(quadruped_small) => match quadruped_small.species { get_body_u32_attribute(&body_health_increases.biped_large, body.species)
quadruped_small::Species::Boar => 20,
quadruped_small::Species::Batfox => 10,
quadruped_small::Species::Dodarock => 30,
quadruped_small::Species::Holladon => 30,
quadruped_small::Species::Hyena => 20,
quadruped_small::Species::Truffler => 20,
_ => 10,
}, },
Body::QuadrupedMedium(quadruped_medium) => match quadruped_medium.species { Body::BipedSmall(body) => {
quadruped_medium::Species::Grolgar => 30, get_body_u32_attribute(&body_health_increases.biped_small, body.species)
quadruped_medium::Species::Saber => 20,
quadruped_medium::Species::Tiger => 20,
quadruped_medium::Species::Tuskram => 30,
quadruped_medium::Species::Lion => 40,
quadruped_medium::Species::Tarasque => 60,
quadruped_medium::Species::Wolf => 20,
quadruped_medium::Species::Frostfang => 40,
quadruped_medium::Species::Mouflon => 30,
quadruped_medium::Species::Catoblepas => 50,
quadruped_medium::Species::Bonerattler => 30,
quadruped_medium::Species::Deer => 20,
quadruped_medium::Species::Hirdrasil => 30,
quadruped_medium::Species::Roshwalr => 40,
quadruped_medium::Species::Donkey => 30,
quadruped_medium::Species::Camel => 30,
quadruped_medium::Species::Zebra => 30,
quadruped_medium::Species::Antelope => 20,
quadruped_medium::Species::Kelpie => 30,
quadruped_medium::Species::Horse => 30,
quadruped_medium::Species::Barghest => 50,
quadruped_medium::Species::Cattle => 30,
quadruped_medium::Species::Highland => 30,
quadruped_medium::Species::Yak => 30,
quadruped_medium::Species::Panda => 40,
quadruped_medium::Species::Bear => 40,
quadruped_medium::Species::Moose => 30,
quadruped_medium::Species::Dreadhorn => 50,
_ => 20,
}, },
Body::BirdMedium(bird_medium) => match bird_medium.species { Body::BirdMedium(body) => {
bird_medium::Species::Chicken => 10, get_body_u32_attribute(&body_health_increases.bird_medium, body.species)
bird_medium::Species::Duck => 10,
bird_medium::Species::Goose => 10,
bird_medium::Species::Parrot => 10,
bird_medium::Species::Peacock => 10,
bird_medium::Species::Eagle => 10,
_ => 20,
}, },
Body::FishMedium(_) => 10, Body::BirdLarge(body) => {
Body::Dragon(_) => 500, get_body_u32_attribute(&body_health_increases.bird_large, body.species)
Body::BirdLarge(_) => 120,
Body::FishSmall(_) => 10,
Body::BipedLarge(biped_large) => match biped_large.species {
biped_large::Species::Ogre => 70,
biped_large::Species::Cyclops => 80,
biped_large::Species::Wendigo => 80,
biped_large::Species::Troll => 60,
biped_large::Species::Dullahan => 120,
biped_large::Species::Tidalwarrior => 90,
biped_large::Species::Yeti => 80,
biped_large::Species::Harvester => 80,
// Boss enemies have their health set, not adjusted by level.
biped_large::Species::Mindflayer => 0,
biped_large::Species::Minotaur => 0,
_ => 100,
}, },
Body::BipedSmall(_) => 10, Body::FishSmall(body) => {
Body::Object(_) => 10, get_body_u32_attribute(&body_health_increases.fish_small, body.species)
Body::Golem(_) => 0,
Body::Theropod(_) => 20,
Body::QuadrupedLow(quadruped_low) => match quadruped_low.species {
quadruped_low::Species::Crocodile => 20,
quadruped_low::Species::Alligator => 20,
quadruped_low::Species::Salamander => 10,
quadruped_low::Species::Monitor => 10,
quadruped_low::Species::Asp => 10,
quadruped_low::Species::Tortoise => 20,
quadruped_low::Species::Rocksnapper => 50,
quadruped_low::Species::Pangolin => 10,
quadruped_low::Species::Maneater => 30,
quadruped_low::Species::Sandshark => 40,
quadruped_low::Species::Hakulaq => 10,
quadruped_low::Species::Deadwood => 30,
_ => 20,
}, },
Body::FishMedium(body) => {
get_body_u32_attribute(&body_health_increases.fish_medium, body.species)
},
Body::Humanoid(body) => {
get_body_u32_attribute(&body_health_increases.humanoid, body.species)
},
Body::QuadrupedMedium(body) => {
get_body_u32_attribute(&body_health_increases.quadruped_medium, body.species)
},
Body::QuadrupedSmall(body) => {
get_body_u32_attribute(&body_health_increases.quadruped_small, body.species)
},
Body::Theropod(body) => {
get_body_u32_attribute(&body_health_increases.theropod, body.species)
},
Body::Dragon(body) => {
get_body_u32_attribute(&body_health_increases.dragon, body.species)
},
Body::QuadrupedLow(body) => {
get_body_u32_attribute(&body_health_increases.quadruped_low, body.species)
},
Body::Golem(body) => get_body_u32_attribute(&body_health_increases.golem, body.species),
Body::Ship(_) => 500, Body::Ship(_) => 500,
Body::Object(_) => 10,
} }
} }

View File

@ -1,4 +1,3 @@
use crate::comp::Body;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use specs::{Component, DerefFlaggedStorage}; use specs::{Component, DerefFlaggedStorage};
use specs_idvs::IdvStorage; use specs_idvs::IdvStorage;
@ -31,10 +30,10 @@ pub enum StatChangeError {
} }
impl Energy { impl Energy {
pub fn new(body: Body, level: u16) -> Energy { pub fn new(base_energy: u32, level: u16) -> Energy {
let mut energy = Energy::empty(); let mut energy = Energy::empty();
energy.update_max_energy(Some(body), level); energy.update_max_energy(base_energy, level);
energy.set_to(energy.maximum(), EnergySource::Revive); energy.set_to(energy.maximum(), EnergySource::Revive);
energy energy
@ -96,15 +95,13 @@ impl Energy {
// it'll set it to base max // it'll set it to base max
pub fn last_set(&mut self) { self.last_max = self.maximum } pub fn last_set(&mut self) { self.last_max = self.maximum }
pub fn update_max_energy(&mut self, body: Option<Body>, level: u16) { pub fn update_max_energy(&mut self, base_energy: u32, level: u16) {
if let Some(body) = body { self.set_base_max(base_energy + 50 * level as u32);
self.set_base_max(body.base_energy() + 50 * level as u32); self.set_maximum(base_energy + 50 * level as u32);
self.set_maximum(body.base_energy() + 50 * level as u32); self.change_by(EnergyChange {
self.change_by(EnergyChange { amount: 50,
amount: 50, source: EnergySource::LevelUp,
source: EnergySource::LevelUp, });
});
}
} }
pub fn reset_max(&mut self) { pub fn reset_max(&mut self) {

View File

@ -1,5 +1,4 @@
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use crate::comp::Body;
use crate::{uid::Uid, DamageSource}; use crate::{uid::Uid, DamageSource};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -45,10 +44,10 @@ pub struct Health {
impl Health { impl Health {
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
pub fn new(body: Body, level: u16) -> Self { pub fn new(base_health: u32, base_health_increase: u32, level: u16) -> Self {
let mut health = Health::empty(); let mut health = Health::empty();
health.update_max_hp(Some(body), level); health.update_max_health(base_health, base_health_increase, level);
health.set_to(health.maximum(), HealthSource::Revive); health.set_to(health.maximum(), HealthSource::Revive);
health health
@ -120,15 +119,13 @@ impl Health {
// TODO: Delete this once stat points will be a thing // TODO: Delete this once stat points will be a thing
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
pub fn update_max_hp(&mut self, body: Option<Body>, level: u16) { pub fn update_max_health(&mut self, base_health: u32, base_health_increase: u32, level: u16) {
if let Some(body) = body { self.set_base_max(base_health + base_health_increase * level as u32);
self.set_base_max(body.base_health() + body.base_health_increase() * level as u32); self.set_maximum(base_health + base_health_increase * level as u32);
self.set_maximum(body.base_health() + body.base_health_increase() * level as u32); self.change_by(HealthChange {
self.change_by(HealthChange { amount: base_health_increase as i32,
amount: body.base_health_increase() as i32, cause: HealthSource::LevelUp,
cause: HealthSource::LevelUp, });
});
}
} }
/// Returns the fraction of health an entity has remaining /// Returns the fraction of health an entity has remaining

View File

@ -41,6 +41,14 @@ pub enum ServerEvent {
explosion: Explosion, explosion: Explosion,
owner: Option<Uid>, owner: Option<Uid>,
}, },
ModifyHealthLevel {
entity: EcsEntity,
level: u16,
},
ModifyEnergyLevel {
entity: EcsEntity,
level: u16,
},
Damage { Damage {
entity: EcsEntity, entity: EcsEntity,
change: comp::HealthChange, change: comp::HealthChange,

View File

@ -98,8 +98,10 @@ impl CharacterBehavior for Data {
pos: *data.pos, pos: *data.pos,
stats, stats,
skill_set, skill_set,
// FIXME somehow get husk health in here
health: comp::Health::new( health: comp::Health::new(
body, 200,
10,
self.static_data.summon_info.health_scaling, self.static_data.summon_info.health_scaling,
), ),
poise: comp::Poise::new(body), poise: comp::Poise::new(body),
@ -107,9 +109,9 @@ impl CharacterBehavior for Data {
body, body,
agent: Some(comp::Agent::new( agent: Some(comp::Agent::new(
None, None,
&body,
Behavior::from(BehaviorCapability::SPEAK), Behavior::from(BehaviorCapability::SPEAK),
true, true,
0.0,
)), )),
alignment: comp::Alignment::Owned(*data.uid), alignment: comp::Alignment::Owned(*data.uid),
scale: self scale: self

View File

@ -160,35 +160,40 @@ impl Body {
/// Returns thrust force if the body type can swim, otherwise None /// Returns thrust force if the body type can swim, otherwise None
pub fn swim_thrust(&self) -> Option<f32> { pub fn swim_thrust(&self) -> Option<f32> {
match self { Some(14000.0)
Body::Object(_) | Body::Ship(_) => None, //match self {
Body::BipedLarge(_) | Body::Golem(_) => Some(200.0 * self.mass().0), // Body::Object(_) | Body::Ship(_) => None,
Body::BipedSmall(_) => Some(100.0 * self.mass().0), // Body::BipedLarge(_) | Body::Golem(_) => Some(200.0 *
Body::BirdMedium(_) => Some(50.0 * self.mass().0), // self.mass().0), Body::BipedSmall(_) => Some(100.0 *
Body::BirdLarge(_) => Some(50.0 * self.mass().0), // self.mass().0), Body::BirdMedium(_) => Some(50.0 *
Body::FishMedium(_) => Some(50.0 * self.mass().0), // self.mass().0), Body::BirdLarge(_) => Some(50.0 *
Body::FishSmall(_) => Some(50.0 * self.mass().0), // self.mass().0), Body::FishMedium(_) => Some(50.0 *
Body::Dragon(_) => Some(200.0 * self.mass().0), // self.mass().0), Body::FishSmall(_) => Some(50.0 *
Body::Humanoid(_) => Some(200.0 * self.mass().0), // self.mass().0), Body::Dragon(_) => Some(200.0 *
Body::Theropod(body) => match body.species { // self.mass().0), Body::Humanoid(_) => Some(200.0 *
theropod::Species::Sandraptor // self.mass().0), Body::Theropod(body) => match body.species
| theropod::Species::Snowraptor // { theropod::Species::Sandraptor
| theropod::Species::Sunlizard // | theropod::Species::Snowraptor
| theropod::Species::Woodraptor // | theropod::Species::Sunlizard
| theropod::Species::Yale => Some(200.0 * self.mass().0), // | theropod::Species::Woodraptor
_ => Some(100.0 * self.mass().0), // | theropod::Species::Yale => Some(200.0 * self.mass().0),
}, // _ => Some(100.0 * self.mass().0),
Body::QuadrupedLow(_) => Some(300.0 * self.mass().0), // },
Body::QuadrupedMedium(_) => Some(300.0 * self.mass().0), // Body::QuadrupedLow(_) => Some(300.0 * self.mass().0),
Body::QuadrupedSmall(_) => Some(300.0 * self.mass().0), // Body::QuadrupedMedium(_) => Some(300.0 * self.mass().0),
} // Body::QuadrupedSmall(_) => Some(300.0 * self.mass().0),
//}
} }
/// Returns thrust force if the body type can fly, otherwise None /// Returns thrust force if the body type can fly, otherwise None
pub fn fly_thrust(&self) -> Option<f32> { pub fn fly_thrust(&self) -> Option<f32> {
match self { match self {
Body::BirdMedium(_) => Some(GRAVITY * self.mass().0 * 2.0), //Body::BirdMedium(_) => Some(GRAVITY * self.mass().0 * 2.0),
Body::BirdLarge(_) => Some(GRAVITY * self.mass().0 * 0.5), //Body::BirdLarge(_) => Some(GRAVITY * self.mass().0 * 0.5),
//Body::Dragon(_) => Some(200_000.0),
//Body::Ship(ship::Body::DefaultAirship) => Some(300_000.0),
Body::BirdMedium(_) => Some(GRAVITY * 0.5),
Body::BirdLarge(_) => Some(GRAVITY * 2.0),
Body::Dragon(_) => Some(200_000.0), Body::Dragon(_) => Some(200_000.0),
Body::Ship(ship::Body::DefaultAirship) => Some(300_000.0), Body::Ship(ship::Body::DefaultAirship) => Some(300_000.0),
_ => None, _ => None,
@ -197,20 +202,21 @@ impl Body {
/// Returns jump impulse if the body type can jump, otherwise None /// Returns jump impulse if the body type can jump, otherwise None
pub fn jump_impulse(&self) -> Option<f32> { pub fn jump_impulse(&self) -> Option<f32> {
match self { Some(30.0)
Body::Object(_) | Body::Ship(_) => None, //match self {
Body::BipedLarge(_) | Body::Dragon(_) | Body::Golem(_) | Body::QuadrupedLow(_) => { // Body::Object(_) | Body::Ship(_) => None,
Some(0.1 * self.mass().0) // Body::BipedLarge(_) | Body::Dragon(_) | Body::Golem(_) | Body::QuadrupedLow(_) => {
}, // Some(0.1 * self.mass().0)
Body::QuadrupedMedium(_) => Some(0.4 * self.mass().0), // },
Body::Theropod(body) => match body.species { // Body::QuadrupedMedium(_) => Some(0.4 * self.mass().0),
theropod::Species::Snowraptor // Body::Theropod(body) => match body.species {
| theropod::Species::Sandraptor // theropod::Species::Snowraptor
| theropod::Species::Woodraptor => Some(0.4 * self.mass().0), // | theropod::Species::Sandraptor
_ => None, // | theropod::Species::Woodraptor => Some(0.4 * self.mass().0),
}, // _ => None,
_ => Some(0.4 * self.mass().0), // },
} // _ => Some(0.4 * self.mass().0),
//}
.map(|f| f * GRAVITY) .map(|f| f * GRAVITY)
} }

View File

@ -2,8 +2,8 @@ use common::{
comp::{ comp::{
self, self,
skills::{GeneralSkill, Skill}, skills::{GeneralSkill, Skill},
Body, CharacterState, Combo, Energy, EnergyChange, EnergySource, Health, Poise, CharacterState, Combo, Energy, EnergyChange, EnergySource, Health, Poise, PoiseChange,
PoiseChange, PoiseSource, Pos, SkillSet, Stats, PoiseSource, Pos, SkillSet, Stats,
}, },
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
outcome::Outcome, outcome::Outcome,
@ -28,7 +28,6 @@ pub struct ReadData<'a> {
server_bus: Read<'a, EventBus<ServerEvent>>, server_bus: Read<'a, EventBus<ServerEvent>>,
positions: ReadStorage<'a, Pos>, positions: ReadStorage<'a, Pos>,
uids: ReadStorage<'a, Uid>, uids: ReadStorage<'a, Uid>,
bodies: ReadStorage<'a, Body>,
char_states: ReadStorage<'a, CharacterState>, char_states: ReadStorage<'a, CharacterState>,
} }
@ -112,13 +111,13 @@ impl<'a> System<'a> for Sys {
} }
let stat = stats; let stat = stats;
let update_max_hp = { let update_max_health = {
let health = health.get_unchecked(); let health = health.get_unchecked();
(stat.max_health_modifier - 1.0).abs() > f32::EPSILON (stat.max_health_modifier - 1.0).abs() > f32::EPSILON
|| health.base_max() != health.maximum() || health.base_max() != health.maximum()
}; };
if update_max_hp { if update_max_health {
let mut health = health.get_mut_unchecked(); let mut health = health.get_mut_unchecked();
health.scale_maximum(stat.max_health_modifier); health.scale_maximum(stat.max_health_modifier);
} }
@ -148,33 +147,32 @@ impl<'a> System<'a> for Sys {
} }
// Apply effects from leveling skills // Apply effects from leveling skills
for (mut skill_set, mut health, mut energy, body) in ( for (entity, mut skill_set) in (&read_data.entities, &mut skill_sets.restrict_mut()).join()
&mut skill_sets.restrict_mut(),
&mut healths.restrict_mut(),
&mut energies.restrict_mut(),
&read_data.bodies,
)
.join()
{ {
let skillset = skill_set.get_unchecked(); let skillset = skill_set.get_unchecked();
if skillset.modify_health { if skillset.modify_health {
let mut health = health.get_mut_unchecked(); //let mut health = health.get_mut_unchecked();
let health_level = skillset let health_level = skillset
.skill_level(Skill::General(GeneralSkill::HealthIncrease)) .skill_level(Skill::General(GeneralSkill::HealthIncrease))
.unwrap_or(None) .unwrap_or(None)
.unwrap_or(0); .unwrap_or(0);
health.update_max_hp(Some(*body), health_level); server_event_emitter.emit(ServerEvent::ModifyHealthLevel {
entity,
level: health_level,
});
let mut skillset = skill_set.get_mut_unchecked(); let mut skillset = skill_set.get_mut_unchecked();
skillset.modify_health = false; skillset.modify_health = false;
} }
let skillset = skill_set.get_unchecked(); let skillset = skill_set.get_unchecked();
if skillset.modify_energy { if skillset.modify_energy {
let mut energy = energy.get_mut_unchecked();
let energy_level = skillset let energy_level = skillset
.skill_level(Skill::General(GeneralSkill::EnergyIncrease)) .skill_level(Skill::General(GeneralSkill::EnergyIncrease))
.unwrap_or(None) .unwrap_or(None)
.unwrap_or(0); .unwrap_or(0);
energy.update_max_energy(Some(*body), energy_level); server_event_emitter.emit(ServerEvent::ModifyEnergyLevel {
entity,
level: energy_level,
});
let mut skill_set = skill_set.get_mut_unchecked(); let mut skill_set = skill_set.get_mut_unchecked();
skill_set.modify_energy = false; skill_set.modify_energy = false;
} }

View File

@ -1007,6 +1007,23 @@ fn handle_spawn(
let body = body(); let body = body();
let loadout = LoadoutBuilder::build_loadout(body, None, None, None).build(); let loadout = LoadoutBuilder::build_loadout(body, None, None, None).build();
let inventory = Inventory::new_with_loadout(loadout); let inventory = Inventory::new_with_loadout(loadout);
let (base_health, base_health_increase) = {
let body_attributes = server
.state
.ecs()
.read_resource::<comp::body::BodyAttributes>();
(
body_attributes
.base_health
.as_ref()
.map_or(500, |bh| body.base_health(&bh)),
body_attributes
.base_health_increase
.as_ref()
.map_or(30, |bhi| body.base_health_increase(&bhi)),
)
//(500, 30)
};
let mut entity_base = server let mut entity_base = server
.state .state
@ -1014,7 +1031,7 @@ fn handle_spawn(
pos, pos,
comp::Stats::new(get_npc_name(id, npc::BodyType::from_body(body))), comp::Stats::new(get_npc_name(id, npc::BodyType::from_body(body))),
comp::SkillSet::default(), comp::SkillSet::default(),
comp::Health::new(body, 1), comp::Health::new(base_health, base_health_increase, 1),
comp::Poise::new(body), comp::Poise::new(body),
inventory, inventory,
body, body,
@ -1107,7 +1124,24 @@ fn handle_spawn_training_dummy(
let stats = comp::Stats::new("Training Dummy".to_string()); let stats = comp::Stats::new("Training Dummy".to_string());
let skill_set = comp::SkillSet::default(); let skill_set = comp::SkillSet::default();
let health = comp::Health::new(body, 0); let (base_health, base_health_increase) = {
let body_attributes = server
.state
.ecs()
.read_resource::<comp::body::BodyAttributes>();
(
body_attributes
.base_health
.as_ref()
.map_or(500, |bh| body.base_health(&bh)),
body_attributes
.base_health_increase
.as_ref()
.map_or(30, |bhi| body.base_health_increase(&bhi)),
)
//(500, 30)
};
let health = comp::Health::new(base_health, base_health_increase, 0);
let poise = comp::Poise::new(body); let poise = comp::Poise::new(body);
server server

View File

@ -62,6 +62,40 @@ pub fn handle_damage(server: &Server, entity: EcsEntity, change: HealthChange) {
} }
} }
pub fn handle_update_health_level(server: &Server, entity: EcsEntity, level: u16) {
let ecs = &server.state.ecs();
if let Some(body) = ecs.read_storage::<Body>().get(entity) {
let body_attributes = ecs.read_resource::<comp::body::BodyAttributes>();
let base_health = body_attributes
.base_health
.as_ref()
.map_or(500, |bh| body.base_health(&bh));
let base_health_increase = body_attributes
.base_health_increase
.as_ref()
.map_or(500, |bhi| body.base_health_increase(&bhi));
if let Some(mut health) = ecs.write_storage::<Health>().get_mut(entity) {
health.update_max_health(base_health, base_health_increase, level);
}
}
}
pub fn handle_update_energy_level(server: &Server, entity: EcsEntity, level: u16) {
let ecs = &server.state.ecs();
if let Some(body) = ecs.read_storage::<Body>().get(entity) {
let body_attributes = ecs.read_resource::<comp::body::BodyAttributes>();
let base_energy = body_attributes
.base_energy
.as_ref()
.map_or(1000, |bh| body.base_energy(&bh));
if let Some(mut energy) = ecs.write_storage::<Energy>().get_mut(entity) {
energy.update_max_energy(base_energy, level);
}
}
}
pub fn handle_knockback(server: &Server, entity: EcsEntity, impulse: Vec3<f32>) { pub fn handle_knockback(server: &Server, entity: EcsEntity, impulse: Vec3<f32>) {
let ecs = &server.state.ecs(); let ecs = &server.state.ecs();
let clients = ecs.read_storage::<Client>(); let clients = ecs.read_storage::<Client>();

View File

@ -8,7 +8,7 @@ use entity_creation::{
use entity_manipulation::{ use entity_manipulation::{
handle_aura, handle_buff, handle_combo_change, handle_damage, handle_delete, handle_destroy, handle_aura, handle_buff, handle_combo_change, handle_damage, handle_delete, handle_destroy,
handle_energy_change, handle_explosion, handle_knockback, handle_land_on_ground, handle_poise, handle_energy_change, handle_explosion, handle_knockback, handle_land_on_ground, handle_poise,
handle_respawn, handle_teleport_to, handle_respawn, handle_teleport_to, handle_update_energy_level, handle_update_health_level,
}; };
use group_manip::handle_group; use group_manip::handle_group;
use information::handle_site_info; use information::handle_site_info;
@ -90,6 +90,12 @@ impl Server {
handle_knockback(&self, entity, impulse) handle_knockback(&self, entity, impulse)
}, },
ServerEvent::Damage { entity, change } => handle_damage(&self, entity, change), ServerEvent::Damage { entity, change } => handle_damage(&self, entity, change),
ServerEvent::ModifyHealthLevel { entity, level } => {
handle_update_health_level(&self, entity, level)
},
ServerEvent::ModifyEnergyLevel { entity, level } => {
handle_update_energy_level(&self, entity, level)
},
ServerEvent::PoiseChange { ServerEvent::PoiseChange {
entity, entity,
change, change,

View File

@ -232,6 +232,9 @@ impl Server {
let msm = comp::inventory::item::MaterialStatManifest::default(); let msm = comp::inventory::item::MaterialStatManifest::default();
state.ecs_mut().insert(msm); state.ecs_mut().insert(msm);
let body_attributes = comp::body::BodyAttributes::load_expect_cloned("");
state.ecs_mut().insert(body_attributes);
state.ecs_mut().insert(CharacterLoader::new( state.ecs_mut().insert(CharacterLoader::new(
Arc::<RwLock<DatabaseSettings>>::clone(&database_settings), Arc::<RwLock<DatabaseSettings>>::clone(&database_settings),
)?); )?);

View File

@ -2,7 +2,10 @@
use super::*; use super::*;
use common::{ use common::{
comp::{self, inventory::loadout_builder::LoadoutBuilder, Behavior, BehaviorCapability}, comp::{
self, body::BodyAttributes, inventory::loadout_builder::LoadoutBuilder, Behavior,
BehaviorCapability,
},
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
resources::{DeltaTime, Time}, resources::{DeltaTime, Time},
terrain::TerrainGrid, terrain::TerrainGrid,
@ -21,6 +24,7 @@ impl<'a> System<'a> for Sys {
Read<'a, Time>, Read<'a, Time>,
Read<'a, DeltaTime>, Read<'a, DeltaTime>,
Read<'a, EventBus<ServerEvent>>, Read<'a, EventBus<ServerEvent>>,
Read<'a, BodyAttributes>,
WriteExpect<'a, RtSim>, WriteExpect<'a, RtSim>,
ReadExpect<'a, TerrainGrid>, ReadExpect<'a, TerrainGrid>,
ReadExpect<'a, Arc<world::World>>, ReadExpect<'a, Arc<world::World>>,
@ -40,6 +44,7 @@ impl<'a> System<'a> for Sys {
time, time,
dt, dt,
server_event_bus, server_event_bus,
body_attributes,
mut rtsim, mut rtsim,
terrain, terrain,
world, world,
@ -103,17 +108,30 @@ impl<'a> System<'a> for Sys {
.map(|e| e as f32) .map(|e| e as f32)
+ Vec3::new(0.5, 0.5, body.flying_height()); + Vec3::new(0.5, 0.5, body.flying_height());
let pos = comp::Pos(spawn_pos); let pos = comp::Pos(spawn_pos);
let aggro = body_attributes
.aggro
.as_ref()
.map_or(0.0, |ba| body.aggro(&ba));
let agent = Some(comp::Agent::new( let agent = Some(comp::Agent::new(
None, None,
&body,
if matches!(body, comp::Body::Humanoid(_)) { if matches!(body, comp::Body::Humanoid(_)) {
Behavior::from(BehaviorCapability::SPEAK) Behavior::from(BehaviorCapability::SPEAK)
} else { } else {
Behavior::default() Behavior::default()
}, },
false, false,
aggro,
)); ));
let base_health = body_attributes
.base_health
.as_ref()
.map_or(500, |bh| body.base_health(&bh));
let base_health_increase = body_attributes
.base_health_increase
.as_ref()
.map_or(30, |bhi| body.base_health_increase(&bhi));
let rtsim_entity = Some(RtSimEntity(id)); let rtsim_entity = Some(RtSimEntity(id));
let event = match body { let event = match body {
comp::Body::Ship(ship) => ServerEvent::CreateShip { comp::Body::Ship(ship) => ServerEvent::CreateShip {
@ -127,7 +145,7 @@ impl<'a> System<'a> for Sys {
pos: comp::Pos(spawn_pos), pos: comp::Pos(spawn_pos),
stats: comp::Stats::new(entity.get_name()), stats: comp::Stats::new(entity.get_name()),
skill_set: comp::SkillSet::default(), skill_set: comp::SkillSet::default(),
health: comp::Health::new(body, 10), health: comp::Health::new(base_health, base_health_increase, 10),
loadout: match body { loadout: match body {
comp::Body::Humanoid(_) => entity.get_loadout(), comp::Body::Humanoid(_) => entity.get_loadout(),
_ => LoadoutBuilder::new().build(), _ => LoadoutBuilder::new().build(),

View File

@ -8,7 +8,7 @@ use common::{
comp::{ comp::{
self, self,
skills::{GeneralSkill, Skill}, skills::{GeneralSkill, Skill},
Group, Inventory, Density, Group, Inventory, Mass,
}, },
effect::Effect, effect::Effect,
resources::TimeOfDay, resources::TimeOfDay,
@ -180,6 +180,24 @@ impl StateExt for State {
inventory: comp::Inventory, inventory: comp::Inventory,
body: comp::Body, body: comp::Body,
) -> EcsEntityBuilder { ) -> EcsEntityBuilder {
let (mass, density, base_energy) = {
let body_attributes = &self.ecs().read_resource::<comp::body::BodyAttributes>();
(
body_attributes
.mass
.as_ref()
.map_or(Mass::default(), |bm| body.mass(&bm)),
body_attributes
.density
.as_ref()
.map_or(Density::default(), |bd| body.density(&bd)),
body_attributes
.base_energy
.as_ref()
.map_or(0, |be| body.base_energy(&be)),
)
//(Mass::default(), Density::default(), 100)
};
self.ecs_mut() self.ecs_mut()
.create_entity_synced() .create_entity_synced()
.with(pos) .with(pos)
@ -192,8 +210,8 @@ impl StateExt for State {
)) ))
.unwrap_or_default(), .unwrap_or_default(),
) )
.with(body.mass()) .with(mass)
.with(body.density()) .with(density)
.with(match body { .with(match body {
comp::Body::Ship(ship) => comp::Collider::Voxel { comp::Body::Ship(ship) => comp::Collider::Voxel {
id: ship.manifest_entry().to_string(), id: ship.manifest_entry().to_string(),
@ -207,7 +225,7 @@ impl StateExt for State {
.with(comp::Controller::default()) .with(comp::Controller::default())
.with(body) .with(body)
.with(comp::Energy::new( .with(comp::Energy::new(
body, base_energy,
skill_set skill_set
.skill_level(Skill::General(GeneralSkill::EnergyIncrease)) .skill_level(Skill::General(GeneralSkill::EnergyIncrease))
.unwrap_or(None) .unwrap_or(None)
@ -227,13 +245,27 @@ impl StateExt for State {
fn create_object(&mut self, pos: comp::Pos, object: comp::object::Body) -> EcsEntityBuilder { fn create_object(&mut self, pos: comp::Pos, object: comp::object::Body) -> EcsEntityBuilder {
let body = comp::Body::Object(object); let body = comp::Body::Object(object);
let (mass, density) = {
let body_attributes = &self.ecs().read_resource::<comp::body::BodyAttributes>();
(
body_attributes
.mass
.as_ref()
.map_or(Mass::default(), |bm| body.mass(&bm)),
body_attributes
.density
.as_ref()
.map_or(Density::default(), |bd| body.density(&bd)),
)
//(Mass::default(), Density::default())
};
self.ecs_mut() self.ecs_mut()
.create_entity_synced() .create_entity_synced()
.with(pos) .with(pos)
.with(comp::Vel(Vec3::zero())) .with(comp::Vel(Vec3::zero()))
.with(comp::Ori::default()) .with(comp::Ori::default())
.with(body.mass()) .with(mass)
.with(body.density()) .with(density)
.with(comp::Collider::Box { .with(comp::Collider::Box {
radius: body.radius(), radius: body.radius(),
z_min: 0.0, z_min: 0.0,
@ -249,14 +281,32 @@ impl StateExt for State {
mountable: bool, mountable: bool,
) -> EcsEntityBuilder { ) -> EcsEntityBuilder {
let body = comp::Body::Ship(ship); let body = comp::Body::Ship(ship);
let (mass, density, base_energy) = {
let body_attributes = &self.ecs().read_resource::<comp::body::BodyAttributes>();
(
body_attributes
.mass
.as_ref()
.map_or(Mass::default(), |bm| body.mass(&bm)),
body_attributes
.density
.as_ref()
.map_or(Density::default(), |bd| body.density(&bd)),
body_attributes
.base_energy
.as_ref()
.map_or(0, |be| body.base_energy(&be)),
)
//(Mass::default(), Density::default(), 100)
};
let mut builder = self let mut builder = self
.ecs_mut() .ecs_mut()
.create_entity_synced() .create_entity_synced()
.with(pos) .with(pos)
.with(comp::Vel(Vec3::zero())) .with(comp::Vel(Vec3::zero()))
.with(comp::Ori::default()) .with(comp::Ori::default())
.with(body.mass()) .with(mass)
.with(body.density()) .with(density)
.with(comp::Collider::Voxel { .with(comp::Collider::Voxel {
id: ship.manifest_entry().to_string(), id: ship.manifest_entry().to_string(),
}) })
@ -267,7 +317,7 @@ impl StateExt for State {
.with(comp::CharacterState::default()) .with(comp::CharacterState::default())
// TODO: some of these are required in order for the character_behavior system to // TODO: some of these are required in order for the character_behavior system to
// recognize a possesed airship; that system should be refactored to use `.maybe()` // recognize a possesed airship; that system should be refactored to use `.maybe()`
.with(comp::Energy::new(ship.into(), 0)) .with(comp::Energy::new(base_energy, 0))
.with(comp::Stats::new("Airship".to_string())) .with(comp::Stats::new("Airship".to_string()))
.with(comp::SkillSet::default()) .with(comp::SkillSet::default())
.with(comp::Combo::default()); .with(comp::Combo::default());
@ -285,13 +335,27 @@ impl StateExt for State {
body: comp::Body, body: comp::Body,
projectile: comp::Projectile, projectile: comp::Projectile,
) -> EcsEntityBuilder { ) -> EcsEntityBuilder {
let (mass, density) = {
let body_attributes = &self.ecs().read_resource::<comp::body::BodyAttributes>();
(
body_attributes
.mass
.as_ref()
.map_or(Mass::default(), |bm| body.mass(&bm)),
body_attributes
.density
.as_ref()
.map_or(Density::default(), |bd| body.density(&bd)),
)
//(Mass::default(), Density::default())
};
self.ecs_mut() self.ecs_mut()
.create_entity_synced() .create_entity_synced()
.with(pos) .with(pos)
.with(vel) .with(vel)
.with(comp::Ori::from_unnormalized_vec(vel.0).unwrap_or_default()) .with(comp::Ori::from_unnormalized_vec(vel.0).unwrap_or_default())
.with(body.mass()) .with(mass)
.with(body.density()) .with(density)
.with(comp::Collider::Point) .with(comp::Collider::Point)
.with(body) .with(body)
.with(projectile) .with(projectile)
@ -470,6 +534,34 @@ 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) = components; let (body, stats, skill_set, inventory, waypoint) = components;
let (mass, density, base_energy, base_health, base_health_increase) = {
let body_attributes = &self.ecs().read_resource::<comp::body::BodyAttributes>();
(
body_attributes
.mass
.as_ref()
.map_or(Mass::default(), |bm| body.mass(&bm)),
body_attributes
.density
.as_ref()
.map_or(Density::default(), |bd| body.density(&bd)),
// FIXME what should the default value be here?
body_attributes
.base_energy
.as_ref()
.map_or(0, |be| body.base_energy(&be)),
// FIXME what should the default value be here?
body_attributes
.base_health
.as_ref()
.map_or(500, |bh| body.base_health(&bh)),
body_attributes
.base_health_increase
.as_ref()
.map_or(30, |bhi| body.base_health_increase(&bhi)),
)
//(Mass::default(), Density::default(), 100, 500, 30)
};
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
@ -489,8 +581,8 @@ impl StateExt for State {
z_max: body.height(), z_max: body.height(),
}); });
self.write_component_ignore_entity_dead(entity, body); self.write_component_ignore_entity_dead(entity, body);
self.write_component_ignore_entity_dead(entity, body.mass()); self.write_component_ignore_entity_dead(entity, mass);
self.write_component_ignore_entity_dead(entity, body.density()); self.write_component_ignore_entity_dead(entity, density);
let (health_level, energy_level) = ( let (health_level, energy_level) = (
skill_set skill_set
.skill_level(Skill::General(GeneralSkill::HealthIncrease)) .skill_level(Skill::General(GeneralSkill::HealthIncrease))
@ -501,8 +593,14 @@ impl StateExt for State {
.unwrap_or(None) .unwrap_or(None)
.unwrap_or(0), .unwrap_or(0),
); );
self.write_component_ignore_entity_dead(entity, comp::Health::new(body, health_level)); self.write_component_ignore_entity_dead(
self.write_component_ignore_entity_dead(entity, comp::Energy::new(body, energy_level)); entity,
comp::Health::new(base_health, base_health_increase, health_level),
);
self.write_component_ignore_entity_dead(
entity,
comp::Energy::new(base_energy, energy_level),
);
self.write_component_ignore_entity_dead(entity, comp::Poise::new(body)); self.write_component_ignore_entity_dead(entity, comp::Poise::new(body));
self.write_component_ignore_entity_dead(entity, stats); self.write_component_ignore_entity_dead(entity, stats);
self.write_component_ignore_entity_dead(entity, skill_set); self.write_component_ignore_entity_dead(entity, skill_set);

View File

@ -590,6 +590,8 @@ impl<'a> AgentData<'a> {
) { ) {
decrement_awareness(agent); decrement_awareness(agent);
forget_old_sounds(agent, read_data); forget_old_sounds(agent, read_data);
let msg = format!("aggro: {}", agent.psyche.aggro);
event_emitter.emit(ServerEvent::Chat(UnresolvedChatMsg::npc(*self.uid, msg)));
// Set owner if no target // Set owner if no target
if agent.target.is_none() && thread_rng().gen_bool(0.1) { if agent.target.is_none() && thread_rng().gen_bool(0.1) {

View File

@ -4,8 +4,8 @@ use crate::{
}; };
use common::{ use common::{
comp::{ comp::{
self, bird_medium, inventory::loadout_builder::LoadoutConfig, Alignment, self, bird_medium, body::BodyAttributes, inventory::loadout_builder::LoadoutConfig,
BehaviorCapability, Pos, Alignment, BehaviorCapability, Pos,
}, },
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
generation::get_npc_name, generation::get_npc_name,
@ -91,6 +91,7 @@ impl<'a> System<'a> for Sys {
Read<'a, Tick>, Read<'a, Tick>,
Read<'a, SpawnPoint>, Read<'a, SpawnPoint>,
Read<'a, Settings>, Read<'a, Settings>,
Read<'a, BodyAttributes>,
ReadExpect<'a, NetworkRequestMetrics>, ReadExpect<'a, NetworkRequestMetrics>,
WriteExpect<'a, ChunkGenerator>, WriteExpect<'a, ChunkGenerator>,
WriteExpect<'a, TerrainGrid>, WriteExpect<'a, TerrainGrid>,
@ -112,6 +113,7 @@ impl<'a> System<'a> for Sys {
tick, tick,
spawn_point, spawn_point,
server_settings, server_settings,
body_attributes,
network_metrics, network_metrics,
mut chunk_generator, mut chunk_generator,
mut terrain, mut terrain,
@ -207,7 +209,16 @@ impl<'a> System<'a> for Sys {
let loadout = let loadout =
LoadoutBuilder::build_loadout(body, main_tool, loadout_config, economy).build(); LoadoutBuilder::build_loadout(body, main_tool, loadout_config, economy).build();
let health = comp::Health::new(body, entity.level.unwrap_or(0)); let base_health = body_attributes
.base_health
.as_ref()
.map_or(500, |bh| body.base_health(&bh));
let base_health_increase = body_attributes
.base_health_increase
.as_ref()
.map_or(30, |bhi| body.base_health_increase(&bhi));
let health =
comp::Health::new(base_health, base_health_increase, entity.level.unwrap_or(0));
let poise = comp::Poise::new(body); let poise = comp::Poise::new(body);
let can_speak = match body { let can_speak = match body {
@ -225,6 +236,11 @@ impl<'a> System<'a> for Sys {
None None
}; };
let aggro = body_attributes
.aggro
.as_ref()
.map_or(0.0, |ba| body.aggro(&ba));
// TODO: This code sets an appropriate base_damage for the enemy. This doesn't // TODO: This code sets an appropriate base_damage for the enemy. This doesn't
// work because the damage is now saved in an ability // work because the damage is now saved in an ability
/* /*
@ -244,7 +260,6 @@ impl<'a> System<'a> for Sys {
agent: if entity.has_agency { agent: if entity.has_agency {
Some(comp::Agent::new( Some(comp::Agent::new(
Some(entity.pos), Some(entity.pos),
&body,
Behavior::default() Behavior::default()
.maybe_with_capabilities( .maybe_with_capabilities(
can_speak.then(|| BehaviorCapability::SPEAK), can_speak.then(|| BehaviorCapability::SPEAK),
@ -254,6 +269,7 @@ impl<'a> System<'a> for Sys {
loadout_config, loadout_config,
Some(comp::inventory::loadout_builder::LoadoutConfig::Guard) Some(comp::inventory::loadout_builder::LoadoutConfig::Guard)
), ),
aggro,
)) ))
} else { } else {
None None