1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "ultima/nuvie/core/nuvie_defs.h"
24 #include "ultima/nuvie/conf/configuration.h"
25 #include "ultima/nuvie/misc/u6_misc.h"
26 #include "ultima/nuvie/misc/u6_llist.h"
27 #include "ultima/nuvie/actors/actor.h"
28 #include "ultima/nuvie/actors/actor_manager.h"
29 #include "ultima/nuvie/views/view_manager.h"
30 #include "ultima/nuvie/gui/widgets/map_window.h"
31 #include "ultima/nuvie/core/events.h"
32 #include "ultima/nuvie/gui/widgets/msg_scroll.h"
33 #include "ultima/nuvie/gui/widgets/msg_scroll_new_ui.h"
34 #include "ultima/nuvie/core/effect.h" /* for initial fade-in */
35 #include "ultima/nuvie/core/tile_manager.h"
36 #include "ultima/nuvie/sound/sound_manager.h"
37 #include "ultima/nuvie/gui/gui.h"
38 #include "ultima/nuvie/core/game_clock.h"
39 #include "ultima/nuvie/screen/game_palette.h"
40 #include "ultima/nuvie/core/party.h"
41 #include "ultima/nuvie/core/weather.h"
42 #include "ultima/nuvie/script/script.h"
43 #include "ultima/nuvie/core/u6_objects.h"
44 #include "ultima/nuvie/gui/widgets/command_bar.h"
45 #include "ultima/nuvie/views/actor_view.h"
46 #include "ultima/nuvie/views/inventory_view.h"
47 #include "ultima/nuvie/gui/widgets/background.h"
48 #include "ultima/nuvie/keybinding/keys.h"
49 
50 namespace Ultima {
51 namespace Nuvie {
52 
53 #define TMP_MAP_BORDER 3
54 
55 #define WRAP_VIEWP(p,p1,s) ((p1-p) < 0 ? (p1-p) + s : p1-p)
56 
57 // This should make the mouse-cursor hovering identical to that in U6.
58 static const uint8 movement_array[9 * 9] = {
59 	9, 9, 2, 2, 2, 2, 2, 3, 3,
60 	9, 9, 9, 2, 2, 2, 3, 3, 3,
61 	8, 9, 9, 2, 2, 2, 3, 3, 4,
62 	8, 8, 8, 9, 2, 3, 4, 4, 4,
63 	8, 8, 8, 8, 1, 4, 4, 4, 4,
64 	8, 8, 8, 7, 6, 5, 4, 4, 4,
65 	8, 7, 7, 6, 6, 6, 5, 5, 4,
66 	7, 7, 7, 6, 6, 6, 5, 5, 5,
67 	7, 7, 6, 6, 6, 6, 6, 5, 5
68 };
69 
70 static const Tile grid_tile = {
71 	0,
72 	false,
73 	false,
74 	false,
75 	false,
76 	false,
77 	true,
78 	false,
79 	false,
80 	0,
81 	//uint8 qty;
82 	//uint8 flags;
83 
84 	0,
85 	0,
86 	0,
87 
88 	{
89 		54, 255, 255, 255, 58, 255, 255, 255, 58, 255, 255, 255, 58, 255, 255, 255,
90 		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
91 		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
92 		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
93 		58, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
94 		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
95 		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
96 		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
97 		58, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
98 		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
99 		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
100 		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
101 		58, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
102 		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
103 		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
104 		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
105 
106 	}
107 };
108 
MapWindow(Configuration * cfg,Map * m)109 MapWindow::MapWindow(Configuration *cfg, Map *m): GUI_Widget(NULL, 0, 0, 0, 0) {
110 
111 	config = cfg;
112 	config->value("config/GameType", game_type);
113 
114 	uint16 x_off = Game::get_game()->get_game_x_offset();
115 	uint16 y_off = Game::get_game()->get_game_y_offset();
116 
117 	GUI_Widget::Init(NULL, x_off, y_off, 0, 0);
118 
119 	map = m;
120 
121 	screen = NULL;
122 //surface = NULL;
123 	anim_manager = NULL;
124 
125 	cur_x = 0;
126 	mousecenter_x = 0;
127 	cur_y = 0;
128 	mousecenter_y = 0;
129 	cur_x_add = cur_y_add = 0;
130 	vel_x = vel_y = 0;
131 	last_boundary_fill_x = last_boundary_fill_y = 0;
132 
133 	cursor_x = 0;
134 	cursor_y = 0;
135 	show_cursor = false;
136 	show_use_cursor = false;
137 	show_grid = false;
138 	x_ray_view = X_RAY_OFF;
139 	freeze_blacking_location = false;
140 	enable_blacking = true;
141 
142 	new_thumbnail = false;
143 	thumbnail = NULL;
144 	overlay = NULL;
145 	overlay_level = MAP_OVERLAY_DEFAULT;
146 
147 	cur_level = 0;
148 	map_width = map->get_width(cur_level);
149 
150 	tmp_map_buf = NULL;
151 
152 	selected_obj = NULL;
153 	look_obj = NULL;
154 	look_actor = NULL;
155 	walking = false;
156 	looking = false;
157 	config->value(config_get_game_key(config) + "/map_tile_lighting", using_map_tile_lighting, game_type == NUVIE_GAME_MD ? false : true);
158 	config->value("config/input/enable_doubleclick", enable_doubleclick, true);
159 	config->value("config/input/look_on_left_click", look_on_left_click, true);
160 	set_use_left_clicks();
161 	config->value("config/input/walk_with_left_button", walk_with_left_button, true);
162 	set_walk_button_mask();
163 	config->value("config/cheats/min_brightness", min_brightness, 0);
164 	original_obj_loc = MapCoord(0, 0, 0);
165 
166 	roof_mode = Game::get_game()->is_roof_mode();
167 	roof_tiles = NULL;
168 
169 	draw_brit_lens_anim = false;
170 	draw_garg_lens_anim = false;
171 
172 	window_updated = true;
173 	roof_display = ROOF_DISPLAY_NORMAL;
174 
175 	lighting_update_required = true;
176 
177 	set_interface();
178 }
179 
~MapWindow()180 MapWindow::~MapWindow() {
181 	set_overlay(NULL); // free
182 	free(tmp_map_buf);
183 	delete anim_manager;
184 	if (roof_tiles) {
185 		SDL_FreeSurface(roof_tiles);
186 	}
187 }
188 
init(TileManager * tm,ObjManager * om,ActorManager * am)189 bool MapWindow::init(TileManager *tm, ObjManager *om, ActorManager *am) {
190 // int game_type; Why is this local, and retrieved again here? --SB-X
191 
192 	game = Game::get_game();
193 
194 	tile_manager = tm;
195 	obj_manager = om;
196 	actor_manager = am;
197 	uint16 map_w = 11, map_h = 11;
198 	border_width = game->get_background()->get_border_width();
199 	if (!game->is_orig_style()) {
200 		uint16 game_width = game->get_game_width();
201 		uint16 game_height = game->get_game_height();
202 
203 		if (game->is_original_plus_cutoff_map()) {
204 			map_center_xoff = 0;
205 			game_width -= border_width; // don't go over border
206 		} else if (game->is_original_plus_full_map()) {
207 			map_center_xoff = (border_width / 16) % 16;
208 		} else { // new style
209 			map_center_xoff = 0;
210 		}
211 		map_w = game_width / 16;
212 		map_h = game_height / 16;
213 		if (game_width % 16 != 0 || map_w % 2 == 0) { // not just the right size
214 			map_w += 1;
215 			if (map_w % 2 == 0) // need odd number of tiles to center properly
216 				map_w += 1;
217 		}
218 		if (game_height % 16 != 0 || map_h % 2 == 0) { // not just the right size
219 			map_h += 1;
220 			if (map_h % 2 == 0) // need odd number of tiles to center properly
221 				map_h += 1;
222 		}
223 		offset_x -= (map_w * 16 - game_width) / 2;
224 		offset_y -= (map_h * 16 - game_height) / 2;
225 	} else
226 		map_center_xoff = 0;
227 	anim_manager = new AnimManager(offset_x, offset_y);
228 
229 	cursor_tile = tile_manager->get_cursor_tile();
230 	use_tile = tile_manager->get_use_tile();
231 
232 	area.left = offset_x;
233 	area.top = offset_y;
234 
235 	set_windowSize(map_w, map_h);
236 
237 // hide the window until game is fully loaded and does fade-in
238 	get_overlay(); // this allocates `overlay`
239 	overlay_level = MAP_OVERLAY_ONTOP;
240 	assert(SDL_FillRect(overlay, NULL, game->get_palette()->get_bg_color()) == 0);
241 
242 	wizard_eye_info.eye_tile = tile_manager->get_tile(TILE_U6_WIZARD_EYE);
243 	wizard_eye_info.moves_left = 0;
244 	wizard_eye_info.caller = NULL;
245 
246 	if (roof_mode)
247 		loadRoofTiles();
248 
249 	return true;
250 }
251 
set_use_left_clicks()252 void MapWindow::set_use_left_clicks() {
253 	if (enable_doubleclick || look_on_left_click)
254 		set_accept_mouseclick(true, USE_BUTTON); // allow left clicks
255 	else
256 		set_accept_mouseclick(false, USE_BUTTON); // disallow left clicks
257 }
258 
set_windowSize(uint16 width,uint16 height)259 bool MapWindow::set_windowSize(uint16 width, uint16 height) {
260 	win_width = width;
261 	win_height = height;
262 	area.setWidth(win_width * 16);
263 	area.setHeight(win_height * 16);
264 
265 // We make the temp map +1 bigger on the top and left edges
266 // and +2 bigger on the bottom and right edges
267 
268 // The +1 is for the boundary fill function
269 
270 // The additional +1 on the right/bottom edges is needed
271 // to hide objects on boundarys when wall is in darkness
272 
273 	tmp_map_width = win_width + (TMP_MAP_BORDER * 2);// + 1;
274 	tmp_map_height = win_height + (TMP_MAP_BORDER * 2);// + 1;
275 
276 	tmp_map_buf = (uint16 *)nuvie_realloc(tmp_map_buf, tmp_map_width * tmp_map_height * sizeof(uint16));
277 	if (tmp_map_buf == NULL)
278 		return false;
279 
280 // if(surface != NULL)
281 //   delete surface;
282 // surface = new Surface;
283 
284 // if(surface->init(win_width*16,win_height*16) == false)
285 //   return false;
286 	if (game->is_orig_style()) {
287 		clip_rect.left = area.left + 8;
288 		clip_rect.setWidth((win_width - 1) * 16);
289 		clip_rect.setHeight((win_height - 1) * 16);
290 
291 		if (game_type == NUVIE_GAME_U6)
292 			clip_rect.top = area.top + 8;
293 		else {
294 			clip_rect.top = area.top + 16;
295 			clip_rect.bottom -= 16;
296 		}
297 	} else {
298 		clip_rect.left = game->get_game_x_offset();
299 		clip_rect.top = game->get_game_y_offset();
300 		if (game->is_original_plus_cutoff_map())
301 			clip_rect.setWidth(game->get_game_width() - border_width - 1);
302 		else
303 			clip_rect.setWidth(game->get_game_width());
304 		clip_rect.setHeight(game->get_game_height());
305 	}
306 	anim_manager->set_area(clip_rect);
307 
308 	reset_mousecenter();
309 
310 	updateBlacking();
311 
312 	return true;
313 }
314 
set_walk_button_mask()315 void MapWindow::set_walk_button_mask() {
316 	if (walk_with_left_button)
317 		walk_button_mask = (BUTTON_MASK(USE_BUTTON) | BUTTON_MASK(WALK_BUTTON));
318 	else
319 		walk_button_mask = BUTTON_MASK(WALK_BUTTON);
320 }
321 
set_show_cursor(bool state)322 void MapWindow::set_show_cursor(bool state) {
323 	ActorView *actor_view = game->get_view_manager()->get_actor_view();
324 	InventoryView *inventory_view = game->get_view_manager()->get_inventory_view();
325 	if (actor_view)
326 		actor_view->set_show_cursor(false);
327 	if (inventory_view)
328 		inventory_view->set_show_cursor(false);
329 
330 	show_cursor = state;
331 }
332 
set_show_use_cursor(bool state)333 void MapWindow::set_show_use_cursor(bool state) {
334 	ActorView *actor_view = game->get_view_manager()->get_actor_view();
335 	InventoryView *inventory_view = game->get_view_manager()->get_inventory_view();
336 	if (actor_view)
337 		actor_view->set_show_cursor(false);
338 	if (inventory_view)
339 		inventory_view->set_show_cursor(false);
340 	show_use_cursor = state;
341 }
342 
set_show_grid(bool state)343 void MapWindow::set_show_grid(bool state) {
344 	show_grid = state;
345 }
346 
347 /**
348  * cheat_off is needed to turn the X-ray cheat off (set to X_RAY_OFF)
349  * Convoluted logic is so we don't slow down boundaryFill with an extra check
350  */
set_x_ray_view(X_RayType state,bool cheat_off)351 void MapWindow::set_x_ray_view(X_RayType state, bool cheat_off) {
352 	if (x_ray_view == X_RAY_CHEAT_ON) {
353 		if (state == X_RAY_ON) // X_RAY_CHEAT_ON takes precedence to preserve X-ray cheat
354 			return;
355 		else if (state == X_RAY_OFF) {
356 			if (!cheat_off) { // not turning X-ray cheat off
357 				if (game->are_cheats_enabled()) // don't turn off when cheats are enabled
358 					return;
359 				else  // need to preserve X-ray cheat setting when cheats are off
360 					state = X_RAY_CHEAT_OFF;
361 			}
362 		}
363 	} else if (x_ray_view == X_RAY_CHEAT_OFF) {
364 		if (state == X_RAY_OFF) // X_RAY_CHEAT_OFF takes precedence to preserve X-ray cheat
365 			return;
366 		else if (state == X_RAY_ON) // need to preserve X-ray cheat setting when cheats are off
367 			state = X_RAY_CHEAT_ON;
368 	}
369 	x_ray_view = state;
370 	updateBlacking();
371 }
372 
set_freeze_blacking_location(bool state)373 void MapWindow::set_freeze_blacking_location(bool state) {
374 	freeze_blacking_location = state;
375 }
376 
set_enable_blacking(bool state)377 void MapWindow::set_enable_blacking(bool state) {
378 	enable_blacking = state;
379 	updateBlacking();
380 }
381 
set_walking(bool state)382 void MapWindow::set_walking(bool state) {
383 	if (state && game->get_view_manager()->gumps_are_active()) //we don't allow walking while gumps are active.
384 		return;
385 
386 	walking = state;
387 }
388 
moveLevel(uint8 new_level)389 void MapWindow::moveLevel(uint8 new_level) {
390 	cur_level = new_level;
391 
392 	updateBlacking();
393 }
394 
moveMap(sint16 new_x,sint16 new_y,sint8 new_level,uint8 new_x_add,uint8 new_y_add)395 void MapWindow::moveMap(sint16 new_x, sint16 new_y, sint8 new_level, uint8 new_x_add, uint8 new_y_add) {
396 
397 	map_width = map->get_width(new_level);
398 
399 	if (new_x < 0) {
400 		new_x = map_width + new_x;
401 	} else {
402 		new_x %= map_width;
403 	}
404 
405 //printf("cur_x = %d\n",new_x);
406 	cur_x = new_x;
407 	cur_y = new_y;
408 	cur_level = new_level;
409 	cur_x_add = new_x_add;
410 	cur_y_add = new_y_add;
411 	updateBlacking();
412 
413 }
414 
moveMapRelative(sint16 rel_x,sint16 rel_y)415 void MapWindow::moveMapRelative(sint16 rel_x, sint16 rel_y) {
416 	moveMap(cur_x + rel_x, cur_y + rel_y, cur_level);
417 }
418 
419 /* Move map by relative pixel amount.
420  */
shiftMapRelative(sint16 rel_x,sint16 rel_y)421 void MapWindow::shiftMapRelative(sint16 rel_x, sint16 rel_y) {
422 	uint8 tile_pitch = 16;
423 	uint32 total_px = (cur_x * tile_pitch) + cur_x_add,
424 	       total_py = (cur_y * tile_pitch) + cur_y_add;
425 	total_px += rel_x;
426 	total_py += rel_y;
427 	moveMap(total_px / tile_pitch, total_py / tile_pitch, cur_level,
428 	        total_px % tile_pitch, total_py % tile_pitch);
429 }
430 
431 /* Center MapWindow on a location.
432  */
centerMap(uint16 x,uint16 y,uint8 z)433 void MapWindow::centerMap(uint16 x, uint16 y, uint8 z) {
434 	moveMap(x - ((win_width - 1 - map_center_xoff) / 2) , y - ((win_height - 1) / 2), z);
435 }
436 
centerMapOnActor(Actor * actor)437 void MapWindow::centerMapOnActor(Actor *actor) {
438 	uint16 x;
439 	uint16 y;
440 	uint8 z;
441 
442 	actor->get_location(&x, &y, &z);
443 
444 	centerMap(x, y, z);
445 
446 	return;
447 }
448 
centerCursor()449 void MapWindow::centerCursor() {
450 
451 	cursor_x = (win_width - 1 - map_center_xoff) / 2;
452 	cursor_y = (win_height - 1) / 2;
453 
454 	return;
455 }
456 
moveCursor(sint16 new_x,sint16 new_y)457 void MapWindow::moveCursor(sint16 new_x, sint16 new_y) {
458 	if (new_x < 0 || new_x >= win_width)
459 		return;
460 
461 	if (new_y < 0 || new_y >= win_height)
462 		return;
463 
464 	cursor_x = new_x;
465 	cursor_y = new_y;
466 
467 	return;
468 }
469 
moveCursorRelative(sint16 rel_x,sint16 rel_y)470 void MapWindow::moveCursorRelative(sint16 rel_x, sint16 rel_y) {
471 	moveCursor(cursor_x + rel_x, cursor_y + rel_y);
472 }
473 
is_on_screen(uint16 x,uint16 y,uint8 z)474 bool MapWindow::is_on_screen(uint16 x, uint16 y, uint8 z) {
475 	if (z == cur_level && WRAP_VIEWP(cur_x, x, map_width) < win_width && y >= cur_y && y < cur_y + win_height) {
476 		if (tile_is_black(x, y) == false) {
477 			return true;
478 		}
479 	}
480 
481 	return false;
482 }
483 
484 /**
485  * Can we display an object at this location on the tmp map buffer.
486  *
487  * @param x coord on the tmp buf
488  * @param y coord on the tmp buf
489  * @param obj object to display
490  * @return
491  */
can_display_obj(uint16 x,uint16 y,Obj * obj)492 bool MapWindow::can_display_obj(uint16 x, uint16 y, Obj *obj) {
493 	uint16 tile_num = tmp_map_buf[y * tmp_map_width + x];
494 	if (tile_num == 0) //don't draw object if area is in darkness.
495 		return false;
496 	else {
497 		if (x >= tmp_map_width - 1 || y >= tmp_map_height - 1)
498 			return false;
499 
500 		// We don't show objects on walls if the area to the right or bottom of the wall is in darkness
501 		if (tmp_map_buf[y * tmp_map_width + (x + 1)] == 0 || tmp_map_buf[(y + 1)*tmp_map_width + x] == 0) {
502 			Tile *tile = tile_manager->get_tile(tile_num);
503 			if (((tile->flags1 & TILEFLAG_WALL) || (game_type == NUVIE_GAME_U6 && obj->obj_n == OBJ_U6_BARS)))
504 				return false;
505 		}
506 	}
507 
508 	return true;
509 }
510 
tile_is_black(uint16 x,uint16 y,Obj * obj)511 bool MapWindow::tile_is_black(uint16 x, uint16 y, Obj *obj) {
512 	if (game->using_hackmove())
513 		return false;
514 	if (!MapCoord(x, y, cur_level).is_visible()) // tmpBufTileIsBlack will crash if called (doesn't happen in gdb)
515 		return true;
516 	uint16 wrapped_x = WRAP_VIEWP(cur_x, x, map_width);
517 	if (tmpBufTileIsBlack(wrapped_x + TMP_MAP_BORDER, y - cur_y + TMP_MAP_BORDER))
518 		return true;
519 	else if (obj) {
520 		Tile *tile = tile_manager->get_original_tile(obj_manager->get_obj_tile_num(obj->obj_n) + obj->frame_n);
521 		if (!tile || (tmpBufTileIsBlack(wrapped_x + TMP_MAP_BORDER + 1, y - cur_y + TMP_MAP_BORDER)  && !(tile->flags1 & TILEFLAG_WALL))
522 		        || (tmpBufTileIsBlack(wrapped_x + TMP_MAP_BORDER, y - cur_y + TMP_MAP_BORDER + 1) && !(tile->flags1 & TILEFLAG_WALL)))
523 			return true;
524 	}
525 
526 	return false;
527 }
528 
look(uint16 x,uint16 y,bool show_prefix)529 const char *MapWindow::look(uint16 x, uint16 y, bool show_prefix) {
530 	Actor *actor;
531 
532 	if (tmp_map_buf[(y + TMP_MAP_BORDER) * tmp_map_width + (x + TMP_MAP_BORDER)] == 0) //black area
533 		return "darkness."; // nothing to see here. ;)
534 
535 	uint16 wrapped_x = WRAPPED_COORD(cur_x + x, cur_level);
536 	actor = actor_manager->get_actor(wrapped_x, cur_y + y, cur_level);
537 	if (actor != NULL && actor->is_visible())
538 		return actor_manager->look_actor(actor, show_prefix);
539 
540 	return map->look(wrapped_x, cur_y + y, cur_level);
541 }
542 
543 
get_objAtCursor(bool for_use)544 Obj *MapWindow::get_objAtCursor(bool for_use /* = false */) {
545 	MapCoord coord = get_cursorCoord();
546 	return get_objAtCoord(coord, OBJ_SEARCH_TOP, OBJ_EXCLUDE_IGNORED, for_use);
547 }
548 
get_objAtCoord(MapCoord coord,bool top_obj,bool include_ignored_objects,bool for_use)549 Obj *MapWindow::get_objAtCoord(MapCoord coord, bool top_obj, bool include_ignored_objects, bool for_use /* = false */) {
550 	if (tile_is_black(coord.x, coord.y))
551 		return NULL; // nothing to see here. ;)
552 
553 	Obj *obj = obj_manager->get_obj(coord.x, coord.y, coord.z, top_obj, include_ignored_objects);
554 	// Savage Empire Create Object from Tile
555 	if (for_use && game_type == NUVIE_GAME_SE && obj == NULL) {
556 		Script *script = game->get_script();
557 		uint16 map_win_x = WRAP_VIEWP(cur_x, coord.x, map_width);
558 		uint16 map_win_y = coord.y - cur_y;
559 		// Check that x,y is in tmp_map_buf
560 		if (is_on_screen(coord.x, coord.y, coord.z)) {
561 			uint16 tile_n = tmp_map_buf[(map_win_y + TMP_MAP_BORDER) * tmp_map_width + (map_win_x + TMP_MAP_BORDER)];
562 			uint16 obj_n = script->call_get_tile_to_object_mapping(tile_n);
563 			if (obj_n != 0) {
564 				obj = obj_manager->get_tile_obj(obj_n);
565 				obj->x = coord.x;
566 				obj->y = coord.y;
567 				obj->z = coord.z;
568 			}
569 		}
570 	}
571 	return obj;
572 }
573 
get_actorAtCursor()574 Actor *MapWindow::get_actorAtCursor() {
575 //Actor *actor;
576 
577 	if (tmp_map_buf[(cursor_y + TMP_MAP_BORDER) * tmp_map_width + (cursor_x + TMP_MAP_BORDER)] == 0) //black area
578 		return NULL; // nothing to see here. ;)
579 
580 	return actor_manager->get_actor(WRAPPED_COORD(cur_x + cursor_x, cur_level), cur_y + cursor_y, cur_level);
581 }
582 
get_cursorCoord()583 MapCoord MapWindow::get_cursorCoord() {
584 	return (MapCoord(WRAPPED_COORD(cur_x + cursor_x, cur_level), cur_y + cursor_y, cur_level));
585 }
586 
get_level(uint8 * level)587 void MapWindow::get_level(uint8 *level) {
588 	*level = cur_level;
589 }
590 
get_pos(uint16 * x,uint16 * y,uint8 * px,uint8 * py)591 void MapWindow::get_pos(uint16 *x, uint16 *y, uint8 *px, uint8 *py) {
592 	*x = cur_x;
593 	*y = cur_y;
594 	if (px)
595 		*px = cur_x_add;
596 	if (py)
597 		*py = cur_y_add;
598 }
599 
get_windowSize(uint16 * width,uint16 * height)600 void MapWindow::get_windowSize(uint16 *width, uint16 *height) {
601 	*width = win_width;
602 	*height = win_height;
603 }
604 
605 /* Returns true if the location at the coordinates is visible on the map window.
606  */
in_window(uint16 x,uint16 y,uint8 z)607 bool MapWindow::in_window(uint16 x, uint16 y, uint8 z) {
608 	return ((z == cur_level && WRAP_VIEWP(cur_x, x, map_width) < win_width
609 	         && y >= cur_y && y <= (cur_y + win_height)));
610 }
611 
612 
613 /* Update player position if walking to mouse cursor. Update map position.
614  */
update()615 void MapWindow::update() {
616 	GameClock *clock = game->get_clock();
617 	Events *event = game->get_event();
618 	static bool game_started = false; // set to true on the first update()
619 	static uint32 last_update_time = clock->get_ticks();
620 	uint32 update_time = clock->get_ticks();
621 
622 	// do fade-in on the first update (game has loaded now)
623 	if (game_started == false) {
624 //        new FadeEffect(FADE_PIXELATED_ONTOP, FADE_IN, 0x31);
625 		new GameFadeInEffect(game->get_palette()->get_bg_color());
626 		game_started = true;
627 	}
628 
629 	anim_manager->update(); // update animations
630 
631 	if (vel_x || vel_y) { // this slides the map
632 		if ((update_time - last_update_time) >= 100) { // only move every 10th sec
633 			sint32 sx = vel_x / 10, sy = vel_y / 10;
634 			if (vel_x && !sx) // move even if vel_x/vel_y was < 10
635 				sx = (vel_x < 0) ? -1 : 1;
636 			if (vel_y && !sy)
637 				sy = (vel_y < 0) ? -1 : 1;
638 
639 			shiftMapRelative(sx, sy);
640 			last_update_time = update_time;
641 		}
642 	}
643 
644 	if (walking) {
645 		if (Events::get()->getButtonState() & walk_button_mask) {
646 			if (game->user_paused())
647 				return;
648 
649 			int mx, my; // bit-AND buttons with mouse state to test
650 			screen->get_mouse_location(&mx, &my);
651 
652 			if (is_wizard_eye_mode()) {
653 //              int wx, wy;
654 //              mouseToWorldCoords(mx, my, wx, wy);
655 				sint16 rx, ry;
656 				get_movement_direction((uint16)mx, (uint16)my, rx, ry);
657 				moveMapRelative((rx == 0) ? 0 : rx < 0 ? -1 : 1,
658 				                (ry == 0) ? 0 : ry < 0 ? -1 : 1);
659 				wizard_eye_update();
660 			} else {
661 				//DEBUG(0, LEVEL_DEBUGGING, "MOUSE WALKING...\n");
662 				event->walk_to_mouse_cursor((uint32)mx,
663 				                            (uint32)my);
664 			}
665 		} else
666 			walking = false;
667 	}
668 
669 	KeyBinder *keybinder = game->get_keybinder();
670 	if (keybinder->is_joy_repeat_enabled() && (event->get_mode() == MOVE_MODE || is_wizard_eye_mode())
671 	        && keybinder->get_next_joy_repeat_time() < clock->get_ticks()) {
672 		Common::KeyCode key = keybinder->get_key_from_joy_walk_axes();
673 		if (key != Common::KEYCODE_INVALID) {
674 			Common::Event sdl_event;
675 			sdl_event.type = Common::EVENT_KEYDOWN;
676 			sdl_event.kbd.keycode = key;
677 			sdl_event.kbd.flags = 0;
678 			if (GUI::get_gui()->HandleEvent(&sdl_event) == GUI_PASS)
679 				event->handleEvent(&sdl_event);
680 		}
681 	}
682 }
683 
684 // moved from updateBlacking() so you don't have to update all blacking (SB-X)
updateAmbience()685 void MapWindow::updateAmbience() {
686 	lighting_update_required = true;
687 }
688 
689 // moved from updateBlacking() so you don't have to update all blacking (SB-X)
createLightOverlay()690 void MapWindow::createLightOverlay() {
691 	//Dusk starts at 19:00
692 	//It's completely dark by 20:00
693 	//Dawn starts at 5:00
694 	//It's completely bright by 6:00
695 	//Dusk and dawn operate by changing the ambient light, not by changing the radius of the avatar's light globe
696 
697 	if (!screen)
698 		return;
699 	bool dawn_or_dusk = false;
700 	uint8 cur_min_brightness;
701 	if (game->are_cheats_enabled())
702 		cur_min_brightness = min_brightness;
703 	else
704 		cur_min_brightness = 0;
705 
706 	GameClock *clock = game->get_clock();
707 	Weather *weather = game->get_weather();
708 
709 	int h = clock->get_hour();
710 	int a;
711 	if (x_ray_view >= X_RAY_ON)
712 		a = 255;
713 	else if (in_dungeon_level())
714 		a = cur_min_brightness;
715 	else if (weather->is_eclipse())  //solar eclipse
716 		a = cur_min_brightness;
717 	else if (h == 19) { //Dusk -- Smooth transition between 255 and min_brightness during first 59 minutes
718 		if (screen->get_lighting_style() == LIGHTING_STYLE_SMOOTH) {
719 			dawn_or_dusk = true;
720 			a = 255 - (uint8)((255.0f - cur_min_brightness) * (float)clock->get_minute() / 59.0f);
721 		} else {
722 			a = 20 * (6 - clock->get_minute() / 10);
723 			if (a < cur_min_brightness)
724 				a = cur_min_brightness;
725 		}
726 	} else if (h == 5) { //Dawn -- Smooth transition between min_brightness and 255 during first 59 minutes
727 		if (screen->get_lighting_style() == LIGHTING_STYLE_SMOOTH) {
728 			dawn_or_dusk = true;
729 			a = cur_min_brightness + (255.0f - cur_min_brightness) * (float)clock->get_minute() / 59.0f;
730 		} else {
731 			a = 20 * (1 +  clock->get_minute() / 10);
732 			if (a < cur_min_brightness)
733 				a = cur_min_brightness;
734 		}
735 	} else if (h > 5 && h < 19) //Day
736 		a = 255;
737 	else //Night
738 		a = cur_min_brightness;
739 
740 	if (a > 255)
741 		a = 255;
742 	bool party_light_source;
743 	// smooth seems to need an enormous range in order to have smooth transitions
744 	if (a < (screen->get_lighting_style() == LIGHTING_STYLE_SMOOTH ? 248 : 81) &&
745 	        (game->get_party()->has_light_source() || clock->get_timer(GAMECLOCK_TIMER_U6_LIGHT) != 0)) { //FIXME U6 specific
746 		party_light_source = true;
747 		if (screen->get_lighting_style() == LIGHTING_STYLE_SMOOTH) {
748 			if (!dawn_or_dusk) // preserve a when dusk or dawn so we have the correct opacity
749 				a = cur_min_brightness;
750 		} else
751 			a = 80;
752 	} else
753 		party_light_source = false;
754 	screen->set_ambient(a);
755 
756 	//Clear the opacity map
757 	screen->clearalphamap8(0, 0, win_width, win_height, screen->get_ambient(), party_light_source);
758 
759 	updateLighting();
760 
761 	lighting_update_required = false;
762 }
763 
updateLighting()764 void MapWindow::updateLighting() {
765 	uint16 x, y;
766 	if (using_map_tile_lighting) {
767 		uint16 *ptr = tmp_map_buf;
768 		for (y = 0; y < tmp_map_height; y++) {
769 			for (x = 0; x < tmp_map_width; x++) {
770 				if (tmp_map_buf[x + y * tmp_map_width] != 0) {
771 					Tile *tile = tile_manager->get_tile(*ptr);
772 					if (GET_TILE_LIGHT_LEVEL(tile) > 0)
773 						screen->drawalphamap8globe(x - TMP_MAP_BORDER, y - TMP_MAP_BORDER, GET_TILE_LIGHT_LEVEL(tile));
774 
775 					U6LList *obj_list = obj_manager->get_obj_list(cur_x - TMP_MAP_BORDER + x, cur_y - TMP_MAP_BORDER + y, cur_level); //FIXME wrapped coords.
776 					if (obj_list) {
777 						for (U6Link *link = obj_list->start(); link != NULL; link = link->next) {
778 							Obj *obj = (Obj *)link->data;
779 							tile = tile_manager->get_tile(obj_manager->get_obj_tile_num(obj) + obj->frame_n); //FIXME do we need to check the light for each tile in a multi-tile object.
780 							if (GET_TILE_LIGHT_LEVEL(tile) > 0 && can_display_obj(x, y, obj))
781 								screen->drawalphamap8globe(x - TMP_MAP_BORDER, y - TMP_MAP_BORDER, GET_TILE_LIGHT_LEVEL(tile));
782 						}
783 					}
784 				}
785 				ptr++;
786 			}
787 		}
788 
789 		for (Std::vector<TileInfo>::iterator ti = m_ViewableMapTiles.begin();
790 		        ti != m_ViewableMapTiles.end(); ti++) {
791 			if (GET_TILE_LIGHT_LEVEL((*ti).t) > 0)
792 				screen->drawalphamap8globe((*ti).x, (*ti).y, GET_TILE_LIGHT_LEVEL((*ti).t));
793 		}
794 	}
795 
796 	/* draw light coming from the actor
797 	   Wisps can change the light level depending on their current tile so we can't use actor->light for an actor's innate lighting.
798 	*/
799 	Actor *actor;
800 
801 	for (uint16 i = 0; i < 256; i++) {
802 		actor = actor_manager->get_actor(i);
803 
804 		if (actor->z == cur_level) {
805 			if (actor->x >= cur_x - TMP_MAP_BORDER && actor->x < cur_x + win_width + TMP_MAP_BORDER) {
806 				if (actor->y >= cur_y - TMP_MAP_BORDER && actor->y < cur_y + win_height + TMP_MAP_BORDER) {
807 					if (tmp_map_buf[(actor->y - cur_y + TMP_MAP_BORDER) * tmp_map_width + (actor->x - cur_x + TMP_MAP_BORDER)] != 0) {
808 						uint8 light = actor->get_light_level();
809 						if (light > 0) {
810 							screen->drawalphamap8globe(actor->x - cur_x, actor->y - cur_y, light);
811 						}
812 					}
813 				}
814 			}
815 		}
816 	}
817 }
818 
updateBlacking()819 void MapWindow::updateBlacking() {
820 	generateTmpMap();
821 
822 	updateAmbience();
823 
824 	m_ViewableObjects.clear();
825 /// m_ViewableObjTiles.clear();
826 
827 	draw_brit_lens_anim = false;
828 	draw_garg_lens_anim = false;
829 
830 	window_updated = true;
831 }
832 
Display(bool full_redraw)833 void MapWindow::Display(bool full_redraw) {
834 	uint16 i, j;
835 	uint16 *map_ptr;
836 // uint16 map_width;
837 	Tile *tile;
838 //byte *ptr;
839 
840 	if (lighting_update_required) {
841 		createLightOverlay();
842 	}
843 
844 //map_ptr = map->get_map_data(cur_level);
845 // map_width = map->get_width(cur_level);
846 
847 //map_ptr += cur_y * map_width + cur_x;
848 	map_ptr = tmp_map_buf;
849 	map_ptr += (TMP_MAP_BORDER * tmp_map_width + TMP_MAP_BORDER);// * sizeof(uint16); //remember our tmp map is TMP_MAP_BORDER bigger all around.
850 
851 	for (i = 0; i < win_height; i++) {
852 		for (j = 0; j < win_width; j++) {
853 			sint16 draw_x = area.left + (j * 16), draw_y = area.top + (i * 16);
854 			//draw_x -= (cur_x_add <= draw_x) ? cur_x_add : draw_x;
855 			//draw_y -= (cur_y_add <= draw_y) ? cur_y_add : draw_y;
856 			draw_x -= cur_x_add;
857 			draw_y -= cur_y_add;
858 			if (map_ptr[j] == 0)
859 				screen->clear(draw_x, draw_y, 16, 16, &clip_rect); //blackout tile.
860 			else {
861 				if (map_ptr[j] >= 16 && map_ptr[j] < 48) { //lay down the base tile for shoreline tiles
862 					tile = tile_manager->get_anim_base_tile(map_ptr[j]);
863 					screen->blit(draw_x, draw_y, (byte *)tile->data, 8, 16, 16, 16, tile->transparent, &clip_rect);
864 				}
865 
866 				tile = tile_manager->get_tile(map_ptr[j]);
867 				screen->blit(draw_x, draw_y, (byte *)tile->data, 8, 16, 16, 16, tile->transparent, &clip_rect);
868 
869 			}
870 
871 		}
872 		//map_ptr += map_width;
873 		map_ptr += tmp_map_width ;//* sizeof(uint16);
874 	}
875 
876 	drawObjs();
877 
878 //drawAnims();
879 
880 	if (roof_mode && roof_display != ROOF_DISPLAY_OFF) {
881 		drawRoofs();
882 	}
883 
884 	if (game->get_clock()->get_timer(GAMECLOCK_TIMER_U6_STORM) != 0) //FIXME u6 specific.
885 		drawRain();
886 
887 	if (show_grid) {
888 		drawGrid();
889 	}
890 
891 	if (show_cursor) {
892 		screen->blit(area.left + cursor_x * 16, area.top + cursor_y * 16, (byte *)cursor_tile->data, 8, 16, 16, 16, true, &clip_rect);
893 	}
894 
895 	if (show_use_cursor) {
896 		screen->blit(area.left + cursor_x * 16, area.top + cursor_y * 16, (byte *)use_tile->data, 8, 16, 16, 16, true, &clip_rect);
897 	}
898 
899 // screen->fill(0,8,8,win_height*16-16,win_height*16-16);
900 
901 	screen->blitalphamap8(area.left, area.top, &clip_rect);
902 
903 	if (game->get_clock()->get_timer(GAMECLOCK_TIMER_U6_INFRAVISION) != 0)
904 		drawActors();
905 
906 	if (overlay && overlay_level == MAP_OVERLAY_DEFAULT)
907 		screen->blit(area.left, area.top, (byte *)(overlay->getPixels()), overlay->format.bpp(), overlay->w, overlay->h, overlay->pitch, true, &clip_rect);
908 
909 	drawAnims(true);
910 
911 	if (new_thumbnail)
912 		create_thumbnail();
913 
914 	if (is_wizard_eye_mode()) {
915 		uint16 we_x = mousecenter_x * 16 + area.left;
916 		if (game->is_original_plus_full_map())
917 			we_x -= ((map_center_xoff + 1) / 2) * 16;
918 		screen->blit(we_x, mousecenter_y * 16 + area.top, (byte *)wizard_eye_info.eye_tile->data, 8, 16, 16, 16, true, &clip_rect);
919 	}
920 
921 	if (game->is_orig_style())
922 		drawBorder();
923 
924 	if (overlay && overlay_level == MAP_OVERLAY_ONTOP)
925 		screen->blit(area.left, area.top, (byte *)(overlay->getPixels()), overlay->format.bpp(), overlay->w, overlay->h, overlay->pitch, true, &clip_rect);
926 
927 // ptr = (byte *)screen->get_pixels();
928 // ptr += 8 * screen->get_pitch() + 8;
929 
930 // screen->blit(8,8,ptr,8,(win_width-1) * 16,(win_height-1) * 16, win_width * 16, false);
931 
932 	if (game->is_orig_style())
933 		screen->update(area.left + 8, area.top + 8, win_width * 16 - 16, win_height * 16 - 16);
934 	else if (game->is_original_plus_cutoff_map())
935 		screen->update(Game::get_game()->get_game_x_offset(), Game::get_game()->get_game_y_offset(), game->get_game_width() - border_width - 1, game->get_game_height());
936 	else
937 		screen->update(Game::get_game()->get_game_x_offset(), Game::get_game()->get_game_y_offset(), game->get_game_width(), game->get_game_height());
938 
939 	if (window_updated) {
940 		window_updated = false;
941 		game->get_sound_manager()->update_map_sfx();
942 	}
943 
944 }
945 
drawActors()946 void MapWindow::drawActors() {
947 	uint16 i;
948 	Actor *actor;
949 
950 	for (i = 0; i < 256; i++) {
951 		actor = actor_manager->get_actor(i);
952 
953 		if (actor->z == cur_level) {
954 			uint8 x = WRAP_VIEWP(cur_x, actor->x, map_width);
955 			if (x < win_width) { //actor->x >= cur_x && actor->x < cur_x + win_width)
956 				if (actor->y >= cur_y && actor->y < cur_y + win_height) {
957 					if (tmp_map_buf[(actor->y - cur_y + TMP_MAP_BORDER) * tmp_map_width + (x + TMP_MAP_BORDER)] != 0) {
958 						drawActor(actor);
959 					}
960 				}
961 			}
962 		}
963 	}
964 }
965 
966 //FIX need a function for multi-tile actors.
drawActor(Actor * actor)967 inline void MapWindow::drawActor(Actor *actor) {
968 	if (actor->is_visible() /* && actor->obj_n != 0*/
969 	        && (!(actor->obj_flags & OBJ_STATUS_INVISIBLE) || actor->is_in_party() || actor == actor_manager->get_player())
970 	        && actor->get_corpser_flag() == false) {
971 		Tile *tile = tile_manager->get_tile(actor->get_tile_num() + actor->frame_n);
972 		Tile *rtile = 0;
973 
974 		if (actor->obj_flags & OBJ_STATUS_INVISIBLE) {
975 			rtile = new Tile(*tile);
976 			for (int x = 0; x < 256; x++)
977 				if (rtile->data[x] != 0x00)
978 					rtile->data[x] = 0xFF;
979 				else
980 					rtile->data[x] = 0x0B;
981 		} else if (actor->status_flags & ACTOR_STATUS_PROTECTED) { // actually this doesn't appear when using a protection ring
982 			rtile = new Tile(*tile);
983 			for (int x = 0; x < 256; x++)
984 				if (rtile->data[x] == 0x00)
985 					rtile->data[x] = 0x0C;
986 		} else if (actor->is_cursed()) {
987 			rtile = new Tile(*tile);
988 			for (int x = 0; x < 256; x++)
989 				if (rtile->data[x] == 0x00)
990 					rtile->data[x] = 0x9;
991 		}
992 		uint16 wrapped_x = WRAP_VIEWP(cur_x, actor->x, map_width);
993 		if (rtile != 0) {
994 			drawNewTile(rtile, wrapped_x, actor->y - cur_y, false);
995 			drawNewTile(rtile, wrapped_x, actor->y - cur_y, true);
996 			delete rtile;
997 		} else {
998 			drawTile(tile, wrapped_x, actor->y - cur_y, false);
999 			drawTile(tile, wrapped_x, actor->y - cur_y, true);
1000 			if (game->get_clock()->get_timer(GAMECLOCK_TIMER_U6_INFRAVISION) != 0) {
1001 				Std::list<Obj *> *surrounding_objs = actor->get_surrounding_obj_list();
1002 
1003 				if (surrounding_objs) {
1004 					Std::list<Obj *>::iterator obj_iter;
1005 					for (obj_iter = surrounding_objs->begin(); obj_iter != surrounding_objs->end(); obj_iter++) {
1006 						Obj *obj = *obj_iter;
1007 						Tile *t = tile_manager->get_original_tile(obj_manager->get_obj_tile_num(obj->obj_n) + obj->frame_n);
1008 						uint16 wrapped_obj_x = WRAP_VIEWP(cur_x, obj->x, map_width);
1009 						drawTile(t, wrapped_obj_x, obj->y - cur_y, false);
1010 						drawTile(t, wrapped_obj_x, obj->y - cur_y, true); // doesn't seem needed but will do it anyway (for now)
1011 					}
1012 				}
1013 			}
1014 		}
1015 	}
1016 }
1017 
drawObjs()1018 void MapWindow::drawObjs() {
1019 //FIX we need to make this more efficent.
1020 
1021 	drawObjSuperBlock(true, false); //draw force lower objects
1022 	drawObjSuperBlock(false, false); //draw lower objects
1023 
1024 	drawActors();
1025 
1026 	drawAnims(false);
1027 
1028 	drawObjSuperBlock(false, true); //draw top objects
1029 
1030 	drawLensAnim();
1031 	return;
1032 }
1033 
drawLensAnim()1034 inline void MapWindow::drawLensAnim() {
1035 	if (draw_brit_lens_anim) {
1036 		if (cur_x < 0x399)
1037 			drawTile(tile_manager->get_tile(TILE_U6_BRITANNIAN_LENS_ANIM_2), 0x398 - cur_x, 0x353 - cur_y, true);
1038 		if (cur_x + win_width > 0x39a)
1039 			drawTile(tile_manager->get_tile(TILE_U6_BRITANNIAN_LENS_ANIM_1), 0x39a - cur_x, 0x353 - cur_y, true);
1040 	}
1041 
1042 	if (draw_garg_lens_anim) {
1043 		if (cur_x < 0x39d)
1044 			drawTile(tile_manager->get_tile(TILE_U6_GARGOYLE_LENS_ANIM_2), 0x39c - cur_x, 0x353 - cur_y, true);
1045 		if (cur_x + win_width > 0x39e)
1046 			drawTile(tile_manager->get_tile(TILE_U6_GARGOYLE_LENS_ANIM_1), 0x39e - cur_x, 0x353 - cur_y, true);
1047 	}
1048 }
1049 
drawObjSuperBlock(bool draw_lowertiles,bool toptile)1050 void MapWindow::drawObjSuperBlock(bool draw_lowertiles, bool toptile) {
1051 	U6Link *link;
1052 	U6LList *obj_list;
1053 	Obj *obj;
1054 	sint16 x, y;
1055 	uint16 stop_x, stop_y;
1056 
1057 	if (cur_x < 0)
1058 		stop_x = 0;
1059 	else
1060 		stop_x = cur_x;
1061 
1062 	if (cur_y < 0)
1063 		stop_y = 0;
1064 	else
1065 		stop_y = cur_y;
1066 
1067 	for (y = cur_y + win_height; y >= stop_y; y--) {
1068 		for (x = cur_x + win_width; x >= stop_x; x--) {
1069 			obj_list = obj_manager->get_obj_list(x, y, cur_level);
1070 			if (obj_list) {
1071 				for (link = obj_list->start(); link != NULL; link = link->next) {
1072 					obj = (Obj *)link->data;
1073 					drawObj(obj, draw_lowertiles, toptile);
1074 				}
1075 			}
1076 		}
1077 	}
1078 
1079 }
1080 
drawObj(Obj * obj,bool draw_lowertiles,bool toptile)1081 inline void MapWindow::drawObj(Obj *obj, bool draw_lowertiles, bool toptile) {
1082 	sint16 x, y;
1083 	Tile *tile;
1084 
1085 	y = obj->y - cur_y;
1086 	x = WRAP_VIEWP(cur_x, obj->x, map_width);
1087 
1088 	if (x < 0 || y < 0)
1089 		return;
1090 
1091 	if (window_updated) {
1092 		m_ViewableObjects.push_back(obj);
1093 
1094 		if (game_type == NUVIE_GAME_U6 && cur_level == 0 && obj->y == 0x353 && tmp_map_buf[(y + TMP_MAP_BORDER)*tmp_map_width + (x + TMP_MAP_BORDER)] != 0) {
1095 			if (obj->obj_n == 394 && obj->x == 0x399) {
1096 				draw_brit_lens_anim = true;
1097 			} else if (obj->obj_n == 396 && obj->x == 0x39d) {
1098 				draw_garg_lens_anim = true;
1099 			}
1100 		}
1101 	}
1102 
1103 //don't show invisible objects.
1104 	if (obj->status & OBJ_STATUS_INVISIBLE)
1105 		return;
1106 
1107 	tile = tile_manager->get_original_tile(obj_manager->get_obj_tile_num(obj) + obj->frame_n);
1108 
1109 	if (draw_lowertiles == false && (tile->flags3 & 0x4) && toptile == false) //don't display force lower tiles.
1110 		return;
1111 
1112 	if (draw_lowertiles == true && !(tile->flags3 & 0x4))
1113 		return;
1114 
1115 	if (tmp_map_buf[(y + TMP_MAP_BORDER)*tmp_map_width + (x + TMP_MAP_BORDER)] == 0) //don't draw object if area is in darkness.
1116 		return;
1117 	else {
1118 		// We don't show objects on walls if the area to the right or bottom of the wall is in darkness
1119 		if (tmp_map_buf[(y + TMP_MAP_BORDER)*tmp_map_width + (x + TMP_MAP_BORDER + 1)] == 0 || tmp_map_buf[(y + TMP_MAP_BORDER + 1)*tmp_map_width + (x + TMP_MAP_BORDER)] == 0) {
1120 			if ((!(tile->flags1 & TILEFLAG_WALL) || (game_type == NUVIE_GAME_U6 && obj->obj_n == OBJ_U6_BARS)))
1121 				return;
1122 		}
1123 	}
1124 
1125 	drawTile(tile, x, obj->y - cur_y, toptile);
1126 
1127 }
1128 
1129 /* The pixeldata in the passed Tile pointer will be used if use_tile_data is
1130  * true, otherwise the current tile is derived from tile_num. This can't be
1131  * used with animated tiles. It only applies to the base tile in multi-tiles.
1132  */
drawTile(Tile * tile,uint16 x,uint16 y,bool toptile,bool use_tile_data)1133 inline void MapWindow::drawTile(Tile *tile, uint16 x, uint16 y, bool toptile,
1134 								bool use_tile_data) {
1135 	bool dbl_width, dbl_height;
1136 	uint16 tile_num;
1137 
1138 	tile_num = tile->tile_num;
1139 
1140 	//don't show special marker tiles in MD unless "show eggs" is turned on.
1141 	if (game_type == NUVIE_GAME_MD
1142 	        && tile_num > 2040 && tile_num < 2048
1143 	        && !obj_manager->is_showing_eggs())
1144 		return;
1145 
1146 	/* shouldn't be needed for in_town check
1147 	 if(window_updated)
1148 	   {
1149 	    TileInfo ti;
1150 	    ti.t=tile;
1151 	    ti.left=x;
1152 	    ti.top=y;
1153 	    m_ViewableObjTiles.push_back(ti);
1154 	   }
1155 	*/
1156 	dbl_width = tile->dbl_width;
1157 	dbl_height = tile->dbl_height;
1158 
1159 	if (x < win_width && y < win_height)
1160 		drawTopTile(use_tile_data ? tile : tile_manager->get_tile(tile_num), x, y, toptile);
1161 
1162 	if (dbl_width) {
1163 		tile_num--;
1164 		if (x > 0 && y < win_height) {
1165 			tile = tile_manager->get_tile(tile_num);
1166 			drawTopTile(tile, x - 1, y, toptile);
1167 		}
1168 	}
1169 
1170 	if (dbl_height) {
1171 		tile_num--;
1172 		if (y > 0 && x < win_width) {
1173 			tile = tile_manager->get_tile(tile_num);
1174 			drawTopTile(tile, x, y - 1, toptile);
1175 		}
1176 	}
1177 
1178 	if (x > 0 && dbl_width && y > 0 && dbl_height) {
1179 		tile_num--;
1180 		tile = tile_manager->get_tile(tile_num);
1181 		drawTopTile(tile, x - 1, y - 1, toptile);
1182 	}
1183 
1184 }
1185 
drawNewTile(Tile * tile,uint16 x,uint16 y,bool toptile)1186 inline void MapWindow::drawNewTile(Tile *tile, uint16 x, uint16 y, bool toptile) {
1187 	drawTile(tile, x, y, toptile, true);
1188 }
1189 
drawTopTile(Tile * tile,uint16 x,uint16 y,bool toptile)1190 inline void MapWindow::drawTopTile(Tile *tile, uint16 x, uint16 y, bool toptile) {
1191 
1192 
1193 
1194 // if(tile->boundary)
1195 //  {
1196 //    screen->blit(cursor_tile->data,8,x*16,y*16,16,16,false);
1197 //   }
1198 // FIXME: Don't use pixel offset (x_add,y_add) here, pass it via params?
1199 	if (toptile) {
1200 		if (tile->toptile)
1201 //        screen->blit(x*16,y*16,tile->data,8,16,16,16,tile->transparent,&clip_rect);
1202 			screen->blit(area.left + (x * 16) - cur_x_add, area.top + (y * 16) - cur_y_add, tile->data, 8, 16, 16, 16, tile->transparent, &clip_rect);
1203 	} else {
1204 		if (!tile->toptile)
1205 //        screen->blit(x*16,y*16,tile->data,8,16,16,16,tile->transparent,&clip_rect);
1206 			screen->blit(area.left + (x * 16) - cur_x_add, area.top + (y * 16) - cur_y_add, tile->data, 8, 16, 16, 16, tile->transparent, &clip_rect);
1207 	}
1208 }
1209 
drawBorder()1210 void MapWindow::drawBorder() {
1211 	Tile *tile;
1212 	Tile *tile1;
1213 	uint16 i;
1214 
1215 	if (game_type != NUVIE_GAME_U6)
1216 		return;
1217 	uint16 orig_win_w = 11;
1218 	uint16 orig_win_h = 11;
1219 	uint16 x_off = Game::get_game()->get_game_x_offset();
1220 	uint16 y_off = Game::get_game()->get_game_y_offset();
1221 
1222 	tile = tile_manager->get_tile(432);
1223 	screen->blit(x_off, y_off, tile->data, 8, 16, 16, 16, true, &clip_rect); // upper left corner
1224 
1225 	tile = tile_manager->get_tile(434);
1226 	screen->blit(x_off + (orig_win_w - 1) * 16, y_off, tile->data, 8, 16, 16, 16, true); // upper right corner (got rid of &clip_rect for original+)
1227 
1228 	tile = tile_manager->get_tile(435);
1229 	screen->blit(x_off, y_off + (orig_win_h - 1) * 16, tile->data, 8, 16, 16, 16, true, &clip_rect); // lower left corner
1230 
1231 	tile = tile_manager->get_tile(437);
1232 	screen->blit(x_off + (orig_win_w - 1) * 16, y_off + (orig_win_h - 1) * 16, tile->data, 8, 16, 16, 16, true); // lower right corner (got rid of &clip_rect for original+)
1233 
1234 	tile = tile_manager->get_tile(433);
1235 	tile1 = tile_manager->get_tile(436);
1236 
1237 	for (i = 1; i < orig_win_w - 1; i++) {
1238 		screen->blit(x_off + i * 16, y_off, tile->data, 8, 16, 16, 16, true, &clip_rect); // top row
1239 		screen->blit(x_off + i * 16, y_off + (orig_win_h - 1) * 16, tile1->data, 8, 16, 16, 16, true, &clip_rect); // bottom row
1240 	}
1241 
1242 	tile = tile_manager->get_tile(438);
1243 	tile1 = tile_manager->get_tile(439);
1244 
1245 	for (i = 1; i < orig_win_h - 1; i++) {
1246 		screen->blit(x_off, y_off + i * 16, tile->data, 8, 16, 16, 16, true, &clip_rect); // left column
1247 		screen->blit(x_off + (orig_win_w - 1) * 16, y_off + i * 16, tile1->data, 8, 16, 16, 16, true); // right column (got rid of &clip_rect for original+)
1248 	}
1249 }
1250 
1251 //FIXME this won't work for wrapped maps like MD.
drawRoofs()1252 void MapWindow::drawRoofs() {
1253 	if (cur_y < 1 || cur_y > 760) // FIXME We need to handle this properly
1254 		return;
1255 	if (roof_display == ROOF_DISPLAY_NORMAL && map->has_roof(WRAPPED_COORD(cur_x + (win_width - 1 - map_center_xoff) / 2, cur_level), cur_y + (win_height - 1) / 2, cur_level)) //Don't draw roof tiles if player is underneath.
1256 		return;
1257 	if (x_ray_view >= X_RAY_ON)
1258 		return;
1259 
1260 	bool orig_style = game->is_orig_style();
1261 
1262 	uint16 *roof_map_ptr = map->get_roof_data(cur_level);
1263 
1264 	Common::Rect src(16, 16), dst(16, 16);
1265 
1266 	if (roof_map_ptr) {
1267 		roof_map_ptr += cur_y * 1024 + cur_x;
1268 		for (uint16 i = 0; i < win_height; i++) {
1269 			for (uint16 j = 0; j < win_width; j++) {
1270 				if (roof_map_ptr[j] != 0) {
1271 					dst.left = area.left + (j * 16);
1272 					dst.top = area.top + (i * 16);
1273 					dst.left -= cur_x_add;
1274 					dst.top -= cur_y_add;
1275 
1276 					src.left = (roof_map_ptr[j] % MAPWINDOW_ROOFTILES_IMG_W) * 16;
1277 					src.top = (roof_map_ptr[j] / MAPWINDOW_ROOFTILES_IMG_W) * 16;
1278 
1279 					if (orig_style) {
1280 						src.setWidth(16);
1281 						src.setHeight(16);
1282 						dst.setWidth(16);
1283 						dst.setHeight(16);
1284 
1285 						if (i == 0) {
1286 							src.top += 8;
1287 							src.setHeight(8);
1288 							dst.top += 8;
1289 							dst.setHeight(8);
1290 						} else if (i == win_height - 1) {
1291 							src.setHeight(8);
1292 							dst.setHeight(8);
1293 						}
1294 
1295 						if (j == 0) {
1296 							src.left += 8;
1297 							src.setWidth(8);
1298 							dst.left += 8;
1299 							dst.setWidth(8);
1300 						} else if (j == win_width - 1) {
1301 							src.setWidth(8);
1302 							dst.setWidth(8);
1303 						}
1304 						SDL_BlitSurface(roof_tiles, &src, surface, &dst);
1305 					} else {
1306 						byte *ptr = (byte *)roof_tiles->getPixels();
1307 						ptr += src.left + src.top * 80;
1308 						screen->blit(dst.left, dst.top, ptr, 8, 16, 16, 80, true, &clip_rect);
1309 					}
1310 				}
1311 			}
1312 			roof_map_ptr += 1024;
1313 		}
1314 	}
1315 }
1316 
drawRain()1317 void MapWindow::drawRain() {
1318 	int c;
1319 	if (game->is_orig_style())
1320 		c = win_width * win_height;
1321 	else if (game->is_original_plus_cutoff_map())
1322 		c = ((game->get_game_width() - border_width) * game->get_game_height()) / 256;
1323 	else
1324 		c = (game->get_game_width() * game->get_game_height()) / 256;
1325 	for (int i = 0; i < c; i++) {
1326 		uint16 x;
1327 		uint16 y;
1328 		if (game->is_orig_style()) {
1329 			x = area.left + NUVIE_RAND() % ((win_width - 1) * 16 - 2) + 8;
1330 			y = area.top + NUVIE_RAND() % ((win_height - 1) * 16 - 2) + 8;
1331 		} else {
1332 			if (game->is_original_plus_cutoff_map())
1333 				x = game->get_game_x_offset() + NUVIE_RAND() % (game->get_game_width() - border_width - 2);
1334 			else
1335 				x = game->get_game_x_offset() + NUVIE_RAND() % (game->get_game_width() - 2);
1336 			y = game->get_game_y_offset() + NUVIE_RAND() % (game->get_game_height() - 2);
1337 		}
1338 
1339 		//FIXME the original does something with the palette if a pixel is black then draw gray etc.
1340 		//We can't do this easily here because we don't have the original 8 bit display surface.
1341 		screen->put_pixel(118, x, y);
1342 		screen->put_pixel(118, x + 1, y + 1);
1343 		screen->put_pixel(0, x + 2, y + 2);
1344 	}
1345 }
1346 
AddMapTileToVisibleList(uint16 tile_num,uint16 x,uint16 y)1347 void MapWindow::AddMapTileToVisibleList(uint16 tile_num, uint16 x, uint16 y) {
1348 	if (x >= TMP_MAP_BORDER &&
1349 	        y >= TMP_MAP_BORDER &&
1350 	        x < tmp_map_width - TMP_MAP_BORDER &&
1351 	        y < tmp_map_height - TMP_MAP_BORDER) {
1352 		TileInfo ti;
1353 		ti.t = tile_manager->get_tile(tile_num);
1354 		ti.x = (uint16)(x - TMP_MAP_BORDER);
1355 		ti.y = (uint16)(y - TMP_MAP_BORDER);
1356 		m_ViewableMapTiles.push_back(ti);
1357 	}
1358 }
1359 
drawGrid()1360 void MapWindow::drawGrid() {
1361 	for (uint16 i = 0; i < win_height; i++) {
1362 		for (uint16 j = 0; j < win_width; j++) {
1363 			screen->blit(area.left + (j * 16) - cur_x_add, area.top + (i * 16) - cur_y_add,
1364 				(const byte *)grid_tile.data, 8, 16, 16, 16, true);
1365 		}
1366 	}
1367 }
1368 
generateTmpMap()1369 void MapWindow::generateTmpMap() {
1370 	byte *map_ptr;
1371 	uint16 pitch;
1372 	uint16 x, y;
1373 	Tile *tile;
1374 
1375 	m_ViewableMapTiles.clear();
1376 
1377 	map_ptr = map->get_map_data(cur_level);
1378 	pitch = map->get_width(cur_level);
1379 
1380 	if (enable_blacking == false) {
1381 		uint16 *ptr = tmp_map_buf;
1382 		for (y = 0; y < tmp_map_height; y++) {
1383 			for (x = 0; x < tmp_map_width; x++) {
1384 				uint16 x1 = cur_x + x - TMP_MAP_BORDER;
1385 				uint16 y1 = cur_y + y - TMP_MAP_BORDER;
1386 				WRAP_COORD(x1, cur_level);
1387 				WRAP_COORD(y1, cur_level);
1388 				*ptr = map_ptr[y1 * pitch + x1];
1389 				AddMapTileToVisibleList(*ptr, x, y);
1390 
1391 				ptr++;
1392 			}
1393 		}
1394 		return;
1395 	}
1396 
1397 	roof_display = ROOF_DISPLAY_NORMAL;
1398 
1399 	memset(tmp_map_buf, 0, tmp_map_width * tmp_map_height * sizeof(uint16));
1400 
1401 	if (freeze_blacking_location == false) {
1402 		x = cur_x + ((win_width - 1 - map_center_xoff) / 2);
1403 		y = cur_y + ((win_height - 1) / 2);
1404 	} else { // SB-X
1405 		x = last_boundary_fill_x;
1406 		y = last_boundary_fill_y;
1407 	}
1408 
1409 	WRAP_COORD(x, cur_level);
1410 	WRAP_COORD(y, cur_level);
1411 
1412 //This is for U6. Sherry needs to pass through walls
1413 //We shift the boundary fill start location off the wall tile so it flood
1414 //fills correctly. We move east for vertical wall tiles and south for
1415 //horizontal wall tiles.
1416 	if (game_type == NUVIE_GAME_U6 && obj_manager->is_boundary(x, y, cur_level)) {
1417 		tile = obj_manager->get_obj_tile(x, y, cur_level, false);
1418 		if ((tile->flags1 & TILEFLAG_WALL_MASK) == (TILEFLAG_WALL_NORTH | TILEFLAG_WALL_SOUTH))
1419 			x = WRAPPED_COORD(x + 1, cur_level);
1420 		else
1421 			y = WRAPPED_COORD(y + 1, cur_level);
1422 	}
1423 	last_boundary_fill_x = x;
1424 	last_boundary_fill_y = y;
1425 	boundaryFill(map_ptr, pitch, x, y);
1426 
1427 	reshapeBoundary();
1428 
1429 	if (roof_mode && floorTilesVisible())
1430 		roof_display = ROOF_DISPLAY_OFF; // hide roof if a building's floor is showing.
1431 }
1432 
boundaryFill(byte * map_ptr,uint16 pitch,uint16 x,uint16 y)1433 void MapWindow::boundaryFill(byte *map_ptr, uint16 pitch, uint16 x, uint16 y) {
1434 	unsigned char current;
1435 	uint16 *ptr;
1436 	uint16 pos;
1437 	uint16 tmp_x, tmp_y;
1438 	uint16 p_cur_x, p_cur_y; //wrapped cur_x - 1 and wrapped cur_y - 1
1439 
1440 	p_cur_x = WRAPPED_COORD(cur_x - TMP_MAP_BORDER, cur_level);
1441 	p_cur_y = WRAPPED_COORD(cur_y - TMP_MAP_BORDER, cur_level);
1442 
1443 	if (x == WRAPPED_COORD(p_cur_x - 1, cur_level) || x == WRAPPED_COORD(p_cur_x + tmp_map_width, cur_level))
1444 		return;
1445 
1446 	if (y == WRAPPED_COORD(p_cur_y - 1, cur_level) || y == WRAPPED_COORD(p_cur_y + tmp_map_height, cur_level))
1447 		return;
1448 
1449 	if (p_cur_y > y)
1450 		tmp_y = pitch - p_cur_y + y;
1451 	else
1452 		tmp_y = y - p_cur_y;
1453 
1454 	pos = tmp_y * tmp_map_width;
1455 
1456 	if (p_cur_x > x)
1457 		tmp_x = pitch - p_cur_x + x;
1458 	else
1459 		tmp_x = x - p_cur_x;
1460 
1461 	pos += tmp_x;
1462 
1463 	ptr = &tmp_map_buf[pos];
1464 
1465 	if (*ptr != 0)
1466 		return;
1467 
1468 	current = map_ptr[y * pitch + x];
1469 
1470 	*ptr = (uint16)current;
1471 
1472 	AddMapTileToVisibleList(current, tmp_x, tmp_y);
1473 
1474 	if (x_ray_view <= X_RAY_OFF && map->is_boundary(x, y, cur_level)) { //hit the boundary wall tiles
1475 		if (boundaryLookThroughWindow(*ptr, x, y) == false)
1476 			return;
1477 		else
1478 			roof_display = ROOF_DISPLAY_OFF; //hide roof tiles if player is looking through window.
1479 	}
1480 
1481 
1482 	uint16 xp1, xm1;
1483 	uint16 yp1, ym1;
1484 
1485 	xp1 = WRAPPED_COORD(x + 1, cur_level);
1486 	xm1 = WRAPPED_COORD(x - 1, cur_level);
1487 
1488 	yp1 = WRAPPED_COORD(y + 1, cur_level);
1489 	ym1 = WRAPPED_COORD(y - 1, cur_level);
1490 
1491 	boundaryFill(map_ptr, pitch, xp1,   y);
1492 	boundaryFill(map_ptr, pitch,   x, yp1);
1493 	boundaryFill(map_ptr, pitch, xp1, yp1);
1494 	boundaryFill(map_ptr, pitch, xm1, ym1);
1495 	boundaryFill(map_ptr, pitch, xm1,   y);
1496 	boundaryFill(map_ptr, pitch,   x, ym1);
1497 	boundaryFill(map_ptr, pitch, xp1, ym1);
1498 	boundaryFill(map_ptr, pitch, xm1, yp1);
1499 
1500 
1501 	return;
1502 }
1503 
floorTilesVisible()1504 bool MapWindow::floorTilesVisible() {
1505 	Actor *actor;
1506 	uint16 a_x, a_y;
1507 	uint8 a_z;
1508 	actor = actor_manager->get_player();
1509 	if (!actor)
1510 		return false;
1511 	actor->get_location(&a_x, &a_y, &a_z);
1512 	uint16 cX = WRAPPED_COORD(a_x - 1, cur_level), eX = WRAPPED_COORD(a_x + 2, cur_level);
1513 	uint16 cY = WRAPPED_COORD(a_y - 1, cur_level), eY = WRAPPED_COORD(a_y + 2, cur_level);
1514 
1515 	for (; cY != eY;) {
1516 		for (; cX != eX;) {
1517 			if (map->has_roof(cX, cY, cur_level) && !map->is_boundary(cX, cY, cur_level)) {
1518 				Tile *t = obj_manager->get_obj_tile(cX, cY, cur_level, false);
1519 				if (t && (t->flags1 & TILEFLAG_WALL))
1520 					return true;
1521 			}
1522 			cX = WRAPPED_COORD(cX + 1, cur_level);
1523 		}
1524 		cX = WRAPPED_COORD(a_x - 1, cur_level);
1525 		cY = WRAPPED_COORD(cY + 1, cur_level);
1526 	}
1527 
1528 	return false;
1529 }
1530 
boundaryLookThroughWindow(uint16 tile_num,uint16 x,uint16 y)1531 bool MapWindow::boundaryLookThroughWindow(uint16 tile_num, uint16 x, uint16 y) {
1532 	Tile *tile;
1533 	Actor *actor;
1534 	uint16 a_x, a_y;
1535 	uint8 a_z;
1536 	Obj  *obj;
1537 
1538 	tile = tile_manager->get_tile(tile_num);
1539 	if (!(tile->flags2 & TILEFLAG_WINDOW)) {
1540 		obj = obj_manager->get_objBasedAt(x, y, cur_level, true);
1541 		if (obj) { //check for a windowed object.
1542 			tile = tile_manager->get_tile(obj_manager->get_obj_tile_num(obj->obj_n) + obj->frame_n);
1543 			if (!(tile->flags2 & TILEFLAG_WINDOW))
1544 				return false;
1545 		} else
1546 			return false;
1547 	}
1548 
1549 	actor = actor_manager->get_player();
1550 	actor->get_location(&a_x, &a_y, &a_z);
1551 
1552 	if (a_x == x) {
1553 		if (a_y == WRAPPED_COORD(y - 1, cur_level) || a_y == WRAPPED_COORD(y + 1, cur_level))
1554 			return true;
1555 	}
1556 
1557 	if (a_y == y) {
1558 		if (a_x == WRAPPED_COORD(x - 1, cur_level) || a_x == WRAPPED_COORD(x + 1, cur_level))
1559 			return true;
1560 	}
1561 
1562 	return false;
1563 }
1564 
1565 //reshape walls based on new blacked out areas.
1566 
reshapeBoundary()1567 void MapWindow::reshapeBoundary() {
1568 	uint16 x, y;
1569 	uint8 flag, original_flag;
1570 	Tile *tile;
1571 
1572 	for (y = 1; y < tmp_map_height - 1; y++) {
1573 		for (x = 1; x < tmp_map_width - 1; x++) {
1574 			if (tmpBufTileIsBoundary(x, y)) {
1575 				tile = tile_manager->get_tile(tmp_map_buf[y * tmp_map_width + x]);
1576 
1577 				if ((tile->tile_num >= 140 && tile->tile_num <= 187)) { //main U6 wall tiles FIX for WOU games
1578 					flag = 0;
1579 					original_flag = tile->flags1 & TILEFLAG_WALL_MASK;
1580 				} else
1581 					continue;
1582 
1583 				//generate the required wall flags
1584 				if (tmpBufTileIsWall(x, y - 1, NUVIE_DIR_N))
1585 					flag |= TILEFLAG_WALL_NORTH;
1586 				if (tmpBufTileIsWall(x + 1, y, NUVIE_DIR_E))
1587 					flag |= TILEFLAG_WALL_EAST;
1588 				if (tmpBufTileIsWall(x, y + 1, NUVIE_DIR_S))
1589 					flag |= TILEFLAG_WALL_SOUTH;
1590 				if (tmpBufTileIsWall(x - 1, y, NUVIE_DIR_W))
1591 					flag |= TILEFLAG_WALL_WEST;
1592 
1593 				//we want to keep existing tile if it is pointing to non-wall tiles which are not blacked
1594 				//this is used to support cookfire walls which aren't considered walls in tileflags.
1595 
1596 				if (tmpBufTileIsBlack(x, y - 1) == false && (original_flag & TILEFLAG_WALL_NORTH))
1597 					flag |= TILEFLAG_WALL_NORTH;
1598 				if (tmpBufTileIsBlack(x + 1, y) == false && (original_flag & TILEFLAG_WALL_EAST))
1599 					flag |= TILEFLAG_WALL_EAST;
1600 				if (tmpBufTileIsBlack(x, y + 1) == false && (original_flag & TILEFLAG_WALL_SOUTH))
1601 					flag |= TILEFLAG_WALL_SOUTH;
1602 				if (tmpBufTileIsBlack(x - 1, y) == false && (original_flag & TILEFLAG_WALL_WEST))
1603 					flag |= TILEFLAG_WALL_WEST;
1604 
1605 				if (flag == 0) //isolated border tiles
1606 					continue;
1607 
1608 				if (flag == 48) { // 0011 top right corner
1609 					if (tmpBufTileIsBlack(x, y - 1) && tmpBufTileIsBlack(x + 1, y)) { //replace with blacked corner tile
1610 						//Oh dear! this is evil. FIX
1611 						tmp_map_buf[y * tmp_map_width + x] = 266 + 2 * (((tile->tile_num - tile->tile_num % 16) - 140) / 16);
1612 						continue;
1613 					}
1614 				}
1615 
1616 				if (flag == 192) { // 1100 bottom left corner
1617 					if (tmpBufTileIsBlack(x, y + 1) && tmpBufTileIsBlack(x - 1, y)) { //replace with blacked corner tile
1618 						//Oh dear! this is evil. FIX
1619 						tmp_map_buf[y * tmp_map_width + x] = 266 + 1 + 2 * (((tile->tile_num - tile->tile_num % 16) - 140) / 16);
1620 						continue;
1621 					}
1622 				}
1623 
1624 				if ((tile->flags1 & TILEFLAG_WALL_MASK) == flag) // complete match no work needed
1625 					continue;
1626 
1627 				// Look for a suitable tile to transform into
1628 
1629 				// ERIC 05/03/05 flag |= TILEFLAG_WALL_NORTH | TILEFLAG_WALL_WEST;
1630 
1631 				if (((tile->flags1) & TILEFLAG_WALL_MASK) > flag && flag != 144) { // 1001 _| corner
1632 					//flag |= TILEFLAG_WALL_NORTH | TILEFLAG_WALL_WEST;
1633 					for (; ((tile->flags1) & TILEFLAG_WALL_MASK) != flag && (tile->flags1 & TILEFLAG_WALL_MASK);)
1634 						tile = tile_manager->get_tile(tile->tile_num - 1);
1635 				} else {
1636 					//flag |= TILEFLAG_WALL_NORTH | TILEFLAG_WALL_WEST;
1637 					for (; ((tile->flags1) & TILEFLAG_WALL_MASK) != flag && (tile->flags1 & TILEFLAG_WALL_MASK);)
1638 						tile = tile_manager->get_tile(tile->tile_num + 1);
1639 				}
1640 
1641 				if ((tile->flags1 & TILEFLAG_WALL_MASK) == flag)
1642 					tmp_map_buf[y * tmp_map_width + x] = tile->tile_num;
1643 			}
1644 		}
1645 	}
1646 }
1647 
tmpBufTileIsBlack(uint16 x,uint16 y)1648 inline bool MapWindow::tmpBufTileIsBlack(uint16 x, uint16 y) {
1649 	if (tmp_map_buf[y * tmp_map_width + x] == 0)
1650 		return true;
1651 
1652 	return false;
1653 }
1654 
tmpBufTileIsBoundary(uint16 x,uint16 y)1655 bool MapWindow::tmpBufTileIsBoundary(uint16 x, uint16 y) {
1656 	uint16 tile_num;
1657 	Tile *tile;
1658 
1659 	tile_num = tmp_map_buf[y * tmp_map_width + x];
1660 
1661 	if (tile_num == 0)
1662 		return false;
1663 
1664 	tile = tile_manager->get_tile(tile_num);
1665 
1666 	if (tile->boundary)
1667 		return true;
1668 
1669 	if (obj_manager->is_boundary(WRAPPED_COORD(cur_x - TMP_MAP_BORDER + x, cur_level), WRAPPED_COORD(cur_y - TMP_MAP_BORDER + y, cur_level), cur_level))
1670 		return true;
1671 
1672 	return false;
1673 }
1674 
tmpBufTileIsWall(uint16 x,uint16 y,uint8 direction)1675 bool MapWindow::tmpBufTileIsWall(uint16 x, uint16 y, uint8 direction) {
1676 	uint16 tile_num;
1677 	Tile *tile;
1678 	uint8 mask = 0;
1679 
1680 	tile_num = tmp_map_buf[y * tmp_map_width + x];
1681 
1682 	if (tile_num == 0)
1683 		return false;
1684 
1685 	switch (direction) {
1686 	case NUVIE_DIR_N :
1687 		mask = TILEFLAG_WALL_SOUTH;
1688 		break;
1689 	case NUVIE_DIR_S :
1690 		mask = TILEFLAG_WALL_NORTH;
1691 		break;
1692 	case NUVIE_DIR_E :
1693 		mask = TILEFLAG_WALL_WEST;
1694 		break;
1695 	case NUVIE_DIR_W :
1696 		mask = TILEFLAG_WALL_EAST;
1697 		break;
1698 	}
1699 
1700 	tile = tile_manager->get_tile(tile_num);
1701 
1702 	if (tile->flags1 & TILEFLAG_WALL) {
1703 		if (tile->flags1 & mask)
1704 			return true;
1705 	}
1706 
1707 // if(obj_manager->is_boundary(cur_x-1+x, cur_y-1+y, cur_level))
1708 //  return true;
1709 
1710 	tile = obj_manager->get_obj_tile(WRAPPED_COORD(cur_x - TMP_MAP_BORDER + x, cur_level), WRAPPED_COORD(cur_y - TMP_MAP_BORDER + y, cur_level), cur_level, false);
1711 	if (tile != NULL) {
1712 		if (tile->flags2 & TILEFLAG_BOUNDARY) {
1713 			if (tile->flags1 & mask)
1714 				return true;
1715 		}
1716 	}
1717 
1718 	return false;
1719 }
1720 
1721 /* Returns MSG_SUCCESS if the obj can be dropped or moved by the actor at world coordinates x,y or an error msg.
1722  * There must be a direct path between the actor to the obj and also between the obj and destination.
1723  * Objs that can't be picked up will be blocked actors and unpassable areas. (z is always cur_level)
1724  */
can_drop_or_move_obj(uint16 x,uint16 y,Actor * actor,Obj * obj)1725 CanDropOrMoveMsg MapWindow::can_drop_or_move_obj(uint16 x, uint16 y, Actor *actor, Obj *obj) {
1726 	bool in_inventory = obj->is_in_inventory();
1727 	if (!in_inventory && obj->x == x && obj->y == y)
1728 		return MSG_NOT_POSSIBLE;
1729 	if (game->using_hackmove())
1730 		return MSG_SUCCESS;
1731 
1732 	if (tile_is_black(x, y, obj)) {
1733 		if (tile_is_black(x, y))
1734 			return MSG_NOT_POSSIBLE;
1735 		else
1736 			return MSG_BLOCKED;
1737 	}
1738 	MapCoord actor_loc = actor->get_location();
1739 	if (actor_manager->get_actor(x, y, actor_loc.z))
1740 		return MSG_NOT_POSSIBLE;
1741 
1742 	Obj *dest_obj = NULL;
1743 	if (game_type == NUVIE_GAME_U6) {
1744 		dest_obj = obj_manager->get_obj(x, y, actor_loc.z); //FIXME this might not be right. We might want to exclude obj.
1745 	} else {
1746 		dest_obj = obj_manager->get_obj(x, y, actor_loc.z, OBJ_SEARCH_TOP, OBJ_EXCLUDE_IGNORED, obj);
1747 	}
1748 
1749 	bool can_go_in_water = (game_type == NUVIE_GAME_U6
1750 	                        && (obj->obj_n == OBJ_U6_SKIFF || obj->obj_n == OBJ_U6_RAFT));
1751 	if (can_go_in_water && dest_obj) // it is drawn underneath so only allow on hackmove
1752 		return MSG_NOT_POSSIBLE;
1753 
1754 	LineTestResult lt;
1755 	MapCoord target_loc(x, y, actor_loc.z);
1756 	MapCoord obj_loc(obj->x, obj->y, actor_loc.z);
1757 
1758 	if (in_inventory && !obj->get_actor_holding_obj()->is_onscreen()
1759 	        && obj->get_actor_holding_obj()->get_location().distance(target_loc) > 5)
1760 		return MSG_OUT_OF_RANGE;
1761 
1762 	if (get_interface() == INTERFACE_IGNORE_BLOCK && map->can_put_obj(x, y, cur_level))
1763 		return MSG_SUCCESS;
1764 
1765 	if (actor_loc.distance(target_loc) > 5 && get_interface() == INTERFACE_NORMAL)
1766 		return MSG_OUT_OF_RANGE;
1767 
1768 	uint8 lt_flags;
1769 	lt_flags = (game_type == NUVIE_GAME_U6) ? LT_HitMissileBoundary : 0; //FIXME this probably isn't quite right for MD/SE
1770 	if (map->lineTest(actor_loc.x, actor_loc.y, x, y, actor_loc.z, lt_flags, lt, 0, obj)) {
1771 		MapCoord hit_loc = MapCoord(lt.hit_x, lt.hit_y, lt.hit_level);
1772 		if (obj_loc.distance(target_loc) != 1 || hit_loc.distance(target_loc) != 1) {
1773 			if (lt.hitObj && target_loc == hit_loc) {
1774 				if (obj_manager->can_store_obj(lt.hitObj, obj)) //if we are moving onto a container.
1775 					return MSG_SUCCESS;
1776 			}
1777 			return MSG_BLOCKED;
1778 		}
1779 		// trying to push object one tile away from actor
1780 		if (map->lineTest(obj->x, obj->y, x, y, actor_loc.z, lt_flags, lt, 0, obj)) {
1781 			if (lt.hitObj) {
1782 				if (obj_manager->can_store_obj(lt.hitObj, obj)) //if we are moving onto a container.
1783 					return MSG_SUCCESS;
1784 				/*                else // I don't think these are needed
1785 				                {
1786 				                    // We can place an object on a bench or table. Or on any other object if
1787 				                    // the object is passable and not on a boundary.
1788 
1789 				                    Tile *obj_tile = obj_manager->get_obj_tile(lt.hitObj->obj_n, lt.hitObj->frame_n);
1790 				                    if(!obj_tile) // shouldn't happen
1791 				                        return MSG_NO_TILE;
1792 				                    if((obj_tile->flags3 & TILEFLAG_CAN_PLACE_ONTOP)
1793 				                       || (obj_tile->passable && !map->is_boundary(lt.hit_x, lt.hit_y, lt.hit_level)) )
1794 				                        return MSG_SUCCESS;
1795 				                }*/
1796 			}
1797 			return MSG_BLOCKED;
1798 		}
1799 	}
1800 	Tile *tile;
1801 	if (dest_obj)
1802 		tile = obj_manager->get_obj_tile(dest_obj->obj_n, dest_obj->frame_n);
1803 	else
1804 		tile = map->get_tile(x, y, actor_loc.z);
1805 
1806 	if (!tile) // shouldn't happen
1807 		return MSG_NO_TILE;
1808 
1809 	if ((can_go_in_water || !map->is_water(x, y, actor_loc.z))
1810 	        && ((tile->flags3 & TILEFLAG_CAN_PLACE_ONTOP)
1811 	            || (tile->passable && !map->is_boundary(x, y, actor_loc.z))))
1812 		return MSG_SUCCESS;
1813 
1814 	return MSG_NOT_POSSIBLE;
1815 }
1816 
display_can_drop_or_move_msg(CanDropOrMoveMsg msg,string msg_text)1817 void MapWindow::display_can_drop_or_move_msg(CanDropOrMoveMsg msg, string msg_text) {
1818 	if (msg == MSG_NOT_POSSIBLE)
1819 		msg_text += "Not possible\n";
1820 	else if (msg == MSG_BLOCKED)
1821 		msg_text += "Blocked\n";
1822 	else if (msg == MSG_OUT_OF_RANGE)
1823 		msg_text += "Out of range\n";
1824 	/*  else if(msg == MSG_NO_TILE) // shouldn't be needed now that blacked out areas are checked first
1825 	        msg_text += "ERROR: No tile. Report me\n";*/
1826 	game->get_scroll()->display_string(msg_text);
1827 }
1828 
can_get_obj(Actor * actor,Obj * obj)1829 bool MapWindow::can_get_obj(Actor *actor, Obj *obj) {
1830 	if (!obj)
1831 		return false;
1832 	if (get_interface() == INTERFACE_IGNORE_BLOCK)
1833 		return true;
1834 	if (obj->is_in_inventory())
1835 		return false;
1836 	if (obj->is_in_container())
1837 		obj = obj->get_container_obj(true);
1838 
1839 	if (actor->get_z() != obj->z)
1840 		return false;
1841 
1842 	LineTestResult lt;
1843 	if (map->lineTest(actor->get_x(), actor->get_y(), obj->x, obj->y, obj->z, LT_HitUnpassable, lt, 0, obj)) {
1844 		// Skip Check for SE Tile Objects - We are actually using the blocking item/tree
1845 		Script *script = game->get_script();
1846 		if (game_type != NUVIE_GAME_SE || !script->call_is_tile_object(obj->obj_n)) {
1847 			return false;
1848 		}
1849 	}
1850 
1851 	if (game_type == NUVIE_GAME_U6 && obj->obj_n == OBJ_U6_SECRET_DOOR)
1852 		return true;
1853 	return !blocked_by_wall(actor, obj);
1854 }
1855 
1856 /*
1857  * Check to make sure the obj isn't on the other side of a wall or trying to push through it.
1858  * The original engine didn't bother to check.
1859  */
blocked_by_wall(Actor * actor,Obj * obj)1860 bool MapWindow::blocked_by_wall(Actor *actor, Obj *obj) {
1861 	if (game_type == NUVIE_GAME_U6 && obj->x == 282 && obj->y == 438 && cur_level == 0) // HACK for buggy location
1862 		return false;
1863 	Tile *tile = map->get_tile(obj->x, obj->y, cur_level);
1864 	if (((tile->flags1 & TILEFLAG_WALL) && !game->get_usecode()->is_door(obj))
1865 	        && (((tile->flags1 & TILEFLAG_WALL_MASK) == 208 && actor->get_y() < obj->y) // can't get items that are south
1866 	            || ((tile->flags1 & TILEFLAG_WALL_MASK) == 176 && actor->get_x() < obj->x) // can't get items that are east
1867 	            || ((tile->flags1 & TILEFLAG_WALL_MASK) == 240 // northwest corner - used in SE (not sure if used in other games)
1868 	                && (actor->get_y() < obj->y || actor->get_x() < obj->x))))
1869 		return true;
1870 
1871 	return false;
1872 }
1873 
drag_accept_drop(int x,int y,int message,void * data)1874 bool MapWindow::drag_accept_drop(int x, int y, int message, void *data) {
1875 	DEBUG(0, LEVEL_DEBUGGING, "MapWindow::drag_accept_drop()\n");
1876 	uint16 mapWidth;
1877 
1878 	x -= area.left;
1879 	y -= area.top;
1880 
1881 	x /= 16;
1882 	y /= 16;
1883 
1884 	GUI::get_gui()->force_full_redraw();
1885 
1886 	if (message == GUI_DRAG_OBJ) {
1887 		if (game->get_player()->is_in_vehicle() && !game->using_hackmove()) {
1888 			game->get_event()->display_not_aboard_vehicle();
1889 			return false;
1890 		}
1891 		mapWidth = map->get_width(cur_level);
1892 		x = (cur_x + x) % mapWidth;
1893 		y = (cur_y + y) % mapWidth;
1894 
1895 		Obj *obj = (Obj *)data;
1896 		Actor *p = actor_manager->get_player();
1897 		Actor *target_actor = map->get_actor(x, y, cur_level);
1898 
1899 		if (obj->is_in_inventory() == false) { //obj on map.
1900 			if (can_get_obj(p, obj)) { //make sure there is a clear line from player to object
1901 				if (target_actor) {
1902 					game->get_event()->display_move_text(target_actor, obj);
1903 
1904 					if (target_actor == p || (target_actor->is_in_party())) {
1905 						if (obj_manager->obj_is_damaging(obj, p)) {
1906 							game->get_player()->subtract_movement_points(3);
1907 							return false;
1908 						}
1909 						if ((!game->get_usecode()->has_getcode(obj) || game->get_usecode()->get_obj(obj, target_actor))
1910 						        && game->get_event()->can_move_obj_between_actors(obj, p, target_actor))
1911 							return true;
1912 						else {
1913 							game->get_scroll()->message("\n\n");
1914 							return false;
1915 						}
1916 					} else {
1917 						game->get_scroll()->display_string("\n\nOnly within the party!");
1918 						game->get_scroll()->message("\n\n");
1919 						return false;
1920 					}
1921 				} else
1922 					return true;
1923 			}
1924 		} else {
1925 			if (game->get_usecode()->cannot_unready(obj)) {
1926 				game->get_event()->unready(obj);
1927 				return false;
1928 			}
1929 			if (target_actor) {
1930 				Actor *owner = obj->get_actor_holding_obj();
1931 				game->get_event()->display_move_text(target_actor, obj);
1932 
1933 				if (game->get_event()->can_move_obj_between_actors(obj, owner, target_actor) == false) {
1934 					game->get_scroll()->message("\n\n");
1935 					return false;
1936 				} else
1937 					return true;
1938 			} else
1939 				return true; //throw on ground
1940 		}
1941 		game->get_scroll()->display_string("Move-");
1942 		game->get_scroll()->display_string(obj_manager->look_obj(obj)); // getting obj name
1943 		game->get_scroll()->display_string("\nto ");
1944 		game->get_scroll()->display_string(get_direction_name(x - obj->x ,  y - obj->y));
1945 		game->get_scroll()->message(".\n\nCan't reach it\n\n");
1946 	}
1947 
1948 	return false;
1949 }
1950 
drag_perform_drop(int x,int y,int message,void * data)1951 void MapWindow::drag_perform_drop(int x, int y, int message, void *data) {
1952 	DEBUG(0, LEVEL_DEBUGGING, "MapWindow::drag_perform_drop()\n");
1953 	Events *event = game->get_event();
1954 	uint16 mapWidth = map->get_width(cur_level);
1955 
1956 	x -= area.left;
1957 	y -= area.top;
1958 
1959 	if (message == GUI_DRAG_OBJ) {
1960 		x = (cur_x + x / 16) % mapWidth;
1961 		y = (cur_y + y / 16) % mapWidth;
1962 		Obj *obj = (Obj *)data;
1963 
1964 		if (obj->obj_n == OBJ_U6_LOCK_PICK && game_type == NUVIE_GAME_U6)
1965 			game->get_usecode()->search_container(obj, false);
1966 		Actor *a = map->get_actor(x, y, cur_level);
1967 		if (a && (a->is_in_party() || a == actor_manager->get_player())) {
1968 			if (a == actor_manager->get_player()) // get
1969 				game->get_player()->subtract_movement_points(3);
1970 			else // get plus move
1971 				game->get_player()->subtract_movement_points(8);
1972 			obj_manager->moveto_inventory(obj, a);
1973 			game->get_scroll()->message("\n\n");
1974 		} else {
1975 			if (!obj->is_in_inventory() && !obj->is_in_container()) { // !need is_in_container to exclude container gumps
1976 				move_on_drop(obj); // no longer determines whether to drop or move but can call usecode
1977 				event->newAction(PUSH_MODE);
1978 				event->select_obj(obj);
1979 				event->pushTo(x - obj->x, y - obj->y, PUSH_FROM_OBJECT);
1980 				event->endAction();
1981 				return;
1982 			}
1983 			CanDropOrMoveMsg can_drop; // so we can skip quantity prompt
1984 			if ((can_drop = can_drop_or_move_obj(x, y, actor_manager->get_player(), obj)) != MSG_SUCCESS) {
1985 				game->get_scroll()->display_string("Drop-");
1986 				game->get_scroll()->display_string(obj_manager->look_obj(obj));
1987 				game->get_scroll()->display_string("\n\nlocation:\n\n");
1988 				display_can_drop_or_move_msg(can_drop, "");
1989 				game->get_scroll()->message("\n");
1990 				return;
1991 			}
1992 			// drop on ground or into a container
1993 			event->newAction(DROP_MODE);
1994 			event->select_obj(obj);
1995 			if (obj->qty <= 1 || !obj_manager->is_stackable(obj))
1996 				event->select_target(x, y);
1997 			else
1998 				event->set_drop_target(x, y); // pre-select target
1999 		}
2000 	}
2001 
2002 }
2003 // performs some usecode but used to decide whether to move or drop too
move_on_drop(Obj * obj)2004 bool MapWindow::move_on_drop(Obj *obj) {
2005 	bool move = (get_interface() == INTERFACE_NORMAL);
2006 	/*  if(drop_with_move && move)
2007 	        return true;
2008 
2009 	    if(obj_manager->obj_is_damaging(obj))
2010 	        return move;
2011 	*/
2012 	if (game->get_usecode()->has_getcode(obj) && obj->is_in_inventory() == false) {
2013 		if (game_type == NUVIE_GAME_U6) {
2014 			switch (obj->obj_n) {
2015 			case OBJ_U6_CHEST:
2016 			case OBJ_U6_LOCK_PICK:
2017 			case OBJ_U6_MOONSTONE:
2018 				game->get_usecode()->get_obj(obj, actor_manager->get_player());
2019 				return false;
2020 			case OBJ_U6_SKIFF:
2021 				return false;
2022 			case OBJ_U6_TORCH:
2023 				if (obj->frame_n == 0)
2024 					return false;
2025 				break;
2026 			default :
2027 				break;
2028 			}
2029 		}
2030 
2031 		return move;
2032 	}
2033 
2034 	return false;
2035 }
2036 
set_interface()2037 void MapWindow::set_interface() {
2038 	Std::string interface_str;
2039 	config->value("config/input/interface", interface_str, "normal");
2040 	if (interface_str == "ignore_block" ||  Game::get_game()->using_hackmove()) // game variable is not initialized
2041 		interface = INTERFACE_IGNORE_BLOCK;
2042 	else if (interface_str == "fullscreen")
2043 		interface = INTERFACE_FULLSCREEN;
2044 	else
2045 		interface = INTERFACE_NORMAL;
2046 }
2047 
get_interface()2048 InterfaceType MapWindow::get_interface() {
2049 	// check is easily exploited but would be annoying if checking for nearby enemies
2050 	if (interface == INTERFACE_FULLSCREEN && game->get_party()->is_in_combat_mode())
2051 		return INTERFACE_NORMAL;
2052 	return interface;
2053 }
2054 
is_interface_fullscreen_in_combat()2055 bool MapWindow::is_interface_fullscreen_in_combat() {
2056 	if (interface == INTERFACE_FULLSCREEN && game->get_party()->is_in_combat_mode())
2057 		return true;
2058 	return false;
2059 }
2060 
Idle(void)2061 GUI_status MapWindow::Idle(void) {
2062 	return (GUI_Widget::Idle());
2063 }
2064 
2065 
2066 // single-click (press and release button)
MouseClick(int x,int y,Shared::MouseButton button)2067 GUI_status MapWindow::MouseClick(int x, int y, Shared::MouseButton button) {
2068 	if (button == USE_BUTTON && look_on_left_click) {
2069 		wait_for_mouseclick(button); // see MouseDelayed
2070 	}
2071 	return (MouseUp(x, y, button)); // do MouseUp so selected_obj is cleared
2072 }
2073 
2074 // single-click; waited for double-click
MouseDelayed(int x,int y,Shared::MouseButton button)2075 GUI_status MapWindow::MouseDelayed(int x, int y, Shared::MouseButton button) {
2076 	Events *event = game->get_event();
2077 	if (!looking || game->user_paused() || event->cursor_mode
2078 	        || (event->get_mode() != MOVE_MODE && event->get_mode() != EQUIP_MODE)) {
2079 		look_obj = NULL;
2080 		look_actor = NULL;
2081 		return (GUI_PASS);
2082 	}
2083 	game->get_scroll()->display_string("Look-");
2084 	event->set_mode(LOOK_MODE);
2085 	event->lookAtCursor(true, original_obj_loc.x, original_obj_loc.y, original_obj_loc.z, look_obj, look_actor);
2086 	look_obj = NULL;
2087 	look_actor = NULL;
2088 
2089 	return (MouseUp(x, y, button)); // do MouseUp so selected_obj is cleared
2090 }
2091 
2092 // MouseDown; waited for MouseUp
MouseHeld(int x,int y,Shared::MouseButton button)2093 GUI_status MapWindow::MouseHeld(int x, int y, Shared::MouseButton button) {
2094 	looking = false;
2095 	if (walk_with_left_button)
2096 		set_walking(true);
2097 	return (GUI_PASS);
2098 }
2099 
2100 // double-click
MouseDouble(int x,int y,Shared::MouseButton button)2101 GUI_status MapWindow::MouseDouble(int x, int y, Shared::MouseButton button) {
2102 	Events *event = game->get_event();
2103 
2104 	// only USE if not doing anything in event
2105 	if (enable_doubleclick && event->get_mode() == MOVE_MODE && !is_wizard_eye_mode()) {
2106 		int wx, wy;
2107 		mouseToWorldCoords(x, y, wx, wy);
2108 		event->multiuse((uint16)wx, (uint16)wy);
2109 	}
2110 	looking = false;
2111 	return (MouseUp(x, y, button)); // do MouseUp so selected_obj is cleared
2112 }
2113 
MouseWheel(sint32 x,sint32 y)2114 GUI_status MapWindow::MouseWheel(sint32 x, sint32 y) {
2115 	Game *g = Game::get_game();
2116 
2117 	if (g->is_new_style()) {
2118 		if (y > 0)
2119 			g->get_scroll()->move_scroll_up();
2120 		if (y < 0)
2121 			g->get_scroll()->move_scroll_down();
2122 	} else {
2123 		if (y > 0)
2124 			g->get_scroll()->page_up();
2125 		if (y < 0)
2126 			g->get_scroll()->page_down();
2127 	}
2128 	return GUI_YUM;
2129 }
2130 
MouseDown(int x,int y,Shared::MouseButton button)2131 GUI_status MapWindow::MouseDown(int x, int y, Shared::MouseButton button) {
2132 	//DEBUG(0,LEVEL_DEBUGGING,"MapWindow::MouseDown, button = %i\n", button);
2133 	Events *event = game->get_event();
2134 	Actor *player = actor_manager->get_player();
2135 	Obj *obj = get_objAtMousePos(x, y);
2136 
2137 	if (is_wizard_eye_mode()) {
2138 		set_walking(true);
2139 		return GUI_YUM;
2140 	}
2141 	if (event->is_looking_at_spellbook()) {
2142 		event->cancelAction();
2143 		return GUI_YUM;
2144 	}
2145 
2146 	if (game->is_original_plus() && y <= Game::get_game()->get_game_y_offset() + 200
2147 	        && x >= Game::get_game()->get_game_x_offset() + game->get_game_width() - border_width) {
2148 		looking = false;
2149 		return GUI_PASS;
2150 	}
2151 	if (event->get_mode() == MOVE_MODE || event->get_mode() == EQUIP_MODE) {
2152 		int wx, wy;
2153 		mouseToWorldCoords(x, y, wx, wy);
2154 
2155 		if (button == WALK_BUTTON && game->get_command_bar()->get_selected_action() != -1) {
2156 			if (game->get_command_bar()->try_selected_action() == false) // start new action
2157 				return GUI_PASS; // false if new event doesn't need target
2158 		} else if (wx == player->x && wy == player->y // PASS if Avatar is hit
2159 		           && (button == WALK_BUTTON || !enable_doubleclick)) {
2160 			event->cancelAction(); // MOVE_MODE, so this should work
2161 			return GUI_PASS;
2162 		} else if (button == WALK_BUTTON
2163 		           || (!enable_doubleclick && button == USE_BUTTON
2164 		               && !game->is_dragging_enabled() && !look_on_left_click)) {
2165 			set_walking(true);
2166 		} else if (button == USE_BUTTON) { // you can also walk by holding the USE button
2167 			if (look_on_left_click && !event->cursor_mode) { // need to preserve location because of click delay
2168 				looking = true;
2169 				original_obj_loc = MapCoord(wx, wy , cur_level);
2170 				look_actor = actor_manager->get_actor(wx , wy, cur_level);
2171 				look_obj = obj_manager->get_obj(wx , wy, cur_level);
2172 				moveCursor(WRAP_VIEWP(cur_x, wx, map_width), wy - cur_y);
2173 			}
2174 			wait_for_mousedown(button);
2175 		}
2176 	}
2177 
2178 	if (event->get_mode() == INPUT_MODE || event->get_mode() == ATTACK_MODE) { // finish whatever action is being done, with mouse coordinates
2179 		if (button != USE_BUTTON && button != WALK_BUTTON)
2180 			return GUI_PASS;
2181 		looking = false;
2182 		select_target(x, y);
2183 		return  GUI_PASS;
2184 	} else if (event->get_mode() != MOVE_MODE && event->get_mode() != EQUIP_MODE) {
2185 		return GUI_PASS;
2186 	}
2187 
2188 	if (!obj || button != DRAG_BUTTON)
2189 		return  GUI_PASS;
2190 
2191 	original_obj_loc = MapCoord(obj->x, obj->y, obj->z);
2192 	int distance = player->get_location().distance(original_obj_loc);
2193 	float weight = obj_manager->get_obj_weight(obj, OBJ_WEIGHT_EXCLUDE_CONTAINER_ITEMS);
2194 
2195 	if ((weight == 0 || player->get_actor_num() == 0
2196 	        || tile_is_black(obj->x, obj->y, obj)) && !game->using_hackmove())
2197 		return  GUI_PASS;
2198 
2199 	// checking interface directly to allow dragging in INTERFACE_FULLSCREEN when in combat
2200 	if (distance > 1 && interface == INTERFACE_NORMAL)
2201 		return  GUI_PASS;
2202 
2203 	if (button == DRAG_BUTTON && game->is_dragging_enabled())
2204 		selected_obj = obj;
2205 
2206 	return  GUI_PASS;
2207 }
2208 
MouseUp(int x,int y,Shared::MouseButton button)2209 GUI_status MapWindow::MouseUp(int x, int y, Shared::MouseButton button) {
2210 	// cancel dragging and movement no matter what button is released
2211 	if (selected_obj) {
2212 		selected_obj = NULL;
2213 	}
2214 	walking = false;
2215 	dragging = false;
2216 
2217 	return  GUI_PASS;
2218 }
2219 
MouseMotion(int x,int y,uint8 state)2220 GUI_status  MapWindow::MouseMotion(int x, int y, uint8 state) {
2221 //	Events *event = game->get_event();
2222 	Tile    *tile;
2223 
2224 	update_mouse_cursor((uint32)x, (uint32)y);
2225 
2226 	//  DEBUG(0,LEVEL_DEBUGGING,"MapWindow::MouseMotion\n");
2227 
2228 //	if(selected_obj) // We don't want to walk if we are selecting an object to move.
2229 //		walking = false;
2230 	if (walking) { // No, we don't want to select an object to move if we are walking.
2231 		selected_obj = NULL;
2232 		dragging = false;
2233 	}
2234 
2235 	if (selected_obj && !dragging) {
2236 		int wx, wy;
2237 		// ensure that the player can reach the selected object before
2238 		// letting them drag it
2239 		//mouseToWorldCoords(x, y, wx, wy);
2240 		wx = selected_obj->x;
2241 		wy = selected_obj->y;
2242 		LineTestResult result;
2243 		Actor *player = actor_manager->get_player();
2244 
2245 		if (map->lineTest(player->x, player->y, wx, wy, cur_level, LT_HitUnpassable, result)
2246 		        && !(result.hitObj && result.hitObj->x == wx && result.hitObj->y == wy)
2247 		        && get_interface() == INTERFACE_NORMAL)
2248 			// something was in the way, so don't allow a drag
2249 			return GUI_PASS;
2250 		dragging = true;
2251 		set_mousedown(0, DRAG_BUTTON); // cancel MouseHeld
2252 		game->set_mouse_pointer(0); // arrow
2253 		tile = tile_manager->get_tile(obj_manager->get_obj_tile_num(selected_obj->obj_n) + selected_obj->frame_n);
2254 		bool out_of_range;
2255 		if (is_interface_fullscreen_in_combat() && player->get_location().distance(original_obj_loc) > 1)
2256 			out_of_range = true;
2257 		else
2258 			out_of_range = false;
2259 		return gui_drag_manager->start_drag(this, GUI_DRAG_OBJ, selected_obj, tile->data, 16, 16, 8, out_of_range);
2260 	}
2261 
2262 	return  GUI_PASS;
2263 }
2264 
drag_drop_success(int x,int y,int message,void * data)2265 void    MapWindow::drag_drop_success(int x, int y, int message, void *data) {
2266 	//DEBUG(0,LEVEL_DEBUGGING,"MapWindow::drag_drop_success\n");
2267 	dragging = false;
2268 
2269 // handled by drop target
2270 //	if (selected_obj)
2271 //		obj_manager->remove_obj (selected_obj);
2272 
2273 	selected_obj = NULL;
2274 	Redraw();
2275 }
2276 
drag_drop_failed(int x,int y,int message,void * data)2277 void    MapWindow::drag_drop_failed(int x, int y, int message, void *data) {
2278 	DEBUG(0, LEVEL_DEBUGGING, "MapWindow::drag_drop_failed\n");
2279 	dragging = false;
2280 	selected_obj = NULL;
2281 }
2282 
2283 // this does nothing
KeyDown(const Common::KeyState & key)2284 GUI_status MapWindow::KeyDown(const Common::KeyState &key) {
2285 	if (is_wizard_eye_mode()) {
2286 		KeyBinder *keybinder = Game::get_game()->get_keybinder();
2287 		ActionType a = keybinder->get_ActionType(key);
2288 		switch (keybinder->GetActionKeyType(a)) {
2289 		case WEST_KEY:
2290 			moveMapRelative(-1, 0);
2291 			break;
2292 		case EAST_KEY:
2293 			moveMapRelative(1, 0);
2294 			break;
2295 		case SOUTH_KEY:
2296 			moveMapRelative(0, 1);
2297 			break;
2298 		case NORTH_KEY:
2299 			moveMapRelative(0, -1);
2300 			break;
2301 		case NORTH_EAST_KEY:
2302 			moveMapRelative(1, -1);
2303 			break;
2304 		case SOUTH_EAST_KEY:
2305 			moveMapRelative(1, 1);
2306 			break;
2307 		case NORTH_WEST_KEY:
2308 			moveMapRelative(-1, -1);
2309 			break;
2310 		case SOUTH_WEST_KEY:
2311 			moveMapRelative(-1, 1);
2312 			break;
2313 		case CANCEL_ACTION_KEY:
2314 			wizard_eye_stop();
2315 			break;
2316 		default:
2317 			keybinder->handle_always_available_keys(a);
2318 			return GUI_YUM;
2319 		}
2320 		if (keybinder->GetActionKeyType(a) <= SOUTH_WEST_KEY)
2321 			wizard_eye_update();
2322 		return GUI_YUM;
2323 	}
2324 	return GUI_PASS;
2325 }
2326 
get_objAtMousePos(int mx,int my)2327 Obj *MapWindow::get_objAtMousePos(int mx, int my) {
2328 	int wx, wy;
2329 	mouseToWorldCoords(mx, my, wx, wy);
2330 
2331 	return  obj_manager->get_obj(wx, wy, cur_level);
2332 }
2333 
2334 
get_actorAtMousePos(int mx,int my)2335 Actor *MapWindow::get_actorAtMousePos(int mx, int my) {
2336 	int wx, wy;
2337 	mouseToWorldCoords(mx, my, wx, wy);
2338 
2339 	return  actor_manager->get_actor(wx, wy, cur_level);
2340 }
2341 
teleport_to_cursor()2342 void MapWindow::teleport_to_cursor() {
2343 	int mx, my, wx, wy;
2344 	screen->get_mouse_location(&mx, &my);
2345 
2346 	mouseToWorldCoords(mx, my, wx, wy);
2347 	game->get_player()->move(wx, wy, cur_level, true);
2348 }
2349 
select_target(int x,int y)2350 void MapWindow::select_target(int x, int y) {
2351 	int wx, wy;
2352 	mouseToWorldCoords(x, y, wx, wy);
2353 	moveCursor(WRAP_VIEWP(cur_x, wx, map_width), wy - cur_y);
2354 	game->get_event()->select_target(uint16(wx), uint16(wy), cur_level);
2355 }
2356 
mouseToWorldCoords(int mx,int my,int & wx,int & wy)2357 void MapWindow::mouseToWorldCoords(int mx, int my, int &wx, int &wy) {
2358 	int x = mx - area.left;
2359 	int y = my - area.top;
2360 
2361 	int mapWidth = map->get_width(cur_level);
2362 
2363 	wx = (cur_x + x / 16) % mapWidth;
2364 	wy = (cur_y + y / 16) % mapWidth;
2365 }
2366 
drag_draw(int x,int y,int message,void * data)2367 void MapWindow::drag_draw(int x, int y, int message, void *data) {
2368 	Tile *tile;
2369 
2370 	if (!selected_obj)
2371 		return;
2372 
2373 	tile = tile_manager->get_tile(obj_manager->get_obj_tile_num(selected_obj) + selected_obj->frame_n);
2374 
2375 	int nx = x - 8;
2376 	int ny = y - 8;
2377 
2378 	if (nx + 16 >= screen->get_width())
2379 		nx = screen->get_width() - 17;
2380 	else if (nx < 0)
2381 		nx = 0;
2382 
2383 	if (ny + 16 >= screen->get_height())
2384 		ny = screen->get_height() - 17;
2385 	else if (ny < 0)
2386 		ny = 0;
2387 
2388 	screen->blit(nx, ny, tile->data, 8, 16, 16, 16, true);
2389 	screen->update(nx, ny, 16, 16);
2390 }
2391 
2392 
2393 /* Display MapWindow animations. */
drawAnims(bool top_anims)2394 void MapWindow::drawAnims(bool top_anims) {
2395 	if (!screen) // screen should be set early on
2396 		return;
2397 	else if (!anim_manager->get_surface()) // screen must be assigned to AnimManager
2398 		anim_manager->set_surface(screen);
2399 	anim_manager->display(top_anims);
2400 }
2401 
2402 
2403 /* Set mouse pointer to a movement-arrow for walking, or a crosshair. */
update_mouse_cursor(uint32 mx,uint32 my)2404 void MapWindow::update_mouse_cursor(uint32 mx, uint32 my) {
2405 	Events *event = game->get_event();
2406 	int wx = 0, wy = 0;
2407 	sint16 rel_x, rel_y;
2408 	uint8 mptr; // mouse-pointer is set here in get_movement_direction()
2409 
2410 	if (event->get_mode() != MOVE_MODE && event->get_mode() != INPUT_MODE)
2411 		return;
2412 
2413 	// MousePos->WorldCoord->Direction&MousePointer
2414 	if (game->is_orig_style())
2415 		mouseToWorldCoords((int)mx, (int)my, wx, wy);
2416 	get_movement_direction((uint16)mx, (uint16)my, rel_x, rel_y, &mptr);
2417 	if (event->get_mode() == INPUT_MODE && mousecenter_x == (win_width / 2) && mousecenter_y == (win_height / 2)
2418 	        && !event->dont_show_target_cursor())
2419 		game->set_mouse_pointer(1); // crosshairs
2420 	else if (dragging || (game->is_orig_style() && (wx == cur_x || wy == cur_y || wx == WRAP_VIEWP(cur_x, win_width - 1, map_width) || wy == (cur_y + win_height - 1)))
2421 	         || (game->is_original_plus() && (my <= (uint32)Game::get_game()->get_game_y_offset() + 200 || game->is_original_plus_cutoff_map())
2422 	             && mx >= (uint32)Game::get_game()->get_game_x_offset() + game->get_game_width() - border_width))
2423 		game->set_mouse_pointer(0); // arrow
2424 	else
2425 		game->set_mouse_pointer(mptr); // 1=crosshairs, 2to9=arrows
2426 }
2427 
2428 /* Get relative movement direction from the MouseCenter coordinates to the
2429  * mouse coordinates mx,my, for walking with the mouse, etc. The mouse-pointer
2430  * number that should be used for that direction will be set to mptr.
2431  */
get_movement_direction(uint16 mx,uint16 my,sint16 & rel_x,sint16 & rel_y,uint8 * mptr)2432 void MapWindow::get_movement_direction(uint16 mx, uint16 my, sint16 &rel_x, sint16 &rel_y, uint8 *mptr) {
2433 	uint16 cent_x = mousecenter_x,
2434 	       cent_y = mousecenter_y;
2435 	if (game->is_original_plus_full_map() && game->get_event()->get_mode() != INPUT_MODE)
2436 		cent_x -= (map_center_xoff + 1) / 2; // player is off center
2437 
2438 	mx = (mx - area.left) / 16;
2439 	my = (my - area.top) / 16;
2440 	uint16 dist_x = abs(mx - cent_x), dist_y = abs(my - cent_y);
2441 
2442 	rel_x = rel_y = 0;
2443 	if (dist_x <= 4 && dist_y <= 4) {
2444 		// use mapwindow coords (4,4 is center of mapwindow)
2445 		uint8 cursor_num = movement_array[(9 * (4 + (my - cent_y))) + (4 + (mx - cent_x))];
2446 		if (mptr) // set mouse-pointer number
2447 			*mptr = cursor_num;
2448 		if (cursor_num == 1) // nowhere
2449 			return;
2450 		if (cursor_num == 2) // up
2451 			rel_y = -1;
2452 		else if (cursor_num == 6) // down
2453 			rel_y = 1;
2454 		else if (cursor_num == 8) // left
2455 			rel_x = -1;
2456 		else if (cursor_num == 4) // right
2457 			rel_x = 1;
2458 		else if (cursor_num == 3) { // up-right
2459 			rel_x = 1;
2460 			rel_y = -1;
2461 		} else if (cursor_num == 5) { // down-right
2462 			rel_x = 1;
2463 			rel_y = 1;
2464 		} else if (cursor_num == 7) { // down-left
2465 			rel_x = -1;
2466 			rel_y = 1;
2467 		} else if (cursor_num == 9) { // up-left
2468 			rel_x = -1;
2469 			rel_y = -1;
2470 		}
2471 	} else { // mapwindow is larger than the array; use 4 squares around center array
2472 		if (dist_x <= 4 && my < cent_y) { // up
2473 			rel_y = -1;
2474 			if (mptr) *mptr = 2;
2475 		} else if (dist_x <= 4 && my > cent_y) { // down
2476 			rel_y = 1;
2477 			if (mptr) *mptr = 6;
2478 		} else if (mx < cent_x && dist_y <= 4) { // left
2479 			rel_x = -1;
2480 			if (mptr) *mptr = 8;
2481 		} else if (mx > cent_x && dist_y <= 4) { // right
2482 			rel_x = 1;
2483 			if (mptr) *mptr = 4;
2484 		} else if (mx > cent_x && my < cent_y) { // up-right
2485 			rel_x = 1;
2486 			rel_y = -1;
2487 			if (mptr) *mptr = 3;
2488 		} else if (mx > cent_x && my > cent_y) { // down-right
2489 			rel_x = 1;
2490 			rel_y = 1;
2491 			if (mptr) *mptr = 5;
2492 		} else if (mx < cent_x && my > cent_y) { // down-left
2493 			rel_x = -1;
2494 			rel_y = 1;
2495 			if (mptr) *mptr = 7;
2496 		} else if (mx < cent_x && my < cent_y) { // up-left
2497 			rel_x = -1;
2498 			rel_y = -1;
2499 			if (mptr) *mptr = 9;
2500 		}
2501 	}
2502 }
2503 
2504 
2505 /* Revert mouse cursor to normal arrow. Stop walking. */
MouseLeave(uint8 state)2506 GUI_status MapWindow::MouseLeave(uint8 state) {
2507 	if (game_type == NUVIE_GAME_MD) // magnifying glass - pointer 0 should be used too for some areas
2508 		game->set_mouse_pointer(1);
2509 	else
2510 		game->set_mouse_pointer(0);
2511 	walking = false;
2512 	dragging = false;
2513 	// NOTE: Don't clear selected_obj here! It's used to remove the object after
2514 	// dragging.
2515 	return (GUI_PASS);
2516 }
2517 
make_thumbnail()2518 byte *MapWindow::make_thumbnail() {
2519 	if (thumbnail)
2520 		return NULL;
2521 
2522 	new_thumbnail = true;
2523 
2524 	GUI::get_gui()->Display(); // this calls MapWindow::display() which in turn calls create_thumbnail(). :-)
2525 
2526 	return thumbnail;
2527 }
2528 
create_thumbnail()2529 void MapWindow::create_thumbnail() {
2530 	Common::Rect src_rect;
2531 
2532 	src_rect.setWidth(MAPWINDOW_THUMBNAIL_SIZE * MAPWINDOW_THUMBNAIL_SCALE);
2533 	src_rect.setHeight(src_rect.width());
2534 
2535 	src_rect.left = area.left + win_width * 8 - (src_rect.width() / 2); // area.left + (win_width * 16) / 2 - 120 / 2
2536 	src_rect.top = area.top + win_height * 8 - (src_rect.height() / 2); // area.top + (win_height * 16) / 2 - 120 / 2
2537 
2538 	thumbnail = screen->copy_area(&src_rect, MAPWINDOW_THUMBNAIL_SCALE); //scale down x3
2539 
2540 	new_thumbnail = false;
2541 }
2542 
free_thumbnail()2543 void MapWindow::free_thumbnail() {
2544 	if (thumbnail) {
2545 		delete[] thumbnail;
2546 		thumbnail = NULL;
2547 	}
2548 
2549 	return;
2550 }
2551 
2552 
2553 /* Returns a new 8bit copy of the mapwindow as displayed. Caller must free it. */
get_sdl_surface()2554 Graphics::ManagedSurface *MapWindow::get_sdl_surface() {
2555 	return (get_sdl_surface(0, 0, area.width(), area.height()));
2556 }
2557 
get_sdl_surface(uint16 x,uint16 y,uint16 w,uint16 h)2558 Graphics::ManagedSurface *MapWindow::get_sdl_surface(uint16 x, uint16 y, uint16 w, uint16 h) {
2559 	Graphics::ManagedSurface *new_surface = NULL;
2560 	byte *screen_area;
2561 	Common::Rect copy_area(area.left + x, area.top + y, area.left + x + w, area.top + y + h);
2562 
2563 	GUI::get_gui()->Display();
2564 	screen_area = screen->copy_area(&copy_area);
2565 
2566 	new_surface = screen->create_sdl_surface_8(screen_area, copy_area.width(), copy_area.height());
2567 // new_surface = screen->create_sdl_surface_from(screen_area, screen->get_bpp(),
2568 //                                               copy_area.w, copy_area.h,
2569 //                                               copy_area.w);
2570 	free(screen_area);
2571 	return (new_surface);
2572 }
2573 
2574 /* Returns the overlay surface. A new 8bit overlay is created if necessary. */
get_overlay()2575 Graphics::ManagedSurface *MapWindow::get_overlay() {
2576 	if (!overlay)
2577 		overlay = new Graphics::ManagedSurface(area.width(), area.height(),
2578 			Graphics::PixelFormat::createFormatCLUT8());
2579 
2580 	return (overlay);
2581 }
2582 
2583 /* Set the overlay surface. The current overlay is deleted if necessary. */
set_overlay(Graphics::ManagedSurface * surfpt)2584 void MapWindow::set_overlay(Graphics::ManagedSurface *surfpt) {
2585 	if (overlay && (overlay != surfpt))
2586 		SDL_FreeSurface(overlay);
2587 	overlay = surfpt;
2588 }
2589 
2590 /* Returns true if town tiles are within 5 tiles of the player */
in_town()2591 bool MapWindow::in_town() {
2592 	MapCoord player_loc = actor_manager->get_player()->get_location();
2593 
2594 	for (Std::vector<TileInfo>::iterator ti = m_ViewableMapTiles.begin();
2595 	        ti != m_ViewableMapTiles.end(); ti++)
2596 		if (MapCoord((*ti).x + cur_x, (*ti).y + cur_y, cur_level).distance(player_loc) <= 5 && // make sure tile is close enough
2597 		        ((*ti).t->flags1 & TILEFLAG_WALL) && ((*ti).t->flags1 & TILEFLAG_WALL_MASK)) { //only wall tiles with wall direction bits set.
2598 			return true;
2599 		}
2600 	return false;
2601 }
2602 
wizard_eye_start(MapCoord location,uint16 duration,CallBack * caller)2603 void MapWindow::wizard_eye_start(MapCoord location, uint16 duration, CallBack *caller) {
2604 	wizard_eye_info.moves_left = duration;
2605 	wizard_eye_info.caller = caller;
2606 
2607 	wizard_eye_info.prev_x = cur_x;
2608 	wizard_eye_info.prev_y = cur_y;
2609 
2610 	set_x_ray_view(X_RAY_ON);
2611 	sint16 map_x = location.x - (win_width / 2);
2612 	if (game->is_original_plus_full_map())
2613 		map_x += ((map_center_xoff + 1) / 2);
2614 	moveMap(map_x, location.y - (win_height / 2) , cur_level); // FIXME - map should already be centered on the caster so why are we doing this?
2615 	grab_focus();
2616 }
2617 
wizard_eye_stop()2618 void MapWindow::wizard_eye_stop() {
2619 	if (wizard_eye_info.moves_left > 0) {
2620 		wizard_eye_info.moves_left = 0;
2621 		wizard_eye_update();
2622 	}
2623 }
2624 
wizard_eye_update()2625 void MapWindow::wizard_eye_update() {
2626 	if (wizard_eye_info.moves_left > 0)
2627 		wizard_eye_info.moves_left--;
2628 
2629 	if (wizard_eye_info.moves_left == 0) {
2630 		set_x_ray_view(X_RAY_OFF);
2631 		moveMap(wizard_eye_info.prev_x, wizard_eye_info.prev_y, cur_level);
2632 		wizard_eye_info.caller->callback(EFFECT_CB_COMPLETE, (CallBack *)this, NULL);
2633 		release_focus();
2634 	}
2635 }
2636 
set_roof_mode(bool roofs)2637 void MapWindow::set_roof_mode(bool roofs) {
2638 	roof_mode = roofs;
2639 	if (roof_mode) {
2640 		if (roof_tiles)
2641 			return;
2642 		else
2643 			loadRoofTiles();
2644 	} else {
2645 		if (roof_tiles) {
2646 			SDL_FreeSurface(roof_tiles);
2647 			roof_tiles = NULL;
2648 		}
2649 	}
2650 }
2651 
loadRoofTiles()2652 void MapWindow::loadRoofTiles() {
2653 	Std::string imagefile = map->getRoofTilesetFilename();
2654 	roof_tiles = SDL_LoadBMP(imagefile.c_str());
2655 	if (roof_tiles && game->is_orig_style()) {
2656 		SDL_SetColorKey(roof_tiles, SDL_TRUE, SDL_MapRGB(roof_tiles->format, 0, 0x70, 0xfc));
2657 	}
2658 }
2659 
in_dungeon_level()2660 bool MapWindow::in_dungeon_level() {
2661 	if (game_type == NUVIE_GAME_MD) {
2662 		return (cur_level == 1 || cur_level > 3); //FIXME this should probably be moved into script.
2663 	}
2664 	return (cur_level != 0 && cur_level != 5);
2665 }
2666 
2667 } // End of namespace Nuvie
2668 } // End of namespace Ultima
2669