Added Elvish Shaman's heal animation

This commit is contained in:
Dave White 2004-06-03 17:09:53 +00:00
parent a8409c19d1
commit 0debf0d593
16 changed files with 100 additions and 22 deletions

View file

@ -60,8 +60,10 @@ Defeat:
y=23
[/unit]
[ai]
avoid_x=20-31
avoid_y=1-12
[avoid]
x=20-31
y=1-12
[/avoid]
village_value=0.0
leader_value=0.0
[target]

View file

@ -49,7 +49,11 @@ Defeat:
canrecruit=1
recruit=Vampire Bat,Walking Corpse,Dark Adept
[ai]
recruitment_pattern=fighter,fighter,fighter,fighter,fighter,fighter,fighter,archer
recruitment_pattern=fighter,fighter,fighter,fighter,fighter,fighter,fighter,archer
grouping=no
aggression=1.0
caution=-1.0
simple_targetting=yes
[/ai]
{GOLD 240 300 400}
enemy=1

View file

@ -4,7 +4,8 @@ race=elf
gender=female
image=elvish-shaman.png
image_defensive=elvish-shaman-defend.png
image_healing=elvish-shaman-healing.png
image_healing=null
image_halo_healing=elvish-shaman-heal1.png:70,elvish-shaman-heal2.png:70,elvish-shaman-heal3.png:70,elvish-shaman-heal4.png:70,elvish-shaman-heal5.png:70
hitpoints=26
ability=heals
movement_type=woodland

Binary file not shown.

After

Width:  |  Height:  |  Size: 990 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View file

@ -1118,6 +1118,12 @@ void calculate_healing(display& disp, const gamestatus& status, const gamemap& m
unit& healer = units.find(i->second)->second;
healer.set_healing(true);
const std::string& halo_image = healer.type().image_halo_healing();
if(halo_image.empty() == false) {
halo::add(disp.get_location_x(i->second)+disp.hex_size()/2,disp.get_location_y(i->second)+disp.hex_size()/2,
halo_image,healer.facing_left() ? halo::NORMAL : halo::REVERSE,1);
}
disp.draw_tile(i->second.x,i->second.y);
}

View file

@ -1281,7 +1281,7 @@ void ai::analyze_potential_recruit_movements()
std::cerr << "targets: " << targets.size() << "\n";
int best_score = -1;
std::map<std::string,int> best_scores;
for(std::set<std::string>::const_iterator i = recruits.begin(); i != recruits.end(); ++i) {
const game_data::unit_type_map::const_iterator info = gameinfo_.unit_types.find(*i);
@ -1318,13 +1318,21 @@ void ai::analyze_potential_recruit_movements()
const int average_cost = cost/targets_reached;
const int score = (average_cost * (targets_reached+targets_missed))/targets_reached;
unit_movement_scores_[*i] = score;
if(best_score == -1 || score < best_score) {
best_score = score;
const std::map<std::string,int>::const_iterator current_best = best_scores.find(temp_unit.type().usage());
if(current_best == best_scores.end() || score < current_best->second) {
best_scores[temp_unit.type().usage()] = score;
}
}
}
for(std::map<std::string,int>::iterator j = unit_movement_scores_.begin(); j != unit_movement_scores_.end(); ++j) {
const game_data::unit_type_map::const_iterator info = gameinfo_.unit_types.find(j->first);
if(info == gameinfo_.unit_types.end()) {
}
continue;
const int best_score = best_scores[info->second.usage()];
if(best_score > 0) {
j->second = (j->second*10)/best_score;
if(j->second > 15) {
@ -1515,7 +1523,7 @@ void ai::move_leader_after_recruit(const move_map& enemy_dstsrc)
std::cerr << "moving leader after recruit...\n";
const unit_map::iterator leader = find_leader(units_,team_num_);
if(leader == units_.end() || leader->second.stone()) {
if(leader == units_.end() || leader->second.incapacitated()) {
return;
}
@ -1599,6 +1607,29 @@ 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()) {
return false;
}
const gamemap::location& start_pos = nearest_keep(leader->first);
if(start_pos.valid() == false) {
return false;
}
if(leader->first == start_pos) {
return true;
}
//find where the leader can move
const paths leader_paths(map_,state_,gameinfo_,units_,leader->first,teams_,false,false);
return leader_paths.routes.count(start_pos) > 0;
}
int ai::rate_terrain(const unit& u, const gamemap::location& loc)
{
const gamemap::TERRAIN terrain = map_.get_terrain(loc);
@ -1741,12 +1772,13 @@ const gamemap::location& ai::nearest_keep(const gamemap::location& loc) const
const std::set<gamemap::location>& ai::avoided_locations() const
{
if(avoid_.empty()) {
const std::string& xrange = current_team().ai_parameters()["avoid_x"];
const std::string& yrange = current_team().ai_parameters()["avoid_y"];
const config::child_list& avoids = current_team().ai_parameters().get_children("avoid");
for(config::child_list::const_iterator a = avoids.begin(); a != avoids.end(); ++a) {
const std::vector<location>& locs = parse_location_range(xrange,yrange);
for(std::vector<location>::const_iterator i = locs.begin(); i != locs.end(); ++i) {
avoid_.insert(*i);
const std::vector<location>& locs = parse_location_range((**a)["x"],(**a)["y"]);
for(std::vector<location>::const_iterator i = locs.begin(); i != locs.end(); ++i) {
avoid_.insert(*i);
}
}
if(avoid_.empty()) {

View file

@ -324,6 +324,8 @@ public:
const move_map& enemy_dstsrc, const move_map& enemy_srcdst) const;
void invalidate_defensive_position_cache();
bool leader_can_reach_keep() const;
protected:
mutable std::map<location,defensive_position> defensive_position_cache_;

View file

@ -536,6 +536,12 @@ double ai::attack_analysis::rating(double aggression, ai& ai_obj) const
value -= exposure;
}
//if this attack uses our leader, and the leader can reach the keep, and has gold to spend, reduce
//the value to reflect the leader's lost recruitment opportunity in the case of an attack
if(uses_leader && ai_obj.leader_can_reach_keep() && ai_obj.current_team().gold() > 20) {
value -= double(ai_obj.current_team().gold())*0.5;
}
//prefer to attack already damaged targets
value += ((target_starting_damage/3 + avg_damage_inflicted) - (1.0-aggression)*avg_damage_taken)/10.0;

View file

@ -16,12 +16,14 @@ display* disp = NULL;
class effect
{
public:
effect(int xpos, int ypos, const std::string& img);
effect(int xpos, int ypos, const std::string& img, ORIENTATION orientation, int lifetime);
void set_location(int x, int y);
void render();
void unrender();
bool expired() const;
private:
const std::string& current_image();
@ -50,7 +52,8 @@ private:
std::vector<frame> images_;
std::string current_image_;
int start_cycle_, cycle_time_;
bool reverse_;
int start_cycle_, cycle_time_, lifetime_;
int x_, y_;
double zoom_;
@ -65,8 +68,8 @@ bool hide_halo = false;
static const SDL_Rect empty_rect = {0,0,0,0};
effect::effect(int xpos, int ypos, const std::string& img)
: start_cycle_(-1), cycle_time_(50), x_(xpos), y_(ypos), zoom_(disp->zoom()), surf_(NULL), buffer_(NULL), rect_(empty_rect)
effect::effect(int xpos, int ypos, const std::string& img, ORIENTATION orientation, int lifetime)
: reverse_(orientation == REVERSE), start_cycle_(-1), cycle_time_(50), lifetime_(lifetime), x_(xpos), y_(ypos), zoom_(disp->zoom()), surf_(NULL), buffer_(NULL), rect_(empty_rect)
{
if(std::find(img.begin(),img.end(),',') != img.end()) {
const std::vector<std::string>& imgs = config::split(img,',');
@ -125,6 +128,10 @@ void effect::rezoom()
zoom_ = new_zoom;
surf_.assign(image::get_image(current_image_,image::UNSCALED));
if(surf_ != NULL && reverse_) {
surf_.assign(image::reverse_image(surf_));
}
if(surf_ != NULL && zoom_ != 1.0) {
surf_.assign(scale_surface(surf_,int(surf_->w*zoom_),int(surf_->h*zoom_)));
}
@ -196,6 +203,11 @@ void effect::unrender()
update_rect(rect_);
}
bool effect::expired() const
{
return lifetime_ >= 0 && start_cycle_ >= 0 && SDL_GetTicks() - start_cycle_ > lifetime_*cycle_time_;
}
}
manager::manager(display& screen) : old(disp)
@ -219,10 +231,10 @@ halo_hider::~halo_hider()
hide_halo = old;
}
int add(int x, int y, const std::string& image)
int add(int x, int y, const std::string& image, ORIENTATION orientation, int lifetime_cycles)
{
const int id = halo_id++;
haloes.insert(std::pair<int,effect>(id,effect(x,y,image)));
haloes.insert(std::pair<int,effect>(id,effect(x,y,image,orientation,lifetime_cycles)));
return id;
}
@ -245,8 +257,13 @@ void render()
return;
}
for(std::map<int,effect>::iterator i = haloes.begin(); i != haloes.end(); ++i) {
i->second.render();
for(std::map<int,effect>::iterator i = haloes.begin(); i != haloes.end(); ) {
if(i->second.expired()) {
haloes.erase(i++);
} else {
i->second.render();
++i;
}
}
}

View file

@ -25,10 +25,12 @@ private:
bool old;
};
enum ORIENTATION { NORMAL, REVERSE };
///function to add a haloing effect using 'image'
///centered on (x,y)
///returns the handle to the halo object
int add(int x, int y, const std::string& image);
int add(int x, int y, const std::string& image, ORIENTATION orientation=NORMAL, int lifetime_cycles=-1);
///function to set the position of an existing haloing
///effect, according to its handle

View file

@ -671,6 +671,11 @@ const std::string& unit_type::image_healing() const
}
}
const std::string& unit_type::image_halo_healing() const
{
return cfg_["image_halo_healing"];
}
const std::string& unit_type::image_profile() const
{
const std::string& val = cfg_["profile"];

View file

@ -166,6 +166,7 @@ public:
const std::string& image_defensive(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& unit_description() const;
const std::string& get_hit_sound() const;
const std::string& die_sound() const;