Merging branch 'xan'.
Everything should work the same; report all deviations to me.
This commit is contained in:
commit
b3dc620783
44 changed files with 5254 additions and 3100 deletions
|
@ -1,87 +1,498 @@
|
|||
|
||||
#define ABILITY_HEALS
|
||||
[heals]
|
||||
description=heals4
|
||||
amount=4
|
||||
value=4
|
||||
cumulative=no
|
||||
affect_allies=yes
|
||||
name= _ "heals +4"
|
||||
description= _ "Heals +4:
|
||||
Allows the unit to heal adjacent friendly units at the beginning of each turn.
|
||||
|
||||
A unit cared for by this healer may heal up to 4 HP per turn, or stop poison from taking effect for that turn.
|
||||
A poisoned unit cannot be cured of its poison by a healer, and must seek the care of a village or a unit that can cure."
|
||||
affect_self=no
|
||||
poison=slowed
|
||||
[affect_adjacent]
|
||||
adjacent=n,ne,se,s,sw,nw
|
||||
[/affect_adjacent]
|
||||
[/heals]
|
||||
#enddef
|
||||
|
||||
# For backward compat reasons, this heals & cures.
|
||||
#define ABILITY_CURES
|
||||
[heals]
|
||||
description=heals8
|
||||
amount=8
|
||||
value=8
|
||||
cumulative=no
|
||||
affect_allies=yes
|
||||
name= _ "heals +8"
|
||||
description= _ "Heals +8:
|
||||
This unit combines herbal remedies with magic to heal units more quickly than is normally possible on the battlefield.
|
||||
|
||||
A unit cared for by this healer may heal up to 8 HP per turn, or stop poison from taking effect for that turn.
|
||||
A poisoned unit cannot be cured of its poison by a healer, and must seek the care of a village or a unit that can cure."
|
||||
affect_self=no
|
||||
poison=slowed
|
||||
[affect_adjacent]
|
||||
adjacent=n,ne,se,s,sw,nw
|
||||
[/affect_adjacent]
|
||||
[/heals]
|
||||
[heals]
|
||||
affect_allies=yes
|
||||
name= _ "cures"
|
||||
description= _ "Cures:
|
||||
A curer can cure a unit of poison, although that unit will receive no additional healing on the turn it is cured of the poison."
|
||||
affect_self=no
|
||||
poison=cured
|
||||
[affect_adjacent]
|
||||
adjacent=n,ne,se,s,sw,nw
|
||||
[/affect_adjacent]
|
||||
[/heals]
|
||||
[cures]
|
||||
[/cures]
|
||||
#enddef
|
||||
|
||||
#define ABILITY_REGENERATES
|
||||
[regenerates]
|
||||
description=regenerates
|
||||
amount=8
|
||||
[/regenerates]
|
||||
[regenerate]
|
||||
value=8
|
||||
cumulative=no
|
||||
name= _ "regenerates"
|
||||
description= _ "Regenerates:
|
||||
The unit will heal itself 8 hp per turn. If it is poisoned, it will remove the poison instead of healing."
|
||||
affect_self=yes
|
||||
poison=cured
|
||||
[/regenerate]
|
||||
#enddef
|
||||
|
||||
#define ABILITY_STEADFAST
|
||||
[steadfast]
|
||||
description=steadfast
|
||||
bonus=100%
|
||||
max=50
|
||||
[/steadfast]
|
||||
[resistance]
|
||||
multiply=2
|
||||
max_value=50
|
||||
apply_to=blade,pierce,impact,fire,cold,holy
|
||||
[filter_apply]
|
||||
filter=value
|
||||
greater_than=0
|
||||
[/filter_apply]
|
||||
name= _ "steadfast"
|
||||
description= _ "Steadfast:
|
||||
This unit's resistances are doubled, up to a maximum of 50%, when defending. Vulnerabilities are not affected."
|
||||
affect_self=yes
|
||||
active_on=defense
|
||||
[/resistance]
|
||||
#enddef
|
||||
|
||||
#define ABILITY_LEADERSHIP
|
||||
#define ABILITY_LEADERSHIP_LEVEL_1
|
||||
[leadership]
|
||||
description=leadership
|
||||
perlevel_bonus=25
|
||||
value=25
|
||||
cumulative=no
|
||||
affect_allies=yes
|
||||
name= _ "leadership"
|
||||
description= _ "Leadership:
|
||||
This unit can lead friendly units that are next to it, making them fight better.
|
||||
|
||||
Adjacent friendly units of lower level will do more damage in battle. When a unit adjacent to, of a lower level than, and on the same side as a unit with Leadership engages in combat, its attacks do 25% more damage times the difference in their levels."
|
||||
affect_self=no
|
||||
[affect_adjacent]
|
||||
adjacent=n,ne,se,s,sw,nw
|
||||
[filter]
|
||||
level=0
|
||||
[/filter]
|
||||
[/affect_adjacent]
|
||||
[/leadership]
|
||||
#enddef
|
||||
#define ABILITY_LEADERSHIP_LEVEL_2
|
||||
[leadership]
|
||||
value=50
|
||||
cumulative=no
|
||||
affect_allies=yes
|
||||
name= _ "leadership"
|
||||
description= _ "Leadership:
|
||||
This unit can lead friendly units that are next to it, making them fight better.
|
||||
|
||||
Adjacent friendly units of lower level will do more damage in battle. When a unit adjacent to, of a lower level than, and on the same side as a unit with Leadership engages in combat, its attacks do 25% more damage times the difference in their levels."
|
||||
affect_self=no
|
||||
[affect_adjacent]
|
||||
adjacent=n,ne,se,s,sw,nw
|
||||
[filter]
|
||||
level=0
|
||||
[/filter]
|
||||
[/affect_adjacent]
|
||||
[/leadership]
|
||||
[leadership]
|
||||
value=25
|
||||
cumulative=no
|
||||
affect_allies=yes
|
||||
affect_self=no
|
||||
[affect_adjacent]
|
||||
adjacent=n,ne,se,s,sw,nw
|
||||
[filter]
|
||||
level=1
|
||||
[/filter]
|
||||
[/affect_adjacent]
|
||||
[/leadership]
|
||||
#enddef
|
||||
#define ABILITY_LEADERSHIP_LEVEL_3
|
||||
[leadership]
|
||||
value=75
|
||||
cumulative=no
|
||||
affect_allies=yes
|
||||
name= _ "leadership"
|
||||
description= _ "Leadership:
|
||||
This unit can lead friendly units that are next to it, making them fight better.
|
||||
|
||||
Adjacent friendly units of lower level will do more damage in battle. When a unit adjacent to, of a lower level than, and on the same side as a unit with Leadership engages in combat, its attacks do 25% more damage times the difference in their levels."
|
||||
affect_self=no
|
||||
[affect_adjacent]
|
||||
adjacent=n,ne,se,s,sw,nw
|
||||
[filter]
|
||||
level=0
|
||||
[/filter]
|
||||
[/affect_adjacent]
|
||||
[/leadership]
|
||||
[leadership]
|
||||
value=50
|
||||
cumulative=no
|
||||
affect_allies=yes
|
||||
affect_self=no
|
||||
[affect_adjacent]
|
||||
adjacent=n,ne,se,s,sw,nw
|
||||
[filter]
|
||||
level=1
|
||||
[/filter]
|
||||
[/affect_adjacent]
|
||||
[/leadership]
|
||||
[leadership]
|
||||
value=25
|
||||
cumulative=no
|
||||
affect_allies=yes
|
||||
affect_self=no
|
||||
[affect_adjacent]
|
||||
adjacent=n,ne,se,s,sw,nw
|
||||
[filter]
|
||||
level=2
|
||||
[/filter]
|
||||
[/affect_adjacent]
|
||||
[/leadership]
|
||||
#enddef
|
||||
#define ABILITY_LEADERSHIP_LEVEL_4
|
||||
[leadership]
|
||||
value=100
|
||||
cumulative=no
|
||||
affect_allies=yes
|
||||
name= _ "leadership"
|
||||
description= _ "Leadership:
|
||||
This unit can lead friendly units that are next to it, making them fight better.
|
||||
|
||||
Adjacent friendly units of lower level will do more damage in battle. When a unit adjacent to, of a lower level than, and on the same side as a unit with Leadership engages in combat, its attacks do 25% more damage times the difference in their levels."
|
||||
affect_self=no
|
||||
[affect_adjacent]
|
||||
adjacent=n,ne,se,s,sw,nw
|
||||
[filter]
|
||||
level=0
|
||||
[/filter]
|
||||
[/affect_adjacent]
|
||||
[/leadership]
|
||||
[leadership]
|
||||
value=75
|
||||
cumulative=no
|
||||
affect_allies=yes
|
||||
affect_self=no
|
||||
[affect_adjacent]
|
||||
adjacent=n,ne,se,s,sw,nw
|
||||
[filter]
|
||||
level=1
|
||||
[/filter]
|
||||
[/affect_adjacent]
|
||||
[/leadership]
|
||||
[leadership]
|
||||
value=50
|
||||
cumulative=no
|
||||
affect_allies=yes
|
||||
affect_self=no
|
||||
[affect_adjacent]
|
||||
adjacent=n,ne,se,s,sw,nw
|
||||
[filter]
|
||||
level=2
|
||||
[/filter]
|
||||
[/affect_adjacent]
|
||||
[/leadership]
|
||||
[leadership]
|
||||
value=25
|
||||
cumulative=no
|
||||
affect_allies=yes
|
||||
affect_self=no
|
||||
[affect_adjacent]
|
||||
adjacent=n,ne,se,s,sw,nw
|
||||
[filter]
|
||||
level=3
|
||||
[/filter]
|
||||
[/affect_adjacent]
|
||||
[/leadership]
|
||||
#enddef
|
||||
#define ABILITY_LEADERSHIP_LEVEL_5
|
||||
[leadership]
|
||||
value=125
|
||||
cumulative=no
|
||||
affect_allies=yes
|
||||
name= _ "leadership"
|
||||
description= _ "Leadership:
|
||||
This unit can lead friendly units that are next to it, making them fight better.
|
||||
|
||||
Adjacent friendly units of lower level will do more damage in battle. When a unit adjacent to, of a lower level than, and on the same side as a unit with Leadership engages in combat, its attacks do 25% more damage times the difference in their levels."
|
||||
affect_self=no
|
||||
[affect_adjacent]
|
||||
adjacent=n,ne,se,s,sw,nw
|
||||
[filter]
|
||||
level=0
|
||||
[/filter]
|
||||
[/affect_adjacent]
|
||||
[/leadership]
|
||||
[leadership]
|
||||
value=100
|
||||
cumulative=no
|
||||
affect_allies=yes
|
||||
affect_self=no
|
||||
[affect_adjacent]
|
||||
adjacent=n,ne,se,s,sw,nw
|
||||
[filter]
|
||||
level=1
|
||||
[/filter]
|
||||
[/affect_adjacent]
|
||||
[/leadership]
|
||||
[leadership]
|
||||
value=75
|
||||
cumulative=no
|
||||
affect_allies=yes
|
||||
affect_self=no
|
||||
[affect_adjacent]
|
||||
adjacent=n,ne,se,s,sw,nw
|
||||
[filter]
|
||||
level=2
|
||||
[/filter]
|
||||
[/affect_adjacent]
|
||||
[/leadership]
|
||||
[leadership]
|
||||
value=50
|
||||
cumulative=no
|
||||
affect_allies=yes
|
||||
affect_self=no
|
||||
[affect_adjacent]
|
||||
adjacent=n,ne,se,s,sw,nw
|
||||
[filter]
|
||||
level=3
|
||||
[/filter]
|
||||
[/affect_adjacent]
|
||||
[/leadership]
|
||||
[leadership]
|
||||
value=25
|
||||
cumulative=no
|
||||
affect_allies=yes
|
||||
affect_self=no
|
||||
[affect_adjacent]
|
||||
adjacent=n,ne,se,s,sw,nw
|
||||
[filter]
|
||||
level=4
|
||||
[/filter]
|
||||
[/affect_adjacent]
|
||||
[/leadership]
|
||||
#enddef
|
||||
|
||||
#define ABILITY_SKIRMISHER
|
||||
[skirmisher]
|
||||
description=skirmisher
|
||||
name= _ "skirmisher"
|
||||
description= _ "Skirmisher:
|
||||
This unit is skilled in moving past enemies quickly, and ignores all enemy Zones of Control. (Exception: if you stop in an enemy zone of control, your remaining movement will be set to 0 even if you are a skirmisher.)"
|
||||
affect_self=yes
|
||||
[/skirmisher]
|
||||
#enddef
|
||||
|
||||
#define ABILITY_ILLUMINATES
|
||||
[illuminates]
|
||||
description=illuminates
|
||||
level=1
|
||||
value=1
|
||||
cumulative=no
|
||||
name= _ "illuminates"
|
||||
description= _ "Illuminates:
|
||||
This unit illuminates the surrounding area, making lawful units fight better, and chaotic units fight worse.
|
||||
|
||||
Any units adjacent to this unit will fight as if it were dusk when it is night, and as if it were day when it is dusk."
|
||||
affect_self=yes
|
||||
[/illuminates]
|
||||
#enddef
|
||||
|
||||
#define ABILITY_TELEPORT
|
||||
[teleport]
|
||||
description=teleport
|
||||
name= _ "teleport"
|
||||
description= _ "Teleport:
|
||||
This unit may teleport between any two friendly villages using one of its moves."
|
||||
[/teleport]
|
||||
#enddef
|
||||
|
||||
#define ABILITY_AMBUSH
|
||||
[hides]
|
||||
description=ambush
|
||||
name= _ "ambush"
|
||||
description= _ "Ambush:
|
||||
This unit can hide in forest, and remain undetected by its enemies.
|
||||
|
||||
Enemy units cannot see or attack this unit when it is in forest, except for any turn immediately after this unit has attacked, or if there are enemy units next to this unit."
|
||||
affect_self=yes
|
||||
[filter]
|
||||
terrains=f
|
||||
[filter_location]
|
||||
terrain=f,T,F
|
||||
[/filter_location]
|
||||
[/filter]
|
||||
[/hides]
|
||||
#enddef
|
||||
|
||||
#define ABILITY_NIGHTSTALK
|
||||
[hides]
|
||||
description=nightstalk
|
||||
name= _ "nightstalk"
|
||||
description= _ "Nightstalk:
|
||||
The unit becomes invisible during night.
|
||||
|
||||
Enemy units cannot see or attack this unit at night, except for any turn immediately after this unit has attacked, or if there are enemy units next to this unit."
|
||||
affect_self=yes
|
||||
[filter]
|
||||
tod=chaotic
|
||||
[filter_location]
|
||||
time_of_day=chaotic
|
||||
[/filter_location]
|
||||
[/filter]
|
||||
[/hides]
|
||||
#enddef
|
||||
|
||||
#define ABILITY_SUBMERGE
|
||||
[hides]
|
||||
description=submerge
|
||||
name= _ "submerge"
|
||||
description= _ "Submerge:
|
||||
This unit can hide in deep water, and remain undetected by its enemies.
|
||||
|
||||
Enemy units cannot see or attack this unit when it is in deep water, except for any turn immediately after this unit has attacked, or if there are enemy units next to this unit."
|
||||
affect_self=yes
|
||||
[filter]
|
||||
terrains=s
|
||||
[filter_location]
|
||||
terrain=s
|
||||
[/filter_location]
|
||||
[/filter]
|
||||
[/hides]
|
||||
#enddef
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define WEAPON_SPECIAL_BERSERK
|
||||
[berserk]
|
||||
name= _ "berserk"
|
||||
description= _ "Berserk:
|
||||
Whether used offensively or defensively, this attack presses the engagement until one of the combatants is slain, or 30 rounds of attacks have occurred."
|
||||
cumulative=no
|
||||
rounds=30
|
||||
[/berserk]
|
||||
#enddef
|
||||
|
||||
#define WEAPON_SPECIAL_BACKSTAB
|
||||
[damage]
|
||||
name= _ "backstab"
|
||||
description= _ "Backstab:
|
||||
This attack deals double damage if there is an enemy of the target on the opposite side of the target, and that unit is not incapacitated (e.g. turned to stone)."
|
||||
cumulative=no
|
||||
multiply=2
|
||||
backstab=yes
|
||||
active_on=offense
|
||||
[/damage]
|
||||
#enddef
|
||||
|
||||
#define WEAPON_SPECIAL_PLAGUE_TYPE TYPE
|
||||
[plague]
|
||||
name= _ "plague"
|
||||
description= _ "Plague:
|
||||
When a unit is killed by a Plague attack, that unit is replaced with a unit identical to and on the same side as the unit with the Plague attack. (This doesn't work on Undead or units in villages.)"
|
||||
type={TYPE}
|
||||
[/plague]
|
||||
#enddef
|
||||
#define WEAPON_SPECIAL_PLAGUE
|
||||
[plague]
|
||||
name= _ "plague"
|
||||
description= _ "Plague:
|
||||
When a unit is killed by a Plague attack, that unit is replaced with a unit identical to and on the same side as the unit with the Plague attack. (This doesn't work on Undead or units in villages.)"
|
||||
[/plague]
|
||||
#enddef
|
||||
|
||||
#define WEAPON_SPECIAL_SLOW
|
||||
[slow]
|
||||
name= _ "slows"
|
||||
description= _ "Slow:
|
||||
This attack slows the target. Slow halves the damage caused by attacks and slowed units move at half the normal speed (rounded up)."
|
||||
cumulative=no
|
||||
[/slow]
|
||||
#enddef
|
||||
|
||||
#define WEAPON_SPECIAL_STONE
|
||||
[stones]
|
||||
name= _ "stones"
|
||||
description= _ "Stone:
|
||||
This attack turns the target to stone. Units that have been turned to stone may not move or attack."
|
||||
[/stones]
|
||||
#enddef
|
||||
|
||||
#define WEAPON_SPECIAL_MARKSMAN
|
||||
[chance_to_hit]
|
||||
name= _ "marksman"
|
||||
description= _ "Marksman:
|
||||
When used offensively, this attack always has at least a 60% chance to hit."
|
||||
value=60
|
||||
cumulative=yes
|
||||
active_on=offense
|
||||
[/chance_to_hit]
|
||||
#enddef
|
||||
|
||||
#define WEAPON_SPECIAL_MAGICAL
|
||||
[chance_to_hit]
|
||||
name= _ "magical"
|
||||
description= _ "Magical:
|
||||
This attack always has a 70% chance to hit."
|
||||
value=70
|
||||
cumulative=no
|
||||
[/chance_to_hit]
|
||||
#enddef
|
||||
|
||||
#define WEAPON_SPECIAL_SWARM
|
||||
[attacks]
|
||||
name= _ "swarm"
|
||||
description= _ "Swarm:
|
||||
The number of strikes of this attack decreases when the unit is wounded. The number of strikes is proportional to the % of HP/maximum HP the unit has. For example a unit with 3/4 of its maximum HP will get 3/4 of the number of strikes."
|
||||
[/attacks]
|
||||
#enddef
|
||||
|
||||
#define WEAPON_SPECIAL_CHARGE
|
||||
[damage]
|
||||
name= _ "charge"
|
||||
description= _ "Charge:
|
||||
This attack deals double damage to the target. It also causes this unit to take double damage from the target's counterattack."
|
||||
multiply=2
|
||||
cumulative=no
|
||||
apply_to=self,opponent
|
||||
active_on=offense
|
||||
[/damage]
|
||||
#enddef
|
||||
|
||||
#define WEAPON_SPECIAL_DRAIN
|
||||
[drains]
|
||||
name= _ "drains"
|
||||
description= _ "Drain:
|
||||
This unit drains health from living units, healing itself for half the amount of damage it deals (rounded down)."
|
||||
[/drains]
|
||||
#enddef
|
||||
|
||||
#define WEAPON_SPECIAL_FIRSTSTRIKE
|
||||
[firststrike]
|
||||
name= _ "firststrike"
|
||||
description= _ "First Strike:
|
||||
This unit always strikes first with this attack, even if they are defending."
|
||||
[/firststrike]
|
||||
#enddef
|
||||
|
||||
#define WEAPON_SPECIAL_POISON
|
||||
[poison]
|
||||
name= _ "poison"
|
||||
description= _ "Poison:
|
||||
This attack poisons the target. Poisoned units lose 8 HP every turn until they are cured or are reduced to 1 HP."
|
||||
[/poison]
|
||||
#enddef
|
||||
|
||||
|
||||
|
|
882
src/actions.cpp
882
src/actions.cpp
File diff suppressed because it is too large
Load diff
|
@ -24,6 +24,7 @@ class replay;
|
|||
#include "unit.hpp"
|
||||
|
||||
#include <deque>
|
||||
typedef std::map<gamemap::location,unit> units_map;
|
||||
|
||||
//this file defines various functions which implement different in-game
|
||||
//events and commands.
|
||||
|
@ -41,7 +42,7 @@ bool can_recruit_on(const gamemap& map, const gamemap::location& leader, const g
|
|||
//If the unit cannot be recruited, then a human-readable message
|
||||
//describing why not 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,
|
||||
unit u, gamemap::location& recruit_location,
|
||||
display *disp=NULL, bool need_castle=true, bool full_movement=false);
|
||||
|
||||
//a structure which defines all the statistics for a potential
|
||||
|
@ -57,8 +58,10 @@ struct battle_stats
|
|||
bool attacker_plague, defender_plague;
|
||||
std::string attacker_plague_type, defender_plague_type;
|
||||
bool attacker_slows, defender_slows;
|
||||
bool to_the_death, defender_strikes_first;
|
||||
std::string attacker_special, defender_special;
|
||||
int rounds;
|
||||
bool defender_strikes_first;
|
||||
bool attacker_poisons, defender_poisons;
|
||||
bool attacker_stones, defender_stones;
|
||||
};
|
||||
|
||||
struct battle_stats_strings
|
||||
|
@ -89,8 +92,9 @@ battle_stats evaluate_battle_stats(const gamemap& map,
|
|||
const gamemap::location& attacker,
|
||||
const gamemap::location& defender,
|
||||
int attack_with,
|
||||
std::map<gamemap::location,unit>& units,
|
||||
units_map& units,
|
||||
const gamestatus& state,
|
||||
const game_data& gamedata,
|
||||
gamemap::TERRAIN attacker_terrain_override = 0,
|
||||
battle_stats_strings *strings = NULL);
|
||||
|
||||
|
@ -100,7 +104,7 @@ void attack(display& gui, const gamemap& map,
|
|||
gamemap::location attacker,
|
||||
gamemap::location defender,
|
||||
int attack_with,
|
||||
std::map<gamemap::location,unit>& units,
|
||||
units_map& units,
|
||||
const gamestatus& state,
|
||||
const game_data& info,
|
||||
bool update_display = true);
|
||||
|
@ -126,7 +130,7 @@ unit_map::const_iterator find_leader(const unit_map& units, int side);
|
|||
//calculates healing for all units for the given side. Should be called
|
||||
//at the beginning of a side's turn.
|
||||
void calculate_healing(display& disp, const gamestatus& status, const gamemap& map,
|
||||
std::map<gamemap::location,unit>& units, unsigned int side,
|
||||
units_map& units, unsigned int side,
|
||||
const std::vector<team>& teams, bool update_display);
|
||||
|
||||
// Resets resting for all units on this side: should be called after calculate_healing().
|
||||
|
@ -137,7 +141,7 @@ void reset_resting(std::map<gamemap::location,unit>& units, unsigned int side);
|
|||
//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,
|
||||
std::map<gamemap::location,unit>& units,
|
||||
units_map& units,
|
||||
const gamemap::location& loc, const std::string& advance_to);
|
||||
|
||||
//function which will advance the unit at loc to 'advance_to'.
|
||||
|
@ -145,7 +149,7 @@ unit get_advanced_unit(const game_data& info,
|
|||
//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,
|
||||
std::map<gamemap::location,unit>& units,
|
||||
units_map& units,
|
||||
gamemap::location loc, const std::string& advance_to);
|
||||
|
||||
//function which tests if the unit at loc is currently affected
|
||||
|
@ -153,26 +157,26 @@ void advance_unit(const game_data& info,
|
|||
//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 std::map<gamemap::location,unit>& units,
|
||||
gamemap::location under_leadership(const units_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
|
||||
void check_victory(std::map<gamemap::location,unit>& units,
|
||||
void check_victory(units_map& units,
|
||||
std::vector<team>& teams);
|
||||
|
||||
//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.
|
||||
const time_of_day& timeofday_at(const gamestatus& status,
|
||||
const std::map<gamemap::location,unit>& units,
|
||||
const units_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.
|
||||
int combat_modifier(const gamestatus& status,
|
||||
const std::map<gamemap::location,unit>& units,
|
||||
const units_map& units,
|
||||
const gamemap::location& loc,
|
||||
unit_type::ALIGNMENT alignment,
|
||||
const gamemap& map);
|
||||
|
@ -242,6 +246,6 @@ namespace victory_conditions {
|
|||
//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,
|
||||
std::map<gamemap::location,unit>& units, std::vector<team>& teams);
|
||||
units_map& units, std::vector<team>& teams);
|
||||
|
||||
#endif
|
||||
|
|
79
src/ai.cpp
79
src/ai.cpp
|
@ -73,7 +73,7 @@ protected:
|
|||
|
||||
const gamemap::TERRAIN terrain = get_info().map.get_terrain(dst);
|
||||
|
||||
const int chance_to_hit = un->second.defense_modifier(get_info().map,terrain);
|
||||
const int chance_to_hit = un->second.defense_modifier(terrain);
|
||||
|
||||
if(best_defense == -1 || chance_to_hit < best_defense) {
|
||||
best_defense = chance_to_hit;
|
||||
|
@ -105,7 +105,7 @@ protected:
|
|||
int best_attack = -1;
|
||||
for(size_t n = 0; n != attacks.size(); ++n) {
|
||||
if (attacks[n].attack_weight() > 0){
|
||||
const battle_stats stats = evaluate_battle_stats(get_info().map, get_info().teams, attacker, defender, n, get_info().units, get_info().state);
|
||||
const battle_stats stats = evaluate_battle_stats(get_info().map, get_info().teams, attacker, defender, n, get_info().units, get_info().state, get_info().gameinfo);
|
||||
const double attack_rating = stats.damage_defender_takes
|
||||
*stats.nattacks*stats.chance_to_hit_defender*attacks[n].attack_weight();
|
||||
if(best_attack == -1 || attack_rating > best_attack_rating) {
|
||||
|
@ -286,7 +286,7 @@ bool ai_interface::recruit(const std::string& unit_name, location loc)
|
|||
" gold=" << (current_team().gold()) <<
|
||||
" (-> " << (current_team().gold()-u->second.cost()) << ")\n";
|
||||
|
||||
unit new_unit(&u->second,info_.team_num,true);
|
||||
unit new_unit(&info_.gameinfo,&info_.units,&info_.map,&info_.state,&info_.teams,&u->second,info_.team_num,true);
|
||||
|
||||
//see if we can actually recruit (i.e. have enough room etc)
|
||||
if(recruit_unit(info_.map,info_.team_num,info_.units,new_unit,loc,preferences::show_ai_moves() ? &info_.disp : NULL).empty()) {
|
||||
|
@ -379,10 +379,12 @@ gamemap::location ai_interface::move_unit(location from, location to, std::map<l
|
|||
const location loc = move_unit_partial(from,to,possible_moves);
|
||||
const unit_map::iterator u = info_.units.find(loc);
|
||||
if(u != info_.units.end()) {
|
||||
if (from == to)
|
||||
u->second.set_movement(unit::NOT_MOVED);
|
||||
else
|
||||
if(u->second.movement_left()==u->second.total_movement()) {
|
||||
u->second.set_movement(0);
|
||||
u->second.set_state("not_moved","yes");
|
||||
} else {
|
||||
u->second.set_movement(0);
|
||||
}
|
||||
}
|
||||
|
||||
return loc;
|
||||
|
@ -414,8 +416,8 @@ gamemap::location ai_interface::move_unit_partial(location from, location to, st
|
|||
|
||||
const bool show_move = preferences::show_ai_moves();
|
||||
|
||||
const bool ignore_zocs = u_it->second.type().is_skirmisher();
|
||||
const bool teleport = u_it->second.type().teleports();
|
||||
const bool ignore_zocs = u_it->second.get_ability_bool("skirmisher",u_it->first);
|
||||
const bool teleport = u_it->second.get_ability_bool("teleports",u_it->first);
|
||||
paths current_paths(info_.map,info_.state,info_.gameinfo,info_.units,from,info_.teams,ignore_zocs,teleport,current_team());
|
||||
|
||||
const std::map<location,paths>::iterator p_it = possible_moves.find(from);
|
||||
|
@ -594,10 +596,10 @@ gamemap::location ai::move_unit(location from, location to, std::map<location,pa
|
|||
//we've been ambushed; find the ambushing unit and attack them
|
||||
adjacent_tiles_array locs;
|
||||
get_adjacent_tiles(res,locs.data());
|
||||
for(adjacent_tiles_array::const_iterator i = locs.begin(); i != locs.end(); ++i) {
|
||||
const unit_map::const_iterator itor = units_.find(*i);
|
||||
for(adjacent_tiles_array::const_iterator adj_i = locs.begin(); adj_i != locs.end(); ++adj_i) {
|
||||
const unit_map::const_iterator itor = units_.find(*adj_i);
|
||||
if(itor != units_.end() && current_team().is_enemy(itor->second.side()) &&
|
||||
!itor->second.incapacitated()) {
|
||||
itor->second.get_state("stoned") != "yes") {
|
||||
battle_stats stats;
|
||||
const int weapon = choose_weapon(res,itor->first,stats,0);
|
||||
attack_enemy(res,itor->first,weapon);
|
||||
|
@ -631,7 +633,7 @@ void ai::attack_enemy(const location& attacking_unit, const location& target, in
|
|||
|
||||
void ai_interface::calculate_possible_moves(std::map<location,paths>& res, move_map& srcdst, move_map& dstsrc, bool enemy, bool assume_full_movement, const std::set<gamemap::location>* remove_destinations)
|
||||
{
|
||||
for(std::map<gamemap::location,unit>::iterator un_it = info_.units.begin(); un_it != info_.units.end(); ++un_it) {
|
||||
for(units_map::iterator un_it = info_.units.begin(); un_it != info_.units.end(); ++un_it) {
|
||||
//if we are looking for the movement of enemies, then this unit must be an enemy unit
|
||||
//if we are looking for movement of our own units, it must be on our side.
|
||||
//if we are assuming full movement, then it may be a unit on our side, or allied
|
||||
|
@ -642,7 +644,7 @@ void ai_interface::calculate_possible_moves(std::map<location,paths>& res, move_
|
|||
}
|
||||
|
||||
//discount incapacitated units
|
||||
if(un_it->second.incapacitated()) {
|
||||
if(un_it->second.get_state("stoned")=="yes") {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -662,8 +664,8 @@ void ai_interface::calculate_possible_moves(std::map<location,paths>& res, move_
|
|||
dstsrc.insert(trivial_mv);
|
||||
}
|
||||
|
||||
const bool ignore_zocs = un_it->second.type().is_skirmisher();
|
||||
const bool teleports = un_it->second.type().teleports();
|
||||
const bool ignore_zocs = un_it->second.get_ability_bool("skirmisher",un_it->first);
|
||||
const bool teleports = un_it->second.get_ability_bool("teleports",un_it->first);
|
||||
res.insert(std::pair<gamemap::location,paths>(
|
||||
un_it->first,paths(info_.map,info_.state,info_.gameinfo,info_.units,
|
||||
un_it->first,info_.teams,ignore_zocs,teleports,current_team())));
|
||||
|
@ -1003,11 +1005,11 @@ void ai_interface::attack_enemy(const location& u, const location& target, int w
|
|||
const command_disabler disable_commands;
|
||||
|
||||
if(info_.units.count(u) && info_.units.count(target)) {
|
||||
if(info_.units.find(target)->second.stone()) {
|
||||
if(info_.units.find(target)->second.get_state("stoned")=="yes") {
|
||||
LOG_STREAM(err, ai) << "attempt to attack unit that is turned to stone\n";
|
||||
return;
|
||||
}
|
||||
if(!info_.units.find(u)->second.can_attack()) {
|
||||
if(!info_.units.find(u)->second.attacks_left()) {
|
||||
LOG_STREAM(err, ai) << "attempt to attack twice with the same unit\n";
|
||||
return;
|
||||
}
|
||||
|
@ -1139,12 +1141,12 @@ bool ai::get_villages(std::map<gamemap::location,paths>& possible_moves, const m
|
|||
}
|
||||
|
||||
const unit_map::const_iterator u = units_.find(j->second);
|
||||
if(u == units_.end() || u->second.is_guardian()) {
|
||||
if(u == units_.end() || u->second.get_state("guardian")=="yes") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const unit& un = u->second;
|
||||
if(un.hitpoints() < (threat*2*un.defense_modifier(map_,map_.get_terrain(j->first)))/100) {
|
||||
if(un.hitpoints() < (threat*2*un.defense_modifier(map_.get_terrain(j->first)))/100) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1207,7 +1209,7 @@ bool ai::get_healing(std::map<gamemap::location,paths>& possible_moves, const mo
|
|||
//find a vacant village for it to rest in
|
||||
if(u.side() == team_num_ &&
|
||||
u.max_hitpoints() - u.hitpoints() >= game_config::poison_amount/2 &&
|
||||
!u.type().regenerates()) {
|
||||
!u.get_ability_bool("regenerate",u_it->first)) {
|
||||
|
||||
//look for the village which is the least vulnerable to enemy attack
|
||||
typedef std::multimap<location,location>::const_iterator Itor;
|
||||
|
@ -1253,7 +1255,7 @@ bool ai::should_retreat(const gamemap::location& loc, const unit_map::const_iter
|
|||
}
|
||||
|
||||
const double optimal_terrain = best_defensive_position(un->first,dstsrc,srcdst,enemy_dstsrc).chance_to_hit/100.0;
|
||||
const double proposed_terrain = un->second.defense_modifier(map_,map_.get_terrain(loc))/100.0;
|
||||
const double proposed_terrain = un->second.defense_modifier(map_.get_terrain(loc))/100.0;
|
||||
|
||||
//the 'exposure' is the additional % chance to hit this unit receives from being on a sub-optimal defensive terrain
|
||||
const double exposure = proposed_terrain - optimal_terrain;
|
||||
|
@ -1304,7 +1306,7 @@ bool ai::retreat_units(std::map<gamemap::location,paths>& possible_moves, const
|
|||
//to theirs, multiplying their power projection by their chance to hit us
|
||||
//on the hex we're planning to flee to.
|
||||
const gamemap::location& hex = itors.first->second;
|
||||
const int defense = i->second.type().movement_type().defense_modifier(map_,map_.get_terrain(hex));
|
||||
const int defense = i->second.defense_modifier(map_.get_terrain(hex));
|
||||
const double our_power = power_projection(hex,dstsrc);
|
||||
const double their_power = power_projection(hex,enemy_dstsrc) * double(defense)/100.0;
|
||||
const double rating = our_power - their_power;
|
||||
|
@ -1335,7 +1337,7 @@ bool ai::retreat_units(std::map<gamemap::location,paths>& possible_moves, const
|
|||
}
|
||||
|
||||
if(best_pos.valid()) {
|
||||
LOG_AI << "retreating '" << i->second.type().id() << "' " << i->first
|
||||
LOG_AI << "retreating '" << i->second.id() << "' " << i->first
|
||||
<< " -> " << best_pos << '\n';
|
||||
move_unit(i->first,best_pos,possible_moves);
|
||||
return true;
|
||||
|
@ -1392,7 +1394,7 @@ bool ai::move_to_targets(std::map<gamemap::location,paths>& possible_moves, move
|
|||
teams_,current_team());
|
||||
|
||||
if(enemy != units_.end() &&
|
||||
current_team().is_enemy(enemy->second.side()) && enemy->second.stone() == false) {
|
||||
current_team().is_enemy(enemy->second.side()) && enemy->second.get_state("stoned") != "yes") {
|
||||
const int res = choose_weapon(move.first,adj[n],bat_stats,
|
||||
map_[move.second.x][move.second.y]);
|
||||
|
||||
|
@ -1416,9 +1418,10 @@ bool ai::move_to_targets(std::map<gamemap::location,paths>& possible_moves, move
|
|||
}
|
||||
|
||||
const unit_map::const_iterator u_it = units_.find(move.second);
|
||||
const unit_map::const_iterator un_it = units_.find(arrived_at);
|
||||
|
||||
//if we're going to attack someone
|
||||
if(u_it != units_.end() && u_it->second.stone() == false && weapon != -1) {
|
||||
if(u_it != units_.end() && u_it->second.get_state("stoned") != "yes" && weapon != -1) {
|
||||
attack_enemy(move.second,target,weapon);
|
||||
}
|
||||
|
||||
|
@ -1502,8 +1505,8 @@ void ai::analyze_potential_recruit_combat()
|
|||
continue;
|
||||
}
|
||||
|
||||
weighting += j->second.type().cost();
|
||||
score += compare_unit_types(info->second,j->second.type())*j->second.type().cost();
|
||||
weighting += j->second.cost();
|
||||
score += compare_unit_types(info->second,gameinfo_.unit_types.find(j->second.id())->second)*j->second.cost();
|
||||
}
|
||||
|
||||
if(weighting != 0) {
|
||||
|
@ -1588,7 +1591,7 @@ void ai::analyze_potential_recruit_movements()
|
|||
continue;
|
||||
}
|
||||
|
||||
const unit temp_unit(&info->second,team_num_);
|
||||
const unit temp_unit(&get_info().gameinfo,&get_info().units,&get_info().map,&get_info().state,&get_info().teams,&info->second,team_num_);
|
||||
unit_map units;
|
||||
const temporary_unit_placer placer(units,start,temp_unit);
|
||||
|
||||
|
@ -1618,9 +1621,9 @@ void ai::analyze_potential_recruit_movements()
|
|||
const int score = (average_cost * (targets_reached+targets_missed))/targets_reached;
|
||||
unit_movement_scores_[*i] = score;
|
||||
|
||||
const std::map<std::string,int>::const_iterator current_best = best_scores.find(temp_unit.type().usage());
|
||||
const std::map<std::string,int>::const_iterator current_best = best_scores.find(temp_unit.usage());
|
||||
if(current_best == best_scores.end() || score < current_best->second) {
|
||||
best_scores[temp_unit.type().usage()] = score;
|
||||
best_scores[temp_unit.usage()] = score;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1700,7 +1703,7 @@ void ai::do_recruitment()
|
|||
|
||||
for(unit_map::const_iterator u = units_.begin(); u != units_.end(); ++u) {
|
||||
if(u->second.side() == team_num_) {
|
||||
++unit_types[u->second.type().usage()];
|
||||
++unit_types[u->second.usage()];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1741,7 +1744,7 @@ void ai::move_leader_to_goals( const move_map& enemy_dstsrc)
|
|||
}
|
||||
|
||||
const unit_map::iterator leader = find_leader(units_,team_num_);
|
||||
if(leader == units_.end() || leader->second.incapacitated()) {
|
||||
if(leader == units_.end() || leader->second.get_state("stoned")=="yes") {
|
||||
WRN_AI << "Leader not found\n";
|
||||
return;
|
||||
}
|
||||
|
@ -1778,7 +1781,7 @@ void ai::move_leader_to_goals( const move_map& enemy_dstsrc)
|
|||
void ai::move_leader_to_keep(const move_map& enemy_dstsrc)
|
||||
{
|
||||
const unit_map::iterator leader = find_leader(units_,team_num_);
|
||||
if(leader == units_.end() || leader->second.incapacitated()) {
|
||||
if(leader == units_.end() || leader->second.get_state("stoned")=="yes") {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1827,7 +1830,7 @@ void ai::move_leader_after_recruit(const move_map& enemy_dstsrc)
|
|||
LOG_AI << "moving leader after recruit...\n";
|
||||
|
||||
const unit_map::iterator leader = find_leader(units_,team_num_);
|
||||
if(leader == units_.end() || leader->second.incapacitated()) {
|
||||
if(leader == units_.end() || leader->second.get_state("stoned")=="yes") {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1915,7 +1918,7 @@ void ai::move_leader_after_recruit(const move_map& enemy_dstsrc)
|
|||
bool ai::leader_can_reach_keep() const
|
||||
{
|
||||
const unit_map::iterator leader = find_leader(units_,team_num_);
|
||||
if(leader == units_.end() || leader->second.incapacitated()) {
|
||||
if(leader == units_.end() || leader->second.get_state("stoned")=="yes") {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1938,7 +1941,7 @@ bool ai::leader_can_reach_keep() const
|
|||
int ai::rate_terrain(const unit& u, const gamemap::location& loc)
|
||||
{
|
||||
const gamemap::TERRAIN terrain = map_.get_terrain(loc);
|
||||
const int defense = u.defense_modifier(map_,terrain);
|
||||
const int defense = u.defense_modifier(terrain);
|
||||
int rating = 100 - defense;
|
||||
|
||||
const int healing_value = 10;
|
||||
|
@ -1946,7 +1949,7 @@ int ai::rate_terrain(const unit& u, const gamemap::location& loc)
|
|||
const int neutral_village_value = 10;
|
||||
const int enemy_village_value = 15;
|
||||
|
||||
if(map_.gives_healing(terrain) && u.type().regenerates() == false) {
|
||||
if(map_.gives_healing(terrain) && u.get_ability_bool("regenerates",loc) == false) {
|
||||
rating += healing_value;
|
||||
}
|
||||
|
||||
|
@ -1988,7 +1991,7 @@ const ai::defensive_position& ai::best_defensive_position(const gamemap::locatio
|
|||
typedef move_map::const_iterator Itor;
|
||||
const std::pair<Itor,Itor> itors = srcdst.equal_range(loc);
|
||||
for(Itor i = itors.first; i != itors.second; ++i) {
|
||||
const int defense = itor->second.defense_modifier(map_,map_.get_terrain(i->second));
|
||||
const int defense = itor->second.defense_modifier(map_.get_terrain(i->second));
|
||||
if(defense > pos.chance_to_hit) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -67,20 +67,22 @@ void ai::do_attack_analysis(
|
|||
for(size_t i = 0; i != units.size(); ++i) {
|
||||
const location current_unit = units[i];
|
||||
|
||||
const unit_map::const_iterator unit_itor = units_.find(current_unit);
|
||||
unit_map::iterator unit_itor = units_.find(current_unit);
|
||||
wassert(unit_itor != units_.end());
|
||||
|
||||
//see if the unit has the backstab ability -- units with backstab
|
||||
//will want to try to have a friendly unit opposite the position they move to
|
||||
//see if the unit has the slow ability -- units with slow only attack first
|
||||
bool backstab = false, slow = false;
|
||||
const std::vector<attack_type>& attacks = unit_itor->second.attacks();
|
||||
for(std::vector<attack_type>::const_iterator a = attacks.begin(); a != attacks.end(); ++a) {
|
||||
if(a->backstab()) {
|
||||
std::vector<attack_type>& attacks = unit_itor->second.attacks();
|
||||
for(std::vector<attack_type>::iterator a = attacks.begin(); a != attacks.end(); ++a) {
|
||||
a->set_specials_context(gamemap::location(),gamemap::location(),
|
||||
&gameinfo_,&units_,&map_,&state_,&teams_,true,NULL);
|
||||
if(a->get_special_bool("backstab")) {
|
||||
backstab = true;
|
||||
}
|
||||
|
||||
if(a->slow()) {
|
||||
if(a->get_special_bool("slow")) {
|
||||
slow = true;
|
||||
}
|
||||
}
|
||||
|
@ -327,7 +329,7 @@ int ai::choose_weapon(const location& att, const location& def,
|
|||
for(size_t a = 0; a != attacks.size(); ++a) {
|
||||
if (attacks[a].attack_weight() > 0){
|
||||
const battle_stats stats = evaluate_battle_stats(map_, teams_, att, def, a, units_,
|
||||
state_, terrain);
|
||||
state_, gameinfo_, terrain);
|
||||
|
||||
//TODO: improve this rating formula!
|
||||
const double rating =
|
||||
|
@ -374,7 +376,7 @@ void ai::attack_analysis::analyze(const gamemap& map, unit_map& units, int num_s
|
|||
leader_threat = (tile != 6);
|
||||
uses_leader = false;
|
||||
|
||||
target_value = defend_it->second.type().cost();
|
||||
target_value = defend_it->second.cost();
|
||||
target_value += (double(defend_it->second.experience())/
|
||||
double(defend_it->second.max_experience()))*target_value;
|
||||
target_starting_damage = defend_it->second.max_hitpoints() -
|
||||
|
@ -412,7 +414,7 @@ void ai::attack_analysis::analyze(const gamemap& map, unit_map& units, int num_s
|
|||
|
||||
int defenderxp = 0;
|
||||
|
||||
bool defender_slowed= defend_it->second.slowed();
|
||||
bool defender_slowed= defend_it->second.get_state("slowed")=="yes";
|
||||
|
||||
int defhp = target_hp;
|
||||
for(size_t i = 0; i != movements.size() && defhp; ++i) {
|
||||
|
@ -423,14 +425,14 @@ void ai::attack_analysis::analyze(const gamemap& map, unit_map& units, int num_s
|
|||
int defends = stat.ndefends;
|
||||
|
||||
unit_map::const_iterator att = units.find(movements[i].first);
|
||||
double cost = att->second.type().cost();
|
||||
double cost = att->second.cost();
|
||||
|
||||
if(att->second.can_recruit()) {
|
||||
uses_leader = true;
|
||||
}
|
||||
|
||||
const bool on_village = map.is_village(movements[i].second);
|
||||
bool attacker_slowed= att->second.slowed();
|
||||
bool attacker_slowed= att->second.get_state("slowed")=="yes";
|
||||
|
||||
//up to double the value of a unit based on experience
|
||||
cost += (double(att->second.experience())/
|
||||
|
@ -498,14 +500,14 @@ void ai::attack_analysis::analyze(const gamemap& map, unit_map& units, int num_s
|
|||
}
|
||||
}
|
||||
|
||||
const int xp = defend_it->second.type().level() * (defhp <= 0 ? game_config::kill_experience : 1);
|
||||
const int xp = defend_it->second.level() * (defhp <= 0 ? game_config::kill_experience : 1);
|
||||
|
||||
const int xp_for_advance = att->second.max_experience() - att->second.experience();
|
||||
|
||||
//the reward for advancing a unit is to get a 'negative' loss of that unit
|
||||
if(att->second.type().advances_to().empty() == false) {
|
||||
if(att->second.advances_to().empty() == false) {
|
||||
if(xp >= xp_for_advance) {
|
||||
avg_losses -= att->second.type().cost();
|
||||
avg_losses -= att->second.cost();
|
||||
|
||||
//ignore any damage done to this unit
|
||||
atthp = hitpoints[i];
|
||||
|
@ -514,7 +516,7 @@ void ai::attack_analysis::analyze(const gamemap& map, unit_map& units, int num_s
|
|||
//the proportion of remaining experience needed, and multiply
|
||||
//it by a quarter of the unit cost. This will cause the AI
|
||||
//to heavily favor getting xp for close-to-advance units.
|
||||
avg_losses -= (att->second.type().cost()*xp)/(xp_for_advance*4);
|
||||
avg_losses -= (att->second.cost()*xp)/(xp_for_advance*4);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -522,7 +524,7 @@ void ai::attack_analysis::analyze(const gamemap& map, unit_map& units, int num_s
|
|||
//the reward for killing with a unit that
|
||||
//plagues is to get a 'negative' loss of that unit
|
||||
if(stat.attacker_plague) {
|
||||
avg_losses -= att->second.type().cost();
|
||||
avg_losses -= att->second.cost();
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -535,14 +537,14 @@ void ai::attack_analysis::analyze(const gamemap& map, unit_map& units, int num_s
|
|||
atthp += game_config::poison_amount*2; //double reward to emphasize getting onto villages
|
||||
}
|
||||
|
||||
defenderxp += (atthp == 0 ? game_config::kill_experience:1)*att->second.type().level();
|
||||
defenderxp += (atthp == 0 ? game_config::kill_experience:1)*att->second.level();
|
||||
|
||||
avg_damage_taken += hitpoints[i] - atthp;
|
||||
}
|
||||
|
||||
//penalty for allowing advancement is a 'negative' kill, and
|
||||
//defender's hitpoints get restored to maximum
|
||||
if(defend_it->second.type().advances_to().empty() == false &&
|
||||
if(defend_it->second.advances_to().empty() == false &&
|
||||
defend_it->second.experience() < defend_it->second.max_experience() &&
|
||||
defend_it->second.experience() + defenderxp >=
|
||||
defend_it->second.max_experience()) {
|
||||
|
@ -568,7 +570,7 @@ void ai::attack_analysis::analyze(const gamemap& map, unit_map& units, int num_s
|
|||
double cost_sum = 0.0;
|
||||
for(size_t i = 0; i != movements.size(); ++i) {
|
||||
const unit_map::const_iterator att = units.find(movements[i].first);
|
||||
const double cost = att->second.type().cost();
|
||||
const double cost = att->second.cost();
|
||||
cost_sum += cost;
|
||||
alternative_terrain_quality += cost*ai_obj.best_defensive_position(att->first,dstsrc,srcdst,enemy_dstsrc).chance_to_hit;
|
||||
}
|
||||
|
@ -689,7 +691,7 @@ std::vector<ai::attack_analysis> ai::analyze_targets(
|
|||
for(unit_map::const_iterator j = units_.begin(); j != units_.end(); ++j) {
|
||||
|
||||
//attack anyone who is on the enemy side, and who is not invisible or turned to stone
|
||||
if(current_team().is_enemy(j->second.side()) && j->second.stone() == false &&
|
||||
if(current_team().is_enemy(j->second.side()) && j->second.get_state("stoned")!="yes" &&
|
||||
j->second.invisible(map_.underlying_union_terrain(map_[j->first.x][j->first.y]),
|
||||
state_.get_time_of_day().lawful_bonus,j->first,
|
||||
units_,teams_) == false) {
|
||||
|
@ -761,9 +763,9 @@ double ai::power_projection(const gamemap::location& loc, const move_map& dstsr
|
|||
const unit& un = u->second;
|
||||
|
||||
int tod_modifier = 0;
|
||||
if(un.type().alignment() == unit_type::LAWFUL) {
|
||||
if(un.alignment() == unit_type::LAWFUL) {
|
||||
tod_modifier = lawful_bonus;
|
||||
} else if(un.type().alignment() == unit_type::CHAOTIC) {
|
||||
} else if(un.alignment() == unit_type::CHAOTIC) {
|
||||
tod_modifier = -lawful_bonus;
|
||||
}
|
||||
|
||||
|
@ -781,7 +783,7 @@ double ai::power_projection(const gamemap::location& loc, const move_map& dstsr
|
|||
const bool village = map_.is_village(terrain);
|
||||
const double village_bonus = (use_terrain && village) ? 1.5 : 1.0;
|
||||
|
||||
const double defense = use_terrain ? double(100 - un.defense_modifier(map_,terrain))/100.0 : 0.5;
|
||||
const double defense = use_terrain ? double(100 - un.defense_modifier(terrain))/100.0 : 0.5;
|
||||
const double rating = village_bonus*hp*defense*double(most_damage);
|
||||
if(rating > best_rating) {
|
||||
best_rating = rating;
|
||||
|
|
|
@ -225,7 +225,7 @@ namespace dfool {
|
|||
{
|
||||
unit_map filtered_units_;
|
||||
for(unit_map::const_iterator i = units_.begin(); i != units_.end(); ++i) {
|
||||
if(i->second.matches_filter(filter)) {
|
||||
if(i->second.matches_filter(filter,i->first)) {
|
||||
filtered_units_.insert(*i);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,11 +33,11 @@ struct move_cost_calculator : cost_calculator
|
|||
const ai::move_map& dstsrc,
|
||||
const ai::move_map& enemy_dstsrc)
|
||||
: unit_(u), map_(map), data_(data), units_(units),
|
||||
move_type_(u.type().movement_type()), loc_(loc), dstsrc_(dstsrc), enemy_dstsrc_(enemy_dstsrc),
|
||||
avoid_enemies_(u.type().usage() == "scout")
|
||||
loc_(loc), dstsrc_(dstsrc), enemy_dstsrc_(enemy_dstsrc),
|
||||
avoid_enemies_(u.usage() == "scout")
|
||||
{}
|
||||
|
||||
virtual double cost(const gamemap::location& loc, const double, const bool) const
|
||||
virtual double cost(const gamemap::location& src,const gamemap::location& loc, const double, const bool) const
|
||||
{
|
||||
/*
|
||||
if(!map_.on_board(loc))
|
||||
|
@ -58,7 +58,7 @@ struct move_cost_calculator : cost_calculator
|
|||
const gamemap::TERRAIN terrain = map_[loc.x][loc.y];
|
||||
|
||||
const double modifier = 1.0; //move_type_.defense_modifier(map_,terrain);
|
||||
const double move_cost = move_type_.movement_cost(map_,terrain);
|
||||
const double move_cost = unit_.movement_cost(terrain);//move_type_[terrain];
|
||||
|
||||
const int enemies = 1 + (avoid_enemies_ ? enemy_dstsrc_.count(loc) : 0);
|
||||
double res = modifier*move_cost*double(enemies);
|
||||
|
@ -77,7 +77,7 @@ private:
|
|||
const gamemap& map_;
|
||||
const game_data& data_;
|
||||
const unit_map& units_;
|
||||
const unit_movement_type& move_type_;
|
||||
// mutable std::map<gamemap::TERRAIN,int> move_type_;
|
||||
const gamemap::location loc_;
|
||||
const ai::move_map dstsrc_, enemy_dstsrc_;
|
||||
const bool avoid_enemies_;
|
||||
|
@ -153,7 +153,7 @@ std::vector<ai::target> ai::find_targets(unit_map::const_iterator leader, const
|
|||
//explicit targets for this team
|
||||
for(std::vector<team::target>::iterator j = team_targets.begin();
|
||||
j != team_targets.end(); ++j) {
|
||||
if(u->second.matches_filter(j->criteria)) {
|
||||
if(u->second.matches_filter(j->criteria,u->first)) {
|
||||
LOG_AI << "found explicit target..." << j->value << "\n";
|
||||
targets.push_back(target(u->first,j->value,target::EXPLICIT));
|
||||
}
|
||||
|
@ -303,7 +303,7 @@ bool ai::move_group(const location& dst, const std::vector<location>& route, con
|
|||
continue;
|
||||
}
|
||||
|
||||
const int defense = un->second.defense_modifier(map_,map_.get_terrain(*j));
|
||||
const int defense = un->second.defense_modifier(map_.get_terrain(*j));
|
||||
if(best_loc.valid() == false || defense < best_defense) {
|
||||
best_loc = *j;
|
||||
best_defense = defense;
|
||||
|
@ -352,7 +352,7 @@ double ai::rate_group(const std::set<location>& group, const std::vector<locatio
|
|||
|
||||
int defense = 0;
|
||||
for(std::vector<location>::const_iterator j = battlefield.begin(); j != battlefield.end(); ++j) {
|
||||
defense += un.defense_modifier(map_,map_.get_terrain(*j));
|
||||
defense += un.defense_modifier(map_.get_terrain(*j));
|
||||
}
|
||||
|
||||
defense /= battlefield.size();
|
||||
|
@ -398,7 +398,7 @@ std::pair<gamemap::location,gamemap::location> ai::choose_move(std::vector<targe
|
|||
|
||||
//find the first eligible unit
|
||||
for(u = units_.begin(); u != units_.end(); ++u) {
|
||||
if(!(u->second.side() != team_num_ || u->second.can_recruit() || u->second.movement_left() <= 0 || u->second.incapacitated())) {
|
||||
if(!(u->second.side() != team_num_ || u->second.can_recruit() || u->second.movement_left() <= 0 || u->second.get_state("stoned")=="yes")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -409,8 +409,8 @@ std::pair<gamemap::location,gamemap::location> ai::choose_move(std::vector<targe
|
|||
}
|
||||
|
||||
//guardian units stay put
|
||||
if(u->second.is_guardian()) {
|
||||
LOG_AI << u->second.type().id() << " is guardian, staying still\n";
|
||||
if(u->second.get_state("guardian")=="yes") {
|
||||
LOG_AI << u->second.id() << " is guardian, staying still\n";
|
||||
return std::pair<location,location>(u->first,u->first);
|
||||
}
|
||||
|
||||
|
@ -454,7 +454,7 @@ std::pair<gamemap::location,gamemap::location> ai::choose_move(std::vector<targe
|
|||
}
|
||||
|
||||
//scouts do not like encountering enemies on their paths
|
||||
if(u->second.type().usage() == "scout") {
|
||||
if(u->second.usage() == "scout") {
|
||||
std::set<location> enemies_guarding;
|
||||
enemies_along_path(cur_route.steps,enemy_dstsrc,enemies_guarding);
|
||||
|
||||
|
@ -499,7 +499,7 @@ std::pair<gamemap::location,gamemap::location> ai::choose_move(std::vector<targe
|
|||
//now see if any other unit can put a better bid forward
|
||||
for(++u; u != units_.end(); ++u) {
|
||||
if(u->second.side() != team_num_ || u->second.can_recruit() ||
|
||||
u->second.movement_left() <= 0 || u->second.is_guardian() || u->second.incapacitated()) {
|
||||
u->second.movement_left() <= 0 || u->second.get_state("guardian")=="yes" || u->second.get_state("stoned")=="yes") {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -535,7 +535,7 @@ std::pair<gamemap::location,gamemap::location> ai::choose_move(std::vector<targe
|
|||
}
|
||||
|
||||
//scouts do not like encountering enemies on their paths
|
||||
if(u->second.type().usage() == "scout") {
|
||||
if(u->second.usage() == "scout") {
|
||||
std::set<location> enemies_guarding;
|
||||
enemies_along_path(cur_route.steps,enemy_dstsrc,enemies_guarding);
|
||||
|
||||
|
@ -583,7 +583,7 @@ std::pair<gamemap::location,gamemap::location> ai::choose_move(std::vector<targe
|
|||
|
||||
for(std::vector<location>::const_iterator i = locs.begin(); i != locs.end(); ++i) {
|
||||
const int distance = distance_between(*i,best_target->loc);
|
||||
const int defense = best->second.defense_modifier(map_,map_.get_terrain(*i));
|
||||
const int defense = best->second.defense_modifier(map_.get_terrain(*i));
|
||||
const double vulnerability = power_projection(*i,enemy_dstsrc);
|
||||
|
||||
if(best_loc.valid() == false || defense < best_defense || defense == best_defense && vulnerability < best_vulnerability) {
|
||||
|
@ -626,7 +626,7 @@ std::pair<gamemap::location,gamemap::location> ai::choose_move(std::vector<targe
|
|||
}
|
||||
|
||||
if(!defensive_grouping) {
|
||||
movement -= best->second.movement_cost(map_,map_.get_terrain(*i));
|
||||
movement -= best->second.movement_cost(map_.get_terrain(*i));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -676,7 +676,7 @@ std::pair<gamemap::location,gamemap::location> ai::choose_move(std::vector<targe
|
|||
const std::pair<move_map::const_iterator,move_map::const_iterator> itors = srcdst.equal_range(loc);
|
||||
for(move_map::const_iterator i = itors.first; i != itors.second; ++i) {
|
||||
const int distance = distance_between(target_loc,i->second);
|
||||
const int defense = un.defense_modifier(map_,map_.get_terrain(i->second));
|
||||
const int defense = un.defense_modifier(map_.get_terrain(i->second));
|
||||
const double threat = (power_projection(i->second,enemy_dstsrc)*defense)/100;
|
||||
|
||||
if(best_loc.valid() == false || threat < maximum<double>(best_threat,max_acceptable_threat) && distance < best_distance) {
|
||||
|
@ -716,7 +716,7 @@ std::pair<gamemap::location,gamemap::location> ai::choose_move(std::vector<targe
|
|||
while(its.first != its.second) {
|
||||
if(its.first->second == best->first) {
|
||||
if(!should_retreat(its.first->first,best,fullmove_srcdst,fullmove_dstsrc,enemy_dstsrc)) {
|
||||
const double value = best_target->value - best->second.type().cost()/20.0;
|
||||
const double value = best_target->value - best->second.cost()/20.0;
|
||||
|
||||
if(value > 0.0 && best_target->type != target::MASS) {
|
||||
//there are enemies ahead. Rally troops around us to
|
||||
|
|
|
@ -283,7 +283,7 @@ struct passage_path_calculator : cost_calculator
|
|||
: map_(mapdata), wall_(wall), laziness_(laziness), windiness_(windiness)
|
||||
{}
|
||||
|
||||
virtual double cost(const gamemap::location& loc, const double so_far, const bool is_dest) const;
|
||||
virtual double cost(const gamemap::location& src,const gamemap::location& loc, const double so_far, const bool is_dest) const;
|
||||
private:
|
||||
const std::vector<std::vector<gamemap::TERRAIN> >& map_;
|
||||
gamemap::TERRAIN wall_;
|
||||
|
@ -291,7 +291,7 @@ private:
|
|||
size_t windiness_;
|
||||
};
|
||||
|
||||
double passage_path_calculator::cost(const gamemap::location& loc, const double, const bool) const
|
||||
double passage_path_calculator::cost(const gamemap::location& src,const gamemap::location& loc, const double, const bool) const
|
||||
{
|
||||
wassert(loc.x >= 0 && loc.y >= 0 && size_t(loc.x) < map_.size() &&
|
||||
!map_.empty() && size_t(loc.y) < map_.front().size());
|
||||
|
|
|
@ -27,7 +27,7 @@ std::string get_unique_saveid(const config& cfg, std::set<std::string>& seen_sav
|
|||
return save_id;
|
||||
}
|
||||
|
||||
void get_player_info(const config& cfg, game_state& gamestate, std::string save_id, std::vector<team>& teams, const config& level, const game_data& gameinfo, gamemap& map, unit_map& units){
|
||||
void get_player_info(const config& cfg, game_state& gamestate, std::string save_id, std::vector<team>& teams, const config& level, const game_data& gameinfo, gamemap& map, unit_map& units, gamestatus& game_status){
|
||||
player_info *player = NULL;
|
||||
|
||||
if(cfg["controller"] == "human" ||
|
||||
|
@ -73,14 +73,15 @@ void get_player_info(const config& cfg, game_state& gamestate, std::string save_
|
|||
|
||||
//if this side tag describes the leader of the side
|
||||
if(cfg["no_leader"] != "yes" && cfg["controller"] != "null") {
|
||||
unit new_unit(gameinfo, cfg);
|
||||
|
||||
unit new_unit(&gameinfo, &units, &map, &game_status, &teams,cfg);
|
||||
|
||||
//search the recall list for leader units, and if there is
|
||||
//one, use it in place of the config-described unit
|
||||
if(player != NULL) {
|
||||
for(std::vector<unit>::iterator it = player->available_units.begin(); it != player->available_units.end(); ++it) {
|
||||
if(it->can_recruit()) {
|
||||
new_unit = *it;
|
||||
new_unit.set_game_context(&gameinfo, &units, &map, &game_status, &teams);
|
||||
player->available_units.erase(it);
|
||||
break;
|
||||
}
|
||||
|
@ -107,7 +108,7 @@ void get_player_info(const config& cfg, game_state& gamestate, std::string save_
|
|||
lexical_cast<std::string>(side) + ".");
|
||||
}
|
||||
|
||||
new_unit.new_turn();
|
||||
new_unit.new_turn(map.starting_position(new_unit.side()));
|
||||
units.insert(std::pair<gamemap::location,unit>(
|
||||
map.starting_position(new_unit.side()), new_unit));
|
||||
LOG_NG << "initializing side '" << cfg["side"] << "' at "
|
||||
|
@ -128,7 +129,7 @@ void get_player_info(const config& cfg, game_state& gamestate, std::string save_
|
|||
//if there are additional starting units on this side
|
||||
const config::child_list& starting_units = cfg.get_children("unit");
|
||||
for(config::child_list::const_iterator su = starting_units.begin(); su != starting_units.end(); ++su) {
|
||||
unit new_unit(gameinfo,**su);
|
||||
unit new_unit(&gameinfo, &units, &map, &game_status,&teams,**su);
|
||||
|
||||
new_unit.set_side(side);
|
||||
|
||||
|
|
|
@ -22,13 +22,13 @@
|
|||
#include "gamestatus.hpp"
|
||||
|
||||
class unit;
|
||||
|
||||
typedef std::map<gamemap::location,unit> units_map;
|
||||
//This module is responsible for constructing objects like 'team'
|
||||
//or 'unit' out of config-information, that is based on WML.
|
||||
|
||||
std::string get_unique_saveid(const config& cfg, std::set<std::string>& seen_save_ids);
|
||||
int get_first_human_team(const config::child_list::const_iterator& cfg, const config::child_list& unit_cfg);
|
||||
void get_player_info(const config& cfg, game_state& gamestate, std::string save_id, std::vector<team>& teams, const config& level, const game_data& gameinfo, gamemap& map, std::map<gamemap::location,unit>& units);
|
||||
void get_player_info(const config& cfg, game_state& gamestate, std::string save_id, std::vector<team>& teams, const config& level, const game_data& gameinfo, gamemap& map, units_map& units, gamestatus& game_status);
|
||||
const config* get_theme(const config& game_config, std::string theme_name);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -52,38 +52,38 @@ namespace dialogs
|
|||
|
||||
void advance_unit(const game_data& info,
|
||||
const gamemap& map,
|
||||
std::map<gamemap::location,unit>& units,
|
||||
units_map& units,
|
||||
gamemap::location loc,
|
||||
display& gui, bool random_choice)
|
||||
{
|
||||
std::map<gamemap::location,unit>::iterator u = units.find(loc);
|
||||
units_map::iterator u = units.find(loc);
|
||||
if(u == units.end() || u->second.advances() == false)
|
||||
return;
|
||||
|
||||
LOG_DP << "advance_unit: " << u->second.type().id() << "\n";
|
||||
LOG_DP << "advance_unit: " << u->second.id() << "\n";
|
||||
|
||||
const std::vector<std::string>& options = u->second.type().advances_to();
|
||||
const std::vector<std::string>& options = u->second.advances_to();
|
||||
|
||||
std::vector<std::string> lang_options;
|
||||
|
||||
std::vector<unit> sample_units;
|
||||
for(std::vector<std::string>::const_iterator op = options.begin(); op != options.end(); ++op) {
|
||||
sample_units.push_back(::get_advanced_unit(info,units,loc,*op));
|
||||
const unit_type& type = sample_units.back().type();
|
||||
lang_options.push_back(IMAGE_PREFIX + type.image() + COLUMN_SEPARATOR + type.language_name());
|
||||
const unit& type = sample_units.back();
|
||||
lang_options.push_back(IMAGE_PREFIX + type.absolute_image() + COLUMN_SEPARATOR + type.language_name());
|
||||
preferences::encountered_units().insert(*op);
|
||||
}
|
||||
|
||||
const config::child_list& mod_options = u->second.get_modification_advances();
|
||||
|
||||
for(config::child_list::const_iterator mod = mod_options.begin(); mod != mod_options.end(); ++mod) {
|
||||
sample_units.push_back(::get_advanced_unit(info,units,loc,u->second.type().id()));
|
||||
sample_units.push_back(::get_advanced_unit(info,units,loc,u->second.id()));
|
||||
sample_units.back().add_modification("advance",**mod);
|
||||
const unit_type& type = sample_units.back().type();
|
||||
const unit& type = sample_units.back();
|
||||
if((**mod)["image"].str().size()){
|
||||
lang_options.push_back(IMAGE_PREFIX + (**mod)["image"].str() + COLUMN_SEPARATOR + (**mod)["description"].str());
|
||||
}else{
|
||||
lang_options.push_back(IMAGE_PREFIX + type.image() + COLUMN_SEPARATOR + (**mod)["description"].str());
|
||||
lang_options.push_back(IMAGE_PREFIX + type.absolute_image() + COLUMN_SEPARATOR + (**mod)["description"].str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,12 +117,12 @@ bool animate_unit_advancement(const game_data& info,unit_map& units, gamemap::lo
|
|||
{
|
||||
const command_disabler cmd_disabler;
|
||||
|
||||
std::map<gamemap::location,unit>::iterator u = units.find(loc);
|
||||
units_map::iterator u = units.find(loc);
|
||||
if(u == units.end() || u->second.advances() == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& options = u->second.type().advances_to();
|
||||
const std::vector<std::string>& options = u->second.advances_to();
|
||||
const config::child_list& mod_options = u->second.get_modification_advances();
|
||||
|
||||
if(choice >= options.size() + mod_options.size()) {
|
||||
|
@ -143,7 +143,7 @@ bool animate_unit_advancement(const game_data& info,unit_map& units, gamemap::lo
|
|||
}
|
||||
|
||||
if(choice < options.size()) {
|
||||
const std::string& chosen_unit = choice < options.size() ? options[choice] : u->second.type().id();
|
||||
const std::string& chosen_unit = choice < options.size() ? options[choice] : u->second.id();
|
||||
::advance_unit(info,units,loc,chosen_unit);
|
||||
}
|
||||
|
||||
|
@ -608,10 +608,10 @@ std::string load_game_dialog(display& disp, const config& game_config, const gam
|
|||
void unit_speak(const config& message_info, display& disp, const unit_map& units)
|
||||
{
|
||||
for(unit_map::const_iterator i = units.begin(); i != units.end(); ++i) {
|
||||
if(i->second.matches_filter(message_info)) {
|
||||
if(i->second.matches_filter(message_info,i->first)) {
|
||||
|
||||
disp.scroll_to_tile(i->first.x,i->first.y);
|
||||
const surface surface(image::get_image(i->second.type().image_profile(),image::UNSCALED));
|
||||
const surface surface(image::get_image(i->second.profile(),image::UNSCALED));
|
||||
gui::show_dialog(disp,surface,i->second.underlying_description(),message_info["message"],gui::MESSAGE);
|
||||
}
|
||||
}
|
||||
|
@ -634,7 +634,7 @@ unit_preview_pane::unit_preview_pane(display& disp, const gamemap* map, const un
|
|||
unit_store_.push_back(u);
|
||||
}
|
||||
|
||||
unit_preview_pane::unit_preview_pane(display& disp, const gamemap* map, const std::vector<unit>& units, TYPE type, bool on_left_side)
|
||||
unit_preview_pane::unit_preview_pane(display& disp, const gamemap* map, std::vector<unit>& units, TYPE type, bool on_left_side)
|
||||
: gui::preview_pane(disp.video()), disp_(disp),
|
||||
details_button_(disp.video(),_("Profile"),gui::button::TYPE_PRESS,"lite_small",gui::button::MINIMUM_SPACE),
|
||||
map_(map), units_(&units), index_(0), left_(on_left_side),
|
||||
|
@ -671,7 +671,7 @@ void unit_preview_pane::draw_contents()
|
|||
return;
|
||||
}
|
||||
|
||||
const unit& u = (*units_)[index_];
|
||||
unit& u = (*units_)[index_];
|
||||
|
||||
const bool right_align = left_side();
|
||||
|
||||
|
@ -712,18 +712,19 @@ void unit_preview_pane::draw_contents()
|
|||
}
|
||||
|
||||
std::stringstream details;
|
||||
details << u.type().language_name()
|
||||
details << u.language_name()
|
||||
<< "\n" << _("level") << " "
|
||||
<< u.type().level() << "\n"
|
||||
<< unit_type::alignment_description(u.type().alignment()) << "\n"
|
||||
<< u.level() << "\n"
|
||||
<< unit_type::alignment_description(u.alignment()) << "\n"
|
||||
<< u.traits_description() << " \n";
|
||||
|
||||
const std::vector<std::string>& abilities = u.type().ability_tooltips();
|
||||
const std::vector<std::string>& abilities = u.unit_ability_tooltips();
|
||||
for(std::vector<std::string>::const_iterator a = abilities.begin(); a != abilities.end(); ++a) {
|
||||
details << gettext(a->c_str());
|
||||
if(a+1 != abilities.end()) {
|
||||
if(a+2 != abilities.end()) {
|
||||
details << ", ";
|
||||
}
|
||||
++a;
|
||||
}
|
||||
|
||||
details << " \n";
|
||||
|
@ -755,14 +756,15 @@ void unit_preview_pane::draw_contents()
|
|||
<< u.total_movement()
|
||||
<< "\n";
|
||||
|
||||
const std::vector<attack_type>& attacks = u.attacks();
|
||||
for(std::vector<attack_type>::const_iterator at_it = attacks.begin();
|
||||
std::vector<attack_type>& attacks = u.attacks();
|
||||
for(std::vector<attack_type>::iterator at_it = attacks.begin();
|
||||
at_it != attacks.end(); ++at_it) {
|
||||
at_it->set_specials_context(gamemap::location(),u);
|
||||
|
||||
details << "\n" << at_it->name()
|
||||
<< " (" << gettext(at_it->type().c_str()) << ")\n";
|
||||
if (!at_it->special().empty())
|
||||
details << gettext(at_it->special().c_str());
|
||||
|
||||
details << at_it->weapon_specials();
|
||||
details << "\n"
|
||||
<< at_it->damage() << "-" << at_it->num_attacks() << " -- "
|
||||
<< _(at_it->range().c_str());
|
||||
|
@ -801,7 +803,7 @@ void unit_preview_pane::process_event()
|
|||
|
||||
void show_unit_description(display &disp, const unit& u)
|
||||
{
|
||||
help::show_help(disp,"unit_" + u.type().id());
|
||||
help::show_help(disp,"unit_" + u.id());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ public:
|
|||
enum TYPE { SHOW_ALL, SHOW_BASIC };
|
||||
|
||||
unit_preview_pane(display &disp, const gamemap* map, const unit& u, TYPE type=SHOW_ALL, bool left_side=true);
|
||||
unit_preview_pane(display &disp, const gamemap* map, const std::vector<unit>& units, TYPE type=SHOW_ALL, bool left_side=true);
|
||||
unit_preview_pane(display &disp, const gamemap* map, std::vector<unit>& units, TYPE type=SHOW_ALL, bool left_side=true);
|
||||
|
||||
bool show_above() const;
|
||||
bool left_side() const;
|
||||
|
@ -80,7 +80,7 @@ private:
|
|||
|
||||
gui::button details_button_;
|
||||
const gamemap* map_;
|
||||
const std::vector<unit>* units_;
|
||||
std::vector<unit>* units_;
|
||||
std::vector<unit> unit_store_;
|
||||
int index_;
|
||||
bool left_;
|
||||
|
|
|
@ -932,7 +932,7 @@ void display::draw_sidebar()
|
|||
if(invalidateUnit_) {
|
||||
//we display the unit the mouse is over if it is over a unit
|
||||
//otherwise we display the unit that is selected
|
||||
std::map<gamemap::location,unit>::const_iterator i =
|
||||
units_map::const_iterator i =
|
||||
find_visible_unit(units_,mouseoverHex_,
|
||||
map_,
|
||||
status_.get_time_of_day().lawful_bonus,
|
||||
|
@ -1230,12 +1230,9 @@ void display::draw_unit_on_tile(int x, int y)
|
|||
if(it == units_.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
it->second.refresh_unit(*this,src,true);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void display::draw_bar(const std::string& image, int xpos, int ypos, size_t height, double filled, const SDL_Color& col, fixed_t alpha)
|
||||
|
@ -1566,7 +1563,7 @@ void display::draw_footstep(const gamemap::location& loc, int xloc, int yloc)
|
|||
const std::string* image_str = &image_category->front();
|
||||
const unit_map::const_iterator un = units_.find(route_.steps.front());
|
||||
if(un != units_.end()) {
|
||||
const int move_cost = un->second.movement_cost(map_,map_.get_terrain(loc)) - 1;
|
||||
const int move_cost = un->second.movement_cost(map_.get_terrain(loc)) - 1;
|
||||
if(move_cost >= int(image_category->size())) {
|
||||
image_str = &image_category->back();
|
||||
} else if(move_cost > 0) {
|
||||
|
@ -1607,7 +1604,7 @@ void display::draw_movement_info(const gamemap::location& loc, int xloc, int ylo
|
|||
#ifndef USE_TINY_GUI
|
||||
const unit_map::const_iterator un = units_.find(route_.steps.front());
|
||||
if(un != units_.end() && zoom_ >= DefaultZoom) {
|
||||
text << (100-un->second.defense_modifier(map_,map_.get_terrain(loc))) << "%";
|
||||
text << (100-un->second.defense_modifier(map_.get_terrain(loc))) << "%";
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* $Id$ */
|
||||
/* $Id$ */
|
||||
/*
|
||||
Copyright (C) 2003 by David White <davidnwhite@verizon.net>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
@ -49,7 +50,7 @@ namespace {
|
|||
|
||||
display* screen = NULL;
|
||||
gamemap* game_map = NULL;
|
||||
std::map<gamemap::location,unit>* units = NULL;
|
||||
units_map* units = NULL;
|
||||
std::vector<team>* teams = NULL;
|
||||
game_state* state_of_game = NULL;
|
||||
const game_data* game_data_ptr = NULL;
|
||||
|
@ -59,7 +60,7 @@ int floating_label = 0;
|
|||
|
||||
namespace game_events {
|
||||
|
||||
bool conditional_passed(const std::map<gamemap::location,unit>* units,
|
||||
bool conditional_passed(const units_map* units,
|
||||
const vconfig cond)
|
||||
{
|
||||
//an 'and' statement means that if the contained statements are false,
|
||||
|
@ -91,7 +92,7 @@ bool conditional_passed(const std::map<gamemap::location,unit>* units,
|
|||
if(units == NULL)
|
||||
return false;
|
||||
|
||||
std::map<gamemap::location,unit>::const_iterator itor;
|
||||
units_map::const_iterator itor;
|
||||
for(itor = units->begin(); itor != units->end(); ++itor) {
|
||||
if(itor->second.hitpoints() > 0 && game_events::unit_matches_filter(itor, *u)) {
|
||||
break;
|
||||
|
@ -347,12 +348,12 @@ bool event_handler::handle_event_command(const queued_event& event_info,
|
|||
else if(cmd == "unstone") {
|
||||
const vconfig filter = cfg.child("filter");
|
||||
for(unit_map::iterator i = units->begin(); i != units->end(); ++i) {
|
||||
if(i->second.stone()) {
|
||||
if(i->second.get_state("stoned")=="yes") {
|
||||
if(!filter.null()) {
|
||||
if(game_events::unit_matches_filter(i, filter))
|
||||
i->second.remove_flag("stone");
|
||||
i->second.set_state("stoned","");
|
||||
} else {
|
||||
i->second.remove_flag("stone");
|
||||
i->second.set_state("stoned","");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -616,7 +617,11 @@ bool event_handler::handle_event_command(const queued_event& event_info,
|
|||
const unit_race::GENDER gender = gender_string == "female" ? unit_race::FEMALE : unit_race::MALE;
|
||||
const game_data::unit_type_map::const_iterator itor = game_data_ptr->unit_types.find(type);
|
||||
if(itor != game_data_ptr->unit_types.end()) {
|
||||
unit dummy_unit(&itor->second,0,false,true,gender);
|
||||
wassert(game_data_ptr != NULL);
|
||||
wassert(units != NULL);
|
||||
wassert(game_map != NULL);
|
||||
wassert(status_ptr != NULL);
|
||||
unit dummy_unit(game_data_ptr,units,game_map,status_ptr,teams,&itor->second,0,false,true,gender);
|
||||
const std::vector<std::string> xvals = utils::split(x);
|
||||
const std::vector<std::string> yvals = utils::split(y);
|
||||
std::vector<gamemap::location> path;
|
||||
|
@ -918,7 +923,7 @@ bool event_handler::handle_event_command(const queued_event& event_info,
|
|||
item["role"] = "";
|
||||
vconfig filter(&item);
|
||||
|
||||
std::map<gamemap::location,unit>::iterator itor;
|
||||
units_map::iterator itor;
|
||||
for(itor = units->begin(); itor != units->end(); ++itor) {
|
||||
if(game_events::unit_matches_filter(itor, filter)) {
|
||||
itor->second.assign_role(cfg["role"]);
|
||||
|
@ -945,7 +950,7 @@ bool event_handler::handle_event_command(const queued_event& event_info,
|
|||
std::vector<unit>::iterator ui;
|
||||
for(ui = player->available_units.begin();
|
||||
ui != player->available_units.end(); ++ui) {
|
||||
if(game_events::unit_matches_filter(*ui, filter)) {
|
||||
if(game_events::unit_matches_filter(*ui, filter,gamemap::location())) {
|
||||
ui->assign_role(cfg["role"]);
|
||||
found=true;
|
||||
break;
|
||||
|
@ -960,7 +965,7 @@ bool event_handler::handle_event_command(const queued_event& event_info,
|
|||
//iterate over the units, and try to find one that matches
|
||||
for(ui = pi->second.available_units.begin();
|
||||
ui != pi->second.available_units.end(); ++ui) {
|
||||
if(game_events::unit_matches_filter(*ui, filter)) {
|
||||
if(game_events::unit_matches_filter(*ui, filter,gamemap::location())) {
|
||||
ui->assign_role(cfg["role"]);
|
||||
found=true;
|
||||
break;
|
||||
|
@ -985,7 +990,7 @@ bool event_handler::handle_event_command(const queued_event& event_info,
|
|||
}
|
||||
|
||||
else if(cmd == "unit_overlay") {
|
||||
for(std::map<gamemap::location,unit>::iterator itor = units->begin(); itor != units->end(); ++itor) {
|
||||
for(units_map::iterator itor = units->begin(); itor != units->end(); ++itor) {
|
||||
if(game_events::unit_matches_filter(itor,cfg)) {
|
||||
itor->second.add_overlay(cfg["image"]);
|
||||
break;
|
||||
|
@ -994,7 +999,7 @@ bool event_handler::handle_event_command(const queued_event& event_info,
|
|||
}
|
||||
|
||||
else if(cmd == "remove_unit_overlay") {
|
||||
for(std::map<gamemap::location,unit>::iterator itor = units->begin(); itor != units->end(); ++itor) {
|
||||
for(units_map::iterator itor = units->begin(); itor != units->end(); ++itor) {
|
||||
if(game_events::unit_matches_filter(itor,cfg)) {
|
||||
itor->second.remove_overlay(cfg["image"]);
|
||||
break;
|
||||
|
@ -1087,8 +1092,12 @@ bool event_handler::handle_event_command(const queued_event& event_info,
|
|||
|
||||
//if we should spawn a new unit on the map somewhere
|
||||
else if(cmd == "unit") {
|
||||
unit new_unit(*game_data_ptr, cfg.get_parsed_config());
|
||||
preferences::encountered_units().insert(new_unit.type().id());
|
||||
wassert(game_data_ptr != NULL);
|
||||
wassert(units != NULL);
|
||||
wassert(game_map != NULL);
|
||||
wassert(status_ptr != NULL);
|
||||
unit new_unit(game_data_ptr,units,game_map,status_ptr,teams,cfg.get_parsed_config());
|
||||
preferences::encountered_units().insert(new_unit.id());
|
||||
gamemap::location loc = cfg_to_loc(cfg);
|
||||
|
||||
if(game_map->on_board(loc)) {
|
||||
|
@ -1150,8 +1159,13 @@ bool event_handler::handle_event_command(const queued_event& event_info,
|
|||
|
||||
for(std::vector<unit>::iterator u = avail.begin(); u != avail.end(); ++u) {
|
||||
LOG_NG << "checking unit against filter...\n";
|
||||
if(game_events::unit_matches_filter(*u,cfg)) {
|
||||
if(game_events::unit_matches_filter(*u, cfg,gamemap::location())) {
|
||||
gamemap::location loc = cfg_to_loc(cfg);
|
||||
wassert(game_data_ptr != NULL);
|
||||
wassert(units != NULL);
|
||||
wassert(game_map != NULL);
|
||||
wassert(status_ptr != NULL);
|
||||
u->set_game_context(game_data_ptr,units,game_map,status_ptr,teams);
|
||||
recruit_unit(*game_map,index+1,*units,*u,loc,cfg["show"] == "no" ? NULL : screen,false,true);
|
||||
avail.erase(u);
|
||||
break;
|
||||
|
@ -1252,7 +1266,7 @@ bool event_handler::handle_event_command(const queued_event& event_info,
|
|||
|
||||
//displaying a message dialog
|
||||
else if(cmd == "message") {
|
||||
std::map<gamemap::location,unit>::iterator speaker = units->end();
|
||||
units_map::iterator speaker = units->end();
|
||||
if(cfg["speaker"] == "unit") {
|
||||
speaker = units->find(event_info.loc1);
|
||||
} else if(cfg["speaker"] == "second_unit") {
|
||||
|
@ -1291,20 +1305,13 @@ bool event_handler::handle_event_command(const queued_event& event_info,
|
|||
screen->scroll_to_tile(speaker->first.x,speaker->first.y-1);
|
||||
|
||||
if(image.empty()) {
|
||||
if(speaker->second.profile() == "") {
|
||||
image = speaker->second.type().image_profile();
|
||||
} else {
|
||||
image = speaker->second.profile();
|
||||
if(image == "unit_image") {
|
||||
image = speaker->second.type().image();
|
||||
}
|
||||
}
|
||||
image = speaker->second.profile();
|
||||
}
|
||||
|
||||
if(caption.empty()) {
|
||||
caption = speaker->second.description();
|
||||
if(caption.empty()) {
|
||||
caption = speaker->second.type().language_name();
|
||||
caption = speaker->second.language_name();
|
||||
}
|
||||
}
|
||||
LOG_DP << "done scrolling to speaker...\n";
|
||||
|
@ -1413,7 +1420,7 @@ bool event_handler::handle_event_command(const queued_event& event_info,
|
|||
pi!=players.end(); ++pi) {
|
||||
std::vector<unit>& avail_units = pi->second.available_units;
|
||||
for(std::vector<unit>::iterator j = avail_units.begin(); j != avail_units.end();) {
|
||||
if(game_events::unit_matches_filter(*j, cfg)) {
|
||||
if(game_events::unit_matches_filter(*j, cfg,gamemap::location())) {
|
||||
j = avail_units.erase(j);
|
||||
} else {
|
||||
++j;
|
||||
|
@ -1475,7 +1482,7 @@ bool event_handler::handle_event_command(const queued_event& event_info,
|
|||
pi!=players.end(); ++pi) {
|
||||
std::vector<unit>& avail_units = pi->second.available_units;
|
||||
for(std::vector<unit>::iterator j = avail_units.begin(); j != avail_units.end();) {
|
||||
if(game_events::unit_matches_filter(*j, filter) == false) {
|
||||
if(game_events::unit_matches_filter(*j, filter,gamemap::location())) {
|
||||
++j;
|
||||
continue;
|
||||
}
|
||||
|
@ -1506,7 +1513,11 @@ bool event_handler::handle_event_command(const queued_event& event_info,
|
|||
*state_of_game));
|
||||
|
||||
try {
|
||||
const unit u(*game_data_ptr,var);
|
||||
wassert(game_data_ptr != NULL);
|
||||
wassert(units != NULL);
|
||||
wassert(game_map != NULL);
|
||||
wassert(status_ptr != NULL);
|
||||
const unit u(game_data_ptr,units,game_map,status_ptr,teams,var);
|
||||
gamemap::location loc(var);
|
||||
if(loc.valid()) {
|
||||
if(cfg["find_vacant"] == "yes") {
|
||||
|
@ -1855,11 +1866,6 @@ bool matches_special_filter(const config* cfg, const vconfig filter)
|
|||
return false;
|
||||
}
|
||||
}
|
||||
if(filter["terrain"] != "") {
|
||||
if(filter["terrain"] != (*cfg)["terrain"]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const vconfig::child_list& nots = filter.get_children("not");
|
||||
for(vconfig::child_list::const_iterator i = nots.begin(); i != nots.end(); ++i) {
|
||||
|
@ -1870,13 +1876,13 @@ bool matches_special_filter(const config* cfg, const vconfig filter)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool unit_matches_filter(const unit& u, const vconfig filter)
|
||||
bool unit_matches_filter(const unit& u, const vconfig filter,const gamemap::location& loc)
|
||||
{
|
||||
const bool res = u.matches_filter(filter.get_parsed_config());
|
||||
const bool res = u.matches_filter(filter.get_parsed_config(),loc);
|
||||
if(res == true) {
|
||||
const vconfig::child_list& nots = filter.get_children("not");
|
||||
for(vconfig::child_list::const_iterator i = nots.begin(); i != nots.end(); ++i) {
|
||||
if(unit_matches_filter(u,*i)) {
|
||||
if(unit_matches_filter(u,*i,loc)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1887,7 +1893,7 @@ bool unit_matches_filter(const unit& u, const vconfig filter)
|
|||
|
||||
bool unit_matches_filter(unit_map::const_iterator itor, const vconfig filter)
|
||||
{
|
||||
const bool res = filter_loc(itor->first,filter) && itor->second.matches_filter(filter.get_parsed_config());
|
||||
const bool res = filter_loc(itor->first,filter) && itor->second.matches_filter(filter.get_parsed_config(),itor->first);
|
||||
if(res == true) {
|
||||
const vconfig::child_list& nots = filter.get_children("not");
|
||||
for(vconfig::child_list::const_iterator i = nots.begin(); i != nots.end(); ++i) {
|
||||
|
@ -1901,7 +1907,7 @@ bool unit_matches_filter(unit_map::const_iterator itor, const vconfig filter)
|
|||
}
|
||||
|
||||
manager::manager(const config& cfg, display& gui_, gamemap& map_,
|
||||
std::map<gamemap::location,unit>& units_,
|
||||
units_map& units_,
|
||||
std::vector<team>& teams_,
|
||||
game_state& state_of_game_, gamestatus& status,
|
||||
const game_data& game_data_) :
|
||||
|
|
|
@ -37,7 +37,7 @@ class display;
|
|||
//movement, keyboard events, etc. See events.hpp for how they are handled.
|
||||
namespace game_events
|
||||
{
|
||||
|
||||
typedef std::map<gamemap::location,unit> units_map;
|
||||
//the game event manager loads the scenario configuration object, and
|
||||
//ensures that events are handled according to the scenario configuration
|
||||
//for its lifetime.
|
||||
|
@ -48,7 +48,7 @@ struct manager {
|
|||
//note that references will be maintained, and must remain valid
|
||||
//for the life of the object.
|
||||
manager(const config& scenario_cfg, display& disp, gamemap& map,
|
||||
std::map<gamemap::location,unit>& units, std::vector<team>& teams,
|
||||
units_map& units, std::vector<team>& teams,
|
||||
game_state& state_of_game, gamestatus& status, const game_data& data);
|
||||
~manager();
|
||||
|
||||
|
@ -58,9 +58,8 @@ struct manager {
|
|||
void write_events(config& cfg);
|
||||
|
||||
bool matches_special_filter(const config* cfg, const vconfig filter);
|
||||
bool unit_matches_filter(const unit& u, const vconfig filter);
|
||||
bool unit_matches_filter(const unit& u, const vconfig filter,const gamemap::location& loc);
|
||||
bool unit_matches_filter(unit_map::const_iterator itor, const vconfig filter);
|
||||
bool unit_matches_filter(const unit& u, const vconfig filter);
|
||||
|
||||
//function to fire an event. Events may have up to two arguments, both of
|
||||
//which must be locations.
|
||||
|
@ -74,7 +73,7 @@ void raise(const std::string& event,
|
|||
const gamemap::location& loc2=gamemap::location::null_location,
|
||||
const config& data=config());
|
||||
|
||||
bool conditional_passed(const std::map<gamemap::location,unit>* units,
|
||||
bool conditional_passed(const units_map* units,
|
||||
const vconfig cond);
|
||||
bool pump();
|
||||
|
||||
|
|
|
@ -681,7 +681,7 @@ void extract_summary_data_from_save(const game_state& state, config& out)
|
|||
p!=state.players.end(); ++p) {
|
||||
for(std::vector<unit>::const_iterator u = p->second.available_units.begin(); u != p->second.available_units.end(); ++u) {
|
||||
if(u->can_recruit()) {
|
||||
leader = u->type().id();
|
||||
leader = u->id();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -704,7 +704,7 @@ void extract_summary_data_from_save(const game_state& state, config& out)
|
|||
const config::child_list& units = (**s).get_children("unit");
|
||||
for(config::child_list::const_iterator u = units.begin(); u != units.end(); ++u) {
|
||||
if((**u)["canrecruit"] == "1") {
|
||||
leader = (**u)["type"];
|
||||
leader = (**u)["id"];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
96
src/help.cpp
96
src/help.cpp
|
@ -963,6 +963,7 @@ topic_text::operator std::vector< std::string > const &() const
|
|||
|
||||
std::vector<topic> generate_weapon_special_topics()
|
||||
{
|
||||
|
||||
std::vector<topic> topics;
|
||||
if (game_info == NULL) {
|
||||
return topics;
|
||||
|
@ -977,25 +978,32 @@ std::vector<topic> generate_weapon_special_topics()
|
|||
std::vector<attack_type> attacks = type.attacks();
|
||||
for (std::vector<attack_type>::const_iterator it = attacks.begin();
|
||||
it != attacks.end(); it++) {
|
||||
std::string special = (*it).special();
|
||||
|
||||
//some abilities like plague can be in the form ability(argument)
|
||||
//make sure we cut off the argument
|
||||
special.erase(std::find(special.begin(),special.end(),'('),special.end());
|
||||
if (special != "") {
|
||||
if (checked_specials.find(special) == checked_specials.end()) {
|
||||
std::string lang_special = gettext(special.c_str());
|
||||
lang_special = utils::capitalize(lang_special);
|
||||
std::string description
|
||||
= string_table["weapon_special_" + special + "_description"];
|
||||
const size_t colon_pos = description.find(':');
|
||||
if (colon_pos != std::string::npos) {
|
||||
// Remove the first colon and the following newline.
|
||||
description.erase(0, colon_pos + 2);
|
||||
std::vector<std::string> specials = (*it).special_tooltips(true);
|
||||
std::vector<std::string>::iterator sp_it;
|
||||
for (sp_it = specials.begin(); sp_it != specials.end(); ++sp_it)
|
||||
{
|
||||
std::string special = *sp_it;
|
||||
++sp_it;
|
||||
|
||||
//some abilities like plague can be in the form ability(argument)
|
||||
//make sure we cut off the argument
|
||||
special.erase(std::find(special.begin(),special.end(),'('),special.end());
|
||||
if (special != "") {
|
||||
if (checked_specials.find(special) == checked_specials.end()) {
|
||||
std::string lang_special = gettext(special.c_str());
|
||||
lang_special = utils::capitalize(lang_special);
|
||||
std::string description;
|
||||
description = *sp_it;
|
||||
const size_t colon_pos = description.find(':');
|
||||
if (colon_pos != std::string::npos) {
|
||||
// Remove the first colon and the following newline.
|
||||
description.erase(0, colon_pos + 2);
|
||||
}
|
||||
topic t(lang_special, "weaponspecial_" + special, description);
|
||||
topics.push_back(t);
|
||||
checked_specials.insert(special);
|
||||
}
|
||||
topic t(lang_special, "weaponspecial_" + special, description);
|
||||
topics.push_back(t);
|
||||
checked_specials.insert(special);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1016,15 +1024,24 @@ std::vector<topic> generate_ability_topics()
|
|||
// for display. We do not want to show abilities that the user has
|
||||
// not encountered yet.
|
||||
for(game_data::unit_type_map::const_iterator i = game_info->unit_types.begin();
|
||||
i != game_info->unit_types.end(); i++) {
|
||||
i != game_info->unit_types.end(); ++i) {
|
||||
const unit_type &type = (*i).second;
|
||||
if (description_type(type) == FULL_DESCRIPTION) {
|
||||
for (std::vector<std::string>::const_iterator it = type.ability_tooltips().begin();
|
||||
it != type.ability_tooltips().end(); it++) {
|
||||
std::vector<std::string> descriptions = type.ability_tooltips();
|
||||
std::vector<std::string>::const_iterator desc_it = descriptions.begin();
|
||||
for (std::vector<std::string>::const_iterator it = type.abilities().begin();
|
||||
it != type.abilities().end(); ++it) {
|
||||
if (checked_abilities.find(*it) == checked_abilities.end()) {
|
||||
const std::string id = "ability_" + *it;
|
||||
std::string lang_ability = utils::capitalize(string_table[id]);
|
||||
std::string description = string_table[*it + "_description"];
|
||||
std::string lang_ability = utils::capitalize(gettext(it->c_str()));
|
||||
std::string description;
|
||||
if(desc_it != descriptions.end())
|
||||
{
|
||||
description = *desc_it;
|
||||
++desc_it;
|
||||
} else {
|
||||
description = string_table[*it + "_description"];
|
||||
}
|
||||
const size_t colon_pos = description.find(':');
|
||||
if (colon_pos != std::string::npos) {
|
||||
// Remove the first colon and the following newline.
|
||||
|
@ -1103,13 +1120,13 @@ public:
|
|||
|
||||
// Print the abilities the units has, cross-reference them
|
||||
// to their respective topics.
|
||||
if (!type_.ability_tooltips().empty()) {
|
||||
if (!type_.abilities().empty()) {
|
||||
ss << _("Abilities: ");
|
||||
for(std::vector<std::string>::const_iterator ability_it = type_.ability_tooltips().begin(),
|
||||
ability_end = type_.ability_tooltips().end();
|
||||
for(std::vector<std::string>::const_iterator ability_it = type_.abilities().begin(),
|
||||
ability_end = type_.abilities().end();
|
||||
ability_it != ability_end; ++ability_it) {
|
||||
const std::string ref_id = std::string("ability_") + *ability_it;
|
||||
std::string lang_ability = string_table[ref_id];
|
||||
std::string lang_ability = gettext(ability_it->c_str());
|
||||
ss << "<ref>dst='" << escape(ref_id) << "' text='" << escape(lang_ability)
|
||||
<< "'</ref>";
|
||||
if (ability_it + 1 != ability_end)
|
||||
|
@ -1173,15 +1190,26 @@ public:
|
|||
// Show this attack's special, if it has any. Cross
|
||||
// reference it to the section describing the
|
||||
// special.
|
||||
if (!attack_it->special().empty()) {
|
||||
const std::string ref_id = std::string("weaponspecial_")
|
||||
+ (*attack_it).special();
|
||||
std::string lang_special = gettext(attack_it->special().c_str());
|
||||
attack_ss << "<ref>dst='" << escape(ref_id)
|
||||
<< "' text='" << escape(lang_special) << "'</ref>";
|
||||
std::vector<std::string> specials = attack_it->special_tooltips(true);
|
||||
if(!specials.empty())
|
||||
{
|
||||
std::string lang_special = "";
|
||||
std::vector<std::string>::iterator sp_it;
|
||||
for (sp_it = specials.begin(); sp_it < specials.end(); sp_it++) {
|
||||
const std::string ref_id = std::string("weaponspecial_")
|
||||
+ (*sp_it);
|
||||
lang_special = gettext(sp_it->c_str());
|
||||
attack_ss << "<ref>dst='" << escape(ref_id)
|
||||
<< "' text='" << escape(lang_special) << "'</ref>";
|
||||
if((sp_it + 1) != specials.end() && (sp_it + 2) != specials.end())
|
||||
{
|
||||
attack_ss << ", "; //comma placed before next special
|
||||
}
|
||||
sp_it++; //skip description
|
||||
}
|
||||
row.push_back(std::make_pair(attack_ss.str(),
|
||||
font::line_width(lang_special,
|
||||
normal_font_size)));
|
||||
font::line_width(lang_special, normal_font_size)));
|
||||
|
||||
}
|
||||
table.push_back(row);
|
||||
}
|
||||
|
|
68
src/map.cpp
68
src/map.cpp
|
@ -14,12 +14,14 @@
|
|||
#include "global.hpp"
|
||||
|
||||
#include "config.hpp"
|
||||
#include "gamestatus.hpp"
|
||||
#include "log.hpp"
|
||||
#include "map.hpp"
|
||||
#include "pathutils.hpp"
|
||||
#include "util.hpp"
|
||||
#include "wassert.hpp"
|
||||
#include "serialization/string_utils.hpp"
|
||||
#include "actions.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
@ -526,6 +528,72 @@ const terrain_type& gamemap::get_terrain_info(const gamemap::location &loc) cons
|
|||
{
|
||||
return get_terrain_info(get_terrain(loc));
|
||||
}
|
||||
bool gamemap::terrain_matches_filter(const gamemap::location& loc, const config& cfg, const gamestatus& game_status, const unit_map& units,bool flat_tod) const
|
||||
{
|
||||
const std::string& terrain = cfg["terrain"];
|
||||
const std::string& tod_type = cfg["time_of_day"];
|
||||
const std::string& tod_id = cfg["time_of_day_id"];
|
||||
// Any of these may be a CSV
|
||||
std::string terrain_letter;
|
||||
terrain_letter += get_terrain_info(loc).letter();
|
||||
if(!terrain.empty()) {
|
||||
if(terrain != terrain_letter) {
|
||||
if(std::find(terrain.begin(),terrain.end(),',') != terrain.end() &&
|
||||
std::search(terrain.begin(),terrain.end(),
|
||||
terrain_letter.begin(),terrain_letter.end()) != terrain.end()) {
|
||||
const std::vector<std::string>& vals = utils::split(terrain);
|
||||
if(std::find(vals.begin(),vals.end(),terrain_letter) == vals.end()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static config const dummy_cfg;
|
||||
time_of_day tod(dummy_cfg);
|
||||
if(!tod_type.empty() || !tod_id.empty()) {
|
||||
if(flat_tod) {
|
||||
tod = game_status.get_time_of_day(0,loc);
|
||||
} else {
|
||||
tod = timeofday_at(game_status,units,loc,*this);
|
||||
}
|
||||
}
|
||||
if(!tod_type.empty()) {
|
||||
const std::vector<std::string>& vals = utils::split(terrain);
|
||||
if(tod.lawful_bonus<0) {
|
||||
if(std::find(vals.begin(),vals.end(),"chaotic") == vals.end()) {
|
||||
return false;
|
||||
}
|
||||
} else if(tod.lawful_bonus>0) {
|
||||
if(std::find(vals.begin(),vals.end(),"lawful") == vals.end()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if(std::find(vals.begin(),vals.end(),"neutral") == vals.end()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!tod_id.empty()) {
|
||||
if(tod_id != tod.id) {
|
||||
if(std::find(tod_id.begin(),tod_id.end(),',') != tod_id.end() &&
|
||||
std::search(tod_id.begin(),tod_id.end(),
|
||||
tod.id.begin(),tod.id.end()) != tod_id.end()) {
|
||||
const std::vector<std::string>& vals = utils::split(tod_id);
|
||||
if(std::find(vals.begin(),vals.end(),tod.id) == vals.end()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const std::vector<gamemap::TERRAIN>& gamemap::get_terrain_list() const
|
||||
{
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#define MAP_H_INCLUDED
|
||||
|
||||
class config;
|
||||
class gamestatus;
|
||||
class unit;
|
||||
|
||||
#include "terrain.hpp"
|
||||
|
||||
|
@ -98,6 +100,7 @@ public:
|
|||
|
||||
static location null_location;
|
||||
};
|
||||
typedef std::map<location,unit> unit_map;
|
||||
|
||||
const std::string& underlying_mvt_terrain(const location& loc) const
|
||||
{ return underlying_mvt_terrain(get_terrain(loc)); }
|
||||
|
@ -172,6 +175,8 @@ public:
|
|||
|
||||
//shortcut to get_terrain_info(get_terrain(loc))
|
||||
const terrain_type& get_terrain_info(const location &loc) const;
|
||||
//
|
||||
bool terrain_matches_filter(const location& loc, const config& cfg, const gamestatus& game_status, const unit_map& units,bool flat_tod=false) const;
|
||||
|
||||
//gets the list of terrains
|
||||
const std::vector<TERRAIN>& get_terrain_list() const;
|
||||
|
|
|
@ -329,7 +329,7 @@ struct road_path_calculator : cost_calculator
|
|||
|
||||
//find out how windy roads should be.
|
||||
windiness_(maximum<int>(1,atoi(cfg["road_windiness"].c_str()))) {}
|
||||
virtual double cost(const location& loc, const double so_far, const bool isDst) const;
|
||||
virtual double cost(const location& src, const location& loc, const double so_far, const bool isDst) const;
|
||||
|
||||
void terrain_changed(const location& loc) { loc_cache_.erase(loc); }
|
||||
mutable int calls;
|
||||
|
@ -341,7 +341,7 @@ private:
|
|||
mutable std::map<char,double> cache_;
|
||||
};
|
||||
|
||||
double road_path_calculator::cost(const location& loc, const double /*so_far*/, const bool /*isDst*/) const
|
||||
double road_path_calculator::cost(const location& src, const location& loc, const double /*so_far*/, const bool /*isDst*/) const
|
||||
{
|
||||
++calls;
|
||||
if (loc.x < 0 || loc.y < 0 || loc.x >= (long)map_.size() || loc.y >= (long)map_.front().size())
|
||||
|
@ -911,7 +911,7 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
continue;
|
||||
}
|
||||
|
||||
if (calc.cost(src, 0.0, false) >= 1000.0 || calc.cost(dst, 0.0, true) >= 1000.0) {
|
||||
if (calc.cost(src,src, 0.0, false) >= 1000.0 || calc.cost(src,dst, 0.0, true) >= 1000.0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -168,7 +168,7 @@ namespace events{
|
|||
continue;
|
||||
|
||||
std::stringstream row;
|
||||
row << i->second.type().language_name() << COLUMN_SEPARATOR
|
||||
row << i->second.language_name() << COLUMN_SEPARATOR
|
||||
<< i->second.description() << COLUMN_SEPARATOR
|
||||
<< i->second.hitpoints() << "/" << i->second.max_hitpoints() << COLUMN_SEPARATOR
|
||||
<< i->second.experience() << "/";
|
||||
|
@ -255,7 +255,7 @@ namespace events{
|
|||
//output the number of the side first, and this will
|
||||
//cause it to be displayed in the correct colour
|
||||
if(leader != units.end()) {
|
||||
str << IMAGE_PREFIX << leader->second.type().image() << COLUMN_SEPARATOR
|
||||
str << IMAGE_PREFIX << leader->second.absolute_image() << COLUMN_SEPARATOR
|
||||
<< "\033[3" << lexical_cast<char, size_t>(n+1) << 'm' << leader->second.description() << COLUMN_SEPARATOR;
|
||||
} else {
|
||||
str << ' ' << COLUMN_SEPARATOR << "\033[3" << lexical_cast<char, size_t>(n+1) << "m-" << COLUMN_SEPARATOR;
|
||||
|
@ -347,7 +347,7 @@ namespace events{
|
|||
buf << side_num;
|
||||
side["side"] = buf.str();
|
||||
|
||||
for(std::map<gamemap::location,unit>::const_iterator i = units.begin(); i != units.end(); ++i) {
|
||||
for(units_map::const_iterator i = units.begin(); i != units.end(); ++i) {
|
||||
if(i->second.side() == side_num) {
|
||||
config& u = side.add_child("unit");
|
||||
i->first.write(u);
|
||||
|
|
|
@ -89,7 +89,7 @@ void mouse_handler::mouse_motion(int x, int y)
|
|||
attack_from.valid())) {
|
||||
if(mouseover_unit == units_.end()) {
|
||||
cursor::set(cursor::MOVE);
|
||||
} else if(current_team().is_enemy(mouseover_unit->second.side()) && !mouseover_unit->second.stone()) {
|
||||
} else if(current_team().is_enemy(mouseover_unit->second.side()) && mouseover_unit->second.get_state("stoned")!="yes") {
|
||||
cursor::set(cursor::ATTACK);
|
||||
} else {
|
||||
cursor::set(cursor::NORMAL);
|
||||
|
@ -114,9 +114,9 @@ void mouse_handler::mouse_motion(int x, int y)
|
|||
|
||||
unit_map::const_iterator un = find_unit(selected_hex_);
|
||||
|
||||
if((new_hex != last_hex_ || attack_from.valid()) && un != units_.end() && !un->second.stone()) {
|
||||
if((new_hex != last_hex_ || attack_from.valid()) && un != units_.end() && un->second.get_state("stoned")!="yes") {
|
||||
const shortest_path_calculator calc(un->second,current_team(), visible_units(),teams_,map_,status_);
|
||||
const bool can_teleport = un->second.type().teleports();
|
||||
const bool can_teleport = un->second.get_ability_bool("teleport",un->first);
|
||||
|
||||
const std::set<gamemap::location>* teleports = NULL;
|
||||
|
||||
|
@ -146,8 +146,8 @@ void mouse_handler::mouse_motion(int x, int y)
|
|||
unit un2 = un->second;
|
||||
unit_movement_resetter move_reset(un2);
|
||||
|
||||
const bool ignore_zocs = un->second.type().is_skirmisher();
|
||||
const bool teleport = un->second.type().teleports();
|
||||
const bool ignore_zocs = un->second.get_ability_bool("skirmisher",un->first);
|
||||
const bool teleport = un->second.get_ability_bool("teleport",un->first);
|
||||
current_paths_ = paths(map_,status_,gameinfo_,units_,new_hex,teams_,
|
||||
ignore_zocs,teleport,viewing_team(),path_turns_);
|
||||
gui_->highlight_reach(current_paths_);
|
||||
|
@ -364,8 +364,8 @@ void mouse_handler::left_click(const SDL_MouseButtonEvent& event)
|
|||
unit_map::const_iterator it = find_unit(hex);
|
||||
|
||||
if(it != units_.end() && it->second.side() == team_num_ && !gui_->fogged(it->first.x,it->first.y)) {
|
||||
const bool ignore_zocs = it->second.type().is_skirmisher();
|
||||
const bool teleport = it->second.type().teleports();
|
||||
const bool ignore_zocs = it->second.get_ability_bool("skirmisher",it->first);
|
||||
const bool teleport = it->second.get_ability_bool("teleport",it->first);
|
||||
current_paths_ = paths(map_,status_,gameinfo_,units_,hex,teams_,
|
||||
ignore_zocs,teleport,viewing_team(),path_turns_);
|
||||
|
||||
|
@ -384,7 +384,7 @@ void mouse_handler::left_click(const SDL_MouseButtonEvent& event)
|
|||
const std::set<gamemap::location>* teleports = NULL;
|
||||
|
||||
std::set<gamemap::location> allowed_teleports;
|
||||
if(u.type().teleports()) {
|
||||
if(u.get_ability_bool("teleport",it->first)) {
|
||||
allowed_teleports = vacant_villages(current_team().villages(),units_);
|
||||
teleports = &allowed_teleports;
|
||||
if(current_team().villages().count(it->first))
|
||||
|
@ -404,12 +404,12 @@ void mouse_handler::show_attack_options(unit_map::const_iterator u)
|
|||
{
|
||||
team& current_team = teams_[team_num_-1];
|
||||
|
||||
if(u == units_.end() || u->second.can_attack() == false)
|
||||
if(u == units_.end() || u->second.attacks_left() == 0)
|
||||
return;
|
||||
|
||||
for(unit_map::const_iterator target = units_.begin(); target != units_.end(); ++target) {
|
||||
if(current_team.is_enemy(target->second.side()) &&
|
||||
distance_between(target->first,u->first) == 1 && !target->second.stone()) {
|
||||
distance_between(target->first,u->first) == 1 && target->second.get_state("stoned")!="yes") {
|
||||
current_paths_.routes[target->first] = paths::route();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ static void a_star_explore_neighbours(gamemap::location const &dst, const double
|
|||
if (locLocation.valid(int(parWidth), int(parHeight)) == false)
|
||||
continue;
|
||||
locNextNode = aStarGameWorld.getNodeFromLocation(locLocation, locIsCreated);
|
||||
locCost = locCostFather + costCalculator->cost(locLocation, locCostFather, locLocation == dst);
|
||||
locCost = locCostFather + costCalculator->cost(parCurNode->loc,locLocation, locCostFather, locLocation == dst);
|
||||
if (locIsCreated) {
|
||||
locNextNode->initNode(locLocation, dst, locCost, parCurNode, teleports);
|
||||
if (locNextNode->g + locNextNode->h < stop_at) {
|
||||
|
@ -162,7 +162,7 @@ paths::route a_star_search(gamemap::location const &src, gamemap::location const
|
|||
|
||||
LOG_PF << "A* search: " << src << " -> " << dst << '\n';
|
||||
|
||||
if (costCalculator->cost(dst, 0, true) >= stop_at) {
|
||||
if (costCalculator->cost(src,dst, 0, true) >= stop_at) {
|
||||
LOG_PF << "aborted A* search because Start or Dest is invalid\n";
|
||||
locRoute.move_left = int(costCalculator->getNoPathValue());
|
||||
return locRoute;
|
||||
|
@ -218,7 +218,7 @@ label_AStarSearch_end:
|
|||
|
||||
namespace {
|
||||
gamemap::location find_vacant(const gamemap& map,
|
||||
const std::map<gamemap::location,unit>& units,
|
||||
const units_map& units,
|
||||
const gamemap::location& loc, int depth,
|
||||
VACANT_TILE_TYPE vacancy,
|
||||
std::set<gamemap::location>& touched)
|
||||
|
@ -254,7 +254,7 @@ namespace {
|
|||
}
|
||||
|
||||
gamemap::location find_vacant_tile(const gamemap& map,
|
||||
const std::map<gamemap::location,unit>& units,
|
||||
const units_map& units,
|
||||
const gamemap::location& loc,
|
||||
VACANT_TILE_TYPE vacancy)
|
||||
{
|
||||
|
@ -335,7 +335,7 @@ bool enemy_zoc(gamemap const &map, gamestatus const &status,
|
|||
const team ¤t_team = teams[side-1];
|
||||
get_adjacent_tiles(loc,locs);
|
||||
for(int i = 0; i != 6; ++i) {
|
||||
const std::map<gamemap::location,unit>::const_iterator it
|
||||
const units_map::const_iterator it
|
||||
= find_visible_unit(units,locs[i],
|
||||
map,
|
||||
status.get_time_of_day().lawful_bonus,
|
||||
|
@ -353,7 +353,7 @@ namespace {
|
|||
|
||||
void find_routes(const gamemap& map, const gamestatus& status,
|
||||
const game_data& gamedata,
|
||||
const std::map<gamemap::location,unit>& units,
|
||||
const units_map& units,
|
||||
const unit& u,
|
||||
const gamemap::location& loc,
|
||||
int move_left,
|
||||
|
@ -402,7 +402,7 @@ namespace {
|
|||
continue;
|
||||
|
||||
//see if the tile is on top of an enemy unit
|
||||
const std::map<gamemap::location,unit>::const_iterator unit_it =
|
||||
const units_map::const_iterator unit_it =
|
||||
find_visible_unit(units, locs[i], map,
|
||||
status.get_time_of_day().lawful_bonus,
|
||||
teams, viewing_team);
|
||||
|
@ -415,7 +415,7 @@ namespace {
|
|||
const gamemap::TERRAIN terrain = map[currentloc.x][currentloc.y];
|
||||
|
||||
//find the movement cost of this type onto the terrain
|
||||
const int move_cost = u.movement_cost(map,terrain);
|
||||
const int move_cost = u.movement_cost(terrain);
|
||||
if (move_cost <= move_left ||
|
||||
turns_left > 0 && move_cost <= u.total_movement()) {
|
||||
int new_move_left = move_left - move_cost;
|
||||
|
@ -462,7 +462,7 @@ paths::paths(gamemap const &map, gamestatus const &status,
|
|||
bool ignore_zocs, bool allow_teleport, const team &viewing_team,
|
||||
int additional_turns)
|
||||
{
|
||||
const std::map<gamemap::location,unit>::const_iterator i = units.find(loc);
|
||||
const units_map::const_iterator i = units.find(loc);
|
||||
if(i == units.end()) {
|
||||
std::cerr << "unit not found\n";
|
||||
return;
|
||||
|
@ -483,7 +483,7 @@ int route_turns_to_complete(unit const &u, gamemap const &map, paths::route cons
|
|||
for(std::vector<gamemap::location>::const_iterator i = rt.steps.begin()+1;
|
||||
i != rt.steps.end(); ++i) {
|
||||
wassert(map.on_board(*i));
|
||||
const int move_cost = u.movement_cost(map, map[i->x][i->y]);
|
||||
const int move_cost = u.movement_cost(map[i->x][i->y]);
|
||||
movement -= move_cost;
|
||||
if (movement < 0) {
|
||||
++turns;
|
||||
|
@ -503,13 +503,12 @@ shortest_path_calculator::shortest_path_calculator(unit const &u, team const &t,
|
|||
gamestatus const &status)
|
||||
: unit_(u), team_(t), units_(units), teams_(teams), map_(map),
|
||||
lawful_bonus_(status.get_time_of_day().lawful_bonus),
|
||||
unit_is_skirmisher_(unit_.type().is_skirmisher()),
|
||||
movement_left_(unit_.movement_left()),
|
||||
total_movement_(unit_.total_movement())
|
||||
{
|
||||
}
|
||||
|
||||
double shortest_path_calculator::cost(const gamemap::location& loc, const double so_far, const bool isDst) const
|
||||
double shortest_path_calculator::cost(const gamemap::location& src,const gamemap::location& loc, const double so_far, const bool isDst) const
|
||||
{
|
||||
wassert(map_.on_board(loc));
|
||||
|
||||
|
@ -523,7 +522,7 @@ double shortest_path_calculator::cost(const gamemap::location& loc, const double
|
|||
if (team_.shrouded(loc.x, loc.y))
|
||||
return getNoPathValue();
|
||||
|
||||
int const base_cost = unit_.movement_cost(map_, map_[loc.x][loc.y]);
|
||||
int const base_cost = unit_.movement_cost(map_[loc.x][loc.y]);
|
||||
wassert(base_cost >= 1); // pathfinding heuristic: the cost must be at least 1
|
||||
if (total_movement_ < base_cost)
|
||||
return getNoPathValue();
|
||||
|
@ -535,7 +534,7 @@ double shortest_path_calculator::cost(const gamemap::location& loc, const double
|
|||
if (enemy_unit != units_end && team_.is_enemy(enemy_unit->second.side()))
|
||||
return getNoPathValue();
|
||||
|
||||
if (!isDst && !unit_is_skirmisher_) {
|
||||
if (!isDst && !unit_.get_ability_bool("skirmisher",src)) {
|
||||
gamemap::location adj[6];
|
||||
get_adjacent_tiles(loc, adj);
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ class gamestatus;
|
|||
|
||||
//a convenient type for storing a list of tiles adjacent to a certain tile
|
||||
typedef util::array<gamemap::location,6> adjacent_tiles_array;
|
||||
typedef std::map<gamemap::location,unit> units_map;
|
||||
|
||||
//function which, given a location, will find all tiles within 'radius' of that tile
|
||||
void get_tiles_radius(const gamemap::location& a, size_t radius, std::set<gamemap::location>& res);
|
||||
|
@ -46,7 +47,7 @@ enum VACANT_TILE_TYPE { VACANT_CASTLE, VACANT_ANY };
|
|||
//
|
||||
//if no valid location can be found, it will return a null location.
|
||||
gamemap::location find_vacant_tile(const gamemap& map,
|
||||
const std::map<gamemap::location,unit>& un,
|
||||
const units_map& un,
|
||||
const gamemap::location& loc,
|
||||
VACANT_TILE_TYPE vacancy=VACANT_ANY);
|
||||
|
||||
|
@ -58,7 +59,7 @@ bool enemy_zoc(gamemap const &map, gamestatus const &status,
|
|||
|
||||
struct cost_calculator
|
||||
{
|
||||
virtual double cost(const gamemap::location& loc, const double so_far, const bool isDst) const = 0;
|
||||
virtual double cost(const gamemap::location& src, const gamemap::location& loc, const double so_far, const bool isDst) const = 0;
|
||||
virtual ~cost_calculator() {}
|
||||
inline double getNoPathValue(void) const { return (42424242.0); }
|
||||
};
|
||||
|
@ -110,7 +111,7 @@ struct shortest_path_calculator : cost_calculator
|
|||
shortest_path_calculator(const unit& u, const team& t,
|
||||
const unit_map& units, const std::vector<team>& teams,
|
||||
const gamemap& map, const gamestatus& status);
|
||||
virtual double cost(const gamemap::location& loc, const double so_far, const bool isDst) const;
|
||||
virtual double cost(const gamemap::location& src, const gamemap::location& loc, const double so_far, const bool isDst) const;
|
||||
|
||||
private:
|
||||
unit const &unit_;
|
||||
|
@ -119,7 +120,6 @@ private:
|
|||
std::vector<team> const &teams_;
|
||||
gamemap const &map_;
|
||||
int const lawful_bonus_;
|
||||
bool const unit_is_skirmisher_;
|
||||
int const movement_left_;
|
||||
int const total_movement_;
|
||||
};
|
||||
|
|
|
@ -209,7 +209,7 @@ LEVEL_RESULT play_level(const game_data& gameinfo, const config& game_config,
|
|||
if (first_human_team == -1){
|
||||
first_human_team = get_first_human_team(ui, unit_cfg);
|
||||
}
|
||||
get_player_info(**ui, state_of_game, save_id, teams, lvl, gameinfo, map, units);
|
||||
get_player_info(**ui, state_of_game, save_id, teams, lvl, gameinfo, map, units, status);
|
||||
}
|
||||
|
||||
preferences::encounter_recruitable_units(teams);
|
||||
|
@ -416,7 +416,7 @@ LEVEL_RESULT play_level(const game_data& gameinfo, const config& game_config,
|
|||
if(turn_refresh) {
|
||||
for(unit_map::iterator i = units.begin(); i != units.end(); ++i) {
|
||||
if(i->second.side() == player_number) {
|
||||
i->second.new_turn();
|
||||
i->second.new_turn(i->first);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -647,11 +647,11 @@ redo_turn:
|
|||
state_of_game.scenario != "null";
|
||||
|
||||
//add all the units that survived the scenario
|
||||
for(std::map<gamemap::location,unit>::iterator un = units.begin(); un != units.end(); ++un) {
|
||||
for(units_map::iterator un = units.begin(); un != units.end(); ++un) {
|
||||
player_info *player=state_of_game.get_player(teams[un->second.side()-1].save_id());
|
||||
|
||||
if(player) {
|
||||
un->second.new_turn();
|
||||
un->second.new_turn(un->first);
|
||||
un->second.new_level();
|
||||
player->available_units.push_back(un->second);
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ void play_turn(const game_data& gameinfo, game_state& state_of_game,
|
|||
const gamestatus& status, const config& terrain_config,
|
||||
const config& level, CKey& key, display& gui, gamemap& map,
|
||||
std::vector<team>& teams, unsigned int team_num,
|
||||
std::map<gamemap::location,unit>& units,
|
||||
units_map& units,
|
||||
turn_info::floating_textbox& textbox,
|
||||
replay_network_sender& network_sender,
|
||||
bool skip_replay)
|
||||
|
@ -317,8 +317,8 @@ void turn_info::handle_event(const SDL_Event& event)
|
|||
const unit_map::iterator u = selected_unit();
|
||||
|
||||
if(u != units_.end() && u->second.side() == team_num_) {
|
||||
const bool ignore_zocs = u->second.type().is_skirmisher();
|
||||
const bool teleport = u->second.type().teleports();
|
||||
const bool ignore_zocs = u->second.get_ability_bool("skirmisher",u->first);
|
||||
const bool teleport = u->second.get_ability_bool("teleport",u->first);
|
||||
current_paths_ = paths(map_,status_,gameinfo_,units_,u->first,
|
||||
teams_,ignore_zocs,teleport,
|
||||
viewing_team(),path_turns_);
|
||||
|
@ -405,7 +405,7 @@ void turn_info::mouse_motion(int x, int y)
|
|||
attack_from.valid())) {
|
||||
if(mouseover_unit == units_.end()) {
|
||||
cursor::set(cursor::MOVE);
|
||||
} else if(viewing_team().is_enemy(mouseover_unit->second.side()) && !mouseover_unit->second.stone()) {
|
||||
} else if(viewing_team().is_enemy(mouseover_unit->second.side()) && mouseover_unit->second.get_state("stoned")!="yes") {
|
||||
cursor::set(cursor::ATTACK);
|
||||
} else {
|
||||
cursor::set(cursor::NORMAL);
|
||||
|
@ -430,10 +430,10 @@ void turn_info::mouse_motion(int x, int y)
|
|||
|
||||
unit_map::const_iterator un = find_unit(selected_hex_);
|
||||
|
||||
if((new_hex != last_hex_ || attack_from.valid()) && un != units_.end() && !un->second.stone()) {
|
||||
if((new_hex != last_hex_ || attack_from.valid()) && un != units_.end() && un->second.get_state("stoned")!="yes") {
|
||||
const shortest_path_calculator calc(un->second,viewing_team(),
|
||||
visible_units(),teams_,map_,status_);
|
||||
const bool can_teleport = un->second.type().teleports();
|
||||
const bool can_teleport = un->second.get_ability_bool("teleport",un->first);
|
||||
|
||||
const std::set<gamemap::location>* teleports = NULL;
|
||||
|
||||
|
@ -461,8 +461,8 @@ void turn_info::mouse_motion(int x, int y)
|
|||
current_paths_.routes.empty() && !gui_.fogged(un->first.x,un->first.y)) {
|
||||
unit_movement_resetter move_reset(un->second);
|
||||
|
||||
const bool ignore_zocs = un->second.type().is_skirmisher();
|
||||
const bool teleport = un->second.type().teleports();
|
||||
const bool ignore_zocs = un->second.get_ability_bool("skirmisher",un->first);
|
||||
const bool teleport = un->second.get_ability_bool("teleport",un->first);
|
||||
current_paths_ = paths(map_,status_,gameinfo_,units_,new_hex,teams_,
|
||||
ignore_zocs,teleport,viewing_team(),path_turns_);
|
||||
gui_.highlight_reach(current_paths_);
|
||||
|
@ -698,7 +698,7 @@ bool turn_info::attack_enemy(unit_map::iterator attacker, unit_map::iterator def
|
|||
weapons.push_back(a);
|
||||
battle_stats_strings sts;
|
||||
battle_stats st = evaluate_battle_stats(map_, teams_, attacker_loc, defender_loc,
|
||||
a, units_, status_, 0, &sts);
|
||||
a, units_, status_, gameinfo_, 0, &sts);
|
||||
stats.push_back(sts);
|
||||
|
||||
simple_attack_rating weapon_rating(st);
|
||||
|
@ -916,7 +916,7 @@ void turn_info::left_click(const SDL_MouseButtonEvent& event)
|
|||
u = find_unit(attack_from);
|
||||
// enemy = find_unit(hex);
|
||||
if(u != units_.end() && u->second.side() == team_num_ &&
|
||||
enemy != units_.end() && current_team().is_enemy(enemy->second.side()) && !enemy->second.stone()) {
|
||||
enemy != units_.end() && current_team().is_enemy(enemy->second.side()) && enemy->second.get_state("stoned")!="yes") {
|
||||
if(attack_enemy(u,enemy) == false) {
|
||||
undo();
|
||||
selected_hex_ = src;
|
||||
|
@ -965,8 +965,8 @@ void turn_info::left_click(const SDL_MouseButtonEvent& event)
|
|||
const unit_map::iterator it = find_unit(hex);
|
||||
|
||||
if(it != units_.end() && it->second.side() == team_num_ && !gui_.fogged(it->first.x,it->first.y)) {
|
||||
const bool ignore_zocs = it->second.type().is_skirmisher();
|
||||
const bool teleport = it->second.type().teleports();
|
||||
const bool ignore_zocs = it->second.get_ability_bool("skirmisher",it->first);
|
||||
const bool teleport = it->second.get_ability_bool("teleport",it->first);
|
||||
current_paths_ = paths(map_,status_,gameinfo_,units_,hex,teams_,
|
||||
ignore_zocs,teleport,viewing_team(),path_turns_);
|
||||
|
||||
|
@ -985,7 +985,7 @@ void turn_info::left_click(const SDL_MouseButtonEvent& event)
|
|||
const std::set<gamemap::location>* teleports = NULL;
|
||||
|
||||
std::set<gamemap::location> allowed_teleports;
|
||||
if(u.type().teleports()) {
|
||||
if(u.get_ability_bool("teleport",it->first)) {
|
||||
allowed_teleports = vacant_villages(current_team().villages(),units_);
|
||||
teleports = &allowed_teleports;
|
||||
if(current_team().villages().count(it->first))
|
||||
|
@ -1006,12 +1006,12 @@ void turn_info::show_attack_options(unit_map::const_iterator u)
|
|||
{
|
||||
team& current_team = teams_[team_num_-1];
|
||||
|
||||
if(u == units_.end() || u->second.can_attack() == false)
|
||||
if(u == units_.end() || u->second.attacks_left() == 0)
|
||||
return;
|
||||
|
||||
for(unit_map::const_iterator target = units_.begin(); target != units_.end(); ++target) {
|
||||
if(current_team.is_enemy(target->second.side()) &&
|
||||
distance_between(target->first,u->first) == 1 && !target->second.stone()) {
|
||||
distance_between(target->first,u->first) == 1 && target->second.get_state("stoned")!="yes") {
|
||||
current_paths_.routes[target->first] = paths::route();
|
||||
}
|
||||
}
|
||||
|
@ -1077,7 +1077,7 @@ void turn_info::move_unit_to_loc(const unit_map::const_iterator& ui, const gamem
|
|||
const std::set<gamemap::location>* teleports = NULL;
|
||||
|
||||
std::set<gamemap::location> allowed_teleports;
|
||||
if(u.type().teleports()) {
|
||||
if(u.get_ability_bool("teleport",ui->first)) {
|
||||
allowed_teleports = vacant_villages(current_team().villages(),units_);
|
||||
teleports = &allowed_teleports;
|
||||
if(current_team().villages().count(ui->first))
|
||||
|
@ -1293,8 +1293,8 @@ void turn_info::cycle_units()
|
|||
}
|
||||
|
||||
if(it != units_.end() && !gui_.fogged(it->first.x,it->first.y)) {
|
||||
const bool ignore_zocs = it->second.type().is_skirmisher();
|
||||
const bool teleport = it->second.type().teleports();
|
||||
const bool ignore_zocs = it->second.get_ability_bool("skirmisher",it->first);
|
||||
const bool teleport = it->second.get_ability_bool("teleport",it->first);
|
||||
current_paths_ = paths(map_,status_,gameinfo_,units_,it->first,teams_,ignore_zocs,teleport,viewing_team(),path_turns_);
|
||||
gui_.highlight_reach(current_paths_);
|
||||
|
||||
|
@ -1339,8 +1339,8 @@ void turn_info::cycle_back_units()
|
|||
}
|
||||
|
||||
if(it != units_.begin() && !gui_.fogged(it->first.x,it->first.y)) {
|
||||
const bool ignore_zocs = it->second.type().is_skirmisher();
|
||||
const bool teleport = it->second.type().teleports();
|
||||
const bool ignore_zocs = it->second.get_ability_bool("skirmisher",it->first);
|
||||
const bool teleport = it->second.get_ability_bool("teleport",it->first);
|
||||
current_paths_ = paths(map_,status_,gameinfo_,units_,it->first,teams_,ignore_zocs,teleport,viewing_team(),path_turns_);
|
||||
gui_.highlight_reach(current_paths_);
|
||||
|
||||
|
@ -1588,9 +1588,10 @@ void turn_info::redo()
|
|||
} else {
|
||||
// Redo recall
|
||||
std::vector<unit>& recall_list = player->available_units;
|
||||
unit& un = recall_list[action.recall_pos];
|
||||
unit un = recall_list[action.recall_pos];
|
||||
|
||||
recorder.add_recall(action.recall_pos,action.recall_loc);
|
||||
un.set_game_context(&gameinfo_,&units_,&map_,&status_,&teams_);
|
||||
const std::string& msg = recruit_unit(map_,team_num_,units_,un,action.recall_loc,&gui_);
|
||||
if(msg.empty()) {
|
||||
statistics::recall_unit(un);
|
||||
|
@ -1804,7 +1805,7 @@ void turn_info::write_game_snapshot(config& start) const
|
|||
buf << side_num;
|
||||
side["side"] = buf.str();
|
||||
|
||||
for(std::map<gamemap::location,unit>::const_iterator i = units_.begin(); i != units_.end(); ++i) {
|
||||
for(units_map::const_iterator i = units_.begin(); i != units_.end(); ++i) {
|
||||
if(i->second.side() == side_num) {
|
||||
config& u = side.add_child("unit");
|
||||
i->first.write(u);
|
||||
|
@ -1895,7 +1896,7 @@ void turn_info::status_table()
|
|||
//output the number of the side first, and this will
|
||||
//cause it to be displayed in the correct colour
|
||||
if(leader != units_.end()) {
|
||||
str << IMAGE_PREFIX << leader->second.type().image() << COLUMN_SEPARATOR
|
||||
str << IMAGE_PREFIX << leader->second.absolute_image() << COLUMN_SEPARATOR
|
||||
<< "\033[3" << lexical_cast<char, size_t>(n+1) << 'm' << leader->second.description() << COLUMN_SEPARATOR;
|
||||
} else {
|
||||
str << ' ' << COLUMN_SEPARATOR << "\033[3" << lexical_cast<char, size_t>(n+1) << "m-" << COLUMN_SEPARATOR;
|
||||
|
@ -1958,7 +1959,7 @@ void turn_info::recruit()
|
|||
<< prefix << type.language_name() << "\n"
|
||||
<< prefix << type.cost() << " " << sgettext("unit^Gold");
|
||||
items.push_back(description.str());
|
||||
sample_units.push_back(unit(&type,team_num_));
|
||||
sample_units.push_back(unit(&gameinfo_,&units_,&map_,&status_,&teams_,&type,team_num_));
|
||||
}
|
||||
|
||||
if(sample_units.empty()) {
|
||||
|
@ -2015,7 +2016,7 @@ void turn_info::do_recruit(const std::string& name)
|
|||
|
||||
//create a unit with traits
|
||||
recorder.add_recruit(recruit_num,last_hex_);
|
||||
unit new_unit(&(u_type->second),team_num_,true);
|
||||
unit new_unit(&gameinfo_,&units_,&map_,&status_,&teams_,&(u_type->second),team_num_,true);
|
||||
gamemap::location loc = last_hex_;
|
||||
const std::string& msg = recruit_unit(map_,team_num_,units_,new_unit,loc,&gui_);
|
||||
if(msg.empty()) {
|
||||
|
@ -2069,7 +2070,7 @@ gui::dialog_button_action::RESULT delete_recall_unit::button_pressed(int menu_se
|
|||
//if the unit is of level > 1, or is close to advancing, we warn the player
|
||||
//about it
|
||||
std::string message = "";
|
||||
if(u.type().level() > 1) {
|
||||
if(u.level() > 1) {
|
||||
message = _("My lord, this unit is an experienced one, having advanced levels! Do you really want to dismiss $noun?");
|
||||
} else if(u.experience() > u.max_experience()/2) {
|
||||
message = _("My lord, this unit is close to advancing a level! Do you really want to dismiss $noun?");
|
||||
|
@ -2140,9 +2141,9 @@ void turn_info::recall()
|
|||
std::stringstream option;
|
||||
const std::string& description = u->description().empty() ? "-" : u->description();
|
||||
option << IMAGE_PREFIX << u->absolute_image() << COLUMN_SEPARATOR
|
||||
<< u->type().language_name() << COLUMN_SEPARATOR
|
||||
<< u->language_name() << COLUMN_SEPARATOR
|
||||
<< description << COLUMN_SEPARATOR
|
||||
<< u->type().level() << COLUMN_SEPARATOR
|
||||
<< u->level() << COLUMN_SEPARATOR
|
||||
<< u->experience() << "/";
|
||||
|
||||
if(u->can_advance() == false) {
|
||||
|
@ -2185,6 +2186,7 @@ void turn_info::recall()
|
|||
unit& un = recall_list[res];
|
||||
gamemap::location loc = last_hex_;
|
||||
recorder.add_recall(res,loc);
|
||||
un.set_game_context(&gameinfo_,&units_,&map_,&status_,&teams_);
|
||||
const std::string err = recruit_unit(map_,team_num_,units_,un,loc,&gui_);
|
||||
if(!err.empty()) {
|
||||
recorder.undo();
|
||||
|
@ -2337,8 +2339,8 @@ void turn_info::create_unit()
|
|||
std::vector<unit> unit_choices;
|
||||
for(game_data::unit_type_map::const_iterator i = gameinfo_.unit_types.begin(); i != gameinfo_.unit_types.end(); ++i) {
|
||||
options.push_back(i->second.language_name());
|
||||
unit_choices.push_back(unit(&i->second,1,false));
|
||||
unit_choices.back().new_turn();
|
||||
unit_choices.push_back(unit(&gameinfo_,&units_,&map_,&status_,&teams_,&i->second,1,false));
|
||||
unit_choices.back().new_turn(gamemap::location());
|
||||
}
|
||||
|
||||
int choice = 0;
|
||||
|
@ -2414,7 +2416,7 @@ void turn_info::unit_list()
|
|||
continue;
|
||||
|
||||
std::stringstream row;
|
||||
row << i->second.type().language_name() << COLUMN_SEPARATOR
|
||||
row << i->second.language_name() << COLUMN_SEPARATOR
|
||||
<< i->second.description() << COLUMN_SEPARATOR
|
||||
<< i->second.hitpoints() << "/" << i->second.max_hitpoints() << COLUMN_SEPARATOR
|
||||
<< i->second.experience() << "/";
|
||||
|
@ -2743,7 +2745,7 @@ void turn_info::do_command(const std::string& str)
|
|||
config cfg;
|
||||
i->second.write(cfg);
|
||||
cfg[name] = value;
|
||||
i->second = unit(gameinfo_,cfg);
|
||||
i->second = unit(&gameinfo_,&units_,&map_,&status_,&teams_,cfg);
|
||||
|
||||
gui_.invalidate(i->first);
|
||||
gui_.invalidate_unit();
|
||||
|
@ -2756,7 +2758,7 @@ void turn_info::do_command(const std::string& str)
|
|||
}
|
||||
|
||||
units_.erase(last_hex_);
|
||||
units_.insert(std::pair<gamemap::location,unit>(last_hex_,unit(&i->second,1,false)));
|
||||
units_.insert(std::pair<gamemap::location,unit>(last_hex_,unit(&gameinfo_,&units_,&map_,&status_,&teams_,&i->second,1,false)));
|
||||
gui_.invalidate(last_hex_);
|
||||
gui_.invalidate_unit();
|
||||
} else if(game_config::debug && cmd == "gold") {
|
||||
|
@ -2827,10 +2829,10 @@ void turn_info::show_enemy_moves(bool ignore_units)
|
|||
.lawful_bonus,
|
||||
u->first, units_, teams_);
|
||||
|
||||
if(current_team().is_enemy(u->second.side()) && !gui_.fogged(u->first.x,u->first.y) && !u->second.stone() && !invisible) {
|
||||
if(current_team().is_enemy(u->second.side()) && !gui_.fogged(u->first.x,u->first.y) && u->second.get_state("stoned")!="yes" && !invisible) {
|
||||
const unit_movement_resetter move_reset(u->second);
|
||||
const bool is_skirmisher = u->second.type().is_skirmisher();
|
||||
const bool teleports = u->second.type().teleports();
|
||||
const bool is_skirmisher = u->second.get_ability_bool("skirmisher",u->first);
|
||||
const bool teleports = u->second.get_ability_bool("teleport",u->first);
|
||||
unit_map units;
|
||||
units.insert(*u);
|
||||
const paths& path = paths(map_,status_,gameinfo_,ignore_units?units:units_,
|
||||
|
|
|
@ -255,7 +255,7 @@ void play_turn(const game_data& gameinfo, game_state& state_of_game,
|
|||
const config& level,
|
||||
CKey& key, display& gui, gamemap& map,
|
||||
std::vector<team>& teams, unsigned int team_num,
|
||||
std::map<gamemap::location,unit>& units,
|
||||
units_map& units,
|
||||
turn_info::floating_textbox& textbox,
|
||||
replay_network_sender& network_sender,
|
||||
bool skip_replay);
|
||||
|
|
|
@ -943,7 +943,7 @@ void encounter_recruitable_units(std::vector<team>& teams){
|
|||
void encounter_start_units(unit_map& units){
|
||||
for (unit_map::const_iterator help_unit_it = units.begin();
|
||||
help_unit_it != units.end(); help_unit_it++) {
|
||||
const std::string name = help_unit_it->second.type().id();
|
||||
const std::string name = help_unit_it->second.id();
|
||||
encountered_units_set.insert(name);
|
||||
}
|
||||
}
|
||||
|
@ -951,7 +951,7 @@ void encounter_start_units(unit_map& units){
|
|||
void encounter_recallable_units(game_state& gamestate){
|
||||
for(std::map<std::string, player_info>::iterator pi = gamestate.players.begin(); pi!=gamestate.players.end(); ++pi) {
|
||||
for(std::vector<unit>::iterator help_recall_it = pi->second.available_units.begin(); help_recall_it != pi->second.available_units.end(); help_recall_it++) {
|
||||
encountered_units_set.insert(help_recall_it->type().id());
|
||||
encountered_units_set.insert(help_recall_it->id());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -654,7 +654,7 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
|
|||
const gamemap::location loc(*child);
|
||||
const std::string& name = (*child)["name"];
|
||||
|
||||
std::map<gamemap::location,unit>::iterator u = units.find(loc);
|
||||
units_map::iterator u = units.find(loc);
|
||||
|
||||
if(u->second.unrenamable()) {
|
||||
ERR_NW << "renaming unrenamable unit " << u->second.name() << "\n";
|
||||
|
@ -702,7 +702,7 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
|
|||
if (version < 1.1){
|
||||
old_replay = true;
|
||||
}
|
||||
unit new_unit(&(u_type->second),team_num,true, old_replay);
|
||||
unit new_unit(&gameinfo,&units,&map,&state,&teams,&(u_type->second),team_num,true, old_replay);
|
||||
const std::string& res = recruit_unit(map,team_num,units,new_unit,loc);
|
||||
if(!res.empty()) {
|
||||
ERR_NW << "cannot recruit unit: " << res << "\n";
|
||||
|
@ -741,6 +741,7 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
|
|||
|
||||
if(val >= 0 && val < int(player->available_units.size())) {
|
||||
statistics::recall_unit(player->available_units[val]);
|
||||
player->available_units[val].set_game_context(&gameinfo,&units,&map,&state,&teams);
|
||||
recruit_unit(map,team_num,units,player->available_units[val],loc);
|
||||
player->available_units.erase(player->available_units.begin()+val);
|
||||
current_team.spend_gold(game_config::recall_cost);
|
||||
|
@ -794,7 +795,7 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
|
|||
const gamemap::location src(*source);
|
||||
const gamemap::location dst(*destination);
|
||||
|
||||
std::map<gamemap::location,unit>::iterator u = units.find(dst);
|
||||
units_map::iterator u = units.find(dst);
|
||||
if(u != units.end()) {
|
||||
ERR_NW << "destination already occupied: "
|
||||
<< dst << '\n';
|
||||
|
@ -807,8 +808,8 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
|
|||
throw replay::error();
|
||||
}
|
||||
|
||||
const bool ignore_zocs = u->second.type().is_skirmisher();
|
||||
const bool teleport = u->second.type().teleports();
|
||||
const bool ignore_zocs = u->second.get_ability_bool("skirmisher",u->first);
|
||||
const bool teleport = u->second.get_ability_bool("teleport",u->first);
|
||||
|
||||
paths paths_list(map,state,gameinfo,units,src,teams,ignore_zocs,teleport,current_team);
|
||||
|
||||
|
@ -888,7 +889,7 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
|
|||
const std::string& weapon = (*child)["weapon"];
|
||||
const int weapon_num = atoi(weapon.c_str());
|
||||
|
||||
std::map<gamemap::location,unit>::iterator u = units.find(src);
|
||||
units_map::iterator u = units.find(src);
|
||||
if(u == units.end()) {
|
||||
ERR_NW << "unfound location for source of attack\n";
|
||||
throw replay::error();
|
||||
|
@ -899,7 +900,7 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
|
|||
if (!game_config::ignore_replay_errors) throw replay::error();
|
||||
}
|
||||
|
||||
std::map<gamemap::location,unit>::const_iterator tgt = units.find(dst);
|
||||
units_map::const_iterator tgt = units.find(dst);
|
||||
|
||||
if(tgt == units.end()) {
|
||||
ERR_NW << "unfound defender for attack: " << src << " -> " << dst << '\n';
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "unit.hpp"
|
||||
|
||||
class display;
|
||||
typedef std::map<gamemap::location,unit> units_map;
|
||||
|
||||
struct verification_manager
|
||||
{
|
||||
|
@ -130,7 +131,7 @@ extern replay recorder;
|
|||
//replays up to one turn from the recorder object
|
||||
//returns true if it got to the end of the turn without data running out
|
||||
bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
|
||||
std::map<gamemap::location,unit>& units,
|
||||
units_map& units,
|
||||
std::vector<team>& teams, int team_num, const gamestatus& state,
|
||||
game_state& state_of_game, replay* obj=NULL);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
103
src/reports.cpp
103
src/reports.cpp
|
@ -74,13 +74,13 @@ void report::add_image(const std::string& image, const std::string& tooltip) {
|
|||
this->push_back(element("",image,tooltip));
|
||||
}
|
||||
|
||||
report generate_report(TYPE type, const gamemap& map, const unit_map& units,
|
||||
report generate_report(TYPE type, const gamemap& map, unit_map& units,
|
||||
const std::vector<team>& teams, const team& current_team,
|
||||
int current_side, int playing_side,
|
||||
const gamemap::location& loc, const gamemap::location& mouseover,
|
||||
const gamestatus& status, const std::set<std::string>& observers)
|
||||
{
|
||||
unit_map::const_iterator u = units.end();
|
||||
unit_map::iterator u = units.end();
|
||||
SDL_Color HPC;
|
||||
SDL_Color XPC;
|
||||
|
||||
|
@ -108,9 +108,9 @@ report generate_report(TYPE type, const gamemap& map, const unit_map& units,
|
|||
case UNIT_DESCRIPTION:
|
||||
return report(u->second.description(),"",u->second.description());
|
||||
case UNIT_TYPE:
|
||||
return report(u->second.type().language_name(),"",u->second.unit_description());
|
||||
return report(u->second.language_name(),"",u->second.unit_description());
|
||||
case UNIT_LEVEL:
|
||||
str << u->second.type().level();
|
||||
str << u->second.level();
|
||||
break;
|
||||
case UNIT_AMLA: {
|
||||
report res;
|
||||
|
@ -132,19 +132,19 @@ report generate_report(TYPE type, const gamemap& map, const unit_map& units,
|
|||
tooltip << _("invisible: ") << _("This unit is invisible. It cannot be seen or attacked by enemy units.");
|
||||
res.add_image(unit_status,tooltip);
|
||||
}
|
||||
if(u->second.has_flag("slowed")) {
|
||||
if(u->second.get_state("slowed")=="yes") {
|
||||
unit_status << "misc/slowed.png";
|
||||
tooltip << _("slowed: ") << _("This unit has been slowed. It will only deal half its normal damage when attacking.");
|
||||
res.add_image(unit_status,tooltip);
|
||||
}
|
||||
if(u->second.has_flag("poisoned")) {
|
||||
if(u->second.get_state("poisoned")=="yes") {
|
||||
unit_status << "misc/poisoned.png";
|
||||
tooltip << _("poisoned: ") << _("This unit is poisoned. It will lose 8 HP every turn until it can seek a cure to the poison in a village or from a friendly unit with the 'cures' ability.\n\
|
||||
\n\
|
||||
Units cannot be killed by poison alone. The poison will not reduce it below 1 HP.");
|
||||
res.add_image(unit_status,tooltip);
|
||||
}
|
||||
if(u->second.has_flag("stone")) {
|
||||
if(u->second.get_state("stoned")=="yes") {
|
||||
unit_status << "misc/stone.png";
|
||||
tooltip << _("stone: ") << _("This unit has been turned to stone. It may not move or attack.");
|
||||
res.add_image(unit_status,tooltip);
|
||||
|
@ -153,20 +153,20 @@ Units cannot be killed by poison alone. The poison will not reduce it below 1 HP
|
|||
return res;
|
||||
}
|
||||
case UNIT_ALIGNMENT: {
|
||||
const std::string& align = unit_type::alignment_description(u->second.type().alignment());
|
||||
const std::string& align_id = unit_type::alignment_id(u->second.type().alignment());
|
||||
const std::string& align = unit_type::alignment_description(u->second.alignment());
|
||||
const std::string& align_id = unit_type::alignment_id(u->second.alignment());
|
||||
return report(align, "", string_table[align_id + "_description"]);
|
||||
}
|
||||
case UNIT_ABILITIES: {
|
||||
report res;
|
||||
std::stringstream tooltip;
|
||||
const std::vector<std::string>& abilities = u->second.type().ability_tooltips();
|
||||
const std::vector<std::string>& abilities = u->second.ability_tooltips(u->first);
|
||||
for(std::vector<std::string>::const_iterator i = abilities.begin(); i != abilities.end(); ++i) {
|
||||
str << string_table[std::string("ability_") + *i];
|
||||
if(i+1 != abilities.end())
|
||||
str << gettext(i->c_str());
|
||||
if(i+2 != abilities.end())
|
||||
str << ",";
|
||||
|
||||
tooltip << string_table[*i + "_description"];
|
||||
++i;
|
||||
tooltip << i->c_str();//string_table[*i + "_description"];
|
||||
res.add_text(str,tooltip);
|
||||
}
|
||||
|
||||
|
@ -195,7 +195,7 @@ Units cannot be killed by poison alone. The poison will not reduce it below 1 HP
|
|||
}
|
||||
case UNIT_MOVES: {
|
||||
int x = 180;
|
||||
if(u->second.stone()){
|
||||
if(u->second.get_state("stoned")=="yes"){
|
||||
x = 128;
|
||||
}else{
|
||||
x = (int)(128 + (255-128)*((float)u->second.movement_left()/u->second.total_movement()));
|
||||
|
@ -214,26 +214,41 @@ Units cannot be killed by poison alone. The poison will not reduce it below 1 HP
|
|||
return res;
|
||||
}
|
||||
|
||||
const std::vector<attack_type>& attacks = u->second.attacks();
|
||||
for(std::vector<attack_type>::const_iterator at_it = attacks.begin();
|
||||
std::vector<attack_type>& attacks = u->second.attacks();
|
||||
for(std::vector<attack_type>::iterator at_it = attacks.begin();
|
||||
at_it != attacks.end(); ++at_it) {
|
||||
at_it->set_specials_context(u->first,u->second);
|
||||
const std::string& lang_type = gettext(at_it->type().c_str());
|
||||
str.str("");
|
||||
str << "<245,230,193>";
|
||||
if(u->second.slowed()) {
|
||||
if(u->second.get_state("slowed")=="yes") {
|
||||
str << round_damage(at_it->damage(),1,2) << "-" ;
|
||||
} else {
|
||||
str << at_it->damage() << "-" ;
|
||||
}
|
||||
str << at_it->num_swarm_attacks(u->second.hitpoints(), u->second.max_hitpoints());
|
||||
int nattacks = at_it->num_attacks();
|
||||
// compute swarm attacks;
|
||||
weapon_special_list swarm = at_it->get_specials("attacks");
|
||||
if(!swarm.empty()) {
|
||||
int swarm_min_attacks = swarm.highest("attacks_max",nattacks);
|
||||
int swarm_max_attacks = swarm.highest("attacks_min");
|
||||
int hitp = u->second.hitpoints();
|
||||
int mhitp = u->second.max_hitpoints();
|
||||
|
||||
nattacks = swarm_min_attacks + swarm_max_attacks * hitp / mhitp;
|
||||
|
||||
} else {
|
||||
nattacks = at_it->num_attacks();
|
||||
}
|
||||
str << nattacks;
|
||||
str << " " << at_it->name();
|
||||
tooltip << at_it->name() << "\n";
|
||||
if(u->second.slowed()) {
|
||||
if(u->second.get_state("slowed")=="yes") {
|
||||
tooltip << round_damage(at_it->damage(),1,2) << " " << _("damage") << ", ";
|
||||
} else {
|
||||
tooltip << at_it->damage() << " " << _("damage") << ", ";
|
||||
}
|
||||
tooltip << at_it->num_swarm_attacks(u->second.hitpoints(), u->second.max_hitpoints());
|
||||
tooltip << nattacks;
|
||||
tooltip << " " << _("attacks");
|
||||
|
||||
str<<"\n";
|
||||
|
@ -251,10 +266,10 @@ Units cannot be killed by poison alone. The poison will not reduce it below 1 HP
|
|||
std::map<int,std::vector<std::string> > resistances;
|
||||
for(unit_map::const_iterator u_it = units.begin(); u_it != units.end(); ++u_it) {
|
||||
if(teams[team_index].is_enemy(u_it->second.side()) && !current_team.fogged(u_it->first.x,u_it->first.y) &&
|
||||
seen_units.count(u_it->second.type().id()) == 0) {
|
||||
seen_units.insert(u_it->second.type().id());
|
||||
const int resistance = u_it->second.type().movement_type().resistance_against(*at_it) - 100;
|
||||
resistances[resistance].push_back(u_it->second.type().language_name());
|
||||
seen_units.count(u_it->second.id()) == 0) {
|
||||
seen_units.insert(u_it->second.id());
|
||||
const int resistance = u_it->second.resistance_against(*at_it,false,u_it->first) - 100;
|
||||
resistances[resistance].push_back(u_it->second.language_name());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -274,36 +289,26 @@ Units cannot be killed by poison alone. The poison will not reduce it below 1 HP
|
|||
res.add_text(str,tooltip);
|
||||
|
||||
str << "<166,146,117> ";
|
||||
static const std::string swarm_string("swarm");
|
||||
const std::string special = at_it->special();
|
||||
if (!special.empty()) {
|
||||
if(special == swarm_string){
|
||||
str << gettext(special.c_str())<<"("<<at_it->num_swarm_attacks(u->second.hitpoints(),u->second.max_hitpoints())<<"/"<< at_it->num_attacks() <<")" << "\n";
|
||||
tooltip << string_table["weapon_special_" + special + "_description"];
|
||||
}else{
|
||||
//check if we use special(argument)
|
||||
const std::string::size_type parindex = special.find('(',0);
|
||||
if (parindex != std::string::npos) {
|
||||
// If there is an argument, we use weapon_special_specialname_arg_description instead
|
||||
tooltip << string_table["weapon_special_" + special.substr(0,parindex) + "_arg_description"];
|
||||
} else {
|
||||
tooltip << string_table["weapon_special_" + special + "_description"];
|
||||
}
|
||||
str << gettext(special.c_str());
|
||||
}
|
||||
str<<"\n";
|
||||
|
||||
const std::vector<std::string>& specials = at_it->special_tooltips();
|
||||
|
||||
if(! specials.empty()) {
|
||||
for(std::vector<std::string>::const_iterator sp_it = specials.begin(); sp_it != specials.end(); ++sp_it) {
|
||||
str << gettext(sp_it->c_str());
|
||||
str<<"\n";
|
||||
++sp_it;
|
||||
tooltip << gettext(sp_it->c_str());
|
||||
}
|
||||
res.add_text(str,tooltip);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
case UNIT_IMAGE:
|
||||
return report("",u->second.type().image(),"");
|
||||
return report("",u->second.absolute_image(),"");
|
||||
case UNIT_PROFILE:
|
||||
return report("",u->second.type().image_profile(),"");
|
||||
return report("",u->second.profile(),"");
|
||||
case TIME_OF_DAY: {
|
||||
time_of_day tod = timeofday_at(status,units,mouseover,map);
|
||||
// don't show illuminated time on fogged/shrouded tiles
|
||||
|
@ -406,8 +411,8 @@ Units cannot be killed by poison alone. The poison will not reduce it below 1 HP
|
|||
|
||||
const gamemap::TERRAIN terrain = map[mouseover.x][mouseover.y];
|
||||
|
||||
const int move_cost = u->second.movement_cost(map,terrain);
|
||||
const int defense = 100 - u->second.defense_modifier(map,terrain);
|
||||
const int move_cost = u->second.movement_cost(terrain);
|
||||
const int defense = 100 - u->second.defense_modifier(terrain);
|
||||
|
||||
if(move_cost > 10) {
|
||||
str << " (-)";
|
||||
|
|
|
@ -87,7 +87,7 @@ namespace reports {
|
|||
void add_image(std::stringstream& image, std::stringstream& tooltip);
|
||||
};
|
||||
|
||||
report generate_report(TYPE type, const gamemap& map, const unit_map& units,
|
||||
report generate_report(TYPE type, const gamemap& map, unit_map& units,
|
||||
const std::vector<team>& teams, const team& current_team,
|
||||
int current_side, int active_side,
|
||||
const gamemap::location& loc, const gamemap::location& mouseover,
|
||||
|
|
|
@ -269,7 +269,7 @@ scenario_context::~scenario_context()
|
|||
}
|
||||
|
||||
attack_context::attack_context(const unit& a, const unit& d, const battle_stats& stats)
|
||||
: attacker_type(a.type().id()), defender_type(d.type().id()),
|
||||
: attacker_type(a.id()), defender_type(d.id()),
|
||||
bat_stats(stats), attacker_side(a.side()), defender_side(d.side())
|
||||
{
|
||||
}
|
||||
|
@ -346,8 +346,8 @@ void recruit_unit(const unit& u)
|
|||
return;
|
||||
|
||||
stats& s = get_stats(u.side());
|
||||
s.recruits[u.type().id()]++;
|
||||
s.recruit_cost += u.type().cost();
|
||||
s.recruits[u.id()]++;
|
||||
s.recruit_cost += u.cost();
|
||||
}
|
||||
|
||||
void recall_unit(const unit& u)
|
||||
|
@ -356,8 +356,8 @@ void recall_unit(const unit& u)
|
|||
return;
|
||||
|
||||
stats& s = get_stats(u.side());
|
||||
s.recalls[u.type().id()]++;
|
||||
s.recall_cost += u.type().cost();
|
||||
s.recalls[u.id()]++;
|
||||
s.recall_cost += u.cost();
|
||||
}
|
||||
|
||||
void un_recall_unit(const unit& u)
|
||||
|
@ -366,8 +366,8 @@ void un_recall_unit(const unit& u)
|
|||
return;
|
||||
|
||||
stats& s = get_stats(u.side());
|
||||
s.recalls[u.type().id()]--;
|
||||
s.recall_cost -= u.type().cost();
|
||||
s.recalls[u.id()]--;
|
||||
s.recall_cost -= u.cost();
|
||||
}
|
||||
|
||||
void advance_unit(const unit& u)
|
||||
|
@ -376,7 +376,7 @@ void advance_unit(const unit& u)
|
|||
return;
|
||||
|
||||
stats& s = get_stats(u.side());
|
||||
s.advanced_to[u.type().id()]++;
|
||||
s.advanced_to[u.id()]++;
|
||||
}
|
||||
|
||||
std::vector<std::string> get_categories()
|
||||
|
|
|
@ -805,7 +805,7 @@ void validate_side(int side)
|
|||
}
|
||||
|
||||
if(side < 1 || side > int(teams->size())) {
|
||||
throw game::game_error("invalid side found in unit definition");
|
||||
throw game::game_error("invalid side(" + lexical_cast_default<std::string>(side) + ") found in unit definition");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
2641
src/unit.cpp
2641
src/unit.cpp
File diff suppressed because it is too large
Load diff
585
src/unit.hpp
585
src/unit.hpp
|
@ -20,280 +20,375 @@
|
|||
#include "unit_types.hpp"
|
||||
#include "image.hpp"
|
||||
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* 1. Add terrain and ToD filtering. DONE
|
||||
* 2. Implement abilities and weapon specials. DONE
|
||||
* 3. Write backwards compatibility. SHOULD WORK
|
||||
* 4. Fix bugs.
|
||||
* 5. Goto step 4.
|
||||
*
|
||||
*
|
||||
* Known Issues:
|
||||
* 1. The wesnoth help is _seriously_ messed up. FIXED
|
||||
* 2. Translations probably don't work.
|
||||
* 3. The modification 'set_special' doesn't work. FIXED
|
||||
* 4. [damage] and [backstab] should be merged. DONE
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class unit;
|
||||
class display;
|
||||
class gamestatus;
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class unit;
|
||||
class display;
|
||||
|
||||
typedef std::map<gamemap::location,unit> unit_map;
|
||||
|
||||
|
||||
class unit_ability_list
|
||||
{
|
||||
public:
|
||||
|
||||
bool empty() const;
|
||||
|
||||
std::pair<int,gamemap::location> highest(const std::string& key, int def=0) const;
|
||||
std::pair<int,gamemap::location> lowest(const std::string& key, int def=100) const;
|
||||
|
||||
std::vector<std::pair<config*,gamemap::location> > cfgs;
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
|
||||
class unit
|
||||
{
|
||||
public:
|
||||
friend struct unit_movement_resetter;
|
||||
|
||||
//unit(const unit& u) { *this=u ; unit_halo_ = 0; unit_anim_halo_ = 0; anim_ =new unit_animation(*u.anim_);}
|
||||
unit(const unit& u) { *this=u ; unit_halo_ = 0; unit_anim_halo_ = 0; anim_ =NULL; }
|
||||
unit(const game_data& data, const config& cfg);
|
||||
unit(const unit_type* t, int side, bool use_traits=false, bool dummy_unit=false, unit_race::GENDER gender=unit_race::MALE);
|
||||
|
||||
//a constructor used when advancing a unit
|
||||
unit(const unit_type* t, const unit& u);
|
||||
virtual ~unit();
|
||||
const unit_type& type() const;
|
||||
std::string name() const;
|
||||
const std::string& description() const;
|
||||
const std::string& underlying_description() const;
|
||||
const std::string& profile() const;
|
||||
|
||||
//information about the unit -- a detailed description of it
|
||||
const std::string& unit_description() const;
|
||||
|
||||
void rename(const std::string& new_description);
|
||||
static const int UNIT_ID_MAX;
|
||||
|
||||
int hitpoints() const;
|
||||
int max_hitpoints() const;
|
||||
SDL_Colour hp_color() const;
|
||||
int experience() const;
|
||||
SDL_Colour xp_color() const;
|
||||
int max_experience() const;
|
||||
bool get_experience(int xp);
|
||||
bool unrenamable() const; /** < Set to true for some scenario-specific units which should not be renamed */
|
||||
bool advances() const;
|
||||
unsigned int side() const;
|
||||
public:
|
||||
friend struct unit_movement_resetter;
|
||||
// Copy constructor
|
||||
unit(const unit& u);
|
||||
// Initilizes a unit from a config
|
||||
unit(const game_data& gamedata, const config& cfg);
|
||||
unit(const game_data* gamedata, unit_map* unitmap, const gamemap* map, const gamestatus* game_status, const std::vector<team>* teams, const config& cfg);
|
||||
// Initilizes a unit from a unit type
|
||||
unit(const unit_type* t, int side, bool use_traits=false, bool dummy_unit=false, unit_race::GENDER gender=unit_race::MALE);
|
||||
unit(const game_data* gamedata, 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);
|
||||
virtual ~unit();
|
||||
|
||||
void set_game_context(const game_data* gamedata, unit_map* unitmap, const gamemap* map, const gamestatus* game_status, const std::vector<team>* teams);
|
||||
|
||||
// Advances this unit to another type
|
||||
void advance_to(const unit_type* t);
|
||||
const std::vector<std::string> advances_to() const;
|
||||
|
||||
// the current type id
|
||||
const std::string& id() const;
|
||||
// the actual name of the unit
|
||||
const std::string& name() const;
|
||||
void rename(const std::string& name);
|
||||
// the unit type name
|
||||
const std::string& description() const;
|
||||
const std::string& underlying_description() const;
|
||||
const t_string& language_name() const;
|
||||
const std::string& undead_variation() const;
|
||||
// the unit's profile
|
||||
const std::string& profile() const;
|
||||
//information about the unit -- a detailed description of it
|
||||
const std::string& unit_description() const;
|
||||
|
||||
int hitpoints() const;
|
||||
int max_hitpoints() const;
|
||||
int experience() const;
|
||||
int max_experience() const;
|
||||
int level() const;
|
||||
// adds 'xp' points to the units experience; returns true if advancement should occur
|
||||
bool get_experience(int xp);
|
||||
SDL_Colour hp_color() const;
|
||||
SDL_Colour xp_color() const;
|
||||
bool unrenamable() const; /** < Set to true for some scenario-specific units which should not be renamed */
|
||||
unsigned int side() const;
|
||||
Uint32 team_rgb() const;
|
||||
std::vector<Uint32> team_rgb_range() const;
|
||||
unit_race::GENDER gender() const;
|
||||
void set_side(unsigned int new_side);
|
||||
fixed_t alpha() const;
|
||||
void make_recruiter();
|
||||
bool can_recruit() const;
|
||||
int total_movement() const;
|
||||
int movement_left() const;
|
||||
void set_hold_position(bool value);
|
||||
bool hold_position() const;
|
||||
void set_user_end_turn(bool value=true);
|
||||
bool user_end_turn() const;
|
||||
bool can_attack() const;
|
||||
void set_movement(int moves);
|
||||
void set_attacked();
|
||||
void unit_hold_position();
|
||||
void end_unit_turn();
|
||||
void new_turn();
|
||||
void end_turn();
|
||||
void new_level();
|
||||
void refresh() {if(anim_ && !refreshing_) anim_->update_current_frame(); }
|
||||
|
||||
void set_resting(bool resting);
|
||||
bool is_resting() const;
|
||||
|
||||
bool gets_hit(int damage);
|
||||
void heal(int amount);
|
||||
void heal_all();
|
||||
|
||||
bool invisible(const std::string& terrain, int lawful_bonus,
|
||||
const gamemap::location& loc,
|
||||
const unit_map& units,const std::vector<team>& teams) const;
|
||||
bool poisoned() const;
|
||||
bool slowed() const;
|
||||
bool stone() const;
|
||||
|
||||
bool incapacitated() const;
|
||||
bool healable() const;
|
||||
|
||||
bool has_moved() const;
|
||||
bool has_goto() const;
|
||||
|
||||
bool emits_zoc() const;
|
||||
|
||||
bool matches_filter(const config& cfg) const;
|
||||
|
||||
void set_flag(const std::string& flag);
|
||||
void remove_flag(const std::string& flag);
|
||||
bool has_flag(const std::string& flag) const;
|
||||
|
||||
void add_overlay(const std::string& overlay);
|
||||
void remove_overlay(const std::string& overlay);
|
||||
const std::vector<std::string>& overlays() const;
|
||||
|
||||
/**
|
||||
* Initializes this unit from a cfg object.
|
||||
*
|
||||
* \param data The global game_data object
|
||||
* \param cfg Configuration object from which to read the unit
|
||||
*/
|
||||
void read(const game_data& data, const config& cfg);
|
||||
|
||||
void write(config& cfg) const;
|
||||
|
||||
void assign_role(const std::string& role);
|
||||
|
||||
const std::vector<attack_type>& attacks() const;
|
||||
|
||||
int movement_cost(const gamemap& map, gamemap::TERRAIN terrain) const;
|
||||
int defense_modifier(const gamemap& map, gamemap::TERRAIN terrain) const;
|
||||
int damage_against(const attack_type& attack) const;
|
||||
|
||||
//the name of the file to display (used in menus
|
||||
const std::string& absolute_image() const {return type_->image();}
|
||||
// a sdl surface, ready for display for place where we need a fix image of the unit
|
||||
const surface still_image() const;
|
||||
void refresh_unit(display& disp,gamemap::location hex, bool with_status =false);
|
||||
|
||||
void set_standing(const display& disp);
|
||||
void set_defending(const display& disp, int damage, std::string range);
|
||||
void set_leading(const display& disp);
|
||||
void set_healing(const display& disp);
|
||||
void set_leveling_in(const display& disp);
|
||||
void set_leveling_out(const display& disp);
|
||||
void set_teleporting (const display& disp);
|
||||
void set_extra_anim(const display& disp, std::string flag);
|
||||
void set_dying( const display& disp,const attack_type *attack);
|
||||
void set_walking(const display& disp,const std::string terrain);
|
||||
const unit_animation & set_attacking(const display& disp,bool hit,const attack_type& type);
|
||||
void set_recruited(const display& disp);
|
||||
void set_healed(const display& disp,int healing);
|
||||
void set_poisoned(const display& disp,int damage);
|
||||
void restart_animation(const display& disp,int start_time);
|
||||
const unit_animation* get_animation() const { return anim_;};
|
||||
void set_offset(double offset){offset_ = offset;}
|
||||
|
||||
void set_facing(gamemap::location::DIRECTION);
|
||||
gamemap::location::DIRECTION facing() const;
|
||||
|
||||
const t_string& traits_description() const;
|
||||
|
||||
int value() const;
|
||||
bool is_guardian() const;
|
||||
|
||||
const gamemap::location& get_goto() const;
|
||||
void set_goto(const gamemap::location& new_goto);
|
||||
|
||||
int upkeep() const;
|
||||
|
||||
void set_hidden(bool state) {hidden_ = state;};
|
||||
bool is_flying() const;
|
||||
|
||||
bool can_advance() const;
|
||||
|
||||
const std::vector<Uint32>& flag_rgb() const;
|
||||
unit_race::GENDER gender() const;
|
||||
void set_side(unsigned int new_side);
|
||||
fixed_t alpha() const;
|
||||
|
||||
bool can_recruit() const;
|
||||
const std::vector<std::string>& recruits() const;
|
||||
int total_movement() const;
|
||||
int movement_left() const;
|
||||
void set_hold_position(bool value);
|
||||
bool hold_position() const;
|
||||
void set_user_end_turn(bool value=true);
|
||||
bool user_end_turn() const;
|
||||
int attacks_left() const;
|
||||
void set_movement(int moves);
|
||||
void set_attacks(int left);
|
||||
void unit_hold_position();
|
||||
void end_unit_turn();
|
||||
void new_turn(const gamemap::location& loc);
|
||||
void end_turn();
|
||||
void new_level();
|
||||
void refresh() {if(anim_ && !refreshing_) anim_->update_current_frame(); }
|
||||
|
||||
bool take_hit(int damage);
|
||||
void heal(int amount);
|
||||
void heal_all();
|
||||
bool resting() const;
|
||||
void set_resting(bool rest);
|
||||
|
||||
const std::string get_state(const std::string& state) const;
|
||||
void set_state(const std::string& state, const std::string& value);
|
||||
|
||||
bool has_moved() const;
|
||||
bool has_goto() const;
|
||||
int emits_zoc() const;
|
||||
/* cfg: standard unit filter */
|
||||
bool matches_filter(const config& cfg,const gamemap::location& loc,bool use_flat_tod=false) const;
|
||||
void add_overlay(const std::string& overlay);
|
||||
void remove_overlay(const std::string& overlay);
|
||||
const std::vector<std::string>& overlays() const;
|
||||
/**
|
||||
* Initializes this unit from a cfg object.
|
||||
*
|
||||
* \param cfg Configuration object from which to read the unit
|
||||
*/
|
||||
void read(const config& cfg);
|
||||
void write(config& cfg) const;
|
||||
|
||||
void assign_role(const std::string& role);
|
||||
const std::vector<attack_type>& attacks() const;
|
||||
std::vector<attack_type>& attacks();
|
||||
|
||||
int damage_from(const attack_type& attack,bool attacker,const gamemap::location& loc) const;
|
||||
|
||||
// a sdl surface, ready for display for place where we need a fix image of the unit
|
||||
const surface still_image() const;
|
||||
void refresh_unit(display& disp,gamemap::location hex, bool with_status =false);
|
||||
|
||||
void set_standing(const display& disp);
|
||||
void set_defending(const display& disp, int damage, std::string range);
|
||||
void set_leading(const display& disp);
|
||||
void set_healing(const display& disp);
|
||||
void set_leveling_in(const display& disp);
|
||||
void set_leveling_out(const display& disp);
|
||||
void set_teleporting (const display& disp);
|
||||
void set_extra_anim(const display& disp, std::string flag);
|
||||
void set_dying( const display& disp,const attack_type *attack);
|
||||
void set_walking(const display& disp,const std::string terrain);
|
||||
const unit_animation & set_attacking(const display& disp,bool hit,const attack_type& type);
|
||||
void set_recruited(const display& disp);
|
||||
void set_healed(const display& disp,int healing);
|
||||
void set_poisoned(const display& disp,int damage);
|
||||
void restart_animation(const display& disp,int start_time);
|
||||
const unit_animation* get_animation() const { return anim_;};
|
||||
void set_offset(double offset){offset_ = offset;}
|
||||
void set_facing(gamemap::location::DIRECTION);
|
||||
gamemap::location::DIRECTION facing() const;
|
||||
|
||||
const t_string& traits_description() const;
|
||||
|
||||
int value() const;
|
||||
int cost() const;
|
||||
|
||||
const gamemap::location& get_goto() const;
|
||||
void set_goto(const gamemap::location& new_goto);
|
||||
|
||||
int upkeep() const;
|
||||
|
||||
void set_hidden(bool state) {hidden_ = state;};
|
||||
bool is_flying() const;
|
||||
int movement_cost(gamemap::TERRAIN terrain, int recurse_count=0) const;
|
||||
int defense_modifier(gamemap::TERRAIN terrain, int recurse_count=0) const;
|
||||
int resistance_against(const attack_type& damage_type,bool attacker,const gamemap::location& loc) const;
|
||||
// std::map<gamemap::TERRAIN,int> movement_type() const;
|
||||
|
||||
bool can_advance() const;
|
||||
bool advances() const;
|
||||
|
||||
std::map<std::string,std::string> advancement_icons() const;
|
||||
std::vector<std::pair<std::string,std::string> > amla_icons() const;
|
||||
|
||||
config::child_list get_modification_advances() const;
|
||||
|
||||
size_t modification_count(const std::string& type, const std::string& id) const;
|
||||
|
||||
void add_modification(const std::string& type, const config& modification,
|
||||
|
||||
config::child_list get_modification_advances() const;
|
||||
const config::child_list& modification_advancements() const;
|
||||
|
||||
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);
|
||||
|
||||
const t_string& modification_description(const std::string& type) const;
|
||||
|
||||
bool move_interrupted() const;
|
||||
const gamemap::location& get_interrupted_move() const;
|
||||
void set_interrupted_move(const gamemap::location& interrupted_move);
|
||||
//is set to the number of moves left, ATTACKED if attacked,
|
||||
// MOVED if moved and then pressed "end turn"
|
||||
// NOT_MOVED if not moved and pressed "end turn"
|
||||
enum MOVES { ATTACKED=-1, MOVED=-2, NOT_MOVED=-3 };
|
||||
enum STATE { STATE_STANDING, STATE_ATTACKING, STATE_DEFENDING,
|
||||
|
||||
const t_string& modification_description(const std::string& type) const;
|
||||
|
||||
bool move_interrupted() const;
|
||||
const gamemap::location& get_interrupted_move() const;
|
||||
void set_interrupted_move(const gamemap::location& interrupted_move);
|
||||
|
||||
enum STATE { STATE_STANDING, STATE_ATTACKING, STATE_DEFENDING,
|
||||
STATE_LEADING, STATE_HEALING, STATE_WALKING, STATE_LEVELIN,
|
||||
STATE_LEVELOUT, STATE_DYING, STATE_EXTRA, STATE_TELEPORT,
|
||||
STATE_RECRUITED, STATE_HEALED, STATE_POISONED};
|
||||
STATE state() const {return state_;}
|
||||
private:
|
||||
const std::string& image() const;
|
||||
unit_race::GENDER generate_gender(const unit_type& type, bool use_genders);
|
||||
unit_race::GENDER gender_;
|
||||
std::string variation_;
|
||||
|
||||
const unit_type* type_;
|
||||
|
||||
STATE state_;
|
||||
bool getsHit_;
|
||||
|
||||
int hitpoints_;
|
||||
int maxHitpoints_, backupMaxHitpoints_;
|
||||
int experience_;
|
||||
int maxExperience_, backupMaxExperience_;
|
||||
|
||||
unsigned int side_;
|
||||
|
||||
int moves_;
|
||||
bool user_end_turn_;
|
||||
gamemap::location::DIRECTION facing_;
|
||||
int maxMovement_, backupMaxMovement_;
|
||||
bool resting_;
|
||||
bool hold_position_;
|
||||
|
||||
std::string underlying_description_, description_, profile_;
|
||||
|
||||
//this field is used if the scenario creator places a custom unit description
|
||||
//with a certain unit. If this field is empty, then the more general unit description
|
||||
//from the unit's base type will be used
|
||||
std::string custom_unit_description_;
|
||||
|
||||
bool recruit_;
|
||||
|
||||
std::string role_;
|
||||
|
||||
std::set<std::string> statusFlags_;
|
||||
std::vector<std::string> overlays_;
|
||||
|
||||
//this field stores user-variables associated with the unit
|
||||
config variables_;
|
||||
|
||||
std::vector<attack_type> attacks_;
|
||||
std::vector<attack_type> backupAttacks_;
|
||||
|
||||
config modifications_;
|
||||
|
||||
t_string traitsDescription_;
|
||||
|
||||
string_map modificationDescriptions_;
|
||||
|
||||
bool guardian_;
|
||||
|
||||
gamemap::location goto_, interrupted_move_;
|
||||
|
||||
enum UPKEEP_COST { UPKEEP_FREE, UPKEEP_LOYAL, UPKEEP_FULL_PRICE };
|
||||
|
||||
UPKEEP_COST upkeep_;
|
||||
|
||||
bool unrenamable_;
|
||||
|
||||
unit_animation *anim_;
|
||||
int frame_begin_time;
|
||||
double offset_;
|
||||
std::string user_image_;
|
||||
|
||||
void reset_modifications();
|
||||
void apply_modifications();
|
||||
void remove_temporary_modifications();
|
||||
void generate_traits();
|
||||
void generate_traits_description();
|
||||
int unit_halo_;
|
||||
int unit_anim_halo_;
|
||||
bool refreshing_; // avoid infinit recursion
|
||||
bool hidden_;
|
||||
STATE state() const;
|
||||
|
||||
//the name of the file to display (used in menus
|
||||
const std::string& absolute_image() const;
|
||||
const std::string& image_halo() const;
|
||||
const std::string& image_profile() const;
|
||||
const std::string& image_fighting(attack_type::RANGE range) const;
|
||||
const std::string& image_leading() const;
|
||||
const std::string& image_healing() const;
|
||||
const std::string& image_halo_healing() const;
|
||||
const std::string& get_hit_sound() const;
|
||||
const std::string& die_sound() const;
|
||||
const std::string& image_ellipse() const;
|
||||
|
||||
const std::string& usage() const;
|
||||
unit_type::ALIGNMENT alignment() const;
|
||||
const std::string& race() const;
|
||||
|
||||
const defensive_animation& defend_animation(bool hits, std::string range) const;
|
||||
const unit_animation& teleport_animation() const;
|
||||
const unit_animation* extra_animation(std::string flag) const;
|
||||
const death_animation& die_animation(const attack_type* attack) const;
|
||||
const movement_animation& move_animation(const std::string terrain,gamemap::location::DIRECTION) const;
|
||||
|
||||
bool get_ability_bool(const std::string& ability, const gamemap::location& loc) const;
|
||||
unit_ability_list get_abilities(const std::string& ability, const gamemap::location& loc) const;
|
||||
std::vector<std::string> ability_tooltips(const gamemap::location& loc) const;
|
||||
std::vector<std::string> unit_ability_tooltips() const;
|
||||
|
||||
void reset_modifications();
|
||||
void backup_state();
|
||||
void apply_modifications();
|
||||
void remove_temporary_modifications();
|
||||
void generate_traits();
|
||||
void generate_traits_description();
|
||||
std::string generate_description() const;
|
||||
|
||||
bool invisible(const std::string& terrain, int lawful_bonus,
|
||||
const gamemap::location& loc,
|
||||
const unit_map& units,const std::vector<team>& teams) const;
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
* cfg: an ability WML structure
|
||||
*/
|
||||
bool ability_active(const std::string& ability,const config& cfg,const gamemap::location& loc) const;
|
||||
bool ability_affects_adjacent(const std::string& ability,const config& cfg,int dir,const gamemap::location& loc) const;
|
||||
bool ability_affects_self(const std::string& ability,const config& cfg,const gamemap::location& loc) const;
|
||||
bool resistance_filter_matches(const config& cfg,const gamemap::location& loc,bool attacker,const attack_type& damage_type) const;
|
||||
|
||||
config cfg_;
|
||||
|
||||
std::vector<std::string> advances_to_;
|
||||
std::string id_;
|
||||
const unit_race* race_;
|
||||
std::string name_;
|
||||
std::string description_;
|
||||
std::string custom_unit_description_;
|
||||
std::string underlying_description_;
|
||||
t_string language_name_;
|
||||
std::string undead_variation_;
|
||||
std::string variation_;
|
||||
|
||||
int hit_points_;
|
||||
int max_hit_points_, max_hit_points_b_;
|
||||
int experience_;
|
||||
int max_experience_, max_experience_b_;
|
||||
int level_;
|
||||
unit_type::ALIGNMENT alignment_;
|
||||
std::vector<Uint32> flag_rgb_;
|
||||
|
||||
bool unrenamable_;
|
||||
unsigned int side_;
|
||||
unit_race::GENDER gender_;
|
||||
|
||||
fixed_t alpha_;
|
||||
|
||||
std::vector<std::string> recruits_;
|
||||
|
||||
int movement_;
|
||||
int max_movement_, max_movement_b_;
|
||||
bool hold_position_;
|
||||
bool end_turn_;
|
||||
bool resting_;
|
||||
int attacks_left_;
|
||||
int max_attacks_;
|
||||
|
||||
std::map<std::string,std::string> states_;
|
||||
config variables_;
|
||||
int emit_zoc_;
|
||||
STATE state_;
|
||||
|
||||
std::vector<std::string> overlays_;
|
||||
|
||||
std::string role_;
|
||||
std::vector<attack_type> attacks_, attacks_b_;
|
||||
gamemap::location::DIRECTION facing_;
|
||||
|
||||
t_string traits_description_;
|
||||
int unit_value_;
|
||||
gamemap::location goto_, interrupted_move_;
|
||||
int upkeep_;
|
||||
bool flying_;
|
||||
|
||||
// std::map<gamemap::TERRAIN,int> movement_costs_, movement_costs_b_;
|
||||
// std::map<gamemap::TERRAIN,int> defense_mods_, defense_mods_b_;
|
||||
|
||||
string_map modification_descriptions_;
|
||||
std::vector<defensive_animation> defensive_animations_;
|
||||
|
||||
std::vector<unit_animation> teleport_animations_;
|
||||
|
||||
std::multimap<std::string,unit_animation> extra_animations_;
|
||||
|
||||
std::vector<death_animation> death_animations_;
|
||||
|
||||
std::vector<movement_animation> movement_animations_;
|
||||
unit_animation *anim_;
|
||||
int frame_begin_time;
|
||||
double offset_;
|
||||
int unit_halo_;
|
||||
int unit_anim_halo_;
|
||||
bool getsHit_;
|
||||
bool refreshing_; // avoid infinite recursion
|
||||
bool hidden_;
|
||||
|
||||
config modifications_;
|
||||
|
||||
public:
|
||||
const game_data* gamedata_;
|
||||
mutable unit_map* units_;
|
||||
const gamemap* map_;
|
||||
const gamestatus* gamestatus_;
|
||||
const std::vector<team>* teams_;
|
||||
|
||||
};
|
||||
|
||||
//object which temporarily resets a unit's movement
|
||||
struct unit_movement_resetter
|
||||
{
|
||||
unit_movement_resetter(unit& u, bool operate=true) : u_(u), moves_(u.moves_)
|
||||
unit_movement_resetter(unit& u, bool operate=true) : u_(u), moves_(u.movement_)
|
||||
{
|
||||
if(operate) {
|
||||
u.moves_ = u.total_movement();
|
||||
u.movement_ = u.total_movement();
|
||||
}
|
||||
}
|
||||
|
||||
~unit_movement_resetter()
|
||||
{
|
||||
u_.moves_ = moves_;
|
||||
u_.movement_ = moves_;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -328,7 +423,7 @@ std::string get_team_name(unsigned int side, const unit_map& units);
|
|||
const std::set<gamemap::location> vacant_villages(const std::set<gamemap::location>& villages, const unit_map& units);
|
||||
|
||||
//this object is used to temporary place a unit in the unit map, swapping out any unit
|
||||
//that is already there. On destruction, it restores the unit map to its original state.
|
||||
//that is already there. On destruction, it restores the unit map to its original .
|
||||
struct temporary_unit_placer
|
||||
{
|
||||
temporary_unit_placer(unit_map& m, const gamemap::location& loc, const unit& u);
|
||||
|
|
906
src/unit_abilities.cpp
Executable file
906
src/unit_abilities.cpp
Executable file
|
@ -0,0 +1,906 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
Copyright (C) 2006 by Dominic Bolin <dominic.bolin@exong.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.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "unit.hpp"
|
||||
|
||||
#include "wassert.hpp"
|
||||
#include "log.hpp"
|
||||
#include "pathutils.hpp"
|
||||
|
||||
typedef std::map<gamemap::location,unit> units_map;
|
||||
|
||||
/*
|
||||
*
|
||||
* [abilities]
|
||||
* ...
|
||||
*
|
||||
* [heals]
|
||||
* value=4
|
||||
* max_value=8
|
||||
* cumulative=no
|
||||
* affect_allies=yes
|
||||
* name= _ "heals"
|
||||
// * name_inactive=null
|
||||
* description= _ "Heals:
|
||||
Allows the unit to heal adjacent friendly units at the beginning of each turn.
|
||||
|
||||
A unit cared for by a healer may heal up to 4 HP per turn.
|
||||
A poisoned unit cannot be cured of its poison by a healer, and must seek the care of a village or a unit that can cure."
|
||||
// * description_inactive=null
|
||||
* icon="misc/..."
|
||||
// * icon_inactive=null
|
||||
* [adjacent_description]
|
||||
* name= _ "heals"
|
||||
// * name_inactive=null
|
||||
* description= _ "Heals:
|
||||
Allows the unit to heal adjacent friendly units at the beginning of each turn.
|
||||
|
||||
A unit cared for by a healer may heal up to 4 HP per turn.
|
||||
A poisoned unit cannot be cured of its poison by a healer, and must seek the care of a village or a unit that can cure."
|
||||
// * description_inactive=null
|
||||
* icon="misc/..."
|
||||
// * icon_inactive=null
|
||||
* [/adjacent_description]
|
||||
*
|
||||
* affect_self=yes
|
||||
* [filter] // SUF
|
||||
* ...
|
||||
* [/filter]
|
||||
* [filter_location]
|
||||
* terrain=f
|
||||
* tod=lawful
|
||||
* [/filter_location]
|
||||
* [filter_self] // SUF
|
||||
* ...
|
||||
* [/filter_self]
|
||||
* [filter_adjacent] // SUF
|
||||
* adjacent=n,ne,nw
|
||||
* ...
|
||||
* [/filter_adjacent]
|
||||
* [filter_adjacent_location]
|
||||
* adjacent=n,ne,nw
|
||||
* ...
|
||||
* [/filter_adjacent]
|
||||
* [affect_adjacent]
|
||||
* adjacent=n,ne,nw
|
||||
* [filter] // SUF
|
||||
* ...
|
||||
* [/filter]
|
||||
* [/affect_adjacent]
|
||||
* [affect_adjacent]
|
||||
* adjacent=s,se,sw
|
||||
* [filter] // SUF
|
||||
* ...
|
||||
* [/filter]
|
||||
* [/affect_adjacent]
|
||||
*
|
||||
* [/heals]
|
||||
*
|
||||
* ...
|
||||
* [/abilities]
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
bool unit::get_ability_bool(const std::string& ability, const gamemap::location& loc) const
|
||||
{
|
||||
const config* abilities = cfg_.child("abilities");
|
||||
if(abilities) {
|
||||
const config::child_list& list = abilities->get_children(ability);
|
||||
for(config::child_list::const_iterator i = list.begin(); i != list.end(); ++i) {
|
||||
if(ability_active(ability,**i,loc) && ability_affects_self(ability,**i,loc)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wassert(units_ != NULL);
|
||||
wassert(teams_ != NULL);
|
||||
gamemap::location adjacent[6];
|
||||
get_adjacent_tiles(loc,adjacent);
|
||||
for(int i = 0; i != 6; ++i) {
|
||||
const unit_map::const_iterator it = units_->find(adjacent[i]);
|
||||
if(it != units_->end() &&
|
||||
it->second.get_state("stoned") != "yes") {
|
||||
const config* adj_abilities = it->second.cfg_.child("abilities");
|
||||
if(adj_abilities) {
|
||||
const config::child_list& list = adj_abilities->get_children(ability);
|
||||
for(config::child_list::const_iterator j = list.begin(); j != list.end(); ++j) {
|
||||
if(((**j)["affect_allies"]=="yes" && !(*teams_)[side()-1].is_enemy(it->second.side()))
|
||||
|| ((**j)["affect_enemies"]=="yes" && (*teams_)[side()-1].is_enemy(it->second.side())) &&
|
||||
ability_active(ability,**j,loc) && ability_affects_adjacent(ability,**j,i,loc)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
unit_ability_list unit::get_abilities(const std::string& ability, const gamemap::location& loc) const
|
||||
{
|
||||
unit_ability_list res;
|
||||
|
||||
const config* abilities = cfg_.child("abilities");
|
||||
if(abilities) {
|
||||
const config::child_list& list = abilities->get_children(ability);
|
||||
for(config::child_list::const_iterator i = list.begin(); i != list.end(); ++i) {
|
||||
if(ability_active(ability,**i,loc) && ability_affects_self(ability,**i,loc)) {
|
||||
res.cfgs.push_back(std::pair<config*,gamemap::location>(*i,loc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wassert(units_ != NULL);
|
||||
gamemap::location adjacent[6];
|
||||
get_adjacent_tiles(loc,adjacent);
|
||||
for(int i = 0; i != 6; ++i) {
|
||||
const unit_map::const_iterator it = units_->find(adjacent[i]);
|
||||
if(it != units_->end() &&
|
||||
it->second.get_state("stoned") != "yes") {
|
||||
const config* adj_abilities = it->second.cfg_.child("abilities");
|
||||
if(adj_abilities) {
|
||||
const config::child_list& list = adj_abilities->get_children(ability);
|
||||
for(config::child_list::const_iterator j = list.begin(); j != list.end(); ++j) {
|
||||
if(((**j)["affect_allies"]=="yes" && !(*teams_)[side()-1].is_enemy(it->second.side()))
|
||||
|| ((**j)["affect_enemies"]=="yes" && (*teams_)[side()-1].is_enemy(it->second.side())) &&
|
||||
ability_active(ability,**j,loc) && ability_affects_adjacent(ability,**j,i,loc)) {
|
||||
res.cfgs.push_back(std::pair<config*,gamemap::location>(*j,loc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<std::string> unit::unit_ability_tooltips() const
|
||||
{
|
||||
std::vector<std::string> res;
|
||||
|
||||
const config* abilities = cfg_.child("abilities");
|
||||
if(abilities) {
|
||||
const config::child_map& list_map = abilities->all_children();
|
||||
for(config::child_map::const_iterator i = list_map.begin(); i != list_map.end(); ++i) {
|
||||
for(config::child_list::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
|
||||
if((**j)["name"] != "") {
|
||||
res.push_back((**j)["name"].str());
|
||||
res.push_back((**j)["description"].str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<std::string> unit::ability_tooltips(const gamemap::location& loc) const
|
||||
{
|
||||
std::vector<std::string> res;
|
||||
|
||||
const config* abilities = cfg_.child("abilities");
|
||||
if(abilities) {
|
||||
const config::child_map& list_map = abilities->all_children();
|
||||
for(config::child_map::const_iterator i = list_map.begin(); i != list_map.end(); ++i) {
|
||||
for(config::child_list::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
|
||||
if(ability_active(i->first,**j,loc)) {
|
||||
if((**j)["name"] != "") {
|
||||
res.push_back((**j)["name"].str());
|
||||
res.push_back((**j)["description"].str());
|
||||
}
|
||||
} else {
|
||||
if((**j)["name_inactive"] != "") {
|
||||
res.push_back((**j)["name_inactive"].str());
|
||||
res.push_back((**j)["description_inactive"].str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wassert(units_ != NULL);
|
||||
gamemap::location adjacent[6];
|
||||
get_adjacent_tiles(loc,adjacent);
|
||||
for(int i = 0; i != 6; ++i) {
|
||||
const unit_map::const_iterator it = units_->find(adjacent[i]);
|
||||
if(it != units_->end() && 0 &&
|
||||
it->second.get_state("stoned") != "yes") {
|
||||
const config* adj_abilities = it->second.cfg_.child("abilities");
|
||||
if(adj_abilities) {
|
||||
const config::child_map& adj_list_map = adj_abilities->all_children();
|
||||
for(config::child_map::const_iterator k = adj_list_map.begin(); k != adj_list_map.end(); ++k) {
|
||||
for(config::child_list::const_iterator j = k->second.begin(); j != k->second.end(); ++j) {
|
||||
if(((**j)["affect_allies"]=="yes" && !(*teams_)[side()-1].is_enemy(it->second.side()))
|
||||
|| ((**j)["affect_enemies"]=="yes" && (*teams_)[side()-1].is_enemy(it->second.side()))) {
|
||||
const config* adj_desc = (*j)->child("adjacent_description");
|
||||
if(ability_affects_adjacent(k->first,**j,i,loc)) {
|
||||
if(!adj_desc) {
|
||||
if(ability_active(k->first,**j,loc)) {
|
||||
if((**j)["name"] != "") {
|
||||
res.push_back((**j)["name"].str());
|
||||
res.push_back((**j)["description"].str());
|
||||
}
|
||||
} else {
|
||||
if((**j)["name_inactive"] != "") {
|
||||
res.push_back((**j)["name_inactive"].str());
|
||||
res.push_back((**j)["description_inactive"].str());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(ability_active(k->first,**j,loc)) {
|
||||
if((*adj_desc)["name"] != "") {
|
||||
res.push_back((*adj_desc)["name"].str());
|
||||
res.push_back((*adj_desc)["description"].str());
|
||||
}
|
||||
} else {
|
||||
if((*adj_desc)["name_inactive"] != "") {
|
||||
res.push_back((*adj_desc)["name_inactive"].str());
|
||||
res.push_back((*adj_desc)["description_inacive"].str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* cfg: an ability WML structure
|
||||
*
|
||||
*/
|
||||
|
||||
bool unit::ability_active(const std::string& ability,const config& cfg,const gamemap::location& loc) const
|
||||
{
|
||||
if(cfg.child("filter_self") != NULL) {
|
||||
if(!matches_filter(*cfg.child("filter_self"),loc,ability=="illuminates")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
wassert(units_ != NULL);
|
||||
gamemap::location adjacent[6];
|
||||
get_adjacent_tiles(loc,adjacent);
|
||||
int index=-1;
|
||||
const config::child_list& adj_filt = cfg.get_children("filter_adjacent");
|
||||
config::child_list::const_iterator i;
|
||||
for(i = adj_filt.begin(); i != adj_filt.end(); ++i) {
|
||||
std::vector<std::string> dirs = utils::split((**i)["adjacent"]);
|
||||
if(dirs.size()==1 && dirs.front()=="") {
|
||||
} else {
|
||||
for(std::vector<std::string>::const_iterator j = dirs.begin(); j != dirs.end(); ++j) {
|
||||
if(*j=="n") {
|
||||
index=0;
|
||||
} else if(*j=="ne") {
|
||||
index=1;
|
||||
} else if(*j=="se") {
|
||||
index=2;
|
||||
} else if(*j=="s") {
|
||||
index=3;
|
||||
} else if(*j=="sw") {
|
||||
index=4;
|
||||
} else if(*j=="nw") {
|
||||
index=5;
|
||||
} else {
|
||||
index=-1;
|
||||
}
|
||||
if(index != -1) {
|
||||
units_map::const_iterator unit = units_->find(adjacent[index]);
|
||||
if(unit == units_->end()) {
|
||||
return false;
|
||||
}
|
||||
if(!unit->second.matches_filter(**i,unit->first,ability=="illuminates")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
index=-1;
|
||||
const config::child_list& adj_filt_loc = cfg.get_children("filter_adjacent_location");
|
||||
for(i = adj_filt_loc.begin(); i != adj_filt_loc.end(); ++i) {
|
||||
std::vector<std::string> dirs = utils::split((**i)["adjacent"]);
|
||||
if(dirs.size()==1 && dirs.front()=="") {
|
||||
} else {
|
||||
for(std::vector<std::string>::const_iterator j = dirs.begin(); j != dirs.end(); ++j) {
|
||||
if(*j=="n") {
|
||||
index=0;
|
||||
} else if(*j=="ne") {
|
||||
index=1;
|
||||
} else if(*j=="se") {
|
||||
index=2;
|
||||
} else if(*j=="s") {
|
||||
index=3;
|
||||
} else if(*j=="sw") {
|
||||
index=4;
|
||||
} else if(*j=="nw") {
|
||||
index=5;
|
||||
} else {
|
||||
index=-1;
|
||||
}
|
||||
if(index != -1) {
|
||||
wassert(map_ != NULL);
|
||||
wassert(gamestatus_ != NULL);
|
||||
if(!map_->terrain_matches_filter(adjacent[index],**i,*gamestatus_,*units_,ability=="illuminates")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
*
|
||||
* cfg: an ability WML structure
|
||||
*
|
||||
*/
|
||||
bool unit::ability_affects_adjacent(const std::string& ability,const config& cfg,int dir,const gamemap::location& loc) const
|
||||
{
|
||||
// wassert("not done" == "done");
|
||||
wassert(dir >=0 && dir <= 5);
|
||||
static const std::string adjacent_names[6] = {"n","ne","se","s","sw","nw"};
|
||||
const config::child_list& affect_adj = cfg.get_children("affect_adjacent");
|
||||
bool passed = false;
|
||||
for(config::child_list::const_iterator i = affect_adj.begin(); i != affect_adj.end(); ++i) {
|
||||
std::vector<std::string> dirs = utils::split((**i)["adjacent"]);
|
||||
if(std::find(dirs.begin(),dirs.end(),adjacent_names[dir]) != dirs.end()) {
|
||||
if((*i)->child("filter") != NULL) {
|
||||
if(matches_filter(*(*i)->child("filter"),loc,ability=="illuminates")) {
|
||||
passed = true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
passed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return passed;
|
||||
}
|
||||
/*
|
||||
*
|
||||
* cfg: an ability WML structure
|
||||
*
|
||||
*/
|
||||
bool unit::ability_affects_self(const std::string& ability,const config& cfg,const gamemap::location& loc) const
|
||||
{
|
||||
if(cfg.child("filter")==NULL) {
|
||||
if(cfg["affect_self"] == "yes") {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(cfg["affect_self"] == "yes") {
|
||||
return matches_filter(*cfg.child("filter"),loc,ability=="illuminates");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool unit_ability_list::empty() const
|
||||
{
|
||||
return cfgs.empty();
|
||||
}
|
||||
|
||||
std::pair<int,gamemap::location> unit_ability_list::highest(const std::string& key, int def) const
|
||||
{
|
||||
gamemap::location best_loc;
|
||||
int abs_max = def;
|
||||
int flat = def;
|
||||
int stack = 0;
|
||||
for(std::vector<std::pair<config*,gamemap::location> >::const_iterator i = cfgs.begin(); i != cfgs.end(); ++i) {
|
||||
if((*i->first)["cumulative"]=="yes") {
|
||||
stack += lexical_cast_default<int>((*i->first)[key]);
|
||||
if(lexical_cast_default<int>((*i->first)[key]) > abs_max) {
|
||||
abs_max = lexical_cast_default<int>((*i->first)[key]);
|
||||
best_loc = i->second;
|
||||
}
|
||||
} else {
|
||||
flat = maximum<int>(flat,lexical_cast_default<int>((*i->first)[key]));
|
||||
if(lexical_cast_default<int>((*i->first)[key]) > abs_max) {
|
||||
abs_max = lexical_cast_default<int>((*i->first)[key]);
|
||||
best_loc = i->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::pair<int,gamemap::location>(flat + stack,best_loc);
|
||||
}
|
||||
std::pair<int,gamemap::location> unit_ability_list::lowest(const std::string& key, int def) const
|
||||
{
|
||||
gamemap::location best_loc;
|
||||
int abs_max = def;
|
||||
int flat = def;
|
||||
int stack = 0;
|
||||
for(std::vector<std::pair<config*,gamemap::location> >::const_iterator i = cfgs.begin(); i != cfgs.end(); ++i) {
|
||||
if((*i->first)["cumulative"]=="yes") {
|
||||
stack += lexical_cast_default<int>((*i->first)[key]);
|
||||
if(lexical_cast_default<int>((*i->first)[key]) < abs_max) {
|
||||
abs_max = lexical_cast_default<int>((*i->first)[key]);
|
||||
best_loc = i->second;
|
||||
}
|
||||
} else {
|
||||
flat = minimum<int>(flat,lexical_cast_default<int>((*i->first)[key]));
|
||||
if(lexical_cast_default<int>((*i->first)[key]) < abs_max) {
|
||||
abs_max = lexical_cast_default<int>((*i->first)[key]);
|
||||
best_loc = i->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::pair<int,gamemap::location>(flat + stack,best_loc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* [special]
|
||||
* [swarm]
|
||||
* name= _ "swarm"
|
||||
* name_inactive= _ ""
|
||||
* description= _ ""
|
||||
* description_inactive= _ ""
|
||||
* cumulative=no
|
||||
* apply_to=self #self,opponent,defender,attacker
|
||||
* #active_on=defend .. offense
|
||||
*
|
||||
* attacks_max=4
|
||||
* attacks_min=2
|
||||
*
|
||||
* [filter_self] // SUF
|
||||
* ...
|
||||
* [/filter_self]
|
||||
* [filter_opponent] // SUF
|
||||
* [filter_attacker] // SUF
|
||||
* [filter_defender] // SUF
|
||||
* [filter_adjacent] // SAUF
|
||||
* [filter_adjacent_location] // SAUF + locs
|
||||
* [/swarm]
|
||||
* [/special]
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool attack_type::get_special_bool(const std::string& special,bool force) const
|
||||
{
|
||||
// log_scope("get_special_bool");
|
||||
const config* specials = cfg_.child("specials");
|
||||
if(specials) {
|
||||
const config::child_list& list = specials->get_children(special);
|
||||
for(config::child_list::const_iterator i = list.begin(); i != list.end(); ++i) {
|
||||
if(force || special_active(**i,true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!force && other_attack_ != NULL) {
|
||||
specials = other_attack_->cfg_.child("specials");
|
||||
if(specials) {
|
||||
const config::child_list& list = specials->get_children(special);
|
||||
for(config::child_list::const_iterator i = list.begin(); i != list.end(); ++i) {
|
||||
if(other_attack_->special_active(**i,false)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
weapon_special_list attack_type::get_specials(const std::string& special) const
|
||||
{
|
||||
// log_scope("get_specials");
|
||||
weapon_special_list res;
|
||||
const config* specials = cfg_.child("specials");
|
||||
if(specials) {
|
||||
const config::child_list& list = specials->get_children(special);
|
||||
for(config::child_list::const_iterator i = list.begin(); i != list.end(); ++i) {
|
||||
if(special_active(**i,true)) {
|
||||
res.cfgs.push_back(*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(other_attack_ != NULL) {
|
||||
specials = other_attack_->cfg_.child("specials");
|
||||
if(specials) {
|
||||
const config::child_list& list = specials->get_children(special);
|
||||
for(config::child_list::const_iterator i = list.begin(); i != list.end(); ++i) {
|
||||
if(other_attack_->special_active(**i,false)) {
|
||||
res.cfgs.push_back(*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
std::vector<std::string> attack_type::special_tooltips(bool force) const
|
||||
{
|
||||
// log_scope("special_tooltips");
|
||||
std::vector<std::string> res;
|
||||
const config* specials = cfg_.child("specials");
|
||||
if(specials) {
|
||||
const config::child_map& list_map = specials->all_children();
|
||||
for(config::child_map::const_iterator i = list_map.begin(); i != list_map.end(); ++i) {
|
||||
for(config::child_list::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
|
||||
if(force || special_active(**j,true)) {
|
||||
if((**j)["name"] != "") {
|
||||
res.push_back((**j)["name"]);
|
||||
res.push_back((**j)["description"]);
|
||||
}
|
||||
} else {
|
||||
if((**j)["name_inactive"] != "") {
|
||||
res.push_back((**j)["name_inactive"]);
|
||||
res.push_back((**j)["description_inactive"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
std::string attack_type::weapon_specials(bool force) const
|
||||
{
|
||||
// log_scope("weapon_specials");
|
||||
std::string res;
|
||||
const config* specials = cfg_.child("specials");
|
||||
if(specials) {
|
||||
const config::child_map& list_map = specials->all_children();
|
||||
for(config::child_map::const_iterator i = list_map.begin(); i != list_map.end(); ++i) {
|
||||
for(config::child_list::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
|
||||
if(force || special_active(**j,true)) {
|
||||
if((**j)["name"] != "") {
|
||||
res += (**j)["name"];
|
||||
res += ",";
|
||||
}
|
||||
} else {
|
||||
if((**j)["name_inactive"] != "") {
|
||||
res += (**j)["name_inactive"];
|
||||
res += ",";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res.substr(0,res.size()-1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* cfg: a weapon special WML structure
|
||||
*
|
||||
*/
|
||||
bool attack_type::special_active(const config& cfg,bool self) const
|
||||
{
|
||||
// log_scope("special_active");
|
||||
wassert(unitmap_ != NULL);
|
||||
unit_map::const_iterator att = unitmap_->find(aloc_);
|
||||
unit_map::const_iterator def = unitmap_->find(dloc_);
|
||||
|
||||
if(self) {
|
||||
if(!special_affects_self(cfg)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if(!special_affects_opponent(cfg)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(attacker_) {
|
||||
if(cfg["active_on"] != "" && cfg["active_on"] != "attacker") {
|
||||
return false;
|
||||
}
|
||||
if(cfg.child("filter_self") != NULL) {
|
||||
if(att == unitmap_->end() || !att->second.matches_filter(*cfg.child("filter_self"),aloc_)) {
|
||||
return false;
|
||||
}
|
||||
if(cfg.child("filter_self")->child("filter_weapon") != NULL) {
|
||||
if(!matches_filter(*cfg.child("filter_self")->child("filter_weapon"),0,true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(cfg.child("filter_opponent") != NULL) {
|
||||
if(def == unitmap_->end() || !def->second.matches_filter(*cfg.child("filter_opponent"),dloc_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(cfg.child("filter_opponent")->child("filter_weapon") != NULL) {
|
||||
if(!other_attack_ || other_attack_->matches_filter(*cfg.child("filter_opponent")->child("filter_weapon"),0,true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(cfg["active_on"] != "" && cfg["active_on"] != "defender") {
|
||||
return false;
|
||||
}
|
||||
if(cfg.child("filter_self") != NULL) {
|
||||
if(def == unitmap_->end() || !def->second.matches_filter(*cfg.child("filter_self"),dloc_)) {
|
||||
return false;
|
||||
}
|
||||
if(cfg.child("filter_self")->child("filter_weapon") != NULL) {
|
||||
if(!matches_filter(*cfg.child("filter_self")->child("filter_weapon"),0,true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(cfg.child("filter_opponent") != NULL) {
|
||||
if(att == unitmap_->end() || !att->second.matches_filter(*cfg.child("filter_opponent"),aloc_)) {
|
||||
return false;
|
||||
}
|
||||
if(cfg.child("filter_opponent")->child("filter_weapon") != NULL) {
|
||||
if(!other_attack_ || !other_attack_->matches_filter(*cfg.child("filter_opponent")->child("filter_weapon"),0,true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(cfg.child("filter_attacker") != NULL) {
|
||||
if(att == unitmap_->end() || !att->second.matches_filter(*cfg.child("filter_attacker"),aloc_)) {
|
||||
return false;
|
||||
}
|
||||
if(attacker_) {
|
||||
if(cfg.child("filter_attacker")->child("filter_weapon") != NULL) {
|
||||
if(!matches_filter(*cfg.child("filter_attacker")->child("filter_weapon"),0,true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(cfg.child("filter_attacker")->child("filter_weapon") != NULL) {
|
||||
if(!other_attack_ || !other_attack_->matches_filter(*cfg.child("filter_attacker")->child("filter_weapon"),0,true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(cfg.child("filter_defender") != NULL) {
|
||||
if(def == unitmap_->end() || !def->second.matches_filter(*cfg.child("filter_defender"),dloc_)) {
|
||||
return false;
|
||||
}
|
||||
if(!attacker_) {
|
||||
if(cfg.child("filter_defender")->child("filter_weapon") != NULL) {
|
||||
if(!matches_filter(*cfg.child("filter_defender")->child("filter_weapon"),0,true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(cfg.child("filter_defender")->child("filter_weapon") != NULL) {
|
||||
if(!other_attack_ || !other_attack_->matches_filter(*cfg.child("filter_defender")->child("filter_weapon"),0,true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
gamemap::location adjacent[6];
|
||||
if(attacker_) {
|
||||
get_adjacent_tiles(aloc_,adjacent);
|
||||
} else {
|
||||
get_adjacent_tiles(dloc_,adjacent);
|
||||
}
|
||||
int index=-1;
|
||||
const config::child_list& adj_filt = cfg.get_children("filter_adjacent");
|
||||
config::child_list::const_iterator i;
|
||||
for(i = adj_filt.begin(); i != adj_filt.end(); ++i) {
|
||||
std::vector<std::string> dirs = utils::split((**i)["adjacent"]);
|
||||
if(dirs.size()==1 && dirs.front()=="") {
|
||||
} else {
|
||||
for(std::vector<std::string>::const_iterator j = dirs.begin(); j != dirs.end(); ++j) {
|
||||
if(*j=="n") {
|
||||
index=0;
|
||||
} else if(*j=="ne") {
|
||||
index=1;
|
||||
} else if(*j=="se") {
|
||||
index=2;
|
||||
} else if(*j=="s") {
|
||||
index=3;
|
||||
} else if(*j=="sw") {
|
||||
index=4;
|
||||
} else if(*j=="nw") {
|
||||
index=5;
|
||||
} else {
|
||||
index=-1;
|
||||
}
|
||||
if(index != -1) {
|
||||
units_map::const_iterator unit = unitmap_->find(adjacent[index]);
|
||||
if(unit == unitmap_->end()) {
|
||||
return false;
|
||||
}
|
||||
if(!unit->second.matches_filter(**i,unit->first)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
index=-1;
|
||||
const config::child_list& adj_filt_loc = cfg.get_children("filter_adjacent_location");
|
||||
for(i = adj_filt_loc.begin(); i != adj_filt_loc.end(); ++i) {
|
||||
std::vector<std::string> dirs = utils::split((**i)["adjacent"]);
|
||||
if(dirs.size()==1 && dirs.front()=="") {
|
||||
} else {
|
||||
for(std::vector<std::string>::const_iterator j = dirs.begin(); j != dirs.end(); ++j) {
|
||||
if(*j=="n") {
|
||||
index=0;
|
||||
} else if(*j=="ne") {
|
||||
index=1;
|
||||
} else if(*j=="se") {
|
||||
index=2;
|
||||
} else if(*j=="s") {
|
||||
index=3;
|
||||
} else if(*j=="sw") {
|
||||
index=4;
|
||||
} else if(*j=="nw") {
|
||||
index=5;
|
||||
} else {
|
||||
index=-1;
|
||||
}
|
||||
if(index != -1) {
|
||||
wassert(map_ != NULL);
|
||||
wassert(game_status_ != NULL);
|
||||
if(!map_->terrain_matches_filter(adjacent[index],**i,*game_status_,*unitmap_)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
*
|
||||
* cfg: a weapon special WML structure
|
||||
*
|
||||
*/
|
||||
bool attack_type::special_affects_opponent(const config& cfg) const
|
||||
{
|
||||
// log_scope("special_affects_opponent");
|
||||
if(cfg["apply_to"]=="opponent") {
|
||||
return true;
|
||||
}
|
||||
if(cfg["apply_to"]!="") {
|
||||
if(attacker_ && cfg["apply_to"] == "defender") {
|
||||
return true;
|
||||
}
|
||||
if(!attacker_ && cfg["apply_to"] == "attacker") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
*
|
||||
* cfg: a weapon special WML structure
|
||||
*
|
||||
*/
|
||||
bool attack_type::special_affects_self(const config& cfg) const
|
||||
{
|
||||
// log_scope("special_affects_self");
|
||||
if(cfg["apply_to"]=="self" || cfg["apply_to"]=="") {
|
||||
return true;
|
||||
}
|
||||
if(attacker_ && cfg["apply_to"] == "attacker") {
|
||||
return true;
|
||||
}
|
||||
if(!attacker_ && cfg["apply_to"] == "defender") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void attack_type::set_specials_context(const gamemap::location& aloc,const gamemap::location& dloc,
|
||||
const game_data* gamedata, unit_map* unitmap,
|
||||
const gamemap* map, const gamestatus* game_status,
|
||||
const std::vector<team>* teams, bool attacker,attack_type* other_attack)
|
||||
{
|
||||
aloc_ = aloc;
|
||||
dloc_ = dloc;
|
||||
gamedata_ = gamedata;
|
||||
unitmap_ = unitmap;
|
||||
map_ = map;
|
||||
game_status_ = game_status;
|
||||
teams_ = teams;
|
||||
attacker_ = attacker;
|
||||
other_attack_ = other_attack;
|
||||
}
|
||||
|
||||
void attack_type::set_specials_context(const gamemap::location& loc,const unit& un)
|
||||
{
|
||||
aloc_ = loc;
|
||||
dloc_ = gamemap::location();
|
||||
gamedata_ = un.gamedata_;
|
||||
unitmap_ = un.units_;
|
||||
map_ = un.map_;
|
||||
game_status_ = un.gamestatus_;
|
||||
teams_ = un.teams_;
|
||||
attacker_ = true;
|
||||
other_attack_ = NULL;
|
||||
}
|
||||
|
||||
|
||||
bool weapon_special_list::empty() const
|
||||
{
|
||||
return cfgs.empty();
|
||||
}
|
||||
|
||||
int weapon_special_list::highest(const std::string& key, int def) const
|
||||
{
|
||||
int flat = def;
|
||||
int stack = 0;
|
||||
for(config::child_list::const_iterator i = cfgs.begin(); i != cfgs.end(); ++i) {
|
||||
if((**i)["cumulative"]=="yes") {
|
||||
stack += lexical_cast_default<int>((**i)[key]);
|
||||
} else {
|
||||
flat = maximum<int>(flat,lexical_cast_default<int>((**i)[key]));
|
||||
}
|
||||
}
|
||||
return flat + stack;
|
||||
}
|
||||
int weapon_special_list::lowest(const std::string& key, int def) const
|
||||
{
|
||||
int flat = def;
|
||||
int stack = 0;
|
||||
for(config::child_list::const_iterator i = cfgs.begin(); i != cfgs.end(); ++i) {
|
||||
if((**i)["cumulative"]=="yes") {
|
||||
stack += lexical_cast_default<int>((**i)[key]);
|
||||
} else {
|
||||
flat = minimum<int>(flat,lexical_cast_default<int>((**i)[key]));
|
||||
}
|
||||
}
|
||||
return flat + stack;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -147,10 +147,16 @@ int death_animation::matches(const attack_type* attack) const
|
|||
}
|
||||
|
||||
if(special.empty()== false) {
|
||||
if (std::find(special.begin(),special.end(),attack->special())== special.end()) {
|
||||
bool found = false;
|
||||
std::vector<std::string> at_specials = utils::split(attack->weapon_specials(true));
|
||||
for(std::vector<std::string>::const_iterator sp_it = special.begin(); sp_it != special.end(); ++sp_it) {
|
||||
if (std::find(at_specials.begin(),at_specials.end(),*sp_it) != at_specials.end()) {
|
||||
result ++;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if(!found) {
|
||||
return -1;
|
||||
} else {
|
||||
result ++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ void move_unit_between(display& disp, const gamemap& map, const gamemap::locatio
|
|||
gamemap::location dst_adjacent[6];
|
||||
get_adjacent_tiles(b, dst_adjacent);
|
||||
|
||||
const int total_mvt_time = 150 * u.movement_cost(map,dst_terrain)/acceleration;
|
||||
const int total_mvt_time = 150 * u.movement_cost(dst_terrain)/acceleration;
|
||||
const unsigned int start_time = SDL_GetTicks();
|
||||
int mvt_time = SDL_GetTicks() -start_time;
|
||||
disp.scroll_to_tiles(a.x,a.y,b.x,b.y,display::ONSCREEN);
|
||||
|
@ -164,7 +164,7 @@ void unit_die(display& disp, const gamemap &map,const gamemap::location& loc, un
|
|||
return;
|
||||
}
|
||||
|
||||
const std::string& die_sound = u.type().die_sound();
|
||||
const std::string& die_sound = u.die_sound();
|
||||
if(die_sound != "" && die_sound != "null") {
|
||||
sound::play_sound(die_sound);
|
||||
}
|
||||
|
@ -208,10 +208,6 @@ bool unit_attack_ranged(display& disp,const gamemap& map, unit_map& units,
|
|||
const int acceleration = disp.turbo() ? 5 : 1;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// more damage shown for longer, but 1s at most for this factor
|
||||
const double xsrc = disp.get_location_x(a);
|
||||
const double ysrc = disp.get_location_y(a);
|
||||
|
@ -251,7 +247,6 @@ bool unit_attack_ranged(display& disp,const gamemap& map, unit_map& units,
|
|||
const bool hflip = b.x < a.x;
|
||||
const unit_animation::FRAME_DIRECTION dir = (a.x == b.x) ? unit_animation::VERTICAL:unit_animation::DIAGONAL;
|
||||
|
||||
|
||||
defender.set_defending(disp,damage,attack.range());
|
||||
const int start_time = minimum<int>(minimum<int>(defender.get_animation()->get_first_frame_time(),
|
||||
missile_animation.get_first_frame_time()),-200);
|
||||
|
@ -288,10 +283,10 @@ bool unit_attack_ranged(display& disp,const gamemap& map, unit_map& units,
|
|||
animation_time = defender.get_animation()->get_animation_time();
|
||||
}
|
||||
if(damage > 0 && !hide) {
|
||||
sound::play_sound(def->second.type().get_hit_sound());
|
||||
sound::play_sound(def->second.get_hit_sound());
|
||||
disp.float_label(b,lexical_cast<std::string>(damage),255,0,0);
|
||||
}
|
||||
if(def->second.gets_hit(damage)) {
|
||||
if(def->second.take_hit(damage)) {
|
||||
dead = true;
|
||||
}
|
||||
|
||||
|
@ -356,7 +351,6 @@ bool unit_attack(display& disp, unit_map& units, const gamemap& map,
|
|||
end_time=maximum<int>(end_time,defender.get_animation()->get_last_frame_time());
|
||||
|
||||
|
||||
|
||||
const gamemap::location leader_loc = under_leadership(units,a);
|
||||
unit_map::iterator leader = units.end();
|
||||
if(leader_loc.valid()){
|
||||
|
@ -397,10 +391,10 @@ bool unit_attack(display& disp, unit_map& units, const gamemap& map,
|
|||
animation_time = attacker.get_animation()->get_animation_time();
|
||||
}
|
||||
if(damage > 0 && !hide) {
|
||||
sound::play_sound(def->second.type().get_hit_sound());
|
||||
sound::play_sound(def->second.get_hit_sound());
|
||||
disp.float_label(b,lexical_cast<std::string>(damage),255,0,0);
|
||||
}
|
||||
if(def->second.gets_hit(damage)) {
|
||||
if(def->second.take_hit(damage)) {
|
||||
dead = true;
|
||||
}
|
||||
while(!attacker.get_animation()->animation_finished() ||
|
||||
|
|
|
@ -27,8 +27,9 @@
|
|||
#include <iostream>
|
||||
|
||||
|
||||
attack_type::attack_type(const config& cfg,const unit_type& unit)
|
||||
attack_type::attack_type(const config& cfg,const std::string& id, const std::string& image_fighting)
|
||||
{
|
||||
cfg_ = cfg;
|
||||
if(cfg["range"] == "long" || cfg["range"] == "ranged") {
|
||||
range_type_ = LONG_RANGE;
|
||||
} else {
|
||||
|
@ -40,13 +41,13 @@ attack_type::attack_type(const config& cfg,const unit_type& unit)
|
|||
}
|
||||
|
||||
if(cfg.child("frame") || cfg.child("missile_frame") || cfg.child("sound")) {
|
||||
LOG_STREAM(err, config) << "the animation for " << cfg["name"] << "in unit " << unit.id() << " is directly in the attack, please use [animation]\n" ;
|
||||
LOG_STREAM(err, config) << "the animation for " << cfg["name"] << "in unit " << id << " is directly in the attack, please use [animation]\n" ;
|
||||
}
|
||||
if(animation_.empty()) {
|
||||
animation_.push_back(attack_animation(cfg));
|
||||
}
|
||||
if(animation_.empty()) {
|
||||
animation_.push_back(attack_animation(unit.image_fighting(range_type_)));
|
||||
animation_.push_back(attack_animation(image_fighting));
|
||||
}
|
||||
assert(!animation_.empty());
|
||||
|
||||
|
@ -56,9 +57,6 @@ attack_type::attack_type(const config& cfg,const unit_type& unit)
|
|||
description_ = egettext(id_.c_str());
|
||||
|
||||
type_ = cfg["type"];
|
||||
special_ = cfg["special"];
|
||||
backstab_ = special_ == "backstab";
|
||||
slow_ = special_ == "slow";
|
||||
icon_ = cfg["icon"];
|
||||
if(icon_.empty())
|
||||
icon_ = "attacks/" + id_ + ".png";
|
||||
|
@ -69,6 +67,28 @@ attack_type::attack_type(const config& cfg,const unit_type& unit)
|
|||
|
||||
attack_weight_ = lexical_cast_default<double>(cfg["attack_weight"],1.0);
|
||||
defense_weight_ = lexical_cast_default<double>(cfg["defense_weight"],1.0);
|
||||
|
||||
gamedata_=NULL;
|
||||
unitmap_=NULL;
|
||||
map_=NULL;
|
||||
game_status_=NULL;
|
||||
teams_=NULL;
|
||||
other_attack_=NULL;
|
||||
|
||||
// BACKWARDS COMPATIBILITY
|
||||
const std::string& set_special = cfg["special"];
|
||||
if(set_special != "") {
|
||||
LOG_STREAM(err, config) << "[attack] uses special=" << set_special <<", which is now deprecated. Use the macros provided in abilities.cfg.\n";
|
||||
config new_specials;
|
||||
|
||||
new_specials["set_special"] = set_special;
|
||||
apply_modification(new_specials,NULL,0);
|
||||
}
|
||||
}
|
||||
|
||||
const config& attack_type::get_cfg() const
|
||||
{
|
||||
return cfg_;
|
||||
}
|
||||
|
||||
const t_string& attack_type::name() const
|
||||
|
@ -86,11 +106,6 @@ const std::string& attack_type::type() const
|
|||
return type_;
|
||||
}
|
||||
|
||||
const std::string& attack_type::special() const
|
||||
{
|
||||
return special_;
|
||||
}
|
||||
|
||||
const std::string& attack_type::icon() const
|
||||
{
|
||||
return icon_;
|
||||
|
@ -116,15 +131,6 @@ int attack_type::num_attacks() const
|
|||
return num_attacks_;
|
||||
}
|
||||
|
||||
int attack_type::num_swarm_attacks(int hp, int maxhp) const
|
||||
{
|
||||
if(special() == "swarm"){
|
||||
return (num_attacks_ - (num_attacks_ * (maxhp-hp) / maxhp));
|
||||
}else{
|
||||
return (num_attacks_);
|
||||
}
|
||||
}
|
||||
|
||||
double attack_type::attack_weight() const
|
||||
{
|
||||
return attack_weight_;
|
||||
|
@ -135,14 +141,10 @@ double attack_type::defense_weight() const
|
|||
return defense_weight_;
|
||||
}
|
||||
|
||||
bool attack_type::backstab() const
|
||||
{
|
||||
return backstab_;
|
||||
}
|
||||
|
||||
bool attack_type::slow() const
|
||||
int attack_type::movement_used() const
|
||||
{
|
||||
return slow_;
|
||||
return cfg_["movement_used"] == "" ? 100000 : lexical_cast_default<int>(cfg_["movement_used"]);
|
||||
}
|
||||
|
||||
const attack_type::attack_animation& attack_type::animation(bool hit,const gamemap::location::DIRECTION dir) const
|
||||
|
@ -205,7 +207,7 @@ int attack_type::attack_animation::matches(bool hit,gamemap::location::DIRECTION
|
|||
|
||||
return result;
|
||||
}
|
||||
bool attack_type::matches_filter(const config& cfg) const
|
||||
bool attack_type::matches_filter(const config& cfg,int set_,bool self) const
|
||||
{
|
||||
const std::string& filter_range = cfg["range"];
|
||||
const t_string& filter_name = cfg["name"];
|
||||
|
@ -221,15 +223,15 @@ bool attack_type::matches_filter(const config& cfg) const
|
|||
if(filter_type.empty() == false && filter_type != type())
|
||||
return false;
|
||||
|
||||
if(filter_special.empty() == false && filter_special != special())
|
||||
if(!self && filter_special.empty() == false && !get_special_bool(filter_special,true))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool attack_type::apply_modification(const config& cfg, std::string* description)
|
||||
bool attack_type::apply_modification(const config& cfg,std::string* description,int set_)
|
||||
{
|
||||
if(!matches_filter(cfg))
|
||||
if(!matches_filter(cfg,0))
|
||||
return false;
|
||||
|
||||
const t_string& set_name = cfg["set_name"];
|
||||
|
@ -252,7 +254,79 @@ bool attack_type::apply_modification(const config& cfg, std::string* description
|
|||
}
|
||||
|
||||
if(set_special.empty() == false) {
|
||||
special_ = set_special;
|
||||
cfg_.clear_children("specials");
|
||||
config new_specials;
|
||||
if(set_special == "berserk") {
|
||||
config& sp = new_specials.add_child("berserk");
|
||||
sp["name"] = t_string("berserk","wesnoth");
|
||||
sp["description"] = t_string("Berserk:\nWhether used offensively or defensively, this attack presses the engagement until one of the combatants is slain, or 30 rounds of attacks have occurred.","wesnoth");
|
||||
sp["cumulative"] = "no";
|
||||
sp["rounds"] = "30";
|
||||
} else if(set_special == "backstab") {
|
||||
config& sp = new_specials.add_child("damage");
|
||||
sp["name"] = t_string("backstab","wesnoth");
|
||||
sp["description"] = t_string("Backstab:\nThis attack deals double damage if there is an enemy of the target on the opposite side of the target, and that unit is not incapacitated (e.g. turned to stone).","wesnoth");
|
||||
sp["cumulative"] = "no";
|
||||
sp["backstab"] = "yes";
|
||||
sp["multiply"] = "2";
|
||||
sp["active_on"] = "offense";
|
||||
} else if(set_special == "plague") {
|
||||
config& sp = new_specials.add_child("plague");
|
||||
sp["name"] = t_string("plague","wesnoth");
|
||||
sp["description"] = t_string("Plague:\nWhen a unit is killed by a Plague attack, that unit is replaced with a unit identical to and on the same side as the unit with the Plague attack. (This doesn't work on Undead or units in villages.)","wesnoth");
|
||||
} else if(set_special.substr(0,7) == "plague(") {
|
||||
config& sp = new_specials.add_child("plague");
|
||||
sp["name"] = t_string("plague","wesnoth") + set_special.substr(6,set_special.size());
|
||||
sp["description"] = t_string("Plague:\nWhen a unit is killed by a Plague attack, that unit is replaced with a unit of the specified type on the same side as the unit with the Plague attack. (This doesn't work on Undead or units in villages.)","wesnoth");
|
||||
sp["type"] = set_special.substr(7,set_special.size()-1);
|
||||
} else if(set_special == "swarm") {
|
||||
config& sp = new_specials.add_child("attacks");
|
||||
sp["name"] = t_string("swarm","wesnoth");
|
||||
sp["description"] = t_string("Swarm:\nThe number of strikes of this attack decreases when the unit is wounded. The number of strikes is proportional to the % of HP/maximum HP the unit has. For example a unit with 3/4 of its maximum HP will get 3/4 of the number of strikes.","wesnoth");
|
||||
} else if(set_special == "slow") {
|
||||
config& sp = new_specials.add_child("slow");
|
||||
sp["name"] = t_string("slows","wesnoth");
|
||||
sp["description"] = t_string("Slow:\nThis attack slows the target. Slow halves the damage caused by attacks and slowed units move at half the normal speed (rounded up).","wesnoth");
|
||||
sp["cumulative"] = "no";
|
||||
} else if(set_special == "stone") {
|
||||
config& sp = new_specials.add_child("stones");
|
||||
sp["name"] = t_string("stones","wesnoth");
|
||||
sp["description"] = t_string("Stone:\nThis attack turns the target to stone. Units that have been turned to stone may not move or attack.","wesnoth");
|
||||
} else if(set_special == "marksman") {
|
||||
config& sp = new_specials.add_child("chance_to_hit");
|
||||
sp["name"] = t_string("marksman","wesnoth");
|
||||
sp["description"] = t_string("Marksman:\nWhen used offensively, this attack always has at least a 60% chance to hit.","wesnoth");
|
||||
sp["value"] = "60";
|
||||
sp["cumulative"] = "yes";
|
||||
sp["active_on"] = "offense";
|
||||
} else if(set_special == "magical") {
|
||||
config& sp = new_specials.add_child("chance_to_hit");
|
||||
sp["name"] = t_string("magical","wesnoth");
|
||||
sp["description"] = t_string("Magical:\nThis attack always has a 70% chance to hit.","wesnoth");
|
||||
sp["value"] = "70";
|
||||
sp["cumulative"] = "no";
|
||||
} else if(set_special == "charge") {
|
||||
config& sp = new_specials.add_child("damage");
|
||||
sp["name"] = t_string("charge","wesnoth");
|
||||
sp["description"] = t_string("Charge:\nThis attack deals double damage to the target. It also causes this unit to take double damage from the target's counterattack.","wesnoth");
|
||||
sp["cumulative"] = "no";
|
||||
sp["multiply"] = "2";
|
||||
sp["active_on"] = "offense";
|
||||
sp["apply_to"] = "self,opponent";
|
||||
} else if(set_special == "drain") {
|
||||
config& sp = new_specials.add_child("drains");
|
||||
sp["name"] = t_string("drains","wesnoth");
|
||||
sp["description"] = t_string("Drain:\nThis unit drains health from living units, healing itself for half the amount of damage it deals (rounded down).","wesnoth");
|
||||
} else if(set_special == "firststrike") {
|
||||
config& sp = new_specials.add_child("firststrike");
|
||||
sp["name"] = t_string("firststrike","wesnoth");
|
||||
sp["description"] = t_string("Firststrike:\nThis unit always strikes first with this attack, even if they are defending.","wesnoth");
|
||||
} else if(set_special == "poison") {
|
||||
config& sp = new_specials.add_child("poison");
|
||||
sp["name"] = t_string("poison","wesnoth");
|
||||
sp["description"] = t_string("Poison:\nThis attack poisons the target. Poisoned units lose 8 HP every turn until they are cured or are reduced to 1 HP.","wesnoth");
|
||||
}
|
||||
cfg_.add_child("specials",new_specials);
|
||||
}
|
||||
|
||||
if(increase_damage.empty() == false) {
|
||||
|
@ -492,11 +566,30 @@ bool unit_movement_type::is_flying() const
|
|||
return flies == "true";
|
||||
}
|
||||
|
||||
const config& unit_movement_type::get_cfg() const
|
||||
{
|
||||
return cfg_;
|
||||
}
|
||||
const unit_movement_type* unit_movement_type::get_parent() const
|
||||
{
|
||||
return parent_;
|
||||
}
|
||||
|
||||
void unit_movement_type::set_parent(const unit_movement_type* parent)
|
||||
{
|
||||
parent_ = parent;
|
||||
}
|
||||
|
||||
const std::map<gamemap::TERRAIN,int>& unit_movement_type::movement_costs() const
|
||||
{
|
||||
return moveCosts_;
|
||||
}
|
||||
const std::map<gamemap::TERRAIN,int>& unit_movement_type::defense_mods() const
|
||||
{
|
||||
return defenseMods_;
|
||||
}
|
||||
|
||||
|
||||
ability_filter::ability_filter()
|
||||
{
|
||||
// we add a null string to prevent the filter to be empty
|
||||
|
@ -603,17 +696,6 @@ void ability_filter::add_filters(const config* cfg)
|
|||
unit_type::unit_type(const unit_type& o)
|
||||
: variations_(o.variations_), cfg_(o.cfg_), race_(o.race_),
|
||||
alpha_(o.alpha_), abilities_(o.abilities_),ability_tooltips_(o.ability_tooltips_),
|
||||
heals_(o.heals_), cures_(o.cures_),
|
||||
regenerates_filter_(o.regenerates_filter_),regenerates_(o.regenerates_),
|
||||
regeneration_(o.regeneration_),
|
||||
leadership_filter_(o.leadership_filter_), leadership_(o.leadership_),
|
||||
leadership_percent_(o.leadership_percent_),
|
||||
illuminates_filter_(o.illuminates_filter_), illuminates_(o.illuminates_),
|
||||
skirmisher_filter_(o.skirmisher_filter_), skirmish_(o.skirmish_),
|
||||
teleports_filter_(o.teleports_filter_), teleport_(o.teleport_),
|
||||
steadfast_filter_(o.steadfast_filter_), steadfast_(o.steadfast_),
|
||||
steadfast_bonus_(o.steadfast_bonus_),steadfast_max_(o.steadfast_max_),
|
||||
hides_filter_(o.hides_filter_), hides_(o.hides_),
|
||||
advances_to_(o.advances_to_), experience_needed_(o.experience_needed_),
|
||||
alignment_(o.alignment_),
|
||||
movementType_(o.movementType_), possibleTraits_(o.possibleTraits_),
|
||||
|
@ -707,223 +789,15 @@ unit_type::unit_type(const config& cfg, const movement_type_map& mv_types,
|
|||
const config::child_list& unit_traits = cfg.get_children("trait");
|
||||
possibleTraits_.insert(possibleTraits_.end(),unit_traits.begin(),unit_traits.end());
|
||||
|
||||
heals_ = 0;
|
||||
cures_ = false;
|
||||
regenerates_ = false;
|
||||
regeneration_ = 0;
|
||||
steadfast_ = false;
|
||||
steadfast_bonus_ = 0;
|
||||
steadfast_max_ = 0;
|
||||
skirmish_ = false;
|
||||
teleport_ = false;
|
||||
illuminates_ = 0;
|
||||
leadership_ = false;
|
||||
hides_ = false;
|
||||
|
||||
/* handle deprecated ability=x,y,... */
|
||||
|
||||
std::vector<std::string> deprecated_abilities = utils::split(cfg_["ability"]);
|
||||
|
||||
//if the string was empty, split will give us one empty string in the list,
|
||||
//remove it.
|
||||
if(!deprecated_abilities.empty() && deprecated_abilities.back() == "") {
|
||||
deprecated_abilities.pop_back();
|
||||
}
|
||||
|
||||
if(!deprecated_abilities.empty()) {
|
||||
LOG_STREAM(err, config) << "unit " << id() << " uses the ability=list tag, which is deprecated\n";
|
||||
if(std::find(deprecated_abilities.begin(),deprecated_abilities.end(),"heals") != deprecated_abilities.end()) {
|
||||
heals_ = 4;
|
||||
abilities_.push_back("heals");
|
||||
ability_tooltips_.push_back("heals4");
|
||||
}
|
||||
if(std::find(deprecated_abilities.begin(),deprecated_abilities.end(),"cures") != deprecated_abilities.end()) {
|
||||
heals_ = 8;
|
||||
cures_ = true;
|
||||
abilities_.push_back("heals");
|
||||
ability_tooltips_.push_back("heals8");
|
||||
abilities_.push_back("cures");
|
||||
ability_tooltips_.push_back("cures");
|
||||
}
|
||||
if(std::find(deprecated_abilities.begin(),deprecated_abilities.end(),"regenerates") != deprecated_abilities.end()) {
|
||||
regenerates_ = true;
|
||||
regeneration_ = 8;
|
||||
regenerates_filter_.unfilter();
|
||||
abilities_.push_back("regenerates");
|
||||
ability_tooltips_.push_back("regenerates");
|
||||
}
|
||||
if(std::find(deprecated_abilities.begin(),deprecated_abilities.end(),"steadfast") != deprecated_abilities.end()) {
|
||||
steadfast_ = true;
|
||||
steadfast_bonus_ = 100;
|
||||
steadfast_max_ = 50;
|
||||
steadfast_percent_ = true;
|
||||
steadfast_filter_.unfilter();
|
||||
abilities_.push_back("steadfast");
|
||||
ability_tooltips_.push_back("steadfast");
|
||||
}
|
||||
if(std::find(deprecated_abilities.begin(),deprecated_abilities.end(),"teleport") != deprecated_abilities.end()) {
|
||||
teleport_ = true;
|
||||
teleports_filter_.unfilter();
|
||||
abilities_.push_back("teleport");
|
||||
ability_tooltips_.push_back("teleport");
|
||||
}
|
||||
if(std::find(deprecated_abilities.begin(),deprecated_abilities.end(),"skirmisher") != deprecated_abilities.end()) {
|
||||
skirmish_ = true;
|
||||
skirmisher_filter_.unfilter();
|
||||
abilities_.push_back("skirmisher");
|
||||
ability_tooltips_.push_back("skirmisher");
|
||||
}
|
||||
if(std::find(deprecated_abilities.begin(),deprecated_abilities.end(),"leadership") != deprecated_abilities.end()) {
|
||||
leadership_ = true;
|
||||
leadership_percent_ = game_config::leadership_bonus;
|
||||
leadership_filter_.unfilter();
|
||||
abilities_.push_back("leadership");
|
||||
ability_tooltips_.push_back("leadership");
|
||||
}
|
||||
if(std::find(deprecated_abilities.begin(),deprecated_abilities.end(),"illuminates") != deprecated_abilities.end()) {
|
||||
illuminates_ = 1;
|
||||
illuminates_filter_.unfilter();
|
||||
abilities_.push_back("illuminates");
|
||||
ability_tooltips_.push_back("illuminates");
|
||||
}
|
||||
if(std::find(deprecated_abilities.begin(),deprecated_abilities.end(),"ambush") != deprecated_abilities.end()) {
|
||||
hides_ = true;
|
||||
hides_filter_.add_terrain_filter("f");
|
||||
abilities_.push_back("ambush");
|
||||
ability_tooltips_.push_back("ambush");
|
||||
}
|
||||
if(std::find(deprecated_abilities.begin(),deprecated_abilities.end(),"nightstalk") != deprecated_abilities.end()) {
|
||||
hides_ = true;
|
||||
hides_filter_.add_tod_filter("chaotic");
|
||||
abilities_.push_back("nightstalk");
|
||||
ability_tooltips_.push_back("nightstalk");
|
||||
}
|
||||
}
|
||||
|
||||
const config* abil_cfg = cfg.child("abilities");
|
||||
if(abil_cfg) {
|
||||
const config::child_list& heal_abilities = abil_cfg->get_children("heals");
|
||||
if (!heal_abilities.empty()) {
|
||||
abilities_.push_back("heals");
|
||||
for(config::child_list::const_iterator ab = heal_abilities.begin(); ab != heal_abilities.end(); ++ab) {
|
||||
if((**ab)["description"] != "") {
|
||||
ability_tooltips_.push_back((**ab)["description"]);
|
||||
} else {
|
||||
ability_tooltips_.push_back("heals");
|
||||
const config::child_map& abi = abil_cfg->all_children();
|
||||
for(config::child_map::const_iterator j = abi.begin(); j != abi.end(); ++j) {
|
||||
for(config::child_list::const_iterator k = j->second.begin(); k != j->second.end(); ++k) {
|
||||
if((**k)["name"] != "") {
|
||||
abilities_.push_back((**k)["name"]);
|
||||
ability_tooltips_.push_back((**k)["description"]);
|
||||
}
|
||||
if ((**ab)["amount"] == "")
|
||||
LOG_STREAM(err, config) << "unit " << id() << " uses the [heals] tag without amount=\n";
|
||||
|
||||
heals_ = maximum<int>(heals_, lexical_cast<int>((**ab)["amount"]));
|
||||
}
|
||||
}
|
||||
const config::child_list& cure_abilities = abil_cfg->get_children("cures");
|
||||
if (!cure_abilities.empty()) {
|
||||
abilities_.push_back("cures");
|
||||
ability_tooltips_.push_back("cures");
|
||||
cures_ = true;
|
||||
}
|
||||
const config::child_list& regenerate_abilities = abil_cfg->get_children("regenerates");
|
||||
if (!regenerate_abilities.empty()) {
|
||||
abilities_.push_back("regenerates");
|
||||
for(config::child_list::const_iterator ab = regenerate_abilities.begin(); ab != regenerate_abilities.end(); ++ab) {
|
||||
if((**ab)["description"] != "") {
|
||||
ability_tooltips_.push_back((**ab)["description"]);
|
||||
} else {
|
||||
ability_tooltips_.push_back("regenerates");
|
||||
}
|
||||
regenerates_ = true;
|
||||
if ((**ab)["amount"] == "")
|
||||
LOG_STREAM(err, config) << "unit " << id() << " uses the [regenerates] tag without amount=\n";
|
||||
regeneration_ = maximum<int>(regeneration_, lexical_cast<int>((**ab)["amount"]));
|
||||
regenerates_filter_.add_filters((*ab)->child("filter"));
|
||||
}
|
||||
}
|
||||
const config::child_list& steadfast_abilities = abil_cfg->get_children("steadfast");
|
||||
if (!steadfast_abilities.empty()) {
|
||||
abilities_.push_back("steadfast");
|
||||
for(config::child_list::const_iterator ab = steadfast_abilities.begin(); ab != steadfast_abilities.end(); ++ab) {
|
||||
if((**ab)["description"] != "") {
|
||||
ability_tooltips_.push_back((**ab)["description"]);
|
||||
} else {
|
||||
ability_tooltips_.push_back("steadfast");
|
||||
}
|
||||
steadfast_ = true;
|
||||
steadfast_bonus_ = maximum<int>(steadfast_bonus_,lexical_cast_default<int>((**ab)["bonus"],100));
|
||||
steadfast_max_ = maximum<int>(steadfast_max_,lexical_cast_default<int>((**ab)["max"],50));
|
||||
std::string steadfast_ispercent = (**ab)["bonus"];
|
||||
if(steadfast_ispercent != "" && steadfast_ispercent[steadfast_ispercent.size()-1] == '%') {
|
||||
steadfast_percent_ = true;
|
||||
} else {
|
||||
steadfast_percent_ = false;
|
||||
}
|
||||
steadfast_filter_.add_filters((*ab)->child("filter"));
|
||||
}
|
||||
}
|
||||
const config::child_list& leadership_abilities = abil_cfg->get_children("leadership");
|
||||
if (!leadership_abilities.empty()) {
|
||||
abilities_.push_back("leadership");
|
||||
for(config::child_list::const_iterator ab = leadership_abilities.begin(); ab != leadership_abilities.end(); ++ab) {
|
||||
if((**ab)["description"] != "") {
|
||||
ability_tooltips_.push_back((**ab)["description"]);
|
||||
} else {
|
||||
ability_tooltips_.push_back("leadership");
|
||||
}
|
||||
leadership_ = true;
|
||||
leadership_percent_ = lexical_cast_default<int>((**ab)["perlevel_bonus"],game_config::leadership_bonus);
|
||||
leadership_filter_.add_filters((*ab)->child("filter"));
|
||||
}
|
||||
}
|
||||
const config::child_list& skirmisher_abilities = abil_cfg->get_children("skirmisher");
|
||||
if (!skirmisher_abilities.empty()) {
|
||||
abilities_.push_back("skirmisher");
|
||||
for(config::child_list::const_iterator ab = skirmisher_abilities.begin(); ab != skirmisher_abilities.end(); ++ab) {
|
||||
if((**ab)["description"] != "") {
|
||||
ability_tooltips_.push_back((**ab)["description"]);
|
||||
} else {
|
||||
ability_tooltips_.push_back("skirmisher");
|
||||
}
|
||||
skirmish_ = true;
|
||||
skirmisher_filter_.add_filters((*ab)->child("filter"));
|
||||
}
|
||||
}
|
||||
const config::child_list& illuminate_abilities = abil_cfg->get_children("illuminates");
|
||||
if (!illuminate_abilities.empty()) {
|
||||
abilities_.push_back("illuminates");
|
||||
for(config::child_list::const_iterator ab = illuminate_abilities.begin(); ab != illuminate_abilities.end(); ++ab) {
|
||||
if((**ab)["description"] != "") {
|
||||
ability_tooltips_.push_back((**ab)["description"]);
|
||||
} else {
|
||||
ability_tooltips_.push_back("illuminates");
|
||||
}
|
||||
illuminates_ += lexical_cast_default<int>((**ab)["level"],1);
|
||||
illuminates_filter_.add_filters((*ab)->child("filter"));
|
||||
}
|
||||
}
|
||||
const config::child_list& teleport_abilities = abil_cfg->get_children("teleport");
|
||||
if (!teleport_abilities.empty()) {
|
||||
abilities_.push_back("teleport");
|
||||
for(config::child_list::const_iterator ab = teleport_abilities.begin(); ab != teleport_abilities.end(); ++ab) {
|
||||
if((**ab)["description"] != "") {
|
||||
ability_tooltips_.push_back((**ab)["description"]);
|
||||
} else {
|
||||
ability_tooltips_.push_back("teleport");
|
||||
}
|
||||
teleport_ = true;
|
||||
teleports_filter_.add_filters((*ab)->child("filter"));
|
||||
}
|
||||
}
|
||||
const config::child_list& hide_abilities = abil_cfg->get_children("hides");
|
||||
if (!hide_abilities.empty()) {
|
||||
abilities_.push_back("hides");
|
||||
for(config::child_list::const_iterator ab = hide_abilities.begin(); ab != hide_abilities.end(); ++ab) {
|
||||
if((**ab)["description"] != "") {
|
||||
ability_tooltips_.push_back((**ab)["description"]);
|
||||
} else {
|
||||
ability_tooltips_.push_back("hides");
|
||||
}
|
||||
hides_ = true;
|
||||
hides_filter_.add_filters((*ab)->child("filter"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1200,7 +1074,7 @@ std::vector<attack_type> unit_type::attacks() const
|
|||
std::vector<attack_type> res;
|
||||
for(config::const_child_itors range = cfg_.child_range("attack");
|
||||
range.first != range.second; ++range.first) {
|
||||
res.push_back(attack_type(**range.first,*this));
|
||||
res.push_back(attack_type(**range.first,id(),image_fighting((**range.first)["range"] == "ranged" ? attack_type::LONG_RANGE : attack_type::SHORT_RANGE)));
|
||||
}
|
||||
|
||||
return res;
|
||||
|
@ -1301,78 +1175,6 @@ const std::vector<std::string>& unit_type::ability_tooltips() const
|
|||
return ability_tooltips_;
|
||||
}
|
||||
|
||||
int unit_type::heals() const
|
||||
{
|
||||
return heals_;
|
||||
}
|
||||
|
||||
bool unit_type::cures() const
|
||||
{
|
||||
return cures_;
|
||||
}
|
||||
|
||||
bool unit_type::regenerates() const
|
||||
{
|
||||
return regenerates_;
|
||||
}
|
||||
|
||||
int unit_type::regenerate_amount() const
|
||||
{
|
||||
return regeneration_;
|
||||
}
|
||||
|
||||
|
||||
bool unit_type::is_leader() const
|
||||
{
|
||||
return leadership_;
|
||||
}
|
||||
|
||||
int unit_type::leadership(int led_level) const
|
||||
{
|
||||
char key[24]; // level[x]
|
||||
snprintf(key,sizeof(key),"level_%d",led_level);
|
||||
const config* abilities=cfg_.child("abilities");
|
||||
const config* leadership_ability=abilities ? abilities->child("leadership") : NULL;
|
||||
if(leadership_ability) {
|
||||
if((*leadership_ability)[key] != "") {
|
||||
return lexical_cast_default<int>((*leadership_ability)[key]);
|
||||
}
|
||||
}
|
||||
return maximum<int>(0,leadership_percent_*(level()-led_level));
|
||||
}
|
||||
|
||||
int unit_type::illuminates() const
|
||||
{
|
||||
return illuminates_;
|
||||
}
|
||||
|
||||
bool unit_type::is_skirmisher() const
|
||||
{
|
||||
return skirmish_;
|
||||
}
|
||||
|
||||
bool unit_type::teleports() const
|
||||
{
|
||||
return teleport_;
|
||||
}
|
||||
|
||||
bool unit_type::steadfast() const
|
||||
{
|
||||
return steadfast_;
|
||||
}
|
||||
|
||||
int unit_type::steadfast_bonus() const
|
||||
{
|
||||
return steadfast_bonus_;
|
||||
}
|
||||
int unit_type::steadfast_max() const
|
||||
{
|
||||
return steadfast_max_;
|
||||
}
|
||||
bool unit_type::steadfast_ispercent() const
|
||||
{
|
||||
return steadfast_percent_;
|
||||
}
|
||||
|
||||
bool unit_type::not_living() const
|
||||
{
|
||||
|
@ -1414,34 +1216,6 @@ const std::string& unit_type::race() const
|
|||
return race_->name();
|
||||
}
|
||||
|
||||
const ability_filter unit_type::regenerates_filter() const
|
||||
{
|
||||
return regenerates_filter_;
|
||||
}
|
||||
const ability_filter unit_type::leadership_filter() const
|
||||
{
|
||||
return leadership_filter_;
|
||||
}
|
||||
const ability_filter unit_type::illuminates_filter() const
|
||||
{
|
||||
return illuminates_filter_;
|
||||
}
|
||||
const ability_filter unit_type::skirmisher_filter() const
|
||||
{
|
||||
return skirmisher_filter_;
|
||||
}
|
||||
const ability_filter unit_type::teleports_filter() const
|
||||
{
|
||||
return teleports_filter_;
|
||||
}
|
||||
const ability_filter unit_type::steadfast_filter() const
|
||||
{
|
||||
return steadfast_filter_;
|
||||
}
|
||||
const ability_filter unit_type::hides_filter() const
|
||||
{
|
||||
return hides_filter_;
|
||||
}
|
||||
|
||||
const defensive_animation& unit_type::defend_animation(bool hits, std::string range) const
|
||||
{
|
||||
|
|
|
@ -25,6 +25,24 @@
|
|||
|
||||
|
||||
class unit_type;
|
||||
class unit;
|
||||
struct game_data;
|
||||
class gamestatus;
|
||||
class team;
|
||||
typedef std::map<gamemap::location,unit> unit_map;
|
||||
class weapon_special_list
|
||||
{
|
||||
public:
|
||||
|
||||
bool empty() const;
|
||||
|
||||
int highest(const std::string& key, int def=0) const;
|
||||
int lowest(const std::string& key, int def=100) const;
|
||||
|
||||
config::child_list cfgs;
|
||||
private:
|
||||
|
||||
};
|
||||
//the 'attack type' is the type of attack, how many times it strikes,
|
||||
//and how much damage it does.
|
||||
class attack_type
|
||||
|
@ -32,28 +50,51 @@ class attack_type
|
|||
public:
|
||||
enum RANGE { SHORT_RANGE, LONG_RANGE };
|
||||
|
||||
attack_type(const config& cfg, const unit_type& unit);
|
||||
attack_type(const config& cfg, const std::string& id, const std::string& image_fighting);
|
||||
const t_string& name() const;
|
||||
const std::string& id() const;
|
||||
const std::string& type() const;
|
||||
const std::string& special() const;
|
||||
const std::string& icon() const;
|
||||
RANGE range_type() const;
|
||||
const std::string& range() const;
|
||||
int damage() const;
|
||||
int num_attacks() const;
|
||||
int num_swarm_attacks(int hp, int maxhp) const;
|
||||
double attack_weight() const;
|
||||
double defense_weight() const;
|
||||
|
||||
bool backstab() const;
|
||||
bool slow() const;
|
||||
|
||||
|
||||
bool get_special_bool(const std::string& special,bool force=false) const;
|
||||
weapon_special_list get_specials(const std::string& special) const;
|
||||
std::vector<std::string> special_tooltips(bool force=false) const;
|
||||
std::string weapon_specials(bool force=false) const;
|
||||
void set_specials_context(const gamemap::location& aloc,const gamemap::location& dloc,
|
||||
const game_data* gamedata, unit_map* unitmap,
|
||||
const gamemap* map, const gamestatus* game_status,
|
||||
const std::vector<team>* teams,bool attacker,attack_type* other_attack);
|
||||
void set_specials_context(const gamemap::location& loc,const unit& un);
|
||||
//this function returns a random animation out of the possible
|
||||
//animations for this attack. It will not return the same attack
|
||||
//each time.
|
||||
bool matches_filter(const config& cfg) const;
|
||||
bool apply_modification(const config& cfg,std::string* description);
|
||||
bool matches_filter(const config& cfg,int set_,bool self=false) const;
|
||||
bool apply_modification(const config& cfg,std::string* description,int set_);
|
||||
|
||||
int movement_used() const;
|
||||
|
||||
const config& get_cfg() const;
|
||||
gamemap::location aloc_,dloc_;
|
||||
bool attacker_;
|
||||
const game_data* gamedata_;
|
||||
mutable unit_map* unitmap_;
|
||||
const gamemap* map_;
|
||||
const gamestatus* game_status_;
|
||||
const std::vector<team>* teams_;
|
||||
mutable attack_type* other_attack_;
|
||||
/*
|
||||
* cfg: a weapon special WML structure
|
||||
*/
|
||||
bool special_active(const config& cfg,bool self) const;
|
||||
bool special_affects_opponent(const config& cfg) const;
|
||||
bool special_affects_self(const config& cfg) const;
|
||||
|
||||
struct attack_animation
|
||||
{
|
||||
typedef enum { HIT, MISS, HIT_OR_MISS } hit_type;
|
||||
|
@ -68,25 +109,21 @@ public:
|
|||
hit_type hits;
|
||||
|
||||
};
|
||||
config cfg_;
|
||||
const attack_animation& animation(bool hit,gamemap::location::DIRECTION dir=gamemap::location::NDIRECTIONS) const;
|
||||
private:
|
||||
std::vector<attack_animation> animation_;
|
||||
t_string description_;
|
||||
std::string id_;
|
||||
std::string type_;
|
||||
std::string special_;
|
||||
std::string icon_;
|
||||
RANGE range_type_;
|
||||
std::string range_;
|
||||
int hexes_;
|
||||
int damage_;
|
||||
int num_attacks_;
|
||||
double attack_weight_;
|
||||
double defense_weight_;
|
||||
|
||||
//caches whether the unit can backstab and slow. This is important
|
||||
//because the AI queries it alot.
|
||||
bool backstab_, slow_;
|
||||
};
|
||||
|
||||
class unit_movement_type;
|
||||
|
@ -111,7 +148,11 @@ public:
|
|||
void set_parent(const unit_movement_type* parent);
|
||||
|
||||
bool is_flying() const;
|
||||
|
||||
const std::map<gamemap::TERRAIN,int>& movement_costs() const;
|
||||
const std::map<gamemap::TERRAIN,int>& defense_mods() const;
|
||||
|
||||
const config& get_cfg() const;
|
||||
const unit_movement_type* get_parent() const;
|
||||
private:
|
||||
const config cfg_;
|
||||
|
||||
|
@ -141,23 +182,22 @@ private:
|
|||
class unit_type
|
||||
{
|
||||
public:
|
||||
//this class assumes that the passed in references will remain valid
|
||||
//for at least as long as the class instance
|
||||
friend class unit;
|
||||
unit_type(const config& cfg, const movement_type_map& movement_types,
|
||||
const race_map& races, const std::vector<config*>& traits);
|
||||
unit_type(const unit_type& o);
|
||||
|
||||
~unit_type();
|
||||
|
||||
// adds an additional advancement path to a unit type
|
||||
// this is used to implement the [advancefrom] tag
|
||||
void add_advancement(const unit_type &advance_to,int experience);
|
||||
// adds an additional advancement path to a unit type
|
||||
// this is used to implement the [advancefrom] tag
|
||||
void add_advancement(const unit_type &advance_to,int experience);
|
||||
|
||||
|
||||
const unit_type& get_gender_unit_type(unit_race::GENDER gender) const;
|
||||
const unit_type& get_variation(const std::string& name) const;
|
||||
//info on the type of unit that the unit reanimates as
|
||||
const std::string& undead_variation() const;
|
||||
//info on the type of unit that the unit reanimates as
|
||||
const std::string& undead_variation() const;
|
||||
|
||||
int num_traits() const;
|
||||
|
||||
|
@ -183,7 +223,7 @@ public:
|
|||
const std::string& get_hit_sound() const;
|
||||
const std::string& die_sound() const;
|
||||
|
||||
const std::vector<Uint32>& flag_rgb() const;
|
||||
const std::vector<Uint32>& flag_rgb() const;
|
||||
|
||||
int hitpoints() const;
|
||||
std::vector<attack_type> attacks() const;
|
||||
|
@ -216,19 +256,6 @@ public:
|
|||
const std::vector<std::string>& abilities() const;
|
||||
const std::vector<std::string>& ability_tooltips() const;
|
||||
|
||||
int heals() const;
|
||||
bool cures() const;
|
||||
bool regenerates() const;
|
||||
int regenerate_amount() const;
|
||||
bool is_leader() const;
|
||||
int leadership(int led_level) const;
|
||||
int illuminates() const;
|
||||
bool is_skirmisher() const;
|
||||
bool teleports() const;
|
||||
bool steadfast() const;
|
||||
int steadfast_bonus() const;
|
||||
bool steadfast_ispercent() const;
|
||||
int steadfast_max() const;
|
||||
bool not_living() const;
|
||||
bool can_advance() const;
|
||||
|
||||
|
@ -248,14 +275,6 @@ public:
|
|||
const death_animation& die_animation(const attack_type* attack) const;
|
||||
const movement_animation& move_animation(const std::string terrain,gamemap::location::DIRECTION) const;
|
||||
|
||||
const ability_filter regenerates_filter() const;
|
||||
const ability_filter leadership_filter() const;
|
||||
const ability_filter illuminates_filter() const;
|
||||
const ability_filter skirmisher_filter() const;
|
||||
const ability_filter teleports_filter() const;
|
||||
const ability_filter steadfast_filter() const;
|
||||
const ability_filter hides_filter() const;
|
||||
|
||||
private:
|
||||
void operator=(const unit_type& o);
|
||||
|
||||
|
@ -275,38 +294,10 @@ private:
|
|||
|
||||
mutable std::string id_;
|
||||
|
||||
int heals_;
|
||||
bool cures_;
|
||||
|
||||
ability_filter regenerates_filter_;
|
||||
bool regenerates_;
|
||||
int regeneration_;
|
||||
|
||||
ability_filter leadership_filter_;
|
||||
bool leadership_;
|
||||
int leadership_percent_;
|
||||
|
||||
ability_filter illuminates_filter_;
|
||||
int illuminates_;
|
||||
|
||||
ability_filter skirmisher_filter_;
|
||||
bool skirmish_;
|
||||
|
||||
ability_filter teleports_filter_;
|
||||
bool teleport_;
|
||||
|
||||
ability_filter steadfast_filter_;
|
||||
bool steadfast_;
|
||||
int steadfast_bonus_;
|
||||
int steadfast_max_;
|
||||
bool steadfast_percent_;
|
||||
|
||||
ability_filter hides_filter_;
|
||||
bool hides_;
|
||||
bool zoc_;
|
||||
|
||||
std::vector<std::string> advances_to_;
|
||||
int experience_needed_;
|
||||
std::vector<std::string> advances_to_;
|
||||
int experience_needed_;
|
||||
|
||||
|
||||
ALIGNMENT alignment_;
|
||||
|
@ -327,7 +318,7 @@ private:
|
|||
|
||||
std::vector<movement_animation> movement_animations_;
|
||||
|
||||
std::vector<Uint32> flag_rgb_;
|
||||
std::vector<Uint32> flag_rgb_;
|
||||
};
|
||||
|
||||
struct game_data
|
||||
|
|
|
@ -208,7 +208,7 @@ void upload_log::start(game_state &state, const team &team,
|
|||
if ((*i)->can_recruit()) {
|
||||
config &sp = game_->add_child("special-unit");
|
||||
sp["name"] = (*i)->name();
|
||||
sp["level"] = lexical_cast<std::string>((*i)->type().level());
|
||||
sp["level"] = lexical_cast<std::string>((*i)->level());
|
||||
sp["experience"] = lexical_cast<std::string>((*i)->experience());
|
||||
}
|
||||
}
|
||||
|
@ -221,13 +221,13 @@ void upload_log::start(game_state &state, const team &team,
|
|||
|
||||
higher_units = false;
|
||||
for (i = all_units.begin(); i != all_units.end(); ++i) {
|
||||
if ((*i)->type().level() > level)
|
||||
if ((*i)->level() > level)
|
||||
higher_units = true;
|
||||
else if ((*i)->type().level() == level) {
|
||||
if (tally.find((*i)->type().id()) == tally.end())
|
||||
tally[(*i)->type().id()] = 1;
|
||||
else if ((*i)->level() == level) {
|
||||
if (tally.find((*i)->id()) == tally.end())
|
||||
tally[(*i)->id()] = 1;
|
||||
else
|
||||
tally[(*i)->type().id()]++;
|
||||
tally[(*i)->id()]++;
|
||||
}
|
||||
}
|
||||
if (!tally.empty()) {
|
||||
|
|
|
@ -61,14 +61,14 @@ void file_chooser::display_current_files() {
|
|||
if (!is_root(current_dir_)) {
|
||||
to_show.push_back("..");
|
||||
}
|
||||
std::copy(dirs_in_current_dir_.begin(), dirs_in_current_dir_.end(),
|
||||
std::back_inserter(to_show));
|
||||
//std::copy(dirs_in_current_dir_.begin(), dirs_in_current_dir_.end(),
|
||||
// std::back_inserter(to_show));
|
||||
std::vector<std::string>::iterator it;
|
||||
for (it = to_show.begin(); it != to_show.end(); it++) {
|
||||
for (it = dirs_in_current_dir_.begin(); it != dirs_in_current_dir_.end(); it++) {
|
||||
// Add an image to show that these are directories.
|
||||
std::stringstream ss;
|
||||
ss << font::IMAGE << dir_picture << COLUMN_SEPARATOR << *it;
|
||||
*it = ss.str();
|
||||
to_show.push_back(ss.str());
|
||||
}
|
||||
for (it = files_in_current_dir_.begin(); it != files_in_current_dir_.end(); it++) {
|
||||
const std::string display_string = COLUMN_SEPARATOR + *it;
|
||||
|
|
Loading…
Add table
Reference in a new issue