added missile haloes, with sample for Red Mage

This commit is contained in:
Dave White 2004-05-25 17:07:03 +00:00
parent 312f113cd2
commit 431c713d20
9 changed files with 245 additions and 18 deletions

View File

@ -53,6 +53,7 @@ get_hit_sound=groan.wav
begin=-100
end=0
image=fireball.png
halo=fireball-halo.png
[/missile_frame]
[/attack]
[/unit]

BIN
images/fireball-halo.png Normal file

Binary file not shown.

View File

@ -1 +1,162 @@
#include "halo.hpp"
#include "halo.hpp"
#include "image.hpp"
#include "sdl_utils.hpp"
#include <cassert>
#include <map>
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<int,effect> 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<int,effect>(id,effect(x,y,image)));
return id;
}
void remove(int handle)
{
haloes.erase(handle);
}
void render()
{
for(std::map<int,effect>::iterator i = haloes.begin(); i != haloes.end(); ++i) {
i->second.render();
}
}
void unrender()
{
for(std::map<int,effect>::reverse_iterator i = haloes.rbegin(); i != haloes.rend(); ++i) {
i->second.unrender();
}
}
}

View File

@ -1,5 +1,40 @@
#ifndef HALO_HPP_INCLUDED
#define HALO_HPP_INCLUDED
#include "display.hpp"
#include <string>
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

View File

@ -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";

View File

@ -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<int,halo::remover> 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<int>(time_resolution*4,-wait_time);
}
ticks = SDL_GetTicks();

View File

@ -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<frame>::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 {

View File

@ -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<frame> frames_[2];

View File

@ -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()