item flashing
This commit is contained in:
@@ -2,15 +2,10 @@ use bevy::prelude::*;
|
||||
|
||||
#[derive(Component, Debug)]
|
||||
pub struct Container {
|
||||
// Maximum weight this container can hold
|
||||
pub max_weight: u32,
|
||||
// Maximum number of items (None = unlimited)
|
||||
pub max_items: Option<u32>,
|
||||
// Current weight of contents
|
||||
pub current_weight: u32,
|
||||
// List of item entities contained
|
||||
pub contents: Vec<Entity>, // TODO - move away from Entity
|
||||
// Whether the container is currently open/accessible
|
||||
pub is_open: bool,
|
||||
}
|
||||
|
||||
|
||||
@@ -8,14 +8,10 @@ use crate::entities::item::types::ItemType;
|
||||
#[derive(Component, Debug)]
|
||||
#[require(Transform, Visibility)]
|
||||
pub struct Item {
|
||||
// How worn/damaged the item is (0-255, where 255 is completely destroyed)
|
||||
pub wear: u8,
|
||||
// The quality of craftsmanship for the base item
|
||||
pub quality: Quality,
|
||||
// Time until stains fade (in game ticks/turns),
|
||||
pub stain_time: u16,
|
||||
// Temperature of the item (for hot/cold items)
|
||||
pub temperature: i16, // Can be negative for very cold items
|
||||
pub temperature: i16, // Can be negative for cold items
|
||||
}
|
||||
|
||||
impl Default for Item {
|
||||
@@ -52,27 +48,19 @@ impl Item {
|
||||
|
||||
let total_weight = base_weight + decoration_weight;
|
||||
|
||||
// Convert to u32 (multiply by 1000 to get grams if density was in kg/unit)
|
||||
(total_weight * 1000.0) as u32
|
||||
// Convert to u32
|
||||
(total_weight) as u32
|
||||
}
|
||||
|
||||
// Calculate total value considering all factors
|
||||
pub fn calculate_value(
|
||||
&self,
|
||||
item_type: &ItemType,
|
||||
base_material: &Material,
|
||||
decorations: Option<&ItemDecorations>,
|
||||
) -> u32 {
|
||||
// Base value from item type and material
|
||||
let base_value = item_type.base_value() + base_material.base_value();
|
||||
|
||||
// Apply quality multiplier to base
|
||||
let quality_modified_value = base_value as f32 * self.quality.value_multiplier();
|
||||
|
||||
// Additional value from decorations
|
||||
let decoration_value = decorations.map(|d| d.total_decoration_value()).unwrap_or(0);
|
||||
|
||||
// Reduce value based on wear
|
||||
let wear_multiplier = (255 - self.wear) as f32 / 255.0;
|
||||
|
||||
let total_value = (quality_modified_value + decoration_value as f32) * wear_multiplier;
|
||||
@@ -80,33 +68,27 @@ impl Item {
|
||||
total_value as u32
|
||||
}
|
||||
|
||||
// Check if the item is destroyed due to wear
|
||||
pub fn is_destroyed(&self) -> bool {
|
||||
self.wear >= 255
|
||||
}
|
||||
|
||||
// Apply wear to the item
|
||||
pub fn add_wear(&mut self, wear_amount: u8) {
|
||||
self.wear = self.wear.saturating_add(wear_amount);
|
||||
}
|
||||
|
||||
// Check if item has any stains
|
||||
pub fn has_stains(&self) -> bool {
|
||||
self.stain_time > 0
|
||||
}
|
||||
|
||||
// Reduce stain time (call this periodically to fade stains)
|
||||
pub fn reduce_stain_time(&mut self, amount: u16) {
|
||||
self.stain_time = self.stain_time.saturating_sub(amount);
|
||||
}
|
||||
|
||||
// Add staining to the item
|
||||
pub fn add_stain(&mut self, duration: u16) {
|
||||
self.stain_time = self.stain_time.saturating_add(duration);
|
||||
}
|
||||
}
|
||||
|
||||
// Bundle for creating item entities
|
||||
#[derive(Bundle)]
|
||||
pub struct ItemBundle {
|
||||
pub item: Item,
|
||||
@@ -118,12 +100,9 @@ pub struct ItemBundle {
|
||||
pub sprite: Sprite,
|
||||
}
|
||||
|
||||
// Component for items that have names (can be generated or custom)
|
||||
#[derive(Component, Debug, Clone)]
|
||||
pub struct ItemName {
|
||||
// The base name of the item type
|
||||
pub base_name: String,
|
||||
// Custom name given by player or generated
|
||||
pub custom_name: Option<String>,
|
||||
}
|
||||
|
||||
@@ -144,25 +123,20 @@ impl ItemName {
|
||||
) -> String {
|
||||
let mut parts = Vec::new();
|
||||
|
||||
// Quality prefix
|
||||
let quality_name = item.quality.display_name();
|
||||
if !quality_name.is_empty() {
|
||||
parts.push(quality_name.to_string());
|
||||
}
|
||||
|
||||
// Base material
|
||||
parts.push(base_material.name());
|
||||
|
||||
// Item name
|
||||
parts.push(self.base_name.clone());
|
||||
|
||||
let mut result = parts.join(" ");
|
||||
|
||||
// Add decorations to the description
|
||||
if let Some(decorations) = decorations {
|
||||
let mut decoration_parts = Vec::new();
|
||||
|
||||
// Gem encrustings
|
||||
for gem in &decorations.gem_encrustings {
|
||||
let quality_prefix = if gem.quality != Quality::Ordinary {
|
||||
format!("{} ", gem.quality.display_name())
|
||||
@@ -176,7 +150,6 @@ impl ItemName {
|
||||
));
|
||||
}
|
||||
|
||||
// Trim materials
|
||||
for trim in &decorations.trim_materials {
|
||||
let quality_prefix = if trim.quality != Quality::Ordinary {
|
||||
format!("{} ", trim.quality.display_name())
|
||||
@@ -191,7 +164,6 @@ impl ItemName {
|
||||
decoration_parts.push(format!("with {} trim", trim_name));
|
||||
}
|
||||
|
||||
// Engravings
|
||||
for engraving in &decorations.engravings {
|
||||
let quality_prefix = if engraving.quality != Quality::Ordinary {
|
||||
format!("{} ", engraving.quality.display_name())
|
||||
@@ -209,7 +181,6 @@ impl ItemName {
|
||||
}
|
||||
}
|
||||
|
||||
// Custom name
|
||||
if let Some(custom) = &self.custom_name {
|
||||
result = format!("\"{}\" {}", custom, result);
|
||||
}
|
||||
|
||||
@@ -5,11 +5,8 @@ use crate::entities::item::quality::Quality;
|
||||
|
||||
#[derive(Component, Debug, Clone)]
|
||||
pub struct ItemDecorations {
|
||||
// Gems encrusted on the item
|
||||
pub gem_encrustings: Vec<GemEncrusting>,
|
||||
// Metal trim/bands
|
||||
pub trim_materials: Vec<TrimMaterial>,
|
||||
// Engravings on the item
|
||||
pub engravings: Vec<Engraving>,
|
||||
}
|
||||
|
||||
@@ -28,7 +25,6 @@ impl ItemDecorations {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
// Calculate total additional weight from decorations
|
||||
pub fn total_decoration_weight(&self) -> f32 {
|
||||
let gem_weight: f32 = self
|
||||
.gem_encrustings
|
||||
@@ -42,11 +38,9 @@ impl ItemDecorations {
|
||||
.map(|trim| trim.material.density() * trim.amount)
|
||||
.sum();
|
||||
|
||||
// Engravings don't add weight, they remove material
|
||||
gem_weight + trim_weight
|
||||
}
|
||||
|
||||
// Calculate total additional value from decorations
|
||||
pub fn total_decoration_value(&self) -> u32 {
|
||||
let gem_value: f32 = self
|
||||
.gem_encrustings
|
||||
@@ -97,26 +91,26 @@ impl ItemDecorations {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GemEncrusting {
|
||||
pub material: Material, // Should be a gem, but using material to gain access to its wider functions
|
||||
pub size: f32, // Size of the gem (affects weight and value)
|
||||
pub quality: Quality, // Quality of the gem cut
|
||||
pub size: f32,
|
||||
pub quality: Quality,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TrimMaterial {
|
||||
pub material: Material, // Usually metal for bands/trim
|
||||
pub amount: f32, // Amount of material used
|
||||
pub quality: Quality, // Quality of the trim work
|
||||
pub amount: f32,
|
||||
pub quality: Quality,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Engraving {
|
||||
pub subject: String, // What the engraving depicts
|
||||
pub quality: Quality, // Quality of the engraving
|
||||
pub subject: String,
|
||||
pub quality: Quality,
|
||||
}
|
||||
|
||||
impl Engraving {
|
||||
pub fn base_value(&self) -> f32 {
|
||||
// Base value for engravings (they're pure craftsmanship)
|
||||
// Base value for engravings (they're pure craftsmanship so a static value is fine)
|
||||
20.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ pub enum Material {
|
||||
}
|
||||
|
||||
impl Material {
|
||||
// Weight per unit volume (arbitrary units - adjust as needed)
|
||||
// Weight per unit volume (arbitrary units - TODO: Adjust later)
|
||||
pub fn density(&self) -> f32 {
|
||||
match self {
|
||||
Material::NA => 1.0,
|
||||
|
||||
@@ -6,18 +6,15 @@ use crate::entities::item::Item;
|
||||
|
||||
#[derive(Component, Debug)]
|
||||
pub struct Perishable {
|
||||
// How much the item has decayed (0-255)
|
||||
pub decay: u8,
|
||||
// How fast this item decays per tick
|
||||
pub decay_rate: u8,
|
||||
// What happens when fully decayed
|
||||
pub decay_result: DecayResult,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DecayResult {
|
||||
Disappear,
|
||||
Transform(ItemType, Material), // Transform into another item type with different material
|
||||
Transform(ItemType, Material), // Transform into another item type with different material (fish -> rotten fish)
|
||||
}
|
||||
|
||||
pub fn decay_system(
|
||||
@@ -26,18 +23,14 @@ pub fn decay_system(
|
||||
mut commands: Commands,
|
||||
) {
|
||||
for (entity, mut perishable, item, item_type, base_material) in perishable_items.iter_mut() {
|
||||
// Simple decay - you might want to make this more sophisticated
|
||||
if time.elapsed_secs_f64() as u32 % 60 == 0 {
|
||||
// Decay every 60 seconds
|
||||
perishable.decay = perishable.decay.saturating_add(perishable.decay_rate);
|
||||
|
||||
if perishable.decay >= 255 {
|
||||
match &perishable.decay_result {
|
||||
DecayResult::Disappear => {
|
||||
commands.entity(entity).despawn();
|
||||
}
|
||||
DecayResult::Transform(new_item_type, new_material) => {
|
||||
// Transform the item
|
||||
commands
|
||||
.entity(entity)
|
||||
.insert(new_item_type.clone())
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use bevy::prelude::*;
|
||||
|
||||
use crate::entities::item::{Item, ItemBundle, ItemDecorations, ItemType, Material, Quality};
|
||||
use crate::world::tiles::tilemap;
|
||||
use crate::world::VisibleGameEntity;
|
||||
|
||||
// Enum for misc item prefabs
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum MiscPrefab {
|
||||
RawMeat,
|
||||
@@ -12,11 +12,13 @@ pub enum MiscPrefab {
|
||||
|
||||
// Spawns a misc prefab at a given position.
|
||||
// These are all likely temporary to speed up development but will be replaced by semi-custom items everywhere.
|
||||
// As well as acting as demonstration of how to spawn items for the future.
|
||||
pub fn spawn_prefab(
|
||||
commands: &mut Commands,
|
||||
asset_server: &Res<AssetServer>,
|
||||
prefab: MiscPrefab,
|
||||
position: Vec3,
|
||||
tilemap: &mut ResMut<tilemap::TileMap>,
|
||||
) -> Entity {
|
||||
match prefab {
|
||||
MiscPrefab::RawMeat => {
|
||||
@@ -37,7 +39,16 @@ pub fn spawn_prefab(
|
||||
},
|
||||
})
|
||||
.id();
|
||||
commands.entity(meat).insert(VisibleGameEntity).id()
|
||||
let mut items = tilemap
|
||||
.item_tiles
|
||||
.get(&position.as_ivec3())
|
||||
.unwrap_or(&Vec::new())
|
||||
.clone();
|
||||
items.push(meat.index());
|
||||
tilemap
|
||||
.item_tiles
|
||||
.insert(position.as_ivec3(), items.clone());
|
||||
return commands.entity(meat).insert(VisibleGameEntity).id();
|
||||
}
|
||||
MiscPrefab::Coin => {
|
||||
let coin = commands
|
||||
@@ -57,6 +68,15 @@ pub fn spawn_prefab(
|
||||
},
|
||||
})
|
||||
.id();
|
||||
let mut items = tilemap
|
||||
.item_tiles
|
||||
.get(&position.as_ivec3())
|
||||
.unwrap_or(&Vec::new())
|
||||
.clone();
|
||||
items.push(coin.index());
|
||||
tilemap
|
||||
.item_tiles
|
||||
.insert(position.as_ivec3(), items.clone());
|
||||
commands.entity(coin).insert(VisibleGameEntity).id()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ pub enum Quality {
|
||||
Superior = 3,
|
||||
Exceptional = 4,
|
||||
Masterwork = 5,
|
||||
// Special artifact quality
|
||||
// Special artifact quality (created through moments of genius or madness)
|
||||
Artifact = 10,
|
||||
}
|
||||
|
||||
|
||||
@@ -8,9 +8,7 @@ use crate::entities::item::Item;
|
||||
use crate::entities::item::ItemBundle;
|
||||
use crate::entities::item::ItemName;
|
||||
|
||||
// System to reduce stain time over time
|
||||
pub fn stain_fade_system(time: Res<Time>, mut items: Query<&mut Item>) {
|
||||
// Fade stains every 10 seconds
|
||||
if time.elapsed_secs_f64() as u32 % 10 == 0 {
|
||||
for mut item in items.iter_mut() {
|
||||
item.reduce_stain_time(1);
|
||||
@@ -18,7 +16,7 @@ pub fn stain_fade_system(time: Res<Time>, mut items: Query<&mut Item>) {
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to create a decorated item
|
||||
// Helper function to create a decorated item (DEMO ONLY)
|
||||
pub fn create_decorated_item(
|
||||
commands: &mut Commands,
|
||||
item_type: ItemType,
|
||||
|
||||
@@ -2,22 +2,15 @@ use bevy::prelude::*;
|
||||
|
||||
#[derive(Component, Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum ItemType {
|
||||
// Weapons
|
||||
Weapon(WeaponType),
|
||||
// Armor/Clothing
|
||||
Armor(ArmorType),
|
||||
// Tools
|
||||
Tool(ToolType),
|
||||
// Consumables
|
||||
Food(FoodType),
|
||||
Drink(DrinkType),
|
||||
Medicine,
|
||||
// Crafting materials
|
||||
RawMaterial,
|
||||
// Trade goods
|
||||
Gem,
|
||||
Coin,
|
||||
// Misc
|
||||
Container,
|
||||
Book,
|
||||
Toy,
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
use crate::constants::TILE_SIZE;
|
||||
use crate::constants::*;
|
||||
use crate::entities::item::{
|
||||
create_decorated_item, spawn_prefab, FoodType, Item, ItemBundle, ItemDecorations, ItemType,
|
||||
Material, MiscPrefab, Quality, WoodType,
|
||||
};
|
||||
use crate::entities::item::{spawn_prefab, MiscPrefab};
|
||||
use crate::entities::shared_components::Ambulatory;
|
||||
use crate::world::tiles::tilemap;
|
||||
use crate::world::VisibleGameEntity;
|
||||
use bevy::ecs::spawn;
|
||||
use bevy::prelude::*;
|
||||
use bevy_rand::prelude::*;
|
||||
use rand::Rng;
|
||||
|
||||
// Pig bundle
|
||||
#[derive(Bundle)]
|
||||
pub struct Pig {
|
||||
ambulatory: Ambulatory,
|
||||
sprite: Sprite,
|
||||
transform: Transform,
|
||||
visibility: Visibility,
|
||||
drop_timer: PigDropTimer, // NEW
|
||||
drop_timer: PigDropTimer,
|
||||
}
|
||||
|
||||
impl Pig {
|
||||
@@ -43,11 +39,9 @@ impl Pig {
|
||||
}
|
||||
}
|
||||
|
||||
// Timer component for pigs dropping items
|
||||
#[derive(Component, Deref, DerefMut)]
|
||||
pub struct PigDropTimer(pub Timer);
|
||||
|
||||
// Spawn a handful of pigs
|
||||
pub fn spawn_pigs(
|
||||
mut commands: Commands,
|
||||
asset_server: Res<AssetServer>,
|
||||
@@ -70,12 +64,12 @@ pub fn spawn_pigs(
|
||||
}
|
||||
}
|
||||
|
||||
// System: make pigs drop items every 5 seconds
|
||||
pub fn pig_drop_system(
|
||||
mut commands: Commands,
|
||||
asset_server: Res<AssetServer>,
|
||||
time: Res<Time>,
|
||||
mut pigs: Query<(&mut PigDropTimer, &Transform)>,
|
||||
mut tilemap: ResMut<tilemap::TileMap>,
|
||||
) {
|
||||
for (mut timer, transform) in &mut pigs {
|
||||
timer.tick(time.delta());
|
||||
@@ -87,6 +81,7 @@ pub fn pig_drop_system(
|
||||
&asset_server,
|
||||
MiscPrefab::RawMeat,
|
||||
transform.translation,
|
||||
&mut tilemap,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ pub fn spawn_rabbits(
|
||||
mut rng_q: Query<&mut Entropy<WyRand>, With<Global>>,
|
||||
) {
|
||||
if let Ok(mut rng) = rng_q.single_mut() {
|
||||
// Spawn a handful of rabbits
|
||||
for _ in 0..15 {
|
||||
let rab = commands
|
||||
.spawn(Rabbit::new(
|
||||
|
||||
Reference in New Issue
Block a user