code refactoring - simplified the 'display' module
This commit is contained in:
parent
ab12425061
commit
accbc0f772
26 changed files with 876 additions and 798 deletions
|
@ -25,6 +25,7 @@
|
|||
#include "replay.hpp"
|
||||
#include "sound.hpp"
|
||||
#include "statistics.hpp"
|
||||
#include "unit_display.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
@ -577,7 +578,7 @@ void attack(display& gui, const gamemap& map,
|
|||
}
|
||||
}
|
||||
|
||||
bool dies = gui.unit_attack(attacker,defender,
|
||||
bool dies = unit_display::unit_attack(gui,units,map,attacker,defender,
|
||||
hits ? stats.damage_defender_takes : 0,
|
||||
a->second.attacks()[attack_with]);
|
||||
|
||||
|
@ -711,7 +712,7 @@ void attack(display& gui, const gamemap& map,
|
|||
}
|
||||
}
|
||||
|
||||
bool dies = gui.unit_attack(defender,attacker,
|
||||
bool dies = unit_display::unit_attack(gui,units,map,defender,attacker,
|
||||
hits ? stats.damage_attacker_takes : 0,
|
||||
d->second.attacks()[stats.defend_with]);
|
||||
|
||||
|
@ -828,10 +829,10 @@ void attack(display& gui, const gamemap& map,
|
|||
gui.invalidate_unit();
|
||||
}
|
||||
|
||||
int tower_owner(const gamemap::location& loc, std::vector<team>& teams)
|
||||
int village_owner(const gamemap::location& loc, std::vector<team>& teams)
|
||||
{
|
||||
for(size_t i = 0; i != teams.size(); ++i) {
|
||||
if(teams[i].owns_tower(loc))
|
||||
if(teams[i].owns_village(loc))
|
||||
return i;
|
||||
}
|
||||
|
||||
|
@ -839,10 +840,10 @@ int tower_owner(const gamemap::location& loc, std::vector<team>& teams)
|
|||
}
|
||||
|
||||
|
||||
void get_tower(const gamemap::location& loc, std::vector<team>& teams,
|
||||
size_t team_num, const unit_map& units)
|
||||
void get_village(const gamemap::location& loc, std::vector<team>& teams,
|
||||
size_t team_num, const unit_map& units)
|
||||
{
|
||||
if(team_num < teams.size() && teams[team_num].owns_tower(loc)) {
|
||||
if(team_num < teams.size() && teams[team_num].owns_village(loc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -853,7 +854,7 @@ void get_tower(const gamemap::location& loc, std::vector<team>& teams,
|
|||
for(std::vector<team>::iterator i = teams.begin(); i != teams.end(); ++i) {
|
||||
const int side = i - teams.begin() + 1;
|
||||
if(team_num >= teams.size() || has_leader || teams[team_num].is_enemy(side)) {
|
||||
i->lose_tower(loc);
|
||||
i->lose_village(loc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -862,7 +863,7 @@ void get_tower(const gamemap::location& loc, std::vector<team>& teams,
|
|||
}
|
||||
|
||||
if(has_leader) {
|
||||
teams[team_num].get_tower(loc);
|
||||
teams[team_num].get_village(loc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -951,7 +952,7 @@ void calculate_healing(display& disp, const gamemap& map,
|
|||
for(i = units.begin(); i != units.end(); ++i) {
|
||||
amount_healed = 0;
|
||||
|
||||
//the unit heals if it's on this side, and it's on a tower or
|
||||
//the unit heals if it's on this side, and it's on a village or
|
||||
//it has regeneration, and it is wounded
|
||||
if(i->second.side() == side) {
|
||||
if(i->second.hitpoints() < i->second.max_hitpoints()){
|
||||
|
@ -1191,7 +1192,7 @@ void check_victory(std::map<gamemap::location,unit>& units,
|
|||
//clear villages for teams that have no leader
|
||||
for(std::vector<team>::iterator tm = teams.begin(); tm != teams.end(); ++tm) {
|
||||
if(std::find(seen_leaders.begin(),seen_leaders.end(),tm-teams.begin() + 1) == seen_leaders.end()) {
|
||||
tm->clear_towers();
|
||||
tm->clear_villages();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1526,8 +1527,9 @@ size_t move_unit(display* disp, const game_data& gamedata,
|
|||
}
|
||||
|
||||
units.erase(ui);
|
||||
if(disp != NULL)
|
||||
disp->move_unit(steps,u);
|
||||
if(disp != NULL) {
|
||||
unit_display::move_unit(*disp,map,steps,u);
|
||||
}
|
||||
|
||||
u.set_movement(moves_left);
|
||||
|
||||
|
@ -1537,12 +1539,12 @@ size_t move_unit(display* disp, const game_data& gamedata,
|
|||
disp->invalidate(steps.back());
|
||||
}
|
||||
|
||||
int orig_tower_owner = -1;
|
||||
int orig_village_owner = -1;
|
||||
if(map.is_village(steps.back())) {
|
||||
orig_tower_owner = tower_owner(steps.back(),teams);
|
||||
orig_village_owner = village_owner(steps.back(),teams);
|
||||
|
||||
if(orig_tower_owner != team_num) {
|
||||
get_tower(steps.back(),teams,team_num,units);
|
||||
if(orig_village_owner != team_num) {
|
||||
get_village(steps.back(),teams,team_num,units);
|
||||
ui->second.set_movement(0);
|
||||
}
|
||||
}
|
||||
|
@ -1553,7 +1555,7 @@ size_t move_unit(display* disp, const game_data& gamedata,
|
|||
if(event_mutated || should_clear_stack) {
|
||||
undo_stack->clear();
|
||||
} else {
|
||||
undo_stack->push_back(undo_action(steps,starting_moves,orig_tower_owner));
|
||||
undo_stack->push_back(undo_action(steps,starting_moves,orig_village_owner));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -98,11 +98,11 @@ void attack(display& gui, const gamemap& map,
|
|||
|
||||
//given the location of a village, will return the 0-based index of the team
|
||||
//that currently owns it, and -1 if it is unowned.
|
||||
int tower_owner(const gamemap::location& loc, std::vector<team>& teams);
|
||||
int village_owner(const gamemap::location& loc, std::vector<team>& teams);
|
||||
|
||||
//makes it so the tower at the given location is owned by the given
|
||||
//makes it so the village at the given location is owned by the given
|
||||
//0-based team number
|
||||
void get_tower(const gamemap::location& loc, std::vector<team>& teams,
|
||||
void get_village(const gamemap::location& loc, std::vector<team>& teams,
|
||||
size_t team_num, const unit_map& units);
|
||||
|
||||
//given the 1-based side, will find the leader of that side,
|
||||
|
|
41
src/ai.cpp
41
src/ai.cpp
|
@ -23,6 +23,7 @@
|
|||
#include "replay.hpp"
|
||||
#include "show_dialog.hpp"
|
||||
#include "statistics.hpp"
|
||||
#include "unit_display.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
@ -219,14 +220,14 @@ gamemap::location ai_interface::move_unit(location from, location to, std::map<l
|
|||
}
|
||||
|
||||
steps.push_back(to); //add the destination to the steps
|
||||
info_.disp.move_unit(steps,current_unit);
|
||||
unit_display::move_unit(info_.disp,info_.map,steps,current_unit);
|
||||
}
|
||||
}
|
||||
|
||||
current_unit.set_movement(0);
|
||||
info_.units.insert(std::pair<location,unit>(to,current_unit));
|
||||
if(info_.map.is_village(to)) {
|
||||
get_tower(to,info_.teams,info_.team_num-1,info_.units);
|
||||
get_village(to,info_.teams,info_.team_num-1,info_.units);
|
||||
}
|
||||
|
||||
info_.disp.draw_tile(to.x,to.y);
|
||||
|
@ -295,7 +296,7 @@ void ai_interface::calculate_possible_moves(std::map<location,paths>& res, move_
|
|||
//don't take friendly villages
|
||||
if(!enemy && info_.map.is_village(dst)) {
|
||||
for(size_t n = 0; n != info_.teams.size(); ++n) {
|
||||
if(info_.teams[n].owns_tower(dst)) {
|
||||
if(info_.teams[n].owns_village(dst)) {
|
||||
if(n+1 != info_.team_num && current_team().is_enemy(n+1) == false) {
|
||||
friend_owns = true;
|
||||
}
|
||||
|
@ -508,17 +509,17 @@ void ai_interface::attack_enemy(const location& u, const location& target, int w
|
|||
|
||||
bool ai::get_villages(std::map<gamemap::location,paths>& possible_moves, const move_map& srcdst, const move_map& dstsrc, const move_map& enemy_srcdst, const move_map& enemy_dstsrc, unit_map::const_iterator leader)
|
||||
{
|
||||
//try to acquire towers
|
||||
//try to acquire villages
|
||||
for(move_map::const_iterator i = dstsrc.begin(); i != dstsrc.end(); ++i) {
|
||||
if(map_.is_village(i->first) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool want_tower = true, owned = false;
|
||||
bool want_village = true, owned = false;
|
||||
for(size_t j = 0; j != teams_.size(); ++j) {
|
||||
owned = teams_[j].owns_tower(i->first);
|
||||
owned = teams_[j].owns_village(i->first);
|
||||
if(owned && !current_team().is_enemy(j+1)) {
|
||||
want_tower = false;
|
||||
want_village = false;
|
||||
}
|
||||
|
||||
if(owned) {
|
||||
|
@ -526,12 +527,12 @@ bool ai::get_villages(std::map<gamemap::location,paths>& possible_moves, const m
|
|||
}
|
||||
}
|
||||
|
||||
//if it's a neutral tower, and we have no leader, then the village is no use to us,
|
||||
//if it's a neutral village, and we have no leader, then the village is no use to us,
|
||||
//and we don't want it.
|
||||
if(!owned && leader == units_.end())
|
||||
want_tower = false;
|
||||
want_village = false;
|
||||
|
||||
if(want_tower) {
|
||||
if(want_village) {
|
||||
std::cerr << "trying to acquire village: " << i->first.x
|
||||
<< ", " << i->first.y << "\n";
|
||||
|
||||
|
@ -775,13 +776,13 @@ void ai::do_recruitment()
|
|||
//currently just spend all the gold we can!
|
||||
const int min_gold = 0;
|
||||
|
||||
const int towers = map_.towers().size();
|
||||
int taken_towers = 0;
|
||||
const int villages = map_.villages().size();
|
||||
int taken_villages = 0;
|
||||
for(size_t j = 0; j != teams_.size(); ++j) {
|
||||
taken_towers += teams_[j].towers().size();
|
||||
taken_villages += teams_[j].villages().size();
|
||||
}
|
||||
|
||||
const int neutral_towers = towers - taken_towers;
|
||||
const int neutral_villages = villages - taken_villages;
|
||||
|
||||
//the villages per scout parameter is assumed to be based on a 2-side battle.
|
||||
//in a greater than 2 side battle, we want to recruit less scouts, since the villages
|
||||
|
@ -789,7 +790,7 @@ void ai::do_recruitment()
|
|||
const int villages_per_scout = (current_team().villages_per_scout()*teams_.size())/2;
|
||||
|
||||
//get scouts depending on how many neutral villages there are
|
||||
int scouts_wanted = villages_per_scout > 0 ? neutral_towers/villages_per_scout : 0;
|
||||
int scouts_wanted = villages_per_scout > 0 ? neutral_villages/villages_per_scout : 0;
|
||||
|
||||
std::map<std::string,int> unit_types;
|
||||
while(unit_types["scout"] < scouts_wanted) {
|
||||
|
@ -898,7 +899,7 @@ void ai::move_leader_after_recruit(const move_map& enemy_dstsrc)
|
|||
}
|
||||
|
||||
//search through villages finding one to capture
|
||||
const std::vector<gamemap::location>& villages = map_.towers();
|
||||
const std::vector<gamemap::location>& villages = map_.villages();
|
||||
for(std::vector<gamemap::location>::const_iterator v = villages.begin();
|
||||
v != villages.end(); ++v) {
|
||||
const paths::routes_map::const_iterator itor = leader_paths.routes.find(*v);
|
||||
|
@ -906,7 +907,7 @@ void ai::move_leader_after_recruit(const move_map& enemy_dstsrc)
|
|||
continue;
|
||||
}
|
||||
|
||||
const int owner = tower_owner(*v,teams_);
|
||||
const int owner = village_owner(*v,teams_);
|
||||
if(owner == -1 || current_team().is_enemy(owner+1) || leader->second.hitpoints() < leader->second.max_hitpoints()) {
|
||||
|
||||
//check that no enemies can reach the village
|
||||
|
@ -944,11 +945,11 @@ int ai::rate_terrain(const unit& u, const gamemap::location& loc)
|
|||
}
|
||||
|
||||
if(map_.is_village(terrain)) {
|
||||
const int village_owner = tower_owner(loc,teams_);
|
||||
const int owner = village_owner(loc,teams_);
|
||||
|
||||
if(village_owner == team_num_) {
|
||||
if(owner == team_num_) {
|
||||
rating += friendly_village_value;
|
||||
} else if(village_owner == -1) {
|
||||
} else if(owner == -1) {
|
||||
rating += neutral_village_value;
|
||||
} else {
|
||||
rating += enemy_village_value;
|
||||
|
|
|
@ -218,7 +218,7 @@ private:
|
|||
calculate_possible_moves(possible_moves,srcdst,dstsrc,false);
|
||||
|
||||
for(move_map::const_iterator i = dstsrc.begin(); i != dstsrc.end(); ++i) {
|
||||
if(get_info().map.is_village(i->first) && current_team().owns_tower(i->first) == false) {
|
||||
if(get_info().map.is_village(i->first) && current_team().owns_village(i->first) == false) {
|
||||
move_unit(i->second,i->first,possible_moves);
|
||||
get_villages();
|
||||
return;
|
||||
|
|
|
@ -125,18 +125,18 @@ std::vector<ai::target> ai::find_targets(unit_map::const_iterator leader, const
|
|||
}
|
||||
|
||||
if(has_leader && current_team().village_value() > 0.0) {
|
||||
const std::vector<location>& towers = map_.towers();
|
||||
for(std::vector<location>::const_iterator t = towers.begin(); t != towers.end(); ++t) {
|
||||
const std::vector<location>& villages = map_.villages();
|
||||
for(std::vector<location>::const_iterator t = villages.begin(); t != villages.end(); ++t) {
|
||||
assert(map_.on_board(*t));
|
||||
bool get_tower = true;
|
||||
bool get_village = true;
|
||||
for(size_t i = 0; i != teams_.size(); ++i) {
|
||||
if(!current_team().is_enemy(i+1) && teams_[i].owns_tower(*t)) {
|
||||
get_tower = false;
|
||||
if(!current_team().is_enemy(i+1) && teams_[i].owns_village(*t)) {
|
||||
get_village = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(get_tower) {
|
||||
if(get_village) {
|
||||
targets.push_back(target(*t,current_team().village_value()));
|
||||
}
|
||||
}
|
||||
|
|
676
src/display.cpp
676
src/display.cpp
|
@ -27,6 +27,7 @@
|
|||
#include "sound.hpp"
|
||||
#include "team.hpp"
|
||||
#include "tooltips.hpp"
|
||||
#include "unit_display.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
#include "SDL_image.h"
|
||||
|
@ -292,8 +293,17 @@ void display::scroll(double xmove, double ymove)
|
|||
}
|
||||
}
|
||||
|
||||
void display::zoom(double amount)
|
||||
int display::hex_size() const
|
||||
{
|
||||
return int(zoom_);
|
||||
}
|
||||
|
||||
double display::zoom(double amount)
|
||||
{
|
||||
if(amount == 0.0) {
|
||||
return zoom_/DefaultZoom;
|
||||
}
|
||||
|
||||
const double orig_xpos = xpos_;
|
||||
const double orig_ypos = ypos_;
|
||||
|
||||
|
@ -308,7 +318,7 @@ void display::zoom(double amount)
|
|||
zoom_ = orig_zoom;
|
||||
xpos_ = orig_xpos;
|
||||
ypos_ = orig_ypos;
|
||||
return;
|
||||
return zoom_/DefaultZoom;
|
||||
}
|
||||
|
||||
xpos_ *= zoom_;
|
||||
|
@ -325,7 +335,7 @@ void display::zoom(double amount)
|
|||
xpos_ = orig_xpos;
|
||||
ypos_ = orig_ypos;
|
||||
zoom_ = orig_zoom;
|
||||
return;
|
||||
return zoom_/DefaultZoom;
|
||||
}
|
||||
|
||||
energy_bar_rect_.x = -1;
|
||||
|
@ -333,6 +343,8 @@ void display::zoom(double amount)
|
|||
image::set_zoom(zoom_);
|
||||
map_labels_.recalculate_labels();
|
||||
invalidate_all();
|
||||
|
||||
return zoom_/DefaultZoom;
|
||||
}
|
||||
|
||||
void display::default_zoom()
|
||||
|
@ -1082,7 +1094,6 @@ void display::draw_unit_on_tile(int x, int y, SDL_Surface* unit_image_override,
|
|||
|
||||
const int max_energy = 80;
|
||||
double energy_size = 1.0;
|
||||
bool face_left = true;
|
||||
|
||||
if(unit_image_override != NULL)
|
||||
sdl_add_ref(unit_image_override);
|
||||
|
@ -1172,7 +1183,17 @@ void display::draw_unit_on_tile(int x, int y, SDL_Surface* unit_image_override,
|
|||
energy_size = double(it->second.max_hitpoints())/double(max_energy);
|
||||
}
|
||||
|
||||
face_left = it->second.facing_left();
|
||||
if(it->second.facing_left() == false) {
|
||||
//reverse the image here. image::reverse_image is more efficient, however
|
||||
//it can be used only if we are sure that unit_image came from image::get_image.
|
||||
//Since we aren't sure of that in the case of overrides, use the less efficient
|
||||
//flip_surface if the image has been over-ridden.
|
||||
if(unit_image_override == NULL) {
|
||||
unit_image.assign(image::reverse_image(unit_image));
|
||||
} else {
|
||||
unit_image.assign(flip_surface(unit_image));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(deadUnit_ == gamemap::location(x,y)) {
|
||||
|
@ -1217,7 +1238,7 @@ void display::draw_unit_on_tile(int x, int y, SDL_Surface* unit_image_override,
|
|||
ellipse_front.assign(image::get_image(buf));
|
||||
}
|
||||
|
||||
draw_unit(xpos,ypos - height_adjust,unit_image,face_left,false,
|
||||
draw_unit(xpos,ypos - height_adjust,unit_image,false,
|
||||
highlight_ratio,blend_with,submerge,ellipse_back,ellipse_front);
|
||||
}
|
||||
|
||||
|
@ -1417,8 +1438,7 @@ void display::draw_tile(int x, int y, SDL_Surface* unit_image, double alpha, Uin
|
|||
if(game_config::debug && debugHighlights_.count(gamemap::location(x,y))) {
|
||||
const scoped_sdl_surface cross(image::get_image(game_config::cross_image));
|
||||
if(cross != NULL)
|
||||
draw_unit(xpos,ypos,cross,false,false,
|
||||
debugHighlights_[loc],0);
|
||||
draw_unit(xpos,ypos,cross,false,debugHighlights_[loc],0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1475,7 +1495,7 @@ void display::draw_footstep(const gamemap::location& loc, int xloc, int yloc)
|
|||
}
|
||||
}
|
||||
|
||||
const scoped_sdl_surface image(image::get_image(*image_str));
|
||||
scoped_sdl_surface image(image::get_image(*image_str));
|
||||
if(image == NULL) {
|
||||
std::cerr << "Could not find image: " << *image_str << "\n";
|
||||
return;
|
||||
|
@ -1486,7 +1506,11 @@ void display::draw_footstep(const gamemap::location& loc, int xloc, int yloc)
|
|||
const bool vflip = (direction >= gamemap::location::SOUTH_EAST &&
|
||||
direction <= gamemap::location::SOUTH_WEST);
|
||||
|
||||
draw_unit(xloc,yloc,image,hflip,vflip,0.5);
|
||||
if(!hflip) {
|
||||
image.assign(image::reverse_image(image));
|
||||
}
|
||||
|
||||
draw_unit(xloc,yloc,image,vflip,0.5);
|
||||
|
||||
if(show_time && route_.move_left > 0 && route_.move_left < 10) {
|
||||
//draw number in yellow if terrain is light, else draw in black
|
||||
|
@ -1703,7 +1727,7 @@ SDL_Surface* display::getFlag(gamemap::TERRAIN terrain, int x, int y)
|
|||
const gamemap::location loc(x,y);
|
||||
|
||||
for(size_t i = 0; i != teams_.size(); ++i) {
|
||||
if(teams_[i].owns_tower(loc) && (!fogged(x,y) || !shrouded(x,y) && !teams_[currentTeam_].is_enemy(i+1))) {
|
||||
if(teams_[i].owns_village(loc) && (!fogged(x,y) || !shrouded(x,y) && !teams_[currentTeam_].is_enemy(i+1))) {
|
||||
char buf[50];
|
||||
sprintf(buf,"terrain/flag-team%d.png",i+1);
|
||||
return image::get_image(buf);
|
||||
|
@ -1716,62 +1740,14 @@ SDL_Surface* display::getFlag(gamemap::TERRAIN terrain, int x, int y)
|
|||
void display::blit_surface(int x, int y, SDL_Surface* surface, SDL_Rect* srcrect, SDL_Rect* clip_rect)
|
||||
{
|
||||
SDL_Surface* const target = video().getSurface();
|
||||
|
||||
SDL_Rect clip;
|
||||
if(clip_rect == NULL) {
|
||||
clip = screen_area();
|
||||
clip_rect = &clip;
|
||||
SDL_Rect dst = {x,y,0,0};
|
||||
|
||||
if(clip_rect != NULL) {
|
||||
const clip_rect_setter(target,*clip_rect);
|
||||
SDL_BlitSurface(surface,srcrect,target,&dst);
|
||||
} else {
|
||||
SDL_BlitSurface(surface,srcrect,target,&dst);
|
||||
}
|
||||
|
||||
SDL_Rect src;
|
||||
if(srcrect == NULL) {
|
||||
src.x = 0;
|
||||
src.y = 0;
|
||||
src.w = surface->w;
|
||||
src.h = surface->h;
|
||||
srcrect = &src;
|
||||
}
|
||||
|
||||
if(x + srcrect->w < clip_rect->x) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(y + srcrect->h < clip_rect->y) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(x > clip_rect->x + clip_rect->w) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(y > clip_rect->y + clip_rect->h) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(x < clip_rect->x) {
|
||||
const int diff = clip_rect->x - x;
|
||||
srcrect->x += diff;
|
||||
srcrect->w -= diff;
|
||||
x = clip_rect->x;
|
||||
}
|
||||
|
||||
if(y < clip_rect->y) {
|
||||
const int diff = clip_rect->y - y;
|
||||
srcrect->y += diff;
|
||||
srcrect->h -= diff;
|
||||
y = clip_rect->y;
|
||||
}
|
||||
|
||||
if(x + srcrect->w > clip_rect->x + clip_rect->w) {
|
||||
srcrect->w = clip_rect->x + clip_rect->w - x;
|
||||
}
|
||||
|
||||
if(y + srcrect->h > clip_rect->y + clip_rect->h) {
|
||||
srcrect->h = clip_rect->y + clip_rect->h - y;
|
||||
}
|
||||
|
||||
SDL_Rect dstrect = {x,y,0,0};
|
||||
SDL_BlitSurface(surface,srcrect,target,&dstrect);
|
||||
}
|
||||
|
||||
SDL_Surface* display::getMinimap(int w, int h)
|
||||
|
@ -1814,28 +1790,11 @@ void display::set_route(const paths::route* route)
|
|||
invalidate_route();
|
||||
}
|
||||
|
||||
void display::move_unit(const std::vector<gamemap::location>& path, unit& u)
|
||||
void display::remove_footstep(const gamemap::location& loc)
|
||||
{
|
||||
for(size_t i = 0; i+1 < path.size(); ++i) {
|
||||
if(path[i+1].x > path[i].x) {
|
||||
u.set_facing_left(true);
|
||||
} else if(path[i+1].x < path[i].x) {
|
||||
u.set_facing_left(false);
|
||||
}
|
||||
|
||||
//remove the footstep we are on.
|
||||
const std::vector<gamemap::location>::iterator it = std::find(route_.steps.begin(),route_.steps.end(),path[i]);
|
||||
if(it != route_.steps.end())
|
||||
route_.steps.erase(it);
|
||||
|
||||
move_unit_between(path[i],path[i+1],u);
|
||||
}
|
||||
|
||||
//make sure the entire path is cleaned properly
|
||||
for(std::vector<gamemap::location>::const_iterator it = path.begin();
|
||||
it != path.end(); ++it) {
|
||||
draw_tile(it->x,it->y);
|
||||
}
|
||||
const std::vector<gamemap::location>::iterator it = std::find(route_.steps.begin(),route_.steps.end(),loc);
|
||||
if(it != route_.steps.end())
|
||||
route_.steps.erase(it);
|
||||
}
|
||||
|
||||
void display::float_label(const gamemap::location& loc, const std::string& text,
|
||||
|
@ -1850,545 +1809,12 @@ void display::float_label(const gamemap::location& loc, const std::string& text,
|
|||
0,-2,60,screen_area());
|
||||
}
|
||||
|
||||
bool display::unit_attack_ranged(const gamemap::location& a,
|
||||
const gamemap::location& b, int damage,
|
||||
const attack_type& attack)
|
||||
{
|
||||
const bool hide = update_locked() || fogged(a.x,a.y) && fogged(b.x,b.y)
|
||||
|| preferences::show_combat() == false;
|
||||
|
||||
const unit_map::iterator att = units_.find(a);
|
||||
const unit_map::iterator def = units_.find(b);
|
||||
|
||||
def->second.set_defending(true,attack_type::LONG_RANGE);
|
||||
|
||||
//the missile frames are based around the time when the missile impacts.
|
||||
//the 'real' frames are based around the time when the missile launches.
|
||||
const int first_missile = minimum<int>(-100,
|
||||
attack.get_first_frame(attack_type::MISSILE_FRAME));
|
||||
const int last_missile = attack.get_last_frame(attack_type::MISSILE_FRAME);
|
||||
|
||||
const int real_last_missile = last_missile - first_missile;
|
||||
const int missile_impact = -first_missile;
|
||||
|
||||
const int time_resolution = 20;
|
||||
const int acceleration = turbo() ? 5:1;
|
||||
|
||||
const std::vector<attack_type::sfx>& sounds = attack.sound_effects();
|
||||
std::vector<attack_type::sfx>::const_iterator sfx_it = sounds.begin();
|
||||
|
||||
const std::string& hit_sound = def->second.type().get_hit_sound();
|
||||
bool played_hit_sound = (hit_sound == "" || hit_sound == "null");
|
||||
const int play_hit_sound_at = 0;
|
||||
|
||||
const bool hits = damage > 0;
|
||||
const int begin_at = attack.get_first_frame();
|
||||
const int end_at = maximum((damage+1)*time_resolution+missile_impact,
|
||||
maximum(attack.get_last_frame(),real_last_missile));
|
||||
|
||||
const double xsrc = get_location_x(a);
|
||||
const double ysrc = get_location_y(a);
|
||||
const double xdst = get_location_x(b);
|
||||
const double ydst = get_location_y(b);
|
||||
|
||||
gamemap::location update_tiles[6];
|
||||
get_adjacent_tiles(a,update_tiles);
|
||||
|
||||
const bool vflip = b.y > a.y || b.y == a.y && is_even(a.x);
|
||||
const bool hflip = b.x < a.x;
|
||||
const attack_type::FRAME_DIRECTION dir =
|
||||
(a.x == b.x) ? attack_type::VERTICAL:attack_type::DIAGONAL;
|
||||
|
||||
bool dead = false;
|
||||
const int drain_speed = 1*acceleration;
|
||||
|
||||
int flash_num = 0;
|
||||
|
||||
int ticks = SDL_GetTicks();
|
||||
|
||||
bool shown_label = false;
|
||||
|
||||
for(int i = begin_at; i < end_at; i += time_resolution*acceleration) {
|
||||
events::pump();
|
||||
|
||||
//this is a while instead of an if, because there might be multiple
|
||||
//sounds playing simultaneously or close together
|
||||
while(!hide && sfx_it != sounds.end() && i >= sfx_it->time) {
|
||||
const std::string& sfx = hits ? sfx_it->on_hit : sfx_it->on_miss;
|
||||
if(sfx.empty() == false) {
|
||||
sound::play_sound(hits ? sfx_it->on_hit : sfx_it->on_miss);
|
||||
}
|
||||
|
||||
++sfx_it;
|
||||
}
|
||||
|
||||
if(!hide && hits && !played_hit_sound && i >= play_hit_sound_at) {
|
||||
sound::play_sound(hit_sound);
|
||||
played_hit_sound = true;
|
||||
}
|
||||
|
||||
const std::string* unit_image = attack.get_frame(i);
|
||||
|
||||
if(unit_image == NULL) {
|
||||
unit_image =
|
||||
&att->second.type().image_fighting(attack_type::LONG_RANGE);
|
||||
}
|
||||
|
||||
if(!hide) {
|
||||
const scoped_sdl_surface image((unit_image == NULL) ? NULL : image::get_image(*unit_image));
|
||||
draw_tile(a.x,a.y,image);
|
||||
}
|
||||
|
||||
if(damage > 0 && i >= missile_impact && shown_label == false) {
|
||||
shown_label = true;
|
||||
|
||||
char buf[50];
|
||||
sprintf(buf,"%d",damage);
|
||||
float_label(b,buf,255,0,0);
|
||||
}
|
||||
|
||||
Uint32 defensive_colour = 0;
|
||||
double defensive_alpha = 1.0;
|
||||
|
||||
if(damage > 0 && i >= missile_impact) {
|
||||
if(def->second.gets_hit(minimum<int>(drain_speed,damage))) {
|
||||
dead = true;
|
||||
damage = 0;
|
||||
} else {
|
||||
damage -= drain_speed;
|
||||
}
|
||||
|
||||
if(flash_num == 0 || flash_num == 2) {
|
||||
defensive_alpha = 0.0;
|
||||
defensive_colour = rgb(200,0,0);
|
||||
}
|
||||
|
||||
++flash_num;
|
||||
}
|
||||
|
||||
for(int j = 0; j != 6; ++j) {
|
||||
if(update_tiles[j] != b) {
|
||||
draw_tile(update_tiles[j].x,update_tiles[j].y);
|
||||
}
|
||||
}
|
||||
|
||||
draw_tile(b.x,b.y,NULL,defensive_alpha,defensive_colour);
|
||||
|
||||
if(i >= 0 && i < real_last_missile && !hide) {
|
||||
const int missile_frame = i + first_missile;
|
||||
|
||||
const std::string* missile_image
|
||||
= attack.get_frame(missile_frame,NULL,
|
||||
attack_type::MISSILE_FRAME,dir);
|
||||
|
||||
static const std::string default_missile(game_config::missile_n_image);
|
||||
static const std::string default_diag_missile(game_config::missile_ne_image);
|
||||
if(missile_image == NULL) {
|
||||
if(dir == attack_type::VERTICAL)
|
||||
missile_image = &default_missile;
|
||||
else
|
||||
missile_image = &default_diag_missile;
|
||||
}
|
||||
|
||||
const scoped_sdl_surface img(image::get_image(*missile_image));
|
||||
if(img != NULL) {
|
||||
double pos = double(missile_impact - i)/double(missile_impact);
|
||||
if(pos < 0.0)
|
||||
pos = 0.0;
|
||||
const int xpos = int(xsrc*pos + xdst*(1.0-pos));
|
||||
const int ypos = int(ysrc*pos + ydst*(1.0-pos));
|
||||
|
||||
draw_unit(xpos,ypos,img,!hflip,vflip);
|
||||
}
|
||||
}
|
||||
|
||||
const int wait_time = ticks + time_resolution - SDL_GetTicks();
|
||||
if(wait_time > 0 && !hide)
|
||||
SDL_Delay(wait_time);
|
||||
|
||||
ticks = SDL_GetTicks();
|
||||
|
||||
update_display();
|
||||
}
|
||||
|
||||
def->second.set_defending(false);
|
||||
|
||||
draw_tile(a.x,a.y);
|
||||
draw_tile(b.x,b.y);
|
||||
|
||||
if(dead) {
|
||||
unit_die(b);
|
||||
}
|
||||
|
||||
return dead;
|
||||
}
|
||||
|
||||
bool display::unit_attack(const gamemap::location& a,
|
||||
const gamemap::location& b, int damage,
|
||||
const attack_type& attack)
|
||||
{
|
||||
const bool hide = update_locked() || fogged(a.x,a.y) && fogged(b.x,b.y)
|
||||
|| preferences::show_combat() == false;
|
||||
|
||||
if(!hide) {
|
||||
const double side_threshhold = 80.0;
|
||||
|
||||
double xloc = get_location_x(a);
|
||||
double yloc = get_location_y(a);
|
||||
|
||||
//we try to scroll the map if the unit is at the edge.
|
||||
//keep track of the old position, and if the map moves at all,
|
||||
//then recenter it on the unit
|
||||
double oldxpos = xpos_;
|
||||
double oldypos = ypos_;
|
||||
if(xloc < map_area().x + side_threshhold) {
|
||||
scroll(xloc - side_threshhold - map_area().x,0.0);
|
||||
}
|
||||
|
||||
if(yloc < map_area().y + side_threshhold) {
|
||||
scroll(0.0,yloc - side_threshhold - map_area().y);
|
||||
}
|
||||
|
||||
if(xloc + zoom_ > map_area().x + map_area().w - side_threshhold) {
|
||||
scroll(((xloc + zoom_) -
|
||||
(map_area().x + map_area().w - side_threshhold)),0.0);
|
||||
}
|
||||
|
||||
if(yloc + zoom_ > map_area().y + map_area().h - side_threshhold) {
|
||||
scroll(0.0,((yloc + zoom_) -
|
||||
(map_area().y + map_area().h - side_threshhold)));
|
||||
}
|
||||
|
||||
if(oldxpos != xpos_ || oldypos != ypos_) {
|
||||
scroll_to_tile(a.x,a.y,WARP);
|
||||
}
|
||||
}
|
||||
|
||||
log_scope("unit_attack");
|
||||
invalidate_all();
|
||||
draw(true,true);
|
||||
|
||||
const unit_map::iterator att = units_.find(a);
|
||||
assert(att != units_.end());
|
||||
|
||||
unit& attacker = att->second;
|
||||
|
||||
const unit_map::iterator def = units_.find(b);
|
||||
assert(def != units_.end());
|
||||
|
||||
if(b.x > a.x) {
|
||||
att->second.set_facing_left(true);
|
||||
def->second.set_facing_left(false);
|
||||
} else if(b.x < a.x) {
|
||||
att->second.set_facing_left(false);
|
||||
def->second.set_facing_left(true);
|
||||
}
|
||||
|
||||
if(attack.range() == attack_type::LONG_RANGE) {
|
||||
return unit_attack_ranged(a,b,damage,attack);
|
||||
}
|
||||
|
||||
const bool hits = damage > 0;
|
||||
const std::vector<attack_type::sfx>& sounds = attack.sound_effects();
|
||||
std::vector<attack_type::sfx>::const_iterator sfx_it = sounds.begin();
|
||||
|
||||
const std::string& hit_sound = def->second.type().get_hit_sound();
|
||||
bool played_hit_sound = (hit_sound == "" || hit_sound == "null");
|
||||
const int play_hit_sound_at = 0;
|
||||
|
||||
const int time_resolution = 20;
|
||||
const int acceleration = turbo() ? 5 : 1;
|
||||
|
||||
def->second.set_defending(true,attack_type::SHORT_RANGE);
|
||||
|
||||
const int begin_at = minimum<int>(-200,attack.get_first_frame());
|
||||
const int end_at = maximum<int>((damage+1)*time_resolution,
|
||||
maximum<int>(200,
|
||||
attack.get_last_frame()));
|
||||
|
||||
const double xsrc = get_location_x(a);
|
||||
const double ysrc = get_location_y(a);
|
||||
const double xdst = get_location_x(b)*0.6 + xsrc*0.4;
|
||||
const double ydst = get_location_y(b)*0.6 + ysrc*0.4;
|
||||
|
||||
gamemap::location update_tiles[6];
|
||||
get_adjacent_tiles(b,update_tiles);
|
||||
|
||||
bool dead = false;
|
||||
const int drain_speed = 1*acceleration;
|
||||
|
||||
int flash_num = 0;
|
||||
|
||||
int ticks = SDL_GetTicks();
|
||||
|
||||
hiddenUnit_ = a;
|
||||
|
||||
const gamemap::TERRAIN src_terrain = map_.get_terrain(a);
|
||||
const gamemap::TERRAIN dst_terrain = map_.get_terrain(b);
|
||||
|
||||
const double src_height_adjust = attacker.is_flying() ? 0 : map_.get_terrain_info(src_terrain).unit_height_adjust() * (zoom_/DefaultZoom);
|
||||
const double dst_height_adjust = attacker.is_flying() ? 0 : map_.get_terrain_info(dst_terrain).unit_height_adjust() * (zoom_/DefaultZoom);
|
||||
|
||||
const double src_submerge = attacker.is_flying() ? 0 : map_.get_terrain_info(src_terrain).unit_submerge();
|
||||
const double dst_submerge = attacker.is_flying() ? 0 : map_.get_terrain_info(dst_terrain).unit_submerge();
|
||||
|
||||
bool shown_label = false;
|
||||
|
||||
for(int i = begin_at; i < end_at; i += time_resolution*acceleration) {
|
||||
events::pump();
|
||||
|
||||
//this is a while instead of an if, because there might be multiple
|
||||
//sounds playing simultaneously or close together
|
||||
while(!hide && sfx_it != sounds.end() && i >= sfx_it->time) {
|
||||
const std::string& sfx = hits ? sfx_it->on_hit : sfx_it->on_miss;
|
||||
if(sfx.empty() == false) {
|
||||
sound::play_sound(hits ? sfx_it->on_hit : sfx_it->on_miss);
|
||||
}
|
||||
|
||||
++sfx_it;
|
||||
}
|
||||
|
||||
if(!hide && hits && !played_hit_sound && i >= play_hit_sound_at) {
|
||||
sound::play_sound(hit_sound);
|
||||
played_hit_sound = true;
|
||||
}
|
||||
|
||||
for(int j = 0; j != 6; ++j) {
|
||||
draw_tile(update_tiles[j].x,update_tiles[j].y);
|
||||
}
|
||||
|
||||
Uint32 defender_colour = 0;
|
||||
double defender_alpha = 1.0;
|
||||
|
||||
if(damage > 0 && i >= 0 && shown_label == false) {
|
||||
shown_label = true;
|
||||
char buf[50];
|
||||
sprintf(buf,"%d",damage);
|
||||
float_label(b,buf,255,0,0);
|
||||
}
|
||||
|
||||
if(damage > 0 && i >= 0) {
|
||||
if(def->second.gets_hit(minimum<int>(drain_speed,damage))) {
|
||||
dead = true;
|
||||
damage = 0;
|
||||
} else {
|
||||
damage -= drain_speed;
|
||||
}
|
||||
|
||||
if(flash_num == 0 || flash_num == 2) {
|
||||
defender_alpha = 0.0;
|
||||
defender_colour = rgb(200,0,0);
|
||||
}
|
||||
|
||||
++flash_num;
|
||||
}
|
||||
|
||||
draw_tile(b.x,b.y,NULL,defender_alpha,defender_colour);
|
||||
|
||||
int xoffset = 0;
|
||||
const std::string* unit_image = attack.get_frame(i,&xoffset);
|
||||
if(!attacker.facing_left())
|
||||
xoffset *= -1;
|
||||
|
||||
xoffset = int(double(xoffset)*(zoom_/DefaultZoom));
|
||||
|
||||
if(unit_image == NULL)
|
||||
unit_image = &attacker.image();
|
||||
|
||||
const scoped_sdl_surface image((unit_image == NULL) ? NULL : image::get_image(*unit_image));
|
||||
|
||||
const double pos = double(i)/double(i < 0 ? begin_at : end_at);
|
||||
const int posx = int(pos*xsrc + (1.0-pos)*xdst) + xoffset;
|
||||
const int posy = int(pos*ysrc + (1.0-pos)*ydst);
|
||||
|
||||
const int height_adjust = int(src_height_adjust*pos + dst_height_adjust*(1.0-pos));
|
||||
const double submerge = src_submerge*pos + dst_submerge*(1.0-pos);
|
||||
|
||||
if(image != NULL && !hide)
|
||||
draw_unit(posx,posy-height_adjust,image,attacker.facing_left(),false,1.0,0,submerge);
|
||||
|
||||
const int wait_time = ticks + time_resolution - SDL_GetTicks();
|
||||
if(wait_time > 0 && !hide)
|
||||
SDL_Delay(wait_time);
|
||||
|
||||
ticks = SDL_GetTicks();
|
||||
|
||||
update_display();
|
||||
}
|
||||
|
||||
hiddenUnit_ = gamemap::location();
|
||||
def->second.set_defending(false);
|
||||
|
||||
draw_tile(a.x,a.y);
|
||||
draw_tile(b.x,b.y);
|
||||
|
||||
if(dead) {
|
||||
unit_die(b);
|
||||
}
|
||||
|
||||
return dead;
|
||||
}
|
||||
|
||||
void display::unit_die(const gamemap::location& loc, SDL_Surface* image)
|
||||
{
|
||||
if(update_locked() || fogged(loc.x,loc.y)
|
||||
|| preferences::show_combat() == false)
|
||||
return;
|
||||
|
||||
const unit_map::const_iterator u = units_.find(loc);
|
||||
assert(u != units_.end());
|
||||
|
||||
const std::string& die_sound = u->second.type().die_sound();
|
||||
if(die_sound != "" && die_sound != "null") {
|
||||
sound::play_sound(die_sound);
|
||||
}
|
||||
|
||||
const int frame_time = 30;
|
||||
int ticks = SDL_GetTicks();
|
||||
|
||||
for(double alpha = 1.0; alpha > 0.0; alpha -= 0.05) {
|
||||
draw_tile(loc.x,loc.y,image,alpha);
|
||||
|
||||
const int wait_time = ticks + frame_time - SDL_GetTicks();
|
||||
|
||||
if(wait_time > 0 && !turbo())
|
||||
SDL_Delay(wait_time);
|
||||
|
||||
ticks = SDL_GetTicks();
|
||||
|
||||
update_display();
|
||||
}
|
||||
|
||||
draw(true,true);
|
||||
}
|
||||
|
||||
void display::move_unit_between(const gamemap::location& a,
|
||||
const gamemap::location& b,
|
||||
const unit& u)
|
||||
{
|
||||
if(update_locked() || team_valid()
|
||||
&& teams_[currentTeam_].fogged(a.x,a.y)
|
||||
&& teams_[currentTeam_].fogged(b.x,b.y))
|
||||
return;
|
||||
|
||||
const bool face_left = u.facing_left();
|
||||
|
||||
const double side_threshhold = 80.0;
|
||||
|
||||
double xsrc = get_location_x(a);
|
||||
double ysrc = get_location_y(a);
|
||||
double xdst = get_location_x(b);
|
||||
double ydst = get_location_y(b);
|
||||
|
||||
const gamemap::TERRAIN src_terrain = map_.get_terrain(a);
|
||||
const gamemap::TERRAIN dst_terrain = map_.get_terrain(b);
|
||||
|
||||
const int src_height_adjust = u.is_flying() ? 0 : int(map_.get_terrain_info(src_terrain).unit_height_adjust() * (zoom_/DefaultZoom));
|
||||
const int dst_height_adjust = u.is_flying() ? 0 : int(map_.get_terrain_info(dst_terrain).unit_height_adjust() * (zoom_/DefaultZoom));
|
||||
|
||||
const double src_submerge = u.is_flying() ? 0 : int(map_.get_terrain_info(src_terrain).unit_submerge());
|
||||
const double dst_submerge = u.is_flying() ? 0 : int(map_.get_terrain_info(dst_terrain).unit_submerge());
|
||||
|
||||
const double nsteps = turbo() ? 3.0 : 10.0;
|
||||
const double xstep = (xdst - xsrc)/nsteps;
|
||||
const double ystep = (ydst - ysrc)/nsteps;
|
||||
|
||||
const int time_between_frames = turbo() ? 2 : 10;
|
||||
int ticks = SDL_GetTicks();
|
||||
|
||||
int skips = 0;
|
||||
|
||||
for(double i = 0.0; i < nsteps; i += 1.0) {
|
||||
events::pump();
|
||||
|
||||
const scoped_sdl_surface image(image::get_image(u.type().image()));
|
||||
if(image == NULL) {
|
||||
std::cerr << "failed to get image " << u.type().image() << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
xsrc = get_location_x(a);
|
||||
ysrc = get_location_y(a);
|
||||
xdst = get_location_x(b);
|
||||
ydst = get_location_y(b);
|
||||
|
||||
double xloc = xsrc + xstep*i;
|
||||
double yloc = ysrc + ystep*i;
|
||||
|
||||
//we try to scroll the map if the unit is at the edge.
|
||||
//keep track of the old position, and if the map moves at all,
|
||||
//then recenter it on the unit
|
||||
double oldxpos = xpos_;
|
||||
double oldypos = ypos_;
|
||||
if(xloc < side_threshhold) {
|
||||
scroll(xloc - side_threshhold,0.0);
|
||||
}
|
||||
|
||||
if(yloc < side_threshhold) {
|
||||
scroll(0.0,yloc - side_threshhold);
|
||||
}
|
||||
|
||||
if(xloc + double(image->w) > this->mapx() - side_threshhold) {
|
||||
scroll(((xloc + double(image->w)) -
|
||||
(this->mapx() - side_threshhold)),0.0);
|
||||
}
|
||||
|
||||
if(yloc + double(image->h) > this->y() - side_threshhold) {
|
||||
scroll(0.0,((yloc + double(image->h)) -
|
||||
(this->y() - side_threshhold)));
|
||||
}
|
||||
|
||||
if(oldxpos != xpos_ || oldypos != ypos_) {
|
||||
scroll_to_tile(b.x,b.y,WARP);
|
||||
}
|
||||
|
||||
xsrc = get_location_x(a);
|
||||
ysrc = get_location_y(a);
|
||||
xdst = get_location_x(b);
|
||||
ydst = get_location_y(b);
|
||||
|
||||
xloc = xsrc + xstep*i;
|
||||
yloc = ysrc + ystep*i;
|
||||
|
||||
//invalidate the source tile and all adjacent tiles,
|
||||
//since the unit can partially overlap adjacent tiles
|
||||
gamemap::location adjacent[6];
|
||||
get_adjacent_tiles(a,adjacent);
|
||||
draw_tile(a.x,a.y);
|
||||
for(int tile = 0; tile != 6; ++tile) {
|
||||
draw_tile(adjacent[tile].x,adjacent[tile].y);
|
||||
}
|
||||
|
||||
const int height_adjust = src_height_adjust + (dst_height_adjust-src_height_adjust)*(i/nsteps);
|
||||
const double submerge = src_submerge + (dst_submerge-src_submerge)*(i/nsteps);
|
||||
|
||||
draw(false);
|
||||
draw_unit((int)xloc,(int)yloc - height_adjust,image,face_left,false,1.0,0,submerge);
|
||||
|
||||
const int new_ticks = SDL_GetTicks();
|
||||
const int wait_time = time_between_frames - (new_ticks - ticks);
|
||||
if(wait_time > 0) {
|
||||
SDL_Delay(wait_time);
|
||||
}
|
||||
|
||||
ticks = SDL_GetTicks();
|
||||
|
||||
if(wait_time >= 0 || skips == 4 || (i+1.0) >= nsteps) {
|
||||
skips = 0;
|
||||
update_display();
|
||||
} else {
|
||||
++skips;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void display::draw_unit(int x, int y, SDL_Surface* image,
|
||||
bool reverse, bool upside_down,
|
||||
double alpha, Uint32 blendto, double submerged,
|
||||
bool upside_down, double alpha, Uint32 blendto, double submerged,
|
||||
SDL_Surface* ellipse_back, SDL_Surface* ellipse_front)
|
||||
{
|
||||
if(ellipse_back != NULL) {
|
||||
draw_unit(x,y,ellipse_back,false,false,blendto == 0 ? alpha : 1.0,0,submerged);
|
||||
draw_unit(x,y,ellipse_back,false,blendto == 0 ? alpha : 1.0,0,submerged);
|
||||
}
|
||||
|
||||
sdl_add_ref(image);
|
||||
|
@ -2398,10 +1824,6 @@ void display::draw_unit(int x, int y, SDL_Surface* image,
|
|||
surf.assign(flop_surface(surf));
|
||||
}
|
||||
|
||||
if(!reverse) {
|
||||
surf.assign(flip_surface(surf));
|
||||
}
|
||||
|
||||
if(alpha > 1.0) {
|
||||
surf.assign(brighten_image(surf,alpha));
|
||||
} else if(alpha != 1.0 && blendto != 0) {
|
||||
|
@ -2432,7 +1854,7 @@ void display::draw_unit(int x, int y, SDL_Surface* image,
|
|||
}
|
||||
|
||||
if(ellipse_front != NULL) {
|
||||
draw_unit(x,y,ellipse_front,false,false,blendto == 0 ? alpha : 1.0,0,submerged);
|
||||
draw_unit(x,y,ellipse_front,false,blendto == 0 ? alpha : 1.0,0,submerged);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -79,12 +79,16 @@ public:
|
|||
void scroll(double xmov, double ymov);
|
||||
|
||||
//function which zooms the display by the specified amount. Negative
|
||||
//valeus zoom out.
|
||||
void zoom(double amount);
|
||||
//valeus zoom out. Returns the current zoom ratio
|
||||
double zoom(double amount=0.0);
|
||||
|
||||
//function to take the zoom amount to the default.
|
||||
void default_zoom();
|
||||
|
||||
//function which returns the size of a hex in pixels
|
||||
//(from top tip to bottom tip or left edge to right edge)
|
||||
int hex_size() const;
|
||||
|
||||
enum SCROLL_TYPE { SCROLL, WARP };
|
||||
|
||||
//function which will scroll such that location x,y is on-screen.
|
||||
|
@ -152,13 +156,8 @@ public:
|
|||
double get_location_x(const gamemap::location& loc) const;
|
||||
double get_location_y(const gamemap::location& loc) const;
|
||||
|
||||
//function to display movement of a unit along the given sequence of tiles
|
||||
void move_unit(const std::vector<gamemap::location>& path, unit& u);
|
||||
|
||||
//function to show one unit taking one attack attempt at another. damage
|
||||
//is the amount of damage inflicted, and 0 if the attack misses.
|
||||
bool unit_attack(const gamemap::location& a, const gamemap::location& b,
|
||||
int damage, const attack_type& attack);
|
||||
//function to remove a footstep from a specific location
|
||||
void remove_footstep(const gamemap::location& loc);
|
||||
|
||||
//function to draw the tile at location (x,y). If unit_image is not NULL,
|
||||
//then it will be used, otherwise the unit's default image will be used.
|
||||
|
@ -284,8 +283,6 @@ public:
|
|||
|
||||
const theme::menu* menu_pressed(int mousex, int mousey, bool button_pressed);
|
||||
|
||||
void unit_die(const gamemap::location& loc, SDL_Surface* image=NULL);
|
||||
|
||||
void add_observer(const std::string& name);
|
||||
void remove_observer(const std::string& name);
|
||||
|
||||
|
@ -295,14 +292,6 @@ public:
|
|||
enum MESSAGE_TYPE { MESSAGE_PUBLIC, MESSAGE_PRIVATE };
|
||||
void add_chat_message(const std::string& speaker, int side, const std::string& msg, MESSAGE_TYPE type);
|
||||
|
||||
private:
|
||||
display(const display&);
|
||||
void operator=(const display&);
|
||||
|
||||
void move_unit_between(const gamemap::location& a,
|
||||
const gamemap::location& b,
|
||||
const unit& u);
|
||||
|
||||
//function to draw the image of a unit at a certain location
|
||||
//x,y: pixel location on screen to draw the unit
|
||||
//image: the image of the unit
|
||||
|
@ -314,13 +303,12 @@ private:
|
|||
//submerged: the amount of the unit out of 1.0 that is submerged
|
||||
// (presumably under water) and thus shouldn't be drawn
|
||||
void draw_unit(int x, int y, SDL_Surface* image,
|
||||
bool reverse, bool upside_down=false,
|
||||
double alpha=1.0, Uint32 blendto=0, double submerged=0.0,
|
||||
bool upside_down=false,double alpha=1.0, Uint32 blendto=0, double submerged=0.0,
|
||||
SDL_Surface* ellipse_back=NULL, SDL_Surface* ellipse_front=NULL);
|
||||
|
||||
bool unit_attack_ranged(const gamemap::location& a,
|
||||
const gamemap::location& b,
|
||||
int damage, const attack_type& attack);
|
||||
private:
|
||||
display(const display&);
|
||||
void operator=(const display&);
|
||||
|
||||
void draw_sidebar();
|
||||
void draw_minimap(int x, int y, int w, int h);
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
namespace game_config
|
||||
{
|
||||
int base_income = 2;
|
||||
int tower_income = 1;
|
||||
int village_income = 1;
|
||||
int heal_amount = 4;
|
||||
int healer_heals_per_turn = 8;
|
||||
int cure_amount = 8;
|
||||
|
@ -64,7 +64,7 @@ namespace game_config
|
|||
const config& v = *cfg;
|
||||
|
||||
base_income = atoi(v["base_income"].c_str());
|
||||
tower_income = atoi(v["village_income"].c_str());
|
||||
village_income = atoi(v["village_income"].c_str());
|
||||
heal_amount = atoi(v["heal_amount"].c_str());
|
||||
healer_heals_per_turn = atoi(v["healer_heals_per_turn"].c_str());
|
||||
cure_amount = atoi(v["cure_amount"].c_str());
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
namespace game_config
|
||||
{
|
||||
extern int base_income;
|
||||
extern int tower_income;
|
||||
extern int village_income;
|
||||
extern int heal_amount;
|
||||
extern int healer_heals_per_turn;
|
||||
extern int cure_amount;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "replay.hpp"
|
||||
#include "show_dialog.hpp"
|
||||
#include "sound.hpp"
|
||||
#include "unit_display.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
|
@ -434,7 +435,7 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
|
|||
atoi(yvals[i].c_str())-1));
|
||||
}
|
||||
|
||||
screen->move_unit(path,dummy_unit);
|
||||
unit_display::move_unit(*screen,*game_map,path,dummy_unit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -868,7 +869,7 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
|
|||
if(game_events::unit_matches_filter(un,cfg)) {
|
||||
if(cfg["animate"] == "yes") {
|
||||
screen->scroll_to_tile(un->first.x,un->first.y,display::WARP);
|
||||
screen->unit_die(un->first);
|
||||
unit_display::unit_die(*screen,un->first,un->second);
|
||||
}
|
||||
|
||||
units->erase(un++);
|
||||
|
|
|
@ -20,6 +20,8 @@ mini_terrain_cache_map mini_terrain_cache;
|
|||
typedef std::map<std::string,SDL_Surface*> image_map;
|
||||
image_map images_,scaledImages_,unmaskedImages_,greyedImages_,brightenedImages_;
|
||||
|
||||
std::map<SDL_Surface*,SDL_Surface*> reversedImages_;
|
||||
|
||||
int red_adjust = 0, green_adjust = 0, blue_adjust = 0;
|
||||
|
||||
std::string image_mask;
|
||||
|
@ -74,6 +76,7 @@ void flush_cache()
|
|||
clear_surfaces(greyedImages_);
|
||||
clear_surfaces(brightenedImages_);
|
||||
clear_surfaces(mini_terrain_cache);
|
||||
clear_surfaces(reversedImages_);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -111,6 +114,7 @@ void set_colour_adjustment(int r, int g, int b)
|
|||
clear_surfaces(scaledImages_);
|
||||
clear_surfaces(greyedImages_);
|
||||
clear_surfaces(brightenedImages_);
|
||||
clear_surfaces(reversedImages_);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,6 +140,7 @@ void set_image_mask(const std::string& image)
|
|||
clear_surfaces(scaledImages_);
|
||||
clear_surfaces(greyedImages_);
|
||||
clear_surfaces(brightenedImages_);
|
||||
clear_surfaces(reversedImages_);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -148,6 +153,7 @@ void set_zoom(double amount)
|
|||
clear_surfaces(greyedImages_);
|
||||
clear_surfaces(brightenedImages_);
|
||||
clear_surfaces(unmaskedImages_);
|
||||
clear_surfaces(reversedImages_);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -286,6 +292,28 @@ SDL_Surface* get_image_dim(const std::string& filename, size_t x, size_t y)
|
|||
return surf;
|
||||
}
|
||||
|
||||
SDL_Surface* reverse_image(SDL_Surface* surf)
|
||||
{
|
||||
if(surf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const std::map<SDL_Surface*,SDL_Surface*>::iterator itor = reversedImages_.find(surf);
|
||||
if(itor != reversedImages_.end()) {
|
||||
sdl_add_ref(itor->second);
|
||||
return itor->second;
|
||||
}
|
||||
|
||||
SDL_Surface* const rev = flip_surface(surf);
|
||||
if(rev == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
reversedImages_.insert(std::pair<SDL_Surface*,SDL_Surface*>(surf,rev));
|
||||
sdl_add_ref(rev);
|
||||
return rev;
|
||||
}
|
||||
|
||||
void register_image(const std::string& id, SDL_Surface* surf)
|
||||
{
|
||||
if(surf == NULL) {
|
||||
|
|
|
@ -9,78 +9,84 @@
|
|||
|
||||
class team;
|
||||
|
||||
//this module manages the cache of images. With an image name, you can get
|
||||
//the surface corresponding to that image, and don't need to free the image.
|
||||
//Note that surfaces returned from here are invalidated whenever events::pump()
|
||||
//is called, and so shouldn't be kept, but should be regotten from here as
|
||||
//needed.
|
||||
///this module manages the cache of images. With an image name, you can get
|
||||
///the surface corresponding to that image, and don't need to free the image.
|
||||
///Note that surfaces returned from here are invalidated whenever events::pump()
|
||||
///is called, and so shouldn't be kept, but should be regotten from here as
|
||||
///needed.
|
||||
//
|
||||
//images come in a number of varieties:
|
||||
// - unscaled: no modifications have been done on the image.
|
||||
// - scaled: images are scaled to the size of a tile
|
||||
// - greyed: images are scaled and in greyscale
|
||||
// - brightened: images are scaled and brighter than normal.
|
||||
///images come in a number of varieties:
|
||||
/// - unscaled: no modifications have been done on the image.
|
||||
/// - scaled: images are scaled to the size of a tile
|
||||
/// - unmasked: images are scaled, but have no time of day masking applied to them
|
||||
/// - greyed: images are scaled and in greyscale
|
||||
/// - brightened: images are scaled and brighter than normal.
|
||||
namespace image {
|
||||
|
||||
//the image manager is responsible for setting up images, and destroying
|
||||
//all images when the program exits. It should probably
|
||||
//be created once for the life of the program
|
||||
///the image manager is responsible for setting up images, and destroying
|
||||
///all images when the program exits. It should probably
|
||||
///be created once for the life of the program
|
||||
struct manager
|
||||
{
|
||||
manager();
|
||||
~manager();
|
||||
};
|
||||
|
||||
//function to set the program's icon to the window manager.
|
||||
//must be called after SDL_Init() is called, but before setting the
|
||||
//video mode
|
||||
///function to set the program's icon to the window manager.
|
||||
///must be called after SDL_Init() is called, but before setting the
|
||||
///video mode
|
||||
void set_wm_icon();
|
||||
|
||||
//will make all scaled images have these rgb values added to all
|
||||
//their pixels. i.e. add a certain colour hint to images. useful
|
||||
//for representing day/night. Invalidates all scaled images.
|
||||
///will make all scaled images have these rgb values added to all
|
||||
///their pixels. i.e. add a certain colour hint to images. useful
|
||||
///for representing day/night. Invalidates all scaled images.
|
||||
void set_colour_adjustment(int r, int g, int b);
|
||||
|
||||
//function to get back the current colour adjustment values
|
||||
///function to get back the current colour adjustment values
|
||||
void get_colour_adjustment(int *r, int *g, int *b);
|
||||
|
||||
//function which sets a certain image as a 'mask' for all scaled images.
|
||||
//the 'mask' is blitted onto all scaled images.
|
||||
///function which sets a certain image as a 'mask' for all scaled images.
|
||||
///the 'mask' is blitted onto all scaled images.
|
||||
void set_image_mask(const std::string& image_name);
|
||||
|
||||
//sets the pixel format used by the images. Is called every time the
|
||||
//video mode changes. Invalidates all images.
|
||||
///sets the pixel format used by the images. Is called every time the
|
||||
///video mode changes. Invalidates all images.
|
||||
void set_pixel_format(SDL_PixelFormat* format);
|
||||
|
||||
//sets the amount scaled images should be scaled. Invalidates all
|
||||
//scaled images.
|
||||
///sets the amount scaled images should be scaled. Invalidates all
|
||||
///scaled images.
|
||||
void set_zoom(double zoom);
|
||||
|
||||
enum TYPE { UNSCALED, SCALED, UNMASKED, GREYED, BRIGHTENED };
|
||||
|
||||
enum COLOUR_ADJUSTMENT { ADJUST_COLOUR, NO_ADJUST_COLOUR };
|
||||
|
||||
//function to get the surface corresponding to an image.
|
||||
//note that this surface must be freed by the user by calling
|
||||
//SDL_FreeSurface
|
||||
///function to get the surface corresponding to an image.
|
||||
///note that this surface must be freed by the user by calling
|
||||
///SDL_FreeSurface()
|
||||
SDL_Surface* get_image(const std::string& filename,TYPE type=SCALED, COLOUR_ADJUSTMENT adj=ADJUST_COLOUR);
|
||||
|
||||
//function to get a scaled image, but scale it to specific dimensions.
|
||||
//if you later try to get the same image using get_image() the image will
|
||||
//have the dimensions specified here.
|
||||
//Note that this surface must be freed by the user by calling SDL_FreeSurface
|
||||
///function to get a scaled image, but scale it to specific dimensions.
|
||||
///if you later try to get the same image using get_image() the image will
|
||||
///have the dimensions specified here.
|
||||
///Note that this surface must be freed by the user by calling SDL_FreeSurface
|
||||
SDL_Surface* get_image_dim(const std::string& filename, size_t x, size_t y);
|
||||
|
||||
//function to register an image with the given id. Calls to get_image(id,UNSCALED) will
|
||||
//return this image. register_image() will take ownership of this image and free
|
||||
//it when the cache is cleared (change of video mode or colour adjustment).
|
||||
//If there is already an image registered with this id, that image will be freed
|
||||
//and replaced with this image.
|
||||
///function to reverse an image. The image MUST have originally been returned from
|
||||
///an image:: function. Returned images have the same semantics as for get_image()
|
||||
///and must be freed using SDL_FreeSurface()
|
||||
SDL_Surface* reverse_image(SDL_Surface* surf);
|
||||
|
||||
///function to register an image with the given id. Calls to get_image(id,UNSCALED) will
|
||||
///return this image. register_image() will take ownership of this image and free
|
||||
///it when the cache is cleared (change of video mode or colour adjustment).
|
||||
///If there is already an image registered with this id, that image will be freed
|
||||
///and replaced with this image.
|
||||
void register_image(const std::string& id, SDL_Surface* surf);
|
||||
|
||||
//the surface returned must be freed by the user
|
||||
SDL_Surface* getMinimap(int w, int h, const gamemap& map_, int lawful_bonus,
|
||||
const team* tm=NULL);
|
||||
///function to create the minimap for a given map
|
||||
///the surface returned must be freed by the user
|
||||
SDL_Surface* getMinimap(int w, int h, const gamemap& map_, int lawful_bonus, const team* tm=NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -189,7 +189,7 @@ gamemap::gamemap(const config& cfg, const std::string& data) : tiles_(1)
|
|||
}
|
||||
|
||||
if(is_village(c)) {
|
||||
towers_.push_back(location(int(x),int(y)));
|
||||
villages_.push_back(location(int(x),int(y)));
|
||||
}
|
||||
|
||||
if(x >= tiles_.size()) {
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
//in dynamically because they're special. It's asserted that there will
|
||||
//be corresponding entries for these types of terrain in the terrain
|
||||
//configuration file.
|
||||
enum { FOGGED = '~', VOID_TERRAIN = ' ', KEEP = 'K', CASTLE = 'C', TOWER = 't', FOREST = 'f' };
|
||||
enum { FOGGED = '~', VOID_TERRAIN = ' ', KEEP = 'K', CASTLE = 'C', VILLAGE = 't', FOREST = 'f' };
|
||||
|
||||
//the name of the terrain is the terrain itself, the underlying terrain
|
||||
//is the name of the terrain for game-logic purposes. I.e. if the terrain
|
||||
|
@ -125,7 +125,7 @@ public:
|
|||
}
|
||||
|
||||
//function to return a list of the locations of villages on the map
|
||||
const std::vector<location>& towers() const { return towers_; }
|
||||
const std::vector<location>& villages() const { return villages_; }
|
||||
|
||||
//function to get the corresponding terrain_type information object
|
||||
//for a given type of terrain
|
||||
|
@ -147,7 +147,7 @@ private:
|
|||
std::map<std::string,terrain_type> terrain_;
|
||||
|
||||
std::vector<std::vector<TERRAIN> > tiles_;
|
||||
std::vector<location> towers_;
|
||||
std::vector<location> villages_;
|
||||
location startingPositions_[10];
|
||||
|
||||
mutable std::map<location,TERRAIN> borderCache_;
|
||||
|
|
|
@ -157,16 +157,16 @@ void find_routes(const gamemap& map, const gamestatus& status,
|
|||
get_adjacent_tiles(loc,&locs[0]);
|
||||
|
||||
//check for teleporting units -- we must be on a vacant (or occupied by this unit)
|
||||
//tower, that is controlled by our team to be able to teleport.
|
||||
//village, that is controlled by our team to be able to teleport.
|
||||
if(allow_teleport && map.is_village(loc) &&
|
||||
current_team.owns_tower(loc) && (starting_pos || units.count(loc) == 0)) {
|
||||
const std::vector<gamemap::location>& towers = map.towers();
|
||||
current_team.owns_village(loc) && (starting_pos || units.count(loc) == 0)) {
|
||||
const std::vector<gamemap::location>& villages = map.villages();
|
||||
|
||||
//if we are on a tower, see all friendly towers that we can
|
||||
//if we are on a village, see all friendly villages that we can
|
||||
//teleport to
|
||||
for(std::vector<gamemap::location>::const_iterator t = towers.begin();
|
||||
t != towers.end(); ++t) {
|
||||
if(!current_team.owns_tower(*t) || units.count(*t))
|
||||
for(std::vector<gamemap::location>::const_iterator t = villages.begin();
|
||||
t != villages.end(); ++t) {
|
||||
if(!current_team.owns_village(*t) || units.count(*t))
|
||||
continue;
|
||||
|
||||
locs.push_back(*t);
|
||||
|
|
|
@ -377,7 +377,7 @@ LEVEL_RESULT play_level(game_data& gameinfo, const config& game_config,
|
|||
//if the expense is less than the number of villages owned,
|
||||
//then we don't have to pay anything at all
|
||||
const int expense = team_upkeep(units,player_number) -
|
||||
team_it->towers().size();
|
||||
team_it->villages().size();
|
||||
if(expense > 0) {
|
||||
team_it->spend_gold(expense);
|
||||
}
|
||||
|
@ -573,7 +573,7 @@ redo_turn:
|
|||
}
|
||||
|
||||
const int remaining_gold = teams[0].gold();
|
||||
const int finishing_bonus_per_turn = map.towers().size()*game_config::tower_income + game_config::base_income;
|
||||
const int finishing_bonus_per_turn = map.villages().size()*game_config::village_income + game_config::base_income;
|
||||
const int turns_left = maximum<int>(0,status.number_of_turns() - status.turn());
|
||||
const int finishing_bonus = end_level.gold_bonus ?
|
||||
(finishing_bonus_per_turn * turns_left) : 0;
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "statistics.hpp"
|
||||
#include "tooltips.hpp"
|
||||
#include "unit.hpp"
|
||||
#include "unit_display.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
@ -106,9 +107,9 @@ void play_turn(game_data& gameinfo, game_state& state_of_game,
|
|||
|
||||
std::set<gamemap::location> allowed_teleports;
|
||||
if(u.type().teleports()) {
|
||||
allowed_teleports = vacant_towers(current_team.towers(),units);
|
||||
allowed_teleports = vacant_villages(current_team.villages(),units);
|
||||
teleports = &allowed_teleports;
|
||||
if(current_team.towers().count(ui->first))
|
||||
if(current_team.villages().count(ui->first))
|
||||
allowed_teleports.insert(ui->first);
|
||||
}
|
||||
|
||||
|
@ -373,9 +374,9 @@ void turn_info::mouse_motion(const SDL_MouseMotionEvent& event)
|
|||
|
||||
std::set<gamemap::location> allowed_teleports;
|
||||
if(can_teleport) {
|
||||
allowed_teleports = vacant_towers(current_team.towers(),units_);
|
||||
allowed_teleports = vacant_villages(current_team.villages(),units_);
|
||||
teleports = &allowed_teleports;
|
||||
if(current_team.towers().count(un->first))
|
||||
if(current_team.villages().count(un->first))
|
||||
allowed_teleports.insert(un->first);
|
||||
}
|
||||
|
||||
|
@ -805,9 +806,9 @@ void turn_info::left_click(const SDL_MouseButtonEvent& event)
|
|||
|
||||
std::set<gamemap::location> allowed_teleports;
|
||||
if(u.type().teleports()) {
|
||||
allowed_teleports = vacant_towers(current_team.towers(),units_);
|
||||
allowed_teleports = vacant_villages(current_team.villages(),units_);
|
||||
teleports = &allowed_teleports;
|
||||
if(current_team.towers().count(it->first))
|
||||
if(current_team.villages().count(it->first))
|
||||
allowed_teleports.insert(it->first);
|
||||
|
||||
}
|
||||
|
@ -1142,7 +1143,7 @@ void turn_info::undo()
|
|||
}
|
||||
|
||||
if(map_.is_village(route.front())) {
|
||||
get_tower(route.front(),teams_,action.original_village_owner,units_);
|
||||
get_village(route.front(),teams_,action.original_village_owner,units_);
|
||||
}
|
||||
|
||||
action.starting_moves = u->second.movement_left();
|
||||
|
@ -1150,7 +1151,7 @@ void turn_info::undo()
|
|||
unit un = u->second;
|
||||
un.set_goto(gamemap::location());
|
||||
units_.erase(u);
|
||||
gui_.move_unit(route,un);
|
||||
unit_display::move_unit(gui_,map_,route,un);
|
||||
un.set_movement(starting_moves);
|
||||
units_.insert(std::pair<gamemap::location,unit>(route.back(),un));
|
||||
gui_.draw_tile(route.back().x,route.back().y);
|
||||
|
@ -1220,12 +1221,12 @@ void turn_info::redo()
|
|||
unit un = u->second;
|
||||
un.set_goto(gamemap::location());
|
||||
units_.erase(u);
|
||||
gui_.move_unit(route,un);
|
||||
unit_display::move_unit(gui_,map_,route,un);
|
||||
un.set_movement(starting_moves);
|
||||
units_.insert(std::pair<gamemap::location,unit>(route.back(),un));
|
||||
|
||||
if(map_.is_village(route.back())) {
|
||||
get_tower(route.back(),teams_,un.side()-1,units_);
|
||||
get_village(route.back(),teams_,un.side()-1,units_);
|
||||
}
|
||||
|
||||
gui_.draw_tile(route.back().x,route.back().y);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "show_dialog.hpp"
|
||||
#include "sound.hpp"
|
||||
#include "statistics.hpp"
|
||||
#include "unit_display.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
|
@ -707,16 +708,17 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
|
|||
|
||||
rt->second.steps.push_back(dst);
|
||||
|
||||
if(!replayer.skipping())
|
||||
disp.move_unit(rt->second.steps,current_unit);
|
||||
if(!replayer.skipping()) {
|
||||
unit_display::move_unit(disp,map,rt->second.steps,current_unit);
|
||||
}
|
||||
|
||||
current_unit.set_movement(rt->second.move_left);
|
||||
u = units.insert(std::pair<gamemap::location,unit>(dst,current_unit)).first;
|
||||
if(map.is_village(dst)) {
|
||||
const int orig_owner = tower_owner(dst,teams) + 1;
|
||||
const int orig_owner = village_owner(dst,teams) + 1;
|
||||
if(orig_owner != team_num) {
|
||||
u->second.set_movement(0);
|
||||
get_tower(dst,teams,team_num-1,units);
|
||||
get_village(dst,teams,team_num-1,units);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
34
src/team.cpp
34
src/team.cpp
|
@ -57,7 +57,7 @@ team::team_info::team_info(const config& cfg)
|
|||
|
||||
const std::string& village_income = cfg["village_gold"];
|
||||
if(village_income.empty())
|
||||
income_per_village = game_config::tower_income;
|
||||
income_per_village = game_config::village_income;
|
||||
else
|
||||
income_per_village = atoi(village_income.c_str());
|
||||
|
||||
|
@ -226,7 +226,7 @@ team::team(const config& cfg, int gold) : gold_(gold), info_(cfg)
|
|||
//load in the villages the side controls at the start
|
||||
const config::child_list& villages = cfg.get_children("village");
|
||||
for(config::child_list::const_iterator v = villages.begin(); v != villages.end(); ++v) {
|
||||
towers_.insert(gamemap::location(**v));
|
||||
villages_.insert(gamemap::location(**v));
|
||||
}
|
||||
|
||||
const std::string& shroud_data = cfg["shroud_data"];
|
||||
|
@ -252,7 +252,7 @@ void team::write(config& cfg) const
|
|||
cfg["gold"] = buf;
|
||||
|
||||
//write village locations
|
||||
for(std::set<gamemap::location>::const_iterator t = towers_.begin(); t != towers_.end(); ++t) {
|
||||
for(std::set<gamemap::location>::const_iterator t = villages_.begin(); t != villages_.end(); ++t) {
|
||||
t->write(cfg.add_child("village"));
|
||||
}
|
||||
|
||||
|
@ -270,31 +270,31 @@ void team::write(config& cfg) const
|
|||
cfg["shroud_data"] = shroud_str.str();
|
||||
}
|
||||
|
||||
void team::get_tower(const gamemap::location& loc)
|
||||
void team::get_village(const gamemap::location& loc)
|
||||
{
|
||||
towers_.insert(loc);
|
||||
villages_.insert(loc);
|
||||
}
|
||||
|
||||
void team::lose_tower(const gamemap::location& loc)
|
||||
void team::lose_village(const gamemap::location& loc)
|
||||
{
|
||||
if(owns_tower(loc)) {
|
||||
towers_.erase(towers_.find(loc));
|
||||
if(owns_village(loc)) {
|
||||
villages_.erase(villages_.find(loc));
|
||||
}
|
||||
}
|
||||
|
||||
void team::clear_towers()
|
||||
void team::clear_villages()
|
||||
{
|
||||
towers_.clear();
|
||||
villages_.clear();
|
||||
}
|
||||
|
||||
const std::set<gamemap::location>& team::towers() const
|
||||
const std::set<gamemap::location>& team::villages() const
|
||||
{
|
||||
return towers_;
|
||||
return villages_;
|
||||
}
|
||||
|
||||
bool team::owns_tower(const gamemap::location& loc) const
|
||||
bool team::owns_village(const gamemap::location& loc) const
|
||||
{
|
||||
return towers_.count(loc) > 0;
|
||||
return villages_.count(loc) > 0;
|
||||
}
|
||||
|
||||
int team::gold() const
|
||||
|
@ -305,7 +305,7 @@ int team::gold() const
|
|||
int team::income() const
|
||||
{
|
||||
return atoi(info_.income.c_str()) +
|
||||
towers_.size()*info_.income_per_village+game_config::base_income;
|
||||
villages_.size()*info_.income_per_village+game_config::base_income;
|
||||
}
|
||||
|
||||
void team::new_turn()
|
||||
|
@ -561,11 +561,11 @@ int team::nteams()
|
|||
}
|
||||
}
|
||||
|
||||
const std::set<gamemap::location> vacant_towers(const std::set<gamemap::location>& towers, const unit_map& units)
|
||||
const std::set<gamemap::location> vacant_villages(const std::set<gamemap::location>& villages, const unit_map& units)
|
||||
{
|
||||
std::set<gamemap::location> res;
|
||||
|
||||
for(std::set<gamemap::location>::const_iterator i = towers.begin(); i != towers.end(); ++i) {
|
||||
for(std::set<gamemap::location>::const_iterator i = villages.begin(); i != villages.end(); ++i) {
|
||||
if(units.count(*i) == 0) {
|
||||
res.insert(*i);
|
||||
}
|
||||
|
|
12
src/team.hpp
12
src/team.hpp
|
@ -68,11 +68,11 @@ public:
|
|||
|
||||
void write(config& cfg) const;
|
||||
|
||||
void get_tower(const gamemap::location&);
|
||||
void lose_tower(const gamemap::location&);
|
||||
void clear_towers();
|
||||
const std::set<gamemap::location>& towers() const;
|
||||
bool owns_tower(const gamemap::location&) const;
|
||||
void get_village(const gamemap::location&);
|
||||
void lose_village(const gamemap::location&);
|
||||
void clear_villages();
|
||||
const std::set<gamemap::location>& villages() const;
|
||||
bool owns_village(const gamemap::location&) const;
|
||||
|
||||
int gold() const;
|
||||
int income() const;
|
||||
|
@ -126,7 +126,7 @@ public:
|
|||
|
||||
private:
|
||||
int gold_;
|
||||
std::set<gamemap::location> towers_;
|
||||
std::set<gamemap::location> villages_;
|
||||
|
||||
typedef std::vector<std::vector<bool> > shroud_map;
|
||||
shroud_map shroud_, fog_;
|
||||
|
|
18
src/unit.cpp
18
src/unit.cpp
|
@ -405,6 +405,8 @@ bool unit::matches_filter(const config& cfg) const
|
|||
const std::string& side = cfg["side"];
|
||||
const std::string& weapon = cfg["has_weapon"];
|
||||
const std::string& role = cfg["role"];
|
||||
const std::string& race = cfg["race"];
|
||||
const std::string& gender = cfg["gender"];
|
||||
|
||||
if(description.empty() == false && description != this->underlying_description()) {
|
||||
return false;
|
||||
|
@ -436,8 +438,20 @@ bool unit::matches_filter(const config& cfg) const
|
|||
}
|
||||
}
|
||||
|
||||
if(ability.empty() == false && this->type().has_ability(ability) == false)
|
||||
if(ability.empty() == false && this->type().has_ability(ability) == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(race.empty() == false && this->type().race() != race) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(gender.empty() == false) {
|
||||
const unit_race::GENDER gender_type = gender == "female" ? unit_race::FEMALE : unit_race::MALE;
|
||||
if(gender_type != this->type().gender()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(side.empty() == false && this->side() != atoi(side.c_str()))
|
||||
{
|
||||
|
@ -1070,7 +1084,7 @@ team_data calculate_team_data(const team& tm, int side, const unit_map& units)
|
|||
team_data res;
|
||||
res.units = team_units(units,side);
|
||||
res.upkeep = team_upkeep(units,side);
|
||||
res.villages = tm.towers().size();
|
||||
res.villages = tm.villages().size();
|
||||
res.expenses = maximum<int>(0,res.upkeep - res.villages);
|
||||
res.net_income = tm.income() - res.expenses;
|
||||
res.gold = tm.gold();
|
||||
|
|
|
@ -235,7 +235,7 @@ team_data calculate_team_data(const class team& tm, int side, const unit_map& un
|
|||
|
||||
std::string get_team_name(int side, const unit_map& units);
|
||||
|
||||
const std::set<gamemap::location> vacant_towers(const std::set<gamemap::location>& towers, 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.
|
||||
|
|
571
src/unit_display.cpp
Normal file
571
src/unit_display.cpp
Normal file
|
@ -0,0 +1,571 @@
|
|||
#include "events.hpp"
|
||||
#include "game_config.hpp"
|
||||
#include "image.hpp"
|
||||
#include "log.hpp"
|
||||
#include "preferences.hpp"
|
||||
#include "sound.hpp"
|
||||
#include "unit_display.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void move_unit_between(display& disp, const gamemap& map, const gamemap::location& a, const gamemap::location& b, const unit& u)
|
||||
{
|
||||
if(disp.update_locked() || disp.fogged(a.x,a.y) && disp.fogged(b.x,b.y)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool face_left = u.facing_left();
|
||||
|
||||
const double side_threshhold = 80.0;
|
||||
|
||||
double xsrc = disp.get_location_x(a);
|
||||
double ysrc = disp.get_location_y(a);
|
||||
double xdst = disp.get_location_x(b);
|
||||
double ydst = disp.get_location_y(b);
|
||||
|
||||
const gamemap::TERRAIN src_terrain = map.get_terrain(a);
|
||||
const gamemap::TERRAIN dst_terrain = map.get_terrain(b);
|
||||
|
||||
const int src_height_adjust = u.is_flying() ? 0 : int(map.get_terrain_info(src_terrain).unit_height_adjust() * disp.zoom());
|
||||
const int dst_height_adjust = u.is_flying() ? 0 : int(map.get_terrain_info(dst_terrain).unit_height_adjust() * disp.zoom());
|
||||
|
||||
const double src_submerge = u.is_flying() ? 0 : int(map.get_terrain_info(src_terrain).unit_submerge());
|
||||
const double dst_submerge = u.is_flying() ? 0 : int(map.get_terrain_info(dst_terrain).unit_submerge());
|
||||
|
||||
const double nsteps = disp.turbo() ? 3.0 : 10.0;
|
||||
const double xstep = (xdst - xsrc)/nsteps;
|
||||
const double ystep = (ydst - ysrc)/nsteps;
|
||||
|
||||
const int time_between_frames = disp.turbo() ? 2 : 10;
|
||||
int ticks = SDL_GetTicks();
|
||||
|
||||
int skips = 0;
|
||||
|
||||
for(double i = 0.0; i < nsteps; i += 1.0) {
|
||||
events::pump();
|
||||
|
||||
scoped_sdl_surface image(image::get_image(u.type().image()));
|
||||
if(!face_left) {
|
||||
image.assign(image::reverse_image(image));
|
||||
}
|
||||
|
||||
if(image == NULL) {
|
||||
std::cerr << "failed to get image " << u.type().image() << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
xsrc = disp.get_location_x(a);
|
||||
ysrc = disp.get_location_y(a);
|
||||
xdst = disp.get_location_x(b);
|
||||
ydst = disp.get_location_y(b);
|
||||
|
||||
double xloc = xsrc + xstep*i;
|
||||
double yloc = ysrc + ystep*i;
|
||||
|
||||
//we try to scroll the map if the unit is at the edge.
|
||||
//keep track of the old position, and if the map moves at all,
|
||||
//then recenter it on the unit
|
||||
if(xloc < side_threshhold) {
|
||||
disp.scroll(xloc - side_threshhold,0.0);
|
||||
}
|
||||
|
||||
if(yloc < side_threshhold) {
|
||||
disp.scroll(0.0,yloc - side_threshhold);
|
||||
}
|
||||
|
||||
if(xloc + double(image->w) > disp.mapx() - side_threshhold) {
|
||||
disp.scroll(((xloc + double(image->w)) -
|
||||
(disp.mapx() - side_threshhold)),0.0);
|
||||
}
|
||||
|
||||
if(yloc + double(image->h) > disp.y() - side_threshhold) {
|
||||
disp.scroll(0.0,((yloc + double(image->h)) -
|
||||
(disp.y() - side_threshhold)));
|
||||
}
|
||||
|
||||
if(xsrc != disp.get_location_x(a) || ysrc != disp.get_location_y(a)) {
|
||||
disp.scroll_to_tile(b.x,b.y,display::WARP);
|
||||
xsrc = disp.get_location_x(a);
|
||||
ysrc = disp.get_location_y(a);
|
||||
xdst = disp.get_location_x(b);
|
||||
ydst = disp.get_location_y(b);
|
||||
xloc = xsrc + xstep*i;
|
||||
yloc = ysrc + ystep*i;
|
||||
}
|
||||
|
||||
//invalidate the source tile and all adjacent tiles,
|
||||
//since the unit can partially overlap adjacent tiles
|
||||
gamemap::location adjacent[6];
|
||||
get_adjacent_tiles(a,adjacent);
|
||||
disp.draw_tile(a.x,a.y);
|
||||
for(int tile = 0; tile != 6; ++tile) {
|
||||
disp.draw_tile(adjacent[tile].x,adjacent[tile].y);
|
||||
}
|
||||
|
||||
const int height_adjust = src_height_adjust + (dst_height_adjust-src_height_adjust)*(i/nsteps);
|
||||
const double submerge = src_submerge + (dst_submerge-src_submerge)*(i/nsteps);
|
||||
|
||||
disp.draw(false);
|
||||
disp.draw_unit((int)xloc,(int)yloc - height_adjust,image,false,1.0,0,submerge);
|
||||
|
||||
const int new_ticks = SDL_GetTicks();
|
||||
const int wait_time = time_between_frames - (new_ticks - ticks);
|
||||
if(wait_time > 0) {
|
||||
SDL_Delay(wait_time);
|
||||
}
|
||||
|
||||
ticks = SDL_GetTicks();
|
||||
|
||||
if(wait_time >= 0 || skips == 4 || (i+1.0) >= nsteps) {
|
||||
skips = 0;
|
||||
disp.update_display();
|
||||
} else {
|
||||
++skips;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace unit_display
|
||||
{
|
||||
|
||||
void move_unit(display& disp, const gamemap& map, const std::vector<gamemap::location>& path, unit& u)
|
||||
{
|
||||
for(size_t i = 0; i+1 < path.size(); ++i) {
|
||||
if(path[i+1].x > path[i].x) {
|
||||
u.set_facing_left(true);
|
||||
} else if(path[i+1].x < path[i].x) {
|
||||
u.set_facing_left(false);
|
||||
}
|
||||
|
||||
disp.remove_footstep(path[i]);
|
||||
|
||||
move_unit_between(disp,map,path[i],path[i+1],u);
|
||||
}
|
||||
|
||||
//make sure the entire path is cleaned properly
|
||||
for(std::vector<gamemap::location>::const_iterator it = path.begin(); it != path.end(); ++it) {
|
||||
disp.draw_tile(it->x,it->y);
|
||||
}
|
||||
}
|
||||
|
||||
void unit_die(display& disp, const gamemap::location& loc, const unit& u)
|
||||
{
|
||||
if(disp.update_locked() || disp.fogged(loc.x,loc.y) || preferences::show_combat() == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string& die_sound = u.type().die_sound();
|
||||
if(die_sound != "" && die_sound != "null") {
|
||||
sound::play_sound(die_sound);
|
||||
}
|
||||
|
||||
const int frame_time = 30;
|
||||
int ticks = SDL_GetTicks();
|
||||
|
||||
for(double alpha = 1.0; alpha > 0.0; alpha -= 0.05) {
|
||||
disp.draw_tile(loc.x,loc.y,NULL,alpha);
|
||||
|
||||
const int wait_time = ticks + frame_time - SDL_GetTicks();
|
||||
|
||||
if(wait_time > 0 && !disp.turbo())
|
||||
SDL_Delay(wait_time);
|
||||
|
||||
ticks = SDL_GetTicks();
|
||||
|
||||
disp.update_display();
|
||||
}
|
||||
|
||||
disp.draw(true,true);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool unit_attack_ranged(display& disp, unit_map& units, const gamemap& map,
|
||||
const gamemap::location& a, const gamemap::location& b, int damage,
|
||||
const attack_type& attack)
|
||||
{
|
||||
const bool hide = disp.update_locked() || disp.fogged(a.x,a.y) && disp.fogged(b.x,b.y)
|
||||
|| preferences::show_combat() == false;
|
||||
|
||||
const unit_map::iterator att = units.find(a);
|
||||
const unit_map::iterator def = units.find(b);
|
||||
|
||||
def->second.set_defending(true,attack_type::LONG_RANGE);
|
||||
|
||||
//the missile frames are based around the time when the missile impacts.
|
||||
//the 'real' frames are based around the time when the missile launches.
|
||||
const int first_missile = minimum<int>(-100,attack.get_first_frame(attack_type::MISSILE_FRAME));
|
||||
const int last_missile = attack.get_last_frame(attack_type::MISSILE_FRAME);
|
||||
|
||||
const int real_last_missile = last_missile - first_missile;
|
||||
const int missile_impact = -first_missile;
|
||||
|
||||
const int time_resolution = 20;
|
||||
const int acceleration = disp.turbo() ? 5:1;
|
||||
|
||||
const std::vector<attack_type::sfx>& sounds = attack.sound_effects();
|
||||
std::vector<attack_type::sfx>::const_iterator sfx_it = sounds.begin();
|
||||
|
||||
const std::string& hit_sound = def->second.type().get_hit_sound();
|
||||
bool played_hit_sound = (hit_sound == "" || hit_sound == "null");
|
||||
const int play_hit_sound_at = 0;
|
||||
|
||||
const bool hits = damage > 0;
|
||||
const int begin_at = attack.get_first_frame();
|
||||
const int end_at = maximum((damage+1)*time_resolution+missile_impact,
|
||||
maximum(attack.get_last_frame(),real_last_missile));
|
||||
|
||||
const double xsrc = disp.get_location_x(a);
|
||||
const double ysrc = disp.get_location_y(a);
|
||||
const double xdst = disp.get_location_x(b);
|
||||
const double ydst = disp.get_location_y(b);
|
||||
|
||||
gamemap::location update_tiles[6];
|
||||
get_adjacent_tiles(a,update_tiles);
|
||||
|
||||
const bool vflip = b.y > a.y || b.y == a.y && is_even(a.x);
|
||||
const bool hflip = b.x < a.x;
|
||||
const attack_type::FRAME_DIRECTION dir =
|
||||
(a.x == b.x) ? attack_type::VERTICAL:attack_type::DIAGONAL;
|
||||
|
||||
bool dead = false;
|
||||
const int drain_speed = 1*acceleration;
|
||||
|
||||
int flash_num = 0;
|
||||
|
||||
int ticks = SDL_GetTicks();
|
||||
|
||||
bool shown_label = false;
|
||||
|
||||
for(int i = begin_at; i < end_at; i += time_resolution*acceleration) {
|
||||
events::pump();
|
||||
|
||||
//this is a while instead of an if, because there might be multiple
|
||||
//sounds playing simultaneously or close together
|
||||
while(!hide && sfx_it != sounds.end() && i >= sfx_it->time) {
|
||||
const std::string& sfx = hits ? sfx_it->on_hit : sfx_it->on_miss;
|
||||
if(sfx.empty() == false) {
|
||||
sound::play_sound(hits ? sfx_it->on_hit : sfx_it->on_miss);
|
||||
}
|
||||
|
||||
++sfx_it;
|
||||
}
|
||||
|
||||
if(!hide && hits && !played_hit_sound && i >= play_hit_sound_at) {
|
||||
sound::play_sound(hit_sound);
|
||||
played_hit_sound = true;
|
||||
}
|
||||
|
||||
const std::string* unit_image = attack.get_frame(i);
|
||||
|
||||
if(unit_image == NULL) {
|
||||
unit_image = &att->second.type().image_fighting(attack_type::LONG_RANGE);
|
||||
}
|
||||
|
||||
if(!hide) {
|
||||
const scoped_sdl_surface image((unit_image == NULL) ? NULL : image::get_image(*unit_image));
|
||||
disp.draw_tile(a.x,a.y,image);
|
||||
}
|
||||
|
||||
if(damage > 0 && i >= missile_impact && shown_label == false) {
|
||||
shown_label = true;
|
||||
disp.float_label(b,lexical_cast<std::string>(damage),255,0,0);
|
||||
}
|
||||
|
||||
Uint32 defensive_colour = 0;
|
||||
double defensive_alpha = 1.0;
|
||||
|
||||
if(damage > 0 && i >= missile_impact) {
|
||||
if(def->second.gets_hit(minimum<int>(drain_speed,damage))) {
|
||||
dead = true;
|
||||
damage = 0;
|
||||
} else {
|
||||
damage -= drain_speed;
|
||||
}
|
||||
|
||||
if(flash_num == 0 || flash_num == 2) {
|
||||
defensive_alpha = 0.0;
|
||||
defensive_colour = disp.rgb(200,0,0);
|
||||
}
|
||||
|
||||
++flash_num;
|
||||
}
|
||||
|
||||
for(int j = 0; j != 6; ++j) {
|
||||
if(update_tiles[j] != b) {
|
||||
disp.draw_tile(update_tiles[j].x,update_tiles[j].y);
|
||||
}
|
||||
}
|
||||
|
||||
disp.draw_tile(b.x,b.y,NULL,defensive_alpha,defensive_colour);
|
||||
|
||||
if(i >= 0 && i < real_last_missile && !hide) {
|
||||
const int missile_frame = i + first_missile;
|
||||
|
||||
const std::string* missile_image = attack.get_frame(missile_frame,NULL,
|
||||
attack_type::MISSILE_FRAME,dir);
|
||||
|
||||
static const std::string default_missile(game_config::missile_n_image);
|
||||
static const std::string default_diag_missile(game_config::missile_ne_image);
|
||||
if(missile_image == NULL) {
|
||||
if(dir == attack_type::VERTICAL)
|
||||
missile_image = &default_missile;
|
||||
else
|
||||
missile_image = &default_diag_missile;
|
||||
}
|
||||
|
||||
scoped_sdl_surface img(image::get_image(*missile_image));
|
||||
|
||||
if(hflip) {
|
||||
img.assign(image::reverse_image(img));
|
||||
}
|
||||
|
||||
if(img != NULL) {
|
||||
double pos = double(missile_impact - i)/double(missile_impact);
|
||||
if(pos < 0.0) {
|
||||
pos = 0.0;
|
||||
}
|
||||
const int xpos = int(xsrc*pos + xdst*(1.0-pos));
|
||||
const int ypos = int(ysrc*pos + ydst*(1.0-pos));
|
||||
|
||||
disp.draw_unit(xpos,ypos,img,vflip);
|
||||
}
|
||||
}
|
||||
|
||||
const int wait_time = ticks + time_resolution - SDL_GetTicks();
|
||||
if(wait_time > 0 && !hide) {
|
||||
SDL_Delay(wait_time);
|
||||
}
|
||||
|
||||
ticks = SDL_GetTicks();
|
||||
|
||||
disp.update_display();
|
||||
}
|
||||
|
||||
def->second.set_defending(false);
|
||||
|
||||
disp.draw_tile(a.x,a.y);
|
||||
disp.draw_tile(b.x,b.y);
|
||||
|
||||
if(dead) {
|
||||
unit_die(disp,def->first,def->second);
|
||||
}
|
||||
|
||||
return dead;
|
||||
}
|
||||
|
||||
} //end anon namespace
|
||||
|
||||
bool unit_attack(display& disp, unit_map& units, const gamemap& map,
|
||||
const gamemap::location& a, const gamemap::location& b, int damage,
|
||||
const attack_type& attack)
|
||||
{
|
||||
const bool hide = disp.update_locked() || disp.fogged(a.x,a.y) && disp.fogged(b.x,b.y)
|
||||
|| preferences::show_combat() == false;
|
||||
|
||||
if(!hide) {
|
||||
const double side_threshhold = 80.0;
|
||||
|
||||
double xloc = disp.get_location_x(a);
|
||||
double yloc = disp.get_location_y(a);
|
||||
|
||||
SDL_Rect area = disp.map_area();
|
||||
|
||||
//we try to scroll the map if the unit is at the edge.
|
||||
//keep track of the old position, and if the map moves at all,
|
||||
//then recenter it on the unit
|
||||
if(xloc < area.x + side_threshhold) {
|
||||
disp.scroll(xloc - side_threshhold - disp.map_area().x,0.0);
|
||||
}
|
||||
|
||||
if(yloc < area.y + side_threshhold) {
|
||||
disp.scroll(0.0,yloc - side_threshhold - area.y);
|
||||
}
|
||||
|
||||
if(xloc + disp.hex_size() > area.x + area.w - side_threshhold) {
|
||||
disp.scroll(((xloc + disp.hex_size()) - (area.x + area.w - side_threshhold)),0.0);
|
||||
}
|
||||
|
||||
if(yloc + disp.hex_size() > area.y + area.h - side_threshhold) {
|
||||
disp.scroll(0.0,((yloc + disp.hex_size()) - (area.y + area.h - side_threshhold)));
|
||||
}
|
||||
|
||||
if(xloc != disp.get_location_x(a) || yloc != disp.get_location_y(a)) {
|
||||
disp.scroll_to_tile(a.x,a.y,display::WARP);
|
||||
}
|
||||
}
|
||||
|
||||
log_scope("unit_attack");
|
||||
disp.invalidate_all();
|
||||
disp.draw(true,true);
|
||||
|
||||
const unit_map::iterator att = units.find(a);
|
||||
assert(att != units.end());
|
||||
|
||||
unit& attacker = att->second;
|
||||
|
||||
const unit_map::iterator def = units.find(b);
|
||||
assert(def != units.end());
|
||||
|
||||
if(b.x > a.x) {
|
||||
att->second.set_facing_left(true);
|
||||
def->second.set_facing_left(false);
|
||||
} else if(b.x < a.x) {
|
||||
att->second.set_facing_left(false);
|
||||
def->second.set_facing_left(true);
|
||||
}
|
||||
|
||||
if(attack.range() == attack_type::LONG_RANGE) {
|
||||
return unit_attack_ranged(disp,units,map,a,b,damage,attack);
|
||||
}
|
||||
|
||||
const bool hits = damage > 0;
|
||||
const std::vector<attack_type::sfx>& sounds = attack.sound_effects();
|
||||
std::vector<attack_type::sfx>::const_iterator sfx_it = sounds.begin();
|
||||
|
||||
const std::string& hit_sound = def->second.type().get_hit_sound();
|
||||
bool played_hit_sound = (hit_sound == "" || hit_sound == "null");
|
||||
const int play_hit_sound_at = 0;
|
||||
|
||||
const int time_resolution = 20;
|
||||
const int acceleration = disp.turbo() ? 5 : 1;
|
||||
|
||||
def->second.set_defending(true,attack_type::SHORT_RANGE);
|
||||
|
||||
const int begin_at = minimum<int>(-200,attack.get_first_frame());
|
||||
const int end_at = maximum<int>((damage+1)*time_resolution,
|
||||
maximum<int>(200,attack.get_last_frame()));
|
||||
|
||||
const double xsrc = disp.get_location_x(a);
|
||||
const double ysrc = disp.get_location_y(a);
|
||||
const double xdst = disp.get_location_x(b)*0.6 + xsrc*0.4;
|
||||
const double ydst = disp.get_location_y(b)*0.6 + ysrc*0.4;
|
||||
|
||||
gamemap::location update_tiles[6];
|
||||
get_adjacent_tiles(b,update_tiles);
|
||||
|
||||
bool dead = false;
|
||||
const int drain_speed = 1*acceleration;
|
||||
|
||||
int flash_num = 0;
|
||||
|
||||
int ticks = SDL_GetTicks();
|
||||
|
||||
disp.hide_unit(a);
|
||||
|
||||
const gamemap::TERRAIN src_terrain = map.get_terrain(a);
|
||||
const gamemap::TERRAIN dst_terrain = map.get_terrain(b);
|
||||
|
||||
const double src_height_adjust = attacker.is_flying() ? 0 : map.get_terrain_info(src_terrain).unit_height_adjust() * disp.zoom();
|
||||
const double dst_height_adjust = attacker.is_flying() ? 0 : map.get_terrain_info(dst_terrain).unit_height_adjust() * disp.zoom();
|
||||
|
||||
const double src_submerge = attacker.is_flying() ? 0 : map.get_terrain_info(src_terrain).unit_submerge();
|
||||
const double dst_submerge = attacker.is_flying() ? 0 : map.get_terrain_info(dst_terrain).unit_submerge();
|
||||
|
||||
bool shown_label = false;
|
||||
|
||||
for(int i = begin_at; i < end_at; i += time_resolution*acceleration) {
|
||||
events::pump();
|
||||
|
||||
//this is a while instead of an if, because there might be multiple
|
||||
//sounds playing simultaneously or close together
|
||||
while(!hide && sfx_it != sounds.end() && i >= sfx_it->time) {
|
||||
const std::string& sfx = hits ? sfx_it->on_hit : sfx_it->on_miss;
|
||||
if(sfx.empty() == false) {
|
||||
sound::play_sound(hits ? sfx_it->on_hit : sfx_it->on_miss);
|
||||
}
|
||||
|
||||
++sfx_it;
|
||||
}
|
||||
|
||||
if(!hide && hits && !played_hit_sound && i >= play_hit_sound_at) {
|
||||
sound::play_sound(hit_sound);
|
||||
played_hit_sound = true;
|
||||
}
|
||||
|
||||
for(int j = 0; j != 6; ++j) {
|
||||
disp.draw_tile(update_tiles[j].x,update_tiles[j].y);
|
||||
}
|
||||
|
||||
Uint32 defender_colour = 0;
|
||||
double defender_alpha = 1.0;
|
||||
|
||||
if(damage > 0 && i >= 0 && shown_label == false) {
|
||||
shown_label = true;
|
||||
disp.float_label(b,lexical_cast<std::string>(damage),255,0,0);
|
||||
}
|
||||
|
||||
if(damage > 0 && i >= 0) {
|
||||
if(def->second.gets_hit(minimum<int>(drain_speed,damage))) {
|
||||
dead = true;
|
||||
damage = 0;
|
||||
} else {
|
||||
damage -= drain_speed;
|
||||
}
|
||||
|
||||
if(flash_num == 0 || flash_num == 2) {
|
||||
defender_alpha = 0.0;
|
||||
defender_colour = disp.rgb(200,0,0);
|
||||
}
|
||||
|
||||
++flash_num;
|
||||
}
|
||||
|
||||
disp.draw_tile(b.x,b.y,NULL,defender_alpha,defender_colour);
|
||||
|
||||
int xoffset = 0;
|
||||
const std::string* unit_image = attack.get_frame(i,&xoffset);
|
||||
if(!attacker.facing_left())
|
||||
xoffset *= -1;
|
||||
|
||||
xoffset = int(double(xoffset)*disp.zoom());
|
||||
|
||||
if(unit_image == NULL) {
|
||||
unit_image = &attacker.image();
|
||||
}
|
||||
|
||||
scoped_sdl_surface image((unit_image == NULL) ? NULL : image::get_image(*unit_image));
|
||||
if(attacker.facing_left() == false) {
|
||||
image.assign(image::reverse_image(image));
|
||||
}
|
||||
|
||||
const double pos = double(i)/double(i < 0 ? begin_at : end_at);
|
||||
const int posx = int(pos*xsrc + (1.0-pos)*xdst) + xoffset;
|
||||
const int posy = int(pos*ysrc + (1.0-pos)*ydst);
|
||||
|
||||
const int height_adjust = int(src_height_adjust*pos + dst_height_adjust*(1.0-pos));
|
||||
const double submerge = src_submerge*pos + dst_submerge*(1.0-pos);
|
||||
|
||||
if(image != NULL && !hide) {
|
||||
disp.draw_unit(posx,posy-height_adjust,image,false,1.0,0,submerge);
|
||||
}
|
||||
|
||||
const int wait_time = ticks + time_resolution - SDL_GetTicks();
|
||||
if(wait_time > 0 && !hide) {
|
||||
SDL_Delay(wait_time);
|
||||
}
|
||||
|
||||
ticks = SDL_GetTicks();
|
||||
|
||||
disp.update_display();
|
||||
}
|
||||
|
||||
disp.hide_unit(gamemap::location());
|
||||
|
||||
def->second.set_defending(false);
|
||||
|
||||
disp.draw_tile(a.x,a.y);
|
||||
disp.draw_tile(b.x,b.y);
|
||||
|
||||
if(dead) {
|
||||
unit_display::unit_die(disp,def->first,def->second);
|
||||
}
|
||||
|
||||
return dead;
|
||||
}
|
||||
|
||||
}
|
30
src/unit_display.hpp
Normal file
30
src/unit_display.hpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef UNIT_DISPLAY_HPP_INCLUDED
|
||||
#define UNIT_DISPLAY_HPP_INCLUDED
|
||||
|
||||
#include "display.hpp"
|
||||
#include "unit.hpp"
|
||||
|
||||
///the unit_display namespace contains a number of free functions
|
||||
///which display units performing various on-screen actions - moving,
|
||||
///attacking, and dying
|
||||
namespace unit_display
|
||||
{
|
||||
///a function to display a unit moving along a given path
|
||||
void move_unit(display& disp, const gamemap& map, const std::vector<gamemap::location>& path, unit& u);
|
||||
|
||||
///a function to show a unit fading out. Note that this only shows the effect, it doesn't
|
||||
///actually kill the unit.
|
||||
void unit_die(display& disp, const gamemap::location& loc, const unit& u);
|
||||
|
||||
///a function to make the unit on tile 'a' attack the unit on tile 'b'.
|
||||
///the 'damage' will be subtracted from the unit's hitpoints, and a die effect will be
|
||||
///displayed if the unit dies.
|
||||
///true is returned if the defending unit is dead, and should be removed from the
|
||||
///playing field.
|
||||
bool unit_attack(display& disp, unit_map& units, const gamemap& map,
|
||||
const gamemap::location& a, const gamemap::location& b, int damage,
|
||||
const attack_type& attack);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -748,6 +748,16 @@ const std::vector<config*>& unit_type::possible_traits() const
|
|||
|
||||
unit_race::GENDER unit_type::gender() const { return gender_; }
|
||||
|
||||
const std::string& unit_type::race() const
|
||||
{
|
||||
if(race_ == NULL) {
|
||||
static const std::string empty_string;
|
||||
return empty_string;
|
||||
}
|
||||
|
||||
return race_->name();
|
||||
}
|
||||
|
||||
game_data::game_data(const config& cfg)
|
||||
{
|
||||
static const std::vector<config*> dummy_traits;
|
||||
|
|
|
@ -208,6 +208,8 @@ public:
|
|||
|
||||
unit_race::GENDER gender() const;
|
||||
|
||||
const std::string& race() const;
|
||||
|
||||
private:
|
||||
const config& cfg_;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue