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