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/gui/gui.h"
27 #include "ultima/nuvie/views/view_manager.h"
28 #include "ultima/nuvie/actors/actor.h"
29 #include "ultima/nuvie/views/actor_view.h"
30 #include "ultima/nuvie/views/portrait_view.h"
31 #include "ultima/nuvie/views/inventory_view.h"
32 #include "ultima/nuvie/views/doll_view_gump.h"
33 #include "ultima/nuvie/views/container_view_gump.h"
34 #include "ultima/nuvie/views/portrait_view_gump.h"
35 #include "ultima/nuvie/views/sign_view_gump.h"
36 #include "ultima/nuvie/views/scroll_view_gump.h"
37 #include "ultima/nuvie/views/party_view.h"
38 #include "ultima/nuvie/views/spell_view.h"
39 #include "ultima/nuvie/views/spell_view_gump.h"
40 #include "ultima/nuvie/views/sun_moon_ribbon.h"
41 #include "ultima/nuvie/gui/widgets/map_window.h"
42 #include "ultima/nuvie/views/map_editor_view.h"
43 #include "ultima/nuvie/gui/widgets/msg_scroll.h"
44 #include "ultima/nuvie/core/party.h"
45 #include "ultima/nuvie/core/events.h"
46 #include "ultima/nuvie/portraits/portrait.h"
47 #include "ultima/nuvie/usecode/usecode.h"
48 #include "ultima/nuvie/files/nuvie_bmp_file.h"
49 #include "ultima/nuvie/views/md_sky_strip_widget.h"
50 
51 namespace Ultima {
52 namespace Nuvie {
53 
ViewManager(Configuration * cfg)54 ViewManager::ViewManager(Configuration *cfg) {
55 	config = cfg;
56 	config->value("config/GameType", game_type);
57 	current_view = NULL;
58 	gui = NULL;
59 	font = NULL;
60 	tile_manager = NULL;
61 	obj_manager = NULL;
62 	party = NULL;
63 	portrait = NULL;
64 	actor_view = NULL;
65 	inventory_view = NULL;
66 	portrait_view = NULL;
67 	party_view = NULL;
68 	spell_view = NULL;
69 	doll_next_party_member = 0;
70 	ribbon = NULL;
71 	mdSkyWidget = NULL;
72 }
73 
~ViewManager()74 ViewManager::~ViewManager() {
75 // only delete the views that are not currently active
76 	if (current_view != actor_view)     delete actor_view;
77 	if (current_view != inventory_view) delete inventory_view;
78 	if (current_view != party_view)     delete party_view;
79 	if (current_view != portrait_view)  delete portrait_view;
80 	if (current_view != spell_view)  delete spell_view;
81 
82 }
83 
init(GUI * g,Font * f,Party * p,Player * player,TileManager * tm,ObjManager * om,Portrait * por)84 bool ViewManager::init(GUI *g, Font *f, Party *p, Player *player, TileManager *tm, ObjManager *om, Portrait *por) {
85 	gui = g;
86 	font = f;
87 	party = p;
88 	tile_manager = tm;
89 	obj_manager = om;
90 	portrait = por;
91 
92 	uint16 x_off = Game::get_game()->get_game_x_offset();
93 	uint16 y_off = Game::get_game()->get_game_y_offset();
94 	if (Game::get_game()->is_original_plus())
95 		x_off += Game::get_game()->get_game_width() - 320;
96 
97 	inventory_view = new InventoryView(config);
98 	inventory_view->init(gui->get_screen(), this, 176 + x_off, 8 + y_off, font, party, tile_manager, obj_manager);
99 
100 	portrait_view = new PortraitView(config);
101 	portrait_view->init(176 + x_off, 8 + y_off, font, party, player, tile_manager, obj_manager, portrait);
102 
103 	if (!Game::get_game()->is_new_style()) {
104 		//inventory_view = new InventoryView(config);
105 		//inventory_view->init(gui->get_screen(), this, 176+x_off,8+y_off, font, party, tile_manager, obj_manager);
106 		actor_view = new ActorView(config);
107 		actor_view->init(gui->get_screen(), this, 176 + x_off, 8 + y_off, font, party, tile_manager, obj_manager, portrait);
108 
109 		party_view = new PartyView(config);
110 		if (game_type == NUVIE_GAME_U6) {
111 			party_view->init(this, 168 + x_off, 6 + y_off, font, party, player, tile_manager, obj_manager);
112 			spell_view = new SpellView(config);
113 		} else {
114 			party_view->init(this, 176 + x_off, 6 + y_off, font, party, player, tile_manager, obj_manager);
115 		}
116 		if (game_type == NUVIE_GAME_MD) {
117 			if (Game::get_game()->is_new_style() == false) {
118 				mdSkyWidget = new MDSkyStripWidget(config, Game::get_game()->get_clock(), player);
119 				mdSkyWidget->init(32 + x_off, 2 + y_off);
120 				gui->AddWidget(mdSkyWidget);
121 				if (Game::get_game()->is_original_plus())
122 					mdSkyWidget->Hide();
123 			}
124 		}
125 	} else {
126 		//inventory_view = new InventoryViewGump(config);
127 		//inventory_view->init(gui->get_screen(), this, 176+x_off,8+y_off, font, party, tile_manager, obj_manager);
128 		if (game_type == NUVIE_GAME_U6) {
129 			spell_view = new SpellViewGump(config);
130 			ribbon = new SunMoonRibbon(player, Game::get_game()->get_weather(), tile_manager);
131 			ribbon->init(gui->get_screen());
132 			gui->AddWidget(ribbon);
133 			ribbon->Hide(); //will be shown on first call to update()
134 		}
135 	}
136 
137 	uint16 spell_x_offset = 168 + x_off;
138 	if (Game::get_game()->is_new_style()) {
139 		spell_x_offset = Game::get_game()->get_game_width() - SPELLVIEWGUMP_WIDTH + x_off;
140 	}
141 
142 	if (spell_view) {
143 		spell_view->init(gui->get_screen(), this, spell_x_offset, 6 + y_off, font, party, tile_manager, obj_manager);
144 	}
145 //set_current_view((View *)party_view);
146 
147 	return true;
148 }
149 
reload()150 void ViewManager::reload() {
151 	if (!Game::get_game()->is_new_style())
152 		actor_view->set_party_member(0);
153 	inventory_view->lock_to_actor(false);
154 	inventory_view->set_party_member(0);
155 
156 	set_party_mode();
157 	update();
158 }
159 
set_current_view(View * view)160 bool ViewManager::set_current_view(View *view) {
161 	uint8 cur_party_member;
162 
163 //actor_view->set_party_member(cur_party_member);
164 	if (view == NULL) // || game_type != NUVIE_GAME_U6) //HACK! remove this when views support MD and SE
165 		return false;
166 
167 	if (current_view == view) // nothing to do if view is already the current_view.
168 		return false;
169 
170 	if (current_view != NULL) {
171 		gui->removeWidget((GUI_Widget *)current_view);//remove current widget from gui
172 
173 		cur_party_member = current_view->get_party_member_num();
174 		view->set_party_member(cur_party_member);
175 	}
176 
177 	current_view = view;
178 	view->Show();
179 	gui->AddWidget((GUI_Widget *)view);
180 	view->Redraw();
181 	gui->Display();
182 
183 	if (actor_view) {
184 		if (view != actor_view) {
185 			actor_view->set_show_cursor(false);
186 			actor_view->release_focus();
187 		}
188 	}
189 
190 	if (inventory_view) {
191 		if (view != inventory_view) {
192 			inventory_view->set_show_cursor(false);
193 			inventory_view->release_focus();
194 		}
195 	}
196 
197 	return true;
198 }
199 
close_current_view()200 void ViewManager::close_current_view() {
201 	if (current_view == NULL)
202 		return;
203 
204 	gui->removeWidget((GUI_Widget *)current_view);//remove current widget from gui
205 	current_view = NULL;
206 }
207 
update()208 void ViewManager::update() {
209 	if (current_view)
210 		current_view->Redraw();
211 
212 	if (ribbon && ribbon->Status() == WIDGET_HIDDEN) {
213 		ribbon->Show();
214 	}
215 
216 	if (mdSkyWidget) {
217 		mdSkyWidget->Redraw();
218 	}
219 
220 	return;
221 }
222 
223 // We only change to portrait mode if the actor has a portrait.
set_portrait_mode(Actor * actor,const char * name)224 void ViewManager::set_portrait_mode(Actor *actor, const char *name) {
225 	if (portrait_view->set_portrait(actor, name) == true) {
226 		set_current_view((View *)portrait_view);
227 	}
228 }
229 
set_inventory_mode()230 void ViewManager::set_inventory_mode() {
231 	set_current_view((View *)inventory_view);
232 	Events *event = Game::get_game()->get_event();
233 	if (event->get_mode() == EQUIP_MODE || event->get_mode() == INPUT_MODE
234 	        || event->get_mode() == ATTACK_MODE)
235 		inventory_view->set_show_cursor(true);
236 }
237 
set_party_mode()238 void ViewManager::set_party_mode() {
239 	Events *event = Game::get_game()->get_event();
240 	if (event->get_mode() == EQUIP_MODE)
241 		event->cancelAction();
242 	else if (event->get_mode() == INPUT_MODE || event->get_mode() == ATTACK_MODE)
243 		event->moveCursorToMapWindow();
244 
245 	if (!Game::get_game()->is_new_style())
246 		set_current_view((View *)party_view);
247 	return;
248 }
249 
set_actor_mode()250 void ViewManager::set_actor_mode() {
251 	set_current_view((View *)actor_view);
252 	Events *event = Game::get_game()->get_event();
253 	if (event->get_mode() == EQUIP_MODE || event->get_mode() == INPUT_MODE
254 	        || event->get_mode() == ATTACK_MODE) {
255 		actor_view->set_show_cursor(true);
256 		actor_view->moveCursorToButton(2);
257 	}
258 }
259 
set_spell_mode(Actor * caster,Obj * spell_container,bool eventMode)260 void ViewManager::set_spell_mode(Actor *caster, Obj *spell_container, bool eventMode) {
261 	if (spell_view != NULL) {
262 		spell_view->set_spell_caster(caster, spell_container, eventMode);
263 		set_current_view((View *)spell_view);
264 	}
265 	return;
266 }
267 
close_spell_mode()268 void ViewManager::close_spell_mode() {
269 	if (spell_view) {
270 		//FIXME this should set previous view. Don't default to inventory view.
271 		spell_view->release_focus();
272 		if (!Game::get_game()->is_new_style())
273 			set_inventory_mode();
274 		else
275 			close_current_view();
276 	}
277 }
278 
open_doll_view(Actor * actor)279 void ViewManager::open_doll_view(Actor *actor) {
280 	Screen *screen = Game::get_game()->get_screen();
281 
282 	if (Game::get_game()->is_new_style()) {
283 		if (actor == NULL) {
284 			actor = doll_view_get_next_party_member();
285 		}
286 		DollViewGump *doll = get_doll_view(actor);
287 		if (doll == NULL) {
288 			uint16 x_off = Game::get_game()->get_game_x_offset();
289 			uint16 y_off = Game::get_game()->get_game_y_offset();
290 			uint8 num_doll_gumps = doll_gumps.size();
291 			doll = new DollViewGump(config);
292 			uint16 x = 12 * num_doll_gumps;
293 			uint16 y = 12 * num_doll_gumps;
294 
295 			if (y + DOLLVIEWGUMP_HEIGHT > screen->get_height())
296 				y = screen->get_height() - DOLLVIEWGUMP_HEIGHT;
297 
298 			doll->init(Game::get_game()->get_screen(), this, x + x_off, y + y_off, actor, font, party, tile_manager, obj_manager);
299 
300 			add_view((View *)doll);
301 			add_gump(doll);
302 			doll_gumps.push_back(doll);
303 		} else {
304 			move_gump_to_top(doll);
305 		}
306 	}
307 }
308 
doll_view_get_next_party_member()309 Actor *ViewManager::doll_view_get_next_party_member() {
310 	if (doll_gumps.empty()) {
311 		doll_next_party_member = 0; //reset to first party member when there are no doll gumps on screen.
312 	}
313 	Actor *a = party->get_actor(doll_next_party_member);
314 	doll_next_party_member = (doll_next_party_member + 1) % party->get_party_size();
315 
316 	return a;
317 }
318 
get_doll_view(Actor * actor)319 DollViewGump *ViewManager::get_doll_view(Actor *actor) {
320 	Std::list<DraggableView *>::iterator iter;
321 	for (iter = doll_gumps.begin(); iter != doll_gumps.end(); iter++) {
322 		DollViewGump *view = (DollViewGump *)*iter;
323 		if (view->get_actor() == actor) {
324 			return view;
325 		}
326 	}
327 
328 	return NULL;
329 }
330 
get_container_view(Actor * actor,Obj * obj)331 ContainerViewGump *ViewManager::get_container_view(Actor *actor, Obj *obj) {
332 	Std::list<DraggableView *>::iterator iter;
333 	for (iter = container_gumps.begin(); iter != container_gumps.end(); iter++) {
334 		ContainerViewGump *view = (ContainerViewGump *)*iter;
335 		if (actor) {
336 			if (view->is_actor_container() && view->get_actor() == actor) {
337 				return view;
338 			}
339 		} else if (obj) {
340 			if (!view->is_actor_container() && view->get_container_obj() == obj) {
341 				return view;
342 			}
343 		}
344 	}
345 
346 	return NULL;
347 }
348 
open_container_view(Actor * actor,Obj * obj)349 void ViewManager::open_container_view(Actor *actor, Obj *obj) {
350 	ContainerViewGump *view = get_container_view(actor, obj);
351 
352 	if (view == NULL) {
353 		uint16 x_off = Game::get_game()->get_game_x_offset();
354 		uint16 y_off = Game::get_game()->get_game_y_offset();
355 		uint16 container_x, container_y;
356 		if (!Game::get_game()->is_new_style()) {
357 			container_x = x_off;
358 			container_y = y_off;
359 		} else {
360 			container_x = Game::get_game()->get_game_width() - 120 + x_off;
361 			container_y = 20 + y_off;
362 		}
363 
364 		view = new ContainerViewGump(config);
365 		view->init(Game::get_game()->get_screen(), this, container_x, container_y, font, party, tile_manager, obj_manager, obj);
366 		if (actor)
367 			view->set_actor(actor);
368 		else
369 			view->set_container_obj(obj);
370 
371 		container_gumps.push_back(view);
372 		add_gump(view);
373 		add_view((View *)view);
374 	} else {
375 		move_gump_to_top(view);
376 	}
377 }
378 
close_container_view(Actor * actor)379 void ViewManager::close_container_view(Actor *actor) {
380 	ContainerViewGump *view = get_container_view(actor, NULL);
381 
382 	if (view) {
383 		close_gump(view);
384 	}
385 }
386 
open_mapeditor_view()387 void ViewManager::open_mapeditor_view() {
388 	if (Game::get_game()->is_new_style() && Game::get_game()->is_roof_mode()) {
389 		uint16 x_off = Game::get_game()->get_game_x_offset();
390 		uint16 y_off = Game::get_game()->get_game_y_offset();
391 		x_off += Game::get_game()->get_game_width() - 90;
392 		MapEditorView *view = new MapEditorView(config);
393 		view->init(Game::get_game()->get_screen(), this, x_off , y_off, font, party, tile_manager, obj_manager);
394 		add_view((View *)view);
395 		view->grab_focus();
396 	}
397 }
398 
open_portrait_gump(Actor * a)399 void ViewManager::open_portrait_gump(Actor *a) {
400 	if (Game::get_game()->is_new_style()) {
401 		uint16 x_off = Game::get_game()->get_game_x_offset();
402 		uint16 y_off = Game::get_game()->get_game_y_offset();
403 		PortraitViewGump *view = new PortraitViewGump(config);
404 		view->init(Game::get_game()->get_screen(), this, 62 + x_off, y_off, font, party, tile_manager, obj_manager, portrait, a);
405 		add_view((View *)view);
406 		add_gump(view);
407 		view->grab_focus();
408 	}
409 }
410 
open_sign_gump(const char * sign_text,uint16 length)411 void ViewManager::open_sign_gump(const char *sign_text, uint16 length) {
412 	if (Game::get_game()->is_using_text_gumps()) { // check should be useless
413 		SignViewGump *view = new SignViewGump(config);
414 		view->init(Game::get_game()->get_screen(), this, font, party, tile_manager, obj_manager, sign_text, length);
415 		add_view((View *)view);
416 		add_gump(view);
417 		view->grab_focus();
418 	}
419 }
420 
open_scroll_gump(const char * text,uint16 length)421 void ViewManager::open_scroll_gump(const char *text, uint16 length) {
422 	if (Game::get_game()->is_using_text_gumps()) { // check should be useless
423 		ScrollViewGump *view = new ScrollViewGump(config);
424 		view->init(Game::get_game()->get_screen(), this, font, party, tile_manager, obj_manager, string(text, length));
425 		add_view((View *)view);
426 		add_gump(view);
427 		view->grab_focus();
428 	}
429 }
430 
add_view(View * view)431 void ViewManager::add_view(View *view) {
432 	view->Show();
433 	gui->AddWidget((GUI_Widget *)view);
434 	if (Game::get_game()->is_new_style()) {
435 		Game::get_game()->get_scroll()->moveToFront();
436 	}
437 	view->Redraw();
438 	gui->Display();
439 }
440 
add_gump(DraggableView * gump)441 void ViewManager::add_gump(DraggableView *gump) {
442 	gumps.push_back(gump);
443 	Game::get_game()->get_map_window()->set_walking(false);
444 	if (ribbon) {
445 		ribbon->extend();
446 	}
447 }
448 
close_gump(DraggableView * gump)449 void ViewManager::close_gump(DraggableView *gump) {
450 	gumps.remove(gump);
451 	container_gumps.remove(gump);
452 	doll_gumps.remove(gump);
453 
454 	gump->close_view();
455 	gump->Delete();
456 	//gui->removeWidget((GUI_Widget *)gump);
457 
458 	if (gumps.empty() && ribbon != NULL) {
459 		ribbon->retract();
460 	}
461 }
462 
close_all_gumps()463 void ViewManager::close_all_gumps() {
464 	Std::list<DraggableView *>::iterator iter;
465 	for (iter = gumps.begin(); iter != gumps.end();) {
466 		DraggableView *gump = *iter;
467 		iter++;
468 
469 		close_gump(gump);
470 	}
471 	//TODO make sure all gump objects have been deleted by GUI.
472 }
473 
move_gump_to_top(DraggableView * gump)474 void ViewManager::move_gump_to_top(DraggableView *gump) {
475 	gump->moveToFront();
476 	Game::get_game()->get_scroll()->moveToFront();
477 }
478 
479 // callbacks for switching views
480 
partyViewButtonCallback(void * data)481 GUI_status partyViewButtonCallback(void *data) {
482 	ViewManager *view_manager;
483 
484 	view_manager = (ViewManager *)data;
485 
486 	view_manager->set_party_mode();
487 
488 	return GUI_YUM;
489 }
490 
actorViewButtonCallback(void * data)491 GUI_status actorViewButtonCallback(void *data) {
492 	ViewManager *view_manager;
493 
494 	view_manager = (ViewManager *)data;
495 
496 	view_manager->set_actor_mode();
497 
498 	return GUI_YUM;
499 }
500 
inventoryViewButtonCallback(void * data)501 GUI_status inventoryViewButtonCallback(void *data) {
502 	ViewManager *view_manager;
503 
504 	view_manager = (ViewManager *)data;
505 
506 	view_manager->set_inventory_mode();
507 
508 	return GUI_YUM;
509 }
510 
double_click_obj(Obj * obj)511 void ViewManager::double_click_obj(Obj *obj) {
512 	Events *event = Game::get_game()->get_event();
513 	if (Game::get_game()->get_usecode()->is_readable(obj)) { // look at a scroll or book
514 		event->set_mode(LOOK_MODE);
515 		event->look(obj);
516 		event->endAction(false); // FIXME: should be in look()
517 	} else if (event->newAction(USE_MODE))
518 		event->select_obj(obj);
519 }
520 
get_display_weight(float weight)521 unsigned int ViewManager::get_display_weight(float weight) {
522 	if (weight > 1)
523 		return static_cast<unsigned int>(roundf(weight));
524 	else if (weight > 0)
525 		return 1;
526 	else // weight == 0 (or somehow negative)
527 		return 0;
528 }
529 
530 // beginning of custom doll functions shared between DollWidget and DollViewGump
getDollDataDirString()531 Std::string ViewManager::getDollDataDirString() {
532 	if (!DollDataDirString.empty())
533 		return DollDataDirString;
534 	DollDataDirString = GUI::get_gui()->get_data_dir();
535 	Std::string path;
536 	build_path(DollDataDirString, "images", path);
537 	DollDataDirString = path;
538 	build_path(DollDataDirString, "gumps", path);
539 	DollDataDirString = path;
540 	build_path(DollDataDirString, "doll", path);
541 	DollDataDirString = path;
542 
543 	return DollDataDirString;
544 }
545 
loadAvatarDollImage(Graphics::ManagedSurface * avatar_doll,bool orig)546 Graphics::ManagedSurface *ViewManager::loadAvatarDollImage(Graphics::ManagedSurface *avatar_doll, bool orig) {
547 	char filename[17]; //avatar_nn_nn.bmp\0
548 	Std::string imagefile;
549 	uint8 portrait_num = Game::get_game()->get_portrait()->get_avatar_portrait_num();
550 
551 	sprintf(filename, "avatar_%s_%02d.bmp", get_game_tag(Game::get_game()->get_game_type()), portrait_num);
552 	if (orig) {
553 		build_path(getDollDataDirString(), "orig_style", imagefile);
554 		build_path(imagefile, filename, imagefile);
555 	} else {
556 		build_path(getDollDataDirString(), filename, imagefile);
557 	}
558 	if (avatar_doll != NULL)
559 		SDL_FreeSurface(avatar_doll);
560 	NuvieBmpFile bmp;
561 	avatar_doll = bmp.getSdlSurface32(imagefile);
562 	if (avatar_doll == NULL)
563 		avatar_doll = loadGenericDollImage(orig);
564 	return avatar_doll;
565 }
566 
loadCustomActorDollImage(Graphics::ManagedSurface * actor_doll,uint8 actor_num,bool orig)567 Graphics::ManagedSurface *ViewManager::loadCustomActorDollImage(Graphics::ManagedSurface *actor_doll, uint8 actor_num, bool orig) {
568 	char filename[17]; //actor_nn_nnn.bmp\0
569 	Std::string imagefile;
570 
571 	if (actor_doll != NULL)
572 		SDL_FreeSurface(actor_doll);
573 
574 	sprintf(filename, "actor_%s_%03d.bmp", get_game_tag(Game::get_game()->get_game_type()), actor_num);
575 	if (orig) {
576 		build_path(getDollDataDirString(), "orig_style", imagefile);
577 		build_path(imagefile, filename, imagefile);
578 	} else {
579 		build_path(getDollDataDirString(), filename, imagefile);
580 	}
581 	NuvieBmpFile bmp;
582 	actor_doll = bmp.getSdlSurface32(imagefile);
583 
584 	if (actor_doll == NULL)
585 		actor_doll = loadGenericDollImage(orig);
586 	return actor_doll;
587 }
588 
loadGenericDollImage(bool orig)589 Graphics::ManagedSurface *ViewManager::loadGenericDollImage(bool orig) {
590 	char filename[14]; //avatar_nn.bmp\0
591 	Std::string imagefile;
592 
593 	sprintf(filename, "actor_%s.bmp", get_game_tag(Game::get_game()->get_game_type()));
594 	if (orig) {
595 		build_path(getDollDataDirString(), "orig_style", imagefile);
596 		build_path(imagefile, filename, imagefile);
597 	} else {
598 		build_path(getDollDataDirString(), filename, imagefile);
599 	}
600 	NuvieBmpFile bmp;
601 	return bmp.getSdlSurface32(imagefile);
602 }
603 
604 } // End of namespace Nuvie
605 } // End of namespace Ultima
606