actions.hpp

Go to the documentation of this file.
00001 /* $Id: actions.hpp 26154 2008-04-27 01:44:58Z alink $ */
00002 /*
00003    Copyright (C) 2003 - 2008 by David White <dave@whitevine.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License version 2
00008    or at your option any later version.
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY.
00011 
00012    See the COPYING file for more details.
00013 */
00014 
00015 //! @file actions.hpp
00016 //! Various functions which implement in-game events and commands.
00017 
00018 #ifndef ACTIONS_H_INCLUDED
00019 #define ACTIONS_H_INCLUDED
00020 
00021 class display;
00022 class gamestatus;
00023 class game_display;
00024 class replay;
00025 struct combatant;
00026 class unit;
00027 
00028 class attack_type;
00029 class team;
00030 class unit_type_data;
00031 
00032 #include "global.hpp"
00033 #include "map.hpp"
00034 #include "unit.hpp"
00035 #include "unit_map.hpp"
00036 #include "unit_types.hpp"
00037 
00038 #include <deque>
00039 #include <sstream>
00040 
00041 #define RECRUIT_POS -2
00042 
00043 bool can_recruit_on(const gamemap& map, const gamemap::location& leader, const gamemap::location loc);
00044 
00045 struct end_level_exception;
00046 
00047 //! Function which recruits a unit into the game.
00048 // A copy of u will be created and inserted as the new recruited unit.
00049 // If need_castle is true, then the new unit must be on the same castle
00050 // as the leader of the team is on the keep of.
00051 //
00052 // If preferred_location is in a valid location, it will be used,
00053 // otherwise a valid location will be arbitrarily chosen.
00054 // If disp is not NULL, the new unit will be faded in.
00055 //
00056 // If the unit cannot be recruited, then a human-readable message
00057 // describing the reason will be returned.
00058 // On success, the return string is empty.
00059 std::string recruit_unit(const gamemap& map, const int side, unit_map& units,
00060         unit u, gamemap::location& recruit_location,const bool is_recall,
00061         const bool show=false,const bool need_castle=true, 
00062         const bool full_movement=false,const bool wml_triggered=false);
00063 
00064 //! Computes the statistics of a battle between an attacker and a defender unit.
00065 class battle_context
00066 {
00067 public:
00068     //! Structure describing the statistics of a unit involved in the battle.
00069     struct unit_stats
00070     {
00071         const attack_type *weapon;  // The weapon used by the unit to attack the opponent, or NULL if there is none.
00072         int attack_num;         // Index into unit->attacks() or -1 for none.
00073         bool is_attacker;       // True if the unit is the attacker.
00074         bool is_poisoned;       // True if the unit is poisoned at the beginning of the battle.
00075         bool is_slowed;         // True if the unit is slowed at the beginning of the battle.
00076         bool slows;             // Attack slows opponent when it hits.
00077         bool drains;            // Attack drains opponent when it hits.
00078         bool stones;            // Attack turns opponent to stone when it hits.
00079         bool plagues;           // Attack turns opponent into a zombie when fatal.
00080         bool poisons;           // Attack poisons opponent when it hits.
00081         bool backstab_pos;      // True if the attacker is in *position* to backstab the defender (this is used to
00082                                 // determine whether to apply the backstab bonus in case the attacker has backstab).
00083         bool swarm;             // Attack has swarm special.
00084         bool firststrike;       // Attack has firststrike special.
00085 
00086         unsigned int rounds;    // Berserk special can force us to fight more than one round.
00087         unsigned int hp;        // Hitpoints of the unit at the beginning of the battle.
00088         unsigned int max_hp;    // Maximum hitpoints of the unit.
00089         unsigned int chance_to_hit; // Effective chance to hit as a percentage (all factors accounted for).
00090         int damage;             // Effective damage of the weapon (all factors accounted for).
00091         int slow_damage;        // Effective damage if unit becomes slowed (== damage, if already slowed)
00092         unsigned int num_blows; // Effective number of blows, takes swarm into account.
00093         unsigned int swarm_min; // Minimum number of blows with swarm (equal to num_blows if swarm isn't used).
00094         unsigned int swarm_max; // Maximum number of blows with swarm (equal to num_blows if swarm isn't used).
00095 
00096         std::string plague_type; // The plague type used by the attack, if any.
00097 
00098         unit_stats(const unit &u, const gamemap::location& u_loc,
00099                    int u_attack_num, bool attacking,
00100                    const unit &opp, const gamemap::location& opp_loc,
00101                    const attack_type *opp_weapon,
00102                    const unit_map& units,
00103                    const std::vector<team>& teams,
00104                    const gamestatus& status, const gamemap& map);
00105         ~unit_stats();
00106 
00107         //! Dumps the statistics of a unit on stdout. Remove it eventually.
00108         void dump() const;
00109     };
00110 
00111     // If no attacker_weapon is given, we select the best one,
00112     // based on harm_weight (1.0 means 1 hp lost counters 1 hp damage,
00113     // 0.0 means we ignore harm weight).
00114     // prev_def is for predicting multiple attacks against a defender.
00115     battle_context(const gamemap& map, const std::vector<team>& teams, const unit_map& units,
00116                    const gamestatus& status,
00117                    const gamemap::location& attacker_loc, const gamemap::location& defender_loc,
00118                    int attacker_weapon = -1, int defender_weapon = -1, double aggression = 0.0, const combatant *prev_def = NULL, const unit* attacker_ptr=NULL);
00119 
00120     // Used by the AI which caches unit_stats
00121     battle_context(const unit_stats &att, const unit_stats &def);
00122 
00123     battle_context(const battle_context &other);
00124     ~battle_context();
00125 
00126     battle_context& operator=(const battle_context &other);
00127 
00128     //! This method returns the statistics of the attacker.
00129     const unit_stats& get_attacker_stats() const { return *attacker_stats_; }
00130 
00131     //! This method returns the statistics of the defender.
00132     const unit_stats& get_defender_stats() const { return *defender_stats_; }
00133 
00134     //! Get the simulation results.
00135     const combatant &get_attacker_combatant(const combatant *prev_def = NULL);
00136     const combatant &get_defender_combatant(const combatant *prev_def = NULL);
00137 
00138     //! Given this harm_weight, is this attack better than that?
00139     bool better_attack(class battle_context &that, double harm_weight);
00140 
00141 private:
00142     bool better_combat(const combatant &us_a, const combatant &them_a,
00143                        const combatant &us_b, const combatant &them_b,
00144                        double harm_weight);
00145 
00146     int choose_attacker_weapon(const unit &attacker, const unit &defender,
00147                                 const gamemap& map, const std::vector<team>& teams, const unit_map& units,
00148                                 const gamestatus& status,
00149                                 const gamemap::location& attacker_loc, const gamemap::location& defender_loc,
00150                                 double harm_weight, int *defender_weapon, const combatant *prev_def);
00151 
00152     int choose_defender_weapon(const unit &attacker, const unit &defender, unsigned attacker_weapon,
00153                                const gamemap& map, const std::vector<team>& teams, const unit_map& units,
00154                                const gamestatus& status,
00155                                const gamemap::location& attacker_loc, const gamemap::location& defender_loc, const combatant *prev_def);
00156 
00157     // Statistics of the units.
00158     unit_stats *attacker_stats_, *defender_stats_;
00159 
00160     // Outcome of simulated fight.
00161     combatant *attacker_combatant_, *defender_combatant_;
00162 };
00163 
00164 //! Executes an attack.
00165 class attack {
00166     public:
00167         attack(game_display& gui, const gamemap& map,
00168             std::vector<team>& teams,
00169             gamemap::location attacker,
00170             gamemap::location defender,
00171             int attack_with,
00172             int defend_with,
00173             unit_map& units,
00174             const gamestatus& state,
00175             bool update_display = true);
00176         ~attack();
00177     private:
00178         class attack_end_exception {};
00179         void fire_event(const std::string& n);
00180         void refresh_bc();
00181         game_display& gui_;
00182         const gamemap& map_;
00183         std::vector<team>& teams_;
00184         gamemap::location attacker_;
00185         gamemap::location defender_;
00186         int attack_with_;
00187         int defend_with_;
00188         unit_map& units_;
00189         const gamestatus& state_;
00190         unit_map::iterator a_,d_; // attacker and defender
00191         std::string a_id_, d_id_;
00192         std::stringstream errbuf_;
00193         battle_context* bc_;
00194         const battle_context::unit_stats* a_stats_;
00195         const battle_context::unit_stats* d_stats_;
00196         int orig_attacks_,orig_defends_;
00197         int n_attacks_,n_defends_;
00198         int attacker_cth_,defender_cth_;
00199         int attacker_damage_,defender_damage_;
00200         int attackerxp_,defenderxp_;
00201 
00202         bool update_display_;
00203         bool OOS_error_;
00204         end_level_exception* delayed_exception;
00205 
00206 };
00207 
00208 //! Given the location of a village, will return the 0-based index
00209 //! of the team that currently owns it, and -1 if it is unowned.
00210 int village_owner(const gamemap::location& loc, const std::vector<team>& teams);
00211 
00212 //! Makes it so the village at the given location
00213 //! is owned by the given 0-based team number.
00214 //! Returns true if getting the village triggered a mutating event.
00215 bool get_village(const gamemap::location& loc, game_display& disp,
00216                  std::vector<team>& teams, size_t team_num,
00217                  const unit_map& units, int *time_bonus = NULL);
00218 
00219 //! Given the 1-based side, will find the leader of that side,
00220 //! and return an iterator to the leader
00221 unit_map::iterator find_leader(unit_map& units, int side);
00222 
00223 unit_map::const_iterator find_leader(const unit_map& units, int side);
00224 
00225 //! Resets resting for all units on this side: should be called after calculate_healing().
00226 //! @todo FIXME: Try moving this to unit::new_turn, then move it above calculate_healing().
00227 void reset_resting(unit_map& units, unsigned int side);
00228 
00229 //! Calculates healing for all units for the given side.
00230 //! Should be called at the beginning of a side's turn.
00231 void calculate_healing(game_display& disp, const gamemap& map,
00232                        unit_map& units, unsigned int side,
00233                        const std::vector<team>& teams, bool update_display);
00234 
00235 //! Function which, given the location of a unit that is advancing,
00236 //! and the name of the unit it is advancing to,
00237 //! Will return the advanced version of this unit.
00238 //! (with traits and items retained).
00239 unit get_advanced_unit(unit_map& units,
00240                   const gamemap::location& loc, const std::string& advance_to);
00241 
00242 //! Function which will advance the unit at loc to 'advance_to'.
00243 //  Note that 'loc' is not a reference, because if it were a reference,
00244 //  we couldn't safely pass in a reference to the item in the map
00245 //  that we're going to delete, since deletion would invalidate the reference.
00246 void advance_unit(unit_map& units,
00247                   gamemap::location loc, const std::string& advance_to);
00248 
00249 //! function which tests if the unit at loc is currently affected by leadership.
00250 //! (i.e. has a higher-level 'leadership' unit next to it).
00251 //! If it does, then the location of the leader unit will be returned,
00252 //! Otherwise gamemap::location::null_location will be returned.
00253 //! If 'bonus' is not NULL, the % bonus will be stored in it.
00254 gamemap::location under_leadership(const unit_map& units,
00255                                    const gamemap::location& loc, int* bonus=NULL);
00256 
00257 //! Checks to see if a side has won, and will throw
00258 //! an end_level_exception if one has.
00259 //! Will also remove control of villages from sides with dead leaders.
00260 void check_victory(unit_map& units, std::vector<team>& teams, display& disp);
00261 
00262 //! Gets the time of day at a certain tile.
00263 //! Certain tiles may have a time of day that differs
00264 //! from 'the' time of day, if a unit that illuminates
00265 //! is in that tile or adjacent.
00266 time_of_day timeofday_at(const gamestatus& status,
00267                               const unit_map& units,
00268                               const gamemap::location& loc,
00269                   const gamemap& map);
00270 
00271 //! Returns the amount that a unit's damage should be multiplied by
00272 //! due to the current time of day.
00273 int combat_modifier(const gamestatus& status,
00274             const unit_map& units,
00275             const gamemap::location& loc,
00276             unit_type::ALIGNMENT alignment,
00277             bool is_fearless,
00278             const gamemap& map);
00279 
00280 //! Records information to be able to undo a movement.
00281 struct undo_action {
00282     undo_action(const unit& u,
00283         const std::vector<gamemap::location>& rt,
00284         int sm, int timebonus = 0, int orig = -1) :
00285             route(rt),
00286             starting_moves(sm),
00287             original_village_owner(orig),
00288             recall_loc(),
00289             recall_pos(-1),
00290             affected_unit(u),
00291             countdown_time_bonus(timebonus)
00292             {}
00293 
00294     undo_action(const unit& u, const gamemap::location& loc, const int pos) :
00295         route(),
00296         starting_moves(),
00297         original_village_owner(),
00298         recall_loc(loc),
00299         recall_pos(pos),
00300         affected_unit(u),
00301         countdown_time_bonus(1)
00302         {}
00303 
00304     std::vector<gamemap::location> route;
00305     int starting_moves;
00306     int original_village_owner;
00307     gamemap::location recall_loc;
00308     int recall_pos; // set to RECRUIT_POS for an undo-able recruit
00309     unit affected_unit;
00310     int countdown_time_bonus;
00311     bool is_recall() const { return recall_pos >= 0; }
00312     bool is_recruit() const { return recall_pos == RECRUIT_POS; }
00313 };
00314 
00315 typedef std::deque<undo_action> undo_list;
00316 
00317 //! function which moves a unit along the sequence of locations given by steps.
00318 //! If the unit cannot make it completely along the path this turn,
00319 //! a goto order will be set.
00320 //! If move_recorder is not NULL, the move will be recorded in it.
00321 //! If undos is not NULL, undo information will be added.
00322 size_t move_unit(game_display* disp,
00323                 const gamemap& map,
00324                 unit_map& units, std::vector<team>& teams,
00325                 std::vector<gamemap::location> steps,
00326                 replay* move_recorder, undo_list* undos,
00327                 gamemap::location *next_unit = NULL,
00328                 bool continue_move = false, bool should_clear_shroud=true);
00329 
00330 //! Function which recalculates the fog.
00331 void recalculate_fog(const gamemap& map,
00332               unit_map& units, std::vector<team>& teams, int team);
00333 
00334 //! Function which will clear shroud away for the given 0-based team
00335 //! based on current unit positions.
00336 //! Returns true if some shroud is actually cleared away.
00337 bool clear_shroud(game_display& disp,
00338         const gamemap& map,
00339         unit_map& units, std::vector<team>& teams, int team);
00340 
00341 //! Function to apply pending shroud changes in the undo stack.
00342 //! It needs tons of parameters because it calls clear_shroud(...) (see above)
00343 void apply_shroud_changes(undo_list& undos, game_display* disp, const gamemap& map,
00344     unit_map& units, std::vector<team>& teams, int team);
00345 
00346 //! Will return true iff the unit at 'loc' has any possible moves
00347 //! it can do (including attacking etc).
00348 bool unit_can_move(const gamemap::location& loc, const unit_map& units,
00349                    const gamemap& map, const std::vector<team>& teams);
00350 
00351 
00352 namespace victory_conditions {
00353     void set_victory_when_enemies_defeated(const bool on);
00354     void set_carryover_percentage(const int percentage);
00355     void set_carryover_add(const bool add);
00356 }
00357 
00358 //! Function to check if an attack will satisfy the requirements for backstab.
00359 //! Input:
00360 //! - the location from which the attack will occur,
00361 //! - the defending unit location,
00362 //! - the list of units on the map and
00363 //! - the list of teams.
00364 //! The defender and opposite units should be in place already.
00365 //! The attacking unit doesn't need to be, but if it isn't,
00366 //! an external check should be made to make sure the opposite unit
00367 //! isn't also the attacker.
00368 bool backstab_check(const gamemap::location& attacker_loc,
00369     const gamemap::location& defender_loc,
00370     const unit_map& units, const std::vector<team>& teams);
00371 
00372 #endif

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs