00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
00055
00056
00057 static void clear_status_caches();
00058
00059 friend struct unit_movement_resetter;
00060
00061 unit(const unit& u);
00062
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
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
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
00080 const std::string& type_id() const { return type_; }
00081 const unit_type* type() const;
00082
00083
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
00088 const t_string& type_name() const {return type_name_;}
00089 const std::string& undead_variation() const {return undead_variation_;}
00090
00091
00092 const std::string& name() const {return (name_);}
00093 void rename(const std::string& name) {if (!unrenamable_) name_= name;}
00094
00095
00096 const std::string& profile() const;
00097
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
00107
00108
00109 bool get_experience(int xp) { experience_ += xp; return advances(); }
00110
00111 SDL_Colour hp_color() const;
00112
00113 SDL_Colour xp_color() const;
00114
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
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) {
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
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
00173
00174
00175
00176
00177 void read(const config& cfg, bool use_traits=true, game_state* state = 0);
00178 void write(config& cfg) const;
00179
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
00190 const surface still_image(bool scaled = false) const;
00191
00192
00193
00194
00195 void redraw_unit(game_display& disp, const gamemap::location& loc, const bool fake = false);
00196
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
00230 string_map get_base_resistances() const;
00231
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
00254 enum STATE {
00255 STATE_STANDING,
00256 STATE_FORGET,
00257 STATE_ANIM};
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
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 );
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
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
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_;
00360 mutable std::map<t_translation::t_terrain, int> defense_mods_;
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
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_;
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
00409 mutable std::map<gamemap::location, bool> invisibility_cache_;
00410
00411
00412
00413
00414
00415
00416
00417 void clear_visibility_cache() const { invisibility_cache_.clear(); }
00418 };
00419
00420
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
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
00467
00468
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
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492 std::string get_checksum(const unit& u);
00493
00494 #endif