summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJustin Worthe <justin@worthe-it.co.za>2018-07-02 21:29:52 +0200
committerJustin Worthe <justin@worthe-it.co.za>2018-07-02 21:29:52 +0200
commit8251d5899a64515c9b2e8a71349dd4d2fcece69e (patch)
treef869d2e0cb543fbc39861afe33f6945338410f98 /src
parent8dd9517ae4b925fba5b825da04254412e039fa0c (diff)
Game engine working, except for teslas and choosing a move
Diffstat (limited to 'src')
-rw-r--r--src/engine/bitwise_engine.rs125
1 files changed, 112 insertions, 13 deletions
diff --git a/src/engine/bitwise_engine.rs b/src/engine/bitwise_engine.rs
index d8e7868..e3ca4c6 100644
--- a/src/engine/bitwise_engine.rs
+++ b/src/engine/bitwise_engine.rs
@@ -3,7 +3,9 @@ use engine::geometry::Point;
use engine::settings::{GameSettings};
use engine::{GameStatus, Player, GameState};
-const MAP_WIDTH: usize = 16;
+const FULL_MAP_WIDTH: u8 = 16;
+const SINGLE_MAP_WIDTH: u8 = FULL_MAP_WIDTH/2;
+const MAX_CONCURRENT_MISSILES: usize = SINGLE_MAP_WIDTH as usize / 2;
const MISSILE_COOLDOWN: usize = 3;
@@ -11,6 +13,9 @@ const DEFENCE_HEALTH: usize = 4; // '20' health is 4 hits
const MAX_TESLAS: usize = 2;
+const LEFT_COL_MASK: u64 = 0x0101010101010101;
+const RIGHT_COL_MASK: u64 = 0x8080808080808080;
+
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BitwiseGameState {
pub status: GameStatus,
@@ -29,7 +34,7 @@ pub struct PlayerBuildings {
pub energy_towers: u64,
pub missile_towers: [u64; MISSILE_COOLDOWN+1],
- pub missiles: [(u64, u64); MAP_WIDTH/4],
+ pub missiles: [(u64, u64); MAX_CONCURRENT_MISSILES],
pub tesla_cooldowns: [TeslaCooldown; MAX_TESLAS]
}
@@ -61,7 +66,9 @@ impl GameState for BitwiseGameState {
BitwiseGameState::add_left_missiles(&mut self.player_buildings);
BitwiseGameState::add_right_missiles(&mut self.opponent_buildings);
- //TODO: Move and collide missiles
+
+ BitwiseGameState::move_left_and_collide_missiles(settings, &mut self.player, &mut self.player_buildings, &mut self.opponent_buildings.missiles);
+ BitwiseGameState::move_right_and_collide_missiles(settings, &mut self.opponent, &mut self.opponent_buildings, &mut self.player_buildings.missiles);
BitwiseGameState::add_energy(settings, &mut self.player, &mut self.player_buildings);
BitwiseGameState::add_energy(settings, &mut self.opponent, &mut self.opponent_buildings);
@@ -91,12 +98,45 @@ impl BitwiseGameState {
}
}
+ /**
+ * Like with the expressive, this is to make things more
+ * comparable when writing tests, not for actual use in the
+ * engine.
+ */
+ pub fn sort(&mut self) {
+ for i in 0..MAX_CONCURRENT_MISSILES {
+ for j in i+1..MAX_CONCURRENT_MISSILES {
+ let move_down1 = !self.player_buildings.missiles[i].0 & self.player_buildings.missiles[j].0;
+ self.player_buildings.missiles[i].0 |= move_down1;
+ self.player_buildings.missiles[j].0 &= !move_down1;
+
+ let move_down2 = !self.player_buildings.missiles[i].1 & self.player_buildings.missiles[j].1;
+ self.player_buildings.missiles[i].1 |= move_down2;
+ self.player_buildings.missiles[j].1 &= !move_down2;
+
+ let move_down3 = !self.opponent_buildings.missiles[i].0 & self.opponent_buildings.missiles[j].0;
+ self.opponent_buildings.missiles[i].0 |= move_down3;
+ self.opponent_buildings.missiles[j].0 &= !move_down3;
+
+ let move_down4 = !self.opponent_buildings.missiles[i].1 & self.opponent_buildings.missiles[j].1;
+ self.opponent_buildings.missiles[i].1 |= move_down4;
+ self.opponent_buildings.missiles[j].1 &= !move_down4;
+ }
+ }
+ }
+
+ pub fn sorted(&self) -> BitwiseGameState {
+ let mut res = self.clone();
+ res.sort();
+ res
+ }
+
fn perform_command(settings: &GameSettings, player: &mut Player, player_buildings: &mut PlayerBuildings, command: Command) {
match command {
Command::Nothing => {},
Command::Build(p, b) => {
let blueprint = settings.building_settings(b);
- let bitfield = p.to_either_bitfield(settings.size.x);
+ let bitfield = p.to_either_bitfield(SINGLE_MAP_WIDTH);
// This is used internally. I should not be making
// invalid moves!
@@ -116,7 +156,7 @@ impl BitwiseGameState {
},
Command::Deconstruct(p) => {
let unconstructed_to_remove_index = player_buildings.unconstructed.iter().position(|ref b| b.pos == p);
- let deconstruct_mask = !(p.to_either_bitfield(settings.size.x) & player_buildings.buildings[0]);
+ let deconstruct_mask = !(p.to_either_bitfield(SINGLE_MAP_WIDTH) & player_buildings.buildings[0]);
debug_assert!(deconstruct_mask != 0 || unconstructed_to_remove_index.is_some());
@@ -150,7 +190,7 @@ impl BitwiseGameState {
let building_type = player_buildings.unconstructed[i].building_type;
let blueprint = settings.building_settings(building_type);
let pos = player_buildings.unconstructed[i].pos;
- let bitfield = pos.to_either_bitfield(settings.size.x);
+ let bitfield = pos.to_either_bitfield(SINGLE_MAP_WIDTH);
for health_tier in 0..4 {
if blueprint.health > health_tier*5 {
@@ -216,20 +256,79 @@ impl BitwiseGameState {
}
- fn move_and_collide_missiles_left(settings: &GameSettings, player_buildings: &mut PlayerBuildings, opponent: &mut Player) {
+ fn move_left_and_collide_missiles(settings: &GameSettings, opponent: &mut Player, opponent_buildings: &mut PlayerBuildings, player_missiles: &mut [(u64, u64); MAX_CONCURRENT_MISSILES]) {
+ for _ in 0..settings.attack.weapon_speed {
+ for i in 0..player_missiles.len() {
+ let about_to_hit_opponent = player_missiles[i].0 & LEFT_COL_MASK;
+ let damage = about_to_hit_opponent.count_ones() as u8 * settings.attack.weapon_damage;
+ opponent.health = opponent.health.saturating_sub(damage);
+ player_missiles[i].0 = (player_missiles[i].0 & !LEFT_COL_MASK) >> 1;
+
+ let swapping_sides = player_missiles[i].1 & LEFT_COL_MASK;
+ player_missiles[i].0 |= swapping_sides << 7;
+ player_missiles[i].1 = (player_missiles[i].1 & !LEFT_COL_MASK) >> 1;
+
+
+ let mut hits = 0;
+ for health_tier in (0..DEFENCE_HEALTH).rev() {
+ hits = opponent_buildings.buildings[health_tier] & player_missiles[i].0;
+ player_missiles[i].0 &= !hits;
+ opponent_buildings.buildings[health_tier] &= !hits;
+ }
+
+ let deconstruct_mask = !hits;
+ opponent_buildings.energy_towers &= deconstruct_mask;
+ for tier in 0..opponent_buildings.missile_towers.len() {
+ opponent_buildings.missile_towers[tier] &= deconstruct_mask;
+ }
+ for tesla in 0..opponent_buildings.tesla_cooldowns.len() {
+ if opponent_buildings.tesla_cooldowns[tesla].pos.to_either_bitfield(SINGLE_MAP_WIDTH) & deconstruct_mask == 0 {
+ opponent_buildings.tesla_cooldowns[tesla].active = false;
+ }
+ }
+ opponent_buildings.occupied &= deconstruct_mask;
+ }
+ }
+ }
+
+ fn move_right_and_collide_missiles(settings: &GameSettings, opponent: &mut Player, opponent_buildings: &mut PlayerBuildings, player_missiles: &mut [(u64, u64); MAX_CONCURRENT_MISSILES]) {
for _ in 0..settings.attack.weapon_speed {
- for i in 0..player_buildings.missiles.len() {
- //TODO this isn't so simple...
- //collide some with the player, others jump the boundary
- player_buildings.missiles[i].0 = player_buildings.missiles[i].0 << 1;
- //TODO Collide with buildings
+ for i in 0..player_missiles.len() {
+ let about_to_hit_opponent = player_missiles[i].1 & RIGHT_COL_MASK;
+ let damage = about_to_hit_opponent.count_ones() as u8 * settings.attack.weapon_damage;
+ opponent.health = opponent.health.saturating_sub(damage);
+ player_missiles[i].1 = (player_missiles[i].1 & !RIGHT_COL_MASK) << 1;
+
+ let swapping_sides = player_missiles[i].0 & RIGHT_COL_MASK;
+ player_missiles[i].1 |= swapping_sides >> 7;
+ player_missiles[i].0 = (player_missiles[i].0 & !RIGHT_COL_MASK) << 1;
+
+
+ let mut hits = 0;
+ for health_tier in (0..DEFENCE_HEALTH).rev() {
+ hits = opponent_buildings.buildings[health_tier] & player_missiles[i].1;
+ player_missiles[i].1 &= !hits;
+ opponent_buildings.buildings[health_tier] &= !hits;
+ }
+
+ let deconstruct_mask = !hits;
+ opponent_buildings.energy_towers &= deconstruct_mask;
+ for tier in 0..opponent_buildings.missile_towers.len() {
+ opponent_buildings.missile_towers[tier] &= deconstruct_mask;
+ }
+ for tesla in 0..opponent_buildings.tesla_cooldowns.len() {
+ if opponent_buildings.tesla_cooldowns[tesla].pos.to_either_bitfield(SINGLE_MAP_WIDTH) & deconstruct_mask == 0 {
+ opponent_buildings.tesla_cooldowns[tesla].active = false;
+ }
+ }
+ opponent_buildings.occupied &= deconstruct_mask;
}
}
}
fn add_energy(settings: &GameSettings, player: &mut Player, player_buildings: &mut PlayerBuildings) {
- player.energy_generated = player_buildings.energy_towers.count_ones() as u16 * settings.energy.energy_generated_per_turn;
+ player.energy_generated = settings.energy_income + player_buildings.energy_towers.count_ones() as u16 * settings.energy.energy_generated_per_turn;
player.energy += player.energy_generated;
}