mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
New Arena building and visit site for NPCs
This commit is contained in:
parent
5d311e13bd
commit
f4d48d2689
@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Added the ability to make pets sit, they wont follow nor defend you in this state
|
- Added the ability to make pets sit, they wont follow nor defend you in this state
|
||||||
- Portals that spawn in place of the last staircase at old style dungeons to prevent stair cheesing
|
- Portals that spawn in place of the last staircase at old style dungeons to prevent stair cheesing
|
||||||
- Mutliple singleplayer worlds and map generation UI.
|
- Mutliple singleplayer worlds and map generation UI.
|
||||||
|
- New arena building in desert cities, suitable for PVP, also NPCs like to watch the fights too
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
@ -287,3 +287,4 @@ npc-speech-dist_far = far away
|
|||||||
npc-speech-dist_ahead = some way away
|
npc-speech-dist_ahead = some way away
|
||||||
npc-speech-dist_near = nearby
|
npc-speech-dist_near = nearby
|
||||||
npc-speech-dist_near_to = very close
|
npc-speech-dist_near_to = very close
|
||||||
|
npc-speech-arena = Let's sit over there!
|
@ -6,6 +6,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
character::CharacterId,
|
character::CharacterId,
|
||||||
comp::{dialogue::Subject, Content},
|
comp::{dialogue::Subject, Content},
|
||||||
|
util::Dir,
|
||||||
};
|
};
|
||||||
use rand::{seq::IteratorRandom, Rng};
|
use rand::{seq::IteratorRandom, Rng};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -230,6 +231,8 @@ pub struct RtSimController {
|
|||||||
pub actions: VecDeque<NpcAction>,
|
pub actions: VecDeque<NpcAction>,
|
||||||
pub personality: Personality,
|
pub personality: Personality,
|
||||||
pub heading_to: Option<String>,
|
pub heading_to: Option<String>,
|
||||||
|
// TODO: Maybe this should allow for looking at a specific entity target?
|
||||||
|
pub look_dir: Option<Dir>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RtSimController {
|
impl RtSimController {
|
||||||
@ -248,7 +251,9 @@ pub enum NpcActivity {
|
|||||||
Gather(&'static [ChunkResource]),
|
Gather(&'static [ChunkResource]),
|
||||||
// TODO: Generalise to other entities? What kinds of animals?
|
// TODO: Generalise to other entities? What kinds of animals?
|
||||||
HuntAnimals,
|
HuntAnimals,
|
||||||
Dance,
|
Dance(Option<Dir>),
|
||||||
|
Cheer(Option<Dir>),
|
||||||
|
Sit(Option<Dir>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents event-like actions that rtsim NPCs can perform to interact with
|
/// Represents event-like actions that rtsim NPCs can perform to interact with
|
||||||
|
@ -23,5 +23,4 @@ pub enum SettlementKindMeta {
|
|||||||
DesertCity,
|
DesertCity,
|
||||||
SavannahPit,
|
SavannahPit,
|
||||||
CoastalTown,
|
CoastalTown,
|
||||||
PirateHideout,
|
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ use common::{
|
|||||||
},
|
},
|
||||||
store::Id,
|
store::Id,
|
||||||
terrain::CoordinateConversions,
|
terrain::CoordinateConversions,
|
||||||
|
util::Dir,
|
||||||
};
|
};
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
@ -57,6 +58,7 @@ pub struct Controller {
|
|||||||
pub actions: Vec<NpcAction>,
|
pub actions: Vec<NpcAction>,
|
||||||
pub activity: Option<NpcActivity>,
|
pub activity: Option<NpcActivity>,
|
||||||
pub new_home: Option<SiteId>,
|
pub new_home: Option<SiteId>,
|
||||||
|
pub look_dir: Option<Dir>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Controller {
|
impl Controller {
|
||||||
@ -72,7 +74,11 @@ impl Controller {
|
|||||||
|
|
||||||
pub fn do_hunt_animals(&mut self) { self.activity = Some(NpcActivity::HuntAnimals); }
|
pub fn do_hunt_animals(&mut self) { self.activity = Some(NpcActivity::HuntAnimals); }
|
||||||
|
|
||||||
pub fn do_dance(&mut self) { self.activity = Some(NpcActivity::Dance); }
|
pub fn do_dance(&mut self, dir: Option<Dir>) { self.activity = Some(NpcActivity::Dance(dir)); }
|
||||||
|
|
||||||
|
pub fn do_cheer(&mut self, dir: Option<Dir>) { self.activity = Some(NpcActivity::Cheer(dir)); }
|
||||||
|
|
||||||
|
pub fn do_sit(&mut self, dir: Option<Dir>) { self.activity = Some(NpcActivity::Sit(dir)); }
|
||||||
|
|
||||||
pub fn say(&mut self, target: impl Into<Option<Actor>>, content: comp::Content) {
|
pub fn say(&mut self, target: impl Into<Option<Actor>>, content: comp::Content) {
|
||||||
self.actions.push(NpcAction::Say(target.into(), content));
|
self.actions.push(NpcAction::Say(target.into(), content));
|
||||||
|
@ -26,6 +26,7 @@ use common::{
|
|||||||
store::Id,
|
store::Id,
|
||||||
terrain::{CoordinateConversions, SiteKindMeta, TerrainChunkSize},
|
terrain::{CoordinateConversions, SiteKindMeta, TerrainChunkSize},
|
||||||
time::DayPeriod,
|
time::DayPeriod,
|
||||||
|
util::Dir,
|
||||||
};
|
};
|
||||||
use fxhash::FxHasher64;
|
use fxhash::FxHasher64;
|
||||||
use itertools::{Either, Itertools};
|
use itertools::{Either, Itertools};
|
||||||
@ -270,7 +271,7 @@ impl Rule for NpcAi {
|
|||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
};
|
};
|
||||||
|
|
||||||
// The sum of the last `SIMULATED_TICK_SKIP` tick deltatimes is the deltatime since
|
// The sum of the last `SIMULATED_TICK_SKIP` tick deltatimes is the deltatime since
|
||||||
// simulated npcs ran this tick had their ai ran.
|
// simulated npcs ran this tick had their ai ran.
|
||||||
let simulated_dt = last_ticks.iter().sum::<f32>();
|
let simulated_dt = last_ticks.iter().sum::<f32>();
|
||||||
|
|
||||||
@ -283,6 +284,9 @@ impl Rule for NpcAi {
|
|||||||
.for_each(|(npc_id, controller, inbox, sentiments, known_reports, brain)| {
|
.for_each(|(npc_id, controller, inbox, sentiments, known_reports, brain)| {
|
||||||
let npc = &data.npcs[*npc_id];
|
let npc = &data.npcs[*npc_id];
|
||||||
|
|
||||||
|
// Reset look_dir
|
||||||
|
controller.look_dir = None;
|
||||||
|
|
||||||
brain.action.tick(&mut NpcCtx {
|
brain.action.tick(&mut NpcCtx {
|
||||||
state: ctx.state,
|
state: ctx.state,
|
||||||
world: ctx.world,
|
world: ctx.world,
|
||||||
@ -631,7 +635,7 @@ fn socialize() -> impl Action<EveryRange> {
|
|||||||
if matches!(ctx.npc.mode, SimulationMode::Loaded) && socialize.should(ctx) {
|
if matches!(ctx.npc.mode, SimulationMode::Loaded) && socialize.should(ctx) {
|
||||||
// Sometimes dance
|
// Sometimes dance
|
||||||
if ctx.rng.gen_bool(0.15) {
|
if ctx.rng.gen_bool(0.15) {
|
||||||
return just(|ctx, _| ctx.controller.do_dance())
|
return just(|ctx, _| ctx.controller.do_dance(None))
|
||||||
.repeat()
|
.repeat()
|
||||||
.stop_if(timeout(6.0))
|
.stop_if(timeout(6.0))
|
||||||
.debug(|| "dancing")
|
.debug(|| "dancing")
|
||||||
@ -692,11 +696,11 @@ fn adventure() -> impl Action<DefaultState> {
|
|||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
// Travel to the site
|
// Travel to the site
|
||||||
important(just(move |ctx, _| ctx.controller.say(None, Content::localized_with_args("npc-speech-moving_on", [("site", site_name.clone())])))
|
important(just(move |ctx, _| ctx.controller.say(None, Content::localized_with_args("npc-speech-moving_on", [("site", site_name.clone())])))
|
||||||
.then(travel_to_site(tgt_site, 0.6))
|
.then(travel_to_site(tgt_site, 0.6))
|
||||||
// Stop for a few minutes
|
// Stop for a few minutes
|
||||||
.then(villager(tgt_site).repeat().stop_if(timeout(wait_time)))
|
.then(villager(tgt_site).repeat().stop_if(timeout(wait_time)))
|
||||||
.map(|_, _| ())
|
.map(|_, _| ())
|
||||||
.boxed(),
|
.boxed(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
casual(finish().boxed())
|
casual(finish().boxed())
|
||||||
@ -841,6 +845,49 @@ fn villager(visiting_site: SiteId) -> impl Action<DefaultState> {
|
|||||||
.debug(|| "find somewhere to sleep"),
|
.debug(|| "find somewhere to sleep"),
|
||||||
);
|
);
|
||||||
// Villagers with roles should perform those roles
|
// Villagers with roles should perform those roles
|
||||||
|
}
|
||||||
|
// Visiting villagers in DesertCity who are not Merchants should sit down in the Arena during the day
|
||||||
|
else if matches!(ctx.state.data().sites[visiting_site].world_site.map(|ws| &ctx.index.sites.get(ws).kind), Some(SiteKind::DesertCity(_)))
|
||||||
|
&& !matches!(ctx.npc.profession(), Some(Profession::Merchant | Profession::Guard))
|
||||||
|
&& ctx.rng.gen_bool(1.0 / 3.0)
|
||||||
|
{
|
||||||
|
let wait_time = ctx.rng.gen_range(100.0..300.0);
|
||||||
|
if let Some(ws_id) = ctx.state.data().sites[visiting_site].world_site
|
||||||
|
&& let Some(ws) = ctx.index.sites.get(ws_id).site2()
|
||||||
|
&& let Some(arena) = ws.plots().find_map(|p| match p.kind() { PlotKind::DesertCityArena(a) => Some(a), _ => None})
|
||||||
|
{
|
||||||
|
// We don't use Z coordinates for seats because they are complicated to calculate from the Ramp procedural generation
|
||||||
|
// and using goto_2d seems to work just fine. However it also means that NPC will never go seat on the stands
|
||||||
|
// on the first floor of the arena. This is a compromise that was made because in the current arena procedural generation
|
||||||
|
// there is also no pathways to the stands on the first floor for NPCs.
|
||||||
|
let arena_center = Vec3::new(arena.center.x, arena.center.y, arena.base).as_::<f32>();
|
||||||
|
let stand_dist = arena.stand_dist as f32;
|
||||||
|
let seat_var_width = ctx.rng.gen_range(0..arena.stand_width) as f32;
|
||||||
|
let seat_var_length = ctx.rng.gen_range(-arena.stand_length..arena.stand_length) as f32;
|
||||||
|
// Select a seat on one of the 4 arena stands
|
||||||
|
let seat = match ctx.rng.gen_range(0..4) {
|
||||||
|
0 => Vec3::new(arena_center.x - stand_dist + seat_var_width, arena_center.y + seat_var_length, arena_center.z),
|
||||||
|
1 => Vec3::new(arena_center.x + stand_dist - seat_var_width, arena_center.y + seat_var_length, arena_center.z),
|
||||||
|
2 => Vec3::new(arena_center.x + seat_var_length, arena_center.y - stand_dist + seat_var_width, arena_center.z),
|
||||||
|
_ => Vec3::new(arena_center.x + seat_var_length, arena_center.y + stand_dist - seat_var_width, arena_center.z),
|
||||||
|
};
|
||||||
|
let look_dir = Dir::from_unnormalized(arena_center - seat);
|
||||||
|
// Walk to an arena seat, cheer, sit and dance
|
||||||
|
return casual(just(move |ctx, _| ctx.controller.say(None, Content::localized("npc-speech-arena")))
|
||||||
|
.then(goto_2d(seat.xy(), 0.6, 1.0).debug(|| "go to arena"))
|
||||||
|
// Turn toward the centre of the arena and watch the action!
|
||||||
|
.then(choose(move |ctx, _| if ctx.rng.gen_bool(0.3) {
|
||||||
|
casual(just(move |ctx,_| ctx.controller.do_cheer(look_dir)).repeat().stop_if(timeout(5.0)))
|
||||||
|
} else if ctx.rng.gen_bool(0.15) {
|
||||||
|
casual(just(move |ctx,_| ctx.controller.do_dance(look_dir)).repeat().stop_if(timeout(5.0)))
|
||||||
|
} else {
|
||||||
|
casual(just(move |ctx,_| ctx.controller.do_sit(look_dir)).repeat().stop_if(timeout(15.0)))
|
||||||
|
})
|
||||||
|
.repeat()
|
||||||
|
.stop_if(timeout(wait_time)))
|
||||||
|
.map(|_, _| ())
|
||||||
|
.boxed());
|
||||||
|
}
|
||||||
} else if matches!(ctx.npc.profession(), Some(Profession::Herbalist)) && ctx.rng.gen_bool(0.8)
|
} else if matches!(ctx.npc.profession(), Some(Profession::Herbalist)) && ctx.rng.gen_bool(0.8)
|
||||||
{
|
{
|
||||||
if let Some(forest_wpos) = find_forest(ctx) {
|
if let Some(forest_wpos) = find_forest(ctx) {
|
||||||
|
@ -220,7 +220,9 @@ fn on_tick(ctx: EventCtx<SimulateNpcs, OnTick>) {
|
|||||||
NpcActivity::Goto(_, _)
|
NpcActivity::Goto(_, _)
|
||||||
| NpcActivity::Gather(_)
|
| NpcActivity::Gather(_)
|
||||||
| NpcActivity::HuntAnimals
|
| NpcActivity::HuntAnimals
|
||||||
| NpcActivity::Dance,
|
| NpcActivity::Dance(_)
|
||||||
|
| NpcActivity::Cheer(_)
|
||||||
|
| NpcActivity::Sit(_),
|
||||||
) => {},
|
) => {},
|
||||||
None => {},
|
None => {},
|
||||||
}
|
}
|
||||||
@ -246,7 +248,11 @@ fn on_tick(ctx: EventCtx<SimulateNpcs, OnTick>) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(
|
Some(
|
||||||
NpcActivity::Gather(_) | NpcActivity::HuntAnimals | NpcActivity::Dance,
|
NpcActivity::Gather(_)
|
||||||
|
| NpcActivity::HuntAnimals
|
||||||
|
| NpcActivity::Dance(_)
|
||||||
|
| NpcActivity::Cheer(_)
|
||||||
|
| NpcActivity::Sit(_),
|
||||||
) => {
|
) => {
|
||||||
// TODO: Maybe they should walk around randomly
|
// TODO: Maybe they should walk around randomly
|
||||||
// when gathering resources?
|
// when gathering resources?
|
||||||
|
@ -238,6 +238,7 @@ impl<'a> AgentData<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
agent.action_state.timers[ActionTimers::TimerIdle as usize] = 0.0;
|
agent.action_state.timers[ActionTimers::TimerIdle as usize] = 0.0;
|
||||||
|
|
||||||
'activity: {
|
'activity: {
|
||||||
match agent.rtsim_controller.activity {
|
match agent.rtsim_controller.activity {
|
||||||
Some(NpcActivity::Goto(travel_to, speed_factor)) => {
|
Some(NpcActivity::Goto(travel_to, speed_factor)) => {
|
||||||
@ -371,10 +372,46 @@ impl<'a> AgentData<'a> {
|
|||||||
controller.push_action(ControlAction::Dance);
|
controller.push_action(ControlAction::Dance);
|
||||||
break 'activity; // Don't fall through to idle wandering
|
break 'activity; // Don't fall through to idle wandering
|
||||||
},
|
},
|
||||||
Some(NpcActivity::Dance) => {
|
Some(NpcActivity::Dance(dir)) => {
|
||||||
|
// Look at targets specified by rtsim
|
||||||
|
if let Some(look_dir) = dir {
|
||||||
|
controller.inputs.look_dir = look_dir;
|
||||||
|
if self.ori.look_dir().dot(look_dir.to_vec()) < 0.95 {
|
||||||
|
controller.inputs.move_dir = look_dir.to_vec().xy() * 0.01;
|
||||||
|
break 'activity;
|
||||||
|
} else {
|
||||||
|
controller.inputs.move_dir = Vec2::zero();
|
||||||
|
}
|
||||||
|
}
|
||||||
controller.push_action(ControlAction::Dance);
|
controller.push_action(ControlAction::Dance);
|
||||||
break 'activity; // Don't fall through to idle wandering
|
break 'activity; // Don't fall through to idle wandering
|
||||||
},
|
},
|
||||||
|
Some(NpcActivity::Cheer(dir)) => {
|
||||||
|
if let Some(look_dir) = dir {
|
||||||
|
controller.inputs.look_dir = look_dir;
|
||||||
|
if self.ori.look_dir().dot(look_dir.to_vec()) < 0.95 {
|
||||||
|
controller.inputs.move_dir = look_dir.to_vec().xy() * 0.01;
|
||||||
|
break 'activity;
|
||||||
|
} else {
|
||||||
|
controller.inputs.move_dir = Vec2::zero();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
controller.push_action(ControlAction::Talk);
|
||||||
|
break 'activity; // Don't fall through to idle wandering
|
||||||
|
},
|
||||||
|
Some(NpcActivity::Sit(dir)) => {
|
||||||
|
if let Some(look_dir) = dir {
|
||||||
|
controller.inputs.look_dir = look_dir;
|
||||||
|
if self.ori.look_dir().dot(look_dir.to_vec()) < 0.95 {
|
||||||
|
controller.inputs.move_dir = look_dir.to_vec().xy() * 0.01;
|
||||||
|
break 'activity;
|
||||||
|
} else {
|
||||||
|
controller.inputs.move_dir = Vec2::zero();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
controller.push_action(ControlAction::Sit);
|
||||||
|
break 'activity; // Don't fall through to idle wandering
|
||||||
|
},
|
||||||
Some(NpcActivity::HuntAnimals) => {
|
Some(NpcActivity::HuntAnimals) => {
|
||||||
if rng.gen::<f32>() < 0.1 {
|
if rng.gen::<f32>() < 0.1 {
|
||||||
self.choose_target(
|
self.choose_target(
|
||||||
|
@ -440,6 +440,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
// Update entity state
|
// Update entity state
|
||||||
if let Some(agent) = agent {
|
if let Some(agent) = agent {
|
||||||
agent.rtsim_controller.personality = npc.personality;
|
agent.rtsim_controller.personality = npc.personality;
|
||||||
|
agent.rtsim_controller.look_dir = npc.controller.look_dir;
|
||||||
agent.rtsim_controller.activity = npc.controller.activity;
|
agent.rtsim_controller.activity = npc.controller.activity;
|
||||||
agent
|
agent
|
||||||
.rtsim_controller
|
.rtsim_controller
|
||||||
|
@ -261,19 +261,8 @@ impl Civs {
|
|||||||
let world_dims = ctx.sim.get_aabr();
|
let world_dims = ctx.sim.get_aabr();
|
||||||
for _ in 0..initial_civ_count * 3 {
|
for _ in 0..initial_civ_count * 3 {
|
||||||
attempt(5, || {
|
attempt(5, || {
|
||||||
let (loc, kind) = match ctx.rng.gen_range(0..84) {
|
let (loc, kind) = match ctx.rng.gen_range(0..79) {
|
||||||
0..=5 => (
|
0..=4 => {
|
||||||
find_site_loc(
|
|
||||||
&mut ctx,
|
|
||||||
&ProximityRequirementsBuilder::new()
|
|
||||||
.avoid_all_of(this.castle_enemies(), 40)
|
|
||||||
.close_to_one_of(this.towns(), 20)
|
|
||||||
.finalize(&world_dims),
|
|
||||||
&SiteKind::Castle,
|
|
||||||
)?,
|
|
||||||
SiteKind::Castle,
|
|
||||||
),
|
|
||||||
28..=31 => {
|
|
||||||
if index.features().site2_giant_trees {
|
if index.features().site2_giant_trees {
|
||||||
(
|
(
|
||||||
find_site_loc(
|
find_site_loc(
|
||||||
@ -298,7 +287,7 @@ impl Civs {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
32..=37 => (
|
5..=10 => (
|
||||||
find_site_loc(
|
find_site_loc(
|
||||||
&mut ctx,
|
&mut ctx,
|
||||||
&ProximityRequirementsBuilder::new()
|
&ProximityRequirementsBuilder::new()
|
||||||
@ -308,8 +297,7 @@ impl Civs {
|
|||||||
)?,
|
)?,
|
||||||
SiteKind::Gnarling,
|
SiteKind::Gnarling,
|
||||||
),
|
),
|
||||||
// 32..=37 => (SiteKind::Citadel, (&castle_enemies, 20)),
|
11..=16 => (
|
||||||
38..=43 => (
|
|
||||||
find_site_loc(
|
find_site_loc(
|
||||||
&mut ctx,
|
&mut ctx,
|
||||||
&ProximityRequirementsBuilder::new()
|
&ProximityRequirementsBuilder::new()
|
||||||
@ -319,7 +307,7 @@ impl Civs {
|
|||||||
)?,
|
)?,
|
||||||
SiteKind::ChapelSite,
|
SiteKind::ChapelSite,
|
||||||
),
|
),
|
||||||
44..=49 => (
|
17..=22 => (
|
||||||
find_site_loc(
|
find_site_loc(
|
||||||
&mut ctx,
|
&mut ctx,
|
||||||
&ProximityRequirementsBuilder::new()
|
&ProximityRequirementsBuilder::new()
|
||||||
@ -329,17 +317,7 @@ impl Civs {
|
|||||||
)?,
|
)?,
|
||||||
SiteKind::Adlet,
|
SiteKind::Adlet,
|
||||||
),
|
),
|
||||||
/*50..=55 => (
|
23..=35 => (
|
||||||
find_site_loc(
|
|
||||||
&mut ctx,
|
|
||||||
&ProximityRequirementsBuilder::new()
|
|
||||||
.avoid_all_of(this.mine_site_enemies(), 40)
|
|
||||||
.finalize(&world_dims),
|
|
||||||
&SiteKind::DwarvenMine,
|
|
||||||
)?,
|
|
||||||
SiteKind::DwarvenMine,
|
|
||||||
),*/
|
|
||||||
56..=68 => (
|
|
||||||
find_site_loc(
|
find_site_loc(
|
||||||
&mut ctx,
|
&mut ctx,
|
||||||
&ProximityRequirementsBuilder::new()
|
&ProximityRequirementsBuilder::new()
|
||||||
@ -349,7 +327,7 @@ impl Civs {
|
|||||||
)?,
|
)?,
|
||||||
SiteKind::PirateHideout,
|
SiteKind::PirateHideout,
|
||||||
),
|
),
|
||||||
69..=75 => (
|
36..=42 => (
|
||||||
find_site_loc(
|
find_site_loc(
|
||||||
&mut ctx,
|
&mut ctx,
|
||||||
&ProximityRequirementsBuilder::new()
|
&ProximityRequirementsBuilder::new()
|
||||||
@ -359,6 +337,29 @@ impl Civs {
|
|||||||
)?,
|
)?,
|
||||||
SiteKind::JungleRuin,
|
SiteKind::JungleRuin,
|
||||||
),
|
),
|
||||||
|
/*43..=48 => (
|
||||||
|
find_site_loc(
|
||||||
|
&mut ctx,
|
||||||
|
&ProximityRequirementsBuilder::new()
|
||||||
|
.avoid_all_of(this.mine_site_enemies(), 40)
|
||||||
|
.finalize(&world_dims),
|
||||||
|
&SiteKind::DwarvenMine,
|
||||||
|
)?,
|
||||||
|
SiteKind::DwarvenMine,
|
||||||
|
),
|
||||||
|
49..=54 => (
|
||||||
|
find_site_loc(
|
||||||
|
&mut ctx,
|
||||||
|
&ProximityRequirementsBuilder::new()
|
||||||
|
.avoid_all_of(this.castle_enemies(), 40)
|
||||||
|
.close_to_one_of(this.towns(), 20)
|
||||||
|
.finalize(&world_dims),
|
||||||
|
&SiteKind::Castle,
|
||||||
|
)?,
|
||||||
|
SiteKind::Castle,
|
||||||
|
),
|
||||||
|
55..=60 => (SiteKind::Citadel, (&castle_enemies, 20)),
|
||||||
|
*/
|
||||||
_ => (
|
_ => (
|
||||||
find_site_loc(
|
find_site_loc(
|
||||||
&mut ctx,
|
&mut ctx,
|
||||||
|
@ -373,7 +373,6 @@ impl Site {
|
|||||||
| SiteKind::CliffTown(_)
|
| SiteKind::CliffTown(_)
|
||||||
| SiteKind::SavannahPit(_)
|
| SiteKind::SavannahPit(_)
|
||||||
| SiteKind::CoastalTown(_)
|
| SiteKind::CoastalTown(_)
|
||||||
| SiteKind::PirateHideout(_)
|
|
||||||
| SiteKind::DesertCity(_)
|
| SiteKind::DesertCity(_)
|
||||||
| SiteKind::Settlement(_)
|
| SiteKind::Settlement(_)
|
||||||
)
|
)
|
||||||
@ -417,9 +416,6 @@ impl SiteKind {
|
|||||||
SiteKind::CoastalTown(_) => {
|
SiteKind::CoastalTown(_) => {
|
||||||
Some(SiteKindMeta::Settlement(SettlementKindMeta::CoastalTown))
|
Some(SiteKindMeta::Settlement(SettlementKindMeta::CoastalTown))
|
||||||
},
|
},
|
||||||
SiteKind::PirateHideout(_) => {
|
|
||||||
Some(SiteKindMeta::Settlement(SettlementKindMeta::PirateHideout))
|
|
||||||
},
|
|
||||||
SiteKind::DesertCity(_) => {
|
SiteKind::DesertCity(_) => {
|
||||||
Some(SiteKindMeta::Settlement(SettlementKindMeta::DesertCity))
|
Some(SiteKindMeta::Settlement(SettlementKindMeta::DesertCity))
|
||||||
},
|
},
|
||||||
|
@ -1144,6 +1144,29 @@ impl Site {
|
|||||||
|
|
||||||
site.make_plaza(land, &mut rng);
|
site.make_plaza(land, &mut rng);
|
||||||
|
|
||||||
|
let size = 17.0 as i32;
|
||||||
|
let aabr = Aabr {
|
||||||
|
min: Vec2::broadcast(-size),
|
||||||
|
max: Vec2::broadcast(size),
|
||||||
|
};
|
||||||
|
|
||||||
|
let desert_city_arena =
|
||||||
|
plot::DesertCityArena::generate(land, &mut reseed(&mut rng), &site, aabr);
|
||||||
|
|
||||||
|
let desert_city_arena_alt = desert_city_arena.alt;
|
||||||
|
let plot = site.create_plot(Plot {
|
||||||
|
kind: PlotKind::DesertCityArena(desert_city_arena),
|
||||||
|
root_tile: aabr.center(),
|
||||||
|
tiles: aabr_tiles(aabr).collect(),
|
||||||
|
seed: rng.gen(),
|
||||||
|
});
|
||||||
|
|
||||||
|
site.blit_aabr(aabr, Tile {
|
||||||
|
kind: TileKind::Building,
|
||||||
|
plot: Some(plot),
|
||||||
|
hard_alt: Some(desert_city_arena_alt),
|
||||||
|
});
|
||||||
|
|
||||||
let build_chance = Lottery::from(vec![(20.0, 1), (10.0, 2)]);
|
let build_chance = Lottery::from(vec![(20.0, 1), (10.0, 2)]);
|
||||||
|
|
||||||
let mut temples = 0;
|
let mut temples = 0;
|
||||||
@ -1675,6 +1698,9 @@ impl Site {
|
|||||||
PlotKind::DesertCityTemple(desert_city_temple) => {
|
PlotKind::DesertCityTemple(desert_city_temple) => {
|
||||||
desert_city_temple.render_collect(self, canvas)
|
desert_city_temple.render_collect(self, canvas)
|
||||||
},
|
},
|
||||||
|
PlotKind::DesertCityArena(desert_city_arena) => {
|
||||||
|
desert_city_arena.render_collect(self, canvas)
|
||||||
|
},
|
||||||
PlotKind::Citadel(citadel) => citadel.render_collect(self, canvas),
|
PlotKind::Citadel(citadel) => citadel.render_collect(self, canvas),
|
||||||
PlotKind::Bridge(bridge) => bridge.render_collect(self, canvas),
|
PlotKind::Bridge(bridge) => bridge.render_collect(self, canvas),
|
||||||
PlotKind::PirateHideout(pirate_hideout) => {
|
PlotKind::PirateHideout(pirate_hideout) => {
|
||||||
|
@ -5,6 +5,7 @@ mod citadel;
|
|||||||
mod cliff_tower;
|
mod cliff_tower;
|
||||||
mod coastal_house;
|
mod coastal_house;
|
||||||
mod coastal_workshop;
|
mod coastal_workshop;
|
||||||
|
mod desert_city_arena;
|
||||||
mod desert_city_multiplot;
|
mod desert_city_multiplot;
|
||||||
mod desert_city_temple;
|
mod desert_city_temple;
|
||||||
pub mod dungeon;
|
pub mod dungeon;
|
||||||
@ -23,9 +24,9 @@ mod workshop;
|
|||||||
pub use self::{
|
pub use self::{
|
||||||
adlet::AdletStronghold, bridge::Bridge, castle::Castle, citadel::Citadel,
|
adlet::AdletStronghold, bridge::Bridge, castle::Castle, citadel::Citadel,
|
||||||
cliff_tower::CliffTower, coastal_house::CoastalHouse, coastal_workshop::CoastalWorkshop,
|
cliff_tower::CliffTower, coastal_house::CoastalHouse, coastal_workshop::CoastalWorkshop,
|
||||||
desert_city_multiplot::DesertCityMultiPlot, desert_city_temple::DesertCityTemple,
|
desert_city_arena::DesertCityArena, desert_city_multiplot::DesertCityMultiPlot,
|
||||||
dungeon::Dungeon, dwarven_mine::DwarvenMine, giant_tree::GiantTree,
|
desert_city_temple::DesertCityTemple, dungeon::Dungeon, dwarven_mine::DwarvenMine,
|
||||||
gnarling::GnarlingFortification, house::House, jungle_ruin::JungleRuin,
|
giant_tree::GiantTree, gnarling::GnarlingFortification, house::House, jungle_ruin::JungleRuin,
|
||||||
pirate_hideout::PirateHideout, savannah_hut::SavannahHut, savannah_pit::SavannahPit,
|
pirate_hideout::PirateHideout, savannah_hut::SavannahHut, savannah_pit::SavannahPit,
|
||||||
savannah_workshop::SavannahWorkshop, sea_chapel::SeaChapel, workshop::Workshop,
|
savannah_workshop::SavannahWorkshop, sea_chapel::SeaChapel, workshop::Workshop,
|
||||||
};
|
};
|
||||||
@ -74,6 +75,7 @@ pub enum PlotKind {
|
|||||||
Workshop(Workshop),
|
Workshop(Workshop),
|
||||||
DesertCityMultiPlot(DesertCityMultiPlot),
|
DesertCityMultiPlot(DesertCityMultiPlot),
|
||||||
DesertCityTemple(DesertCityTemple),
|
DesertCityTemple(DesertCityTemple),
|
||||||
|
DesertCityArena(DesertCityArena),
|
||||||
SeaChapel(SeaChapel),
|
SeaChapel(SeaChapel),
|
||||||
JungleRuin(JungleRuin),
|
JungleRuin(JungleRuin),
|
||||||
Plaza,
|
Plaza,
|
||||||
|
1267
world/src/site2/plot/desert_city_arena.rs
Normal file
1267
world/src/site2/plot/desert_city_arena.rs
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user