00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifdef HAVE_CONFIG_H
00022 # include <config.h>
00023 #endif
00024
00025 #include "SDL_events.h"
00026 #include "SDL_keyboard.h"
00027
00028 #include "Configuration.h"
00029 #include "exult.h"
00030 #include "Gump.h"
00031 #include "Gump_manager.h"
00032 #include "gamewin.h"
00033
00034 #include "Actor_gump.h"
00035 #include "Paperdoll_gump.h"
00036 #include "Spellbook_gump.h"
00037 #include "Stats_gump.h"
00038 #include "CombatStats_gump.h"
00039 #include "Jawbone_gump.h"
00040 #include "npcnear.h"
00041 #include "actors.h"
00042 #include "game.h"
00043 #include "Audio.h"
00044 #include "Yesno_gump.h"
00045 #include "gump_utils.h"
00046 #include "Slider_gump.h"
00047
00048 using std::cout;
00049 using std::endl;
00050
00051 Gump_manager::Gump_manager()
00052 : open_gumps(0), non_persistent_count(0), modal_gump_count(0), right_click_close(true), dont_pause_game(false)
00053 {
00054 std::string str;
00055 config->value("config/gameplay/right_click_closes_gumps", str, "yes");
00056 if (str == "no")
00057 right_click_close = false;
00058 config->set("config/gameplay/right_click_closes_gumps", str, true);
00059
00060 config->value("config/gameplay/gumps_dont_pause_game", str, "no");
00061 dont_pause_game = str == "yes";
00062 config->set("config/gameplay/gumps_dont_pause_game", dont_pause_game?"yes":"no", true);
00063 }
00064
00065
00066
00067
00068
00069
00070 bool Gump_manager::showing_gumps(bool no_pers) const
00071 {
00072
00073 if (!no_pers || !open_gumps) return open_gumps != 0;
00074
00075
00076 for (Gump_list *gump = open_gumps; gump; gump = gump->next)
00077 if (!gump->gump->is_persistent()) return true;
00078
00079 return false;
00080 }
00081
00082
00083
00084
00085
00086
00087
00088
00089 Gump *Gump_manager::find_gump
00090 (
00091 int x, int y,
00092 bool pers
00093 )
00094 {
00095 Gump_list *gmp;
00096 Gump *found = 0;
00097 for (gmp = open_gumps; gmp; gmp = gmp->next)
00098 {
00099 Gump *gump = gmp->gump;
00100 if (gump->has_point(x,y) && (pers || !gump->is_persistent()))
00101 found = gump;
00102 }
00103 return (found);
00104 }
00105
00106
00107
00108
00109
00110 Gump *Gump_manager::find_gump
00111 (
00112 Game_object *obj
00113 )
00114 {
00115
00116 Game_object *owner = obj->get_owner();
00117 if (!owner)
00118 return (0);
00119
00120 for (Gump_list *gmp = open_gumps; gmp; gmp = gmp->next)
00121 if (gmp->gump->get_container() == owner)
00122 return (gmp->gump);
00123 return (0);
00124 }
00125
00126
00127
00128
00129
00130 Gump *Gump_manager::find_gump
00131 (
00132 Game_object *owner,
00133 int shapenum
00134 )
00135 {
00136 Gump_list *gmp;
00137 for (gmp = open_gumps; gmp; gmp = gmp->next)
00138 if (gmp->gump->get_owner() == owner &&
00139 gmp->gump->get_shapenum() == shapenum)
00140 return gmp->gump;
00141 return (0);
00142 }
00143
00144
00145
00146
00147
00148 void Gump_manager::add_gump(Gump *gump)
00149 {
00150 Gump_list *g = new Gump_list(gump);
00151
00152 if (!open_gumps)
00153 open_gumps = g;
00154 else
00155 {
00156 Gump_list *last = open_gumps;
00157 while (last->next) last = last->next;
00158 last->next = g;
00159 }
00160 if (!gump->is_persistent())
00161 {
00162 non_persistent_count++;
00163 if (!dont_pause_game) gwin->get_tqueue()->pause(Game::get_ticks());
00164 }
00165 }
00166
00167
00168
00169
00170
00171 bool Gump_manager::close_gump(Gump *gump)
00172 {
00173 bool ret = remove_gump(gump);
00174 delete gump;
00175 return ret;
00176 }
00177
00178
00179
00180
00181
00182 bool Gump_manager::remove_gump(Gump *gump)
00183 {
00184 if (open_gumps)
00185 {
00186 if (open_gumps->gump == gump)
00187 {
00188 Gump_list *p = open_gumps->next;
00189 delete open_gumps;
00190 open_gumps = p;
00191 }
00192 else
00193 {
00194 Gump_list *p = open_gumps;
00195 while (p->next != 0 && p->next->gump != gump) p = p->next;
00196
00197 if (p->next)
00198 {
00199 Gump_list *g = p->next->next;
00200 delete p->next;
00201 p->next = g;
00202 }
00203 else
00204 return true;
00205 }
00206 if (!gump->is_persistent())
00207 {
00208
00209 if (non_persistent_count > 0)
00210 non_persistent_count--;
00211 if (!dont_pause_game) gwin->get_tqueue()->resume(Game::get_ticks());
00212 }
00213 }
00214
00215 return false;
00216 }
00217
00218
00219
00220
00221
00222 void Gump_manager::add_gump
00223 (
00224 Game_object *obj,
00225 int shapenum
00226 )
00227 {
00228 int paperdoll = 0;
00229
00230 if (shapenum >= ACTOR_FIRST_GUMP && shapenum <= ACTOR_LAST_GUMP
00231 && Game::get_game_type() == BLACK_GATE)
00232 paperdoll = 1;
00233
00234
00235 if (shapenum == 123 && (Game::get_game_type() == SERPENT_ISLE ||
00236 (sman->can_use_paperdolls() && sman->get_bg_paperdolls())))
00237 paperdoll=2;
00238
00239 Gump *dragged = gwin->get_dragging_gump();
00240
00241
00242 if (dragged && dragged->get_owner() == obj && dragged->get_shapenum() == shapenum)
00243 return;
00244
00245 static int cnt = 0;
00246 Gump_list *gmp;
00247 for (gmp = open_gumps; gmp; gmp = gmp->next)
00248 if (gmp->gump->get_owner() == obj &&
00249 gmp->gump->get_shapenum() == shapenum)
00250 break;
00251
00252 if (gmp)
00253 {
00254 if (gmp->next)
00255 {
00256 Gump *gump = gmp->gump;
00257 remove_gump(gump);
00258 add_gump(gump);
00259 }
00260 gwin->paint();
00261 return;
00262 }
00263
00264 int x = (1 + cnt)*gwin->get_width()/10,
00265 y = (1 + cnt)*gwin->get_height()/10;
00266
00267 ShapeID s_id(shapenum, 0, paperdoll == 2 ? SF_PAPERDOL_VGA : SF_GUMPS_VGA);
00268 Shape_frame *shape = s_id.get_shape();
00269
00270 if (x + shape->get_xright() > gwin->get_width() ||
00271 y + shape->get_ybelow() > gwin->get_height())
00272 {
00273 cnt = 0;
00274 x = gwin->get_width()/10;
00275 y = gwin->get_width()/10;
00276 }
00277
00278 Gump *new_gump = 0;
00279 Actor *npc = 0;
00280 if (obj)
00281 npc = obj->as_actor();
00282 if (npc && paperdoll == 2)
00283 new_gump = new Paperdoll_gump(npc, x, y, npc->get_npc_num());
00284 else if (npc && paperdoll)
00285 new_gump = new Actor_gump(npc, x, y, shapenum);
00286 else if (shapenum == game->get_shape("gumps/statsdisplay"))
00287 new_gump = new Stats_gump((Container_game_object *) obj, x, y);
00288 else if (shapenum == game->get_shape("gumps/spellbook"))
00289 new_gump = new Spellbook_gump((Spellbook_object *) obj);
00290 else if (Game::get_game_type() == SERPENT_ISLE)
00291 {
00292 if (shapenum == game->get_shape("gumps/spell_scroll"))
00293 new_gump = new Spellscroll_gump(obj);
00294 else if (shapenum >= game->get_shape("gumps/cstats/1")&&
00295 shapenum <= game->get_shape("gumps/cstats/6"))
00296 new_gump = new CombatStats_gump(x, y);
00297 else if (shapenum == game->get_shape("gumps/jawbone"))
00298 new_gump = new Jawbone_gump(
00299 (Jawbone_object*) obj, x, y);
00300 }
00301
00302 if (!new_gump)
00303 new_gump = new Container_gump((Container_game_object *) obj, x, y, shapenum);
00304
00305
00306 add_gump(new_gump);
00307 if (++cnt == 8)
00308 cnt = 0;
00309 int sfx = Audio::game_sfx(14);
00310 Audio::get_ptr()->play_sound_effect(sfx);
00311 gwin->paint();
00312 }
00313
00314
00315
00316
00317
00318 void Gump_manager::close_all_gumps
00319 (
00320 bool pers
00321 )
00322 {
00323 bool removed = false;
00324
00325 Gump_list *prev = 0;
00326 Gump_list *next = open_gumps;
00327
00328 while (next)
00329 {
00330 Gump_list *gump = next;
00331 next = gump->next;
00332
00333
00334 if ((!gump->gump->is_persistent() || pers) &&
00335 !gump->gump->is_modal())
00336 {
00337 if (!gump->gump->is_persistent())
00338 gwin->get_tqueue()->resume(Game::get_ticks());
00339 if (prev) prev->next = gump->next;
00340 else open_gumps = gump->next;
00341 delete gump->gump;
00342 delete gump;
00343 removed = true;
00344 }
00345 else
00346 prev = gump;
00347 }
00348 non_persistent_count = 0;
00349 gwin->get_npc_prox()->wait(4);
00350 if (removed) gwin->paint();
00351 }
00352
00353
00354
00355
00356
00357
00358 bool Gump_manager::double_clicked
00359 (
00360 int x, int y,
00361 Game_object *&obj
00362 )
00363 {
00364 Gump *gump = find_gump(x, y);
00365
00366 if (gump)
00367 {
00368 obj = gump->find_object(x, y);
00369 if (!obj)
00370 {
00371 Gump_button *btn = gump->on_button(x, y);
00372 if (btn) btn->double_clicked(x, y);
00373 else if (gwin->get_double_click_closes_gumps())
00374 {
00375 gump->close();
00376 gwin->paint();
00377 }
00378 }
00379 return true;
00380 }
00381
00382 return false;
00383 }
00384
00385
00386
00387
00388 void Gump_manager::update_gumps()
00389 {
00390 for (Gump_list *gmp = open_gumps; gmp; gmp = gmp->next)
00391 gmp->gump->update_gump();
00392 }
00393
00394
00395
00396
00397 void Gump_manager::paint()
00398 {
00399 for (Gump_list *gmp = open_gumps; gmp; gmp = gmp->next)
00400 gmp->gump->paint();
00401 }
00402
00403
00404
00405
00406
00407
00408
00409 int Gump_manager::okay_to_quit()
00410 {
00411 if (Yesno_gump::ask("Do you really want to quit?"))
00412 quitting_time = QUIT_TIME_YES;
00413 return quitting_time;
00414 }
00415
00416
00417 int Gump_manager::handle_modal_gump_event
00418 (
00419 Modal_gump *gump,
00420 SDL_Event& event
00421 )
00422 {
00423
00424 int scale_factor = gwin->get_fastmouse() ? 1
00425 : gwin->get_win()->get_scale();
00426 static bool rightclick;
00427
00428 switch (event.type)
00429 {
00430 case SDL_MOUSEBUTTONDOWN:
00431 #ifdef DEBUG
00432 cout << "(x,y) rel. to gump is (" << ((event.button.x / scale_factor) - gump->get_x())
00433 << ", " << ((event.button.y / scale_factor) - gump->get_y()) << ")"<<endl;
00434 #endif
00435 if (event.button.button == 1)
00436 gump->mouse_down(event.button.x / scale_factor,
00437 event.button.y / scale_factor);
00438 else if (event.button.button == 2 && gwin->get_mouse3rd()) {
00439 gump->key_down(SDLK_RETURN);
00440 gump->text_input(SDLK_RETURN, SDLK_RETURN);
00441 } else if (event.button.button == 3)
00442 rightclick = true;
00443 else if (event.button.button == 4)
00444 gump->mousewheel_up();
00445 else if (event.button.button == 5)
00446 gump->mousewheel_down();
00447 break;
00448 case SDL_MOUSEBUTTONUP:
00449 if (event.button.button == 1)
00450 gump->mouse_up(event.button.x / scale_factor,
00451 event.button.y / scale_factor);
00452 else if (event.button.button == 3 && gwin->get_mouse3rd() && rightclick) {
00453 rightclick = false;
00454 if (gumpman->can_right_click_close()) return 0;
00455 }
00456 break;
00457 case SDL_MOUSEMOTION:
00458 Mouse::mouse->move(event.motion.x / scale_factor, event.motion.y / scale_factor);
00459 Mouse::mouse_update = true;
00460
00461 if (event.motion.state & SDL_BUTTON(1))
00462 gump->mouse_drag(event.motion.x / scale_factor,
00463 event.motion.y / scale_factor);
00464 break;
00465 case SDL_QUIT:
00466 if (okay_to_quit())
00467 return (0);
00468 case SDL_KEYDOWN:
00469 {
00470 if (event.key.keysym.sym == SDLK_ESCAPE)
00471 return (0);
00472 if ((event.key.keysym.sym == SDLK_s) &&
00473 (event.key.keysym.mod & KMOD_ALT) &&
00474 (event.key.keysym.mod & KMOD_CTRL)) {
00475 make_screenshot(true);
00476 return 1;
00477 }
00478
00479 int chr = event.key.keysym.sym;
00480 #if 0
00481 gump->key_down((event.key.keysym.mod & KMOD_SHIFT)
00482 ? toupper(chr) : chr, event);
00483 #else
00484 gump->key_down(event.key.keysym.sym);
00485 gump->text_input(event.key.keysym.sym, event.key.keysym.unicode);
00486 #endif
00487
00488 break;
00489 }
00490 }
00491 return (1);
00492 }
00493
00494
00495
00496
00497
00498
00499
00500
00501 int Gump_manager::do_modal_gump
00502 (
00503 Modal_gump *gump,
00504 Mouse::Mouse_shapes shape,
00505 Paintable *paint
00506 )
00507 {
00508 if (!modal_gump_count)
00509 SDL_EnableUNICODE(1);
00510 modal_gump_count++;
00511
00512
00513
00514
00515
00516
00517
00518
00519 gwin->get_tqueue()->pause(SDL_GetTicks());
00520
00521 Mouse::Mouse_shapes saveshape = Mouse::mouse->get_shape();
00522 if (shape != Mouse::dontchange)
00523 Mouse::mouse->set_shape(shape);
00524 int escaped = 0;
00525 add_gump(gump);
00526 gwin->paint();
00527 if (paint)
00528 paint->paint();
00529 Mouse::mouse->show();
00530 gwin->show();
00531 do
00532 {
00533 Delay();
00534 Mouse::mouse->hide();
00535 Mouse::mouse_update = false;
00536 SDL_Event event;
00537 while (!escaped && !gump->is_done() && SDL_PollEvent(&event))
00538 escaped = !handle_modal_gump_event(gump, event);
00539 if (GL_manager::get_instance())
00540 {
00541 gwin->paint();
00542 if (paint)
00543 paint->paint();
00544 }
00545 Mouse::mouse->show();
00546 if (!gwin->show() &&
00547 Mouse::mouse_update)
00548 Mouse::mouse->blit_dirty();
00549 }
00550 while (!gump->is_done() && !escaped);
00551 Mouse::mouse->hide();
00552 remove_gump(gump);
00553 Mouse::mouse->set_shape(saveshape);
00554
00555 gwin->paint();
00556 gwin->show(true);
00557
00558
00559 gwin->get_tqueue()->resume(SDL_GetTicks());
00560
00561 modal_gump_count--;
00562
00563 if (!modal_gump_count)
00564 SDL_EnableUNICODE(0);
00565
00566 return (!escaped);
00567 }
00568
00569
00570
00571
00572
00573
00574
00575
00576 int Gump_manager::prompt_for_number
00577 (
00578 int minval, int maxval,
00579 int step,
00580 int defval,
00581 Paintable *paint
00582 )
00583 {
00584 Slider_gump *slider = new Slider_gump(minval, maxval,
00585 step, defval);
00586 int ok = do_modal_gump(slider, Mouse::hand, paint);
00587 int ret = !ok ? 0 : slider->get_val();
00588 delete slider;
00589 return (ret);
00590 }
00591
00592
00593
00594
00595
00596
00597 void Gump_manager::paint_num
00598 (
00599 int num,
00600 int x,
00601 int y
00602 )
00603 {
00604
00605 const int font = 2;
00606 char buf[20];
00607 snprintf(buf, 20, "%d", num);
00608 sman->paint_text(font, buf, x - sman->get_text_width(font, buf), y);
00609 }
00610
00611
00612
00613
00614 void Gump_manager::set_gumps_dont_pause_game(bool p)
00615 {
00616
00617 if (dont_pause_game == p) return;
00618
00619 dont_pause_game = p;
00620
00621
00622 if (!dont_pause_game) {
00623 for (Gump_list *gump = open_gumps; gump; gump = gump->next)
00624 if (!gump->gump->is_persistent())
00625 gwin->get_tqueue()->pause(Game::get_ticks());
00626 }
00627
00628 else {
00629 for (Gump_list *gump = open_gumps; gump; gump = gump->next)
00630 if (!gump->gump->is_persistent())
00631 gwin->get_tqueue()->resume(Game::get_ticks());
00632 }
00633 }