made it so healers can heal allies.

made it so that if a leader dies, all villages for that side become neutral
This commit is contained in:
uid68803 2004-01-05 19:20:09 +00:00
parent f734529e45
commit 2d9f035095
14 changed files with 139 additions and 100 deletions

View file

@ -121,9 +121,9 @@ error_no_campaigns="There are no campaigns available"
choose_campaign="Choose the campaign you want to play:"
difficulty_level="Select difficulty level:"
EASY="Fighter (easy)"
NORMAL="*Hero (medium)"
HARD="Champion (hard)"
EASY="&elvish-fighter.png,Fighter (easy)"
NORMAL="*&elvish-hero.png,Hero (medium)"
HARD="&elvish-champion.png,Champion (hard)"
lawful_description="Lawful units fight better at day, and worse at night.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 B

After

Width:  |  Height:  |  Size: 127 B

View file

@ -599,15 +599,17 @@ int tower_owner(const gamemap::location& loc, std::vector<team>& teams)
void get_tower(const gamemap::location& loc, std::vector<team>& teams,
int team_num)
size_t team_num, const unit_map& units)
{
for(size_t i = 0; i != teams.size(); ++i) {
if(int(i) != team_num && teams[i].owns_tower(loc)) {
if(i != team_num && teams[i].owns_tower(loc)) {
teams[i].lose_tower(loc);
}
}
if(size_t(team_num) < teams.size())
//if the side doesn't have a leader, captured villages become neutral
const bool has_leader = find_leader(units,int(team_num+1)) != units.end();
if(has_leader && team_num < teams.size())
teams[team_num].get_tower(loc);
}
@ -623,8 +625,71 @@ std::map<gamemap::location,unit>::iterator
return units.end();
}
std::map<gamemap::location,unit>::const_iterator
find_leader(const std::map<gamemap::location,unit>& units, int side)
{
for(std::map<gamemap::location,unit>::const_iterator i = units.begin();
i != units.end(); ++i) {
if(i->second.side() == side && i->second.can_recruit())
return i;
}
return units.end();
}
namespace {
//function which returns true iff the unit at 'loc' will heal a unit from side 'side'
//on this turn.
//
//units heal other units if they are (1) on the same side as them; or (2) are on a
//different but allied side, and there are no 'higher priority' sides also adjacent
//to the healer
bool will_heal(const gamemap::location& loc, int side, const std::vector<team>& teams,
const unit_map& units)
{
const unit_map::const_iterator healer_it = units.find(loc);
if(healer_it == units.end() || healer_it->second.type().heals() == false)
return false;
const unit& healer = healer_it->second;
if(healer.side() == side)
return true;
if(size_t(side-1) >= teams.size() || size_t(healer.side()-1) >= teams.size())
return false;
//if the healer is an enemy, it won't heal
if(teams[healer.side()-1].is_enemy(side))
return false;
gamemap::location adjacent[6];
get_adjacent_tiles(loc,adjacent);
for(int n = 0; n != 6; ++n) {
const unit_map::const_iterator u = units.find(adjacent[n]);
if(u != units.end() && u->second.hitpoints() < u->second.max_hitpoints()) {
const int unit_side = u->second.side();
//the healer won't heal an ally if there is a wounded unit on the same
//side next to her
if(unit_side == healer.side())
return false;
//choose an arbitrary order for healing
if(unit_side > side)
return false;
}
}
//there's no-one of higher priority nearby, so the ally will heal
return true;
}
}
void calculate_healing(display& disp, const gamemap& map,
std::map<gamemap::location,unit>& units, int side)
std::map<gamemap::location,unit>& units, int side,
const std::vector<team>& teams)
{
std::map<gamemap::location,int> healed_units, max_healing;
@ -647,17 +712,14 @@ void calculate_healing(display& disp, const gamemap& map,
gamemap::location adjacent[6];
get_adjacent_tiles(i->first,adjacent);
for(int j = 0; j != 6; ++j) {
std::map<gamemap::location,unit>::const_iterator healer =
units.find(adjacent[j]);
if(healer != units.end() && healer->second.side() == side) {
max_heal = maximum(max_heal,
healer->second.type().max_unit_healing());
if(will_heal(adjacent[j],i->second.side(),teams,units)) {
const unit_map::const_iterator healer = units.find(adjacent[j]);
max_heal = maximum(max_heal,healer->second.type().max_unit_healing());
}
}
if(max_heal > 0) {
max_healing.insert(std::pair<gamemap::location,int>(i->first,
max_heal));
max_healing.insert(std::pair<gamemap::location,int>(i->first,max_heal));
}
}
}
@ -665,7 +727,7 @@ void calculate_healing(display& disp, const gamemap& map,
//now see about units that can heal other units
for(i = units.begin(); i != units.end(); ++i) {
if(i->second.side() == side && i->second.type().heals()) {
if(will_heal(i->first,side,teams,units)) {
gamemap::location adjacent[6];
bool gets_healed[6];
get_adjacent_tiles(i->first,adjacent);
@ -677,7 +739,7 @@ void calculate_healing(display& disp, const gamemap& map,
units.find(adjacent[j]);
if(adj != units.end() &&
adj->second.hitpoints() < adj->second.max_hitpoints() &&
adj->second.side() == i->second.side() &&
adj->second.side() == side &&
healed_units[adj->first] < max_healing[adj->first]) {
++nhealed;
gets_healed[j] = true;
@ -715,8 +777,7 @@ void calculate_healing(display& disp, const gamemap& map,
i->second.hitpoints()-1);
if(damage > 0) {
healed_units.insert(std::pair<gamemap::location,int>(
i->first,-damage));
healed_units.insert(std::pair<gamemap::location,int>(i->first,-damage));
}
}
}
@ -836,7 +897,7 @@ void advance_unit(const game_data& info,
}
void check_victory(std::map<gamemap::location,unit>& units,
const std::vector<team>& teams)
std::vector<team>& teams)
{
std::vector<int> seen_leaders;
for(std::map<gamemap::location,unit>::const_iterator i = units.begin();
@ -845,6 +906,13 @@ void check_victory(std::map<gamemap::location,unit>& units,
seen_leaders.push_back(i->second.side());
}
//clear villages for teams that have no leader
for(std::vector<team>::iterator tm = teams.begin(); tm != teams.end(); ++tm) {
if(std::find(seen_leaders.begin(),seen_leaders.end(),tm-teams.begin() + 1) == seen_leaders.end()) {
tm->clear_towers();
}
}
bool found_enemies = false;
bool found_human = false;
@ -1116,7 +1184,7 @@ size_t move_unit(display* disp, const game_data& gamedata, const gamemap& map,
orig_tower_owner = tower_owner(steps.back(),teams);
if(orig_tower_owner != team_num) {
get_tower(steps.back(),teams,team_num);
get_tower(steps.back(),teams,team_num,units);
u.set_movement(0);
}
}

View file

@ -100,17 +100,22 @@ int tower_owner(const gamemap::location& loc, std::vector<team>& teams);
//makes it so the tower at the given location is owned by the given
//0-based team number
void get_tower(const gamemap::location& loc, std::vector<team>& teams,
int team_num);
size_t team_num, const unit_map& units);
//given the 1-based side, will find the leader of that side,
//and return an iterator to the leader
std::map<gamemap::location,unit>::iterator
find_leader(std::map<gamemap::location,unit>& units, int side);
std::map<gamemap::location,unit>::const_iterator
find_leader(const std::map<gamemap::location,unit>& units, int side);
//calculates healing for all units for the given side. Should be called
//at the beginning of a side's turn.
void calculate_healing(display& disp, const gamemap& map,
std::map<gamemap::location,unit>& units, int side);
std::map<gamemap::location,unit>& units, int side,
const std::vector<team>& teams);
//function which, given the location of a unit that is advancing, and the
//name of the unit it is advancing to, will return the advanced version of
@ -133,9 +138,9 @@ bool under_leadership(const std::map<gamemap::location,unit>& units,
const gamemap::location& loc);
//checks to see if a side has won, and will throw an end_level_exception
//if one has.
//if one has. Will also remove control of villages from sides with dead leaders
void check_victory(std::map<gamemap::location,unit>& units,
const std::vector<team>& teams);
std::vector<team>& teams);
//gets the time of day at a certain tile. Certain tiles may have a time of
//day that differs from 'the' time of day, if a unit that illuminates is

View file

@ -148,7 +148,7 @@ void move_unit(const game_data& gameinfo, display& disp,
current_unit.set_movement(0);
units.insert(std::pair<location,unit>(to,current_unit));
if(map.underlying_terrain(map[to.x][to.y]) == gamemap::TOWER)
get_tower(to,teams,team_num-1);
get_tower(to,teams,team_num-1,units);
disp.draw_tile(to.x,to.y);
disp.draw();
@ -161,7 +161,7 @@ void move_unit(const game_data& gameinfo, display& disp,
}
void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
std::map<gamemap::location,unit>& units,
unit_map& units,
std::vector<team>& teams, int team_num, const gamestatus& state,
bool consider_combat, std::vector<target>* additional_targets)
{
@ -248,26 +248,12 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
}
}
const unit_map::iterator leader = find_leader(units,team_num);
//no moves left, recruitment phase
//take stock of our current set of units
if(srcdst.empty()) {
std::cout << "recruitment......\n";
location leader;
int num_units = 0;
std::map<std::string,int> unit_types;
for(std::map<location,unit>::const_iterator i = units.begin();
i != units.end(); ++i) {
if(i->second.side() != team_num)
continue;
if(i->second.can_recruit()) {
leader = i->first;
continue;
}
unit_types[i->second.type().usage()]++;
++num_units;
}
//currently just spend all the gold we can!
const int min_gold = 0;
@ -284,8 +270,9 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
int scouts_wanted = current_team.villages_per_scout() > 0 ?
neutral_towers/current_team.villages_per_scout() : 0;
std::map<std::string,int> unit_types;
while(unit_types["scout"] < scouts_wanted) {
if(recruit(map,leader,"scout",gameinfo,team_num,current_team,
if(recruit(map,leader->first,"scout",gameinfo,team_num,current_team,
min_gold,units,disp) == false)
break;
@ -301,7 +288,7 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
}
//buy fighters as long as we have room and can afford it
while(recruit(map,leader,options[rand()%options.size()].c_str(),
while(recruit(map,leader->first,options[rand()%options.size()].c_str(),
gameinfo,team_num,current_team,min_gold,units,disp)) {
}
@ -431,14 +418,23 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
if(map.underlying_terrain(map[i->first.x][i->first.y]) != gamemap::TOWER)
continue;
bool want_tower = true;
bool want_tower = true, owned = false;
for(size_t j = 0; j != teams.size(); ++j) {
if(!current_team.is_enemy(j+1) && teams[j].owns_tower(i->first)) {
owned = teams[j].owns_tower(i->first);
if(owned && !current_team.is_enemy(j+1)) {
want_tower = false;
}
if(owned) {
break;
}
}
//if it's a neutral tower, and we have no leader, then the village is no use to us,
//and we don't want it.
if(!owned && leader == units.end())
want_tower = false;
if(want_tower) {
std::cerr << "trying to acquire village: " << i->first.x
<< ", " << i->first.y << "\n";
@ -516,7 +512,7 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
}
std::cout << "finding targets...\n";
std::vector<target> targets = find_targets(map,units,teams,team_num);
std::vector<target> targets = find_targets(map,units,teams,team_num,leader != units.end());
targets.insert(targets.end(),additional_targets->begin(),
additional_targets->end());
for(;;) {

View file

@ -87,7 +87,7 @@ private:
std::vector<target> find_targets(
const gamemap& map, std::map<location,unit>& units,
std::vector<team>& teams, int current_team
std::vector<team>& teams, int current_team, bool has_leader
)
{
log_scope("finding targets...");
@ -96,10 +96,9 @@ std::vector<target> find_targets(
std::vector<target> targets;
if(tm.village_value() > 0.0) {
if(has_leader && tm.village_value() > 0.0) {
const std::vector<location>& towers = map.towers();
for(std::vector<location>::const_iterator t = towers.begin();
t != towers.end(); ++t) {
for(std::vector<location>::const_iterator t = towers.begin(); t != towers.end(); ++t) {
assert(map.on_board(*t));
bool get_tower = true;
for(size_t i = 0; i != teams.size(); ++i) {

View file

@ -33,7 +33,7 @@ struct target {
std::vector<target> find_targets(
const gamemap& map, std::map<location,unit>& units,
std::vector<team>& teams, int current_team
std::vector<team>& teams, int current_team, bool has_leader
);
std::pair<location,location> choose_move(

View file

@ -727,7 +727,6 @@ void display::draw_report(reports::TYPE report_num)
//report and its location is unchanged since last time. Do nothing.
if(rect == new_rect && reports_[report_num] == report) {
std::cerr << "report unchanged: '" << report.text << "'\n";
return;
}
@ -775,7 +774,6 @@ void display::draw_report(reports::TYPE report_num)
str += report.text.substr(nchop) + item->postfix();
std::cerr << "draw report text '" << str << "' at " << rect.x << "," << rect.y << "\n";
area = font::draw_text(this,rect,item->font_size(),font::NORMAL_COLOUR,str,rect.x,rect.y);
}
@ -1720,45 +1718,11 @@ void display::blit_surface(int x, int y, SDL_Surface* surface)
if(srcw <= 0 || srch <= 0 || srcx >= surface->w || srcy >= surface->h)
return;
/* //look at why SDL_BlitSurface doesn't always handle transperancy for us.
SDL_Rect src_rect = {srcx, srcy, srcw, srch};
SDL_Rect dst_rect = {x, y, srcw, srch};
SDL_BlitSurface(surface,&src_rect,target,&dst_rect);
return;
*/
if(x < 0)
x = 0;
if(y < 0)
y = 0;
//lines are padded to always fit on 4-byte boundaries, so see if there
//is padding at the beginning of every line
const int padding = is_odd(surface->w);
const int surface_width = surface->w + padding;
surface_lock srclock(surface);
surface_lock dstlock(target);
const short* src = srclock.pixels() + srcy*surface_width + srcx;
short* dst = dstlock.pixels() + y*target->w + x;
static const short transperant = 0;
for(int i = 0; i != srch; ++i) {
const short* s = src + i*surface_width + padding;
const short* const end = s + srcw;
short* d = dst + i*target->w;
while(s != end) {
if(*s != transperant) {
*d = *s;
}
++s;
++d;
}
}
}
SDL_Surface* display::getMinimap(int w, int h)

View file

@ -306,9 +306,10 @@ SDL_Surface* getMinimap(int w, int h, const gamemap& map, const team* tm)
SDL_Rect minirect = {0,0,scale,scale};
for(int y = 0; y != map.y(); ++y) {
for(int x = 0; x != map.x(); ++x) {
const bool shrouded = tm != NULL && tm->shrouded(x,y);
if(map.on_board(gamemap::location(x,y)) && !shrouded) {
const gamemap::TERRAIN terrain = map[x][y];
if(map.on_board(gamemap::location(x,y))) {
const bool shrouded = tm != NULL && tm->shrouded(x,y);
const gamemap::TERRAIN terrain = shrouded ? gamemap::VOID_TERRAIN : map[x][y];
cache_map::iterator i = cache.find(terrain);
if(i == cache.end()) {

View file

@ -59,6 +59,10 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& game_config,
const config::child_list& unit_cfg = level->get_children("side");
for(config::child_list::const_iterator ui = unit_cfg.begin(); ui != unit_cfg.end(); ++ui) {
if(first_human_team == -1 && (**ui)["controller"] == "human") {
first_human_team = ui - unit_cfg.begin();
}
std::string gold = (**ui)["gold"];
if(gold.empty())
gold = "100";
@ -111,10 +115,6 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& game_config,
state_of_game.can_recruit = teams.back().recruits();
}
if(first_human_team == -1 && teams.back().is_human()) {
first_human_team = teams.size()-1;
}
//if there are additional starting units on this side
const config::child_list& starting_units = (*ui)->get_children("unit");
for(config::child_list::const_iterator su = starting_units.begin();
@ -231,7 +231,7 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& game_config,
team_it->spend_gold(expense);
}
calculate_healing(gui,map,units,player_number);
calculate_healing(gui,map,units,player_number,teams);
}
gui.set_playing_team(size_t(player_number-1));

View file

@ -805,7 +805,7 @@ void turn_info::undo()
if(map_.underlying_terrain(map_[route.front().x][route.front().y]) == gamemap::TOWER) {
get_tower(route.front(),teams_,
undo_stack_.back().original_village_owner);
undo_stack_.back().original_village_owner,units_);
}
undo_stack_.back().starting_moves = u->second.movement_left();
@ -868,7 +868,7 @@ void turn_info::redo()
recorder.add_movement(route.front(),route.back());
if(map_.underlying_terrain(map_[route.back().x][route.back().y]) == gamemap::TOWER) {
get_tower(route.back(),teams_,un.side()-1);
get_tower(route.back(),teams_,un.side()-1,units_);
}
gui_.draw_tile(route.back().x,route.back().y);

View file

@ -530,7 +530,7 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
const int orig_owner = tower_owner(dst,teams) + 1;
if(orig_owner != team_num) {
current_unit.set_movement(0);
get_tower(dst,teams,team_num-1);
get_tower(dst,teams,team_num-1,units);
}
}

View file

@ -240,6 +240,11 @@ void team::lose_tower(const gamemap::location& loc)
towers_.erase(towers_.find(loc));
}
void team::clear_towers()
{
towers_.clear();
}
const std::set<gamemap::location>& team::towers() const
{
return towers_;

View file

@ -65,6 +65,7 @@ public:
void get_tower(const gamemap::location&);
void lose_tower(const gamemap::location&);
void clear_towers();
const std::set<gamemap::location>& towers() const;
bool owns_tower(const gamemap::location&) const;