mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-06 06:15:04 +00:00
(svn r14047) -Codechange: move chatmessage handling to the network directory as that's the only case chat messages are used. Furthermore remove any trace of chatmessages when compiling without network support.
This commit is contained in:
parent
6995365535
commit
d0c1a989a4
@ -1767,6 +1767,10 @@
|
||||
RelativePath=".\..\src\music_gui.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\network\network_chat_gui.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\network\network_gui.cpp"
|
||||
>
|
||||
|
@ -1764,6 +1764,10 @@
|
||||
RelativePath=".\..\src\music_gui.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\network\network_chat_gui.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\network\network_gui.cpp"
|
||||
>
|
||||
|
@ -385,6 +385,7 @@ intro_gui.cpp
|
||||
main_gui.cpp
|
||||
misc_gui.cpp
|
||||
music_gui.cpp
|
||||
network/network_chat_gui.cpp
|
||||
network/network_gui.cpp
|
||||
newgrf_gui.cpp
|
||||
news_gui.cpp
|
||||
|
13
src/date.cpp
13
src/date.cpp
@ -33,10 +33,6 @@ void SetDate(Date date)
|
||||
ConvertDateToYMD(date, &ymd);
|
||||
_cur_year = ymd.year;
|
||||
_cur_month = ymd.month;
|
||||
#ifdef ENABLE_NETWORK
|
||||
_network_last_advertise_frame = 0;
|
||||
_network_need_advertise = true;
|
||||
#endif /* ENABLE_NETWORK */
|
||||
}
|
||||
|
||||
#define M(a, b) ((a << 5) | b)
|
||||
@ -161,7 +157,6 @@ Date ConvertYMDToDate(Year year, Month month, Day day)
|
||||
/** Functions used by the IncreaseDate function */
|
||||
|
||||
extern void WaypointsDailyLoop();
|
||||
extern void ChatMessageDailyLoop();
|
||||
extern void EnginesDailyLoop();
|
||||
extern void DisasterDailyLoop();
|
||||
|
||||
@ -228,7 +223,9 @@ void IncreaseDate()
|
||||
/* yeah, increase day counter and call various daily loops */
|
||||
_date++;
|
||||
|
||||
ChatMessageDailyLoop();
|
||||
#ifdef ENABLE_NETWORK
|
||||
NetworkChatMessageDailyLoop();
|
||||
#endif /* ENABLE_NETWORK */
|
||||
|
||||
DisasterDailyLoop();
|
||||
WaypointsDailyLoop();
|
||||
@ -296,9 +293,11 @@ void IncreaseDate()
|
||||
_date -= days_this_year;
|
||||
FOR_ALL_VEHICLES(v) v->date_of_last_service -= days_this_year;
|
||||
|
||||
#ifdef ENABLE_NETWORK
|
||||
/* Because the _date wraps here, and text-messages expire by game-days, we have to clean out
|
||||
* all of them if the date is set back, else those messages will hang for ever */
|
||||
InitChatMessage();
|
||||
NetworkInitChatMessage();
|
||||
#endif /* ENABLE_NETWORK */
|
||||
}
|
||||
|
||||
if (_settings_client.gui.auto_euro) CheckSwitchToEuro();
|
||||
|
11
src/gfx.cpp
11
src/gfx.cpp
@ -20,6 +20,7 @@
|
||||
#include "core/alloc_func.hpp"
|
||||
#include "core/sort_func.hpp"
|
||||
#include "landscape_type.h"
|
||||
#include "network/network_func.h"
|
||||
|
||||
#include "table/palettes.h"
|
||||
#include "table/sprites.h"
|
||||
@ -81,7 +82,10 @@ void GfxScroll(int left, int top, int width, int height, int xo, int yo)
|
||||
if (xo == 0 && yo == 0) return;
|
||||
|
||||
if (_cursor.visible) UndrawMouseCursor();
|
||||
UndrawChatMessage();
|
||||
|
||||
#ifdef ENABLE_NETWORK
|
||||
NetworkUndrawChatMessage();
|
||||
#endif /* ENABLE_NETWORK */
|
||||
|
||||
blitter->ScrollBuffer(_screen.dst_ptr, left, top, width, height, xo, yo);
|
||||
/* This part of the screen is now dirty. */
|
||||
@ -1252,7 +1256,10 @@ void RedrawScreenRect(int left, int top, int right, int bottom)
|
||||
UndrawMouseCursor();
|
||||
}
|
||||
}
|
||||
UndrawChatMessage();
|
||||
|
||||
#ifdef ENABLE_NETWORK
|
||||
NetworkUndrawChatMessage();
|
||||
#endif /* ENABLE_NETWORK */
|
||||
|
||||
DrawOverlappedWindowForAll(left, top, right, bottom);
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "animated_tile_func.h"
|
||||
#include "tilehighlight_func.h"
|
||||
#include "core/bitmath_func.hpp"
|
||||
#include "network/network_func.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
#include "table/sprites.h"
|
||||
@ -105,7 +106,9 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date)
|
||||
InitializeCheats();
|
||||
|
||||
InitTextEffects();
|
||||
InitChatMessage();
|
||||
#ifdef ENABLE_NETWORK
|
||||
NetworkInitChatMessage();
|
||||
#endif /* ENABLE_NETWORK */
|
||||
InitializeAnimatedTiles();
|
||||
|
||||
InitializeLandscapeVariables(false);
|
||||
|
@ -230,7 +230,7 @@ void CDECL NetworkTextMessage(NetworkAction action, ConsoleColour color, bool se
|
||||
|
||||
DebugDumpCommands("ddc:cmsg:%d;%d;%s\n", _date, _date_fract, message);
|
||||
IConsolePrintF(color, "%s", message);
|
||||
AddChatMessage(color, duration, "%s", message);
|
||||
NetworkAddChatMessage(color, duration, "%s", message);
|
||||
}
|
||||
|
||||
// Calculate the frame-lag of a client
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
void NetworkStartUp();
|
||||
void NetworkShutDown();
|
||||
void NetworkDrawChatMessage();
|
||||
|
||||
extern bool _networking; ///< are we in networking mode?
|
||||
extern bool _network_server; ///< network-server is active
|
||||
@ -23,6 +24,7 @@ extern bool _is_network_server; ///< Does this client wants to be a network-ser
|
||||
|
||||
static inline void NetworkStartUp() {}
|
||||
static inline void NetworkShutDown() {}
|
||||
static inline void NetworkDrawChatMessage() {}
|
||||
|
||||
#define _networking 0
|
||||
#define _network_server 0
|
||||
|
487
src/network/network_chat_gui.cpp
Normal file
487
src/network/network_chat_gui.cpp
Normal file
@ -0,0 +1,487 @@
|
||||
/* $Id$ */
|
||||
|
||||
/** @file network_chat_gui.cpp GUI for handling chat messages. */
|
||||
|
||||
#include <stdarg.h> /* va_list */
|
||||
|
||||
#ifdef ENABLE_NETWORK
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "network.h"
|
||||
#include "network_type.h"
|
||||
#include "../date_func.h"
|
||||
#include "../gfx_func.h"
|
||||
#include "../strings_func.h"
|
||||
#include "../blitter/factory.hpp"
|
||||
#include "../console_func.h"
|
||||
#include "../video/video_driver.hpp"
|
||||
#include "../table/sprites.h"
|
||||
#include "../window_gui.h"
|
||||
#include "../textbuf_gui.h"
|
||||
#include "../querystring_gui.h"
|
||||
#include "../town.h"
|
||||
#include "../window_func.h"
|
||||
#include "network_internal.h"
|
||||
#include "network_client.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
enum {
|
||||
MAX_CHAT_MESSAGES = 10,
|
||||
};
|
||||
|
||||
struct ChatMessage {
|
||||
char message[NETWORK_CHAT_LENGTH];
|
||||
uint16 color;
|
||||
Date end_date;
|
||||
};
|
||||
|
||||
/* used for chat window */
|
||||
static ChatMessage _chatmsg_list[MAX_CHAT_MESSAGES];
|
||||
static bool _chatmessage_dirty = false;
|
||||
static bool _chatmessage_visible = false;
|
||||
static bool _chat_tab_completion_active;
|
||||
|
||||
/* The chatbox grows from the bottom so the coordinates are pixels from
|
||||
* the left and pixels from the bottom. The height is the maximum height */
|
||||
static const PointDimension _chatmsg_box = {10, 30, 500, 150};
|
||||
static uint8 _chatmessage_backup[150 * 500 * 6]; // (height * width)
|
||||
|
||||
static inline uint GetChatMessageCount()
|
||||
{
|
||||
uint i = 0;
|
||||
for (; i < MAX_CHAT_MESSAGES; i++) {
|
||||
if (_chatmsg_list[i].message[0] == '\0') break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a text message to the 'chat window' to be shown
|
||||
* @param color The colour this message is to be shown in
|
||||
* @param duration The duration of the chat message in game-days
|
||||
* @param message message itself in printf() style
|
||||
*/
|
||||
void CDECL NetworkAddChatMessage(uint16 color, uint8 duration, const char *message, ...)
|
||||
{
|
||||
char buf[NETWORK_CHAT_LENGTH];
|
||||
const char *bufp;
|
||||
va_list va;
|
||||
uint msg_count;
|
||||
uint16 lines;
|
||||
|
||||
va_start(va, message);
|
||||
vsnprintf(buf, lengthof(buf), message, va);
|
||||
va_end(va);
|
||||
|
||||
|
||||
Utf8TrimString(buf, NETWORK_CHAT_LENGTH);
|
||||
|
||||
/* Force linebreaks for strings that are too long */
|
||||
lines = GB(FormatStringLinebreaks(buf, _chatmsg_box.width - 8), 0, 16) + 1;
|
||||
if (lines >= MAX_CHAT_MESSAGES) return;
|
||||
|
||||
msg_count = GetChatMessageCount();
|
||||
/* We want to add more chat messages than there is free space for, remove 'old' */
|
||||
if (lines > MAX_CHAT_MESSAGES - msg_count) {
|
||||
int i = lines - (MAX_CHAT_MESSAGES - msg_count);
|
||||
memmove(&_chatmsg_list[0], &_chatmsg_list[i], sizeof(_chatmsg_list[0]) * (msg_count - i));
|
||||
msg_count = MAX_CHAT_MESSAGES - lines;
|
||||
}
|
||||
|
||||
for (bufp = buf; lines != 0; lines--) {
|
||||
ChatMessage *cmsg = &_chatmsg_list[msg_count++];
|
||||
ttd_strlcpy(cmsg->message, bufp, sizeof(cmsg->message));
|
||||
|
||||
/* The default colour for a message is player colour. Replace this with
|
||||
* white for any additional lines */
|
||||
cmsg->color = (bufp == buf && color & IS_PALETTE_COLOR) ? color : (0x1D - 15) | IS_PALETTE_COLOR;
|
||||
cmsg->end_date = _date + duration;
|
||||
|
||||
bufp += strlen(bufp) + 1; // jump to 'next line' in the formatted string
|
||||
}
|
||||
|
||||
_chatmessage_dirty = true;
|
||||
}
|
||||
|
||||
void NetworkInitChatMessage()
|
||||
{
|
||||
for (uint i = 0; i < MAX_CHAT_MESSAGES; i++) {
|
||||
_chatmsg_list[i].message[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/** Hide the chatbox */
|
||||
void NetworkUndrawChatMessage()
|
||||
{
|
||||
if (_chatmessage_visible) {
|
||||
Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
|
||||
/* Sometimes we also need to hide the cursor
|
||||
* This is because both textmessage and the cursor take a shot of the
|
||||
* screen before drawing.
|
||||
* Now the textmessage takes his shot and paints his data before the cursor
|
||||
* does, so in the shot of the cursor is the screen-data of the textmessage
|
||||
* included when the cursor hangs somewhere over the textmessage. To
|
||||
* avoid wrong repaints, we undraw the cursor in that case, and everything
|
||||
* looks nicely ;)
|
||||
* (and now hope this story above makes sense to you ;))
|
||||
*/
|
||||
|
||||
if (_cursor.visible) {
|
||||
if (_cursor.draw_pos.x + _cursor.draw_size.x >= _chatmsg_box.x &&
|
||||
_cursor.draw_pos.x <= _chatmsg_box.x + _chatmsg_box.width &&
|
||||
_cursor.draw_pos.y + _cursor.draw_size.y >= _screen.height - _chatmsg_box.y - _chatmsg_box.height &&
|
||||
_cursor.draw_pos.y <= _screen.height - _chatmsg_box.y) {
|
||||
UndrawMouseCursor();
|
||||
}
|
||||
}
|
||||
|
||||
int x = _chatmsg_box.x;
|
||||
int y = _screen.height - _chatmsg_box.y - _chatmsg_box.height;
|
||||
int width = _chatmsg_box.width;
|
||||
int height = _chatmsg_box.height;
|
||||
if (y < 0) {
|
||||
height = max(height + y, min(_chatmsg_box.height, _screen.height));
|
||||
y = 0;
|
||||
}
|
||||
if (x + width >= _screen.width) {
|
||||
width = _screen.width - x;
|
||||
}
|
||||
if (width <= 0 || height <= 0) return;
|
||||
|
||||
_chatmessage_visible = false;
|
||||
/* Put our 'shot' back to the screen */
|
||||
blitter->CopyFromBuffer(blitter->MoveTo(_screen.dst_ptr, x, y), _chatmessage_backup, width, height);
|
||||
/* And make sure it is updated next time */
|
||||
_video_driver->MakeDirty(x, y, width, height);
|
||||
|
||||
_chatmessage_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Check if a message is expired every day */
|
||||
void NetworkChatMessageDailyLoop()
|
||||
{
|
||||
for (uint i = 0; i < MAX_CHAT_MESSAGES; i++) {
|
||||
ChatMessage *cmsg = &_chatmsg_list[i];
|
||||
if (cmsg->message[0] == '\0') continue;
|
||||
|
||||
/* Message has expired, remove from the list */
|
||||
if (cmsg->end_date < _date) {
|
||||
/* Move the remaining messages over the current message */
|
||||
if (i != MAX_CHAT_MESSAGES - 1) memmove(cmsg, cmsg + 1, sizeof(*cmsg) * (MAX_CHAT_MESSAGES - i - 1));
|
||||
|
||||
/* Mark the last item as empty */
|
||||
_chatmsg_list[MAX_CHAT_MESSAGES - 1].message[0] = '\0';
|
||||
_chatmessage_dirty = true;
|
||||
|
||||
/* Go one item back, because we moved the array 1 to the left */
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Draw the chat message-box */
|
||||
void NetworkDrawChatMessage()
|
||||
{
|
||||
Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
|
||||
if (!_chatmessage_dirty) return;
|
||||
|
||||
/* First undraw if needed */
|
||||
NetworkUndrawChatMessage();
|
||||
|
||||
if (_iconsole_mode == ICONSOLE_FULL) return;
|
||||
|
||||
/* Check if we have anything to draw at all */
|
||||
uint count = GetChatMessageCount();
|
||||
if (count == 0) return;
|
||||
|
||||
int x = _chatmsg_box.x;
|
||||
int y = _screen.height - _chatmsg_box.y - _chatmsg_box.height;
|
||||
int width = _chatmsg_box.width;
|
||||
int height = _chatmsg_box.height;
|
||||
if (y < 0) {
|
||||
height = max(height + y, min(_chatmsg_box.height, _screen.height));
|
||||
y = 0;
|
||||
}
|
||||
if (x + width >= _screen.width) {
|
||||
width = _screen.width - x;
|
||||
}
|
||||
if (width <= 0 || height <= 0) return;
|
||||
|
||||
assert(blitter->BufferSize(width, height) < (int)sizeof(_chatmessage_backup));
|
||||
|
||||
/* Make a copy of the screen as it is before painting (for undraw) */
|
||||
blitter->CopyToBuffer(blitter->MoveTo(_screen.dst_ptr, x, y), _chatmessage_backup, width, height);
|
||||
|
||||
_cur_dpi = &_screen; // switch to _screen painting
|
||||
|
||||
/* Paint a half-transparent box behind the chat messages */
|
||||
GfxFillRect(
|
||||
_chatmsg_box.x,
|
||||
_screen.height - _chatmsg_box.y - count * 13 - 2,
|
||||
_chatmsg_box.x + _chatmsg_box.width - 1,
|
||||
_screen.height - _chatmsg_box.y - 2,
|
||||
PALETTE_TO_TRANSPARENT, FILLRECT_RECOLOR // black, but with some alpha for background
|
||||
);
|
||||
|
||||
/* Paint the chat messages starting with the lowest at the bottom */
|
||||
for (uint y = 13; count-- != 0; y += 13) {
|
||||
DoDrawString(_chatmsg_list[count].message, _chatmsg_box.x + 3, _screen.height - _chatmsg_box.y - y + 1, _chatmsg_list[count].color);
|
||||
}
|
||||
|
||||
/* Make sure the data is updated next flush */
|
||||
_video_driver->MakeDirty(x, y, width, height);
|
||||
|
||||
_chatmessage_visible = true;
|
||||
_chatmessage_dirty = false;
|
||||
}
|
||||
|
||||
|
||||
static void SendChat(const char *buf, DestType type, int dest)
|
||||
{
|
||||
if (StrEmpty(buf)) return;
|
||||
if (!_network_server) {
|
||||
SEND_COMMAND(PACKET_CLIENT_CHAT)((NetworkAction)(NETWORK_ACTION_CHAT + type), type, dest, buf);
|
||||
} else {
|
||||
NetworkServerSendChat((NetworkAction)(NETWORK_ACTION_CHAT + type), type, dest, buf, NETWORK_SERVER_INDEX);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct NetworkChatWindow : public QueryStringBaseWindow {
|
||||
DestType dtype;
|
||||
int dest;
|
||||
|
||||
NetworkChatWindow (const WindowDesc *desc, DestType type, int dest) : QueryStringBaseWindow(NETWORK_CHAT_LENGTH, desc)
|
||||
{
|
||||
this->LowerWidget(2);
|
||||
this->dtype = type;
|
||||
this->dest = dest;
|
||||
this->afilter = CS_ALPHANUMERAL;
|
||||
InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, 0);
|
||||
|
||||
InvalidateWindowData(WC_NEWS_WINDOW, 0, this->height);
|
||||
SetBit(_no_scroll, SCROLL_CHAT); // do not scroll the game with the arrow-keys
|
||||
|
||||
_chat_tab_completion_active = false;
|
||||
|
||||
this->FindWindowPlacementAndResize(desc);
|
||||
}
|
||||
|
||||
~NetworkChatWindow ()
|
||||
{
|
||||
InvalidateWindowData(WC_NEWS_WINDOW, 0, 0);
|
||||
ClrBit(_no_scroll, SCROLL_CHAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the next item of the list of things that can be auto-completed.
|
||||
* @param item The current indexed item to return. This function can, and most
|
||||
* likely will, alter item, to skip empty items in the arrays.
|
||||
* @return Returns the char that matched to the index.
|
||||
*/
|
||||
const char *ChatTabCompletionNextItem(uint *item)
|
||||
{
|
||||
static char chat_tab_temp_buffer[64];
|
||||
|
||||
/* First, try clients */
|
||||
if (*item < MAX_CLIENT_INFO) {
|
||||
/* Skip inactive clients */
|
||||
while (_network_client_info[*item].client_index == NETWORK_EMPTY_INDEX && *item < MAX_CLIENT_INFO) (*item)++;
|
||||
if (*item < MAX_CLIENT_INFO) return _network_client_info[*item].client_name;
|
||||
}
|
||||
|
||||
/* Then, try townnames */
|
||||
/* Not that the following assumes all town indices are adjacent, ie no
|
||||
* towns have been deleted. */
|
||||
if (*item <= (uint)MAX_CLIENT_INFO + GetMaxTownIndex()) {
|
||||
const Town *t;
|
||||
|
||||
FOR_ALL_TOWNS_FROM(t, *item - MAX_CLIENT_INFO) {
|
||||
/* Get the town-name via the string-system */
|
||||
SetDParam(0, t->index);
|
||||
GetString(chat_tab_temp_buffer, STR_TOWN, lastof(chat_tab_temp_buffer));
|
||||
return &chat_tab_temp_buffer[0];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find what text to complete. It scans for a space from the left and marks
|
||||
* the word right from that as to complete. It also writes a \0 at the
|
||||
* position of the space (if any). If nothing found, buf is returned.
|
||||
*/
|
||||
static char *ChatTabCompletionFindText(char *buf)
|
||||
{
|
||||
char *p = strrchr(buf, ' ');
|
||||
if (p == NULL) return buf;
|
||||
|
||||
*p = '\0';
|
||||
return p + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* See if we can auto-complete the current text of the user.
|
||||
*/
|
||||
void ChatTabCompletion()
|
||||
{
|
||||
static char _chat_tab_completion_buf[NETWORK_CHAT_LENGTH];
|
||||
assert(this->edit_str_size == lengthof(_chat_tab_completion_buf));
|
||||
|
||||
Textbuf *tb = &this->text;
|
||||
size_t len, tb_len;
|
||||
uint item;
|
||||
char *tb_buf, *pre_buf;
|
||||
const char *cur_name;
|
||||
bool second_scan = false;
|
||||
|
||||
item = 0;
|
||||
|
||||
/* Copy the buffer so we can modify it without damaging the real data */
|
||||
pre_buf = (_chat_tab_completion_active) ? strdup(_chat_tab_completion_buf) : strdup(tb->buf);
|
||||
|
||||
tb_buf = ChatTabCompletionFindText(pre_buf);
|
||||
tb_len = strlen(tb_buf);
|
||||
|
||||
while ((cur_name = ChatTabCompletionNextItem(&item)) != NULL) {
|
||||
item++;
|
||||
|
||||
if (_chat_tab_completion_active) {
|
||||
/* We are pressing TAB again on the same name, is there an other name
|
||||
* that starts with this? */
|
||||
if (!second_scan) {
|
||||
size_t offset;
|
||||
size_t length;
|
||||
|
||||
/* If we are completing at the begin of the line, skip the ': ' we added */
|
||||
if (tb_buf == pre_buf) {
|
||||
offset = 0;
|
||||
length = tb->length - 2;
|
||||
} else {
|
||||
/* Else, find the place we are completing at */
|
||||
offset = strlen(pre_buf) + 1;
|
||||
length = tb->length - offset;
|
||||
}
|
||||
|
||||
/* Compare if we have a match */
|
||||
if (strlen(cur_name) == length && strncmp(cur_name, tb->buf + offset, length) == 0) second_scan = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Now any match we make on _chat_tab_completion_buf after this, is perfect */
|
||||
}
|
||||
|
||||
len = strlen(cur_name);
|
||||
if (tb_len < len && strncasecmp(cur_name, tb_buf, tb_len) == 0) {
|
||||
/* Save the data it was before completion */
|
||||
if (!second_scan) snprintf(_chat_tab_completion_buf, lengthof(_chat_tab_completion_buf), "%s", tb->buf);
|
||||
_chat_tab_completion_active = true;
|
||||
|
||||
/* Change to the found name. Add ': ' if we are at the start of the line (pretty) */
|
||||
if (pre_buf == tb_buf) {
|
||||
snprintf(tb->buf, this->edit_str_size, "%s: ", cur_name);
|
||||
} else {
|
||||
snprintf(tb->buf, this->edit_str_size, "%s %s", pre_buf, cur_name);
|
||||
}
|
||||
|
||||
/* Update the textbuffer */
|
||||
UpdateTextBufferSize(&this->text);
|
||||
|
||||
this->SetDirty();
|
||||
free(pre_buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (second_scan) {
|
||||
/* We walked all posibilities, and the user presses tab again.. revert to original text */
|
||||
strcpy(tb->buf, _chat_tab_completion_buf);
|
||||
_chat_tab_completion_active = false;
|
||||
|
||||
/* Update the textbuffer */
|
||||
UpdateTextBufferSize(&this->text);
|
||||
|
||||
this->SetDirty();
|
||||
}
|
||||
free(pre_buf);
|
||||
}
|
||||
|
||||
virtual void OnPaint()
|
||||
{
|
||||
static const StringID chat_captions[] = {
|
||||
STR_NETWORK_CHAT_ALL_CAPTION,
|
||||
STR_NETWORK_CHAT_COMPANY_CAPTION,
|
||||
STR_NETWORK_CHAT_CLIENT_CAPTION
|
||||
};
|
||||
|
||||
this->DrawWidgets();
|
||||
|
||||
assert((uint)this->dtype < lengthof(chat_captions));
|
||||
DrawStringRightAligned(this->widget[2].left - 2, this->widget[2].top + 1, chat_captions[this->dtype], TC_BLACK);
|
||||
this->DrawEditBox(2);
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget)
|
||||
{
|
||||
switch (widget) {
|
||||
case 2:
|
||||
ShowOnScreenKeyboard(this, 2, 0, 3);
|
||||
break;
|
||||
|
||||
case 3: /* Send */
|
||||
SendChat(this->text.buf, this->dtype, this->dest);
|
||||
/* FALLTHROUGH */
|
||||
case 0: /* Cancel */ delete this; break;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnMouseLoop()
|
||||
{
|
||||
this->HandleEditBox(2);
|
||||
}
|
||||
|
||||
virtual EventState OnKeyPress(uint16 key, uint16 keycode)
|
||||
{
|
||||
EventState state = ES_NOT_HANDLED;
|
||||
if (keycode == WKC_TAB) {
|
||||
ChatTabCompletion();
|
||||
} else {
|
||||
_chat_tab_completion_active = false;
|
||||
switch (this->HandleEditBoxKey(2, key, keycode, state)) {
|
||||
case 1: /* Return */
|
||||
SendChat(this->text.buf, this->dtype, this->dest);
|
||||
/* FALLTHROUGH */
|
||||
case 2: /* Escape */ delete this; break;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
static const Widget _chat_window_widgets[] = {
|
||||
{ WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
|
||||
{ WWT_PANEL, RESIZE_RIGHT, COLOUR_GREY, 11, 319, 0, 13, 0x0, STR_NULL}, // background
|
||||
{ WWT_EDITBOX, RESIZE_RIGHT, COLOUR_GREY, 75, 257, 1, 12, STR_NETWORK_CHAT_OSKTITLE, STR_NULL}, // text box
|
||||
{ WWT_PUSHTXTBTN, RESIZE_LR, COLOUR_GREY, 258, 319, 1, 12, STR_NETWORK_SEND, STR_NULL}, // send button
|
||||
{ WIDGETS_END},
|
||||
};
|
||||
|
||||
static const WindowDesc _chat_window_desc = {
|
||||
WDP_CENTER, -26, 320, 14, 640, 14, // x, y, width, height
|
||||
WC_SEND_NETWORK_MSG, WC_NONE,
|
||||
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET,
|
||||
_chat_window_widgets,
|
||||
};
|
||||
|
||||
void ShowNetworkChatQueryWindow(DestType type, int dest)
|
||||
{
|
||||
DeleteWindowById(WC_SEND_NETWORK_MSG, 0);
|
||||
new NetworkChatWindow (&_chat_window_desc, type, dest);
|
||||
}
|
||||
|
||||
#endif /* ENABLE_NETWORK */
|
@ -57,6 +57,11 @@ void NetworkServerSendRcon(uint16 client_index, ConsoleColour colour_code, const
|
||||
void NetworkServerSendError(uint16 client_index, NetworkErrorCode error);
|
||||
void NetworkServerSendChat(NetworkAction action, DestType type, int dest, const char *msg, uint16 from_index);
|
||||
|
||||
void NetworkInitChatMessage();
|
||||
void CDECL NetworkAddChatMessage(uint16 color, uint8 duration, const char *message, ...);
|
||||
void NetworkUndrawChatMessage();
|
||||
void NetworkChatMessageDailyLoop();
|
||||
|
||||
#define FOR_ALL_ACTIVE_CLIENT_INFOS(ci) for (ci = _network_client_info; ci != endof(_network_client_info); ci++) if (ci->client_index != NETWORK_EMPTY_INDEX)
|
||||
|
||||
#endif /* ENABLE_NETWORK */
|
||||
|
@ -15,11 +15,9 @@
|
||||
#include "network_gamelist.h"
|
||||
#include "../gui.h"
|
||||
#include "../window_gui.h"
|
||||
#include "../textbuf_gui.h"
|
||||
#include "../variables.h"
|
||||
#include "network_server.h"
|
||||
#include "network_udp.h"
|
||||
#include "../town.h"
|
||||
#include "../newgrf.h"
|
||||
#include "../functions.h"
|
||||
#include "../window_func.h"
|
||||
@ -37,8 +35,6 @@
|
||||
#include "../table/sprites.h"
|
||||
|
||||
|
||||
static bool _chat_tab_completion_active;
|
||||
|
||||
static void ShowNetworkStartServerWindow();
|
||||
static void ShowNetworkLobbyWindow(NetworkGameList *ngl);
|
||||
extern void SwitchMode(int new_mode);
|
||||
@ -1732,250 +1728,6 @@ void ShowJoinStatusWindow()
|
||||
new NetworkJoinStatusWindow(&_network_join_status_window_desc);
|
||||
}
|
||||
|
||||
static void SendChat(const char *buf, DestType type, int dest)
|
||||
{
|
||||
if (StrEmpty(buf)) return;
|
||||
if (!_network_server) {
|
||||
SEND_COMMAND(PACKET_CLIENT_CHAT)((NetworkAction)(NETWORK_ACTION_CHAT + type), type, dest, buf);
|
||||
} else {
|
||||
NetworkServerSendChat((NetworkAction)(NETWORK_ACTION_CHAT + type), type, dest, buf, NETWORK_SERVER_INDEX);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct NetworkChatWindow : public QueryStringBaseWindow {
|
||||
DestType dtype;
|
||||
int dest;
|
||||
|
||||
NetworkChatWindow (const WindowDesc *desc, DestType type, int dest) : QueryStringBaseWindow(NETWORK_CHAT_LENGTH, desc)
|
||||
{
|
||||
this->LowerWidget(2);
|
||||
this->dtype = type;
|
||||
this->dest = dest;
|
||||
this->afilter = CS_ALPHANUMERAL;
|
||||
InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, 0);
|
||||
|
||||
InvalidateWindowData(WC_NEWS_WINDOW, 0, this->height);
|
||||
SetBit(_no_scroll, SCROLL_CHAT); // do not scroll the game with the arrow-keys
|
||||
|
||||
_chat_tab_completion_active = false;
|
||||
|
||||
this->FindWindowPlacementAndResize(desc);
|
||||
}
|
||||
|
||||
~NetworkChatWindow ()
|
||||
{
|
||||
InvalidateWindowData(WC_NEWS_WINDOW, 0, 0);
|
||||
ClrBit(_no_scroll, SCROLL_CHAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the next item of the list of things that can be auto-completed.
|
||||
* @param item The current indexed item to return. This function can, and most
|
||||
* likely will, alter item, to skip empty items in the arrays.
|
||||
* @return Returns the char that matched to the index.
|
||||
*/
|
||||
const char *ChatTabCompletionNextItem(uint *item)
|
||||
{
|
||||
static char chat_tab_temp_buffer[64];
|
||||
|
||||
/* First, try clients */
|
||||
if (*item < MAX_CLIENT_INFO) {
|
||||
/* Skip inactive clients */
|
||||
while (_network_client_info[*item].client_index == NETWORK_EMPTY_INDEX && *item < MAX_CLIENT_INFO) (*item)++;
|
||||
if (*item < MAX_CLIENT_INFO) return _network_client_info[*item].client_name;
|
||||
}
|
||||
|
||||
/* Then, try townnames */
|
||||
/* Not that the following assumes all town indices are adjacent, ie no
|
||||
* towns have been deleted. */
|
||||
if (*item <= (uint)MAX_CLIENT_INFO + GetMaxTownIndex()) {
|
||||
const Town *t;
|
||||
|
||||
FOR_ALL_TOWNS_FROM(t, *item - MAX_CLIENT_INFO) {
|
||||
/* Get the town-name via the string-system */
|
||||
SetDParam(0, t->index);
|
||||
GetString(chat_tab_temp_buffer, STR_TOWN, lastof(chat_tab_temp_buffer));
|
||||
return &chat_tab_temp_buffer[0];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find what text to complete. It scans for a space from the left and marks
|
||||
* the word right from that as to complete. It also writes a \0 at the
|
||||
* position of the space (if any). If nothing found, buf is returned.
|
||||
*/
|
||||
static char *ChatTabCompletionFindText(char *buf)
|
||||
{
|
||||
char *p = strrchr(buf, ' ');
|
||||
if (p == NULL) return buf;
|
||||
|
||||
*p = '\0';
|
||||
return p + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* See if we can auto-complete the current text of the user.
|
||||
*/
|
||||
void ChatTabCompletion()
|
||||
{
|
||||
static char _chat_tab_completion_buf[NETWORK_CHAT_LENGTH];
|
||||
assert(this->edit_str_size == lengthof(_chat_tab_completion_buf));
|
||||
|
||||
Textbuf *tb = &this->text;
|
||||
size_t len, tb_len;
|
||||
uint item;
|
||||
char *tb_buf, *pre_buf;
|
||||
const char *cur_name;
|
||||
bool second_scan = false;
|
||||
|
||||
item = 0;
|
||||
|
||||
/* Copy the buffer so we can modify it without damaging the real data */
|
||||
pre_buf = (_chat_tab_completion_active) ? strdup(_chat_tab_completion_buf) : strdup(tb->buf);
|
||||
|
||||
tb_buf = ChatTabCompletionFindText(pre_buf);
|
||||
tb_len = strlen(tb_buf);
|
||||
|
||||
while ((cur_name = ChatTabCompletionNextItem(&item)) != NULL) {
|
||||
item++;
|
||||
|
||||
if (_chat_tab_completion_active) {
|
||||
/* We are pressing TAB again on the same name, is there an other name
|
||||
* that starts with this? */
|
||||
if (!second_scan) {
|
||||
size_t offset;
|
||||
size_t length;
|
||||
|
||||
/* If we are completing at the begin of the line, skip the ': ' we added */
|
||||
if (tb_buf == pre_buf) {
|
||||
offset = 0;
|
||||
length = tb->length - 2;
|
||||
} else {
|
||||
/* Else, find the place we are completing at */
|
||||
offset = strlen(pre_buf) + 1;
|
||||
length = tb->length - offset;
|
||||
}
|
||||
|
||||
/* Compare if we have a match */
|
||||
if (strlen(cur_name) == length && strncmp(cur_name, tb->buf + offset, length) == 0) second_scan = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Now any match we make on _chat_tab_completion_buf after this, is perfect */
|
||||
}
|
||||
|
||||
len = strlen(cur_name);
|
||||
if (tb_len < len && strncasecmp(cur_name, tb_buf, tb_len) == 0) {
|
||||
/* Save the data it was before completion */
|
||||
if (!second_scan) snprintf(_chat_tab_completion_buf, lengthof(_chat_tab_completion_buf), "%s", tb->buf);
|
||||
_chat_tab_completion_active = true;
|
||||
|
||||
/* Change to the found name. Add ': ' if we are at the start of the line (pretty) */
|
||||
if (pre_buf == tb_buf) {
|
||||
snprintf(tb->buf, this->edit_str_size, "%s: ", cur_name);
|
||||
} else {
|
||||
snprintf(tb->buf, this->edit_str_size, "%s %s", pre_buf, cur_name);
|
||||
}
|
||||
|
||||
/* Update the textbuffer */
|
||||
UpdateTextBufferSize(&this->text);
|
||||
|
||||
this->SetDirty();
|
||||
free(pre_buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (second_scan) {
|
||||
/* We walked all posibilities, and the user presses tab again.. revert to original text */
|
||||
strcpy(tb->buf, _chat_tab_completion_buf);
|
||||
_chat_tab_completion_active = false;
|
||||
|
||||
/* Update the textbuffer */
|
||||
UpdateTextBufferSize(&this->text);
|
||||
|
||||
this->SetDirty();
|
||||
}
|
||||
free(pre_buf);
|
||||
}
|
||||
|
||||
virtual void OnPaint()
|
||||
{
|
||||
static const StringID chat_captions[] = {
|
||||
STR_NETWORK_CHAT_ALL_CAPTION,
|
||||
STR_NETWORK_CHAT_COMPANY_CAPTION,
|
||||
STR_NETWORK_CHAT_CLIENT_CAPTION
|
||||
};
|
||||
|
||||
this->DrawWidgets();
|
||||
|
||||
assert((uint)this->dtype < lengthof(chat_captions));
|
||||
DrawStringRightAligned(this->widget[2].left - 2, this->widget[2].top + 1, chat_captions[this->dtype], TC_BLACK);
|
||||
this->DrawEditBox(2);
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget)
|
||||
{
|
||||
switch (widget) {
|
||||
case 2:
|
||||
ShowOnScreenKeyboard(this, 2, 0, 3);
|
||||
break;
|
||||
|
||||
case 3: /* Send */
|
||||
SendChat(this->text.buf, this->dtype, this->dest);
|
||||
/* FALLTHROUGH */
|
||||
case 0: /* Cancel */ delete this; break;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnMouseLoop()
|
||||
{
|
||||
this->HandleEditBox(2);
|
||||
}
|
||||
|
||||
virtual EventState OnKeyPress(uint16 key, uint16 keycode)
|
||||
{
|
||||
EventState state = ES_NOT_HANDLED;
|
||||
if (keycode == WKC_TAB) {
|
||||
ChatTabCompletion();
|
||||
} else {
|
||||
_chat_tab_completion_active = false;
|
||||
switch (this->HandleEditBoxKey(2, key, keycode, state)) {
|
||||
case 1: /* Return */
|
||||
SendChat(this->text.buf, this->dtype, this->dest);
|
||||
/* FALLTHROUGH */
|
||||
case 2: /* Escape */ delete this; break;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
static const Widget _chat_window_widgets[] = {
|
||||
{ WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
|
||||
{ WWT_PANEL, RESIZE_RIGHT, COLOUR_GREY, 11, 319, 0, 13, 0x0, STR_NULL}, // background
|
||||
{ WWT_EDITBOX, RESIZE_RIGHT, COLOUR_GREY, 75, 257, 1, 12, STR_NETWORK_CHAT_OSKTITLE, STR_NULL}, // text box
|
||||
{ WWT_PUSHTXTBTN, RESIZE_LR, COLOUR_GREY, 258, 319, 1, 12, STR_NETWORK_SEND, STR_NULL}, // send button
|
||||
{ WIDGETS_END},
|
||||
};
|
||||
|
||||
static const WindowDesc _chat_window_desc = {
|
||||
WDP_CENTER, -26, 320, 14, 640, 14, // x, y, width, height
|
||||
WC_SEND_NETWORK_MSG, WC_NONE,
|
||||
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET,
|
||||
_chat_window_widgets,
|
||||
};
|
||||
|
||||
void ShowNetworkChatQueryWindow(DestType type, int dest)
|
||||
{
|
||||
DeleteWindowById(WC_SEND_NETWORK_MSG, 0);
|
||||
new NetworkChatWindow (&_chat_window_desc, type, dest);
|
||||
}
|
||||
|
||||
/** Enum for NetworkGameWindow, referring to _network_game_window_widgets */
|
||||
enum NetworkCompanyPasswordWindowWidgets {
|
||||
|
226
src/texteff.cpp
226
src/texteff.cpp
@ -6,27 +6,18 @@
|
||||
#include "openttd.h"
|
||||
#include "landscape.h"
|
||||
#include "gfx_func.h"
|
||||
#include "console_func.h"
|
||||
#include "variables.h"
|
||||
#include "blitter/factory.hpp"
|
||||
#include "texteff.hpp"
|
||||
#include "video/video_driver.hpp"
|
||||
#include "core/bitmath_func.hpp"
|
||||
#include "transparency.h"
|
||||
#include "strings_func.h"
|
||||
#include "core/alloc_func.hpp"
|
||||
#include "date_func.h"
|
||||
#include "functions.h"
|
||||
#include "viewport_func.h"
|
||||
#include "settings_type.h"
|
||||
|
||||
#include "table/sprites.h"
|
||||
|
||||
#include <stdarg.h> /* va_list */
|
||||
|
||||
enum {
|
||||
MAX_TEXTMESSAGE_LENGTH = 200,
|
||||
INIT_NUM_TEXT_MESSAGES = 20,
|
||||
MAX_CHAT_MESSAGES = 10,
|
||||
INIT_NUM_TEXT_EFFECTS = 20,
|
||||
};
|
||||
|
||||
struct TextEffect {
|
||||
@ -41,220 +32,9 @@ struct TextEffect {
|
||||
TextEffectMode mode;
|
||||
};
|
||||
|
||||
|
||||
struct ChatMessage {
|
||||
char message[MAX_TEXTMESSAGE_LENGTH];
|
||||
uint16 color;
|
||||
Date end_date;
|
||||
};
|
||||
|
||||
/* used for text effects */
|
||||
static TextEffect *_text_effect_list = NULL;
|
||||
static uint16 _num_text_effects = INIT_NUM_TEXT_MESSAGES;
|
||||
|
||||
/* used for chat window */
|
||||
static ChatMessage _chatmsg_list[MAX_CHAT_MESSAGES];
|
||||
static bool _chatmessage_dirty = false;
|
||||
static bool _chatmessage_visible = false;
|
||||
|
||||
/* The chatbox grows from the bottom so the coordinates are pixels from
|
||||
* the left and pixels from the bottom. The height is the maximum height */
|
||||
static const PointDimension _chatmsg_box = {10, 30, 500, 150};
|
||||
static uint8 _chatmessage_backup[150 * 500 * 6]; // (height * width)
|
||||
|
||||
static inline uint GetChatMessageCount()
|
||||
{
|
||||
uint i;
|
||||
|
||||
for (i = 0; i < MAX_CHAT_MESSAGES; i++) {
|
||||
if (_chatmsg_list[i].message[0] == '\0') break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Add a text message to the 'chat window' to be shown
|
||||
* @param color The colour this message is to be shown in
|
||||
* @param duration The duration of the chat message in game-days
|
||||
* @param message message itself in printf() style */
|
||||
void CDECL AddChatMessage(uint16 color, uint8 duration, const char *message, ...)
|
||||
{
|
||||
char buf[MAX_TEXTMESSAGE_LENGTH];
|
||||
const char *bufp;
|
||||
va_list va;
|
||||
uint msg_count;
|
||||
uint16 lines;
|
||||
|
||||
va_start(va, message);
|
||||
vsnprintf(buf, lengthof(buf), message, va);
|
||||
va_end(va);
|
||||
|
||||
|
||||
Utf8TrimString(buf, MAX_TEXTMESSAGE_LENGTH);
|
||||
|
||||
/* Force linebreaks for strings that are too long */
|
||||
lines = GB(FormatStringLinebreaks(buf, _chatmsg_box.width - 8), 0, 16) + 1;
|
||||
if (lines >= MAX_CHAT_MESSAGES) return;
|
||||
|
||||
msg_count = GetChatMessageCount();
|
||||
/* We want to add more chat messages than there is free space for, remove 'old' */
|
||||
if (lines > MAX_CHAT_MESSAGES - msg_count) {
|
||||
int i = lines - (MAX_CHAT_MESSAGES - msg_count);
|
||||
memmove(&_chatmsg_list[0], &_chatmsg_list[i], sizeof(_chatmsg_list[0]) * (msg_count - i));
|
||||
msg_count = MAX_CHAT_MESSAGES - lines;
|
||||
}
|
||||
|
||||
for (bufp = buf; lines != 0; lines--) {
|
||||
ChatMessage *cmsg = &_chatmsg_list[msg_count++];
|
||||
ttd_strlcpy(cmsg->message, bufp, sizeof(cmsg->message));
|
||||
|
||||
/* The default colour for a message is player colour. Replace this with
|
||||
* white for any additional lines */
|
||||
cmsg->color = (bufp == buf && color & IS_PALETTE_COLOR) ? color : (0x1D - 15) | IS_PALETTE_COLOR;
|
||||
cmsg->end_date = _date + duration;
|
||||
|
||||
bufp += strlen(bufp) + 1; // jump to 'next line' in the formatted string
|
||||
}
|
||||
|
||||
_chatmessage_dirty = true;
|
||||
}
|
||||
|
||||
void InitChatMessage()
|
||||
{
|
||||
uint i;
|
||||
|
||||
for (i = 0; i < MAX_CHAT_MESSAGES; i++) {
|
||||
_chatmsg_list[i].message[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/** Hide the chatbox */
|
||||
void UndrawChatMessage()
|
||||
{
|
||||
if (_chatmessage_visible) {
|
||||
Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
|
||||
/* Sometimes we also need to hide the cursor
|
||||
* This is because both textmessage and the cursor take a shot of the
|
||||
* screen before drawing.
|
||||
* Now the textmessage takes his shot and paints his data before the cursor
|
||||
* does, so in the shot of the cursor is the screen-data of the textmessage
|
||||
* included when the cursor hangs somewhere over the textmessage. To
|
||||
* avoid wrong repaints, we undraw the cursor in that case, and everything
|
||||
* looks nicely ;)
|
||||
* (and now hope this story above makes sense to you ;))
|
||||
*/
|
||||
|
||||
if (_cursor.visible) {
|
||||
if (_cursor.draw_pos.x + _cursor.draw_size.x >= _chatmsg_box.x &&
|
||||
_cursor.draw_pos.x <= _chatmsg_box.x + _chatmsg_box.width &&
|
||||
_cursor.draw_pos.y + _cursor.draw_size.y >= _screen.height - _chatmsg_box.y - _chatmsg_box.height &&
|
||||
_cursor.draw_pos.y <= _screen.height - _chatmsg_box.y) {
|
||||
UndrawMouseCursor();
|
||||
}
|
||||
}
|
||||
|
||||
int x = _chatmsg_box.x;
|
||||
int y = _screen.height - _chatmsg_box.y - _chatmsg_box.height;
|
||||
int width = _chatmsg_box.width;
|
||||
int height = _chatmsg_box.height;
|
||||
if (y < 0) {
|
||||
height = max(height + y, min(_chatmsg_box.height, _screen.height));
|
||||
y = 0;
|
||||
}
|
||||
if (x + width >= _screen.width) {
|
||||
width = _screen.width - x;
|
||||
}
|
||||
if (width <= 0 || height <= 0) return;
|
||||
|
||||
_chatmessage_visible = false;
|
||||
/* Put our 'shot' back to the screen */
|
||||
blitter->CopyFromBuffer(blitter->MoveTo(_screen.dst_ptr, x, y), _chatmessage_backup, width, height);
|
||||
/* And make sure it is updated next time */
|
||||
_video_driver->MakeDirty(x, y, width, height);
|
||||
|
||||
_chatmessage_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Check if a message is expired every day */
|
||||
void ChatMessageDailyLoop()
|
||||
{
|
||||
uint i;
|
||||
|
||||
for (i = 0; i < MAX_CHAT_MESSAGES; i++) {
|
||||
ChatMessage *cmsg = &_chatmsg_list[i];
|
||||
if (cmsg->message[0] == '\0') continue;
|
||||
|
||||
/* Message has expired, remove from the list */
|
||||
if (cmsg->end_date < _date) {
|
||||
/* Move the remaining messages over the current message */
|
||||
if (i != MAX_CHAT_MESSAGES - 1) memmove(cmsg, cmsg + 1, sizeof(*cmsg) * (MAX_CHAT_MESSAGES - i - 1));
|
||||
|
||||
/* Mark the last item as empty */
|
||||
_chatmsg_list[MAX_CHAT_MESSAGES - 1].message[0] = '\0';
|
||||
_chatmessage_dirty = true;
|
||||
|
||||
/* Go one item back, because we moved the array 1 to the left */
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Draw the chat message-box */
|
||||
void DrawChatMessage()
|
||||
{
|
||||
Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
|
||||
if (!_chatmessage_dirty) return;
|
||||
|
||||
/* First undraw if needed */
|
||||
UndrawChatMessage();
|
||||
|
||||
if (_iconsole_mode == ICONSOLE_FULL) return;
|
||||
|
||||
/* Check if we have anything to draw at all */
|
||||
uint count = GetChatMessageCount();
|
||||
if (count == 0) return;
|
||||
|
||||
int x = _chatmsg_box.x;
|
||||
int y = _screen.height - _chatmsg_box.y - _chatmsg_box.height;
|
||||
int width = _chatmsg_box.width;
|
||||
int height = _chatmsg_box.height;
|
||||
if (y < 0) {
|
||||
height = max(height + y, min(_chatmsg_box.height, _screen.height));
|
||||
y = 0;
|
||||
}
|
||||
if (x + width >= _screen.width) {
|
||||
width = _screen.width - x;
|
||||
}
|
||||
if (width <= 0 || height <= 0) return;
|
||||
|
||||
assert(blitter->BufferSize(width, height) < (int)sizeof(_chatmessage_backup));
|
||||
|
||||
/* Make a copy of the screen as it is before painting (for undraw) */
|
||||
blitter->CopyToBuffer(blitter->MoveTo(_screen.dst_ptr, x, y), _chatmessage_backup, width, height);
|
||||
|
||||
_cur_dpi = &_screen; // switch to _screen painting
|
||||
|
||||
/* Paint a half-transparent box behind the chat messages */
|
||||
GfxFillRect(
|
||||
_chatmsg_box.x,
|
||||
_screen.height - _chatmsg_box.y - count * 13 - 2,
|
||||
_chatmsg_box.x + _chatmsg_box.width - 1,
|
||||
_screen.height - _chatmsg_box.y - 2,
|
||||
PALETTE_TO_TRANSPARENT, FILLRECT_RECOLOR // black, but with some alpha for background
|
||||
);
|
||||
|
||||
/* Paint the chat messages starting with the lowest at the bottom */
|
||||
for (uint y = 13; count-- != 0; y += 13) {
|
||||
DoDrawString(_chatmsg_list[count].message, _chatmsg_box.x + 3, _screen.height - _chatmsg_box.y - y + 1, _chatmsg_list[count].color);
|
||||
}
|
||||
|
||||
/* Make sure the data is updated next flush */
|
||||
_video_driver->MakeDirty(x, y, width, height);
|
||||
|
||||
_chatmessage_visible = true;
|
||||
_chatmessage_dirty = false;
|
||||
}
|
||||
static uint16 _num_text_effects = INIT_NUM_TEXT_EFFECTS;
|
||||
|
||||
/* Text Effects */
|
||||
/**
|
||||
|
@ -26,11 +26,6 @@ void DrawTextEffects(DrawPixelInfo *dpi);
|
||||
void UpdateTextEffect(TextEffectID effect_id, StringID msg);
|
||||
void RemoveTextEffect(TextEffectID effect_id);
|
||||
|
||||
void InitChatMessage();
|
||||
void DrawChatMessage();
|
||||
void CDECL AddChatMessage(uint16 color, uint8 duration, const char *message, ...);
|
||||
void UndrawChatMessage();
|
||||
|
||||
/* misc_gui.cpp */
|
||||
TextEffectID ShowFillingPercent(int x, int y, int z, uint8 percent, StringID color);
|
||||
void UpdateFillingPercent(TextEffectID te_id, uint8 percent, StringID color);
|
||||
|
@ -694,7 +694,7 @@ void QZ_GameLoop()
|
||||
st += GetTick() - st0;
|
||||
#endif
|
||||
_screen.dst_ptr = _cocoa_subdriver->GetPixelBuffer();
|
||||
DrawChatMessage();
|
||||
NetworkDrawChatMessage();
|
||||
DrawMouseCursor();
|
||||
_cocoa_subdriver->Draw();
|
||||
}
|
||||
|
@ -518,7 +518,7 @@ void VideoDriver_SDL::MainLoop()
|
||||
} else {
|
||||
SDL_CALL SDL_Delay(1);
|
||||
_screen.dst_ptr = _sdl_screen->pixels;
|
||||
DrawChatMessage();
|
||||
NetworkDrawChatMessage();
|
||||
DrawMouseCursor();
|
||||
DrawSurfaceToScreen();
|
||||
}
|
||||
|
@ -890,7 +890,7 @@ void VideoDriver_Win32::MainLoop()
|
||||
GdiFlush();
|
||||
#endif
|
||||
_screen.dst_ptr = _wnd.buffer_bits;
|
||||
DrawChatMessage();
|
||||
NetworkDrawChatMessage();
|
||||
DrawMouseCursor();
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "cheat_func.h"
|
||||
#include "window_func.h"
|
||||
#include "tilehighlight_func.h"
|
||||
#include "network/network.h"
|
||||
|
||||
#include "table/sprites.h"
|
||||
|
||||
@ -1984,7 +1985,7 @@ void UpdateWindows()
|
||||
FOR_ALL_WINDOWS(wz) {
|
||||
if ((*wz)->viewport != NULL) UpdateViewportPosition(*wz);
|
||||
}
|
||||
DrawChatMessage();
|
||||
NetworkDrawChatMessage();
|
||||
/* Redraw mouse cursor in case it was hidden */
|
||||
DrawMouseCursor();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user