Only NPCs speak when hit. Farm animal alignment changed from NPC to Tame

This commit is contained in:
CapsizeGlimmer
2020-05-25 22:45:13 -04:00
committed by Pfauenauge90
parent 3cea76b82f
commit 78a06550d0
5 changed files with 57 additions and 20 deletions

View File

@ -402,7 +402,7 @@ Willpower
"AAAHHH! I'm under attack! Help!", "AAAHHH! I'm under attack! Help!",
"Help! We're under attack!", "Help! We're under attack!",
"Help! Murderer!", "Help! Murderer!",
"Help! There's a murder on the loose!", "Help! There's a murderer on the loose!",
"Help! They're trying to kill me!", "Help! They're trying to kill me!",
"Guards, I'm under attack!", "Guards, I'm under attack!",
"Guards! I'm under attack!", "Guards! I'm under attack!",

View File

@ -5,9 +5,15 @@ use vek::*;
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
pub enum Alignment { pub enum Alignment {
/// Wild animals and gentle giants
Wild, Wild,
/// Dungeon cultists and bandits
Enemy, Enemy,
/// Friendly folk in villages
Npc, Npc,
/// Farm animals and pets of villagers
Tame,
/// Pets you've tamed with a collar
Owned(EcsEntity), Owned(EcsEntity),
} }
@ -27,6 +33,10 @@ impl Alignment {
match (self, other) { match (self, other) {
(Alignment::Enemy, Alignment::Enemy) => true, (Alignment::Enemy, Alignment::Enemy) => true,
(Alignment::Owned(a), Alignment::Owned(b)) if a == b => true, (Alignment::Owned(a), Alignment::Owned(b)) if a == b => true,
(Alignment::Npc, Alignment::Npc) => true,
(Alignment::Npc, Alignment::Tame) => true,
(Alignment::Tame, Alignment::Npc) => true,
(Alignment::Tame, Alignment::Tame) => true,
_ => false, _ => false,
} }
} }
@ -40,6 +50,9 @@ impl Component for Alignment {
pub struct Agent { pub struct Agent {
pub patrol_origin: Option<Vec3<f32>>, pub patrol_origin: Option<Vec3<f32>>,
pub activity: Activity, pub activity: Activity,
/// Does the agent talk when e.g. hit by the player
// TODO move speech patterns into a Behavior component
pub can_speak: bool,
} }
impl Agent { impl Agent {
@ -47,6 +60,15 @@ impl Agent {
self.patrol_origin = Some(origin); self.patrol_origin = Some(origin);
self self
} }
pub fn new(origin: Vec3<f32>, can_speak: bool) -> Self {
let patrol_origin = Some(origin);
Agent {
patrol_origin,
can_speak,
..Default::default()
}
}
} }
impl Component for Agent { impl Component for Agent {

View File

@ -378,27 +378,32 @@ impl<'a> System<'a> for Sys {
// last!) --- // last!) ---
// Attack a target that's attacking us // Attack a target that's attacking us
if let Some(stats) = stats.get(entity) { if let Some(my_stats) = stats.get(entity) {
// Only if the attack was recent // Only if the attack was recent
if stats.health.last_change.0 < 5.0 { if my_stats.health.last_change.0 < 5.0 {
if let comp::HealthSource::Attack { by } if let comp::HealthSource::Attack { by }
| comp::HealthSource::Projectile { owner: Some(by) } = | comp::HealthSource::Projectile { owner: Some(by) } =
stats.health.last_change.1.cause my_stats.health.last_change.1.cause
{ {
if !agent.activity.is_attack() { if !agent.activity.is_attack() {
if let Some(attacker) = uid_allocator.retrieve_entity_internal(by.id()) if let Some(attacker) = uid_allocator.retrieve_entity_internal(by.id())
{ {
let message = "npc.speech.villager_under_attack".to_string(); if stats.get(attacker).map_or(false, |a| !a.is_dead) {
let bubble = SpeechBubble::npc_new(message, *time); if agent.can_speak {
let _ = speech_bubbles.insert(entity, bubble); let message =
"npc.speech.villager_under_attack".to_string();
let bubble = SpeechBubble::npc_new(message, *time);
let _ = speech_bubbles.insert(entity, bubble);
}
agent.activity = Activity::Attack { agent.activity = Activity::Attack {
target: attacker, target: attacker,
chaser: Chaser::default(), chaser: Chaser::default(),
time: time.0, time: time.0,
been_close: false, been_close: false,
powerup: 0.0, powerup: 0.0,
}; };
}
} }
} }
} }

View File

@ -329,6 +329,8 @@ impl<'a> System<'a> for Sys {
.health .health
.set_to(stats.health.maximum(), comp::HealthSource::Revive); .set_to(stats.health.maximum(), comp::HealthSource::Revive);
let can_speak = alignment == comp::Alignment::Npc;
// 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
/* /*
@ -344,7 +346,7 @@ impl<'a> System<'a> for Sys {
loadout, loadout,
body, body,
alignment, alignment,
agent: comp::Agent::default().with_patrol_origin(entity.pos), agent: comp::Agent::new(entity.pos, can_speak),
scale: comp::Scale(scale), scale: comp::Scale(scale),
drop_item: entity.loot_drop, drop_item: entity.loot_drop,
}) })

View File

@ -784,8 +784,8 @@ impl Settlement {
if matches!(sample.plot, Some(Plot::Town)) if matches!(sample.plot, Some(Plot::Town))
&& RandomField::new(self.seed).chance(Vec3::from(wpos2d), 1.0 / (50.0 * 50.0)) && RandomField::new(self.seed).chance(Vec3::from(wpos2d), 1.0 / (50.0 * 50.0))
{ {
let is_human: bool;
let entity = EntityInfo::at(entity_wpos) let entity = EntityInfo::at(entity_wpos)
.with_alignment(comp::Alignment::Npc)
.with_body(match rng.gen_range(0, 4) { .with_body(match rng.gen_range(0, 4) {
0 => { 0 => {
let species = match rng.gen_range(0, 3) { let species = match rng.gen_range(0, 3) {
@ -793,7 +793,7 @@ impl Settlement {
1 => quadruped_small::Species::Sheep, 1 => quadruped_small::Species::Sheep,
_ => quadruped_small::Species::Cat, _ => quadruped_small::Species::Cat,
}; };
is_human = false;
comp::Body::QuadrupedSmall(quadruped_small::Body::random_with( comp::Body::QuadrupedSmall(quadruped_small::Body::random_with(
rng, &species, rng, &species,
)) ))
@ -805,14 +805,22 @@ impl Settlement {
2 => bird_medium::Species::Goose, 2 => bird_medium::Species::Goose,
_ => bird_medium::Species::Peacock, _ => bird_medium::Species::Peacock,
}; };
is_human = false;
comp::Body::BirdMedium(bird_medium::Body::random_with( comp::Body::BirdMedium(bird_medium::Body::random_with(
rng, &species, rng, &species,
)) ))
}, },
_ => comp::Body::Humanoid(humanoid::Body::random()), _ => {
is_human = true;
comp::Body::Humanoid(humanoid::Body::random())
},
}) })
.do_if(rng.gen(), |entity| { .with_alignment(if is_human {
comp::Alignment::Npc
} else {
comp::Alignment::Tame
})
.do_if(is_human && rng.gen(), |entity| {
entity.with_main_tool(assets::load_expect_cloned( entity.with_main_tool(assets::load_expect_cloned(
match rng.gen_range(0, 7) { match rng.gen_range(0, 7) {
0 => "common.items.weapons.tool.broom", 0 => "common.items.weapons.tool.broom",