63 #define DBG_AI LOG_STREAM(debug, log_ai)
64 #define LOG_AI LOG_STREAM(info, log_ai)
65 #define WRN_AI LOG_STREAM(warn, log_ai)
66 #define ERR_AI LOG_STREAM(err, log_ai)
167 allow_ally_villages_(),
172 defensive_position_cache_(),
173 dstsrc_(),enemy_dstsrc_(),
174 enemy_possible_moves_(),
179 leader_aggression_(),
181 leader_ignores_keep_(),
183 move_maps_enemy_valid_(false),
184 move_maps_valid_(false),
185 dst_src_valid_lua_(false),
186 dst_src_enemy_valid_lua_(false),
187 src_dst_valid_lua_(false),
188 src_dst_enemy_valid_lua_(false),
190 passive_leader_shares_keep_(),
192 recruitment_diversity_(),
193 recruitment_instructions_(),
195 recruitment_pattern_(),
196 recruitment_randomness_(),
197 recruitment_save_gold_(),
198 recursion_counter_(context.get_recursion_count()),
199 retreat_enemy_weight_(),
201 scout_village_targeting_(),
207 villages_per_scout_()
249 std::vector<aspect_ptr> aspects;
276 for(
const aspect_map::value_type &a :
aspects_) {
277 cfg.
add_child(
"aspect",a.second->to_config());
324 move_map& dstsrc,
bool enemy,
bool assume_full_movement,
325 const terrain_filter* remove_destinations)
const
331 move_map& dstsrc,
bool enemy,
bool assume_full_movement,
332 const terrain_filter* remove_destinations,
342 (!
enemy && !assume_full_movement && un_it->side() !=
get_side()) ||
347 if (un_it->incapacitated() ||
348 (!assume_full_movement && un_it->movement_left() == 0)) {
353 if (
enemy && un_it->invisible(un_it->get_location()) && !see_all) {
360 if (un_it->movement_left() > 0) {
361 std::pair<map_location,map_location> trivial_mv(un_it->get_location(), un_it->get_location());
362 srcdst.insert(trivial_mv);
363 dstsrc.insert(trivial_mv);
381 static const config only_not_tag(
"not");
382 if(remove_destinations && remove_destinations->to_config() == only_not_tag) {
383 remove_destinations =
nullptr;
392 if(remove_destinations !=
nullptr && remove_destinations->match(
dst)) {
396 bool friend_owns =
false;
401 if(
t.owns_village(
dst)) {
427 const std::string
id = a->get_id();
432 ERR_AI <<
"when adding aspects, unknown aspect id["<<
id<<
"]";
441 i->second->add_facet(cfg);
443 ERR_AI <<
"when adding aspects, unknown aspect id["<<
id<<
"]";
458 const std::map<map_location,defensive_position>::const_iterator position =
462 return position->second;
470 typedef move_map::const_iterator Itor;
471 const std::pair<Itor,Itor> itors = srcdst.equal_range(loc);
472 for(Itor
i = itors.first;
i != itors.second; ++
i) {
605 std::string engine_name = cfg[
"engine"];
606 if (engine_name.empty()) {
611 while (en!=
engines_.end() && ((*en)->get_name()!=engine_name) && ((*en)->get_id()!=engine_name)) {
623 DBG_AI <<
"config snippet contains: " << std::endl << cfg;
627 engine_ptr new_engine = eng->second->get_new_instance(*
this,engine_name);
631 DBG_AI <<
"config snippet contains: " << std::endl << cfg;
653 return std::string();
743 return std::vector<std::string>();
751 return std::vector<std::string>();
915 for(
int x = 0; x !=
map_->
w(); ++x) {
916 for(
int y = 0; y !=
map_->
h(); ++y) {
941 if(start_pos.
valid() ==
false) {
945 if (leader->get_location() == start_pos) {
957 std::set<map_location> avoided_locations;
958 get_avoid().get_locations(avoided_locations);
959 const std::set<map_location>&
keeps = this->
keeps();
967 for(std::set<map_location>::const_iterator
i =
keeps.begin();
i !=
keeps.end(); ++
i) {
968 if (avoided_locations.find(*
i)!=avoided_locations.end()) {
972 if(res ==
nullptr || distance < closest) {
988 std::fill_n(ratings, 0, 6);
989 int num_used_locs = 0;
998 bool changed =
false;
999 for (
int i = 0;; ++
i) {
1001 if (!changed)
break;
1014 typedef move_map::const_iterator Itor;
1015 typedef std::pair<Itor,Itor> Range;
1016 Range its = dstsrc.equal_range(locs[
i]);
1021 int best_rating = 0;
1024 for(Itor it = its.first; it != its.second; ++it) {
1028 if(u == units_.
end()) {
1032 const unit& un = *u;
1041 int tod_modifier = 0;
1042 if(un.
alignment() == unit_alignments::type::lawful) {
1043 tod_modifier = lawful_bonus;
1044 }
else if(un.
alignment() == unit_alignments::type::chaotic) {
1045 tod_modifier = -lawful_bonus;
1046 }
else if(un.
alignment() == unit_alignments::type::liminal) {
1047 tod_modifier = -(std::abs(lawful_bonus));
1051 int64_t hp =
static_cast<int>(std::sqrt(
static_cast<double>(un.
hitpoints()) / un.
max_hitpoints()) * 1000);
1052 int64_t most_damage = 0;
1055 int damage = att.damage() * att.num_attacks() * (100 + tod_modifier);
1056 if (damage > most_damage) {
1057 most_damage = damage;
1061 int64_t village_bonus = map_.
is_village(terrain) ? 3 : 2;
1063 int64_t rating_64 = hp * defense * most_damage * village_bonus / 200;
1064 int rating = rating_64;
1065 if(
static_cast<int64_t
>(rating) != rating_64) {
1066 WRN_AI <<
"overflow in ai attack calculation";
1068 if(rating > best_rating) {
1069 map_location *pos = std::find(beg_used, end_used, it->second);
1071 if (pos == end_used || rating >= ratings[pos - beg_used]) {
1072 best_rating = rating;
1073 best_unit = it->second;
1078 if (!best_unit.
valid())
continue;
1079 map_location *pos = std::find(beg_used, end_used, best_unit);
1080 int index = pos - beg_used;
1081 if (
index == num_used_locs)
1083 else if (best_rating == ratings[
index])
1088 res -= ratings[
index];
1091 used_locs[
index] = best_unit;
1092 ratings[
index] = best_rating;
1096 return res / 100000.;
1111 if(it->second == loc) {
1161 return leader_location;
1165 double move_left_at_best_free_keep = 0.0;
1168 double move_left_at_best_occupied_keep = 0.0;
1175 const int move_left_at_loc = dest.
move_left;
1178 best_free_keep = &loc;
1179 move_left_at_best_free_keep = move_left_at_loc;
1183 best_occupied_keep = &loc;
1184 move_left_at_best_occupied_keep = move_left_at_loc;
1191 return *best_free_keep;
1195 return *best_occupied_keep;
1216 if(turns.empty() ==
false) {
1218 const std::vector<std::string>& turns_list =
utils::split(turns);
1219 for(std::vector<std::string>::const_iterator j = turns_list.begin(); j != turns_list.end() ; ++j ) {
1221 if(turn >= range.first && turn <= range.second) {
1231 const utils::variant<
bool, std::vector<std::string>>& aspect_value,
const std::string&
id)
const
1233 return utils::visit(
1234 [&
id](
const auto& v) {
Various functions that implement attacks and attack calculations.
Managing the AI-Game interaction - AI actions and their results.
Managing the AIs lifecycle - headers TODO: Refactor history handling and internal commands.
static recall_result_ptr execute_recall_action(side_number side, bool execute, const std::string &unit_id, const map_location &where, const map_location &from)
Ask the game to recall a unit for us on specified location.
static synced_command_result_ptr execute_synced_command_action(side_number side, bool execute, const std::string &lua_code, const map_location &location)
Ask the game to run Lua code.
static attack_result_ptr execute_attack_action(side_number side, bool execute, const map_location &attacker_loc, const map_location &defender_loc, int attacker_weapon, double aggression)
Ask the game to attack an enemy defender using our unit attacker from attackers current location,...
static move_result_ptr execute_move_action(side_number side, bool execute, const map_location &from, const map_location &to, bool remove_movement, bool unreach_is_ok=false)
Ask the game to move our unit from location 'from' to location 'to', optionally - doing a partial mov...
static recruit_result_ptr execute_recruit_action(side_number side, bool execute, const std::string &unit_name, const map_location &where, const map_location &from)
Ask the game to recruit a unit for us on specified location.
static stopunit_result_ptr execute_stopunit_action(side_number side, bool execute, const map_location &unit_location, bool remove_movement, bool remove_attacks)
Ask the game to remove unit movements and/or attack.
static factory_map & get_list()
static void parse_goal_from_config(readonly_context &context, const config &cfg, std::back_insert_iterator< std::vector< goal_ptr >> b)
static void parse_aspect_from_config(readonly_context &context, const config &cfg, const std::string &id, std::back_insert_iterator< std::vector< aspect_ptr >> b)
static void parse_engine_from_config(readonly_context &context, const config &cfg, std::back_insert_iterator< std::vector< engine_ptr >> b)
void handle_generic_event(const std::string &event_name)
const std::set< map_location > & get()
void init(const gamemap &map)
std::set< map_location > keeps_
void remove_gamestate_observer(events::observer *event_observer)
Removes an observer of game events except ai_user_interact event and ai_sync_network event.
void raise_gamestate_changed()
Notifies all observers of 'ai_gamestate_changed' event.
void add_gamestate_observer(events::observer *event_observer)
Adds observer of game events except ai_user_interact event and ai_sync_network event.
void raise_user_interact()
Notifies all observers of 'ai_user_interact' event.
game_info & get_active_ai_info_for_side(side_number side)
Gets AI info for active AI of the given side.
void add_map_changed_observer(events::observer *event_observer)
Adds an observer of 'ai_map_changed' event.
static manager & get_singleton()
void add_turn_started_observer(events::observer *event_observer)
Adds an observer of 'ai_turn_started' event.
void remove_turn_started_observer(events::observer *event_observer)
Deletes an observer of 'ai_turn_started' event.
void remove_map_changed_observer(events::observer *event_observer)
Deletes an observer of 'ai_map_changed' event.
virtual double get_caution() const override
virtual ~readonly_context_impl()
Destructor.
virtual void recalculate_move_maps_enemy() const override
std::map< map_location, defensive_position > defensive_position_cache_
stopunit_result_ptr check_stopunit_action(const map_location &unit_location, bool remove_movement=true, bool remove_attacks=false) override
Check if it is possible to remove unit movements and/or attack.
typesafe_aspect_ptr< utils::variant< bool, std::vector< std::string > > > passive_leader_
recruit_result_ptr check_recruit_action(const std::string &unit_name, const map_location &where=map_location::null_location(), const map_location &from=map_location::null_location()) override
Check if it is possible to recruit a unit for us on specified location.
virtual bool is_keep_ignoring_leader(const std::string &id) const override
virtual const move_map & get_srcdst() const override
void calculate_possible_moves(std::map< map_location, pathfind::paths > &possible_moves, move_map &srcdst, move_map &dstsrc, bool enemy, bool assume_full_movement=false, const terrain_filter *remove_destinations=nullptr) const override
Calculate the moves units may possibly make.
typesafe_aspect_ptr< std::vector< std::string > > recruitment_more_
virtual bool is_active(const std::string &time_of_day, const std::string &turns) const override
virtual const move_map & get_dstsrc() const override
virtual const std::vector< std::string > get_recruitment_pattern() const override
const defensive_position & best_defensive_position(const map_location &unit, const move_map &dstsrc, const move_map &srcdst, const move_map &enemy_dstsrc) const override
virtual bool get_simple_targeting() const override
typesafe_aspect_ptr< bool > support_villages_
virtual bool is_passive_keep_sharing_leader(const std::string &id) const override
unit_stats_cache_t unit_stats_cache_
void add_known_aspect(const std::string &name, typesafe_aspect_ptr< T > &where)
virtual void add_facet(const std::string &id, const config &cfg) const override
bool move_maps_enemy_valid_
virtual bool get_allow_ally_villages() const override
virtual std::map< map_location, defensive_position > & defensive_position_cache() const override
attack_result_ptr check_attack_action(const map_location &attacker_loc, const map_location &defender_loc, int attacker_weapon) override
Check if it is possible to attack enemy defender using our unit attacker from attackers current locat...
virtual const std::vector< goal_ptr > & get_goals() const override
virtual const game_info & get_info() const override
virtual void recalculate_move_maps() const override
typesafe_aspect_ptr< terrain_filter > avoid_
virtual bool is_dst_src_valid_lua() const override
typesafe_aspect_ptr< bool > simple_targeting_
virtual const move_map & get_enemy_srcdst() const override
virtual double get_recruitment_diversity() const override
virtual bool is_src_dst_enemy_valid_lua() const override
void raise_user_interact() const override
Function which should be called frequently to allow the user to interact with the interface.
virtual double get_retreat_enemy_weight() const override
virtual const std::vector< engine_ptr > & get_engines() const override
virtual const attacks_vector & get_attacks() const override
typesafe_aspect_ptr< attacks_vector > attacks_
virtual const map_location & suitable_keep(const map_location &leader_location, const pathfind::paths &leader_paths) const override
get most suitable keep for leader - nearest free that can be reached in 1 turn, if none - return near...
virtual void invalidate_move_maps() const override
virtual const terrain_filter & get_avoid() const override
virtual int get_recursion_count() const override
Get the value of the recursion counter.
bool applies_to_leader(const utils::variant< bool, std::vector< std::string >> &aspect_value, const std::string &id) const
virtual int get_villages_per_scout() const override
virtual config get_leader_goal() const override
virtual void invalidate_keeps_cache() const override
virtual double get_leader_aggression() const override
readonly_context_impl(side_context &context, const config &cfg)
Constructor.
virtual const aspect_map & get_aspects() const override
virtual const move_map & get_enemy_dstsrc() const override
virtual double get_village_value() const override
typesafe_aspect_ptr< int > recruitment_randomness_
virtual bool is_passive_leader(const std::string &id) const override
const team & current_team() const override
Return a reference to the 'team' object for the AI.
typesafe_aspect_ptr< int > villages_per_scout_
virtual unit_stats_cache_t & unit_stats_cache() const override
Weapon choice cache, to speed simulations.
virtual void set_dst_src_valid_lua() override
typesafe_aspect_ptr< double > recruitment_diversity_
typesafe_aspect_ptr< double > village_value_
virtual void set_src_dst_enemy_valid_lua() override
recursion_counter recursion_counter_
virtual const moves_map & get_enemy_possible_moves() const override
void log_message(const std::string &msg) override
Display a debug message as a chat message.
virtual const map_location & nearest_keep(const map_location &loc) const override
typesafe_aspect_ptr< unit_advancements_aspect > advancements_
typesafe_aspect_ptr< double > retreat_factor_
bool dst_src_enemy_valid_lua_
virtual const config get_recruitment_instructions() const override
virtual double get_aggression() const override
known_aspect_map known_aspects_
typesafe_aspect_ptr< double > retreat_enemy_weight_
synced_command_result_ptr check_synced_command_action(const std::string &lua_code, const map_location &location=map_location::null_location()) override
Check if it is possible to run Lua code.
virtual double power_projection(const map_location &loc, const move_map &dstsrc) const override
Function which finds how much 'power' a side can attack a certain location with.
void calculate_moves(const unit_map &units, std::map< map_location, pathfind::paths > &possible_moves, move_map &srcdst, move_map &dstsrc, bool enemy, bool assume_full_movement=false, const terrain_filter *remove_destinations=nullptr, bool see_all=false) const override
A more fundamental version of calculate_possible_moves which allows the use of a speculative unit map...
virtual void invalidate_defensive_position_cache() const override
virtual utils::variant< bool, std::vector< std::string > > get_passive_leader() const override
typesafe_aspect_ptr< double > leader_value_
typesafe_aspect_ptr< config > recruitment_instructions_
std::vector< engine_ptr > engines_
AI Support Engines.
typesafe_aspect_ptr< utils::variant< bool, std::vector< std::string > > > passive_leader_shares_keep_
virtual bool is_src_dst_valid_lua() const override
virtual void add_aspects(std::vector< aspect_ptr > &aspects) override
virtual bool is_dst_src_enemy_valid_lua() const override
virtual utils::variant< bool, std::vector< std::string > > get_passive_leader_shares_keep() const override
virtual double get_leader_value() const override
typesafe_aspect_ptr< double > scout_village_targeting_
virtual utils::variant< bool, std::vector< std::string > > get_leader_ignores_keep() const override
virtual const std::vector< std::string > get_recruitment_more() const override
virtual const wfl::variant & get_attacks_as_variant() const override
std::vector< goal_ptr > goals_
virtual void set_dst_src_enemy_valid_lua() override
typesafe_aspect_ptr< utils::variant< bool, std::vector< std::string > > > leader_ignores_keep_
typesafe_aspect_ptr< std::vector< std::string > > recruitment_pattern_
virtual const unit_advancements_aspect & get_advancements() const override
recall_result_ptr check_recall_action(const std::string &id, const map_location &where=map_location::null_location(), const map_location &from=map_location::null_location()) override
Check if it is possible to recall a unit for us on specified location.
virtual const std::set< map_location > & keeps() const override
typesafe_aspect_ptr< config > leader_goal_
virtual void handle_generic_event(const std::string &event_name) override
Handle generic event.
virtual bool leader_can_reach_keep() const override
virtual bool get_support_villages() const override
bool src_dst_enemy_valid_lua_
virtual std::string get_grouping() const override
virtual double get_retreat_factor() const override
moves_map possible_moves_
typesafe_aspect_ptr< bool > allow_ally_villages_
moves_map enemy_possible_moves_
virtual const config get_recruitment_save_gold() const override
void diagnostic(const std::string &msg) override
Show a diagnostic message on the screen.
virtual void on_readonly_context_create() override
virtual double get_scout_village_targeting() const override
typesafe_aspect_ptr< double > caution_
virtual const moves_map & get_possible_moves() const override
virtual int get_recruitment_randomness() const override
move_result_ptr check_move_action(const map_location &from, const map_location &to, bool remove_movement=true, bool unreach_is_ok=false) override
Check if it is possible to move our unit from location 'from' to location 'to'.
typesafe_aspect_ptr< std::string > grouping_
virtual config to_readonly_context_config() const override
serialize to config
typesafe_aspect_ptr< double > aggression_
typesafe_aspect_ptr< config > recruitment_save_gold_
typesafe_aspect_ptr< double > leader_aggression_
virtual engine_ptr get_engine_by_cfg(const config &cfg) override
get engine by cfg, creating it if it is not created yet but known
virtual void set_src_dst_valid_lua() override
virtual double get_aggression() const override
virtual double get_leader_aggression() const override
std::map< std::pair< map_location, const unit_type * >, std::pair< battle_context_unit_stats, battle_context_unit_stats > > unit_stats_cache_t
virtual game_info & get_info_w() override
Functions to retrieve the 'info' object.
virtual synced_command_result_ptr execute_synced_command_action(const std::string &lua_code, const map_location &location=map_location::null_location()) override
Ask the game to run Lua code.
virtual recruit_result_ptr execute_recruit_action(const std::string &unit_name, const map_location &where=map_location::null_location(), const map_location &from=map_location::null_location()) override
Ask the game to recruit a unit for us on specified location.
virtual config to_readwrite_context_config() const override
serialize this context to config
void raise_gamestate_changed() const override
Notifies all interested observers of the event respectively.
virtual move_result_ptr execute_move_action(const map_location &from, const map_location &to, bool remove_movement=true, bool unreach_is_ok=false) override
Ask the game to move our unit from location 'from' to location 'to', optionally - doing a partial mov...
virtual recall_result_ptr execute_recall_action(const std::string &id, const map_location &where=map_location::null_location(), const map_location &from=map_location::null_location()) override
Ask the game to recall a unit for us on specified location.
virtual stopunit_result_ptr execute_stopunit_action(const map_location &unit_location, bool remove_movement=true, bool remove_attacks=false) override
Ask the game to remove unit movements and/or attack.
recursion_counter recursion_counter_
virtual team & current_team_w() override
Return a reference to the 'team' object for the AI.
virtual attack_result_ptr execute_attack_action(const map_location &attacker_loc, const map_location &defender_loc, int attacker_weapon) override
Ask the game to attack an enemy defender using our unit attacker from attackers current location,...
virtual int get_recursion_count() const override
Get the value of the recursion counter.
int get_count() const
Get the current value of the recursion counter.
virtual config to_side_context_config() const override
serialize this context to config
virtual int get_recursion_count() const override
Get the value of the recursion counter.
recursion_counter recursion_counter_
void init_side_context_proxy(side_context &target)
virtual side_number get_side() const override
Get the side number.
A config object defines a single node in a WML file, with access to child nodes.
child_itors child_range(config_key_type key)
config & add_child(config_key_type key)
void add_chat_message(const std::time_t &time, const std::string &speaker, int side, const std::string &msg, events::chat_handler::MESSAGE_TYPE type, bool bell)
static display * get_singleton()
Returns the display object if a display object exists.
void set_diagnostic(const std::string &msg)
virtual const unit_map & units() const override
virtual const gamemap & map() const override
static game_display * get_singleton()
display_chat_manager & get_chat_manager()
int w() const
Effective map width.
int h() const
Effective map height.
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Encapsulates the map of the game.
bool is_village(const map_location &loc) const
bool is_castle(const map_location &loc) const
bool is_keep(const map_location &loc) const
This class stores all the data for a single 'side' (in game nomenclature).
const time_of_day & get_time_of_day(int for_turn=0) const
Returns global time of day for the passed turn.
Container associating units to locations.
unit_iterator find(std::size_t id)
unit_iterator find_leader(int side)
This class represents a single unit of a specific type.
A variable-expanding proxy for the config class.
Definitions for the interface to Wesnoth Markup Language (WML).
static lg::log_domain log_ai("ai/general")
Helper functions for the object which operates in the context of AI for specific side this is part of...
AI Support engine - creating specific ai components from config.
Game information for the AI.
int max_hitpoints() const
The max number of hitpoints this unit can have.
unit_alignments::type alignment() const
The alignment of this unit.
int hitpoints() const
The current number of hitpoints this unit has.
int side() const
The side this unit belongs to.
int defense_modifier(const t_translation::terrain_code &terrain) const
The unit's defense on a given terrain.
attack_itors attacks()
Gets an iterator over this unit's attacks.
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
std::size_t distance_between(const map_location &a, const map_location &b)
Function which gives the number of hexes between two tiles (i.e.
Standard logging facilities (interface).
A small explanation about what's going on here: Each action has access to two game_info objects First...
std::shared_ptr< engine > engine_ptr
std::vector< attack_analysis > attacks_vector
std::shared_ptr< recruit_result > recruit_result_ptr
std::shared_ptr< typesafe_aspect< T > > typesafe_aspect_ptr
std::shared_ptr< aspect > aspect_ptr
std::shared_ptr< attack_result > attack_result_ptr
std::shared_ptr< stopunit_result > stopunit_result_ptr
std::multimap< map_location, map_location > move_map
The standard way in which a map of possible moves is recorded.
std::shared_ptr< goal > goal_ptr
std::shared_ptr< synced_command_result > synced_command_result_ptr
std::map< map_location, pathfind::paths > moves_map
The standard way in which a map of possible movement routes to location is recorded.
std::shared_ptr< move_result > move_result_ptr
std::shared_ptr< recall_result > recall_result_ptr
std::map< std::string, aspect_ptr > aspect_map
::tod_manager * tod_manager
filter_context * filter_con
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
constexpr bool decayed_is_same
Equivalent to as std::is_same_v except both types are passed through std::decay first.
bool contains(const Container &container, const Value &value)
Returns true iff value is found in container.
std::pair< int, int > parse_range(const std::string &str)
Recognises the following patterns, and returns a {min, max} pair.
std::vector< std::string > split(const config_attribute_value &val)
std::string::const_iterator iterator
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
@ enemy
Belongs to a non-friendly side; normally visualised by not displaying an orb.
This module contains various pathfinding functions and utilities.
static config unit_name(const unit *u)
rect dst
Location on the final composed sheet.
rect src
Non-transparent portion of the surface to compose.
Encapsulates the map of the game.
static const map_location & null_location()
bool contains(const map_location &) const
Object which contains all the possible locations a unit can move to, with associated best routes to t...
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Object which defines a time of day with associated bonuses, image, sounds etc.
int lawful_bonus
The % bonus lawful units receive.
Object which temporarily resets a unit's movement.