Skip to content
This repository has been archived by the owner on Sep 19, 2022. It is now read-only.

Refactor System Marker Components and Rename Creeps #53

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion assets/skill_defs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ defs:
key: NatureSummon
name: NatureSummon
friendly_name: nature_summon
description: Spawn a treant creep every 6s.
description: Spawn a treant pawn every 6s.
cooldown: 6.0
passive: true
conditions: []
Expand Down
4 changes: 2 additions & 2 deletions doc/create_leader.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ They have:
- `Sprite`: A letter and color for drawing in the terminal
- `SpriteIndex`: A number pointing to the 2d sprite in the spritesheet used by the game. There are 10 sprites per row and 10 rows, for a total of 100 sprites.
- `Team`: Indicates which team the entity is on. Used by AI to determine which entity to attack or follow.
- `SimpleMovement`: A marker component indicating that this entity should be moved by the SimpleMovementSystem (shared by creeps and leaders).
- `ProximityAttack`: A marker component indicating that this entity should attack nearby opponents.
- `MovementSystems`: A marker component indicating that this entity should be moved by the particular movement system specified by the enum variant.
- `ProximityAttackSystems`: A marker component indicating that this entity should attack nearby opponents following the particular proximity attack system specified by the enum variant.
- `Inventory`: An inventory of the items this leader has. This can easily be cloned from the default inventory (default_inventory).
- `SkillSet`: The skillset we defined earlier for this leader.
- `AiPath`: The path that this entity will follow while moving. This is used by the AI systems to move the entities around.
Expand Down
35 changes: 17 additions & 18 deletions src/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,11 @@ use crate::*;
pub struct Tower;
/// Allows this entity to attack other entities in proximity to it.
#[derive(new)]
pub struct ProximityAttack {
/// The radius at which we can attack.
pub radius: f32,
}
/// Allows this leader to attack other entities in proximity to it.
#[derive(new)]
pub struct Leader1ProximityAttack {
/// The radius at which we can attack.
pub radius: f32,
pub enum ProximityAttackSystems {
/// Standard proximity attack
SimpleProximityAttack(f32),
/// Leader proximity attack
Leader1ProximityAttack(f32),
}
/// Identifies which type is the companion
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
Expand All @@ -31,21 +27,24 @@ pub struct Leader(pub u8);
/// Adds a name to an entity.
pub struct Name(pub String);
/// Allows this entity to move to the closest enemy entity.
pub struct SimpleMovement;
/// Allows this entity to move to the closest enemy entity.
pub struct Leader1SimpleMovement;
/// Allows this entity to move a given distance away from the closest enemy entity.
pub struct Leader2SimpleMovement;
pub enum MovementSystems {
/// Standard movement
SimpleMovement,
/// Melee leader movement
Leader1SimpleMovement,
/// Ranged leader movement
Leader2SimpleMovement,
}
/// Makes this entity run back to its team's `Core` when low in health.
pub struct FleeToBase(pub f64);
/// Added on entities which temporarily cannot move.
pub struct IsCaught(pub bool);
/// Tracks whether or not Spell Steal has been used for heroes with that ability.
pub struct SpellSteal(pub bool);
/// Tags a creep.
pub struct Creep;
/// Tags a creep spawner. Contains the delay in ticks between spawns.
pub struct CreepSpawner(pub u32, pub u32);
/// Tags a pawn.
pub struct Pawn;
/// Tags a pawn spawner. Contains the delay in ticks between spawns.
pub struct PawnSpawner(pub u32, pub u32);
/// Tags a base.
pub struct Base;
/// Identifies mouse selectable entities
Expand Down
4 changes: 2 additions & 2 deletions src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ pub enum GameEvent {
TransferedGold(Entity, f64),
/// A leader died.
LeaderDied(u8),
/// Spawn a creep at the specified position in the specified team.
SpawnCreep(Point, Team),
/// Spawn a pawn at the specified position in the specified team.
SpawnPawn(Point, Team),
/// Spawns a leader using the `TeamLeaders`' index and a position.
SpawnLeader(Point, u8),
/// Set additional attack for an entity.
Expand Down
20 changes: 10 additions & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ const PLAY_WIDTH: u32 = 81;
const PLAY_HEIGHT: u32 = 50;
const SCREEN_WIDTH: u32 = 100;
const SCREEN_HEIGHT: u32 = 50;
const CREEP_SPAWN_TICKS: u32 = 125;
const CREEP_ATTACK_RADIUS: f32 = 2.1;
const PAWN_SPAWN_TICKS: u32 = 125;
const PAWN_ATTACK_RADIUS: f32 = 2.1;
const MELEE_LEADER_ATTACK_RADIUS: f32 = 2.1;
const RANGED_LEADER_ATTACK_RADIUS: f32 = 21.0;
const AOE_RADIUS: f32 = 4.0;
Expand Down Expand Up @@ -218,7 +218,7 @@ fn main() -> BError {
update_mouse_events_system,
update_collision_resource_system,
handle_action_points_system,
creep_spawner_system,
pawn_spawner_system,
simple_movement_system,
ai_pathing_system,
ai_movement_system,
Expand Down Expand Up @@ -259,7 +259,7 @@ fn main() -> BError {
leader_teleport_system,
root_system,
respawn_leader_driver,
spawn_creep_system,
spawn_pawn_system,
spawn_leader_system,
game_stats_updater_system,
);
Expand Down Expand Up @@ -313,7 +313,7 @@ fn main() -> BError {
/*register!(world, MultiSprite, Sprite, Team, Barrack, Tower, Core, Leader,
Name, SpriteIndex, StatSet<Stats>, EffectorSet<Effectors>,
SkillSet<Skills>, Inventory<Items, (), ()>, Point, SimpleMovement,
AiPath, AiDestination, Creep, Player, CollisionMap, CreepSpawner, Collision,
AiPath, AiDestination, Pawn, Player, CollisionMap, PawnSpawner, Collision,
ProximityAttack, TowerProjectile, GotoStraight, GotoEntity,);*/

// TODO reenable
Expand Down Expand Up @@ -403,12 +403,12 @@ fn main() -> BError {
Barrack,
default_stats.clone(),
);
// Creep spawners
// Pawn spawners
centity!(
world,
Point::new(x, y + 1),
CreepSpawner(0, CREEP_SPAWN_TICKS),
//CreepSpawner(0, 2))
PawnSpawner(0, PAWN_SPAWN_TICKS),
//PawnSpawner(0, 2))
Team::Other,
);
}
Expand All @@ -430,11 +430,11 @@ fn main() -> BError {
default_stats.clone(),
LineOfSight::new(15),
);
// Creep spawners
// Pawn spawners
centity!(
world,
Point::new(x, y - 1),
CreepSpawner(0, CREEP_SPAWN_TICKS),
PawnSpawner(0, PAWN_SPAWN_TICKS),
Team::Me,
LineOfSight::new(15),
);
Expand Down
9 changes: 2 additions & 7 deletions src/states/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,7 @@ pub struct DefaultState;

#[allow(unused_variables)]
impl minigene::State for DefaultState {
fn update(
&mut self,
world: &mut World,
dispatcher: &mut Dispatcher,
ctx: &mut BTerm,
) -> Trans {
fn update(&mut self, world: &mut World, dispatcher: &mut Dispatcher, ctx: &mut BTerm) -> Trans {
#[cfg(not(feature = "headless"))]
{
ctx.set_active_console(0);
Expand Down Expand Up @@ -56,5 +51,5 @@ impl minigene::State for DefaultState {
}

Trans::None
}
}
}
11 changes: 7 additions & 4 deletions src/systems/elephant_spawner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ pub fn elephant_spawner_system(
events: &Vec<SkillTriggerEvent<Skills>>,
stat_def: &StatDefinitions<Stats>,
teams: &mut Components<Team>,
proximity_attacks: &mut Components<ProximityAttack>,
simple_movements: &mut Components<SimpleMovement>,
proximity_attacks: &mut Components<ProximityAttackSystems>,
simple_movements: &mut Components<MovementSystems>,
stats: &mut Components<StatSet<Stats>>,
positions: &mut Components<Point>,
entities: &mut Entities,
Expand All @@ -22,10 +22,13 @@ pub fn elephant_spawner_system(
let elephant = entities.create();
positions.insert(elephant, pos.clone());
companions.insert(ev.0, Companion::Elephant(elephant));
simple_movements.insert(elephant, SimpleMovement);
simple_movements.insert(elephant, MovementSystems::SimpleMovement);
teams.insert(elephant, team);
stats.insert(elephant, stat_def.to_statset());
proximity_attacks.insert(elephant, ProximityAttack::new(CREEP_ATTACK_RADIUS));
proximity_attacks.insert(
elephant,
ProximityAttackSystems::SimpleProximityAttack(PAWN_ATTACK_RADIUS),
);
let bg = if team == Team::Me {
RGBA::named(GREEN)
} else {
Expand Down
54 changes: 30 additions & 24 deletions src/systems/leader1_proximity_attack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use rand::Rng;
/// Attacks entities that are close to this leader.
pub fn leader1_proximity_attack_system(
entities: &Entities,
proximity_attacks: &Components<Leader1ProximityAttack>,
proximity_attacks: &Components<ProximityAttackSystems>,
leaders: &Components<Leader>,
teams: &Components<Team>,
positions: &Components<Point>,
Expand All @@ -15,37 +15,43 @@ pub fn leader1_proximity_attack_system(
) -> SystemResult {
let mut v = vec![];
let mut rng = thread_rng();
for (e, _proximity, stat, pos, team) in
for (e, proximity, stat, pos, team) in
join!(&entities && &proximity_attacks && &stats && &positions && &teams)
{
let closest = find_closest_in_other_team(
team.unwrap(),
pos.unwrap(),
&teams,
&positions,
&stats,
&entities,
);
if let Some((target, _)) = closest {
let damage = stat.unwrap().stats.get(&Stats::Attack).unwrap().value;
v.push((e.unwrap().clone(), target.clone(), damage));
if let ProximityAttackSystems::Leader1ProximityAttack(radius) = proximity.unwrap() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact that the component/enum contains the word Systems is quite confusing. Could we change it to something else?

let closest = find_closest_in_other_team(
team.unwrap(),
pos.unwrap(),
&teams,
&positions,
&stats,
&entities,
);
if let Some((target, p)) = closest {
if dist(&p, pos.unwrap()) <= *radius {
let damage = stat.unwrap().stats.get(&Stats::Attack).unwrap().value;
v.push((e.unwrap().clone(), target.clone(), damage));
}
}
}
}
// 5% chance of getting caught if leaders are in range of each other
for (proximity, pos, team, _, mut caught) in
join!(&proximity_attacks && &positions && &teams && &leaders && &mut is_caught)
{
let mut vec = join!(&entities && &teams && &positions && &stats && &leaders)
.filter(|(_e, t, _, _, _)| *t.unwrap() != *team.unwrap())
.map(|(e, _, p, _, _)| (dist(pos.unwrap(), p.unwrap()), e.unwrap()))
.filter(|(d, _)| *d < proximity.unwrap().radius)
.collect::<Vec<_>>();
vec.sort_by(|e1, e2| e1.0.partial_cmp(&e2.0).unwrap());
let closest = vec.into_iter().next().map(|(_d, p)| p);
if let Some(_) = closest {
// 5% chance of leaders getting caught
if rng.gen_range(1, 21) == 1 {
caught.as_mut().unwrap().0 = true;
if let ProximityAttackSystems::Leader1ProximityAttack(radius) = proximity.unwrap() {
let mut vec = join!(&entities && &teams && &positions && &stats && &leaders)
.filter(|(_e, t, _, _, _)| *t.unwrap() != *team.unwrap())
.map(|(e, _, p, _, _)| (dist(pos.unwrap(), p.unwrap()), e.unwrap()))
.filter(|(d, _)| *d < *radius)
.collect::<Vec<_>>();
vec.sort_by(|e1, e2| e1.0.partial_cmp(&e2.0).unwrap());
let closest = vec.into_iter().next().map(|(_d, p)| p);
if let Some(_) = closest {
// 5% chance of leaders getting caught
if rng.gen_range(1, 21) == 1 {
caught.as_mut().unwrap().0 = true;
}
}
}
}
Expand Down
70 changes: 38 additions & 32 deletions src/systems/leader1_simple_movement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ use crate::*;
/// Moves melee leaders on the map.
pub fn leader1_simple_movement_system(
entities: &Entities,
simple_movements: &Components<Leader1SimpleMovement>,
simple_movements: &Components<MovementSystems>,
teams: &Components<Team>,
is_caught: &Components<IsCaught>,
stats: &Components<StatSet<Stats>>,
creeps: &Components<Creep>,
pawns: &Components<Pawn>,
leaders: &Components<Leader>,
retreats: &Components<FleeToBase>,
cores: &Components<Core>,
Expand All @@ -20,22 +20,26 @@ pub fn leader1_simple_movement_system(
let leader_team = leader_team.unwrap();
let caught = caught.unwrap();
if caught.0 {
for (e, _, team, pos) in join!(&entities && &simple_movements && &teams && &positions) {
let e = e.unwrap();
let team = team.unwrap();
let pos = pos.unwrap();
// find closest leader in other team
// TODO: optimize
let mut vec = join!(&teams && &positions && &stats && &leaders)
.filter(|(t, _, _, _)| *t.unwrap() != *team)
.map(|(_, p, _, _)| (dist(pos, p.unwrap()), p.unwrap().clone()))
.collect::<Vec<_>>();
vec.sort_by(|e1, e2| e1.0.partial_cmp(&e2.0).unwrap());
let closest = vec.into_iter().next().map(|(_d, p)| p);
if let Some(c) = closest {
targets.insert(e, AiDestination::new(c.clone())).unwrap();
} else {
targets.remove(e);
for (e, movement, team, pos) in
join!(&entities && &simple_movements && &teams && &positions)
{
if let MovementSystems::Leader1SimpleMovement = movement.unwrap() {
let e = e.unwrap();
let team = team.unwrap();
let pos = pos.unwrap();
// find closest leader in other team
// TODO: optimize
let mut vec = join!(&teams && &positions && &stats && &leaders)
.filter(|(t, _, _, _)| *t.unwrap() != *team)
.map(|(_, p, _, _)| (dist(pos, p.unwrap()), p.unwrap().clone()))
.collect::<Vec<_>>();
vec.sort_by(|e1, e2| e1.0.partial_cmp(&e2.0).unwrap());
let closest = vec.into_iter().next().map(|(_d, p)| p);
if let Some(c) = closest {
targets.insert(e, AiDestination::new(c.clone())).unwrap();
} else {
targets.remove(e);
}
}
}
} else {
Expand All @@ -57,20 +61,22 @@ pub fn leader1_simple_movement_system(
}
}
} else {
for (e, _, pos) in join!(&entities && &simple_movements && &positions) {
let e = e.unwrap();
let pos = pos.unwrap();
// find closest creep
// TODO: optimize
let mut vec = join!(&positions && &stats && &creeps)
.map(|(p, _, _)| (dist(pos, p.unwrap()), p.unwrap().clone()))
.collect::<Vec<_>>();
vec.sort_by(|e1, e2| e1.0.partial_cmp(&e2.0).unwrap());
let closest = vec.into_iter().next().map(|(_d, p)| p);
if let Some(c) = closest {
targets.insert(e, AiDestination::new(c.clone())).unwrap();
} else {
targets.remove(e);
for (e, movement, pos) in join!(&entities && &simple_movements && &positions) {
if let MovementSystems::Leader1SimpleMovement = movement.unwrap() {
let e = e.unwrap();
let pos = pos.unwrap();
// find closest pawn
// TODO: optimize
let mut vec = join!(&positions && &stats && &pawns)
.map(|(p, _, _)| (dist(pos, p.unwrap()), p.unwrap().clone()))
.collect::<Vec<_>>();
vec.sort_by(|e1, e2| e1.0.partial_cmp(&e2.0).unwrap());
let closest = vec.into_iter().next().map(|(_d, p)| p);
if let Some(c) = closest {
targets.insert(e, AiDestination::new(c.clone())).unwrap();
} else {
targets.remove(e);
}
}
}
}
Expand Down
Loading