The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
display_chat_manager.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2016 by Chris Beck <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "display_chat_manager.hpp"
16 #include "global.hpp"
17 
19 #include "display.hpp"
20 #include "floating_label.hpp"
21 #include "game_board.hpp" // <-- only needed for is_observer()
22 #include "game_preferences.hpp"
23 #include "log.hpp"
24 #include "marked-up_text.hpp"
25 #include "mp_ui_alerts.hpp"
27 
28 #include <boost/cstdint.hpp>
29 #include <SDL_timer.h>
30 #include <SDL_video.h>
31 
32 static lg::log_domain log_engine("engine");
33 #define ERR_NG LOG_STREAM(err, log_engine)
34 
35 using boost::uint32_t;
36 
37 namespace {
38  const int chat_message_border = 5;
39  const int chat_message_x = 10;
40  const SDL_Color chat_message_color = {255,255,255,SDL_ALPHA_OPAQUE};
41  const SDL_Color chat_message_bg = {0,0,0,140};
42 }
43 
45  : speaker_handle(speaker), handle(h), created_at(SDL_GetTicks())
46 {}
47 
48 
49 void display_chat_manager::add_chat_message(const time_t& time, const std::string& speaker,
51  bool bell)
52 {
53  const bool whisper = speaker.find("whisper: ") == 0;
54  std::string sender = speaker;
55  if (whisper) {
56  sender.assign(speaker, 9, speaker.size());
57  add_whisperer( sender );
58  }
59  //remove disconnected user from whisperer
60  std::string::size_type pos = message.find(" has disconnected");
61  if (pos != std::string::npos){
62  for(std::set<std::string>::const_iterator w = whisperers().begin(); w != whisperers().end(); ++w){
63  if (*w == message.substr(0,pos)) remove_whisperer(*w);
64  }
65  }
66 
67  if (!preferences::parse_should_show_lobby_join(sender, message)) return;
68  if (preferences::is_ignored(sender)) return;
69 
71 
72  bool is_observer = false;
73  { //TODO: Clean this block up somehow
74 
75  const game_board * board = dynamic_cast<const game_board*>(&my_disp_.get_disp_context());
76 
77  if (board) {
78  is_observer = board->is_observer();
79  }
80  }
81 
82  if (bell) {
83  if ((type == events::chat_handler::MESSAGE_PRIVATE && (!is_observer || whisper))
84  || utils::word_match(message, preferences::login())) {
85  mp_ui_alerts::private_message(false, sender, message);
86  } else if (preferences::is_friend(sender)) {
87  mp_ui_alerts::friend_message(false, sender, message);
88  } else if (sender == "server") {
89  mp_ui_alerts::server_message(false, sender, message);
90  } else {
91  mp_ui_alerts::public_message(false, sender, message);
92  }
93  }
94 
95  bool action = false;
96 
98 
99  if (message.find("/me ") == 0) {
100  msg.assign(message, 4, message.size());
101  action = true;
102  } else {
103  msg += message;
104  }
105 
106  try {
107  // We've had a joker who send an invalid utf-8 message to crash clients
108  // so now catch the exception and ignore the message.
110  } catch (utf8::invalid_utf8_exception&) {
111  ERR_NG << "Invalid utf-8 found, chat message is ignored." << std::endl;
112  return;
113  }
114 
115  int ypos = chat_message_x;
116  for(std::vector<chat_message>::const_iterator m = chat_messages_.begin(); m != chat_messages_.end(); ++m) {
117  ypos += std::max(font::get_floating_label_rect(m->handle).h,
118  font::get_floating_label_rect(m->speaker_handle).h);
119  }
120  SDL_Color speaker_color = {255,255,255,SDL_ALPHA_OPAQUE};
121  if(side >= 1) {
122  speaker_color = int_to_color(team::get_side_color_range(side).mid());
123  }
124 
125  SDL_Color message_color = chat_message_color;
126  std::stringstream str;
127  std::stringstream message_str;
128 
130  if(action) {
131  str << "<" << speaker << " " << msg << ">";
132  message_color = speaker_color;
133  message_str << " ";
134  } else {
135  if (!speaker.empty())
136  str << "<" << speaker << ">";
137  message_str << msg;
138  }
139  } else {
140  if(action) {
141  str << "*" << speaker << " " << msg << "*";
142  message_color = speaker_color;
143  message_str << " ";
144  } else {
145  if (!speaker.empty())
146  str << "*" << speaker << "*";
147  message_str << msg;
148  }
149  }
150 
151  // Prepend message with timestamp.
152  std::stringstream message_complete;
153  message_complete << preferences::get_chat_timestamp(time) << str.str();
154 
155  const SDL_Rect rect = my_disp_.map_outside_area();
156 
157  font::floating_label spk_flabel(message_complete.str());
158  spk_flabel.set_font_size(font::SIZE_SMALL);
159  spk_flabel.set_color(speaker_color);
160  spk_flabel.set_position(rect.x + chat_message_x, rect.y + ypos);
161  spk_flabel.set_clip_rect(rect);
162  spk_flabel.set_alignment(font::LEFT_ALIGN);
163  spk_flabel.set_bg_color(chat_message_bg);
164  spk_flabel.set_border_size(chat_message_border);
165  spk_flabel.use_markup(false);
166 
167  int speaker_handle = font::add_floating_label(spk_flabel);
168 
169  font::floating_label msg_flabel(message_str.str());
170  msg_flabel.set_font_size(font::SIZE_SMALL);
171  msg_flabel.set_color(message_color);
172  msg_flabel.set_position(rect.x + chat_message_x + font::get_floating_label_rect(speaker_handle).w,
173  rect.y + ypos);
174  msg_flabel.set_clip_rect(rect);
175  msg_flabel.set_alignment(font::LEFT_ALIGN);
176  msg_flabel.set_bg_color(chat_message_bg);
177  msg_flabel.set_border_size(chat_message_border);
178  msg_flabel.use_markup(false);
179 
180  int message_handle = font::add_floating_label(msg_flabel);
181 
182  chat_messages_.push_back(chat_message(speaker_handle,message_handle));
183 
185 }
186 
188 {
189  const unsigned message_aging = preferences::chat_message_aging();
190  const unsigned message_ttl = remove_all ? 0 : message_aging * 60 * 1000;
191  const unsigned max_chat_messages = preferences::chat_lines();
192  int movement = 0;
193 
194  if(message_aging != 0 || remove_all || chat_messages_.size() > max_chat_messages) {
195  while (!chat_messages_.empty() &&
196  (chat_messages_.front().created_at + message_ttl < SDL_GetTicks() ||
197  chat_messages_.size() > max_chat_messages))
198  {
199  const chat_message &old = chat_messages_.front();
200  movement += font::get_floating_label_rect(old.handle).h;
203  chat_messages_.erase(chat_messages_.begin());
204  }
205  }
206 
207  for(const chat_message &cm : chat_messages_) {
208  font::move_floating_label(cm.speaker_handle, 0, - movement);
209  font::move_floating_label(cm.handle, 0, - movement);
210  }
211 }
212 
213 
214 
Game board class.
Definition: game_board.hpp:55
int pos
Definition: formula.cpp:800
GLuint GLuint GLsizei GLenum type
Definition: glew.h:1221
SDL_Color int_to_color(const Uint32 rgb)
Definition: utils.cpp:63
boost::uint32_t uint32_t
Definition: xbrz.hpp:45
static const color_range get_side_color_range(int side)
Definition: team.cpp:816
void remove_floating_label(int handle)
removes the floating label given by 'handle' from the screen
void parse_admin_authentication(const std::string &sender, const std::string &message)
std::string word_wrap_text(const std::string &unwrapped_text, int font_size, int max_width, int max_height, int max_lines, bool partial_line)
Wrap text.
void set_font_size(int font_size)
std::vector< chat_message > chat_messages_
void move_floating_label(int handle, double xmove, double ymove)
moves the floating label given by 'handle' by (xmove,ymove)
void friend_message(bool is_lobby, const std::string &sender, const std::string &message)
bool is_friend(const std::string &nick)
void add_whisperer(const std::string &nick)
void private_message(bool is_lobby, const std::string &sender, const std::string &message)
GLubyte GLubyte GLubyte GLubyte w
Definition: glew.h:1858
#define ERR_NG
map_display and display: classes which take care of displaying the map and game-data on the screen...
void prune_chat_messages(bool remove_all=false)
void remove_whisperer(const std::string &nick)
bool is_ignored(const std::string &nick)
std::string login()
static lg::log_domain log_engine("engine")
Thrown by operations encountering invalid UTF-8 data.
void public_message(bool is_lobby, const std::string &sender, const std::string &message)
GLfloat GLfloat GLfloat GLfloat h
Definition: glew.h:5910
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:112
int add_floating_label(const floating_label &flabel)
add a label floating on the screen above everything else.
SDL_Rect get_floating_label_rect(int handle)
void server_message(bool is_lobby, const std::string &sender, const std::string &message)
bool faked() const
Definition: video.hpp:166
const GLdouble * m
Definition: glew.h:6968
std::string get_chat_timestamp(const time_t &t)
Standard logging facilities (interface).
const SDL_Rect & map_outside_area() const
Returns the available area for a map, this may differ from the above.
Definition: display.hpp:248
CVideo & video()
Gets the underlying screen object.
Definition: display.hpp:202
bool is_observer() const
Check if we are an observer in this game.
GLsizei GLenum GLuint GLuint GLsizei char * message
Definition: glew.h:2499
bool parse_should_show_lobby_join(const std::string &sender, const std::string &message)
const display_context & get_disp_context() const
Definition: display.hpp:167
void chat_message(std::string const &caption, std::string const &msg)
Displays a message in the chat window.
Definition: lua_api.cpp:48
void add_chat_message(const time_t &time, const std::string &speaker, int side, const std::string &msg, events::chat_handler::MESSAGE_TYPE type, bool bell)
const std::set< std::string > & whisperers() const
GLsizei const GLcharARB ** string
Definition: glew.h:4503
const int SIZE_SMALL
Definition: font.hpp:62
boost::shared_ptr< halo_record > handle
Definition: halo.hpp:34
bool word_match(const std::string &message, const std::string &word)
Check if a message contains a word.