Theropod charge attack

This commit is contained in:
Snowram 2021-03-14 14:23:54 +01:00
parent 9d7e8957bb
commit 60dd47cdea
48 changed files with 277 additions and 619 deletions

View File

@ -0,0 +1,19 @@
DashMelee(
energy_cost: 0,
base_damage: 150,
scaled_damage: 40,
base_poise_damage: 0,
scaled_poise_damage: 0,
base_knockback: 8.0,
scaled_knockback: 17.0,
range: 4.0,
angle: 45.0,
energy_drain: 0,
forward_speed: 2.0,
buildup_duration: 0.5,
charge_duration: 1.2,
swing_duration: 0.1,
recover_duration: 1.1,
infinite_charge: true,
is_interruptible: false,
)

View File

@ -184,6 +184,11 @@
secondary: "common.abilities.unique.theropodbird.triplestrike",
abilities: [],
),
Unique(TheropodCharge): (
primary: "common.abilities.unique.theropodbird.triplestrike",
secondary: "common.abilities.unique.theropodbasic.dash",
abilities: [],
),
Unique(ObjectTurret): (
primary: "common.abilities.unique.turret.arrows",
secondary: "common.abilities.unique.turret.arrows",

View File

@ -0,0 +1,18 @@
ItemDef(
name: "Theropod Charge",
description: "testing123",
kind: Tool((
kind: Unique(TheropodCharge),
hands: Two,
stats: Direct((
equip_time_secs: 0.01,
power: 1.0,
poise_strength: 1.0,
speed: 1.0,
crit_chance: 0.1,
crit_mult: 2.0,
)),
)),
quality: Low,
tags: [],
)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -197,7 +197,7 @@ impl Body {
theropod::Species::Woodraptor => 1.5,
theropod::Species::Archaeos => 3.5,
theropod::Species::Odonto => 3.5,
theropod::Species::Yale => 1.3,
theropod::Species::Yale => 0.8,
theropod::Species::Ntouka => 3.0,
_ => 1.8,
},
@ -249,6 +249,8 @@ impl Body {
quadruped_medium::Species::Saber => 2.0,
quadruped_medium::Species::Catoblepas => 2.9,
quadruped_medium::Species::Barghest => 2.5,
quadruped_medium::Species::Dreadhorn => 2.5,
quadruped_medium::Species::Moose => 2.5,
_ => 1.6,
},
Body::QuadrupedLow(body) => match body.species {
@ -263,7 +265,7 @@ impl Body {
theropod::Species::Sandraptor => 2.6,
theropod::Species::Woodraptor => 2.6,
theropod::Species::Sunlizard => 2.5,
theropod::Species::Yale => 2.8,
theropod::Species::Yale => 3.0,
_ => 8.0,
},
Body::BirdMedium(body) => match body.species {

View File

@ -421,6 +421,7 @@ pub enum UniqueKind {
QuadSmallBasic,
TheropodBasic,
TheropodBird,
TheropodCharge,
ObjectTurret,
WoodenSpear,
}

View File

@ -191,12 +191,16 @@ impl LoadoutBuilder {
Body::Theropod(theropod) => match theropod.species {
theropod::Species::Sandraptor
| theropod::Species::Snowraptor
| theropod::Species::Woodraptor
| theropod::Species::Yale => {
| theropod::Species::Woodraptor => {
main_tool = Some(Item::new_from_asset_expect(
"common.items.npc_weapons.unique.theropodbird",
));
},
theropod::Species::Yale => {
main_tool = Some(Item::new_from_asset_expect(
"common.items.npc_weapons.unique.theropodcharge",
));
},
_ => {
main_tool = Some(Item::new_from_asset_expect(
"common.items.npc_weapons.unique.theropodbasic",

View File

@ -1008,7 +1008,11 @@ impl<'a> AgentData<'a> {
circle_time: 2,
},
Some(ToolKind::Unique(UniqueKind::QuadMedCharge)) => Tactic::CircleCharge {
radius: 15,
radius: 12,
circle_time: 1,
},
Some(ToolKind::Unique(UniqueKind::TheropodCharge)) => Tactic::CircleCharge {
radius: 6,
circle_time: 1,
},

View File

@ -519,15 +519,15 @@ impl<'a> From<&'a Body> for SkeletonAttr {
(Roshwalr, _) => (1.3),
(Barghest, _) => (1.5),
(Antelope, _) => (1.2),
(Kelpie, _) => (1.4),
(Kelpie, _) => (1.35),
(Donkey, _) => (1.2),
(Horse, _) => (1.45),
(Horse, _) => (1.42),
(Zebra, _) => (1.3),
(Cattle, _) => (1.7),
(Highland, _) => (1.7),
(Bear, _) => (1.7),
(Yak, _) => (1.7),
(Camel, _) => (1.45),
(Camel, _) => (1.42),
(Dreadhorn, _) => (2.0),
(Moose, _) => (1.1),
(Snowleopard, _) => (1.2),

View File

@ -3,7 +3,6 @@ use super::{
SkeletonAttr, TheropodSkeleton,
};
use common::states::utils::StageSection;
//use std::ops::Rem;
pub struct AlphaAnimation;

View File

@ -0,0 +1,96 @@
use super::{
super::{vek::*, Animation},
SkeletonAttr, TheropodSkeleton,
};
use common::states::utils::StageSection;
pub struct DashAnimation;
impl Animation for DashAnimation {
type Dependency = (f32, f32, Option<StageSection>, f32);
type Skeleton = TheropodSkeleton;
#[cfg(feature = "use-dyn-lib")]
const UPDATE_FN: &'static [u8] = b"theropod_dash\0";
#[cfg_attr(feature = "be-dyn-lib", export_name = "theropod_dash")]
fn update_skeleton_inner(
skeleton: &Self::Skeleton,
(_velocity, global_time, stage_section, timer): Self::Dependency,
anim_time: f32,
_rate: &mut f32,
_s_a: &SkeletonAttr,
) -> Self::Skeleton {
let mut next = (*skeleton).clone();
let (movement1base, chargemovementbase, movement2base, movement3, legtell) =
match stage_section {
Some(StageSection::Buildup) => (anim_time.sqrt(), 0.0, 0.0, 0.0, anim_time),
Some(StageSection::Charge) => (1.0, 1.0, 0.0, 0.0, 0.0),
Some(StageSection::Swing) => (1.0, 1.0, anim_time.powi(4), 0.0, 1.0),
Some(StageSection::Recover) => (1.0, 1.0, 1.0, anim_time, 1.0),
_ => (0.0, 0.0, 0.0, 0.0, 0.0),
};
let pullback = 1.0 - movement3;
let subtract = global_time - timer;
let check = subtract - subtract.trunc();
let mirror = (check - 0.5).signum();
let movement1 = mirror * movement1base * pullback;
let movement2 = mirror * movement2base * pullback;
let movement1abs = movement1base * pullback;
let movement2abs = movement2base * pullback;
let legtwitch = (legtell * 6.0).sin() * pullback;
let legswing = legtell * pullback;
let chargeanim = (chargemovementbase * anim_time * 15.0).sin();
next.head.orientation =
Quaternion::rotation_x(movement1abs * -0.3 + chargeanim * 0.02 + movement2abs * 0.9)
* Quaternion::rotation_y(movement1 * 0.1 + movement2 * 0.2);
next.neck.orientation =
Quaternion::rotation_x(movement1abs * -0.8 + chargeanim * 0.05 + movement2abs * 0.9)
* Quaternion::rotation_y(movement1 * 0.1 + movement2 * 0.1);
next.jaw.orientation = Quaternion::rotation_x(movement1abs * -0.3 + movement2abs * 0.5);
next.chest_front.orientation = Quaternion::rotation_x(movement1abs * -0.2);
next.chest_back.orientation =
Quaternion::rotation_x(movement1abs * 0.2 + chargeanim * -0.05);
next.leg_l.orientation = Quaternion::rotation_x(movement1abs * -0.1);
next.leg_r.orientation = Quaternion::rotation_x(movement1abs * -0.1);
next.foot_l.orientation = Quaternion::rotation_x(movement1abs * -0.3);
next.foot_r.orientation = Quaternion::rotation_x(movement1abs * -0.3);
next.tail_front.orientation =
Quaternion::rotation_x(
0.1 + movement1abs * -0.1 + chargeanim * -0.05 + movement2abs * -0.3,
) * Quaternion::rotation_z(movement1 * -0.1 + movement2 * -0.2);
next.tail_back.orientation =
Quaternion::rotation_x(
0.1 + movement1abs * -0.1 + chargeanim * -0.05 + movement2abs * -0.3,
) * Quaternion::rotation_z(movement1 * -0.1 + movement2 * -0.2);
if legtell > 0.0 {
if mirror.is_sign_positive() {
next.leg_l.orientation = Quaternion::rotation_x(legswing * 1.1);
next.foot_l.orientation = Quaternion::rotation_x(legswing * -1.1 + legtwitch * 0.5);
next.leg_r.orientation = Quaternion::rotation_x(0.0);
next.foot_r.orientation = Quaternion::rotation_x(0.0);
} else {
next.leg_l.orientation = Quaternion::rotation_x(0.0);
next.foot_l.orientation = Quaternion::rotation_x(0.0);
next.leg_r.orientation = Quaternion::rotation_x(legswing * 1.1);
next.foot_r.orientation = Quaternion::rotation_x(legswing * -1.1 + legtwitch * 0.5);
}
};
next
}
}

View File

@ -1,13 +1,14 @@
pub mod alpha;
pub mod beta;
pub mod dash;
pub mod idle;
pub mod jump;
pub mod run;
// Reexports
pub use self::{
alpha::AlphaAnimation, beta::BetaAnimation, idle::IdleAnimation, jump::JumpAnimation,
run::RunAnimation,
alpha::AlphaAnimation, beta::BetaAnimation, dash::DashAnimation, idle::IdleAnimation,
jump::JumpAnimation, run::RunAnimation,
};
use super::{make_bone, vek::*, FigureBoneData, Skeleton};

View File

@ -3151,6 +3151,36 @@ impl FigureMgr {
),
}
},
CharacterState::DashMelee(s) => {
let stage_time = s.timer.as_secs_f32();
let stage_progress = match s.stage_section {
StageSection::Buildup => {
stage_time / s.static_data.buildup_duration.as_secs_f32()
},
StageSection::Charge => {
stage_time / s.static_data.charge_duration.as_secs_f32()
},
StageSection::Swing => {
stage_time / s.static_data.swing_duration.as_secs_f32()
},
StageSection::Recover => {
stage_time / s.static_data.recover_duration.as_secs_f32()
},
_ => 0.0,
};
anim::theropod::DashAnimation::update_skeleton(
&target_base,
(
vel.0.magnitude(),
time,
Some(s.stage_section),
state.state_time,
),
stage_progress,
&mut state_animation_rate,
skeleton_attr,
)
},
// TODO!
_ => target_base,
};

View File

@ -1,508 +0,0 @@
use super::image_frame::ImageFrame;
use conrod_core::{
builder_method, builder_methods, image, input::global::Global, position::Dimension, text,
widget, widget_ids, Color, Colorable, FontSize, Positionable, Sizeable, Ui, UiCell, Widget,
WidgetCommon, WidgetStyle,
};
use std::time::{Duration, Instant};
#[derive(Copy, Clone)]
struct Hover(widget::Id, [f64; 2]);
#[derive(Copy, Clone)]
enum HoverState {
Hovering(Hover),
Fading(Instant, Hover, Option<(Instant, widget::Id)>),
Start(Instant, widget::Id),
None,
}
// Spacing between the tooltip and mouse
const MOUSE_PAD_Y: f64 = 15.0;
const TEXT_COLOR: Color = Color::Rgba(1.0, 1.0, 1.0, 1.0); // Default text color
pub struct ItemTooltipManager {
tooltip_id: widget::Id,
state: HoverState,
// How long before a tooltip is displayed when hovering
hover_dur: Duration,
// How long it takes a tooltip to disappear
fade_dur: Duration,
// Current scaling of the ui
logical_scale_factor: f64,
}
impl ItemTooltipManager {
pub fn new(
mut generator: widget::id::Generator,
hover_dur: Duration,
fade_dur: Duration,
logical_scale_factor: f64,
) -> Self {
Self {
tooltip_id: generator.next(),
state: HoverState::None,
hover_dur,
fade_dur,
logical_scale_factor,
}
}
pub fn maintain(&mut self, input: &Global, logical_scale_factor: f64) {
self.logical_scale_factor = logical_scale_factor;
let current = &input.current;
if let Some(um_id) = current.widget_under_mouse {
match self.state {
HoverState::Hovering(hover) if um_id == hover.0 => (),
HoverState::Hovering(hover) => {
self.state =
HoverState::Fading(Instant::now(), hover, Some((Instant::now(), um_id)))
},
HoverState::Fading(_, _, Some((_, id))) if um_id == id => {},
HoverState::Fading(start, hover, _) => {
self.state = HoverState::Fading(start, hover, Some((Instant::now(), um_id)))
},
HoverState::Start(_, id) if um_id == id => (),
HoverState::Start(_, _) | HoverState::None => {
self.state = HoverState::Start(Instant::now(), um_id)
},
}
} else {
match self.state {
HoverState::Hovering(hover) => {
self.state = HoverState::Fading(Instant::now(), hover, None)
},
HoverState::Fading(start, hover, Some((_, _))) => {
self.state = HoverState::Fading(start, hover, None)
},
HoverState::Start(_, _) => self.state = HoverState::None,
HoverState::Fading(_, _, None) | HoverState::None => (),
}
}
// Handle fade timing
if let HoverState::Fading(start, _, maybe_hover) = self.state {
if start.elapsed() > self.fade_dur {
self.state = match maybe_hover {
Some((start, hover)) => HoverState::Start(start, hover),
None => HoverState::None,
};
}
}
}
#[allow(clippy::too_many_arguments)] // TODO: Pending review in #587
fn set_tooltip(
&mut self,
tooltip: &ItemTooltip,
title_text: &str,
desc_text: &str,
title_col: Color,
img_id: Option<image::Id>,
image_dims: Option<(f64, f64)>,
src_id: widget::Id,
ui: &mut UiCell,
) {
let tooltip_id = self.tooltip_id;
let mp_h = MOUSE_PAD_Y / self.logical_scale_factor;
let tooltip = |transparency, mouse_pos: [f64; 2], ui: &mut UiCell| {
// Fill in text and the potential image beforehand to get an accurate size for
// spacing
let tooltip = tooltip
.clone()
.title(title_text)
.desc(desc_text)
.title_col(title_col)
.image(img_id)
.image_dims(image_dims);
let [t_w, t_h] = tooltip.get_wh(ui).unwrap_or([0.0, 0.0]);
let [m_x, m_y] = [mouse_pos[0], mouse_pos[1]];
let (w_w, w_h) = (ui.win_w, ui.win_h);
// Determine position based on size and mouse position
// Flow to the top left of the mouse when there is space
let x = if (m_x + w_w / 2.0) > t_w {
m_x - t_w / 2.0
} else {
m_x + t_w / 2.0
};
let y = if w_h - (m_y + w_h / 2.0) > t_h + mp_h {
m_y + mp_h + t_h / 2.0
} else {
m_y - mp_h - t_h / 2.0
};
tooltip
.floating(true)
.transparency(transparency)
.x_y(x, y)
.set(tooltip_id, ui);
};
match self.state {
HoverState::Hovering(Hover(id, xy)) if id == src_id => tooltip(1.0, xy, ui),
HoverState::Fading(start, Hover(id, xy), _) if id == src_id => tooltip(
(0.1f32 - start.elapsed().as_millis() as f32 / self.hover_dur.as_millis() as f32)
.max(0.0),
xy,
ui,
),
HoverState::Start(start, id) if id == src_id && start.elapsed() > self.hover_dur => {
let xy = ui.global_input().current.mouse.xy;
self.state = HoverState::Hovering(Hover(id, xy));
tooltip(1.0, xy, ui);
},
_ => (),
}
}
}
pub struct ItemTooltipped<'a, W> {
inner: W,
tooltip_manager: &'a mut ItemTooltipManager,
title_text: &'a str,
desc_text: &'a str,
img_id: Option<image::Id>,
image_dims: Option<(f64, f64)>,
tooltip: &'a ItemTooltip<'a>,
title_col: Color,
}
impl<'a, W: Widget> ItemTooltipped<'a, W> {
pub fn tooltip_image(mut self, img_id: image::Id) -> Self {
self.img_id = Some(img_id);
self
}
pub fn tooltip_image_dims(mut self, dims: (f64, f64)) -> Self {
self.image_dims = Some(dims);
self
}
pub fn set(self, id: widget::Id, ui: &mut UiCell) -> W::Event {
let event = self.inner.set(id, ui);
self.tooltip_manager.set_tooltip(
self.tooltip,
self.title_text,
self.desc_text,
self.title_col,
self.img_id,
self.image_dims,
id,
ui,
);
event
}
}
pub trait ItemTooltipable {
// If `Tooltip` is expensive to construct accept a closure here instead.
fn with_item_tooltip<'a>(
self,
tooltip_manager: &'a mut ItemTooltipManager,
title_text: &'a str,
desc_text: &'a str,
tooltip: &'a ItemTooltip<'a>,
title_col: Color,
) -> ItemTooltipped<'a, Self>
where
Self: std::marker::Sized;
}
impl<W: Widget> ItemTooltipable for W {
fn with_item_tooltip<'a>(
self,
tooltip_manager: &'a mut ItemTooltipManager,
title_text: &'a str,
desc_text: &'a str,
tooltip: &'a ItemTooltip<'a>,
title_col: Color,
) -> ItemTooltipped<'a, W> {
ItemTooltipped {
inner: self,
tooltip_manager,
title_text,
desc_text,
img_id: None,
image_dims: None,
tooltip,
title_col,
}
}
}
/// Vertical spacing between elements of the tooltip
const V_PAD: f64 = 10.0;
/// Horizontal spacing between elements of the tooltip
const H_PAD: f64 = 10.0;
/// Default portion of inner width that goes to an image
const IMAGE_W_FRAC: f64 = 0.3;
/// Default width multiplied by the description font size
const DEFAULT_CHAR_W: f64 = 30.0;
/// Text vertical spacing factor to account for overhanging text
const TEXT_SPACE_FACTOR: f64 = 0.35;
/// A widget for displaying tooltips
#[derive(Clone, WidgetCommon)]
pub struct ItemTooltip<'a> {
#[conrod(common_builder)]
common: widget::CommonBuilder,
title_text: &'a str,
desc_text: &'a str,
title_col: Color,
image: Option<image::Id>,
image_dims: Option<(f64, f64)>,
style: Style,
transparency: f32,
image_frame: ImageFrame,
}
#[derive(Clone, Debug, Default, PartialEq, WidgetStyle)]
pub struct Style {
#[conrod(default = "Color::Rgba(1.0, 1.0, 1.0, 1.0)")]
pub color: Option<Color>,
title: widget::text::Style,
desc: widget::text::Style,
// add background imgs here
}
widget_ids! {
struct Ids {
title,
desc,
image_frame,
image,
}
}
pub struct State {
ids: Ids,
}
impl<'a> ItemTooltip<'a> {
builder_methods! {
pub desc_text_color { style.desc.color = Some(Color) }
pub title_font_size { style.title.font_size = Some(FontSize) }
pub desc_font_size { style.desc.font_size = Some(FontSize) }
pub title_justify { style.title.justify = Some(text::Justify) }
pub desc_justify { style.desc.justify = Some(text::Justify) }
image { image = Option<image::Id> }
title { title_text = &'a str }
desc { desc_text = &'a str }
image_dims { image_dims = Option<(f64, f64)> }
transparency { transparency = f32 }
title_col { title_col = Color}
}
pub fn new(image_frame: ImageFrame) -> Self {
ItemTooltip {
common: widget::CommonBuilder::default(),
style: Style::default(),
title_text: "",
desc_text: "",
transparency: 1.0,
image_frame,
image: None,
image_dims: None,
title_col: TEXT_COLOR,
}
}
/// Align the text to the left of its bounding **Rect**'s *x* axis range.
//pub fn left_justify(self) -> Self {
// self.justify(text::Justify::Left)
//}
/// Align the text to the middle of its bounding **Rect**'s *x* axis range.
//pub fn center_justify(self) -> Self {
// self.justify(text::Justify::Center)
//}
/// Align the text to the right of its bounding **Rect**'s *x* axis range.
//pub fn right_justify(self) -> Self {
// self.justify(text::Justify::Right)
//}
fn text_image_width(&self, total_width: f64) -> (f64, f64) {
let inner_width = (total_width - H_PAD * 2.0).max(0.0);
// Image defaults to 30% of the width
let image_w = if self.image.is_some() {
match self.image_dims {
Some((w, _)) => w,
None => (inner_width - H_PAD).max(0.0) * IMAGE_W_FRAC,
}
} else {
0.0
};
// Text gets the remaining width
let text_w = (inner_width
- if self.image.is_some() {
image_w + H_PAD
} else {
0.0
})
.max(0.0);
(text_w, image_w)
}
/// Specify the font used for displaying the text.
pub fn font_id(mut self, font_id: text::font::Id) -> Self {
self.style.title.font_id = Some(Some(font_id));
self.style.desc.font_id = Some(Some(font_id));
self
}
}
impl<'a> Widget for ItemTooltip<'a> {
type Event = ();
type State = State;
type Style = Style;
fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
State {
ids: Ids::new(id_gen),
}
}
fn style(&self) -> Self::Style { self.style.clone() }
fn update(self, args: widget::UpdateArgs<Self>) {
let widget::UpdateArgs {
id,
state,
rect,
style,
ui,
..
} = args;
// Widths
let (text_w, image_w) = self.text_image_width(rect.w());
// Apply transparency
let color = style.color(ui.theme()).alpha(self.transparency);
// Background image frame
self.image_frame
.wh(rect.dim())
.xy(rect.xy())
.graphics_for(id)
.parent(id)
.color(color)
.set(state.ids.image_frame, ui);
// Image
if let Some(img_id) = self.image {
widget::Image::new(img_id)
.w_h(image_w, self.image_dims.map_or(image_w, |(_, h)| h))
.graphics_for(id)
.parent(id)
.color(Some(color))
.top_left_with_margins_on(state.ids.image_frame, V_PAD, H_PAD)
.set(state.ids.image, ui);
}
// Spacing for overhanging text
let title_space = self.style.title.font_size(&ui.theme) as f64 * TEXT_SPACE_FACTOR;
// Title of tooltip
if !self.title_text.is_empty() {
let title = widget::Text::new(self.title_text)
.w(text_w)
.graphics_for(id)
.parent(id)
.with_style(self.style.title)
// Apply transparency
.color(self.title_col);
if self.image.is_some() {
title
.right_from(state.ids.image, H_PAD)
.align_top_of(state.ids.image)
} else {
title.top_left_with_margins_on(state.ids.image_frame, V_PAD, H_PAD)
}
.set(state.ids.title, ui);
}
// Description of tooltip
let desc = widget::Text::new(self.desc_text)
.w(text_w)
.graphics_for(id)
.parent(id)
// Apply transparency
.color(style.desc.color(ui.theme()).alpha(self.transparency))
.with_style(self.style.desc);
if !self.title_text.is_empty() {
desc.down_from(state.ids.title, V_PAD * 0.5 + title_space)
.align_left_of(state.ids.title)
} else if self.image.is_some() {
desc.right_from(state.ids.image, H_PAD)
.align_top_of(state.ids.image)
} else {
desc.top_left_with_margins_on(state.ids.image_frame, V_PAD, H_PAD)
}
.set(state.ids.desc, ui);
}
/// Default width is based on the description font size unless the text is
/// small enough to fit on a single line
fn default_x_dimension(&self, ui: &Ui) -> Dimension {
let single_line_title_w = widget::Text::new(self.title_text)
.with_style(self.style.title)
.get_w(ui)
.unwrap_or(0.0);
let single_line_desc_w = widget::Text::new(self.desc_text)
.with_style(self.style.desc)
.get_w(ui)
.unwrap_or(0.0);
let text_w = single_line_title_w.max(single_line_desc_w);
let inner_w = if self.image.is_some() {
match self.image_dims {
Some((w, _)) => w + text_w + H_PAD,
None => text_w / (1.0 - IMAGE_W_FRAC) + H_PAD,
}
} else {
text_w
};
let width =
inner_w.min(self.style.desc.font_size(&ui.theme) as f64 * DEFAULT_CHAR_W) + 2.0 * H_PAD;
Dimension::Absolute(width)
}
fn default_y_dimension(&self, ui: &Ui) -> Dimension {
let (text_w, image_w) = self.text_image_width(self.get_w(ui).unwrap_or(0.0));
let title_h = if self.title_text.is_empty() {
0.0
} else {
widget::Text::new(self.title_text)
.with_style(self.style.title)
.w(text_w)
.get_h(ui)
.unwrap_or(0.0)
+ self.style.title.font_size(&ui.theme) as f64 * TEXT_SPACE_FACTOR
+ 0.5 * V_PAD
};
let desc_h = if self.desc_text.is_empty() {
0.0
} else {
widget::Text::new(self.desc_text)
.with_style(self.style.desc)
.w(text_w)
.get_h(ui)
.unwrap_or(0.0)
+ self.style.desc.font_size(&ui.theme) as f64 * TEXT_SPACE_FACTOR
};
// Image defaults to square shape
let image_h = self.image_dims.map_or(image_w, |(_, h)| h);
// Title height + desc height + padding/spacing
let height = (title_h + desc_h).max(image_h) + 2.0 * V_PAD;
Dimension::Absolute(height)
}
}
impl<'a> Colorable for ItemTooltip<'a> {
builder_method!(color { style.color = Some(Color) });
}

View File

@ -289,7 +289,7 @@ pub fn apply_caves_supplement<'a>(
3 => match dynamic_rng.gen_range(0..2) {
0 => comp::biped_large::Species::Blueoni,
_ => comp::biped_large::Species::Redoni,
}
},
_ => comp::biped_large::Species::Troll,
};
comp::biped_large::Body::random_with(dynamic_rng, &species).into()

View File

@ -119,6 +119,43 @@ pub fn apply_wildlife_supplement<'a, R: Rng>(
is_underwater: false,
get_density: |c, _col| close(c.temp, CONFIG.snow_temp, 0.15) * BASE_DENSITY * 0.1,
},
// Tundra rock solitary ennemies
Entry {
make_entity: |pos, rng| {
EntityInfo::at(pos)
.with_body(
quadruped_low::Body::random_with(rng, &quadruped_low::Species::Rocksnapper)
.into(),
)
.with_alignment(Alignment::Enemy)
},
group_size: 1..2,
is_underwater: false,
get_density: |c, col| {
close(c.temp, CONFIG.snow_temp, 0.15) * BASE_DENSITY * col.rock * 1.0
},
},
// Taiga rare solitary ennemies
Entry {
make_entity: |pos, rng| {
EntityInfo::at(pos)
.with_body(match rng.gen_range(0..3) {
0 => biped_large::Body::random_with(rng, &biped_large::Species::Wendigo)
.into(),
_ => quadruped_medium::Body::random_with(
rng,
&quadruped_medium::Species::Dreadhorn,
)
.into(),
})
.with_alignment(Alignment::Enemy)
},
group_size: 1..2,
is_underwater: false,
get_density: |c, col| {
close(c.temp, CONFIG.snow_temp + 0.2, 0.2) * col.tree_density * BASE_DENSITY * 0.2
},
},
// Taiga pack ennemies
Entry {
make_entity: |pos, rng| {
@ -166,7 +203,7 @@ pub fn apply_wildlife_supplement<'a, R: Rng>(
Entry {
make_entity: |pos, rng| {
EntityInfo::at(pos)
.with_body(match rng.gen_range(0..6) {
.with_body(match rng.gen_range(0..5) {
0 => {
bird_medium::Body::random_with(rng, &bird_medium::Species::Eagle).into()
},
@ -181,11 +218,6 @@ pub fn apply_wildlife_supplement<'a, R: Rng>(
&quadruped_medium::Species::Moose,
)
.into(),
4 => quadruped_medium::Body::random_with(
rng,
&quadruped_medium::Species::Dreadhorn,
)
.into(),
_ => quadruped_medium::Body::random_with(
rng,
&quadruped_medium::Species::Tuskram,
@ -198,22 +230,6 @@ pub fn apply_wildlife_supplement<'a, R: Rng>(
is_underwater: false,
get_density: |c, _col| close(c.temp, CONFIG.snow_temp + 0.2, 0.6) * BASE_DENSITY * 5.0,
},
// Tundra rock solitary ennemies
Entry {
make_entity: |pos, rng| {
EntityInfo::at(pos)
.with_body(
quadruped_low::Body::random_with(rng, &quadruped_low::Species::Rocksnapper)
.into(),
)
.with_alignment(Alignment::Enemy)
},
group_size: 1..2,
is_underwater: false,
get_density: |c, col| {
close(c.temp, CONFIG.snow_temp, 0.15) * BASE_DENSITY * col.rock * 1.0
},
},
// Temperate solitary ennemies
Entry {
make_entity: |pos, rng| {
@ -247,7 +263,10 @@ pub fn apply_wildlife_supplement<'a, R: Rng>(
group_size: 1..2,
is_underwater: false,
get_density: |c, col| {
close(c.temp, CONFIG.temperate_temp, 0.35) * col.tree_density * BASE_DENSITY * 1.0
close(c.temp, CONFIG.temperate_temp + 0.1, 0.5)
* col.tree_density
* BASE_DENSITY
* 1.0
},
},
// Temperate pack wild
@ -318,8 +337,8 @@ pub fn apply_wildlife_supplement<'a, R: Rng>(
group_size: 1..8,
is_underwater: false,
get_density: |c, _col| {
close(c.temp, CONFIG.temperate_temp, 0.5)
* close(c.humidity, CONFIG.forest_hum, 0.4)
close(c.temp, CONFIG.temperate_temp + 0.1, 0.6)
* close(c.humidity, CONFIG.forest_hum, 0.6)
//* col.tree_density
* BASE_DENSITY
* 4.0
@ -329,7 +348,7 @@ pub fn apply_wildlife_supplement<'a, R: Rng>(
Entry {
make_entity: |pos, rng| {
EntityInfo::at(pos)
.with_body(match rng.gen_range(0..12) {
.with_body(match rng.gen_range(0..11) {
0 => quadruped_small::Body {
species: quadruped_small::Species::Fox,
body_type: quadruped_small::BodyType::Male,
@ -370,12 +389,7 @@ pub fn apply_wildlife_supplement<'a, R: Rng>(
&quadruped_medium::Species::Hirdrasil,
)
.into(),
9 => quadruped_medium::Body::random_with(
rng,
&quadruped_medium::Species::Kelpie,
)
.into(),
10 => quadruped_small::Body::random_with(
9 => quadruped_small::Body::random_with(
rng,
&quadruped_small::Species::Truffler,
)
@ -391,9 +405,9 @@ pub fn apply_wildlife_supplement<'a, R: Rng>(
group_size: 1..2,
is_underwater: false,
get_density: |c, _col| {
close(c.temp, CONFIG.temperate_temp, 0.5)
close(c.temp, CONFIG.temperate_temp + 0.1, 0.6)
* BASE_DENSITY
* close(c.humidity, CONFIG.forest_hum, 0.4)
* close(c.humidity, CONFIG.forest_hum, 0.6)
* 8.0
},
},
@ -421,7 +435,7 @@ pub fn apply_wildlife_supplement<'a, R: Rng>(
Entry {
make_entity: |pos, rng| {
EntityInfo::at(pos)
.with_body(match rng.gen_range(0..3) {
.with_body(match rng.gen_range(0..4) {
0 => quadruped_small::Body::random_with(
rng,
&quadruped_small::Species::Beaver,
@ -432,6 +446,11 @@ pub fn apply_wildlife_supplement<'a, R: Rng>(
body_type: quadruped_low::BodyType::Female,
}
.into(),
2 => quadruped_medium::Body::random_with(
rng,
&quadruped_medium::Species::Kelpie,
)
.into(),
_ => {
bird_medium::Body::random_with(rng, &bird_medium::Species::Duck).into()
},
@ -499,7 +518,7 @@ pub fn apply_wildlife_supplement<'a, R: Rng>(
.into()
},
1 => quadruped_low::Body::random_with(rng, &quadruped_low::Species::Asp)
.into(),
.into(),
_ => quadruped_medium::Body::random_with(
rng,
&quadruped_medium::Species::Tiger,
@ -511,8 +530,8 @@ pub fn apply_wildlife_supplement<'a, R: Rng>(
group_size: 1..2,
is_underwater: false,
get_density: |c, _col| {
close(c.temp, CONFIG.tropical_temp + 0.1, 0.3)
* close(c.humidity, CONFIG.jungle_hum, 0.3)
close(c.temp, CONFIG.tropical_temp + 0.2, 0.2)
* close(c.humidity, CONFIG.jungle_hum, 0.2)
* BASE_DENSITY
* 3.0
},
@ -539,8 +558,8 @@ pub fn apply_wildlife_supplement<'a, R: Rng>(
group_size: 1..2,
is_underwater: false,
get_density: |c, _col| {
close(c.temp, CONFIG.tropical_temp + 0.1, 0.3)
* close(c.humidity, CONFIG.jungle_hum, 0.3)
close(c.temp, CONFIG.tropical_temp + 0.2, 0.2)
* close(c.humidity, CONFIG.jungle_hum, 0.2)
* BASE_DENSITY
* 0.8
},
@ -573,8 +592,8 @@ pub fn apply_wildlife_supplement<'a, R: Rng>(
group_size: 1..2,
is_underwater: false,
get_density: |c, _col| {
close(c.temp, CONFIG.tropical_temp, 0.4)
* close(c.humidity, CONFIG.jungle_hum, 0.3)
close(c.temp, CONFIG.tropical_temp + 0.2, 0.3)
* close(c.humidity, CONFIG.jungle_hum, 0.2)
* BASE_DENSITY
* 8.0
},
@ -853,13 +872,12 @@ pub fn apply_wildlife_supplement<'a, R: Rng>(
make_entity: |pos, rng| {
EntityInfo::at(pos)
.with_body(
quadruped_low::Body::random_with(rng, &quadruped_low::Species::Crocodile)
.into(),
fish_medium::Body::random_with(rng, &fish_medium::Species::Icepike).into(),
)
.with_alignment(Alignment::Enemy)
},
group_size: 1..3,
is_underwater: false,
is_underwater: true,
get_density: |c, col| {
close(c.temp, CONFIG.snow_temp, 0.15) * col.tree_density * BASE_DENSITY * 5.0
},

View File

@ -902,12 +902,11 @@ impl Settlement {
object::Body::TrainingDummy.into()
},
0 => {
let species = match dynamic_rng.gen_range(0..6) {
let species = match dynamic_rng.gen_range(0..5) {
0 => quadruped_small::Species::Pig,
1 => quadruped_small::Species::Sheep,
2 => quadruped_small::Species::Goat,
3 => quadruped_small::Species::Dog,
4 => quadruped_small::Species::Goat,
_ => quadruped_small::Species::Cat,
};
is_human = false;