gave ability for terrain to have multiple aliases

This commit is contained in:
Dave White 2004-04-12 20:04:52 +00:00
parent a05c618c27
commit d08630afe7
21 changed files with 238 additions and 142 deletions

View file

@ -12,7 +12,6 @@ char="~"
image=ocean
name=deep water
char=s
blue=150
submerge=0.5
unit_height_adjust=-3
[/terrain]
@ -22,7 +21,6 @@ image=coast
name=shallow water
adjacent_image=coast
char=c
blue=250
submerge=0.4
unit_height_adjust=-4
[/terrain]
@ -41,10 +39,12 @@ image=flag-coast-neutral
adjacent_image=coast
name=mermen village
char=Z
aliasof=t
aliasof=c
no_overlay=true
submerge=0.4
unit_height_adjust=-4
heals=true
gives_income=true
[/terrain]
[terrain]
@ -52,9 +52,7 @@ image=pier
name=pier
adjacent_image=coast
char=p
red=104
green=63
aliasof=g
aliasof=gc
#make this only overlay deep water, not shallow water
no_overlay=true
[/terrain]
@ -72,45 +70,39 @@ image=flag-swampwater-neutral
adjacent_image=swampwater
name=swamp village
char=Y
aliasof=t
aliasof=tw
no_overlay=true
submerge=0.4
unit_height_adjust=-3
heals=true
gives_income=true
[/terrain]
[terrain]
image=bridge-n-s
name=bridge
char=|
green=150
red=150
aliasof=g
aliasof=gc
[/terrain]
[terrain]
image=bridge-ne-sw
name=bridgediag1
char=/
green=150
red=150
aliasof=g
aliasof=gc
[/terrain]
[terrain]
image=bridge-se-nw
name=bridgediag2
char=\
green=150
red=150
aliasof=g
aliasof=gc
[/terrain]
[terrain]
image=desert,desert,desert,desert,desert,desert,desert-plant
name=sand
char=d
red=200
green=200
light=true
[/terrain]
@ -119,9 +111,6 @@ light=true
image=road
name=road
char=R
red=140
green=140
blue=140
aliasof=g
[/terrain]
@ -129,8 +118,6 @@ aliasof=g
image=dirt
name=dirt
char=r
red=104
green=63
aliasof=g
[/terrain]
@ -140,19 +127,17 @@ aliasof=g
image=grassland,grassland,grassland,grassland,grassland,grassland,grassland,grassland,grassland,grassland,grassland,grassland,grassland,grassland,grassland,grassland,grassland,grassland,grassland,grassland,grassland,grassland,grassland-flowers,grassland-flowers,grassland-rocks
name=grassland
char=g
green=200
[/terrain]
[terrain]
image=flag-neutral
name=village
char=t
red=200
green=200
blue=200
#make this not overlay nearby grassland (but will overlay other lower terrain)
no_overlay=true
heals=true
gives_income=true
[/terrain]
[terrain]
@ -163,15 +148,14 @@ aliasof=t
no_overlay=true
adjacent_image=grassland
light=true
heals=true
gives_income=true
[/terrain]
[terrain]
image=snow,snow,snow2
name=tundra
char=S
red=255
green=255
blue=255
light=true
[/terrain]
@ -180,17 +164,17 @@ image=flag-snow-neutral
adjacent_image=snow
name=snow village
char=V
aliasof=t
aliasof=tS
no_overlay=true
light=true
heals=true
gives_income=true
[/terrain]
[terrain]
image=hills
name=hills
char=h
red=100
green=170
[/terrain]
[terrain]
@ -204,15 +188,12 @@ aliasof=h
image=mountains
name=mountains
char=m
red=150
green=150
[/terrain]
[terrain]
image=forest
name=forest
char=f
green=100
[/terrain]
[terrain]
@ -226,9 +207,6 @@ char=F
image=cavewall
name=cavewall
char=W
red=50
green=50
blue=20
light=true
[/terrain]
@ -236,27 +214,25 @@ light=true
image=cave
name=cave
char=u
red=120
green=120
[/terrain]
[terrain]
image=flag-cave-neutral
name=underground village
char=D
aliasof=t
aliasof=tu
no_overlay=true
adjacent_image=cave
heals=true
gives_income=true
[/terrain]
[terrain]
image=castle
name=castle
char=C
red=100
green=100
blue=100
unit_height_adjust=3
recruit_onto=true
[/terrain]
[terrain]

View file

@ -39,7 +39,7 @@ struct castle_cost_calculator
double cost(const gamemap::location& loc, double cost_so_far) const
{
if(!map_.on_board(loc) || map_[loc.x][loc.y] != gamemap::CASTLE)
if(!map_.is_castle(loc))
return 10000;
return 1;
@ -86,7 +86,7 @@ std::string recruit_unit(const gamemap& map, int side,
if(u == units.end())
return string_table["no_leader_to_recruit"];
if(map.get_terrain(u->first) != gamemap::KEEP) {
if(map.is_keep(u->first)) {
std::cerr << "Leader not on start: leader is on " << (u->first.x+1) << "," << (u->first.y+1) << "\n";
return string_table["leader_not_on_start"];
}
@ -95,13 +95,13 @@ std::string recruit_unit(const gamemap& map, int side,
const paths::route& rt = a_star_search(u->first,recruit_location,
100.0,castle_cost_calculator(map));
if(rt.steps.empty() || units.find(recruit_location) != units.end() ||
map[recruit_location.x][recruit_location.y] != gamemap::CASTLE)
!map.is_castle(recruit_location))
recruit_location = gamemap::location();
}
if(!map.on_board(recruit_location)) {
recruit_location = find_vacant_tile(map,units,u->first,
need_castle ? gamemap::CASTLE : 0);
need_castle ? VACANT_CASTLE : VACANT_ANY);
}
if(!map.on_board(recruit_location)) {
@ -625,7 +625,7 @@ void attack(display& gui, const gamemap& map,
//plague units make clones of themselves on the target hex
//units on villages that die cannot be plagued
if(stats.attacker_plague && map.underlying_terrain(map[loc.x][loc.y]) != gamemap::TOWER) {
if(stats.attacker_plague && !map.is_village(loc)) {
a = units.find(attacker_loc);
if(a != units.end()) {
units.insert(std::pair<gamemap::location,unit>(loc,a->second));
@ -757,7 +757,7 @@ void attack(display& gui, const gamemap& map,
//plague units make clones of themselves on the target hex.
//units on villages that die cannot be plagued
if(stats.defender_plague && map.underlying_terrain(map[loc.x][loc.y]) != gamemap::TOWER) {
if(stats.defender_plague && !map.is_village(loc)) {
d = units.find(defender_loc);
if(d != units.end()) {
units.insert(std::pair<gamemap::location,unit>(
@ -953,8 +953,7 @@ void calculate_healing(display& disp, const gamemap& map,
//it has regeneration, and it is wounded
if(i->second.side() == side) {
if(i->second.hitpoints() < i->second.max_hitpoints()){
if((map.underlying_terrain(map[i->first.x][i->first.y]) == gamemap::TOWER ||
i->second.type().regenerates())) {
if(map.gives_healing(i->first) || i->second.type().regenerates()) {
amount_healed = game_config::cure_amount;
}
}
@ -1474,7 +1473,7 @@ size_t move_unit(display* disp, const game_data& gamedata,
//if we use fog or shroud, see if we have sighted an enemy unit, in
//which case we should stop immediately.
if(teams[team_num].uses_shroud() || teams[team_num].uses_fog()) {
if(units.count(*step) == 0 && map.underlying_terrain(map.get_terrain(*step)) != gamemap::TOWER) {
if(units.count(*step) == 0 && !map.is_village(*step)) {
units.insert(std::pair<gamemap::location,unit>(*step,ui->second));
bool res;
@ -1547,7 +1546,7 @@ size_t move_unit(display* disp, const game_data& gamedata,
}
int orig_tower_owner = -1;
if(map.underlying_terrain(map[steps.back().x][steps.back().y]) == gamemap::TOWER) {
if(map.is_village(steps.back())) {
orig_tower_owner = tower_owner(steps.back(),teams);
if(orig_tower_owner != team_num) {

View file

@ -225,8 +225,9 @@ gamemap::location ai_interface::move_unit(location from, location to, std::map<l
current_unit.set_movement(0);
info_.units.insert(std::pair<location,unit>(to,current_unit));
if(info_.map.underlying_terrain(info_.map[to.x][to.y]) == gamemap::TOWER)
if(info_.map.is_village(to)) {
get_tower(to,info_.teams,info_.team_num-1,info_.units);
}
info_.disp.draw_tile(to.x,to.y);
info_.disp.draw();
@ -292,7 +293,7 @@ void ai_interface::calculate_possible_moves(std::map<location,paths>& res, move_
bool friend_owns = false;
//don't take friendly villages
if(!enemy && info_.map.underlying_terrain(info_.map[dst.x][dst.y]) == gamemap::TOWER) {
if(!enemy && info_.map.is_village(dst)) {
for(size_t n = 0; n != info_.teams.size(); ++n) {
if(info_.teams[n].owns_tower(dst)) {
if(n+1 != info_.team_num && current_team().is_enemy(n+1) == false) {
@ -509,8 +510,9 @@ bool ai::get_villages(std::map<gamemap::location,paths>& possible_moves, const m
{
//try to acquire towers
for(move_map::const_iterator i = dstsrc.begin(); i != dstsrc.end(); ++i) {
if(map_.underlying_terrain(map_[i->first.x][i->first.y]) != gamemap::TOWER)
if(map_.is_village(i->first)) {
continue;
}
bool want_tower = true, owned = false;
for(size_t j = 0; j != teams_.size(); ++j) {
@ -571,8 +573,7 @@ bool ai::get_healing(std::map<gamemap::location,paths>& possible_moves, const mo
Itor best_loc = it.second;
while(it.first != it.second) {
const location& dst = it.first->second;
if(map_.underlying_terrain(map_[dst.x][dst.y]) == gamemap::TOWER &&
units_.find(dst) == units_.end()) {
if(map_.is_village(dst) && units_.find(dst) == units_.end()) {
const double vuln = power_projection(it.first->first,
enemy_srcdst,enemy_dstsrc);
std::cerr << "found village with vulnerability: " << vuln << "\n";
@ -665,7 +666,7 @@ bool ai::retreat_units(std::map<gamemap::location,paths>& possible_moves, const
}
//give a bonus for getting to a village.
const int modified_defense = defense - (map_.underlying_terrain(map_.get_terrain(hex)) == gamemap::TOWER ? 10 : 0);
const int modified_defense = defense - (map_.is_village(hex) ? 10 : 0);
if(modified_defense < best_defensive_rating) {
best_defensive_rating = modified_defense;

View file

@ -218,8 +218,7 @@ private:
calculate_possible_moves(possible_moves,srcdst,dstsrc,false);
for(move_map::const_iterator i = dstsrc.begin(); i != dstsrc.end(); ++i) {
if(get_info().map.underlying_terrain(get_info().map.get_terrain(i->first)) == gamemap::TOWER &&
current_team().owns_tower(i->first) == false) {
if(get_info().map.is_village(i->first) && current_team().owns_tower(i->first) == false) {
move_unit(i->second,i->first,possible_moves);
get_villages();
return;

View file

@ -289,7 +289,7 @@ void ai::attack_analysis::analyze(const gamemap& map,
unit_map::const_iterator att = units.find(movements[i].first);
double cost = att->second.type().cost();
const bool on_village = map.underlying_terrain(map[movements[i].second.x][movements[i].second.y]) == gamemap::TOWER;
const bool on_village = map.is_village(movements[i].second);
//up to double the value of a unit based on experience
cost += (double(att->second.experience())/
@ -379,7 +379,7 @@ void ai::attack_analysis::analyze(const gamemap& map,
defhp = defend_it->second.hitpoints();
} else if(defhp == 0) {
chance_to_kill += 1.0;
} else if(map.underlying_terrain(map[defend_it->first.x][defend_it->first.y]) == gamemap::TOWER) {
} else if(map.is_village(defend_it->first)) {
defhp += game_config::heal_amount;
if(defhp > target_hp)
defhp = target_hp;
@ -525,7 +525,7 @@ double ai::power_projection(const gamemap::location& loc, const move_map& srcdst
most_damage = damage;
}
const bool village = map_.underlying_terrain(terrain) == gamemap::TOWER;
const bool village = map_.is_village(terrain);
const double village_bonus = (use_terrain && village) ? 2.0 : 1.0;
const double defense = use_terrain ? double(100 - un.defense_modifier(map_,terrain))/100.0 : 0.5;

View file

@ -40,12 +40,14 @@ struct move_cost_calculator
typedef std::multimap<gamemap::location,gamemap::location>::const_iterator Itor;
std::pair<Itor,Itor> range = dstsrc_.equal_range(loc);
while(range.first != range.second) {
if(range.first->second == loc_)
if(range.first->second == loc_) {
return 0.01;
}
++range.first;
}
const gamemap::TERRAIN terrain = map_.underlying_terrain(map_[loc.x][loc.y]);
const gamemap::TERRAIN terrain = map_[loc.x][loc.y];
const double modifier = 1.0;//move_type_.defense_modifier(map_,terrain);
const double move_cost = move_type_.movement_cost(map_,terrain);

View file

@ -1711,7 +1711,7 @@ SDL_Surface* display::getTerrain(gamemap::TERRAIN terrain,image::TYPE image_type
SDL_Surface* display::getFlag(gamemap::TERRAIN terrain, int x, int y)
{
const bool village = (map_.underlying_terrain(terrain) == gamemap::TOWER);
const bool village = map_.is_village(terrain);
if(!village)
return NULL;

View file

@ -283,7 +283,7 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
if(u != units->end()) {
const gamemap::location dst(cfg);
if(game_map->on_board(dst)) {
const gamemap::location vacant_dst = find_vacant_tile(*game_map,*units,dst,(*game_map)[dst.x][dst.y]);
const gamemap::location vacant_dst = find_vacant_tile(*game_map,*units,dst);
if(game_map->on_board(vacant_dst)) {
//note that inserting into a map does NOT invalidate iterators
//into the map, so this sequence is fine.

View file

@ -35,36 +35,80 @@ const std::string& gamemap::terrain_name(gamemap::TERRAIN terrain) const
return i->second.name();
}
const std::string& gamemap::underlying_terrain_name(gamemap::TERRAIN terrain) const
std::vector<std::string> gamemap::underlying_terrain_name(gamemap::TERRAIN terrain) const
{
static const std::string default_val;
const std::map<TERRAIN,terrain_type>::const_iterator i =
letterToTerrain_.find(terrain);
if(i == letterToTerrain_.end()) {
return default_val;
return std::vector<std::string>();
} else {
if(i->second.is_alias()) {
//we could call underlying_terrain_name, but that could allow
//infinite recursion with bad data files, so we call terrain_name
//to be safe
return terrain_name(i->second.type());
std::vector<std::string> res;
const std::string& type = i->second.type();
for(std::string::const_iterator j = type.begin(); j != type.end(); ++j) {
res.push_back(terrain_name(*j));
}
return res;
} else {
return i->second.name();
return std::vector<std::string>(1,i->second.name());
}
}
}
gamemap::TERRAIN gamemap::underlying_terrain(TERRAIN terrain) const
const std::string& gamemap::underlying_terrain(TERRAIN terrain) const
{
const std::map<TERRAIN,terrain_type>::const_iterator i =
letterToTerrain_.find(terrain);
const std::map<TERRAIN,terrain_type>::const_iterator i = letterToTerrain_.find(terrain);
if(i == letterToTerrain_.end()) {
return terrain;
static std::string res;
res.resize(1);
res[0] = terrain;
return res;
} else {
return i->second.type();
}
}
bool gamemap::is_village(gamemap::TERRAIN terrain) const
{
return get_terrain_info(terrain).is_village();
}
bool gamemap::gives_healing(gamemap::TERRAIN terrain) const
{
return get_terrain_info(terrain).gives_healing();
}
bool gamemap::is_castle(gamemap::TERRAIN terrain) const
{
return get_terrain_info(terrain).is_castle();
}
bool gamemap::is_keep(gamemap::TERRAIN terrain) const
{
return get_terrain_info(terrain).is_keep();
}
bool gamemap::is_village(const gamemap::location& loc) const
{
return on_board(loc) && is_village(get_terrain(loc));
}
bool gamemap::gives_healing(const gamemap::location& loc) const
{
return is_village(loc);
}
bool gamemap::is_castle(const gamemap::location& loc) const
{
return on_board(loc) && is_castle(get_terrain(loc));
}
bool gamemap::is_keep(const gamemap::location& loc) const
{
return on_board(loc) && is_keep(get_terrain(loc));
}
gamemap::location::location(const config& cfg) : x(-1), y(-1)
{
const std::string& xstr = cfg["x"];
@ -144,7 +188,7 @@ gamemap::gamemap(const config& cfg, const std::string& data) : tiles_(1)
}
}
if(underlying_terrain(c) == TOWER) {
if(is_village(c)) {
towers_.push_back(location(int(x),int(y)));
}
@ -230,7 +274,7 @@ gamemap::TERRAIN gamemap::get_terrain(const gamemap::location& loc) const
TERRAIN used_terrain = 0;
int terrain_count = 0;
for(int i = 0; i != nitems; ++i) {
if(items[i] != used_terrain && underlying_terrain(items[i]) != TOWER) {
if(items[i] != used_terrain && !is_village(items[i])) {
const int c = std::count(items+i+1,items+nitems,items[i]) + 1;
if(c > terrain_count) {
used_terrain = items[i];
@ -297,11 +341,7 @@ const std::vector<gamemap::TERRAIN>& gamemap::get_terrain_precedence() const
bool gamemap::is_built(const location &loc) const
{
gamemap::TERRAIN terrain = get_terrain(loc);
if((terrain == gamemap::CASTLE) || (terrain == gamemap::KEEP))
return true;
else
return false;
return is_castle(loc);
}
void gamemap::set_terrain(const gamemap::location& loc, gamemap::TERRAIN ter)

View file

@ -40,8 +40,8 @@ public:
//is simply an alias, the underlying terrain name is the name of the
//terrain that it's aliased to
const std::string& terrain_name(TERRAIN terrain) const;
const std::string& underlying_terrain_name(TERRAIN terrain) const;
TERRAIN underlying_terrain(TERRAIN terrain) const;
std::vector<std::string> underlying_terrain_name(TERRAIN terrain) const;
const std::string& underlying_terrain(TERRAIN terrain) const;
//exception thrown if the map file is not in the correct format.
struct incorrect_format_exception {
@ -74,6 +74,16 @@ public:
static location null_location;
};
bool is_village(TERRAIN terrain) const;
bool gives_healing(TERRAIN terrain) const;
bool is_castle(TERRAIN terrain) const;
bool is_keep(TERRAIN terrain) const;
bool is_village(const location& loc) const;
bool gives_healing(const location& loc) const;
bool is_castle(const location& loc) const;
bool is_keep(const location& loc) const;
//loads a map, with the given terrain configuration.
//data should be a series of lines, with each character representing
//one hex on the map. Starting locations are represented by numbers,

View file

@ -22,7 +22,7 @@ namespace {
gamemap::location find_vacant(const gamemap& map,
const std::map<gamemap::location,unit>& units,
const gamemap::location& loc, int depth,
gamemap::TERRAIN terrain,
VACANT_TILE_TYPE vacancy,
std::set<gamemap::location>& touched)
{
if(touched.count(loc))
@ -31,8 +31,8 @@ gamemap::location find_vacant(const gamemap& map,
touched.insert(loc);
if(map.on_board(loc) && units.find(loc) == units.end() &&
map.underlying_terrain(map[loc.x][loc.y]) != gamemap::TOWER &&
(terrain == 0 || terrain == map[loc.x][loc.y])) {
map.is_village(loc) == false &&
(vacancy == VACANT_ANY || map.is_castle(loc))) {
return loc;
} else if(depth == 0) {
return gamemap::location();
@ -40,12 +40,11 @@ gamemap::location find_vacant(const gamemap& map,
gamemap::location adj[6];
get_adjacent_tiles(loc,adj);
for(int i = 0; i != 6; ++i) {
if(!map.on_board(adj[i]) ||
terrain != 0 && terrain != map[adj[i].x][adj[i].y])
if(!map.on_board(adj[i]) || vacancy == VACANT_CASTLE && !map.is_castle(adj[i]))
continue;
const gamemap::location res =
find_vacant(map,units,adj[i],depth-1,terrain,touched);
find_vacant(map,units,adj[i],depth-1,vacancy,touched);
if(map.on_board(res))
return res;
@ -60,11 +59,11 @@ gamemap::location find_vacant(const gamemap& map,
gamemap::location find_vacant_tile(const gamemap& map,
const std::map<gamemap::location,unit>& units,
const gamemap::location& loc,
gamemap::TERRAIN terrain)
VACANT_TILE_TYPE vacancy)
{
for(int i = 1; i != 50; ++i) {
std::set<gamemap::location> touch;
const gamemap::location res = find_vacant(map,units,loc,i,terrain,touch);
const gamemap::location res = find_vacant(map,units,loc,i,vacancy,touch);
if(map.on_board(res))
return res;
}
@ -159,7 +158,7 @@ void find_routes(const gamemap& map, const gamestatus& status,
//check for teleporting units -- we must be on a vacant (or occupied by this unit)
//tower, that is controlled by our team to be able to teleport.
if(allow_teleport && map.underlying_terrain(map[loc.x][loc.y]) == gamemap::TOWER &&
if(allow_teleport && map.is_village(loc) &&
current_team.owns_tower(loc) && (starting_pos || units.count(loc) == 0)) {
const std::vector<gamemap::location>& towers = map.towers();

View file

@ -39,6 +39,8 @@ bool tiles_adjacent(const gamemap::location& a, const gamemap::location& b);
//number of hexes that have to be traversed to get from one hex to the other)
size_t distance_between(const gamemap::location& a, const gamemap::location& b);
enum VACANT_TILE_TYPE { VACANT_CASTLE, VACANT_ANY };
//function which will find a location on the board that is as near to loc as
//possible, but which is unoccupied by any units. If terrain is not 0, then
//the location found must be of the given terrain type, and must have a path
@ -48,7 +50,7 @@ size_t distance_between(const gamemap::location& a, const gamemap::location& b);
gamemap::location find_vacant_tile(const gamemap& map,
const std::map<gamemap::location,unit>& un,
const gamemap::location& loc,
gamemap::TERRAIN terrain=0);
VACANT_TILE_TYPE vacancy=VACANT_ANY);
//function which determines if a given location is an enemy zone of control
bool enemy_zoc(const gamemap& map,const gamestatus& status,

View file

@ -42,7 +42,7 @@ namespace {
const gamemap::location pos(i,j);
if(map.on_board(pos)) {
++positions;
if(std::count(terrain_liked.begin(),terrain_liked.end(),map.underlying_terrain(map[i][j]))) {
if(std::count(terrain_liked.begin(),terrain_liked.end(),map[i][j])) {
++liked;
}
}

View file

@ -835,9 +835,7 @@ bool turn_info::in_context_menu(hotkey::HOTKEY_COMMAND command) const
case hotkey::HOTKEY_RECALL: {
// last_hex_ is set by turn_info::mouse_motion
// Enable recruit/recall on castle/keep tiles
if(!map_.on_board(last_hex_)) return false;
char terrain = map_.underlying_terrain(map_[last_hex_.x][last_hex_.y]);
return terrain == gamemap::CASTLE || terrain == gamemap::KEEP;
return map_.is_castle(last_hex_);
}
default:
return true;
@ -1129,7 +1127,7 @@ void turn_info::undo()
return;
}
if(map_.underlying_terrain(map_[route.front().x][route.front().y]) == gamemap::TOWER) {
if(map_.is_village(route.front())) {
get_tower(route.front(),teams_,action.original_village_owner,units_);
}
@ -1212,7 +1210,7 @@ void turn_info::redo()
un.set_movement(starting_moves);
units_.insert(std::pair<gamemap::location,unit>(route.back(),un));
if(map_.underlying_terrain(map_[route.back().x][route.back().y]) == gamemap::TOWER) {
if(map_.is_village(route.back())) {
get_tower(route.back(),teams_,un.side()-1,units_);
}

View file

@ -699,7 +699,7 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
current_unit.set_movement(rt->second.move_left);
u = units.insert(std::pair<gamemap::location,unit>(dst,current_unit)).first;
if(map.underlying_terrain(map[dst.x][dst.y]) == gamemap::TOWER) {
if(map.is_village(dst)) {
const int orig_owner = tower_owner(dst,teams) + 1;
if(orig_owner != team_num) {
u->second.set_movement(0);

View file

@ -253,12 +253,21 @@ report generate_report(TYPE type, const gamemap& map, const unit_map& units,
const gamemap::TERRAIN terrain = map.get_terrain(mouseover);
const std::string& name = map.terrain_name(terrain);
const std::string& underlying_name = map.underlying_terrain_name(terrain);
const std::vector<std::string>& underlying_names = map.underlying_terrain_name(terrain);
str << translate_string(name);
if(underlying_name != name) {
str << " (" << translate_string(underlying_name) << ")";
if(underlying_names.size() != 1 || underlying_names.front() != name) {
str << " (";
for(std::vector<std::string>::const_iterator i = underlying_names.begin(); i != underlying_names.end(); ++i) {
str << translate_string(*i);
if(i+1 != underlying_names.end()) {
str << ",";
}
}
str << ")";
}
break;

View file

@ -17,8 +17,9 @@
#include <cstdlib>
#include <iostream>
terrain_type::terrain_type() : images_(1,"void"), type_(' '), letter_(' '),
height_adjust_(0), submerge_(0.0), equal_precedence_(false)
terrain_type::terrain_type() : images_(1,"void"), type_(" "), letter_(' '),
height_adjust_(0), submerge_(0.0), equal_precedence_(false),
heals_(false), village_(false), castle_(false), keep_(false)
{}
terrain_type::terrain_type(const config& cfg)
@ -30,14 +31,20 @@ terrain_type::terrain_type(const config& cfg)
name_ = cfg["name"];
const std::string& letter = cfg["char"];
assert(!letter.empty());
letter_ = letter[0];
if(letter == "") {
letter_ = 0;
} else {
letter_ = letter[0];
}
const std::string& alias = cfg["aliasof"];
if(alias.empty())
type_ = letter_;
else
type_ = alias[0];
if(alias.empty()) {
type_.resize(1);
type_[0] = letter_;
} else {
type_ = alias;
}
colour_.read(cfg);
@ -46,6 +53,11 @@ terrain_type::terrain_type(const config& cfg)
equal_precedence_ = cfg["no_overlay"] == "true";
is_light_ = cfg["light"] == "true";
heals_ = cfg["heals"] == "true";
village_ = cfg["gives_income"] == "true";
castle_ = cfg["recruit_onto"] == "true";
keep_ = cfg["recruit_from"] == "true";
}
const std::string& terrain_type::image(int x, int y) const
@ -76,7 +88,7 @@ char terrain_type::letter() const
return letter_;
}
char terrain_type::type() const
const std::string& terrain_type::type() const
{
return type_;
}
@ -93,7 +105,7 @@ bool terrain_type::is_light() const
bool terrain_type::is_alias() const
{
return type_ != letter_;
return type_.size() != 1 || type_[0] != letter_;
}
int terrain_type::unit_height_adjust() const
@ -111,6 +123,26 @@ bool terrain_type::equal_precedence() const
return equal_precedence_;
}
bool terrain_type::gives_healing() const
{
return heals_;
}
bool terrain_type::is_village() const
{
return village_;
}
bool terrain_type::is_castle() const
{
return castle_;
}
bool terrain_type::is_keep() const
{
return keep_;
}
void create_terrain_maps(const std::vector<config*>& cfgs,
std::vector<char>& terrain_precedence,
std::map<char,terrain_type>& letter_to_terrain,

View file

@ -28,8 +28,12 @@ public:
const std::string& default_image() const;
const std::string& adjacent_image() const;
const std::string& name() const;
//the character representing this terrain
char letter() const;
char type() const;
//the underlying type of the terrain
const std::string& type() const;
pixel_data get_rgb() const;
@ -42,16 +46,21 @@ public:
//whether the terrain's overlay precedence is equal (rather than higher
//than) the preceeding terrain
bool equal_precedence() const;
bool gives_healing() const;
bool is_village() const;
bool is_castle() const;
bool is_keep() const;
private:
std::vector<std::string> images_;
std::string adjacent_image_;
std::string name_;
//the 'letter' is the letter that represents this
//terrain type. The 'type' is the letter of the
//terrain type which this is equivalent to, which
//may be the same as 'letter'
char type_, letter_;
//terrain type. The 'type' is a list of the 'underlying types'
//of the terrain. This may simply be the same as the letter.
char letter_;
std::string type_;
pixel_data colour_;
@ -61,6 +70,8 @@ private:
bool equal_precedence_;
bool is_light_;
bool heals_, village_, castle_, keep_;
};
void create_terrain_maps(const std::vector<config*>& cfgs,

View file

@ -356,14 +356,14 @@ void unit::heal_all()
hitpoints_ = max_hitpoints();
}
bool unit::invisible(gamemap::TERRAIN terrain, int lawful_bonus,
bool unit::invisible(const std::string& terrain, int lawful_bonus,
const gamemap::location loc,
const unit_map& units,const std::vector<team>& teams) const
{
bool is_inv = false;
static const std::string forest_invisible("ambush");
if((terrain == gamemap::FOREST) && has_flag(forest_invisible)) {
if(std::count(terrain.begin(),terrain.end(),gamemap::FOREST) && has_flag(forest_invisible)) {
is_inv = true;
}
static const std::string night_invisible("nightstalk");
@ -671,9 +671,11 @@ int unit::movement_cost(const gamemap& map, gamemap::TERRAIN terrain) const
{
//don't allow level 0 units to take villages - removed until AI
//is smart enough to deal with this.
// if(type_->level() == 0 && terrain == gamemap::TOWER)
// if(type_->level() == 0 && map.is_village(terrain))
// return 100;
const int res = type_->movement_type().movement_cost(map,terrain);
static const std::string slowed_string("slowed");

View file

@ -74,7 +74,7 @@ public:
void heal(int amount);
void heal_all();
bool invisible(gamemap::TERRAIN terrain, int lawful_bonus,
bool invisible(const std::string& terrain, int lawful_bonus,
const gamemap::location loc,
const unit_map& units,const std::vector<team>& teams) const;
bool poisoned() const;

View file

@ -269,16 +269,24 @@ int unit_movement_type::movement_cost(const gamemap& map,
int res = -1;
if(movement_costs != NULL) {
const std::string& name = map.underlying_terrain_name(terrain);
const std::string& val = (*movement_costs)[name];
const std::vector<std::string> names = map.underlying_terrain_name(terrain);
for(std::vector<std::string>::const_iterator i = names.begin(); i != names.end(); ++i) {
const std::string& val = (*movement_costs)[*i];
if(val != "") {
res = atoi(val.c_str());
if(val != "") {
const int value = atoi(val.c_str());
if(res == -1 || value < res) {
res = value;
}
}
}
}
if(res == -1 && parent_ != NULL) {
res = parent_->movement_cost(map,terrain);
if(parent_ != NULL) {
const int value = parent_->movement_cost(map,terrain);
if(res == -1 || value < res) {
res = value;
}
}
if(res <= 0)
@ -303,16 +311,24 @@ int unit_movement_type::defense_modifier(const gamemap& map,
const config* const defense = cfg_.child("defense");
if(defense != NULL) {
const std::string& name = map.underlying_terrain_name(terrain);
const std::string& val = (*defense)[name];
const std::vector<std::string> names = map.underlying_terrain_name(terrain);
for(std::vector<std::string>::const_iterator i = names.begin(); i != names.end(); ++i) {
const std::string& val = (*defense)[*i];
if(val != "") {
res = atoi(val.c_str());
if(val != "") {
const int value = atoi(val.c_str());
if(res == -1 || value < res) {
res = value;
}
}
}
}
if(res == -1 && parent_ != NULL) {
res = parent_->defense_modifier(map,terrain);
if(parent_ != NULL) {
const int value = parent_->defense_modifier(map,terrain);
if(res == -1 || value < res) {
res = value;
}
}
if(res < 0)