improvements to chat system.

fixed bugs with tooltips
This commit is contained in:
Dave White 2004-04-14 17:12:18 +00:00
parent 4271a8c49b
commit 9db644e45b
12 changed files with 243 additions and 127 deletions

View file

@ -59,6 +59,7 @@ Defeat:
villages_per_scout=0
{GOLD 150 200 280}
{INCOME 8 15 20}
team_name=mages
[/side]

View file

@ -267,7 +267,7 @@ void display::scroll(double xmove, double ymove)
//only invalidate if we've actually moved
if(orig_x != xpos_ || orig_y != ypos_) {
map_labels_.scroll(int(util::round(orig_x - xpos_)), int(util::round(orig_y - ypos_)));
map_labels_.scroll(orig_x - xpos_, orig_y - ypos_);
invalidate_all();
}
}
@ -2682,42 +2682,63 @@ void display::remove_observer(const std::string& name)
}
namespace {
const int chat_message_spacing = 20;
const int max_chat_messages = 4;
const int max_chat_messages = 6;
const int chat_message_border = 5;
const int chat_message_x = 10;
const int chat_message_y = 10;
const SDL_Color chat_message_colour = {200,200,200,200};
const SDL_Color chat_message_bg = {0,0,0,100};
}
void display::add_chat_message(const std::string& speaker, const std::string& msg, display::MESSAGE_TYPE type)
void display::add_chat_message(const std::string& speaker, int side, const std::string& message, display::MESSAGE_TYPE type)
{
std::stringstream str;
if(type == MESSAGE_PUBLIC) {
str << "<" << speaker << "> " << msg;
} else {
str << "*" << speaker << "* " << msg;
std::string msg = message;
gui::text_to_lines(msg,80);
int ypos = chat_message_x;
for(std::vector<chat_message>::const_iterator m = chat_messages_.begin(); m != chat_messages_.end(); ++m) {
ypos += font::get_floating_label_rect(m->handle).h;
}
std::stringstream str;
if(type == MESSAGE_PUBLIC) {
str << "<" << speaker << ">";
} else {
str << "*" << speaker << "*";
}
SDL_Color speaker_colour = {255,255,255,255};
if(side >= 1) {
speaker_colour = font::get_side_colour(side);
}
std::cerr << "chat message '" << str.str() << "'\n";
const SDL_Rect rect = map_area();
const int handle = font::add_floating_label(str.str(),12,chat_message_colour,
rect.x+chat_message_x,rect.y+chat_message_y+chat_message_spacing*chat_messages_.size(),0,0,-1,rect,font::LEFT_ALIGN);
std::cerr << "Added label..\n";
chat_messages_.push_back(chat_message(handle));
const int speaker_handle = font::add_floating_label(str.str(),12,speaker_colour,
rect.x+chat_message_x,rect.y+ypos,
0,0,-1,rect,font::LEFT_ALIGN,&chat_message_bg,chat_message_border);
const int message_handle = font::add_floating_label(msg,12,chat_message_colour,
rect.x + chat_message_x + font::get_floating_label_rect(speaker_handle).w,rect.y+ypos,
0,0,-1,rect,font::LEFT_ALIGN,&chat_message_bg,chat_message_border);
chat_messages_.push_back(chat_message(speaker_handle,message_handle));
prune_chat_messages();
std::cerr << "pruned messages...\n";
}
void display::prune_chat_messages(bool remove_all)
{
const int message_ttl = remove_all ? 0 : 1200000;
if(chat_messages_.empty() == false && (chat_messages_.front().created_at+message_ttl < SDL_GetTicks() || chat_messages_.size() > max_chat_messages)) {
const int movement = font::get_floating_label_rect(chat_messages_.front().handle).h;
font::remove_floating_label(chat_messages_.front().speaker_handle);
font::remove_floating_label(chat_messages_.front().handle);
chat_messages_.erase(chat_messages_.begin());
for(std::vector<chat_message>::const_iterator i = chat_messages_.begin(); i != chat_messages_.end(); ++i) {
font::move_floating_label(i->handle,0,-chat_message_spacing);
font::move_floating_label(i->speaker_handle,0,-movement);
font::move_floating_label(i->handle,0,-movement);
}
prune_chat_messages(remove_all);

View file

@ -291,7 +291,7 @@ public:
const map_labels& labels() const { return map_labels_; }
enum MESSAGE_TYPE { MESSAGE_PUBLIC, MESSAGE_PRIVATE };
void add_chat_message(const std::string& speaker, const std::string& msg, MESSAGE_TYPE type);
void add_chat_message(const std::string& speaker, int side, const std::string& msg, MESSAGE_TYPE type);
private:
display(const display&);
@ -424,9 +424,10 @@ private:
struct chat_message
{
chat_message(int h) : handle(h), created_at(SDL_GetTicks())
chat_message(int speaker, int h) : speaker_handle(speaker), handle(h), created_at(SDL_GetTicks())
{}
int speaker_handle;
int handle;
int created_at;
};

View file

@ -20,6 +20,7 @@
#include "log.hpp"
#include "sdl_utils.hpp"
#include "tooltips.hpp"
#include "util.hpp"
#include <cstdio>
#include <iostream>
@ -469,18 +470,21 @@ namespace {
class floating_label
{
public:
floating_label(const std::string& text, int font_size, const SDL_Color& colour,
int xpos, int ypos, int xmove, int ymove, int lifetime, const SDL_Rect& clip_rect, font::ALIGN align)
: surf_(NULL), buf_(NULL), text_(text), font_size_(font_size), colour_(colour), xpos_(xpos), ypos_(ypos),
floating_label(const std::string& text, int font_size, const SDL_Color& colour, const SDL_Color& bgcolour,
double xpos, double ypos, double xmove, double ymove, int lifetime, const SDL_Rect& clip_rect, font::ALIGN align,
int border_size)
: surf_(NULL), buf_(NULL), foreground_(NULL), text_(text), font_size_(font_size), colour_(colour), bgcolour_(bgcolour), bgalpha_(bgcolour.unused), xpos_(xpos), ypos_(ypos),
xmove_(xmove), ymove_(ymove), lifetime_(lifetime), clip_rect_(clip_rect),
alpha_change_(-255/lifetime), visible_(true), align_(align)
alpha_change_(-255/lifetime), visible_(true), align_(align), border_(border_size)
{}
void move(int xmove, int ymove);
void move(double xmove, double ymove);
void draw(SDL_Surface* screen);
void undraw(SDL_Surface* screen);
SDL_Surface* create_surface();
bool expired() const;
const std::string& text() const;
@ -491,25 +495,27 @@ private:
int xpos(size_t width) const;
shared_sdl_surface surf_, buf_;
shared_sdl_surface surf_, buf_, foreground_;
std::string text_;
int font_size_;
SDL_Color colour_;
int xpos_, ypos_, xmove_, ymove_;
SDL_Color colour_, bgcolour_;
int bgalpha_;
double xpos_, ypos_, xmove_, ymove_;
int lifetime_;
SDL_Rect clip_rect_;
int alpha_change_;
bool visible_;
font::ALIGN align_;
int border_;
};
typedef std::map<int,floating_label> label_map;
label_map labels;
int label_id = 0;
int label_id = 1;
bool hide_floating_labels = false;
void floating_label::move(int xmove, int ymove)
void floating_label::move(double xmove, double ymove)
{
xpos_ += xmove;
ypos_ += ymove;
@ -519,14 +525,84 @@ int floating_label::xpos(size_t width) const
{
int xpos = xpos_;
if(align_ == font::CENTER_ALIGN) {
xpos -= surf_->w/2;
xpos -= width/2;
} else if(align_ == font::RIGHT_ALIGN) {
xpos -= surf_->w;
xpos -= width;
}
return xpos;
}
SDL_Surface* floating_label::create_surface()
{
if(surf_ == NULL) {
std::cerr << "creating surface...\n";
TTF_Font* const font = get_font(font_size_);
if(font == NULL) {
return NULL;
}
const std::vector<std::string> lines = config::split(text_,'\n');
std::vector<shared_sdl_surface> surfaces;
for(std::vector<std::string>::const_iterator ln = lines.begin(); ln != lines.end(); ++ln) {
surfaces.push_back(shared_sdl_surface(font::render_text(font,*ln,colour_)));
}
if(surfaces.empty()) {
return NULL;
} else if(surfaces.size() == 1) {
surf_.assign(surfaces.front());
} else {
size_t width = 0, height = 0;
std::vector<shared_sdl_surface>::const_iterator i;
for(i = surfaces.begin(); i != surfaces.end(); ++i) {
width = maximum<size_t>((*i)->w,width);
height += (*i)->h;
}
const SDL_PixelFormat* const format = surfaces.front()->format;
surf_.assign(SDL_CreateRGBSurface(SDL_SWSURFACE,width,height,
format->BitsPerPixel,format->Rmask,format->Gmask,
format->Bmask,format->Amask));
size_t ypos = 0;
for(i = surfaces.begin(); i != surfaces.end(); ++i) {
SDL_SetAlpha(*i,0,0);
SDL_Rect dstrect = {0,ypos,(*i)->w,(*i)->h};
SDL_BlitSurface(*i,NULL,surf_,&dstrect);
ypos += (*i)->h;
}
}
if(surf_ == NULL) {
return NULL;
}
//if the surface has to be created onto some kind of background, then do that here
if(bgalpha_ != 0) {
std::cerr << "creating bg...\n";
shared_sdl_surface tmp(SDL_CreateRGBSurface(SDL_SWSURFACE,surf_->w+border_*2,surf_->h+border_*2,surf_->format->BitsPerPixel,
surf_->format->Rmask,surf_->format->Gmask,surf_->format->Bmask,surf_->format->Amask));
if(tmp == NULL) {
return NULL;
}
SDL_FillRect(tmp,NULL,SDL_MapRGB(tmp.get()->format,bgcolour_.r,bgcolour_.g,bgcolour_.b));
if(bgalpha_ != 255) {
tmp.assign(adjust_surface_alpha_add(tmp.get(),bgalpha_ - 255));
if(tmp == NULL) {
return NULL;
}
}
foreground_.assign(surf_);
surf_.assign(tmp);
}
}
return surf_;
}
void floating_label::draw(SDL_Surface* screen)
{
if(!visible_) {
@ -534,16 +610,9 @@ void floating_label::draw(SDL_Surface* screen)
return;
}
create_surface();
if(surf_ == NULL) {
TTF_Font* const font = get_font(font_size_);
if(font == NULL) {
return;
}
surf_.assign(font::render_text(font,text_,colour_));
if(surf_ == NULL) {
return;
}
return;
}
if(buf_ == NULL) {
@ -560,9 +629,19 @@ void floating_label::draw(SDL_Surface* screen)
SDL_Rect rect = {xpos(surf_->w),ypos_,surf_->w,surf_->h};
const clip_rect_setter clip_setter(screen,clip_rect_);
std::cerr << "blit a\n";
SDL_BlitSurface(screen,&rect,buf_,NULL);
std::cerr << "blit b\n";
SDL_BlitSurface(surf_,NULL,screen,&rect);
if(foreground_ != NULL) {
SDL_Rect rect = {xpos(surf_->w)+border_,ypos_+border_,foreground_->w,foreground_->h};
SDL_BlitSurface(foreground_,NULL,screen,&rect);
}
std::cerr << "update\n";
update_rect(rect);
std::cerr << "done\n";
}
void floating_label::undraw(SDL_Surface* screen)
@ -571,12 +650,16 @@ void floating_label::undraw(SDL_Surface* screen)
return;
}
std::cerr << "undraw....\n";
SDL_Rect rect = {xpos(surf_->w),ypos_,surf_->w,surf_->h};
const clip_rect_setter clip_setter(screen,clip_rect_);
SDL_BlitSurface(buf_,NULL,screen,&rect);
update_rect(rect);
std::cerr << "done undraw\n";
move(xmove_,ymove_);
if(lifetime_ > 0) {
--lifetime_;
@ -596,17 +679,23 @@ void floating_label::show(bool value) { visible_ = value; }
namespace font {
int add_floating_label(const std::string& text, int font_size, const SDL_Color& colour,
int xpos, int ypos, int xmove, int ymove, int lifetime, const SDL_Rect& clip_rect, ALIGN align)
double xpos, double ypos, double xmove, double ymove, int lifetime, const SDL_Rect& clip_rect, ALIGN align,
const SDL_Color* bg_colour, int border_size)
{
if(lifetime <= 0) {
lifetime = -1;
}
labels.insert(std::pair<int,floating_label>(label_id++,floating_label(text,font_size,colour,xpos,ypos,xmove,ymove,lifetime,clip_rect,align)));
SDL_Color bg = {0,0,0,0};
if(bg_colour != NULL) {
bg = *bg_colour;
}
labels.insert(std::pair<int,floating_label>(label_id++,floating_label(text,font_size,colour,bg,xpos,ypos,xmove,ymove,lifetime,clip_rect,align,border_size)));
return label_id-1;
}
void move_floating_label(int handle, int xmove, int ymove)
void move_floating_label(int handle, double xmove, double ymove)
{
const label_map::iterator i = labels.find(handle);
if(i != labels.end()) {
@ -641,6 +730,21 @@ const std::string& get_floating_label_text(int handle)
}
}
SDL_Rect get_floating_label_rect(int handle)
{
static const SDL_Rect empty_rect = {0,0,0,0};
const label_map::iterator i = labels.find(handle);
if(i != labels.end()) {
const SDL_Surface* const surf = i->second.create_surface();
if(surf != NULL) {
SDL_Rect rect = {0,0,surf->w,surf->h};
return rect;
}
}
return empty_rect;
}
floating_label_manager::floating_label_manager()
{
}

View file

@ -129,10 +129,11 @@ enum ALIGN { LEFT_ALIGN, CENTER_ALIGN, RIGHT_ALIGN };
///
/// @returns a handle to the label which can be used with other label functions
int add_floating_label(const std::string& text, int font_size, const SDL_Color& colour,
int xpos, int ypos, int xmove, int ymove, int lifetime, const SDL_Rect& clip_rect, ALIGN alignment=CENTER_ALIGN);
double xpos, double ypos, double xmove, double ymove, int lifetime, const SDL_Rect& clip_rect, ALIGN alignment=CENTER_ALIGN,
const SDL_Color* bg_colour=NULL, int border_size=0);
/// moves the floating label given by 'handle' by (xmove,ymove)
void move_floating_label(int handle, int xmove, int ymove);
void move_floating_label(int handle, double xmove, double ymove);
/// removes the floating label given by 'handle' from the screen
void remove_floating_label(int handle);
@ -142,6 +143,8 @@ void show_floating_label(int handle, bool show);
const std::string& get_floating_label_text(int handle);
SDL_Rect get_floating_label_rect(int handle);
void draw_floating_labels(SDL_Surface* screen);
void undraw_floating_labels(SDL_Surface* screen);

View file

@ -113,10 +113,10 @@ LEVEL_RESULT play_game(display& disp, game_state& state, config& game_config,
std::string label = state.label + " replay";
bool retry;
bool retry = true;
do {
retry=false;
while(retry) {
retry = false;
const int should_save = dialogs::get_save_name(disp,
string_table["save_replay_message"],
@ -124,15 +124,15 @@ LEVEL_RESULT play_game(display& disp, game_state& state, config& game_config,
&label);
if(should_save == 0) {
try {
config snapshot, starting_pos;
config snapshot;
recorder.save_game(units_data,label,snapshot,starting_pos);
} catch(gamestatus::save_game_failed& e) {
gui::show_dialog(disp,NULL,"",string_table["save_game_failed"],gui::MESSAGE);
retry=true;
retry = true;
};
}
} while(retry);
}
state.scenario = orig_scenario;
}
@ -168,10 +168,10 @@ LEVEL_RESULT play_game(display& disp, game_state& state, config& game_config,
if(scenario != NULL) {
state.label = translate_string_default((*scenario)["id"],(*scenario)["name"]);
bool retry;
bool retry = true;
do {
retry=false;
while(retry) {
retry = false;
const int should_save = dialogs::get_save_name(disp,
string_table["save_game_message"],
@ -183,10 +183,10 @@ LEVEL_RESULT play_game(display& disp, game_state& state, config& game_config,
save_game(state);
} catch(gamestatus::save_game_failed& e) {
gui::show_dialog(disp,NULL,"",string_table["save_game_failed"],gui::MESSAGE);
retry=true;
retry = true;
};
}
} while(retry);
}
}
}

View file

@ -93,7 +93,7 @@ void map_labels::clear()
void map_labels::scroll(double xmove, double ymove)
{
for(label_map::const_iterator i = labels_.begin(); i != labels_.end(); ++i) {
font::move_floating_label(i->second,int(xmove),int(ymove));
font::move_floating_label(i->second,xmove,ymove);
}
}

View file

@ -950,6 +950,17 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
for(c = castles.begin(); c != castles.end(); ++c) {
const std::set<gamemap::location>& locs = build_island_for_castle(terrain_tester,*c);
//there should be a high chance of castles placed on invalid terrain getting
//villages near them, since they are likely on bad terrain, and should get
//some compensation
const config* const village_info = cfg.find_child("village","terrain",flatland);
int village_chance = 0;
std::string village;
if(village_info != NULL) {
village_chance = atoi((*village_info)["chance"].c_str())/10;
village = (*village_info)["convert_to"];
}
for(std::set<gamemap::location>::const_iterator i = locs.begin(); i != locs.end(); ++i) {
const int x = i->x;
const int y = i->y;
@ -959,6 +970,10 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
}
terrain[x][y] = flatland[0];
if((rand()%100) < village_chance && village != "") {
terrain[x][y] = village[0];
}
}
}

View file

@ -1762,7 +1762,7 @@ void turn_info::speak()
}
recorder.speak(cfg);
gui_.add_chat_message(leader->second.description(),message,
gui_.add_chat_message(leader->second.description(),leader->second.side(),message,
private_message ? display::MESSAGE_PRIVATE : display::MESSAGE_PUBLIC);
}
}

View file

@ -25,6 +25,7 @@
#include "show_dialog.hpp"
#include "sound.hpp"
#include "statistics.hpp"
#include "util.hpp"
#include <cstdio>
#include <cstdlib>
@ -785,7 +786,8 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
sound::play_sound("bell.wav");
}
disp.add_chat_message((*child)["description"],(*child)["message"],
const int side = lexical_cast_default<int>((*child)["side"].c_str());
disp.add_chat_message((*child)["description"],side,(*child)["message"],
team_name == "" ? display::MESSAGE_PUBLIC : display::MESSAGE_PRIVATE);
}
} else if((child = cfg->child("label")) != NULL) {

View file

@ -160,6 +160,11 @@ struct shared_sdl_surface
SDL_Surface* operator->() const { return surface_.get(); }
void assign(const shared_sdl_surface& o)
{
operator=(o);
}
void assign(SDL_Surface* surf) { surface_.assign(surf); }
private:

View file

@ -34,8 +34,10 @@ struct tooltip
static const int font_size = 12;
std::vector<tooltip> tips;
std::vector<tooltip>::const_iterator current_tooltip = tips.end();
int tooltip_handle = 0;
std::string current_message;
SDL_Rect current_rect;
SDL_Surface* current_background = NULL;
@ -47,81 +49,38 @@ SDL_Rect get_text_size(const std::string& msg)
void clear_tooltip()
{
if(current_background == NULL)
return;
SDL_BlitSurface(current_background,NULL,video_->getSurface(),&current_rect);
SDL_FreeSurface(current_background);
current_background = NULL;
update_rect(current_rect);
}
void draw_tooltip()
{
if(current_background != NULL)
clear_tooltip();
SDL_Surface* screen = video_->getSurface();
current_background = get_surface_portion(screen,current_rect);
if(current_background == NULL)
return;
gui::draw_solid_tinted_rectangle(current_rect.x,current_rect.y,
current_rect.w,current_rect.h,
0,0,0,0.6,screen);
/*
gui::draw_solid_tinted_rectangle(current_rect.x,current_rect.y,
current_rect.w,current_rect.h,
180,180,0,1.0,screen);
gui::draw_rectangle(current_rect.x,current_rect.y,
current_rect.w-1,current_rect.h-1,0,screen);
*/
SDL_Rect text_area = get_text_size(current_message);
text_area.x = current_rect.x + current_rect.w/2 - text_area.w/2;
text_area.y = current_rect.y + current_rect.h/2 - text_area.h/2;
font::draw_text(display_,text_area,font_size,font::NORMAL_COLOUR,
current_message,text_area.x,text_area.y);
update_rect(current_rect);
if(tooltip_handle != 0) {
font::remove_floating_label(tooltip_handle);
tooltip_handle = 0;
}
}
void show_tooltip(const tooltip& tip)
{
clear_tooltip();
const size_t xpadding = 10;
const size_t ypadding = 10;
const SDL_Color bgcolour = {0,0,0,128};
SDL_Rect area = display_->screen_area();
tooltip_handle = font::add_floating_label(tip.message,font_size,font::NORMAL_COLOUR,
0,0,0,0,-1,area,font::LEFT_ALIGN,&bgcolour,10);
SDL_Rect area = get_text_size(tip.message);
area.w += xpadding;
area.h += ypadding;
SDL_Rect rect = font::get_floating_label_rect(tooltip_handle);
//see if there is enough room to fit it above the tip area
if(tip.rect.y > area.h)
area.y = tip.rect.y - area.h;
else if(tip.rect.y+tip.rect.h+area.h+1 < display_->y())
area.y = tip.rect.y + tip.rect.h;
else
return;
if(tip.rect.y > rect.h) {
rect.y = tip.rect.y - rect.h;
} else {
rect.y = tip.rect.y + tip.rect.h;
}
if(area.w >= display_->x())
return;
rect.x = tip.rect.x;
if(rect.x < 0) {
rect.x = 0;
} else if(rect.x + rect.w > area.w) {
rect.x = area.w - rect.w;
}
if(area.w/2 >= tip.rect.x + tip.rect.w/2)
area.x = 1;
else
area.x = tip.rect.x + tip.rect.w/2 - area.w/2;
if(area.x + area.w >= display_->x())
area.x = display_->x() - area.w - 1;
current_rect = area;
current_message = tip.message;
draw_tooltip();
font::move_floating_label(tooltip_handle,rect.x,rect.y);
}
}
@ -145,7 +104,7 @@ void clear_tooltips()
{
clear_tooltip();
tips.clear();
current_message = "";
current_tooltip = tips.end();
}
void clear_tooltips(const SDL_Rect& rect)
@ -154,12 +113,11 @@ void clear_tooltips(const SDL_Rect& rect)
for(std::vector<tooltip>::iterator i = tips.begin(); i != tips.end(); ) {
if(rectangles_overlap(i->rect,rect)) {
i = tips.erase(i);
current_tooltip = tips.end();
} else {
++i;
}
}
current_message = "";
}
void add_tooltip(const SDL_Rect& rect, const std::string& message)
@ -172,6 +130,7 @@ void add_tooltip(const SDL_Rect& rect, const std::string& message)
}
tips.push_back(tooltip(rect,message));
current_tooltip = tips.end();
}
void process(int mousex, int mousey, bool lbutton)
@ -179,12 +138,17 @@ void process(int mousex, int mousey, bool lbutton)
for(std::vector<tooltip>::const_iterator i = tips.begin(); i != tips.end(); ++i) {
if(mousex > i->rect.x && mousey > i->rect.y &&
mousex < i->rect.x + i->rect.w && mousey < i->rect.y + i->rect.h) {
show_tooltip(*i);
if(current_tooltip != i) {
show_tooltip(*i);
current_tooltip = i;
}
return;
}
}
clear_tooltip();
current_tooltip = tips.end();
}
SDL_Rect draw_text(display* gui, const SDL_Rect& area, int size,