Skip to content
Permalink
Browse files

Closed #152: Implemented basic roads system

  • Loading branch information...
ozkriff committed Aug 1, 2016
1 parent 4060a3d commit e8dd709d2437ec949c1ca6ec83c501e6cca0bdbc
@@ -113,7 +113,7 @@ fn get_unit_types(weapon_types: &[WeaponType]) -> Vec<UnitType> {
toughness: 9,
weapon_skill: 5,
weapon_type_id: weapon_type_id(weapon_types, "super_heavy_tank_gun"),
move_points: MovePoints{n: 2},
move_points: MovePoints{n: 5},
attack_points: AttackPoints{n: 1},
reactive_attack_points: AttackPoints{n: 1},
los_range: 7,
@@ -130,7 +130,7 @@ fn get_unit_types(weapon_types: &[WeaponType]) -> Vec<UnitType> {
toughness: 9,
weapon_skill: 5,
weapon_type_id: weapon_type_id(weapon_types, "heavy_tank_gun"),
move_points: MovePoints{n: 3},
move_points: MovePoints{n: 7},
attack_points: AttackPoints{n: 2},
reactive_attack_points: AttackPoints{n: 1},
los_range: 7,
@@ -147,7 +147,7 @@ fn get_unit_types(weapon_types: &[WeaponType]) -> Vec<UnitType> {
toughness: 9,
weapon_skill: 5,
weapon_type_id: weapon_type_id(weapon_types, "medium_tank_gun"),
move_points: MovePoints{n: 3},
move_points: MovePoints{n: 8},
attack_points: AttackPoints{n: 2},
reactive_attack_points: AttackPoints{n: 1},
los_range: 7,
@@ -164,7 +164,7 @@ fn get_unit_types(weapon_types: &[WeaponType]) -> Vec<UnitType> {
toughness: 9,
weapon_skill: 5,
weapon_type_id: weapon_type_id(weapon_types, "light_tank_gun"),
move_points: MovePoints{n: 4},
move_points: MovePoints{n: 10},
attack_points: AttackPoints{n: 2},
reactive_attack_points: AttackPoints{n: 1},
los_range: 7,
@@ -181,7 +181,7 @@ fn get_unit_types(weapon_types: &[WeaponType]) -> Vec<UnitType> {
toughness: 9,
weapon_skill: 7,
weapon_type_id: weapon_type_id(weapon_types, "medium_tank_gun"),
move_points: MovePoints{n: 4},
move_points: MovePoints{n: 10},
attack_points: AttackPoints{n: 2},
reactive_attack_points: AttackPoints{n: 1},
los_range: 7,
@@ -199,7 +199,7 @@ fn get_unit_types(weapon_types: &[WeaponType]) -> Vec<UnitType> {
weapon_skill: 7,
// TODO: "tank_gun" on field gun??
weapon_type_id: weapon_type_id(weapon_types, "medium_tank_gun"),
move_points: MovePoints{n: 2},
move_points: MovePoints{n: 7},
attack_points: AttackPoints{n: 2},
reactive_attack_points: AttackPoints{n: 1},
los_range: 7,
@@ -216,7 +216,7 @@ fn get_unit_types(weapon_types: &[WeaponType]) -> Vec<UnitType> {
toughness: 3,
weapon_skill: 5,
weapon_type_id: weapon_type_id(weapon_types, "machine_gun"),
move_points: MovePoints{n: 5},
move_points: MovePoints{n: 12},
attack_points: AttackPoints{n: 2},
reactive_attack_points: AttackPoints{n: 1},
los_range: 8,
@@ -233,7 +233,7 @@ fn get_unit_types(weapon_types: &[WeaponType]) -> Vec<UnitType> {
toughness: 3,
weapon_skill: 0,
weapon_type_id: weapon_type_id(weapon_types, "machine_gun"), // TODO: remove hack
move_points: MovePoints{n: 5},
move_points: MovePoints{n: 10},
attack_points: AttackPoints{n: 0},
reactive_attack_points: AttackPoints{n: 0},
los_range: 6,
@@ -250,7 +250,7 @@ fn get_unit_types(weapon_types: &[WeaponType]) -> Vec<UnitType> {
toughness: 2,
weapon_skill: 5,
weapon_type_id: weapon_type_id(weapon_types, "rifle"),
move_points: MovePoints{n: 3},
move_points: MovePoints{n: 9},
attack_points: AttackPoints{n: 2},
reactive_attack_points: AttackPoints{n: 1},
los_range: 6,
@@ -267,7 +267,7 @@ fn get_unit_types(weapon_types: &[WeaponType]) -> Vec<UnitType> {
toughness: 2,
weapon_skill: 5,
weapon_type_id: weapon_type_id(weapon_types, "submachine_gun"),
move_points: MovePoints{n: 3},
move_points: MovePoints{n: 9},
attack_points: AttackPoints{n: 2},
reactive_attack_points: AttackPoints{n: 1},
los_range: 6,
@@ -284,7 +284,7 @@ fn get_unit_types(weapon_types: &[WeaponType]) -> Vec<UnitType> {
toughness: 2,
weapon_skill: 5,
weapon_type_id: weapon_type_id(weapon_types, "rifle"),
move_points: MovePoints{n: 5},
move_points: MovePoints{n: 11},
attack_points: AttackPoints{n: 2},
reactive_attack_points: AttackPoints{n: 1},
los_range: 8,
@@ -301,7 +301,7 @@ fn get_unit_types(weapon_types: &[WeaponType]) -> Vec<UnitType> {
toughness: 2,
weapon_skill: 5,
weapon_type_id: weapon_type_id(weapon_types, "mortar"),
move_points: MovePoints{n: 3},
move_points: MovePoints{n: 7},
attack_points: AttackPoints{n: 2},
reactive_attack_points: AttackPoints{n: 0},
los_range: 6,
@@ -15,11 +15,14 @@ pub trait GameState {
&self.units()[id]
}

// TODO: Return iterator not vector
fn units_at(&self, pos: &MapPos) -> Vec<&Unit> {
let mut units = Vec::new();
for unit in self.units().values() {
if unit.pos.map_pos == *pos {
units.push(unit);
for map_pos in unit.pos.map_pos_iter() {
if map_pos == *pos {
units.push(unit);
}
}
}
units
@@ -28,8 +31,10 @@ pub trait GameState {
fn objects_at(&self, pos: &MapPos) -> Vec<&Object> {
let mut objects = Vec::new();
for object in self.objects().values() {
if object.pos.map_pos == *pos {
objects.push(object);
for map_pos in object.pos.map_pos_iter() {
if map_pos == *pos {
objects.push(object);
}
}
}
objects
@@ -7,6 +7,7 @@ use unit::{Unit};
use db::{Db};
use map::{Map, Terrain};
use game_state::{GameState, GameStateMut};
use dir::{Dir};
use ::{
CoreEvent,
FireMode,
@@ -38,9 +39,16 @@ impl InternalState {
pub fn new(map_size: &Size2) -> InternalState {
let mut map = Map::new(map_size);
// TODO: read from scenario.json?
*map.tile_mut(&MapPos{v: Vector2{x: 1, y: 2}}) = Terrain::Trees;
*map.tile_mut(&MapPos{v: Vector2{x: 1, y: 6}}) = Terrain::Trees;
*map.tile_mut(&MapPos{v: Vector2{x: 2, y: 6}}) = Terrain::Trees;
*map.tile_mut(&MapPos{v: Vector2{x: 4, y: 3}}) = Terrain::Trees;
*map.tile_mut(&MapPos{v: Vector2{x: 4, y: 4}}) = Terrain::Trees;
*map.tile_mut(&MapPos{v: Vector2{x: 4, y: 5}}) = Terrain::Trees;
*map.tile_mut(&MapPos{v: Vector2{x: 5, y: 1}}) = Terrain::Trees;
*map.tile_mut(&MapPos{v: Vector2{x: 6, y: 0}}) = Terrain::Trees;
*map.tile_mut(&MapPos{v: Vector2{x: 6, y: 1}}) = Terrain::Trees;
*map.tile_mut(&MapPos{v: Vector2{x: 6, y: 2}}) = Terrain::Trees;
let mut state = InternalState {
units: HashMap::new(),
objects: HashMap::new(),
@@ -52,9 +60,47 @@ impl InternalState {
state.add_big_building(&MapPos{v: Vector2{x: 6, y: 4}});
state.add_buildings(&MapPos{v: Vector2{x: 6, y: 5}}, 3);
state.add_buildings(&MapPos{v: Vector2{x: 6, y: 6}}, 1);
state.add_road(&[
MapPos{v: Vector2{x: 0, y: 1}},
MapPos{v: Vector2{x: 1, y: 1}},
MapPos{v: Vector2{x: 2, y: 1}},
MapPos{v: Vector2{x: 2, y: 2}},
MapPos{v: Vector2{x: 3, y: 2}},
MapPos{v: Vector2{x: 4, y: 2}},
MapPos{v: Vector2{x: 5, y: 2}},
MapPos{v: Vector2{x: 6, y: 3}},
MapPos{v: Vector2{x: 7, y: 3}},
MapPos{v: Vector2{x: 8, y: 3}},
MapPos{v: Vector2{x: 9, y: 3}},
]);
state.add_road(&[
MapPos{v: Vector2{x: 2, y: 2}},
MapPos{v: Vector2{x: 3, y: 3}},
MapPos{v: Vector2{x: 3, y: 4}},
MapPos{v: Vector2{x: 3, y: 5}},
MapPos{v: Vector2{x: 3, y: 6}},
MapPos{v: Vector2{x: 4, y: 6}},
MapPos{v: Vector2{x: 5, y: 7}},
]);
state
}

fn add_road(&mut self, path: &[MapPos]) {
for window in path.windows(2) {
let from = &window[0];
let to = &window[1];
let dir = Dir::get_dir_from_to(from, to);
let object = Object {
class: ObjectClass::Road,
pos: ExactPos {
map_pos: from.clone(),
slot_id: SlotId::TwoTiles(dir),
},
};
self.add_object(object);
}
}

fn add_object(&mut self, object: Object) {
let id = ObjectId{id: self.objects.len() as ZInt + 1};
self.objects.insert(id, object);
@@ -36,6 +36,7 @@ use db::{Db};
use ai::{Ai};
use fow::{Fow};
use fov::{fov};
use dir::{Dir};

#[derive(Clone)]
pub struct MovePoints{pub n: ZInt}
@@ -62,6 +63,7 @@ impl fmt::Display for MapPos {
pub enum SlotId {
Id(u8),
WholeTile,
TwoTiles(Dir),
// Air, // TODO: implement air units
}

@@ -71,6 +73,48 @@ pub struct ExactPos {
pub slot_id: SlotId,
}

pub struct ExactPosIter<'a> {
p: &'a ExactPos,
i: u8,
}

impl ExactPos {
pub fn map_pos_iter(&self) -> ExactPosIter {
ExactPosIter {
p: self,
i: 0,
}
}
}

impl<'a> Iterator for ExactPosIter<'a> {
type Item = MapPos;

fn next(&mut self) -> Option<Self::Item> {
let next_pos = match self.p.slot_id {
SlotId::Id(_) | SlotId::WholeTile => {
if self.i == 0 {
Some(self.p.map_pos.clone())
} else {
None
}
}
SlotId::TwoTiles(ref dir) => {
if self.i == 0 {
Some(self.p.map_pos.clone())
} else if self.i == 1 {
Some(Dir::get_neighbour_pos(&self.p.map_pos, dir))
} else {
None
}
}
};
self.i += 1;
next_pos
}
}

// TODO: return iterator?
impl AsRef<MapPos> for ExactPos {
fn as_ref(&self) -> &MapPos {
&self.map_pos
@@ -86,6 +130,7 @@ impl AsRef<MapPos> for MapPos {
#[derive(Debug, PartialEq, Clone)]
pub enum ObjectClass {
Building,
Road,
}

#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash, Clone)]
@@ -417,10 +462,10 @@ fn check_attack<S: GameState>(
}
let attacker_type = db.unit_type(&attacker.type_id);
let weapon_type = db.weapon_type(&attacker_type.weapon_type_id);
if distance(&attacker.pos, &defender.pos) > weapon_type.max_distance {
if distance(&attacker.pos.map_pos, &defender.pos.map_pos) > weapon_type.max_distance {
return Err(CommandError::OutOfRange);
}
if distance(&attacker.pos, &defender.pos) < weapon_type.min_distance {
if distance(&attacker.pos.map_pos, &defender.pos.map_pos) < weapon_type.min_distance {
return Err(CommandError::TooClose);
}
if !weapon_type.is_inderect
@@ -450,7 +495,8 @@ pub fn check_command<S: GameState>(
return Err(CommandError::BadUnitId);
}
let unit = state.unit(unit_id);
for pos in path {
for window in path.windows(2) {
let pos = &window[1];
if !is_exact_pos_free(db, state, &unit.type_id, pos) {
return Err(CommandError::BadPath);
}
@@ -481,7 +527,6 @@ pub fn check_command<S: GameState>(
return Err(CommandError::BadPassengerId);
}
let passenger = state.unit(passenger_id);
let pos = passenger.pos.clone();
let transporter = state.unit(transporter_id);
if !db.unit_type(&transporter.type_id).is_transporter {
return Err(CommandError::BadTransporterClass);
@@ -495,7 +540,7 @@ pub fn check_command<S: GameState>(
if transporter.passenger_id.is_some() {
return Err(CommandError::TransporterIsNotEmpty);
}
if distance(&transporter.pos, &pos) > 1 {
if distance(&transporter.pos.map_pos, &passenger.pos.map_pos) > 1 {
return Err(CommandError::TransporterIsTooFarAway);
}
// TODO: 0 -> real move cost of transport tile for passenger
@@ -516,7 +561,7 @@ pub fn check_command<S: GameState>(
if !db.unit_type(&transporter.type_id).is_transporter {
return Err(CommandError::BadTransporterClass);
}
if distance(&transporter.pos, pos) > 1 {
if distance(&transporter.pos.map_pos, &pos.map_pos) > 1 {
return Err(CommandError::UnloadDistanceIsTooBig);
}
if let None = transporter.passenger_id {
@@ -660,7 +705,13 @@ pub fn get_free_slot_id<S: GameState>(
let units_at = state.units_at(pos);
let unit_type = db.unit_type(type_id);
if unit_type.is_big {
if units_at.is_empty() && objects_at.is_empty() {
for object in &objects_at {
match object.class {
ObjectClass::Building => return None,
ObjectClass::Road => {},
}
}
if units_at.is_empty() {
return Some(SlotId::WholeTile);
} else {
return None;
@@ -670,7 +721,7 @@ pub fn get_free_slot_id<S: GameState>(
for unit in &units_at {
match unit.pos.slot_id {
SlotId::Id(slot_id) => slots[slot_id as usize] = true,
SlotId::WholeTile => return None,
SlotId::WholeTile | SlotId::TwoTiles(_) => return None,
}
}
if unit_type.class == UnitClass::Vehicle {
@@ -680,6 +731,7 @@ pub fn get_free_slot_id<S: GameState>(
slots[slot_id as usize] = true;
},
SlotId::WholeTile => return None,
SlotId::TwoTiles(_) => {},
}
}
}
@@ -709,7 +761,7 @@ pub fn is_exact_pos_free<S: GameState>(
return false;
}
}
&SlotId::WholeTile => return false,
&SlotId::WholeTile | &SlotId::TwoTiles(_) => return false,
}
}
true
@@ -986,17 +1038,19 @@ impl Core {
Command::Move{unit_id, path, mode} => {
let player_id = self.state.unit(&unit_id).player_id.clone();
let is_careful_move = mode == MoveMode::Hunt;
for pos in path {
for window in path.windows(2) {
let from = &window[0];
let to = &window[1];
let event = {
let unit = self.state.unit(&unit_id);
let cost = MovePoints {
n: tile_cost(&self.db, &self.state, unit, &pos).n
n: tile_cost(&self.db, &self.state, unit, from, to).n
* move_cost_modifier(&mode)
};
CoreEvent::Move {
unit_id: unit_id.clone(),
from: unit.pos.clone(),
to: pos.clone(),
from: from.clone(),
to: to.clone(),
mode: mode.clone(),
cost: cost,
}

0 comments on commit e8dd709

Please sign in to comment.
You can’t perform that action at this time.