1 /* NetHack may be freely redistributed.  See license for details. */
2 
3 #include "vulture_sdl.h" /* XXX this must be the first include,
4                              no idea why but it won't compile otherwise */
5 
6 extern "C" {
7 	#include "hack.h"
8 }
9 
10 #include "vulture_main.h"
11 #include "vulture_win.h"
12 #include "vulture_txt.h"
13 #include "vulture_gra.h"
14 #include "vulture_opt.h"
15 #include "vulture_mou.h"
16 
17 #include "messagewin.h"
18 #include "levelwin.h"
19 
20 
21 messagewin *msgwin;
22 static Uint32 message_colors[V_MAX_MESSAGE_COLORS];
23 
24 
messagewin(window * p)25 messagewin::messagewin(window *p) : window(p)
26 {
27 	int i;
28 	Uint32 color;
29 
30 	v_type = V_WINTYPE_CUSTOM;
31 
32 	bg_img = SDL_CreateRGBSurface(SDL_SWSURFACE, 40, 20, 32,
33 								vulture_px_format->Rmask,
34 								vulture_px_format->Gmask,
35 								vulture_px_format->Bmask, 0);
36 	SDL_FillRect(bg_img, NULL, CLR32_BLACK);
37 	SDL_SetAlpha(bg_img, SDL_SRCALPHA, 128);
38 
39 	/* init message ring buffer */
40 	memset(message_ages, 0, V_MESSAGEBUF_SIZE * sizeof(int));
41 	message_top = -1;
42 	message_cur = -1;
43 
44 	msgwin = this;
45 
46 	/* Set message shading */
47 	for (i = 0; i < V_MAX_MESSAGE_COLORS; i++) {
48 		color = 255 - (i * 11);
49 		message_colors[i] = SDL_MapRGB(vulture_px_format, color, color, color);
50 	}
51 }
52 
53 
54 
~messagewin(void)55 messagewin::~messagewin(void)
56 {
57 	SDL_FreeSurface(bg_img);
58 }
59 
60 
61 
draw()62 bool messagewin::draw()
63 {
64 	int age, textlen, num_messages;
65 	int pos_x, pos_y, i;
66   std::string message;
67 	int refresh_x, refresh_y, refresh_h, refresh_w;
68 	int time_cur = moves;
69 
70 	if (getshown() != 0)
71 		/* set time_cur to the age of the first shown message */
72 		get_message(0, &time_cur);
73 
74 	refresh_x = refresh_y = 99999;
75 	refresh_h = refresh_w = 0;
76 
77 	/* repaint background and free it */
78 	if (background) {
79 		vulture_put_img(abs_x, abs_y, background);
80 		SDL_FreeSurface(background);
81 		background = NULL;
82 
83 		/* we need these values, so that we can refresh the larger
84 		* even if the window shrinks during the redraw */
85 		refresh_x = abs_x;
86 		refresh_y = abs_y;
87 		refresh_w = w;
88 		refresh_h = h;
89 	}
90 
91 	num_messages = 0;
92 	h = 0;
93 	w = 0;
94 
95 	/* calculate height & width of new message area */
96 	while(!(message = get_message(num_messages, &age)).empty() &&
97 		(time_cur-age) < V_MAX_MESSAGE_COLORS && num_messages < vulture_opts.messagelines)
98 	{
99 		h += (vulture_get_lineheight(V_FONT_MESSAGE) + 1);
100 		textlen = vulture_text_length(V_FONT_MESSAGE, message);
101 		w = (w < textlen) ? textlen : w;
102 		num_messages++;
103 	}
104 
105 	/* add a bit of padding around the text */
106 	h += 2;
107 	w += 4;
108 
109 	x = (parent->w - w) / 2;
110 	abs_x = parent->abs_x + x;
111 	abs_y = parent->abs_y;
112 
113 	/* save new background */
114 	background = vulture_get_img(abs_x, abs_y,
115 						abs_x + w-1, abs_y + h-1);
116 
117 
118 	/* shade the message area */
119 	vulture_set_draw_region(abs_x, abs_y,
120 						abs_x + w-1, abs_y + h-1);
121 	pos_y = abs_y;
122 	while (pos_y <= abs_y + h) {
123 		pos_x = abs_x;
124 
125 		while (pos_x <= abs_x+w) {
126 			vulture_put_img(pos_x, pos_y, bg_img);
127 			pos_x += bg_img->w;
128 		}
129 		pos_y += bg_img->h;
130 	}
131 	vulture_set_draw_region(0, 0, vulture_screen->w-1, vulture_screen->h-1);
132 
133 
134 	/* draw the messages */
135 	for (i = 0; i < num_messages; i++) {
136 		message = get_message(num_messages - i - 1, &age);
137 
138 		pos_x = abs_x + (w - vulture_text_length(V_FONT_MESSAGE, message)) / 2;
139 		pos_y = abs_y + i * (vulture_get_lineheight(V_FONT_MESSAGE) + 1);
140 		vulture_put_text(V_FONT_MESSAGE, message, vulture_screen,
141 						pos_x, pos_y, message_colors[time_cur-age]);
142 	}
143 
144 	refresh_w = (refresh_w > w) ? refresh_w : w;
145 	refresh_h = (refresh_h > h) ? refresh_h : h;
146 
147 	if (refresh_x > abs_x)
148 	{
149 		refresh_w += refresh_x - abs_x;
150 		refresh_x = abs_x;
151 	}
152 	refresh_y = (refresh_y < abs_y) ? refresh_y : abs_y;
153 
154 	vulture_invalidate_region(refresh_x, refresh_y, refresh_w, refresh_h);
155 
156 	return false;
157 }
158 
159 
handle_mousemotion_event(window * target,void * result,int xrel,int yrel,int state)160 eventresult messagewin::handle_mousemotion_event(window* target, void* result,
161                                             int xrel, int yrel, int state)
162 {
163 	point mouse = vulture_get_mouse_pos();
164 	window *new_target = levwin->get_window_from_point(mouse);
165 
166 	return levwin->handle_mousemotion_event(new_target, result, xrel, yrel, state);
167 }
168 
169 
handle_mousebuttonup_event(window * target,void * result,int mouse_x,int mouse_y,int button,int state)170 eventresult messagewin::handle_mousebuttonup_event(window* target, void* result,
171                                             int mouse_x, int mouse_y, int button, int state)
172 {
173 	point mouse = vulture_get_mouse_pos();
174 	window *new_target = levwin->get_window_from_point(mouse);
175 
176 	return levwin->handle_mousebuttonup_event(new_target, result, mouse_x, mouse_y, button, state);
177 }
178 
179 
add_message(std::string str)180 void messagewin::add_message(std::string str)
181 {
182 	message_cur = message_top = (message_top + 1) % V_MESSAGEBUF_SIZE;
183 	message_buf[message_top] = str;
184 	message_ages[message_top] = moves;
185 }
186 
187 
setshown(int first)188 void messagewin::setshown(int first)
189 {
190 	message_cur = (message_top - first + V_MESSAGEBUF_SIZE) % V_MESSAGEBUF_SIZE;
191 }
192 
193 
getshown()194 int messagewin::getshown()
195 {
196 	return (message_top - message_cur + V_MESSAGEBUF_SIZE) % V_MESSAGEBUF_SIZE;
197 }
198 
199 
200 /* retrieve a message from the message buffer, offset messages before the current one */
get_message(int offset,int * age)201 std::string messagewin::get_message(int offset, int *age)
202 {
203 	if (offset < V_MESSAGEBUF_SIZE)
204 	{
205     int msg_id = (message_cur - offset + V_MESSAGEBUF_SIZE) % V_MESSAGEBUF_SIZE;
206 
207     if (message_ages[msg_id])
208     {
209       *age = message_ages[msg_id];
210       return message_buf[msg_id];
211     }
212 	}
213 
214 	*age = 0;
215 	return "";
216 }
217 
218 
view_all(void)219 void messagewin::view_all(void)
220 {
221 	int offset, time, winid;
222   std::string message;
223 	char menuline[256];
224 
225 	winid = vulture_create_nhwindow(NHW_MENU);
226 
227 	offset = -getshown();
228 	while ( !(message = get_message(offset, &time)).empty() )
229 	{
230 		sprintf(menuline, "T:%d %s", time, message.c_str());
231 		vulture_putstr(winid, ATR_NONE, menuline);
232 		offset++;
233 	}
234 
235 	/* Display the messages */
236 	vulture_display_nhwindow(winid, TRUE);
237 
238 	/* Clean up */
239 	vulture_destroy_nhwindow(winid);
240 }
241 
242