-
-
Notifications
You must be signed in to change notification settings - Fork 988
/
unit.hpp
551 lines (447 loc) · 19.7 KB
/
unit.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
/*
Copyright (C) 2003 - 2016 by David White <dave@whitevine.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/** @file */
#ifndef UNIT_H_INCLUDED
#define UNIT_H_INCLUDED
#include <boost/tuple/tuple.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include "unit_types.hpp"
#include "unit_ptr.hpp"
#include "unit_id.hpp"
class display;
class gamemap;
#if defined(_MSC_VER) && _MSC_VER <= 1600
/*
This is needed because msvc up to 2010 fails to correcty forward declare this struct as a return value this case.
And will create corrupt binaries without giving a warning / error.
*/
#include <SDL_video.h>
#else
struct SDL_Color;
#endif
class team;
class unit_animation_component;
class unit_formula_manager;
class vconfig;
/// The things contained within a unit_ability_list.
typedef std::pair<const config *, map_location> unit_ability;
class unit_ability_list
{
public:
unit_ability_list() :
cfgs_()
{
}
// Implemented in unit_abilities.cpp:
std::pair<int,map_location> highest(const std::string& key, int def=0) const;
std::pair<int,map_location> lowest(const std::string& key, int def=0) const;
// The following make this class usable with BOOST_FOREACH:
typedef std::vector<unit_ability>::iterator iterator;
typedef std::vector<unit_ability>::const_iterator const_iterator;
iterator begin() { return cfgs_.begin(); }
const_iterator begin() const { return cfgs_.begin(); }
iterator end() { return cfgs_.end(); }
const_iterator end() const { return cfgs_.end(); }
// Vector access:
bool empty() const { return cfgs_.empty(); }
unit_ability & front() { return cfgs_.front(); }
const unit_ability & front() const { return cfgs_.front(); }
unit_ability & back() { return cfgs_.back(); }
const unit_ability & back() const { return cfgs_.back(); }
iterator erase(const iterator & erase_it) { return cfgs_.erase(erase_it); }
void push_back(const unit_ability & ability) { cfgs_.push_back(ability); }
private:
// Data:
std::vector<unit_ability> cfgs_;
};
class unit
{
public:
/**
* Clear the unit status cache for all units. Currently only the hidden
* status of units is cached this way.
*/
static void clear_status_caches();
/** The path to the leader crown overlay. */
static const std::string& leader_crown();
// Copy constructor
unit(const unit& u);
/** Initializes a unit from a config */
explicit unit(
const config& cfg
, bool use_traits = false
, const vconfig* vcfg = NULL
, n_unit::id_manager* id_manager = NULL);
/**
* Initializes a unit from a unit type
* only real_unit may have random traits, name and gender
* (to prevent OOS caused by RNG calls)
*/
unit(const unit_type& t, int side, bool real_unit,
unit_race::GENDER gender = unit_race::NUM_GENDERS);
virtual ~unit();
void swap (unit &);
unit& operator=(unit);
/** Advances this unit to another type */
void advance_to(const unit_type &t, bool use_traits = false)
{
advance_to(cfg_, t, use_traits);
}
const std::vector<std::string>& advances_to() const { return advances_to_; }
const std::vector<std::string> advances_to_translated() const;
void set_advances_to(const std::vector<std::string>& advances_to);
/**
* The id of the type of the unit.
* If you are dealing with creating units (e.g. recruitment), this is not what
* you want, as a variation can change this; use type().base_id() instead.
*/
const std::string& type_id() const { return type_->id(); }
/** The type of the unit (accounting for gender and variation). */
const unit_type& type() const { return *type_; }
/** id assigned by wml */
void set_id(const std::string& id) { id_ = id; }
const std::string& id() const { if (id_.empty()) return type_name(); else return id_; }
/** The unique internal ID of the unit */
size_t underlying_id() const { return underlying_id_.value; }
/** The unit type name */
const t_string& type_name() const {return type_name_;}
const std::string& undead_variation() const {return undead_variation_;}
const std::string& variation() const {return variation_; }
/** The unit name for display */
const t_string &name() const { return name_; }
void set_name(const t_string &name) { name_ = name; }
void rename(const std::string& name) {if (!unrenamable_) name_= name;}
/** The unit's profile */
std::string small_profile() const;
std::string big_profile() const;
/** Information about the unit -- a detailed description of it */
t_string unit_description() const { return cfg_["description"]; }
int hitpoints() const { return hit_points_; }
int max_hitpoints() const { return max_hit_points_; }
void set_hitpoints(int hp) { hit_points_ = hp; }
int experience() const { return experience_; }
int max_experience() const { return max_experience_; }
void set_experience(int xp) { experience_ = xp; }
void set_recall_cost(int recall_cost) { recall_cost_ = recall_cost; }
int level() const { return level_; }
int recall_cost() const { return recall_cost_; }
void remove_movement_ai();
void remove_attacks_ai();
/** Colors for the unit's *current* hitpoints.
* @returns a color between green and red representing
* how wounded the unit is.
* The maximum_hitpoints are considered as base.
*/
SDL_Color hp_color() const;
/** Colors for the unit's hitpoints.
* @param hitpoints the amount of hitpoints the color represents.
* @returns the color considering the current hitpoints as base.
*/
SDL_Color hp_color(int hitpoints) const;
/** Colors for the unit's XP. */
SDL_Color xp_color() const;
double hp_bar_scaling() const { return hp_bar_scaling_; }
double xp_bar_scaling() const { return xp_bar_scaling_; }
/** Set to true for some scenario-specific units which should not be renamed */
bool unrenamable() const { return unrenamable_; }
void set_unrenamable(bool unrenamable) { unrenamable_ = unrenamable; }
int side() const { return side_; }
const std::string& team_color() const { return flag_rgb_; }
unit_race::GENDER gender() const { return gender_; }
void set_side(unsigned int new_side) { side_ = new_side; }
fixed_t alpha() const { return alpha_; }
bool can_recruit() const { return canrecruit_; }
void set_can_recruit(bool canrecruit) { canrecruit_ = canrecruit; }
const std::vector<std::string>& recruits() const
{ return recruit_list_; }
void set_recruits(const std::vector<std::string>& recruits);
const config& recall_filter() const { return filter_recall_; }
bool poisoned() const { return get_state(STATE_POISONED); }
bool incapacitated() const { return get_state(STATE_PETRIFIED); }
bool slowed() const { return get_state(STATE_SLOWED); }
int total_movement() const { return max_movement_; }
/// Returns how far a unit can move this turn (zero if incapacitated).
int movement_left() const { return (movement_ == 0 || incapacitated()) ? 0 : movement_; }
/// Providing a true parameter to movement_left() causes it to ignore incapacitation.
int movement_left(bool base_value) const { return base_value ? movement_ : movement_left(); }
int vision() const { return vision_ < 0 ? max_movement_ : vision_; }
int jamming() const { return jamming_; }
void toggle_hold_position() { hold_position_ = !hold_position_; if ( hold_position_ ) end_turn_ = true; }
bool hold_position() const { return hold_position_; }
void set_user_end_turn(bool value=true) { end_turn_ = value; }
void toggle_user_end_turn() { end_turn_ = !end_turn_; if ( !end_turn_ ) hold_position_ = false; }
bool user_end_turn() const { return end_turn_; }
int attacks_left() const { return (attacks_left_ == 0 || incapacitated()) ? 0 : attacks_left_; }
int max_attacks() const { return max_attacks_; }
void set_movement(int moves, bool unit_action=false);
void set_attacks(int left) { attacks_left_ = std::max<int>(0, left); }
void new_turn();
void end_turn();
void new_scenario();
/** Called on every draw */
bool take_hit(int damage) { hit_points_ -= damage; return hit_points_ <= 0; }
void heal(int amount);
void heal_all() { hit_points_ = max_hitpoints(); }
bool resting() const { return resting_; }
void set_resting(bool rest) { resting_ = rest; }
const std::map<std::string,std::string> get_states() const;
bool get_state(const std::string& state) const;
void set_state(const std::string &state, bool value);
enum state_t { STATE_SLOWED = 0, STATE_POISONED, STATE_PETRIFIED,
STATE_UNCOVERED, STATE_NOT_MOVED, STATE_UNHEALABLE, STATE_GUARDIAN, STATE_UNKNOWN = -1 };
void set_state(state_t state, bool value);
bool get_state(state_t state) const;
static state_t get_known_boolean_state_id(const std::string &state);
static std::map<std::string, state_t> get_known_boolean_state_names();
bool has_moved() const { return movement_left() != total_movement(); }
bool has_goto() const { return get_goto().valid(); }
bool emits_zoc() const { return emit_zoc_ && !incapacitated();}
bool matches_id(const std::string& unit_id) const;
/* cfg: standard unit filter */
const std::vector<std::string>& overlays() const { return overlays_; }
void write(config& cfg) const;
void set_role(const std::string& role) { role_ = role; }
const std::string &get_role() const { return role_; }
void set_emit_zoc(bool val) { emit_zoc_ = val; }
bool get_emit_zoc() const { return emit_zoc_; }
const std::vector<attack_type>& attacks() const { return attacks_; }
std::vector<attack_type>& attacks() { return attacks_; }
int damage_from(const attack_type& attack,bool attacker,const map_location& loc) const { return resistance_against(attack,attacker,loc); }
unit_animation_component & anim_comp() const { return *anim_comp_; }
void set_facing(map_location::DIRECTION dir) const;
map_location::DIRECTION facing() const { return facing_; }
const std::vector<t_string>& trait_names() const { return trait_names_; }
const std::vector<t_string>& trait_descriptions() const { return trait_descriptions_; }
std::vector<std::string> get_traits_list() const;
int cost () const { return unit_value_; }
const map_location &get_location() const { return loc_; }
/** To be called by unit_map or for temporary units only. */
void set_location(const map_location &loc) { loc_ = loc; }
const map_location& get_goto() const { return goto_; }
void set_goto(const map_location& new_goto) { goto_ = new_goto; }
int upkeep() const;
const config::attribute_value& upkeep_raw() const { return cfg_["upkeep"]; }
bool loyal() const;
void set_hidden(bool state) const;
bool get_hidden() const { return hidden_; }
bool is_flying() const { return movement_type_.is_flying(); }
bool is_fearless() const { return is_fearless_; }
bool is_healthy() const { return is_healthy_; }
int movement_cost(const t_translation::t_terrain & terrain) const
{ return movement_type_.movement_cost(terrain, get_state(STATE_SLOWED)); }
int vision_cost(const t_translation::t_terrain & terrain) const
{ return movement_type_.vision_cost(terrain, get_state(STATE_SLOWED)); }
int jamming_cost(const t_translation::t_terrain & terrain) const
{ return movement_type_.jamming_cost(terrain, get_state(STATE_SLOWED)); }
int defense_modifier(const t_translation::t_terrain & terrain) const;
int resistance_against(const std::string& damage_name,bool attacker,const map_location& loc) const;
int resistance_against(const attack_type& damage_type,bool attacker,const map_location& loc) const
{ return resistance_against(damage_type.type(), attacker, loc); }
//return resistances without any abilities applied
utils::string_map get_base_resistances() const { return movement_type_.damage_table(); }
const movetype & movement_type() const { return movement_type_; }
bool can_advance() const { return advances_to_.empty()==false || get_modification_advances().empty() == false; }
bool advances() const { return experience_ >= max_experience() && can_advance(); }
std::map<std::string,std::string> advancement_icons() const;
std::vector<std::pair<std::string,std::string> > amla_icons() const;
std::vector<config> get_modification_advances() const;
typedef boost::ptr_vector<config> t_advancements;
void set_advancements(std::vector<config> advancements);
const t_advancements& modification_advancements() const
{ return advancements_; }
size_t modification_count(const std::string& type, const std::string& id) const;
void add_modification(const std::string& type, const config& modification,
bool no_add=false);
void expire_modifications(const std::string & duration);
bool move_interrupted() const { return movement_left() > 0 && interrupted_move_.x >= 0 && interrupted_move_.y >= 0; }
const map_location& get_interrupted_move() const { return interrupted_move_; }
void set_interrupted_move(const map_location& interrupted_move) { interrupted_move_ = interrupted_move; }
/** The name of the file to game_display (used in menus). */
std::string absolute_image() const;
/** The default image to use for animation frames with no defined image. */
std::string default_anim_image() const;
std::string image_halo() const { return cfg_["halo"]; }
std::string image_ellipse() const { return cfg_["ellipse"]; }
config &variables() { return variables_; }
const config &variables() const { return variables_; }
std::string usage() const { return cfg_["usage"]; }
unit_type::ALIGNMENT alignment() const { return alignment_; }
/// Never returns NULL, but may point to the null race.
const unit_race* race() const { return race_; }
/**
* Returns true if the unit is currently under effect by an ability with this given TAG NAME.
* This means that the ability could be owned by the unit itself, or by an adjacent unit.
*/
bool get_ability_bool(const std::string& tag_name, const map_location& loc) const;
/**
* Returns true if the unit is currently under effect by an ability with this given TAG NAME.
* This means that the ability could be owned by the unit itself, or by an adjacent unit.
*/
bool get_ability_bool(const std::string &tag_name) const
{ return get_ability_bool(tag_name, loc_); }
unit_ability_list get_abilities(const std::string &tag_name, const map_location& loc) const;
unit_ability_list get_abilities(const std::string &tag_name) const
{ return get_abilities(tag_name, loc_); }
/** Tuple of: neutral ability name, gendered ability name, description */
std::vector<boost::tuple<t_string,t_string,t_string> > ability_tooltips(std::vector<bool> *active_list=NULL) const;
std::vector<std::string> get_ability_list() const;
bool has_ability_type(const std::string& ability) const;
unit_formula_manager & formula_manager() const { return *formula_man_; }
void backup_state();
void apply_modifications();
void generate_traits(bool musthaveonly=false);
void generate_name();
// Only see_all=true use caching
bool invisible(const map_location& loc, bool see_all=true) const;
bool is_visible_to_team(team const& team, gamemap const & map , bool const see_all = true) const;
/** Mark this unit as clone so it can be inserted to unit_map
* @returns self (for convenience)
**/
unit& clone(bool is_temporary=true);
std::string TC_image_mods() const;
const std::string& effect_image_mods() const;
std::string image_mods() const;
long ref_count() const { return ref_count_; }
friend void intrusive_ptr_add_ref(const unit *);
friend void intrusive_ptr_release(const unit *);
protected:
mutable long ref_count_; //used by intrusive_ptr
private:
void advance_to(const config &old_cfg, const unit_type &t,
bool use_traits);
/*
* cfg: an ability WML structure
*/
bool ability_active(const std::string& ability,const config& cfg,const map_location& loc) const;
bool ability_affects_adjacent(const std::string& ability,const config& cfg,int dir,const map_location& loc,const unit& from) const;
bool ability_affects_self(const std::string& ability,const config& cfg,const map_location& loc) const;
bool resistance_filter_matches(const config& cfg,bool attacker,const std::string& damage_name, int res) const;
public:
bool has_ability_by_id(const std::string& ability) const;
// ^ Needed for unit_filter
private:
void remove_ability_by_id(const std::string& ability);
/** register a trait's name and its description for UI's use*/
void add_trait_description(const config& trait, const t_string& description);
void set_underlying_id(n_unit::id_manager& id_manager);
config cfg_;
private:
map_location loc_;
std::vector<std::string> advances_to_;
const unit_type * type_;/// Never NULL. Adjusted for gender and variation.
t_string type_name_; /// The displayed name of the unit type.
const unit_race* race_; /// Never NULL, but may point to the null race.
std::string id_;
t_string name_;
n_unit::unit_id underlying_id_;
std::string undead_variation_;
std::string variation_;
int hit_points_;
int max_hit_points_;
int experience_;
int max_experience_;
int level_;
int recall_cost_;
bool canrecruit_;
std::vector<std::string> recruit_list_;
unit_type::ALIGNMENT alignment_;
std::string flag_rgb_;
std::string image_mods_;
bool unrenamable_;
int side_;
unit_race::GENDER gender_;
fixed_t alpha_;
boost::scoped_ptr<unit_formula_manager> formula_man_;
int movement_;
int max_movement_;
int vision_;
int jamming_;
movetype movement_type_;
bool hold_position_;
bool end_turn_;
bool resting_;
int attacks_left_;
int max_attacks_;
std::set<std::string> states_;
std::vector<bool> known_boolean_states_;
static std::map<std::string, state_t> known_boolean_state_names_;
config variables_;
config events_;
config filter_recall_;
bool emit_zoc_;
std::vector<std::string> overlays_;
std::string role_;
std::vector<attack_type> attacks_;
protected:
mutable map_location::DIRECTION facing_; //TODO: I think we actually consider this to be part of the gamestate, so it might be better if it's not mutable
//But it's not easy to separate this guy from the animation code right now.
private:
std::vector<t_string> trait_names_;
std::vector<t_string> trait_descriptions_;
int unit_value_;
map_location goto_, interrupted_move_;
bool is_fearless_, is_healthy_;
utils::string_map modification_descriptions_;
// Animations:
friend class unit_animation_component;
private:
boost::scoped_ptr<unit_animation_component> anim_comp_;
bool getsHit_;
mutable bool hidden_;
double hp_bar_scaling_, xp_bar_scaling_;
config modifications_;
config abilities_;
t_advancements advancements_;
/**
* Hold the visibility status cache for a unit, when not uncovered.
* This is mutable since it is a cache.
*/
mutable std::map<map_location, bool> invisibility_cache_;
/**
* Clears the cache.
*
* Since we don't change the state of the object we're marked const (also
* required since the objects in the cache need to be marked const).
*/
void clear_visibility_cache() const { invisibility_cache_.clear(); }
};
/**
* Object which temporarily resets a unit's movement.
*
* @warning
* The unit whose movement is reset may not be deleted while a
* @ref unit_movement_resetter object 'holds'. So best use it only in a small
* scope.
*/
struct unit_movement_resetter
: private boost::noncopyable
{
unit_movement_resetter(unit& u, bool operate=true);
~unit_movement_resetter();
private:
unit& u_;
int moves_;
};
/**
* Gets a checksum for a unit.
*
* In MP games the descriptions are locally generated and might differ, so it
* should be possible to discard them. Not sure whether replays suffer the
* same problem.
*
* @param u the unit
*
* @returns the checksum for a unit
*/
std::string get_checksum(const unit& u);
#endif