diff --git a/data/units/Red_Mage.cfg b/data/units/Red_Mage.cfg index dba667c2705..448c9a3667a 100644 --- a/data/units/Red_Mage.cfg +++ b/data/units/Red_Mage.cfg @@ -53,6 +53,7 @@ get_hit_sound=groan.wav begin=-100 end=0 image=fireball.png + halo=fireball-halo.png [/missile_frame] [/attack] [/unit] diff --git a/images/fireball-halo.png b/images/fireball-halo.png new file mode 100644 index 00000000000..8b233244b4a Binary files /dev/null and b/images/fireball-halo.png differ diff --git a/src/halo.cpp b/src/halo.cpp index df3a73479c0..4fc2393fe69 100644 --- a/src/halo.cpp +++ b/src/halo.cpp @@ -1 +1,162 @@ -#include "halo.hpp" \ No newline at end of file +#include "halo.hpp" +#include "image.hpp" +#include "sdl_utils.hpp" + +#include +#include + +namespace halo +{ + +namespace { +display* disp = NULL; + +class effect +{ +public: + effect(int xpos, int ypos, const std::string& img); + + void render(); + void unrender(); +private: + + void rezoom(); + + std::string image_; + int x_, y_; + double zoom_; + shared_sdl_surface surf_, buffer_; + SDL_Rect rect_; +}; + +std::map haloes; +int halo_id = 1; + +static const SDL_Rect empty_rect = {0,0,0,0}; + +effect::effect(int xpos, int ypos, const std::string& img) +: image_(img), x_(xpos), y_(ypos), zoom_(disp->zoom()), surf_(NULL), buffer_(NULL), rect_(empty_rect) +{ + assert(disp != NULL); + + const gamemap::location zero_loc(0,0); + x_ -= disp->get_location_x(zero_loc); + y_ -= disp->get_location_y(zero_loc); + + rezoom(); +} + +void effect::rezoom() +{ + const double new_zoom = disp->zoom(); + x_ = (x_*new_zoom)/zoom_; + y_ = (y_*new_zoom)/zoom_; + + zoom_ = new_zoom; + + surf_.assign(image::get_image(image_,image::UNSCALED)); + if(surf_ != NULL && zoom_ != 1.0) { + surf_.assign(scale_surface(surf_,surf_->w*zoom_,surf_->h*zoom_)); + } +} + +void effect::render() +{ + if(disp == NULL || surf_ == NULL) { + return; + } + + if(zoom_ != disp->zoom()) { + rezoom(); + } + + if(surf_ == NULL) { + return; + } + + const gamemap::location zero_loc(0,0); + const int screenx = disp->get_location_x(zero_loc); + const int screeny = disp->get_location_y(zero_loc); + + const int xpos = x_ + screenx - surf_->w/2; + const int ypos = y_ + screeny - surf_->h/2; + + SDL_Rect rect = {xpos,ypos,surf_->w,surf_->h}; + rect_ = rect; + SDL_Rect clip_rect = disp->map_area(); + if(rects_overlap(rect,clip_rect) == false) { + buffer_.assign(NULL); + return; + } + + SDL_Surface* const screen = disp->video().getSurface(); + + const clip_rect_setter clip_setter(screen,clip_rect); + if(buffer_ == NULL || buffer_->w != rect.w || buffer_->h != rect.h) { + SDL_Rect rect = rect_; + buffer_.assign(get_surface_portion(screen,rect)); + } else { + SDL_Rect rect = rect_; + SDL_BlitSurface(screen,&rect,buffer_,NULL); + } + + SDL_BlitSurface(surf_,NULL,screen,&rect); + + update_rect(rect_); +} + +void effect::unrender() +{ + if(buffer_ == NULL) { + return; + } + + SDL_Surface* const screen = disp->video().getSurface(); + + SDL_Rect clip_rect = disp->map_area(); + const clip_rect_setter clip_setter(screen,clip_rect); + SDL_Rect rect = rect_; + SDL_BlitSurface(buffer_,NULL,screen,&rect); + update_rect(rect_); +} + +} + +manager::manager(display& screen) : old(disp) +{ + disp = &screen; +} + +manager::~manager() +{ + haloes.clear(); + disp = old; +} + +int add(int x, int y, const std::string& image) +{ + const int id = halo_id++; + haloes.insert(std::pair(id,effect(x,y,image))); + return id; +} + +void remove(int handle) +{ + haloes.erase(handle); +} + +void render() +{ + for(std::map::iterator i = haloes.begin(); i != haloes.end(); ++i) { + i->second.render(); + } +} + +void unrender() +{ + for(std::map::reverse_iterator i = haloes.rbegin(); i != haloes.rend(); ++i) { + i->second.unrender(); + } +} + +} \ No newline at end of file diff --git a/src/halo.hpp b/src/halo.hpp index 839ad582ddf..7f2d598803b 100644 --- a/src/halo.hpp +++ b/src/halo.hpp @@ -1,5 +1,40 @@ #ifndef HALO_HPP_INCLUDED #define HALO_HPP_INCLUDED +#include "display.hpp" + +#include + +namespace halo +{ + +struct manager +{ + manager(display& disp); + ~manager(); + +private: + display* const old; +}; + +///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); + +///function to remove the halo with the given handle +void remove(int handle); + +struct remover +{ + void operator()(int handle) const { remove(handle); } +}; + +///functions to render and unrender all haloes. Should +///be called immediately before/after flipping the screen +void render(); +void unrender(); + +} #endif \ No newline at end of file diff --git a/src/playlevel.cpp b/src/playlevel.cpp index 4bbdee5e123..c4cf286192e 100644 --- a/src/playlevel.cpp +++ b/src/playlevel.cpp @@ -15,6 +15,7 @@ #include "events.hpp" #include "filesystem.hpp" #include "game_events.hpp" +#include "halo.hpp" #include "hotkeys.hpp" #include "intro.hpp" #include "language.hpp" @@ -295,6 +296,8 @@ LEVEL_RESULT play_level(game_data& gameinfo, const config& game_config, //object that will make sure that labels are removed at the end of the scenario const font::floating_label_manager labels_manager; + const halo::manager halo_manager(gui); + gui.labels().read(*level); std::cerr << "a... " << (SDL_GetTicks() - ticks) << "\n"; diff --git a/src/unit_display.cpp b/src/unit_display.cpp index 12d46576bbc..65c95e56def 100644 --- a/src/unit_display.cpp +++ b/src/unit_display.cpp @@ -5,6 +5,7 @@ #include "image.hpp" #include "log.hpp" #include "preferences.hpp" +#include "scoped_resource.hpp" #include "sound.hpp" #include "unit_display.hpp" #include "util.hpp" @@ -314,11 +315,14 @@ bool unit_attack_ranged(display& disp, unit_map& units, const gamemap& map, disp.draw_tile(leader_loc.x,leader_loc.y); } + util::scoped_resource halo_effect(0); + if(i >= 0 && i < real_last_missile && !hide) { const int missile_frame = i + first_missile; + const std::string* halo_image = NULL; const std::string* missile_image = attack.get_frame(missile_frame,NULL, - attack_type::MISSILE_FRAME,dir); + attack_type::MISSILE_FRAME,dir,&halo_image); static const std::string default_missile(game_config::missile_n_image); static const std::string default_diag_missile(game_config::missile_ne_image); @@ -335,21 +339,29 @@ bool unit_attack_ranged(display& disp, unit_map& units, const gamemap& map, 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)); + 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)); + + if(img != NULL) { disp.draw_unit(xpos,ypos,img,vflip); } + + if(halo_image != NULL) { + halo_effect.assign(halo::add(xpos+disp.hex_width()/2,ypos+disp.hex_size()/2,*halo_image)); + } } const int wait_time = ticks + time_resolution - SDL_GetTicks(); if(wait_time > 0 && !hide) { SDL_Delay(wait_time); + } else if(wait_time < 0) { + //if we're not keeping up, then skip frames + i += minimum(time_resolution*4,-wait_time); } ticks = SDL_GetTicks(); diff --git a/src/unit_types.cpp b/src/unit_types.cpp index 3ebb8dc929b..e43585ef7d6 100644 --- a/src/unit_types.cpp +++ b/src/unit_types.cpp @@ -56,7 +56,8 @@ attack_type::attack_type(const config& cfg) const int end = atoi((**range.first)["end"].c_str()); const int xoff = atoi((**range.first)["xoffset"].c_str()); const std::string& img = (**range.first)["image"]; - frames_[UNIT_FRAME].push_back(frame(beg,end,img,xoff)); + const std::string& halo = (**range.first)["halo"]; + frames_[UNIT_FRAME].push_back(frame(beg,end,img,halo,xoff)); } range = cfg.child_range("missile_frame"); @@ -67,10 +68,11 @@ attack_type::attack_type(const config& cfg) const std::string& img = (**range.first)["image"]; const std::string& img_diag = (**range.first)["image_diagonal"]; + const std::string& halo = (**range.first)["halo"]; if(img_diag.empty()) - frames_[MISSILE_FRAME].push_back(frame(beg,end,img,xoff)); + frames_[MISSILE_FRAME].push_back(frame(beg,end,img,halo,xoff)); else - frames_[MISSILE_FRAME].push_back(frame(beg,end,img,img_diag,xoff)); + frames_[MISSILE_FRAME].push_back(frame(beg,end,img,img_diag,halo,xoff)); } @@ -163,7 +165,7 @@ int attack_type::get_last_frame(attack_type::FRAME_TYPE type) const const std::string* attack_type::get_frame(int milliseconds, int* xoff, attack_type::FRAME_TYPE type, - attack_type::FRAME_DIRECTION dir) const + attack_type::FRAME_DIRECTION dir, const std::string** halo) const { for(std::vector::const_iterator i = frames_[type].begin(); i != frames_[type].end(); ++i) { @@ -175,6 +177,14 @@ const std::string* attack_type::get_frame(int milliseconds, int* xoff, *xoff = i->xoffset; } + if(halo != NULL) { + if(i->halo.empty()) { + *halo = NULL; + } else { + *halo = &i->halo; + } + } + if(dir == DIAGONAL && i->image_diagonal != "") { return &i->image_diagonal; } else { diff --git a/src/unit_types.hpp b/src/unit_types.hpp index c370ae45a1a..18138a99ab5 100644 --- a/src/unit_types.hpp +++ b/src/unit_types.hpp @@ -53,7 +53,8 @@ public: //frames before the time of impact const std::string* get_frame(int milliseconds, int* xoffset=NULL, FRAME_TYPE type=UNIT_FRAME, - FRAME_DIRECTION direction=VERTICAL) const; + FRAME_DIRECTION direction=VERTICAL, + const std::string** halo=NULL) const; struct sfx { int time; @@ -81,20 +82,21 @@ private: bool backstab_; struct frame { - frame(int i1, int i2, const std::string& img, int offset) - : start(i1), end(i2), xoffset(offset), image(img) + frame(int i1, int i2, const std::string& img, const std::string& halo, int offset) + : start(i1), end(i2), xoffset(offset), image(img), halo(halo) {} frame(int i1, int i2, const std::string& img, const std::string& diag, - int offset) + const std::string& halo, int offset) : start(i1), end(i2), xoffset(offset), - image(img), image_diagonal(diag) + image(img), image_diagonal(diag), halo(halo) {} int start, end; int xoffset; std::string image; std::string image_diagonal; + std::string halo; }; std::vector frames_[2]; diff --git a/src/video.cpp b/src/video.cpp index babf9ca747c..8a9c4ac253f 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -17,6 +17,7 @@ #include "cursor.hpp" #include "events.hpp" #include "font.hpp" +#include "halo.hpp" #include "image.hpp" #include "mouse.hpp" #include "preferences.hpp" @@ -292,6 +293,7 @@ void CVideo::flip() if(fake_screen) return; + halo::render(); events::raise_volatile_draw_event(); font::draw_floating_labels(frameBuffer); cursor::draw(frameBuffer); @@ -306,6 +308,7 @@ void CVideo::flip() cursor::undraw(frameBuffer); font::undraw_floating_labels(frameBuffer); events::raise_volatile_undraw_event(); + halo::unrender(); } void CVideo::lock()