doxygen, comments

This commit is contained in:
Hans Joachim Gurt 2007-08-20 00:22:38 +00:00
parent 477ce9d6be
commit 9b4ee443e6
3 changed files with 195 additions and 175 deletions

View file

@ -414,7 +414,7 @@ int divide(int a,int b) {
@{
*/
/** @file actions.hpp */
/** -file actions.hpp */
/** -file ai_attack.hpp */
/** @file ai.hpp */
/** -file ai_move.hpp */

View file

@ -12,6 +12,9 @@
See the COPYING file for more details.
*/
//! @file actions.cpp
//! Recruiting, Fighting.
#include "actions.hpp"
#include "attack_prediction.hpp"
#include "game_config.hpp"
@ -98,7 +101,7 @@ std::string recruit_unit(const gamemap& map, int side,
LOG_NG << "recruiting unit for side " << side << "\n";
//find the unit that can recruit
// Find the unit that can recruit
unit_map::const_iterator u = units.begin();
for(; u != units.end(); ++u) {
@ -167,7 +170,7 @@ std::string recruit_unit(const gamemap& map, int side,
config cfg_unit1;
new_unit.write(cfg_unit1);
::write(std::cerr, cfg_unit1);
// FIXME enabling this exception will trigger an assertion failure
//! @todo FIXME enabling this exception will trigger an assertion failure
// in display.cpp:1010 when loading a map (the cause of that OOS
// will be fixed soon). (Only tested in SP for bug #9728)
// if (!game_config::ignore_replay_errors) {
@ -181,8 +184,8 @@ std::string recruit_unit(const gamemap& map, int side,
set_random_results(cfg);
}
// if an OOS happens this option allows to write the debug info about the
// recruited unit.
// If an OOS happens, this option allows to write
// the debug info about the recruited unit.
if(!lg::info.dont_log(lg::engine)) {
config cfg_unit;
new_unit.write(cfg_unit);
@ -223,10 +226,9 @@ battle_context::battle_context(const gamemap& map, const std::vector<team>& team
const unit& defender = units.find(defender_loc)->second;
const double harm_weight = 1.0 - aggression;
// A Python AI can send an invalid weapon and crash Wesnoth
// Haven't found a way for the Python API to prevent this
// problem. So instead of segfaulting it sends an assertion
// failure.
// A Python AI can send an invalid weapon and crash Wesnoth.
// Haven't found a way for the Python API to prevent this problem.
// So instead of segfaulting it sends an assertion failure.
wassert(attacker_weapon< (int)attacker.attacks().size());
if (attacker_weapon == -1 && attacker.attacks().size() == 1 && attacker.attacks()[0].attack_weight() > 0 )
@ -300,7 +302,7 @@ battle_context& battle_context::operator=(const battle_context &other)
return *this;
}
// FIXME: Hand previous defender unit in here...
//! @todo FIXME: Hand previous defender unit in here.
int battle_context::choose_defender_weapon(const unit &attacker, const unit &defender, unsigned attacker_weapon,
const gamemap& map, const std::vector<team>& teams, const unit_map& units,
const gamestatus& status, const game_data& gamedata,
@ -323,9 +325,10 @@ int battle_context::choose_defender_weapon(const unit &attacker, const unit &def
if (choices.size() == 1)
return choices[0];
// Multiple options: first pass : get the best weight and the minimum simple rating for this weight
// Multiple options:
// First pass : get the best weight and the minimum simple rating for this weight.
// simple rating = number of blows * damage per blows (resistance taken in account) * cth * weight
// elligible attacks for defense should have a simple rating greater or equal to this weight
// Elligible attacks for defense should have a simple rating greater or equal to this weight.
double max_weight = 0.0;
int min_rating = 0;
@ -498,7 +501,7 @@ bool battle_context::better_combat(const combatant &us_a, const combatant &them_
}
// Get the simulation results.
// FIXME: better to initialize combatant initially (move into unit_stats?), just do fight() when required.
//! @todo FIXME: better to initialize combatant initially (move into unit_stats?), just do fight() when required.
const combatant &battle_context::get_attacker_combatant(const combatant *prev_def)
{
// We calculate this lazily, since AI doesn't always need it.
@ -544,7 +547,7 @@ battle_context::unit_stats::unit_stats(const unit &u, const gamemap::location& u
is_poisoned = utils::string_bool(u.get_state("poisoned"));
is_slowed = utils::string_bool(u.get_state("slowed"));
if(u.hitpoints() < 0) {
//FIXME enable after 1.3.2 and find out why this happens -- Mordante
//! @todo FIXME enable after 1.3.2 and find out why this happens -- Mordante
// LOG_STREAM(err, config) << "Unit with " << u.hitpoints() << " hitpoints found, set to 0 for damage calculations\n";
hp = 0;
} else {
@ -705,7 +708,7 @@ void attack::fire_event(const std::string& n)
if(a_ != units_.end()) {
d_weap = d_stats_->weapon->id();
} else {
//the weapon choice will be invalid since the attacker was removed
// The weapon choice will be invalid since the attacker was removed
d_weap = "invalid";
}
}
@ -725,14 +728,16 @@ void attack::fire_event(const std::string& n)
(*(dat.child("first")))["weapon"]=a_stats_->weapon->id();
(*(dat.child("second")))["weapon"]=d_stats_->weapon != NULL ? d_stats_->weapon->id() : "none";
game_events::fire(n,attacker_,defender_,dat);
//the event could have killed either the attacker or
//defender, so we have to make sure they still exist
// The event could have killed either the attacker or
// defender, so we have to make sure they still exist
a_ = units_.find(attacker_);
d_ = units_.find(defender_);
// FIXME: If the event removes this attack, we should stop attacking.
// The previous code checked if 'attack_with' and 'defend_with' were still within the bounds of
// the attack arrays, or -1, but it was incorrect. The attack used could be removed and '*_with'
// variables could still be in bounds but point to a different attack.
//! @todo FIXME: If the event removes this attack, we should stop attacking.
// The previous code checked if 'attack_with' and 'defend_with'
// were still within the bounds of the attack arrays,
// or -1, but it was incorrect.
// The attack used could be removed and '*_with' variables
// could still be in bounds but point to a different attack.
if(a_ == units_.end() || d_ == units_.end()) {
if (update_display_){
recalculate_fog(map_,state_,info_,units_,teams_,attacker_side-1);
@ -781,7 +786,7 @@ attack::attack(game_display& gui, const gamemap& map,
units_(units),state_(state),info_(info),
update_display_(update_display),OOS_error_(false),bc_(NULL)
{
//stop the user from issuing any commands while the units are fighting
// Stop the user from issuing any commands while the units are fighting
const events::command_disabler disable_commands;
a_ = units_.find(attacker);
d_ = units_.find(defender);
@ -802,7 +807,7 @@ attack::attack(game_display& gui, const gamemap& map,
a_->second.set_state("not_moved","");
d_->second.set_resting(false);
//if the attacker was invisible, she isn't anymore!
// If the attacker was invisible, she isn't anymore!
a_->second.set_state("hides","");
bc_ = new battle_context(map_, teams_, units_, state_, info_, attacker_, defender_, attack_with_, defend_with_);
@ -849,8 +854,8 @@ attack::attack(game_display& gui, const gamemap& map,
} else {
damage_defender_takes = 0;
}
//make sure that if we're serializing a game here,
//we got the same results as the game did originally
// Make sure that if we're serializing a game here,
// we got the same results as the game did originally.
const config* ran_results = get_random_results();
if(ran_results != NULL) {
const int results_chance = atoi((*ran_results)["chance"].c_str());
@ -900,7 +905,7 @@ attack::attack(game_display& gui, const gamemap& map,
float_text = float_text + _("slowed") + "\n";
}
//if the defender is turned to stone, the fight stops immediately
// If the defender is turned to stone, the fight stops immediately
static const std::string stone_string("stone");
if (a_stats_->stones) {
float_text = float_text + _("stone") + "\n";
@ -973,7 +978,7 @@ attack::attack(game_display& gui, const gamemap& map,
}
}
if(dies) {//attacker kills defender
if(dies) { // attacker kills defender
attackerxp_ = game_config::kill_experience*d_->second.level();
if(d_->second.level() == 0)
attackerxp_ = game_config::kill_experience/2;
@ -991,7 +996,7 @@ attack::attack(game_display& gui, const gamemap& map,
d_ = units_.find(death_loc);
a_ = units_.find(attacker_loc);
if(d_ == units_.end() || !death_loc.matches_unit(d_->second)) {
//WML has invalidated the dying unit, abort
// WML has invalidated the dying unit, abort
break;
} else if(d_->second.hitpoints() <= 0) {
units_.erase(d_);
@ -999,13 +1004,13 @@ attack::attack(game_display& gui, const gamemap& map,
}
if(a_ == units_.end() || !attacker_loc.matches_unit(a_->second)) {
//WML has invalidated the killing unit, abort
// WML has invalidated the killing unit, abort
break;
}
refresh_bc();
if(a_stats_->plagues) {
//plague units make new units on the target hex
// plague units make new units on the target hex
game_data::unit_type_map::const_iterator reanimitor;
LOG_NG<<"trying to reanimate "<<a_stats_->plague_type<<std::endl;
reanimitor = info_.unit_types.find(a_stats_->plague_type);
@ -1013,7 +1018,7 @@ attack::attack(game_display& gui, const gamemap& map,
if(reanimitor != info_.unit_types.end()) {
unit newunit=unit(&info_,&units_,&map_,&state_,&teams_,&reanimitor->second,a_->second.side(),true,true);
newunit.set_attacks(0);
//apply variation
// Apply variation
if(strcmp(undead_variation.c_str(),"null")) {
config mod;
config& variation=mod.add_child("effect");
@ -1051,7 +1056,7 @@ attack::attack(game_display& gui, const gamemap& map,
LOG_NG << "defender slowed\n";
}
//if the defender is turned to stone, the fight stops immediately
// If the defender is turned to stone, the fight stops immediately
static const std::string stone_string("stone");
if (a_stats_->stones) {
d_->second.set_state("stoned","yes");
@ -1064,7 +1069,7 @@ attack::attack(game_display& gui, const gamemap& map,
--n_attacks_;
}
//if the defender got to strike first, they use it up here.
// If the defender got to strike first, they use it up here.
defender_strikes_first = false;
abs_n_defend_++;
@ -1080,8 +1085,8 @@ attack::attack(game_display& gui, const gamemap& map,
} else {
damage_attacker_takes = 0;
}
//make sure that if we're serializing a game here,
//we got the same results as the game did originally
// Make sure that if we're serializing a game here,
// we got the same results as the game did originally.
const config* ran_results = get_random_results();
if(ran_results != NULL) {
const int results_chance = atoi((*ran_results)["chance"].c_str());
@ -1131,7 +1136,7 @@ attack::attack(game_display& gui, const gamemap& map,
float_text = float_text + _("slowed") + "\n";
}
//if the defender is turned to stone, the fight stops immediately
// If the defender is turned to stone, the fight stops immediately
static const std::string stone_string("stone");
if (d_stats_->stones) {
float_text = float_text + _("stone") + "\n";
@ -1198,7 +1203,7 @@ attack::attack(game_display& gui, const gamemap& map,
}
}
if(dies) {//defender kills attacker
if(dies) { // defender kills attacker
defenderxp_ = game_config::kill_experience*a_->second.level();
if(a_->second.level() == 0)
defenderxp_ = game_config::kill_experience/2;
@ -1216,7 +1221,7 @@ attack::attack(game_display& gui, const gamemap& map,
refresh_bc();
if(a_ == units_.end() || !death_loc.matches_unit(a_->second)) {
//WML has invalidated the dying unit, abort
// WML has invalidated the dying unit, abort
break;
} else if(a_->second.hitpoints() <= 0) {
units_.erase(a_);
@ -1224,17 +1229,17 @@ attack::attack(game_display& gui, const gamemap& map,
}
if(d_ == units_.end() || !defender_loc.matches_unit(d_->second)) {
//WML has invalidated the killing unit, abort
// WML has invalidated the killing unit, abort
break;
} else if(d_stats_->plagues) {
//plague units make new units on the target hex.
// plague units make new units on the target hex.
game_data::unit_type_map::const_iterator reanimitor;
LOG_NG<<"trying to reanimate "<<d_stats_->plague_type<<std::endl;
reanimitor = info_.unit_types.find(d_stats_->plague_type);
LOG_NG<<"found unit type:"<<reanimitor->second.id()<<std::endl;
if(reanimitor != info_.unit_types.end()) {
unit newunit=unit(&info_,&units_,&map_,&state_,&teams_,&reanimitor->second,d_->second.side(),true,true);
//apply variation
// Apply variation
if(strcmp(undead_variation.c_str(),"null")){
config mod;
config& variation=mod.add_child("effect");
@ -1271,7 +1276,7 @@ attack::attack(game_display& gui, const gamemap& map,
}
//if the attacker is turned to stone, the fight stops immediately
// If the attacker is turned to stone, the fight stops immediately
static const std::string stone_string("stone");
if (d_stats_->stones) {
a_->second.set_state("stoned","yes");
@ -1284,7 +1289,7 @@ attack::attack(game_display& gui, const gamemap& map,
--n_defends_;
}
// continue the fight to death; if one of the units got stoned,
// Continue the fight to death; if one of the units got stoned,
// either n_attacks or n_defends is -1
if(rounds > 0 && n_defends_ == 0 && n_attacks_ == 0) {
n_attacks_ = orig_attacks_;
@ -1342,8 +1347,8 @@ bool get_village(const gamemap::location& loc, std::vector<team>& teams,
const bool has_leader = find_leader(units,int(team_num+1)) != units.end();
bool grants_timebonus = false;
//we strip the village off all other sides, unless it is held by an ally
//and we don't have a leader (and thus can't occupy it)
// We strip the village off all other sides, unless it is held by an ally
// and we don't have a leader (and thus can't occupy it)
for(std::vector<team>::iterator i = teams.begin(); i != teams.end(); ++i) {
const unsigned int side = i - teams.begin() + 1;
if(team_num >= teams.size() || has_leader || teams[team_num].is_enemy(side)) {
@ -1432,7 +1437,7 @@ void calculate_healing(game_display& disp, const gamemap& map,
for(std::vector<std::pair<config*,gamemap::location> >::const_iterator heal_it = heal.cfgs.begin(); heal_it != heal.cfgs.end(); ++heal_it) {
if((*heal_it->first)["poison"] == "cured") {
curer = units.find(heal_it->second);
//full curing only occurs on the healer turn (may be changed)
// Full curing only occurs on the healer turn (may be changed)
if(curer->second.side() == side) {
curing = "cured";
} else if(curing != "cured") {
@ -1445,8 +1450,8 @@ void calculate_healing(game_display& disp, const gamemap& map,
}
}
// For heal amounts, only consider healers on side which is starting now
// remove all healers not on this side
// For heal amounts, only consider healers on side which is starting now.
// Remove all healers not on this side.
for(std::vector<std::pair<config*,gamemap::location> >::iterator h_it = heal.cfgs.begin(); h_it != heal.cfgs.end();) {
unit_map::iterator potential_healer = units.find(h_it->second);
wassert(potential_healer != units.end());
@ -1487,7 +1492,7 @@ void calculate_healing(game_display& disp, const gamemap& map,
healing = map.gives_healing(i->first);
healers.clear();
}
// FIXME
//! @todo FIXME
curing = "cured";
curer = units.end();
}
@ -1594,7 +1599,7 @@ void check_victory(unit_map& units,
}
}
//clear villages for teams that have no leader
// 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_villages();
@ -1627,7 +1632,7 @@ void check_victory(unit_map& units,
if (victory_conditions::victory_when_enemies_defeated() == false
&& (found_player || is_observer())){
// this level has asked not to be ended by this condition
// This level has asked not to be ended by this condition.
return;
}
@ -1712,8 +1717,8 @@ bool clear_shroud_loc(const gamemap& map, team& tm,
adj[6] = loc;
for(int i = 0; i != 7; ++i) {
//we clear one past the edge of the board, so that the half-hexes
//at the edge can also be cleared of fog/shroud
// We clear one past the edge of the board, so that the half-hexes
// at the edge can also be cleared of fog/shroud.
if(map.on_board(adj[i]) || map.on_board(loc)) {
const bool res = tm.clear_shroud(adj[i].x,adj[i].y) ||
tm.clear_fog(adj[i].x,adj[i].y);
@ -1729,9 +1734,9 @@ bool clear_shroud_loc(const gamemap& map, team& tm,
return result;
}
//returns true iff some shroud is cleared
//seen_units will return new units that have been seen by this unit
//if known_units is NULL, seen_units can be NULL and will not be changed
//! Returns true iff some shroud is cleared.
//! seen_units will return new units that have been seen by this unit.
//! If known_units is NULL, seen_units can be NULL and will not be changed.
bool clear_shroud_unit(const gamemap& map,
const gamestatus& status,
const game_data& gamedata,
@ -1755,10 +1760,11 @@ bool clear_shroud_unit(const gamemap& map,
clear_shroud_loc(map,teams[team],i->first,&cleared_locations);
}
//clear the location the unit is at
// Clear the location the unit is at
clear_shroud_loc(map,teams[team],loc,&cleared_locations);
//remove all redundant location, if on this location is unit, sighed event is called twice
// Remove all redundant location.
// If a unit is on this location, the sighed event is called twice.
std::unique(cleared_locations.begin(),cleared_locations.end());
for(std::vector<gamemap::location>::const_iterator it =
@ -1838,7 +1844,7 @@ size_t move_unit(game_display* disp, const game_data& gamedata,
{
wassert(route.empty() == false);
//stop the user from issuing any commands while the unit is moving
// Stop the user from issuing any commands while the unit is moving
const events::command_disabler disable_commands;
unit_map::iterator ui = units.find(route.front());
@ -1864,7 +1870,7 @@ size_t move_unit(game_display* disp, const game_data& gamedata,
}
}
//see how far along the given path we can move
// See how far along the given path we can move.
const int starting_moves = ui->second.movement_left();
int moves_left = starting_moves;
std::set<gamemap::location> seen_units;
@ -1890,18 +1896,18 @@ size_t move_unit(game_display* disp, const game_data& gamedata,
moves_left = 0;
}
//if we use fog or shroud, see if we have sighted an enemy unit, in
//which case we should stop immediately. Cannot use check shroud,
//because also need check if delay shroud is on.
// If we use fog or shroud, see if we have sighted an enemy unit,
// in which case we should stop immediately.
// Cannot use check shroud, because also need to check if delay shroud is on.
if(should_clear_shroud && (team.uses_shroud() || team.uses_fog())) {
if(units.count(*step) == 0 && !map.is_village(*step)) {
LOG_NG << "checking for units from " << (step->x+1) << "," << (step->y+1) << "\n";
//temporarily reset the unit's moves to full
// Temporarily reset the unit's moves to full
const unit_movement_resetter move_resetter(ui->second);
//we have to swap out any unit that is already in the hex, so we can put our
//unit there, then we'll swap back at the end.
// We have to swap out any unit that is already in the hex,
// so we can put our unit there, then we'll swap back at the end.
const temporary_unit_placer unit_placer(units,*step,ui->second);
if( team.auto_shroud_updates()) {
should_clear_stack |= clear_shroud_unit(map,status,gamedata,units,*step,teams,
@ -1915,12 +1921,13 @@ size_t move_unit(game_display* disp, const game_data& gamedata,
}
}
}
//check to see if the unit was deleted during a sighted event in clear_shroud_unit()
// Check to see if the unit was deleted
// during a sighted event in clear_shroud_unit()
ui = units.find(route.front());
if(ui == units.end()) {
//FIXME: the correct behavior for sighted event would be to halt movement,
// then fire "sighted" after firing "moveto" (see below).
//However, since we have fired "sighted" during movement calculations
//! @todo FIXME: the correct behavior for sighted event would be
// to halt movement, then fire "sighted" after firing "moveto" (see below).
// However, since we have fired "sighted" during movement calculations
// this is a workaround to prevent a crash.
if(move_recorder != NULL) {
move_recorder->add_movement(route.front(),*step);
@ -1928,12 +1935,12 @@ size_t move_unit(game_display* disp, const game_data& gamedata,
return (step - route.begin());
}
//check if we have discovered an invisible enemy unit
// Check if we have discovered an invisible enemy unit
gamemap::location adjacent[6];
get_adjacent_tiles(*step,adjacent);
for(int i = 0; i != 6; ++i) {
//check if we are checking ourselves
// Check if we are checking ourselves
if(adjacent[i] == ui->first)
continue;
@ -1953,7 +1960,7 @@ size_t move_unit(game_display* disp, const game_data& gamedata,
}
}
//make sure we don't tread on another unit
// Make sure we don't tread on another unit.
std::vector<gamemap::location>::const_iterator begin = route.begin();
std::vector<gamemap::location> steps(begin,step);
@ -1967,7 +1974,7 @@ size_t move_unit(game_display* disp, const game_data& gamedata,
wassert(steps.size() <= route.size());
//if we can't get all the way there and have to set a go-to.
// If we can't get all the way there and have to set a go-to.
if(steps.size() != route.size() && discovered_unit == false) {
if(seen_units.empty() == false) {
ui->second.set_interrupted_move(route.back());
@ -1985,9 +1992,10 @@ size_t move_unit(game_display* disp, const game_data& gamedata,
if (next_unit != NULL)
*next_unit = steps.back();
//move the unit on the screen. Hide the unit in its current location, but don't actually
//remove it until the move is done, so that while the unit is moving status etc will
//still display the correct number of units.
// Move the unit on the screen. Hide the unit in its current location,
// but don't actually remove it until the move is done,
// so that while the unit is moving status etc.
// will still display the correct number of units.
unit_display::move_unit(map,steps,ui->second,teams);
ui->second.set_movement(moves_left);
@ -2016,7 +2024,7 @@ size_t move_unit(game_display* disp, const game_data& gamedata,
}
if(disp != NULL) {
// clear display helpers before firing events
// Clear display helpers before firing events
disp->unhighlight_reach();
disp->set_route(NULL);
disp->draw();
@ -2031,30 +2039,30 @@ size_t move_unit(game_display* disp, const game_data& gamedata,
apply_shroud_changes(*undo_stack,disp,status,map,gamedata,units,teams,team_num);
undo_stack->clear();
} else {
//MP_COUNTDOWN: added param
// MP_COUNTDOWN: added param
undo_stack->push_back(undo_action(ui->second,steps,starting_moves,action_time_bonus,orig_village_owner));
}
}
if(disp != NULL) {
//show messages on the screen here
// Show messages on the screen here
if(discovered_unit) {
if (ambushed_string.empty())
ambushed_string = _("Ambushed!");
//we've been ambushed, display an appropriate message
// We've been ambushed, display an appropriate message
disp->announce(ambushed_string, font::BAD_COLOUR);
}
if(continue_move == false && seen_units.empty() == false) {
//the message depends on how many units have been sighted, and whether
//they are allies or enemies, so calculate that out here
// The message depends on how many units have been sighted,
// and whether they are allies or enemies, so calculate that out here
int nfriends = 0, nenemies = 0;
for(std::set<gamemap::location>::const_iterator i = seen_units.begin(); i != seen_units.end(); ++i) {
LOG_NG << "processing unit at " << (i->x+1) << "," << (i->y+1) << "\n";
const unit_map::const_iterator u = units.find(*i);
//unit may have been removed by an event.
// Unit may have been removed by an event.
if(u == units.end()) {
LOG_NG << "was removed\n";
continue;
@ -2070,8 +2078,9 @@ size_t move_unit(game_display* disp, const game_data& gamedata,
teams[team_num].see(u->second.side()-1);
}
//the message we display is different depending on whether the units sighted
//were enemies or friends, and their respective number
// The message we display is different depending on
// whether the units sighted were enemies or friends,
// and their respective number.
utils::string_map symbols;
symbols["friends"] = lexical_cast<std::string>(nfriends);
symbols["enemies"] = lexical_cast<std::string>(nenemies);
@ -2094,7 +2103,7 @@ size_t move_unit(game_display* disp, const game_data& gamedata,
}
if(steps.size() < route.size()) {
//see if the "Continue Move" action has an associated hotkey
// See if the "Continue Move" action has an associated hotkey
const hotkey::hotkey_item& hk = hotkey::get_hotkey(hotkey::HOTKEY_CONTINUE_MOVE);
if(!hk.null()) {
symbols["hotkey"] = hk.get_name();
@ -2126,8 +2135,8 @@ bool unit_can_move(const gamemap::location& loc, const unit_map& units,
if(!u.attacks_left() && u.movement_left()==0)
return false;
//units with goto commands that have already done their gotos this turn
//(i.e. don't have full movement left) should be red
// Units with goto commands that have already done their gotos this turn
// (i.e. don't have full movement left) should have red globes.
if(u.has_moved() && u.has_goto()) {
return false;
}
@ -2171,26 +2180,26 @@ void apply_shroud_changes(undo_list& undos, game_display* disp, const gamestatus
for(undo_list::iterator un = undos.begin(); un != undos.end(); ++un) {
std::cout << "Turning an undo...\n";
if(un->is_recall() || un->is_recruit()) continue;
//we're not really going to mutate the unit, just temporarily
//set its moves to maximum, but then switch them back
// We're not really going to mutate the unit, just temporarily
// set its moves to maximum, but then switch them back.
const unit_movement_resetter move_resetter(un->affected_unit);
std::vector<gamemap::location>::const_iterator step;
for(step = un->route.begin(); step != un->route.end(); ++step) {
//we have to swap out any unit that is already in the hex, so we can put our
//unit there, then we'll swap back at the end.
// We have to swap out any unit that is already in the hex,
// so we can put our unit there, then we'll swap back at the end.
const temporary_unit_placer unit_placer(units,*step,un->affected_unit);
clear_shroud_unit(map,status,gamedata,units,*step,teams,team,NULL,NULL);
//FIXME
//there is potential for a bug, here. If the "sighted"
//events, raised by the clear_shroud_unit function,
//loops on all units, changing them all, the unit which
//was swapped by the temporary unit placer will not be
//affected. However, if we place the pump() out of the
//temporary_unit_placer scope, the "sighted" event will
//be raised with an invalid source unit, which is even
//worse.
//! @todo FIXME
// There is potential for a bug, here. If the "sighted"
// events, raised by the clear_shroud_unit function,
// loops on all units, changing them all, the unit which
// was swapped by the temporary unit placer will not be
// affected. However, if we place the pump() out of the
// temporary_unit_placer scope, the "sighted" event will
// be raised with an invalid source unit, which is even
// worse.
game_events::pump();
}
}

View file

@ -12,6 +12,9 @@
See the COPYING file for more details.
*/
//! @file actions.hpp
//! Various functions which implement in-game events and commands.
#ifndef ACTIONS_H_INCLUDED
#define ACTIONS_H_INCLUDED
@ -35,39 +38,36 @@ class game_data;
#define RECRUIT_POS -2
//this file defines various functions which implement different in-game
//events and commands.
bool can_recruit_on(const gamemap& map, const gamemap::location& leader, const gamemap::location loc);
//recruit_unit: function which recruits a unit into the game. A
//copy of u will be created and inserted as the new recruited unit.
//If need_castle is true, then the new unit must be on the same castle
//as the leader of the team is on the keep of.
//! Function which recruits a unit into the game.
// A copy of u will be created and inserted as the new recruited unit.
// If need_castle is true, then the new unit must be on the same castle
// as the leader of the team is on the keep of.
//
//If preferred_location is in a valid location, it will be used, otherwise
//a valid location will be arbitrarily chosen. If disp is not NULL, the
//new unit will be faded in.
// If preferred_location is in a valid location, it will be used,
// otherwise a valid location will be arbitrarily chosen.
// If disp is not NULL, the new unit will be faded in.
//
//If the unit cannot be recruited, then a human-readable message
//describing why not will be returned. On success, the return string is empty
// If the unit cannot be recruited, then a human-readable message
// describing the reason will be returned.
// On success, the return string is empty.
std::string recruit_unit(const gamemap& map, int team, unit_map& units,
unit u, gamemap::location& recruit_location,bool show=false,
bool need_castle=true, bool full_movement=false);
/* The battle_context class computes the statistics of a battle between an
* attacker and a defender unit.
*/
//! Computes the statistics of a battle between an attacker and a defender unit.
class battle_context
{
public:
// Structure describing the statistics of a unit involved in the battle.
//! Structure describing the statistics of a unit involved in the battle.
struct unit_stats
{
const attack_type *weapon; // The weapon used by the unit to attack the opponent, or NULL if there is none.
int attack_num; // Index into unit->attacks() or -1 for none.
bool is_attacker; // True if the unit is the attacker.
bool is_poisoned; // True if the unit is poisoned at the beginning of the battle.
bool is_slowed; // True if the unit is slowed at the beginning of the battle.
bool is_slowed; // True if the unit is slowed at the beginning of the battle.
bool slows; // Attack slows opponent when it hits.
bool drains; // Attack drains opponent when it hits.
bool stones; // Attack turns opponent to stone when it hits.
@ -82,7 +82,7 @@ public:
unsigned int hp; // Hitpoints of the unit at the beginning of the battle.
unsigned int max_hp; // Maximum hitpoints of the unit.
unsigned int chance_to_hit; // Effective chance to hit as a percentage (all factors accounted for).
int damage; // Effective damage of the weapon (all factors accounted for).
int damage; // Effective damage of the weapon (all factors accounted for).
int slow_damage; // Effective damage if unit becomes slowed (== damage, if already slowed)
unsigned int num_blows; // Effective number of blows, takes swarm into account.
unsigned int swarm_min; // Minimum number of blows with swarm (equal to num_blows if swarm isn't used).
@ -99,13 +99,14 @@ public:
const gamestatus& status, const gamemap& map, const game_data& gamedata);
~unit_stats();
// This method dumps the statistics of a unit on stdout. Remove it eventually.
//! Dumps the statistics of a unit on stdout. Remove it eventually.
void dump() const;
};
// If no attacker_weapon is given, we select best one, based on
// harm_weight (1.0 means 1 hp lost counters 1 hp damage, 0.0
// means we ignore harm weight). prev_def is for predicting multiple attacks against a defender.
// If no attacker_weapon is given, we select the best one,
// based on harm_weight (1.0 means 1 hp lost counters 1 hp damage,
// 0.0 means we ignore harm weight).
// prev_def is for predicting multiple attacks against a defender.
battle_context(const gamemap& map, const std::vector<team>& teams, const unit_map& units,
const gamestatus& status, const game_data& gamedata,
const gamemap::location& attacker_loc, const gamemap::location& defender_loc,
@ -119,17 +120,17 @@ public:
battle_context& operator=(const battle_context &other);
// This method returns the statistics of the attacker.
//! This method returns the statistics of the attacker.
const unit_stats& get_attacker_stats() const { return *attacker_stats_; }
// This method returns the statistics of the defender.
//! This method returns the statistics of the defender.
const unit_stats& get_defender_stats() const { return *defender_stats_; }
// Get the simulation results.
//! Get the simulation results.
const combatant &get_attacker_combatant(const combatant *prev_def = NULL);
const combatant &get_defender_combatant(const combatant *prev_def = NULL);
// Given this harm_weight, is this attack betteer than that?
//! Given this harm_weight, is this attack better than that?
bool better_attack(class battle_context &that, double harm_weight);
private:
@ -155,7 +156,7 @@ private:
combatant *attacker_combatant_, *defender_combatant_;
};
//attack: executes an attack.
//! Executes an attack.
class attack {
public:
attack(game_display& gui, const gamemap& map,
@ -198,70 +199,74 @@ class attack {
int attackerxp_,defenderxp_;
};
//given the location of a village, will return the 0-based index of the team
//that currently owns it, and -1 if it is unowned.
//! Given the location of a village, will return the 0-based index
//! of the team that currently owns it, and -1 if it is unowned.
int village_owner(const gamemap::location& loc, const std::vector<team>& teams);
//makes it so the village at the given location is owned by the given
//0-based team number. Returns true if getting the village triggered a mutating event
//! Makes it so the village at the given location
//! is owned by the given 0-based team number.
//! Returns true if getting the village triggered a mutating event.
bool get_village(const gamemap::location& loc, std::vector<team>& teams,
size_t team_num, const unit_map& units, int *time_bonus = NULL);
//given the 1-based side, will find the leader of that side,
//and return an iterator to the leader
//! Given the 1-based side, will find the leader of that side,
//! and return an iterator to the leader
unit_map::iterator find_leader(unit_map& units, int side);
unit_map::const_iterator find_leader(const unit_map& units, int side);
// Resets resting for all units on this side: should be called after calculate_healing().
// FIXME: Try moving this to unit::new_turn, then move it above calculate_healing().
//! Resets resting for all units on this side: should be called after calculate_healing().
//! @todo FIXME: Try moving this to unit::new_turn, then move it above calculate_healing().
void reset_resting(unit_map& units, unsigned int side);
//calculates healing for all units for the given side. Should be called
//at the beginning of a side's turn.
//! Calculates healing for all units for the given side.
//! Should be called at the beginning of a side's turn.
void calculate_healing(game_display& disp, const gamemap& map,
unit_map& units, unsigned int side,
const std::vector<team>& teams, bool update_display);
//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
//this unit. (with traits and items retained).
//! 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 this unit.
//! (with traits and items retained).
unit get_advanced_unit(const game_data& info,
unit_map& units,
const gamemap::location& loc, const std::string& advance_to);
//function which will advance the unit at loc to 'advance_to'.
//note that 'loc' is not a reference, because if it were a reference, we couldn't
//safely pass in a reference to the item in the map that we're going to delete,
//since deletion would invalidate the reference.
//! Function which will advance the unit at loc to 'advance_to'.
// Note that 'loc' is not a reference, because if it were a reference,
// we couldn't safely pass in a reference to the item in the map
// that we're going to delete, since deletion would invalidate the reference.
void advance_unit(const game_data& info,
unit_map& units,
gamemap::location loc, const std::string& advance_to);
//function which tests if the unit at loc is currently affected
//by leadership. (i.e. has a higher-level 'leadership' unit next to it).
//if it does, then the location of the leader unit will be returned, otherwise
//gamemap::location::null_location will be returned
//if 'bonus' is not NULL, the % bonus will be stored in it
//! function which tests if the unit at loc is currently affected by leadership.
//! (i.e. has a higher-level 'leadership' unit next to it).
//! If it does, then the location of the leader unit will be returned,
//! Otherwise gamemap::location::null_location will be returned.
//! If 'bonus' is not NULL, the % bonus will be stored in it.
gamemap::location under_leadership(const unit_map& units,
const gamemap::location& loc, int* bonus=NULL);
//checks to see if a side has won, and will throw an end_level_exception
//if one has. Will also remove control of villages from sides with dead leaders
//! Checks to see if a side has won, and will throw
//! an end_level_exception if one has.
//! Will also remove control of villages from sides with dead leaders.
void check_victory(unit_map& units,
std::vector<team>& teams,
game_state &gamestate);
//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
//in that tile or adjacent.
//! 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 in that tile or adjacent.
time_of_day timeofday_at(const gamestatus& status,
const unit_map& units,
const gamemap::location& loc,
const gamemap& map);
//returns the amount that a unit's damage should be multiplied by due to
//the current time of day.
//! Returns the amount that a unit's damage should be multiplied by
//! due to the current time of day.
int combat_modifier(const gamestatus& status,
const unit_map& units,
const gamemap::location& loc,
@ -269,7 +274,7 @@ int combat_modifier(const gamestatus& status,
bool is_fearless,
const gamemap& map);
//structure which records information to be able to undo a movement
//! Records information to be able to undo a movement.
struct undo_action {
undo_action(unit u,const std::vector<gamemap::location>& rt,int sm,int timebonus=0,int orig=-1)
: route(rt), starting_moves(sm), original_village_owner(orig), recall_pos(-1), affected_unit(u), countdown_time_bonus(timebonus) {}
@ -288,10 +293,11 @@ struct undo_action {
typedef std::deque<undo_action> undo_list;
//function which moves a unit along the sequence of locations given by
//steps. If the unit cannot make it completely along the path this turn,
//a goto order will be set. If move_recorder is not NULL, the move will
//be recorded in it. If undos is not NULL, undo information will be added.
//! function which moves a unit along the sequence of locations given by steps.
//! If the unit cannot make it completely along the path this turn,
//! a goto order will be set.
//! If move_recorder is not NULL, the move will be recorded in it.
//! If undos is not NULL, undo information will be added.
size_t move_unit(game_display* disp, const game_data& gamedata,
const gamestatus& status, const gamemap& map,
unit_map& units, std::vector<team>& teams,
@ -300,24 +306,25 @@ size_t move_unit(game_display* disp, const game_data& gamedata,
gamemap::location *next_unit = NULL,
bool continue_move = false, bool should_clear_shroud=true);
//function which recalculates the fog
//! Function which recalculates the fog.
void recalculate_fog(const gamemap& map, const gamestatus& status,
const game_data& gamedata,
unit_map& units, std::vector<team>& teams, int team);
//function which will clear shroud away for the given 0-based team based on
//current unit positions. Returns true if some shroud is actually cleared away.
//! Function which will clear shroud away for the given 0-based team
//! based on current unit positions.
//! Returns true if some shroud is actually cleared away.
bool clear_shroud(game_display& disp, const gamestatus& status,
const gamemap& map, const game_data& gamedata,
unit_map& units, std::vector<team>& teams, int team);
//function to apply pending shroud changes in the undo stack.
//it needs tons of parameters because it calls clear_shroud(...) (see above)
//! Function to apply pending shroud changes in the undo stack.
//! It needs tons of parameters because it calls clear_shroud(...) (see above)
void apply_shroud_changes(undo_list& undos, game_display* disp, const gamestatus& status, const gamemap& map,
const game_data& gamedata, unit_map& units, std::vector<team>& teams, int team);
//will return true iff the unit at 'loc' has any possible moves it can do
//(including attacking etc).
//! Will return true iff the unit at 'loc' has any possible moves
//! it can do (including attacking etc).
bool unit_can_move(const gamemap::location& loc, const unit_map& units,
const gamemap& map, const std::vector<team>& teams);
@ -326,12 +333,16 @@ namespace victory_conditions {
void set_victory_when_enemies_defeated(bool on);
}
//Function to check if an attack will satisfy the requirements for backstab
//given the location from which the attack will occur, the defending unit
//location, the list of units on the map and the list of teams.
//The defender and opposite units should be in place already. The
//attacking unit doesn't need to be, but if it isn't, an external check should
//be made to make sure the opposite unit isn't also the attacker.
//! Function to check if an attack will satisfy the requirements for backstab.
//! Input:
//! - the location from which the attack will occur,
//! - the defending unit location,
//! - the list of units on the map and
//! - the list of teams.
//! The defender and opposite units should be in place already.
//! The attacking unit doesn't need to be, but if it isn't,
//! an external check should be made to make sure the opposite unit
//! isn't also the attacker.
bool backstab_check(const gamemap::location& attacker_loc,
const gamemap::location& defender_loc,
const unit_map& units, const std::vector<team>& teams);