unit.hpp

Go to the documentation of this file.
00001 /* $Id: unit.hpp 26761 2008-05-21 19:57:09Z mordante $ */
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 unit.hpp */
00016 
00017 #ifndef UNIT_H_INCLUDED
00018 #define UNIT_H_INCLUDED
00019 
00020 #include "config.hpp"
00021 #include "map.hpp"
00022 #include "race.hpp"
00023 #include "team.hpp"
00024 #include "unit_types.hpp"
00025 #include "unit_map.hpp"
00026 #include "formula_callable.hpp"
00027 
00028 class game_display;
00029 class gamestatus;
00030 class game_state;
00031 class config_writer;
00032 
00033 #include <set>
00034 #include <string>
00035 #include <vector>
00036 
00037 class unit_ability_list
00038 {
00039 public:
00040 
00041     bool empty() const;
00042 
00043     std::pair<int,gamemap::location> highest(const std::string& key, int def=0) const;
00044     std::pair<int,gamemap::location> lowest(const std::string& key, int def=100) const;
00045 
00046     std::vector<std::pair<config*,gamemap::location> > cfgs;
00047 };
00048 
00049 
00050 class unit
00051 {
00052 public:
00053     /**
00054      * Clear the unit status cache for all units. Currently only the hidden
00055      * status of units is cached this way.
00056      */
00057     static void clear_status_caches();
00058 
00059     friend struct unit_movement_resetter;
00060     // Copy constructor
00061     unit(const unit& u);
00062     /** Initilizes a unit from a config */
00063     unit(const config& cfg, bool use_traits=false);
00064     unit(unit_map* unitmap, const gamemap* map,
00065         const gamestatus* game_status, const std::vector<team>* teams,
00066         const config& cfg, bool use_traits=false, game_state* state = 0);
00067     /** Initializes a unit from a unit type */
00068     unit(const unit_type* t, int side, bool use_traits=false, bool dummy_unit=false, unit_race::GENDER gender=unit_race::MALE, std::string variation="");
00069     unit(unit_map* unitmap, const gamemap* map, const gamestatus* game_status, const std::vector<team>* teams, const unit_type* t, int side, bool use_traits=false, bool dummy_unit=false, unit_race::GENDER gender=unit_race::MALE, std::string variation="");
00070     virtual ~unit();
00071     unit& operator=(const unit&);
00072 
00073     void set_game_context(unit_map* unitmap, const gamemap* map, const gamestatus* game_status, const std::vector<team>* teams);
00074 
00075     /** Advances this unit to another type */
00076     void advance_to(const unit_type* t, bool use_traits=false, game_state* state = 0);
00077     const std::vector<std::string> advances_to() const { return advances_to_; }
00078 
00079     /** The type id of the unit */
00080     const std::string& type_id() const { return type_; }
00081     const unit_type* type() const;
00082 
00083     /** The unique internal ID of the unit */
00084     const std::string& id() const { if (id_.empty()) return type_name(); else return id_; }
00085     const std::string& underlying_id() const { return underlying_id_; }
00086 
00087     /** The unit type name */
00088     const t_string& type_name() const {return type_name_;}
00089     const std::string& undead_variation() const {return undead_variation_;}
00090 
00091     /** The unit name for display */
00092     const std::string& name() const {return (name_);}
00093     void rename(const std::string& name) {if (!unrenamable_) name_= name;}
00094 
00095     /** The unit's profile */
00096     const std::string& profile() const;
00097     /** Information about the unit -- a detailed description of it */
00098     const std::string& unit_description() const { return cfg_["description"]; }
00099 
00100     int hitpoints() const { return hit_points_; }
00101     int max_hitpoints() const { return max_hit_points_; }
00102     int experience() const { return experience_; }
00103     int max_experience() const { return maximum<int>(1,(max_experience_*unit_type::experience_accelerator::get_acceleration() + 50) / 100); }
00104     int level() const { return level_; }
00105     /**
00106      * Adds 'xp' points to the units experience; returns true if advancement
00107      * should occur
00108      */
00109     bool get_experience(int xp) { experience_ += xp; return advances(); }
00110     /** Colors for the unit's hitpoints. */
00111     SDL_Colour hp_color() const;
00112     /** Colors for the unit's XP. */
00113     SDL_Colour xp_color() const;
00114     /** Set to true for some scenario-specific units which should not be renamed */
00115     bool unrenamable() const { return unrenamable_; }
00116     unsigned int side() const { return side_; }
00117     Uint32 team_rgb() const { return(team::get_side_rgb(side())); }
00118     const std::string& team_color() const { return flag_rgb_; }
00119     unit_race::GENDER gender() const { return gender_; }
00120     void set_side(unsigned int new_side) { side_ = new_side; }
00121     fixed_t alpha() const { return alpha_; }
00122 
00123     bool can_recruit() const { return utils::string_bool(cfg_["canrecruit"]); }
00124     bool incapacitated() const { return utils::string_bool(get_state("stoned"),false); }
00125     const std::vector<std::string>& recruits() const { return recruits_; }
00126     int total_movement() const { return max_movement_; }
00127     int movement_left() const { return (movement_ == 0 || incapacitated()) ? 0 : movement_; }
00128     void set_hold_position(bool value) { hold_position_ = value; }
00129     bool hold_position() const { return hold_position_; }
00130     void set_user_end_turn(bool value=true) { end_turn_ = value; }
00131     bool user_end_turn() const { return end_turn_; }
00132     int attacks_left() const { return (attacks_left_ == 0 || incapacitated()) ? 0 : attacks_left_; }
00133     void set_movement(int moves);
00134     void set_attacks(int left) { attacks_left_ = maximum<int>(0,minimum<int>(left,max_attacks_)); }
00135     void unit_hold_position() { hold_position_ = end_turn_ = true; }
00136     void new_turn();
00137     void end_turn();
00138     void new_level();
00139     /** Called on every draw */
00140     void refresh(const game_display& disp,const gamemap::location& loc) {
00141         if (state_ == STATE_FORGET  && anim_ && anim_->animation_finished_potential()) {
00142             set_standing( loc);
00143             return;
00144         }
00145         if (state_ != STATE_STANDING || (get_current_animation_tick() < next_idling_) || incapacitated()) return;
00146         if (get_current_animation_tick() > next_idling_ + 1000) { // prevent all units animating at the same
00147             set_standing(loc);
00148         } else {
00149             set_idling(disp, loc);
00150         }
00151     }
00152 
00153     bool take_hit(int damage) { hit_points_ -= damage; return hit_points_ <= 0; }
00154     void heal(int amount);
00155     void heal_all() { hit_points_ = max_hitpoints(); }
00156     bool resting() const { return resting_; }
00157     void set_resting(bool rest) { resting_ = rest; }
00158 
00159     const std::string get_state(const std::string& state) const;
00160     void set_state(const std::string& state, const std::string& value);
00161 
00162     bool has_moved() const { return movement_left() != total_movement(); }
00163     bool has_goto() const { return get_goto().valid(); }
00164     int emits_zoc() const { return emit_zoc_ && !incapacitated();}
00165     /* cfg: standard unit filter */
00166     bool matches_filter(const vconfig& cfg,const gamemap::location& loc,bool use_flat_tod=false) const;
00167     void add_overlay(const std::string& overlay) { overlays_.push_back(overlay); }
00168     void remove_overlay(const std::string& overlay) { overlays_.erase(std::remove(overlays_.begin(),overlays_.end(),overlay),overlays_.end()); }
00169     const std::vector<std::string>& overlays() const { return overlays_; }
00170 
00171     /** 
00172      * Initialize this unit from a cfg object. 
00173      *
00174      * @param cfg                 Configuration object from which to read the unit.
00175      * @param use_traits          ??
00176      * */
00177     void read(const config& cfg, bool use_traits=true, game_state* state = 0);
00178     void write(config& cfg) const;
00179 //  void write(config_writer& out) const;
00180 
00181     void assign_role(const std::string& role) { role_ = role; }
00182     void assign_ai_special(const std::string& s) { ai_special_ = s;}
00183             std::string get_ai_special() const { return(ai_special_); }
00184     const std::vector<attack_type>& attacks() const { return attacks_; }
00185     std::vector<attack_type>& attacks() { return attacks_; }
00186 
00187     int damage_from(const attack_type& attack,bool attacker,const gamemap::location& loc) const { return resistance_against(attack,attacker,loc); }
00188 
00189     /** A SDL surface, ready for display for place where we need a still-image of the unit. */
00190     const surface still_image(bool scaled = false) const;
00191     /** 
00192      * draw a unit, fake is used for temporary unit not in unit_map (so we can
00193      * skip functions assuming that)
00194      */
00195     void redraw_unit(game_display& disp, const gamemap::location& loc, const bool fake = false);
00196     /** Clear unit_halo_ and unit_anim_halo_ */
00197     void clear_haloes();
00198 
00199 
00200     void set_standing(const gamemap::location& loc, bool with_bars = true);
00201     void set_idling(const game_display& disp,const gamemap::location& loc);
00202     void set_selecting(const game_display& disp,const gamemap::location& loc);
00203     unit_animation* get_animation() {  return anim_;};
00204     const unit_animation* get_animation() const {  return anim_;};
00205     void set_facing(gamemap::location::DIRECTION dir);
00206     gamemap::location::DIRECTION facing() const { return facing_; }
00207 
00208     std::set<gamemap::location> overlaps(const gamemap::location &loc) const;
00209     const t_string& traits_description() const { return traits_description_; }
00210 
00211     int cost () const { return unit_value_; }
00212 
00213     const gamemap::location& get_goto() const { return goto_; }
00214     void set_goto(const gamemap::location& new_goto) { goto_ = new_goto; }
00215 
00216     int upkeep() const;
00217 
00218     void set_hidden(bool state);
00219     bool get_hidden() { return hidden_; };
00220     bool is_flying() const { return flying_; }
00221     bool is_fearless() const { return is_fearless_; }
00222     bool is_healthy() const { return is_healthy_; }
00223     int movement_cost(const t_translation::t_terrain terrain) const;
00224     int defense_modifier(t_translation::t_terrain terrain, int recurse_count=0) const;
00225     int resistance_against(const std::string& damage_name,bool attacker,const gamemap::location& loc) const;
00226     int resistance_against(const attack_type& damage_type,bool attacker,const gamemap::location& loc) const
00227         {return resistance_against(damage_type.type(), attacker, loc);};
00228 
00229     //return resistances without any abililities applied
00230     string_map get_base_resistances() const;
00231 //      std::map<terrain_type::TERRAIN,int> movement_type() const;
00232 
00233     bool can_advance() const { return advances_to_.empty()==false || get_modification_advances().empty() == false; }
00234     bool advances() const { return experience_ >= max_experience() && can_advance(); }
00235 
00236     std::map<std::string,std::string> advancement_icons() const;
00237     std::vector<std::pair<std::string,std::string> > amla_icons() const;
00238 
00239     config::child_list get_modification_advances() const;
00240     const config::child_list& modification_advancements() const { return cfg_.get_children("advancement"); }
00241 
00242     size_t modification_count(const std::string& type, const std::string& id) const;
00243 
00244     void add_modification(const std::string& type, const config& modification,
00245                       bool no_add=false);
00246 
00247     const t_string& modification_description(const std::string& type) const;
00248 
00249     bool move_interrupted() const { return movement_left() > 0 && interrupted_move_.x >= 0 && interrupted_move_.y >= 0; }
00250     const gamemap::location& get_interrupted_move() const { return interrupted_move_; }
00251     void set_interrupted_move(const gamemap::location& interrupted_move) { interrupted_move_ = interrupted_move; }
00252 
00253     /** States for animation. */
00254     enum STATE { 
00255         STATE_STANDING,   /** anim must fit in a hex */
00256         STATE_FORGET,     /** animation will be automaticaly replaced by a standing anim when finished */
00257         STATE_ANIM};      /** normal anims */
00258     void start_animation(const int start_time , const gamemap::location &loc,const unit_animation* animation, bool with_bars,bool cycles=false,const std::string text = "", const Uint32 text_color =0,STATE state = STATE_ANIM);
00259 
00260     /** The name of the file to game_display (used in menus). */
00261     const std::string& absolute_image() const { return cfg_["image"]; }
00262     const std::string& image_halo() const { return cfg_["halo"]; }
00263 
00264     const std::string& get_hit_sound() const { return cfg_["get_hit_sound"]; }
00265     const std::string& image_ellipse() const { return cfg_["ellipse"]; }
00266 
00267     const std::string& usage() const { return cfg_["usage"]; }
00268     unit_type::ALIGNMENT alignment() const { return alignment_; }
00269     const unit_race* race() const { return race_; }
00270 
00271     const unit_animation* choose_animation(const game_display& disp, const gamemap::location& loc,const std::string& event,const int damage=0,const unit_animation::hit_type hit_type = unit_animation::INVALID,const attack_type* attack=NULL,const attack_type* second_attack = NULL, int swing_num =0) const;
00272 
00273     bool get_ability_bool(const std::string& ability, const gamemap::location& loc) const;
00274     unit_ability_list get_abilities(const std::string& ability, const gamemap::location& loc) const;
00275     std::vector<std::string> ability_tooltips(const gamemap::location& loc) const;
00276     std::vector<std::string> unit_ability_tooltips() const;
00277     bool has_ability_type(const std::string& ability) const;
00278     bool abilities_affects_adjacent() const;
00279 
00280     const game_logic::map_formula_callable_ptr& formula_vars() const { return formula_vars_; }
00281     bool has_formula() const { return !unit_formula_.empty(); }
00282     const std::string& get_formula() const { return unit_formula_; }
00283 
00284     void reset_modifications();
00285     void backup_state();
00286     void apply_modifications();
00287     void remove_temporary_modifications();
00288     void add_trait(std::string /*trait*/);
00289     void generate_traits(bool musthaveonly=false, game_state* state = 0);
00290     void generate_traits_description();
00291     std::string generate_name( simple_rng* rng = 0) const
00292         { return race_->generate_name(string_gender(cfg_["gender"]), rng); }
00293 
00294     // Only see_all=true use caching
00295     bool invisible(const gamemap::location& loc,
00296         const unit_map& units,const std::vector<team>& teams, bool see_all=true) const;
00297 
00298     unit_race::GENDER generate_gender(const unit_type& type, bool gen, game_state* state = 0);
00299     std::string image_mods() const;
00300 
00301 private:
00302 
00303     bool internal_matches_filter(const vconfig& cfg,const gamemap::location& loc,
00304         bool use_flat_tod) const;
00305     /*
00306      * cfg: an ability WML structure
00307      */
00308     bool ability_active(const std::string& ability,const config& cfg,const gamemap::location& loc) const;
00309     bool ability_affects_adjacent(const std::string& ability,const config& cfg,int dir,const gamemap::location& loc) const;
00310     bool ability_affects_self(const std::string& ability,const config& cfg,const gamemap::location& loc) const;
00311     bool resistance_filter_matches(const config& cfg,bool attacker,const std::string& damage_name) const;
00312     bool resistance_filter_matches(const config& cfg,bool attacker,const attack_type& damage_type) const
00313     {return resistance_filter_matches(cfg, attacker, damage_type.type()); };
00314 
00315     int movement_cost_internal(t_translation::t_terrain terrain, int recurse_count=0) const;
00316     bool has_ability_by_id(const std::string& ability) const;
00317     void remove_ability_by_id(const std::string& ability);
00318 
00319     void set_underlying_id();
00320 
00321     config cfg_;
00322     config movement_b_;
00323     config defense_b_;
00324     config resistance_b_;
00325         config abilities_b_;
00326 
00327     std::vector<std::string> advances_to_;
00328     std::string type_;
00329     const unit_race* race_;
00330     std::string id_;
00331     std::string name_;
00332     std::string underlying_id_;
00333     t_string type_name_;
00334     std::string undead_variation_;
00335     std::string variation_;
00336 
00337     int hit_points_;
00338     int max_hit_points_, max_hit_points_b_;
00339     int experience_;
00340     int max_experience_, max_experience_b_;
00341     int level_;
00342     unit_type::ALIGNMENT alignment_;
00343     std::string flag_rgb_;
00344     std::string image_mods_;
00345 
00346     bool unrenamable_;
00347     unsigned int side_;
00348     unit_race::GENDER gender_;
00349 
00350     fixed_t alpha_;
00351 
00352     std::string unit_formula_;
00353     game_logic::map_formula_callable_ptr formula_vars_;
00354 
00355     std::vector<std::string> recruits_;
00356 
00357     int movement_;
00358     int max_movement_, max_movement_b_;
00359     mutable std::map<t_translation::t_terrain, int> movement_costs_; // movement cost cache
00360     mutable std::map<t_translation::t_terrain, int> defense_mods_; // defense modifiers cache
00361     bool hold_position_;
00362     bool end_turn_;
00363     bool resting_;
00364     int attacks_left_;
00365     int max_attacks_;
00366 
00367     std::map<std::string,std::string> states_;
00368     config variables_;
00369     int emit_zoc_;
00370     STATE state_;
00371 
00372     std::vector<std::string> overlays_;
00373 
00374     std::string role_;
00375     std::string ai_special_;
00376     std::vector<attack_type> attacks_, attacks_b_;
00377     gamemap::location::DIRECTION facing_;
00378 
00379     t_string traits_description_;
00380     int unit_value_;
00381     gamemap::location goto_, interrupted_move_;
00382     bool flying_, is_fearless_, is_healthy_;
00383 
00384     string_map modification_descriptions_;
00385     // Animations:
00386     std::vector<unit_animation> animations_;
00387 
00388     unit_animation *anim_;
00389     int next_idling_;
00390     int frame_begin_time_;
00391 
00392 
00393     int unit_halo_;
00394     int unit_anim_halo_;
00395     bool getsHit_;
00396     bool refreshing_; // avoid infinite recursion
00397     bool hidden_;
00398     bool draw_bars_;
00399 
00400     config modifications_;
00401 
00402     friend void attack_type::set_specials_context(const gamemap::location& loc, const gamemap::location&, const unit& un, bool) const;
00403     const unit_map* units_;
00404     const gamemap* map_;
00405     const gamestatus* gamestatus_;
00406     const std::vector<team>* teams_;
00407 
00408     /** Hold the visibility status cache for a unit, mutable since it's a cache. */
00409     mutable std::map<gamemap::location, bool> invisibility_cache_;
00410 
00411     /**
00412      * Clears the cache.
00413      *
00414      * Since we don't change the state of the object we're marked const (also
00415      * required since the objects in the cache need to be marked const).
00416      */
00417     void clear_visibility_cache() const { invisibility_cache_.clear(); }
00418 };
00419 
00420 /** Object which temporarily resets a unit's movement */
00421 struct unit_movement_resetter
00422 {
00423     unit_movement_resetter(unit& u, bool operate=true) : u_(u), moves_(u.movement_)
00424     {
00425         if(operate) {
00426             u.movement_ = u.total_movement();
00427         }
00428     }
00429 
00430     ~unit_movement_resetter()
00431     {
00432         u_.movement_ = moves_;
00433     }
00434 
00435 private:
00436     unit& u_;
00437     int moves_;
00438 };
00439 
00440 void sort_units(std::vector< unit > &);
00441 
00442 /** Returns the number of units of the given side (team). */
00443 int team_units(const unit_map& units, unsigned int team_num);
00444 int team_upkeep(const unit_map& units, unsigned int team_num);
00445 unit_map::const_iterator team_leader(unsigned int side, const unit_map& units);
00446 unit_map::iterator find_visible_unit(unit_map& units,
00447         const gamemap::location loc,
00448         const gamemap& map,
00449         const std::vector<team>& teams, const team& current_team,
00450         bool see_all=false);
00451 unit_map::const_iterator find_visible_unit(const unit_map& units,
00452         const gamemap::location loc,
00453         const gamemap& map,
00454         const std::vector<team>& teams, const team& current_team,
00455         bool see_all=false);
00456 
00457 struct team_data
00458 {
00459     int units, upkeep, villages, expenses, net_income, gold;
00460     std::string teamname;
00461 };
00462 
00463 team_data calculate_team_data(const class team& tm, int side, const unit_map& units);
00464 
00465 /**
00466  * This object is used to temporary place a unit in the unit map, swapping out
00467  * any unit that is already there.  On destruction, it restores the unit map to
00468  * its original.
00469  */
00470 struct temporary_unit_placer
00471 {
00472     temporary_unit_placer(unit_map& m, const gamemap::location& loc, const unit& u);
00473     ~temporary_unit_placer();
00474 
00475 private:
00476     unit_map& m_;
00477     const gamemap::location& loc_;
00478     std::pair<gamemap::location,unit> *temp_;
00479 };
00480 
00481 /**
00482  * Gets a checksum for a unit.
00483  *
00484  * In MP games the descriptions are locally generated and might differ, so it
00485  * should be possible to discard them.  Not sure whether replays suffer the
00486  * same problem.
00487  * 
00488  *  @param u                    the unit
00489  * 
00490  *  @returns                    the checksum for a unit
00491  */ 
00492 std::string get_checksum(const unit& u);
00493 
00494 #endif

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