use ggez::{Context, GameResult};
use ggez::graphics::{self, DrawParam, Color, Rect};
use crate::plants::{PlantType, PlantFactory};
use crate::core::resources::Resources;
use std::time::{Duration, Instant};
pub const CARD_WIDTH: f32 = 50.0;
pub const CARD_HEIGHT: f32 = 80.0;
pub const SHOP_START_X: f32 = 325.0;
pub const SHOP_START_Y: f32 = 8.0;
pub const CARD_SPACING: f32 = 10.0;
const COOLDOWN_TIMES: [u64; 3] = [
5000, 5000, 10000, ];
pub struct PlantCard {
pub plant_type: PlantType,
pub position: (f32, f32),
pub available: bool,
pub cooldown: Duration,
pub last_used: Option<Instant>,
pub rect: Rect,
}
impl PlantCard {
pub fn new(plant_type: PlantType, index: usize) -> Self {
let x = SHOP_START_X + (CARD_WIDTH + CARD_SPACING) * index as f32;
let y = SHOP_START_Y;
PlantCard {
plant_type,
position: (x, y),
available: true,
cooldown: Duration::from_millis(COOLDOWN_TIMES[plant_type as usize]),
last_used: None,
rect: Rect::new(x, y, CARD_WIDTH, CARD_HEIGHT),
}
}
pub fn update(&mut self, sun_count: i32) {
if let Some(last_used) = self.last_used {
if last_used.elapsed() < self.cooldown {
self.available = false;
} else {
self.available = sun_count >= self.plant_type.cost();
}
} else {
self.available = sun_count >= self.plant_type.cost();
}
}
pub fn draw(&self, ctx: &mut Context, resources: &Resources) -> GameResult {
let plant = PlantFactory::create_plant(self.plant_type);
let card_image = plant.get_card_image(resources);
graphics::draw(
ctx,
card_image,
DrawParam::default()
.dest([self.position.0, self.position.1])
.scale([0.9, 0.9])
)?;
if let Some(last_used) = self.last_used {
let elapsed = last_used.elapsed();
if elapsed < self.cooldown {
let cooldown_ratio = elapsed.as_millis() as f32 / self.cooldown.as_millis() as f32;
let mask_height = CARD_HEIGHT * (1.0 - cooldown_ratio);
let rect = graphics::Mesh::new_rectangle(
ctx,
graphics::DrawMode::fill(),
Rect::new(self.position.0, self.position.1, CARD_WIDTH, mask_height),
Color::new(0.0, 0.0, 0.0, 0.5),
)?;
graphics::draw(ctx, &rect, DrawParam::default())?;
}
}
let cost_text = graphics::Text::new(
graphics::TextFragment::new(self.plant_type.cost().to_string())
.color(Color::BLACK)
.scale(15.0)
);
let text_pos = [
self.position.0 + CARD_WIDTH/2.0 - cost_text.width(ctx) as f32 / 2.0,
self.position.1 + CARD_HEIGHT - 18.0
];
graphics::draw(ctx, &cost_text, DrawParam::default().dest(text_pos))?;
Ok(())
}
pub fn contains_point(&self, x: f32, y: f32) -> bool {
self.rect.contains([x, y])
}
pub fn use_card(&mut self) {
self.last_used = Some(Instant::now());
}
}
pub struct Shop {
pub cards: Vec<PlantCard>,
pub selected_plant: Option<PlantType>,
}
impl Shop {
pub fn new() -> Self {
let mut cards = Vec::new();
cards.push(PlantCard::new(PlantType::Sunflower, 0));
cards.push(PlantCard::new(PlantType::Peashooter, 1));
cards.push(PlantCard::new(PlantType::WallNut, 2));
Shop {
cards,
selected_plant: None,
}
}
pub fn update(&mut self, sun_count: i32) {
for card in &mut self.cards {
card.update(sun_count);
}
}
pub fn draw(&self, ctx: &mut Context, resources: &Resources) -> GameResult {
for card in &self.cards {
card.draw(ctx, resources)?;
}
if let Some(plant_type) = self.selected_plant {
let mouse_pos = ggez::input::mouse::position(ctx);
let x = mouse_pos.x;
let y = mouse_pos.y;
let plant = PlantFactory::create_plant(plant_type);
let image = plant.get_current_frame_image(resources, 0);
graphics::draw(
ctx,
image,
DrawParam::default()
.dest([x - 30.0, y - 30.0])
.scale([0.6, 0.6])
.color(Color::new(1.0, 1.0, 1.0, 0.7)),
)?;
}
Ok(())
}
pub fn handle_click(&mut self, x: f32, y: f32, sun_count: i32) -> Option<PlantType> {
if self.selected_plant.is_some() {
self.selected_plant = None;
return None;
}
for card in &mut self.cards {
if card.contains_point(x, y) && card.available {
let plant_type = card.plant_type;
if sun_count >= plant_type.cost() {
self.selected_plant = Some(plant_type);
card.use_card();
return Some(plant_type);
}
}
}
None
}
}