tiles_tools 0.2.0

High-performance tile-based game development toolkit with comprehensive coordinate systems (hexagonal, square, triangular, isometric), pathfinding, ECS integration, and grid management.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
//! Core components for tile-based game entities.
//!
//! This module provides fundamental components that entities can have in a
//! tile-based game world. Components are pure data structures that describe
//! entity properties and capabilities.
//!
//! # Component Categories
//!
//! - **Spatial**: Position, Movement capabilities, Size/Shape
//! - **Gameplay**: Health, Stats, Inventory, Teams
//! - **Visual**: Sprites, Animations, Visibility
//! - **Behavioral**: AI, Player control, Triggers
//!
//! # Grid Awareness
//!
//! Many components are designed to work with any coordinate system through
//! generic type parameters, allowing seamless migration between grid types
//! or mixing entities from different coordinate systems in the same world.

use crate::coordinates::{ Distance, Neighbors };
use serde::{ Deserialize, Serialize };
// Note: PhantomData not needed for current components

// =============================================================================
// Spatial Components
// =============================================================================

/// Position component storing an entity's location in any coordinate system.
///
/// This is the fundamental spatial component that anchors entities to specific
/// grid locations. It supports all coordinate systems through generics.
///
/// # Examples
///
/// ```rust
/// use tiles_tools::ecs::Position;
/// use tiles_tools::coordinates::square::{ Coordinate as SquareCoord, FourConnected };
/// use tiles_tools::coordinates::hexagonal::{ Coordinate as HexCoord, Axial, Pointy };
/// 
/// // Square grid position
/// let square_pos = Position::new( SquareCoord::< FourConnected >::new( 3, 7 ) );
/// 
/// // Hexagonal grid position
/// let hex_pos = Position::new( HexCoord::< Axial, Pointy >::new( 2, -1 ) );
/// ```
#[ derive( Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize ) ]
pub struct Position< C >
{
  /// The coordinate location of this entity
  pub coord : C,
}

impl< C > Position< C >
{
  /// Creates a new position component at the specified coordinate.
  pub fn new( coord : C ) -> Self
  {
    Self { coord }
  }

  /// Updates the position to a new coordinate.
  pub fn set( &mut self, coord : C )
  {
    self.coord = coord;
  }

  /// Gets the current coordinate.
  pub fn get( &self ) -> &C
  {
    &self.coord
  }
}

impl< C > Position< C >
where
  C : Distance,
{
  /// Calculates distance to another position.
  pub fn distance_to( &self, other : &Position< C > ) -> u32
  {
    self.coord.distance( &other.coord )
  }
}

impl< C > Position< C >
where
  C : Neighbors,
{
  /// Gets all neighboring positions from this location.
  pub fn neighbors( &self ) -> Vec< Position< C > >
  {
    self.coord.neighbors().into_iter().map( Position::new ).collect()
  }

  /// Checks if another position is adjacent to this one.
  pub fn is_adjacent_to( &self, other : &Position< C > ) -> bool
  where
    C : PartialEq,
  {
    self.coord.neighbors().contains( &other.coord )
  }
}

/// Movement capability component defining how an entity can move.
///
/// This component describes an entity's movement characteristics including
/// speed, movement type, and any constraints or special abilities.
#[ derive( Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize ) ]
pub struct Movable
{
  /// Maximum movement range per action/turn
  pub range : u32,
  /// Whether the entity can move diagonally (for applicable grid types)
  pub diagonal_movement : bool,
  /// Whether the entity can move through other entities
  pub can_pass_through_entities : bool,
  /// Whether the entity can move through obstacles
  pub can_pass_through_obstacles : bool,
}

impl Movable
{
  /// Creates a new movable component with basic movement.
  pub fn new( range : u32 ) -> Self
  {
    Self
    {
      range,
      diagonal_movement : false,
      can_pass_through_entities : false,
      can_pass_through_obstacles : false,
    }
  }

  /// Creates a movable component with diagonal movement capability.
  pub fn with_diagonal( mut self ) -> Self
  {
    self.diagonal_movement = true;
    self
  }

  /// Creates a movable component that can pass through entities.
  pub fn with_entity_passthrough( mut self ) -> Self
  {
    self.can_pass_through_entities = true;
    self
  }

  /// Creates a movable component that can pass through obstacles.
  pub fn with_obstacle_passthrough( mut self ) -> Self
  {
    self.can_pass_through_obstacles = true;
    self
  }
}

/// Size component defining how much space an entity occupies.
///
/// This component describes the entity's spatial footprint, which can affect
/// collision detection, movement constraints, and rendering.
#[ derive( Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize ) ]
pub struct Size
{
  /// Width in grid units
  pub width : u32,
  /// Height in grid units  
  pub height : u32,
}

impl Size
{
  /// Creates a new size component.
  pub fn new( width : u32, height : u32 ) -> Self
  {
    Self { width, height }
  }

  /// Creates a square size (1x1).
  pub fn single() -> Self
  {
    Self::new( 1, 1 )
  }

  /// Creates a square size with the specified dimension.
  pub fn square( size : u32 ) -> Self
  {
    Self::new( size, size )
  }

  /// Calculates the total area occupied.
  pub fn area( &self ) -> u32
  {
    self.width * self.height
  }
}

// =============================================================================
// Gameplay Components
// =============================================================================

/// Health component for entities that can take damage.
///
/// This component manages hit points, damage, and healing for game entities.
#[ derive( Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize ) ]
pub struct Health
{
  /// Current health points
  pub current : u32,
  /// Maximum health points
  pub maximum : u32,
}

impl Health
{
  /// Creates a new health component with the specified maximum health.
  pub fn new( maximum : u32 ) -> Self
  {
    Self
    {
      current : maximum,
      maximum,
    }
  }

  /// Deals damage to this entity, capped at 0.
  pub fn damage( &mut self, amount : u32 )
  {
    self.current = self.current.saturating_sub( amount );
  }

  /// Heals this entity, capped at maximum health.
  pub fn heal( &mut self, amount : u32 )
  {
    self.current = ( self.current + amount ).min( self.maximum );
  }

  /// Sets health to maximum.
  pub fn full_heal( &mut self )
  {
    self.current = self.maximum;
  }

  /// Returns whether this entity is alive (health > 0).
  pub fn is_alive( &self ) -> bool
  {
    self.current > 0
  }

  /// Returns whether this entity is at full health.
  pub fn is_full_health( &self ) -> bool
  {
    self.current == self.maximum
  }

  /// Returns health as a percentage (0.0 to 1.0).
  pub fn health_percentage( &self ) -> f32
  {
    if self.maximum == 0
    {
      0.0
    }
    else
    {
      self.current as f32 / self.maximum as f32
    }
  }
}

/// Stats component for general entity attributes.
///
/// This component provides common RPG-style statistics that can affect
/// various game mechanics.
#[ derive( Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize ) ]
pub struct Stats
{
  /// Attack power for damage calculations
  pub attack : u32,
  /// Defense value for damage reduction
  pub defense : u32,
  /// Speed for turn order and movement
  pub speed : u32,
  /// Level for scaling and requirements
  pub level : u32,
}

impl Stats
{
  /// Creates new stats with specified values.
  pub fn new( attack : u32, defense : u32, speed : u32, level : u32 ) -> Self
  {
    Self { attack, defense, speed, level }
  }

  /// Creates basic level 1 stats.
  pub fn basic() -> Self
  {
    Self::new( 10, 10, 10, 1 )
  }

  /// Calculates damage dealt to a target with specified defense.
  pub fn calculate_damage( &self, target_defense : u32 ) -> u32
  {
    self.attack.saturating_sub( target_defense / 2 ).max( 1 )
  }
}

/// Team component for entity allegiances and relationships.
///
/// This component determines which entities are allies, enemies, or neutral
/// to each other, affecting AI behavior and combat mechanics.
#[ derive( Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize ) ]
pub struct Team
{
  /// Team identifier
  pub id : u32,
  /// Whether this team is hostile to others by default
  pub default_hostile : bool,
}

impl Team
{
  /// Creates a new team component.
  pub fn new( id : u32 ) -> Self
  {
    Self
    {
      id,
      default_hostile : false,
    }
  }

  /// Creates a hostile team component.
  pub fn hostile( id : u32 ) -> Self
  {
    Self
    {
      id,
      default_hostile : true,
    }
  }

  /// Checks if this team is allied with another team.
  pub fn is_allied_with( &self, other : &Team ) -> bool
  {
    self.id == other.id
  }

  /// Checks if this team is hostile to another team.
  pub fn is_hostile_to( &self, other : &Team ) -> bool
  {
    if self.id == other.id
    {
      false // Same team is never hostile
    }
    else
    {
      self.default_hostile || other.default_hostile
    }
  }
}

// =============================================================================
// Visual Components
// =============================================================================

/// Sprite component for visual representation.
///
/// This component defines how an entity appears when rendered, including
/// texture information and visual properties.
#[ derive( Debug, Clone, PartialEq, Serialize, Deserialize ) ]
pub struct Sprite
{
  /// Sprite texture identifier or path
  pub texture_id : String,
  /// Tint color (RGBA)
  pub tint : [ f32; 4 ],
  /// Scale factor for rendering
  pub scale : f32,
  /// Rotation in degrees
  pub rotation : f32,
  /// Whether the sprite is currently visible
  pub visible : bool,
}

impl Sprite
{
  /// Creates a new sprite component.
  pub fn new( texture_id : impl Into< String > ) -> Self
  {
    Self
    {
      texture_id : texture_id.into(),
      tint : [ 1.0, 1.0, 1.0, 1.0 ], // White, fully opaque
      scale : 1.0,
      rotation : 0.0,
      visible : true,
    }
  }

  /// Sets the tint color.
  pub fn with_tint( mut self, r : f32, g : f32, b : f32, a : f32 ) -> Self
  {
    self.tint = [ r, g, b, a ];
    self
  }

  /// Sets the scale.
  pub fn with_scale( mut self, scale : f32 ) -> Self
  {
    self.scale = scale;
    self
  }

  /// Sets the rotation.
  pub fn with_rotation( mut self, rotation : f32 ) -> Self
  {
    self.rotation = rotation;
    self
  }

  /// Hides the sprite.
  pub fn hide( &mut self )
  {
    self.visible = false;
  }

  /// Shows the sprite.
  pub fn show( &mut self )
  {
    self.visible = true;
  }
}

/// Animation component for animated sprites.
///
/// This component manages sprite animations including frame progression,
/// timing, and playback control.
#[ derive( Debug, Clone, PartialEq, Serialize, Deserialize ) ]
pub struct Animation
{
  /// Current frame index
  pub current_frame : u32,
  /// Total number of frames
  pub frame_count : u32,
  /// Time per frame in seconds
  pub frame_duration : f32,
  /// Time accumulated for current frame
  pub frame_timer : f32,
  /// Whether the animation should loop
  pub looping : bool,
  /// Whether the animation is currently playing
  pub playing : bool,
}

impl Animation
{
  /// Creates a new animation component.
  pub fn new( frame_count : u32, frame_duration : f32 ) -> Self
  {
    Self
    {
      current_frame : 0,
      frame_count,
      frame_duration,
      frame_timer : 0.0,
      looping : true,
      playing : true,
    }
  }

  /// Updates the animation by the specified time delta.
  pub fn update( &mut self, dt : f32 )
  {
    if !self.playing
    {
      return;
    }

    self.frame_timer += dt;

    if self.frame_timer >= self.frame_duration
    {
      self.frame_timer = 0.0;
      self.current_frame += 1;

      if self.current_frame >= self.frame_count
      {
        if self.looping
        {
          self.current_frame = 0;
        }
        else
        {
          self.current_frame = self.frame_count - 1;
          self.playing = false;
        }
      }
    }
  }

  /// Starts or resumes the animation.
  pub fn play( &mut self )
  {
    self.playing = true;
  }

  /// Pauses the animation.
  pub fn pause( &mut self )
  {
    self.playing = false;
  }

  /// Resets the animation to the first frame.
  pub fn reset( &mut self )
  {
    self.current_frame = 0;
    self.frame_timer = 0.0;
  }
}

// =============================================================================
// Behavioral Components
// =============================================================================

/// Player control component marking entities controlled by players.
///
/// This component identifies entities that should respond to player input
/// and receive special treatment in game systems.
#[ derive( Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize ) ]
pub struct PlayerControlled
{
  /// Player identifier
  pub player_id : u32,
}

impl PlayerControlled
{
  /// Creates a new player control component.
  pub fn new( player_id : u32 ) -> Self
  {
    Self { player_id }
  }
}

/// AI component for computer-controlled entities.
///
/// This component defines the artificial intelligence behavior and state
/// for entities that act autonomously.
#[ derive( Debug, Clone, PartialEq ) ]
pub struct AI
{
  /// Current AI state
  pub state : AIState,
  /// Target entity (if any)
  pub target : Option< hecs::Entity >,
  /// AI decision timer
  pub decision_timer : f32,
  /// Time between AI decisions
  pub decision_interval : f32,
}

/// AI behavioral states.
#[ derive( Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize ) ]
pub enum AIState
{
  /// Entity is idle and looking for something to do
  Idle,
  /// Entity is patrolling an area
  Patrolling,
  /// Entity is pursuing a target
  Pursuing,
  /// Entity is attacking a target
  Attacking,
  /// Entity is fleeing from danger
  Fleeing,
  /// Entity is guarding a specific location
  Guarding,
}

impl AI
{
  /// Creates a new AI component.
  pub fn new( decision_interval : f32 ) -> Self
  {
    Self
    {
      state : AIState::Idle,
      target : None,
      decision_timer : 0.0,
      decision_interval,
    }
  }

  /// Updates the AI decision timer.
  pub fn update( &mut self, dt : f32 )
  {
    self.decision_timer += dt;
  }

  /// Returns whether it's time for a new AI decision.
  pub fn should_make_decision( &self ) -> bool
  {
    self.decision_timer >= self.decision_interval
  }

  /// Resets the decision timer.
  pub fn reset_decision_timer( &mut self )
  {
    self.decision_timer = 0.0;
  }

  /// Sets a new target.
  pub fn set_target( &mut self, target : Option< hecs::Entity > )
  {
    self.target = target;
  }

  /// Changes the AI state.
  pub fn set_state( &mut self, state : AIState )
  {
    self.state = state;
  }
}

/// Trigger component for entities that can activate when certain conditions are met.
///
/// This component enables entities to respond to proximity, interaction, or
/// other game events with custom behaviors.
#[ derive( Debug, Clone, PartialEq, Serialize, Deserialize ) ]
pub struct Trigger
{
  /// The type of trigger condition
  pub trigger_type : TriggerType,
  /// Whether the trigger can be activated multiple times
  pub repeatable : bool,
  /// Whether the trigger has been activated
  pub activated : bool,
  /// Cooldown time between activations (if repeatable)
  pub cooldown : f32,
  /// Current cooldown timer
  pub cooldown_timer : f32,
}

/// Types of trigger conditions.
#[ derive( Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize ) ]
pub enum TriggerType
{
  /// Triggers when an entity enters the same tile
  OnEnter,
  /// Triggers when an entity leaves the tile
  OnExit,
  /// Triggers when an entity is adjacent
  OnProximity,
  /// Triggers when directly interacted with
  OnInteract,
  /// Triggers after a time delay
  OnTimer( u32 ), // time in game ticks
}

impl Trigger
{
  /// Creates a new trigger component.
  pub fn new( trigger_type : TriggerType ) -> Self
  {
    Self
    {
      trigger_type,
      repeatable : false,
      activated : false,
      cooldown : 0.0,
      cooldown_timer : 0.0,
    }
  }

  /// Makes the trigger repeatable with a cooldown.
  pub fn repeatable( mut self, cooldown : f32 ) -> Self
  {
    self.repeatable = true;
    self.cooldown = cooldown;
    self
  }

  /// Updates the trigger cooldown timer.
  pub fn update( &mut self, dt : f32 )
  {
    if self.cooldown_timer > 0.0
    {
      self.cooldown_timer -= dt;
    }
  }

  /// Returns whether the trigger can be activated.
  pub fn can_activate( &self ) -> bool
  {
    if self.activated && !self.repeatable
    {
      false
    }
    else
    {
      self.cooldown_timer <= 0.0
    }
  }

  /// Activates the trigger.
  pub fn activate( &mut self )
  {
    self.activated = true;
    if self.repeatable
    {
      self.cooldown_timer = self.cooldown;
    }
  }
}