texteff.c
changeset 543 e3b43338096b
parent 534 17ab2f22ff74
child 649 5b5f9ae5115f
--- a/texteff.c	Sat Dec 04 15:02:45 2004 +0000
+++ b/texteff.c	Sat Dec 04 17:54:56 2004 +0000
@@ -3,6 +3,9 @@
 #include "gfx.h"
 #include "viewport.h"
 #include "saveload.h"
+#include "hal.h"
+#include "console.h"
+#include <stdarg.h> /* va_list */
 
 typedef struct TextEffect {
 	StringID string_id;
@@ -12,9 +15,187 @@
 	uint32 params_2;
 } TextEffect;
 
+#define MAX_TEXTMESSAGE_LENGTH 250
+
+typedef struct TextMessage {
+	char message[MAX_TEXTMESSAGE_LENGTH];
+	uint16 color;
+	uint16 end_date;
+} TextMessage;
+
+#define MAX_CHAT_MESSAGES 10
 static TextEffect _text_effect_list[30];
+static TextMessage _text_message_list[MAX_CHAT_MESSAGES];
 TileIndex _animated_tile_list[256];
 
+
+int _textmessage_width = 0;
+bool _textmessage_dirty = true;
+bool _textmessage_visible = false;
+
+const int _textmessage_box_left = 10; // Pixels from left
+const int _textmessage_box_y = 150;  // Height of box
+const int _textmessage_box_bottom = 20; // Pixels from bottom
+const int _textmessage_box_max_width = 400; // Max width of box
+
+static byte _textmessage_backup[150*400]; // (y * max_width)
+
+extern void memcpy_pitch(void *d, void *s, int w, int h, int spitch, int dpitch);
+
+// Duration is in game-days
+void AddTextMessage(uint16 color, uint8 duration, const char *message, ...)
+{
+	int i;
+	char buf[1024];
+	char buf2[MAX_TEXTMESSAGE_LENGTH];
+	va_list va;
+	int length;
+
+	va_start(va, message);
+	vsprintf(buf, message, va);
+	va_end(va);
+
+	if ((color & 0xFF) == 0xC9) color = 0x1CA;
+
+	length = MAX_TEXTMESSAGE_LENGTH;
+	snprintf(buf2, length, "%s", buf);
+	while (GetStringWidth(buf2) > _textmessage_width - 9) {
+		snprintf(buf2, --length, "%s", buf);
+	}
+
+	for (i = 0; i < MAX_CHAT_MESSAGES; i++) {
+		if (_text_message_list[i].message[0] == '\0') {
+			// Empty spot
+			snprintf(_text_message_list[i].message, MAX_TEXTMESSAGE_LENGTH, "%s", buf2);
+			_text_message_list[i].color = color;
+			_text_message_list[i].end_date = _date + duration;
+
+			_textmessage_dirty = true;
+			return;
+		}
+	}
+
+	// We did not found a free spot, trash the first one, and add to the end
+	memmove(&_text_message_list[0], &_text_message_list[1], sizeof(TextMessage) * (MAX_CHAT_MESSAGES - 1));
+	snprintf(_text_message_list[MAX_CHAT_MESSAGES - 1].message, MAX_TEXTMESSAGE_LENGTH, "%s", buf2);
+	_text_message_list[MAX_CHAT_MESSAGES - 1].color = color;
+	_text_message_list[i].end_date = _date + duration;
+
+	_textmessage_dirty = true;
+}
+
+void InitTextMessage()
+{
+	int i;
+	for (i = 0; i < MAX_CHAT_MESSAGES; i++) {
+		_text_message_list[i].message[0] = '\0';
+	}
+
+	_textmessage_width = _textmessage_box_max_width;
+}
+
+// Hide the textbox
+void UndrawTextMessage()
+{
+	if (_textmessage_visible) {
+		// 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 >= _textmessage_box_left &&
+				_cursor.draw_pos.x <= _textmessage_box_left + _textmessage_width &&
+				_cursor.draw_pos.y + _cursor.draw_size.y >= _screen.height - _textmessage_box_bottom - _textmessage_box_y &&
+				_cursor.draw_pos.y <= _screen.height - _textmessage_box_bottom) {
+				UndrawMouseCursor();
+			}
+		}
+
+		_textmessage_visible = false;
+		// Put our 'shot' back to the screen
+		memcpy_pitch(
+			_screen.dst_ptr + _textmessage_box_left + (_screen.height-_textmessage_box_bottom-_textmessage_box_y) * _screen.pitch,
+			_textmessage_backup,
+			_textmessage_width, _textmessage_box_y, _textmessage_width, _screen.pitch);
+
+		// And make sure it is updated next time
+		_video_driver->make_dirty(_textmessage_box_left, _screen.height-_textmessage_box_bottom-_textmessage_box_y, _textmessage_width, _textmessage_box_y);
+
+		_textmessage_dirty = true;
+	}
+}
+
+// Check if a message is expired every day
+void TextMessageDailyLoop()
+{
+	int i = 0;
+	while (i < MAX_CHAT_MESSAGES) {
+		if (_text_message_list[i].message[0] == '\0') break;
+		if (_date > _text_message_list[i].end_date) {
+			memmove(&_text_message_list[i], &_text_message_list[i+1], sizeof(TextMessage) * ((MAX_CHAT_MESSAGES - 1) - i));
+			_text_message_list[MAX_CHAT_MESSAGES - 1].message[0] = '\0';
+			i--;
+			_textmessage_dirty = true;
+		}
+		i++;
+	}
+}
+
+// Draw the textmessage-box
+void DrawTextMessage()
+{
+	int i, j;
+	bool has_message;
+
+	if (!_textmessage_dirty)
+		return;
+
+	// First undraw if needed
+	UndrawTextMessage();
+
+	if (_iconsole_mode == ICONSOLE_FULL)
+		return;
+
+	has_message = false;
+	for ( i = 0; i < MAX_CHAT_MESSAGES; i++) {
+		if (_text_message_list[i].message[0] == '\0') break;
+		has_message = true;
+	}
+	if (!has_message) return;
+
+	// Make a copy of the screen as it is before painting (for undraw)
+	memcpy_pitch(
+		_textmessage_backup,
+		_screen.dst_ptr + _textmessage_box_left + (_screen.height-_textmessage_box_bottom-_textmessage_box_y) * _screen.pitch,
+		_textmessage_width, _textmessage_box_y, _screen.pitch, _textmessage_width);
+
+	// Switch to _screen painting
+	_cur_dpi = &_screen;
+
+	j = 0;
+	// Paint the messages
+	for (i = MAX_CHAT_MESSAGES - 1; i >= 0; i--) {
+		if (_text_message_list[i].message[0] == '\0') continue;
+		j++;
+		GfxFillRect(_textmessage_box_left, _screen.height-_textmessage_box_bottom-j*13-2, _textmessage_box_left+_textmessage_width - 1, _screen.height-_textmessage_box_bottom-j*13+10, /* black, but with some alpha */ 0x4322);
+
+		DoDrawString(_text_message_list[i].message, _textmessage_box_left + 2, _screen.height - _textmessage_box_bottom - j * 13 - 1, 0x10);
+		DoDrawString(_text_message_list[i].message, _textmessage_box_left + 3, _screen.height - _textmessage_box_bottom - j * 13, _text_message_list[i].color);
+	}
+
+	// Make sure the data is updated next flush
+	_video_driver->make_dirty(_textmessage_box_left, _screen.height-_textmessage_box_bottom-_textmessage_box_y, _textmessage_width, _textmessage_box_y);
+
+	_textmessage_visible = true;
+	_textmessage_dirty = false;
+}
+
 static void MarkTextEffectAreaDirty(TextEffect *te)
 {
 	MarkAllViewportsDirty(