- Add Arc<AHashMap> wrapper around floor_tiles, fixture_tiles, item_tiles - Copy-on-write semantics: Arc::make_mut clones only if other Arcs exist - Add insert_floor, insert_fixture, insert_item, remove_item methods - Add get_floor_mut, get_fixture_mut for visibility updates - Update all mutation sites to use new TileMap methods - Enables cheap Arc::clone for async pathfinding workers - Single-threaded pathfinding: no clone, direct access - Multi-threaded pathfinding: clone Arc, read without locks
170 lines
5.2 KiB
Rust
170 lines
5.2 KiB
Rust
use bevy::prelude::*;
|
|
use bevy_platform::collections::HashMap;
|
|
|
|
use crate::entities::item::decorations::ItemDecorations;
|
|
use crate::entities::item::material::{GemType, Material, MetalType};
|
|
use crate::entities::item::quality::Quality;
|
|
use crate::entities::item::types::ItemType;
|
|
use crate::entities::item::Item;
|
|
use crate::entities::item::ItemBundle;
|
|
use crate::entities::item::ItemName;
|
|
use crate::world::tiles::TileMap;
|
|
|
|
pub fn stain_fade_system(time: Res<Time>, mut items: Query<&mut Item>) {
|
|
if time.elapsed_secs_f64() as u32 % 10 == 0 {
|
|
for mut item in items.iter_mut() {
|
|
item.reduce_stain_time(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Ensures all items in item_tiles have the ItemRotationState component.
|
|
/// This handles items that were spawned before the rotation system was added,
|
|
/// or items that somehow got missing the component.
|
|
pub fn initialize_item_rotation_state(
|
|
mut commands: Commands,
|
|
items_without_state: Query<(Entity, &Item), Without<ItemRotationState>>,
|
|
) {
|
|
for (entity, _item) in items_without_state.iter() {
|
|
commands.entity(entity).insert(ItemRotationState {
|
|
should_be_visible: true,
|
|
});
|
|
}
|
|
}
|
|
|
|
// Helper function to create a decorated item (DEMO ONLY)
|
|
pub fn create_decorated_item(
|
|
commands: &mut Commands,
|
|
item_type: ItemType,
|
|
base_material: Material,
|
|
quality: Quality,
|
|
position: Vec3,
|
|
sprite: Sprite,
|
|
) -> Entity {
|
|
let mut decorations = ItemDecorations::new();
|
|
|
|
// Example: Add a ruby encrusting to valuable items
|
|
if quality >= Quality::Superior {
|
|
decorations.add_gem_encrusting(
|
|
Material::Gem(GemType::Ruby),
|
|
0.5, // Small gem
|
|
Quality::WellCrafted,
|
|
);
|
|
}
|
|
|
|
// Example: Add silver trim to masterwork items
|
|
if quality >= Quality::Masterwork {
|
|
decorations.add_trim(
|
|
Material::Metal(MetalType::Silver),
|
|
0.2, // Small amount of trim
|
|
quality,
|
|
);
|
|
}
|
|
|
|
// Example: Add engraving to exceptional+ items
|
|
if quality >= Quality::Exceptional {
|
|
decorations.add_engraving("a majestic dorf holding a pickaxe".to_string(), quality);
|
|
}
|
|
|
|
commands
|
|
.spawn(ItemBundle {
|
|
item: Item {
|
|
quality,
|
|
..Item::default()
|
|
},
|
|
item_type: item_type.clone(),
|
|
base_material,
|
|
decorations,
|
|
transform: Transform::from_translation(position),
|
|
visibility: Visibility::Visible,
|
|
sprite: sprite,
|
|
})
|
|
.insert(ItemName::new(item_type.name()))
|
|
.id()
|
|
}
|
|
|
|
#[derive(Resource)]
|
|
pub struct ItemRotationTimer {
|
|
timer: Timer,
|
|
current_indices: HashMap<IVec3, usize>,
|
|
}
|
|
|
|
impl Default for ItemRotationTimer {
|
|
fn default() -> Self {
|
|
Self {
|
|
timer: Timer::from_seconds(0.4f32, TimerMode::Repeating),
|
|
current_indices: HashMap::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Component)]
|
|
pub struct ItemRotationState {
|
|
pub should_be_visible: bool,
|
|
}
|
|
|
|
pub fn item_tile_management_system(
|
|
time: Res<Time>,
|
|
mut tilemap: ResMut<TileMap>,
|
|
mut rotation_timer: ResMut<ItemRotationTimer>,
|
|
mut item_query: Query<&mut ItemRotationState, With<Item>>,
|
|
) {
|
|
rotation_timer.timer.tick(time.delta());
|
|
|
|
if rotation_timer.timer.just_finished() {
|
|
let positions: Vec<IVec3> = tilemap.item_tiles.keys().copied().collect();
|
|
|
|
for position in positions {
|
|
let items = match tilemap.item_tiles.get(&position) {
|
|
Some(i) => i.clone(),
|
|
None => continue,
|
|
};
|
|
|
|
// Clean up empty tiles
|
|
if items.is_empty() {
|
|
tilemap.remove_item(&position);
|
|
rotation_timer.current_indices.remove(&position);
|
|
continue;
|
|
}
|
|
|
|
// Single item: ensure visible
|
|
if items.len() <= 1 {
|
|
if let Some(&entity_id) = items.first() {
|
|
if let Some(entity) = Entity::from_raw_u32(entity_id) {
|
|
if let Ok(mut rotation_state) = item_query.get_mut(entity) {
|
|
rotation_state.should_be_visible = true;
|
|
}
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// Rotate visibility
|
|
let current_index = rotation_timer
|
|
.current_indices
|
|
.get(&position)
|
|
.copied()
|
|
.unwrap_or(0);
|
|
|
|
for entity_id in &items {
|
|
if let Some(entity) = Entity::from_raw_u32(*entity_id) {
|
|
if let Ok(mut rotation_state) = item_query.get_mut(entity) {
|
|
rotation_state.should_be_visible = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
let next_index = (current_index + 1) % items.len();
|
|
if let Some(&next_entity_id) = items.get(next_index) {
|
|
if let Some(next_entity) = Entity::from_raw_u32(next_entity_id) {
|
|
if let Ok(mut rotation_state) = item_query.get_mut(next_entity) {
|
|
rotation_state.should_be_visible = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
rotation_timer.current_indices.insert(position, next_index);
|
|
}
|
|
}
|
|
}
|