00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #ifdef HAVE_CONFIG_H
00028 # include <config.h>
00029 #endif
00030
00031 #ifndef ALPHA_LINUX_CXX
00032 # include <cstdlib>
00033 # include <cstring>
00034 # include <cstdarg>
00035 # include <cstdio>
00036 #endif
00037
00038 #include "Astar.h"
00039 #include "Audio.h"
00040 #include "Configuration.h"
00041 #include "Face_stats.h"
00042 #include "Flex.h"
00043 #include "Gump.h"
00044 #include "Gump_manager.h"
00045 #include "actions.h"
00046 #include "monsters.h"
00047 #include "animate.h"
00048 #include "barge.h"
00049 #include "bodies.h"
00050 #include "cheat.h"
00051 #include "chunks.h"
00052 #include "chunkter.h"
00053 #include "combat_opts.h"
00054 #include "delobjs.h"
00055 #include "dir.h"
00056 #include "effects.h"
00057 #include "egg.h"
00058 #include "exult.h"
00059 #include "files/U7file.h"
00060 #include "flic/playfli.h"
00061 #include "fnames.h"
00062 #include "game.h"
00063 #include "gamewin.h"
00064 #include "gamemap.h"
00065 #include "gameclk.h"
00066 #include "gamerend.h"
00067 #include "items.h"
00068 #include "jawbone.h"
00069 #include "keys.h"
00070 #include "mouse.h"
00071 #include "npcnear.h"
00072 #include "objiter.h"
00073 #include "paths.h"
00074 #include "schedule.h"
00075 #include "spellbook.h"
00076 #include "ucmachine.h"
00077 #include "ucsched.h"
00078 #include "utils.h"
00079 #include "virstone.h"
00080 #include "mappatch.h"
00081 #include "version.h"
00082 #include "drag.h"
00083 #include "glshape.h"
00084 #include "party.h"
00085
00086 #ifdef USE_EXULTSTUDIO
00087 #include "server.h"
00088 #include "servemsg.h"
00089 #include "objserial.h"
00090 #endif
00091
00092 #ifndef UNDER_CE
00093 using std::cerr;
00094 using std::cout;
00095 using std::endl;
00096 using std::istream;
00097 using std::ifstream;
00098 using std::ios;
00099 using std::memcpy;
00100 using std::memset;
00101 using std::ofstream;
00102 using std::rand;
00103 using std::strcmp;
00104 using std::strcpy;
00105 using std::string;
00106 using std::strlen;
00107 using std::srand;
00108 using std::vector;
00109 #endif
00110
00111
00112 Game_window *Game_window::game_window = 0;
00113
00114
00115
00116
00117 class Background_noise : public Time_sensitive
00118 {
00119 int repeats;
00120 int last_sound;
00121 Game_window *gwin;
00122 int laststate;
00123
00124
00125 public:
00126 Background_noise(Game_window *gw) : repeats(0), last_sound(-1),
00127 gwin(gw), laststate(0)
00128 { gwin->get_tqueue()->add(5000, this, 0L); }
00129 virtual ~Background_noise()
00130 { gwin->get_tqueue()->remove(this); }
00131 virtual void handle_event(unsigned long curtime, long udata);
00132 };
00133
00134
00135
00136
00137
00138 void Background_noise::handle_event
00139 (
00140 unsigned long curtime,
00141 long udata
00142 )
00143 {
00144 Main_actor *ava = gwin->get_main_actor();
00145 unsigned long delay = 8000;
00146 int currentstate = 0;
00147
00148 #ifndef COLOURLESS_REALLY_HATES_THE_BG_SFX
00149
00150 int bghour = gwin->get_clock()->get_hour();
00151 if(gwin->is_in_dungeon())
00152 currentstate = 2;
00153 else
00154 if (bghour < 6 || bghour > 20)
00155 currentstate = 3;
00156 else
00157 currentstate = 1;
00158
00159 MyMidiPlayer *player = Audio::get_ptr()->get_midi();
00160 if (player && player->get_output_driver_type() == MIDI_DRIVER_OGG)
00161 {
00162 delay = 1500;
00163
00164
00165 int curr_track = player->get_current_track();
00166
00167 if(curr_track == 7 && currentstate == 3)
00168 {
00169
00170 delay = 3000 + rand()%5000;
00171 Audio::get_ptr()->play_sound_effect(61, MIX_MAX_VOLUME - 30);
00172 }
00173
00174 if((curr_track == -1 || laststate != currentstate ) && Audio::get_ptr()->is_music_enabled())
00175 {
00176 if(curr_track == -1 || (curr_track >=4 && curr_track <=8) || curr_track == 52)
00177 {
00178 int tracknum=255;
00179
00180
00181 if(gwin->is_in_dungeon())
00182 {
00183
00184 if(Game::get_game_type() == BLACK_GATE)
00185 tracknum = 52;
00186 else
00187 tracknum = 42;
00188 laststate = 2;
00189 }
00190 else
00191 {
00192 if (bghour < 6 || bghour > 20)
00193 {
00194 if(Game::get_game_type() == BLACK_GATE)
00195 tracknum = 7;
00196 else
00197 tracknum = 66;
00198 laststate = 3;
00199 }
00200 else
00201 {
00202
00203 if(Game::get_game_type() == BLACK_GATE)
00204 tracknum = 6;
00205 else
00206 tracknum = 67;
00207 laststate = 1;
00208 }
00209 }
00210 Audio::get_ptr()->start_music(tracknum,1);
00211 }
00212 }
00213 }
00214 else
00215 {
00216
00217
00218
00219
00220 if(player && player->get_current_track() >=4 &&
00221 player->get_current_track() <= 8)
00222 player->stop_music();
00223
00224
00225
00226
00227 if (ava && !gwin->is_main_actor_inside() &&
00228
00229 Game::get_game_type() == BLACK_GATE )
00230 {
00231 int sound;
00232 static unsigned char bgnight[] = {61, 61, 255},
00233 bgday[] = {82, 85, 85};
00234 if (repeats > 0)
00235 sound = last_sound;
00236 else
00237 {
00238 int hour = gwin->get_clock()->get_hour();
00239 if (hour < 6 || hour > 20)
00240 sound = bgnight[rand()%sizeof(bgnight)];
00241 else
00242 sound = bgday[rand()%sizeof(bgday)];
00243
00244 sound = Audio::game_sfx(sound);
00245 last_sound = sound;
00246 }
00247 Audio::get_ptr()->play_sound_effect(sound);
00248 repeats++;
00249 if (rand()%(repeats + 1) == 0)
00250
00251 delay = 500 + rand()%1000;
00252 else
00253 {
00254 delay = 4000 + rand()%3000;
00255 repeats = 0;
00256 }
00257 }
00258 }
00259 #endif
00260
00261 gwin->get_tqueue()->add(curtime + delay, this, udata);
00262 }
00263
00264
00265
00266
00267
00268 static void Set_renderer
00269 (
00270 Image_window8 *win,
00271 Palette *pal
00272 )
00273 {
00274 GL_manager *glman = GL_manager::get_instance();
00275 #ifdef HAVE_OPENGL
00276 delete glman;
00277 glman = 0;
00278 if (win->get_scaler() == Image_window::OpenGL)
00279 {
00280 glman = new GL_manager();
00281
00282 pal->load(PALETTES_FLX, 0);
00283
00284 unsigned char *newpal = new unsigned char[768];
00285 for (int i = 0; i < 256; i++)
00286 {
00287 newpal[3*i] = 4*pal->get_red(i);
00288 newpal[3*i+1] = 4*pal->get_green(i);
00289 newpal[3*i+2] = 4*pal->get_blue(i);
00290 }
00291 glman->set_palette(newpal);
00292 glman->resized(win->get_width(), win->get_height(),
00293 win->get_scale());
00294 }
00295 #endif
00296
00297 Shape_frame::set_to_render(win->get_ib8(), glman);
00298 }
00299
00300
00301
00302
00303
00304 Game_window::Game_window
00305 (
00306 int width, int height, int scale, int scaler
00307 ) :
00308 win(0), map(new Game_map()), pal(0),
00309 usecode(0), combat(false), armageddon(false),
00310 walk_in_formation(false),
00311 tqueue(new Time_queue()), time_stopped(0),
00312 std_delay(c_std_delay),
00313 npc_prox(new Npc_proximity_handler(this)),
00314 effects(new Effects_manager(this)),
00315 gump_man(new Gump_manager), render(new Game_render),
00316 party_man(new Party_manager),
00317 painted(false), focus(true),
00318 in_dungeon(0), ice_dungeon(false),
00319 moving_barge(0), main_actor(0), skip_above_actor(31),
00320 npcs(0), bodies(0), mouse3rd(false), fastmouse(false),
00321 text_bg(false), step_tile_delta(8), allow_double_right_move(true),
00322 special_light(0),
00323 dragging(0),
00324 theft_warnings(0), theft_cx(255), theft_cy(255),
00325 background_noise(new Background_noise(this)),
00326 double_click_closes_gumps(false),
00327 removed(new Deleted_objects()),
00328 skip_lift(16), paint_eggs(false), debug(0), camera_actor(0)
00329 #ifdef RED_PLASMA
00330 ,load_palette_timer(0), plasma_start_color(0), plasma_cycle_range(0)
00331 #endif
00332 {
00333 game_window = this;
00334 clock = new Game_clock(tqueue);
00335 shape_man = new Shape_manager();
00336
00337 string fullscreenstr;
00338 config->value("config/video/fullscreen",fullscreenstr,"no");
00339 bool fullscreen = (fullscreenstr=="yes");
00340 config->set("config/video/fullscreen",fullscreenstr,true);
00341 win = new Image_window8(width, height, scale, fullscreen, scaler);
00342 win->set_title("Exult Ultima7 Engine");
00343 pal = new Palette();
00344 Game_singletons::init(this);
00345 Set_renderer(win, pal);
00346
00347 string str;
00348 config->value("config/gameplay/textbackground", text_bg, -1);
00349 config->value("config/gameplay/mouse3rd", str, "no");
00350 if (str == "yes")
00351 mouse3rd = true;
00352 config->set("config/gameplay/mouse3rd", str, true);
00353 config->value("config/gameplay/fastmouse", str, "no");
00354 if (str == "yes")
00355 fastmouse = true;
00356 config->set("config/gameplay/fastmouse", str, true);
00357 config->value("config/gameplay/double_click_closes_gumps", str, "no");
00358 if (str == "yes")
00359 double_click_closes_gumps = true;
00360 config->set("config/gameplay/double_click_closes_gumps", str, true);
00361 config->value("config/gameplay/combat/difficulty",
00362 Combat::difficulty, 0);
00363 config->set("config/gameplay/combat/difficulty",
00364 Combat::difficulty, true);
00365 config->value("config/gameplay/combat/mode", str, "original");
00366 if (str == "keypause")
00367 Combat::mode = Combat::keypause;
00368 else
00369 Combat::mode = Combat::original;
00370 config->set("config/gameplay/combat/mode", str, true);
00371 config->value("config/gameplay/combat/show_hits", str, "no");
00372 Combat::show_hits = (str == "yes");
00373 config->set("config/gameplay/combat/show_hits", str, true);
00374 config->value("config/audio/disablepause", str, "no");
00375 config->set("config/audio/disablepause", str, true);
00376
00377 config->value("config/gameplay/step_tile_delta", step_tile_delta, 8);
00378 if (step_tile_delta < 1) step_tile_delta = 1;
00379 config->set("config/gameplay/step_tile_delta", step_tile_delta, true);
00380
00381 config->value("config/gameplay/allow_double_right_move", str, "yes");
00382 allow_double_right_move = str == "yes";
00383 config->set("config/gameplay/allow_double_right_move",
00384 allow_double_right_move?"yes":"no", true);
00385
00386 config->value("config/gameplay/formation", str, "yes");
00387
00388 walk_in_formation = true;
00389 config->set("config/gameplay/formation", walk_in_formation?"yes":"no",
00390 true);
00391 }
00392
00393
00394
00395
00396 void Game_window::clear_screen(bool update)
00397 {
00398 win->fill8(0,get_width(),get_height(),0,0);
00399
00400
00401 if (update)
00402 show(1);
00403 }
00404
00405
00406
00407
00408
00409
00410
00411 Game_window::~Game_window
00412 (
00413 )
00414 {
00415 gump_man->close_all_gumps(true);
00416 clear_world();
00417 int i;
00418 for (i = 0; i < sizeof(save_names)/sizeof(save_names[0]); i++)
00419 delete [] save_names[i];
00420 delete shape_man;
00421 delete gump_man;
00422 delete party_man;
00423 delete background_noise;
00424 delete tqueue;
00425 delete win;
00426 delete dragging;
00427 delete pal;
00428 delete map;
00429 delete usecode;
00430 delete removed;
00431 delete clock;
00432 }
00433
00434
00435
00436
00437
00438 void Game_window::abort
00439 (
00440 const char *msg,
00441 ...
00442 )
00443 {
00444 std::va_list ap;
00445 va_start(ap, msg);
00446 char buf[512];
00447 vsprintf(buf, msg, ap);
00448 cerr << "Exult (fatal): " << buf << endl;
00449 delete this;
00450 throw quit_exception(-1);
00451 }
00452
00453 #if 0
00454 #define BLEND(alpha, newc, oldc) ((newc*255L) - (oldc*(255L-alpha)))/alpha
00455 void Analyze_xform(unsigned char *xform, int alpha, Palette *pal)
00456 {
00457 long br = 0, bg = 0, bb = 0;
00458 for (int i = 0; i < 256; i++)
00459 {
00460 int xi = xform[i];
00461 br += BLEND(alpha, pal->get_red(xi), pal->get_red(i));
00462 bg += BLEND(alpha, pal->get_green(xi), pal->get_green(i));
00463 bb += BLEND(alpha, pal->get_blue(xi), pal->get_blue(i));
00464 }
00465 br /= 256;
00466 bg /= 256;
00467 bb /= 256;
00468 cout << "Blend (r,g,b) = " << br << ',' << bg << ',' << bb << endl;
00469 }
00470 #endif
00471
00472
00473 void Game_window::init_files(bool cycle)
00474 {
00475
00476 #ifdef RED_PLASMA
00477
00478 if (cycle)
00479 setup_load_palette();
00480 #endif
00481
00482 usecode = Usecode_machine::create();
00483 Game_singletons::init(this);
00484
00485 CYCLE_RED_PLASMA();
00486 shape_man->load();
00487 CYCLE_RED_PLASMA();
00488
00489 ifstream textflx, exultmsg;
00490 if (is_system_path_defined("<PATCH>") && U7exists(PATCH_TEXT))
00491 U7open(textflx, PATCH_TEXT);
00492 else
00493 U7open(textflx, TEXT_FLX);
00494 if (U7exists(EXULTMSG))
00495 U7open(exultmsg, EXULTMSG, true);
00496 Setup_item_names(textflx, exultmsg);
00497 unsigned long timer = SDL_GetTicks();
00498 srand(timer);
00499
00500 tqueue->add(timer, clock, reinterpret_cast<long>(this));
00501
00502 scrolltx = game->get_start_tile_x();
00503 scrollty = game->get_start_tile_y();
00504
00505
00506 if (keybinder)
00507 delete keybinder;
00508 keybinder = new KeyBinder();
00509
00510 std::string d, keyfilename;
00511 d = "config/disk/game/"+Game::get_gametitle()+"/keys";
00512 config->value(d.c_str(),keyfilename,"(default)");
00513 if (keyfilename == "(default)") {
00514 config->set(d.c_str(), keyfilename, true);
00515 keybinder->LoadDefaults();
00516 } else {
00517 keybinder->LoadFromFile(keyfilename.c_str());
00518 }
00519
00520 CYCLE_RED_PLASMA();
00521
00522
00523
00524
00525 int fps;
00526 config->value("config/video/fps", fps, 5);
00527 if (fps <= 0)
00528 fps = 5;
00529 std_delay = 1000/fps;
00530 }
00531
00532
00533
00534
00535 Map_patch_collection *Game_window::get_map_patches()
00536 {
00537 return map->get_map_patches();
00538 }
00539
00540
00541
00542
00543
00544 void Game_window::set_moving_barge
00545 (
00546 Barge_object *b
00547 )
00548 {
00549 if (b && b != moving_barge)
00550 b->gather();
00551 else if (!b && moving_barge)
00552 moving_barge->done();
00553 moving_barge = b;
00554 }
00555
00556
00557
00558
00559
00560 bool Game_window::is_moving
00561 (
00562 )
00563 {
00564 return moving_barge ? moving_barge->is_moving()
00565 : main_actor->is_moving();
00566 }
00567
00568
00569
00570
00571
00572 bool Game_window::main_actor_dont_move()
00573 {
00574 return main_actor->get_flag(Obj_flags::dont_move) != 0;
00575 }
00576
00577
00578
00579
00580
00581 void Game_window::add_special_light
00582 (
00583 int units
00584 )
00585 {
00586 if (!special_light)
00587 {
00588 special_light = clock->get_total_minutes();
00589 clock->set_palette();
00590 }
00591 special_light += units/20;
00592 }
00593
00594
00595
00596
00597
00598 void Game_window::set_time_stopped
00599 (
00600 long delay
00601
00602
00603 )
00604 {
00605 if (delay == -1)
00606 time_stopped = -1;
00607 else if (!delay)
00608 time_stopped = 0;
00609 else
00610 {
00611 long new_expire = Game::get_ticks() + delay;
00612 if (new_expire > time_stopped)
00613 time_stopped = new_expire;
00614 }
00615 }
00616
00617
00618
00619
00620
00621 long Game_window::check_time_stopped
00622 (
00623 )
00624 {
00625 if (time_stopped == -1)
00626 return 3000;
00627 long delay = time_stopped - Game::get_ticks();
00628 if (delay > 0)
00629 return delay;
00630 time_stopped = 0;
00631 return 0;
00632 }
00633
00634
00635
00636
00637
00638 void Game_window::toggle_combat
00639 (
00640 )
00641 {
00642 combat = !combat;
00643
00644 int newsched = combat ? Schedule::combat : Schedule::follow_avatar;
00645 int cnt = party_man->get_count();
00646 for (int i = 0; i < cnt; i++)
00647 {
00648 int party_member=party_man->get_member(i);
00649 Actor *person=get_npc(party_member);
00650 if (!person)
00651 continue;
00652 int sched = person->get_schedule_type();
00653 if (sched != newsched && sched != Schedule::wait &&
00654 sched != Schedule::loiter)
00655 person->set_schedule_type(newsched);
00656 }
00657 if (main_actor->get_schedule_type() != newsched)
00658 main_actor->set_schedule_type(newsched);
00659 if (combat)
00660 {
00661 set_moving_barge(0);
00662 Actor *all[9];
00663 int cnt = get_party(all, 1);
00664 for (int i = 0; i < cnt; i++)
00665 {
00666 Actor *act = all[i];
00667 if (act->get_attack_mode() == Actor::flee &&
00668 !act->did_user_set_attack())
00669 act->set_attack_mode(Actor::nearest);
00670
00671
00672 Game_object *targ = act->get_target();
00673 if (targ && targ->get_flag(Obj_flags::in_party))
00674 act->set_target(0);
00675 }
00676 }
00677 else
00678 Combat::resume();
00679 }
00680
00681
00682
00683
00684
00685 void Game_window::add_npc
00686 (
00687 Actor *npc,
00688 int num
00689 )
00690 {
00691 assert(num == npc->get_npc_num());
00692 assert(num <= npcs.size());
00693 if (num == npcs.size())
00694 npcs.append(npc);
00695 else
00696 {
00697 assert(!npcs[num] || npcs[num]->is_unused());
00698 delete npcs[num];
00699 npcs[num] = npc;
00700 }
00701 }
00702
00703
00704
00705
00706
00707 int Game_window::get_unused_npc
00708 (
00709 )
00710 {
00711 int cnt = npcs.size();
00712 for (int i = 0; i < cnt; i++)
00713 {
00714 if (!npcs[i])
00715 return i;
00716 if (npcs[i]->is_unused())
00717 return i;
00718 }
00719 return cnt;
00720 }
00721
00722
00723
00724
00725
00726 void Game_window::resized
00727 (
00728 unsigned int neww,
00729 unsigned int newh,
00730 unsigned int newsc,
00731 unsigned int newsclr
00732 )
00733 {
00734 win->resized(neww, newh, newsc, newsclr);
00735 pal->apply(false);
00736 Set_renderer(win, pal);
00737 if (!main_actor)
00738 return;
00739 center_view(main_actor->get_tile());
00740 paint();
00741
00742 if(!gump_man->gump_mode()) {
00743 char msg[80];
00744 snprintf(msg, 80, "%dx%dx%d", neww, newh, newsc);
00745 effects->center_text(msg);
00746 }
00747 }
00748
00749
00750
00751
00752
00753 void Game_window::clear_world
00754 (
00755 )
00756 {
00757 Combat::resume();
00758 tqueue->clear();
00759 clear_dirty();
00760 removed->flush();
00761 Usecode_script::clear();
00762 map->clear();
00763 Monster_actor::delete_all();
00764 main_actor = 0;
00765 camera_actor = 0;
00766 num_npcs1 = 0;
00767 theft_cx = theft_cy = -1;
00768 combat = 0;
00769 npcs.resize(0);
00770 bodies.resize(0);
00771 moving_barge = 0;
00772 special_light = 0;
00773 effects->remove_all_effects(false);
00774 }
00775
00776
00777
00778
00779
00780
00781
00782
00783 bool Game_window::locate_shape
00784 (
00785 int shapenum,
00786 bool upwards
00787 )
00788 {
00789
00790 const std::vector<Game_object *>& sel = cheat.get_selected();
00791 Game_object *start = sel.size() ? sel[0] : 0;
00792 char msg[80];
00793 snprintf(msg, sizeof(msg), "Searching for shape %d", shapenum);
00794 effects->center_text(msg);
00795 paint();
00796 show();
00797 Game_object *obj = map->locate_shape(shapenum, upwards, start);
00798 if (!obj)
00799 {
00800 effects->center_text("Not found");
00801 return false;
00802 }
00803 effects->remove_text_effects();
00804 cheat.clear_selected();
00805 cheat.append_selected(obj);
00806
00807 Game_object *owner = obj->get_outermost();
00808 if (owner != obj)
00809 cheat.append_selected(owner);
00810 center_view(owner->get_tile());
00811 return true;
00812 }
00813
00814
00815
00816
00817
00818 inline void Send_location
00819 (
00820 Game_window *gwin
00821 )
00822 {
00823 #ifdef USE_EXULTSTUDIO
00824 if (client_socket >= 0 &&
00825 cheat.in_map_editor())
00826 {
00827 unsigned char data[50];
00828 unsigned char *ptr = &data[0];
00829 Write4(ptr, gwin->get_scrolltx());
00830 Write4(ptr, gwin->get_scrollty());
00831 Write4(ptr, gwin->get_width()/c_tilesize);
00832 Write4(ptr, gwin->get_height()/c_tilesize);
00833 Write4(ptr, gwin->get_win()->get_scale());
00834 Exult_server::Send_data(client_socket, Exult_server::view_pos,
00835 &data[0], ptr - data);
00836 }
00837 #endif
00838 }
00839
00840
00841
00842
00843
00844 void Game_window::send_location
00845 (
00846 )
00847 {
00848 Send_location(this);
00849 }
00850
00851
00852
00853
00854
00855 void Game_window::set_scrolls
00856 (
00857 int newscrolltx, int newscrollty
00858 )
00859 {
00860 scrolltx = newscrolltx;
00861 scrollty = newscrollty;
00862
00863
00864 scroll_bounds.w = scroll_bounds.h = 2;
00865 scroll_bounds.x = scrolltx +
00866 (get_width()/c_tilesize - scroll_bounds.w)/2;
00867
00868 scroll_bounds.y = scrollty +
00869 ((get_height())/c_tilesize - scroll_bounds.h)/2;
00870
00871 Barge_object *old_active_barge = moving_barge;
00872 map->read_map_data();
00873
00874 if (!old_active_barge && moving_barge)
00875 {
00876 Barge_object *b = moving_barge;
00877 moving_barge = 0;
00878 set_moving_barge(b);
00879 }
00880
00881 int cx = camera_actor->get_cx(), cy = camera_actor->get_cy();
00882 Map_chunk *nlist = map->get_chunk(cx, cy);
00883 nlist->setup_cache();
00884 int tx = camera_actor->get_tx(), ty = camera_actor->get_ty();
00885 set_above_main_actor(nlist->is_roof (tx, ty,
00886 camera_actor->get_lift()));
00887 set_in_dungeon(nlist->has_dungeon()?nlist->is_dungeon(tx, ty):0);
00888 set_ice_dungeon(nlist->is_ice_dungeon(tx, ty));
00889 send_location();
00890 }
00891
00892
00893
00894
00895
00896
00897 void Game_window::set_scrolls
00898 (
00899 Tile_coord cent
00900 )
00901 {
00902
00903
00904 int tw = get_width()/c_tilesize, th = (get_height())/c_tilesize;
00905 set_scrolls(DECR_TILE(cent.tx, tw/2), DECR_TILE(cent.ty, th/2));
00906 }
00907
00908
00909
00910
00911
00912
00913 void Game_window::center_view
00914 (
00915 Tile_coord t
00916 )
00917 {
00918 set_scrolls(t);
00919 set_all_dirty();
00920 }
00921
00922
00923
00924
00925
00926 void Game_window::set_camera_actor
00927 (
00928 Actor *a
00929 )
00930 {
00931 if (a == main_actor &&
00932 camera_actor &&
00933 (camera_actor->get_cx() != main_actor->get_cx() ||
00934 camera_actor->get_cy() != main_actor->get_cy()))
00935
00936 emulate_cache(camera_actor->get_cx(), camera_actor->get_cy(),
00937 main_actor->get_cx(), main_actor->get_cy());
00938 camera_actor = a;
00939 Tile_coord t = a->get_tile();
00940 set_scrolls(t);
00941
00942 set_all_dirty();
00943 }
00944
00945
00946
00947
00948
00949
00950
00951 bool Game_window::scroll_if_needed
00952 (
00953 Tile_coord t
00954 )
00955 {
00956 bool scrolled = false;
00957
00958 int tx = t.tx - t.tz/2, ty = t.ty - t.tz/2;
00959 if (Tile_coord::gte(DECR_TILE(scroll_bounds.x), tx))
00960 {
00961 view_left();
00962 scrolled = true;
00963 }
00964 else if (Tile_coord::gte(tx,
00965 (scroll_bounds.x + scroll_bounds.w)%c_num_tiles))
00966 {
00967 view_right();
00968 scrolled = true;
00969 }
00970 if (Tile_coord::gte(DECR_TILE(scroll_bounds.y), ty))
00971 {
00972 view_up();
00973 scrolled = true;
00974 }
00975 else if (Tile_coord::gte(ty,
00976 (scroll_bounds.y + scroll_bounds.h)%c_num_tiles))
00977 {
00978 view_down();
00979 scrolled = true;
00980 }
00981 return (scrolled);
00982 }
00983
00984
00985
00986
00987
00988
00989 void Game_window::show_game_location
00990 (
00991 int x, int y
00992 )
00993 {
00994 x = get_scrolltx() + x/c_tilesize;
00995 y = get_scrollty() + y/c_tilesize;
00996 cout << "Game location is (" << x << ", " << y << ")"<<endl;
00997 }
00998
00999
01000
01001
01002
01003 Rectangle Game_window::get_shape_rect(Game_object *obj)
01004 {
01005 Shape_frame *s = obj->get_shape();
01006 if(!s)
01007 {
01008
01009 #if DEBUG
01010 std::cerr << "DEATH! get_shape() returned a NULL pointer: " << __FILE__ << ":" << __LINE__ << std::endl;
01011 std::cerr << "Betcha it's a little doggie." << std::endl;
01012 #endif
01013 return Rectangle(0,0,0,0);
01014 }
01015 Tile_coord t = obj->get_tile();
01016 int lftpix = 4*t.tz;
01017 t.tx += 1 - get_scrolltx();
01018 t.ty += 1 - get_scrollty();
01019
01020 if (t.tx < -c_num_tiles/2)
01021 t.tx += c_num_tiles;
01022 if (t.ty < -c_num_tiles/2)
01023 t.ty += c_num_tiles;
01024 return get_shape_rect(s,
01025 t.tx*c_tilesize - 1 - lftpix,
01026 t.ty*c_tilesize - 1 - lftpix);
01027 }
01028
01029
01030
01031
01032
01033 inline void Get_shape_location
01034 (
01035 Tile_coord t,
01036 int scrolltx, int scrollty,
01037 int& x, int& y
01038 )
01039 {
01040 int lft = 4*t.tz;
01041 t.tx += 1 - scrolltx;
01042 t.ty += 1 - scrollty;
01043
01044 if (t.tx < -c_num_tiles/2)
01045 t.tx += c_num_tiles;
01046 if (t.ty < -c_num_tiles/2)
01047 t.ty += c_num_tiles;
01048 x = t.tx*c_tilesize - 1 - lft;
01049 y = t.ty*c_tilesize - 1 - lft;
01050 }
01051
01052
01053
01054
01055
01056 void Game_window::get_shape_location(Game_object *obj, int& x, int& y)
01057 {
01058 Get_shape_location(obj->get_tile(), scrolltx, scrollty, x, y);
01059 }
01060 void Game_window::get_shape_location(Tile_coord t, int&x, int& y)
01061 {
01062 Get_shape_location(t, scrolltx, scrollty, x, y);
01063 }
01064
01065
01066
01067
01068
01069 void Game_window::init_actors
01070 (
01071 )
01072 {
01073 if (main_actor)
01074 {
01075 Game::clear_avname();
01076 Game::clear_avsex();
01077 Game::clear_avskin();
01078 return;
01079 }
01080 read_npcs();
01081
01082
01083
01084 bool changed = false;
01085
01086
01087 if (Game::get_avsex() == 0 || Game::get_avsex() == 1 || Game::get_avname()
01088 || (Game::get_avskin() >= 0 && Game::get_avskin() <= 2))
01089 changed = true;
01090
01091 Game::clear_avname();
01092 Game::clear_avsex();
01093 Game::clear_avskin();
01094
01095
01096 if (changed)
01097 {
01098 schedule_npcs(2,7,false);
01099 write_npcs();
01100 }
01101
01102 }
01103
01104
01105
01106
01107
01108
01109 bool Game_window::init_gamedat(bool create)
01110 {
01111
01112 if (create)
01113 {
01114 cout << "Creating 'gamedat' files."<<endl;
01115 if (is_system_path_defined("<PATCH>") &&
01116 U7exists(PATCH_INITGAME))
01117 restore_gamedat(PATCH_INITGAME);
01118 else
01119 {
01120
01121 Game::set_new_game();
01122 restore_gamedat(INITGAME);
01123 }
01124 ofstream out;
01125
01126 if (Game::is_editing() && !U7exists(IDENTITY))
01127 {
01128 U7open(out, IDENTITY);
01129 std::string gametitlestr = Game::get_gametitle();
01130 out << gametitlestr.c_str() << endl;
01131 out.close();
01132 }
01133
01134
01135 U7open(out, GNEWGAMEVER);
01136 getVersionInfo(out);
01137 out.close();
01138 }
01139
01140 else if ((U7exists(U7NBUF_DAT) || !U7exists(NPC_DAT)) &&
01141 !Game::is_editing())
01142 {
01143 return false;
01144 }
01145 else
01146 {
01147 ifstream identity_file;
01148 U7open(identity_file, IDENTITY);
01149 char gamedat_identity[256];
01150 identity_file.read(gamedat_identity, 256);
01151 char *ptr = gamedat_identity;
01152 for(; (*ptr!=0x1a && *ptr!=0x0d &&
01153 *ptr != 0x0a); ptr++)
01154 ;
01155 *ptr = 0;
01156 cout << "Gamedat identity " << gamedat_identity << endl;
01157 char *static_identity = get_game_identity(INITGAME);
01158 if(strcmp(static_identity, gamedat_identity))
01159 {
01160 delete [] static_identity;
01161 return false;
01162 }
01163 delete [] static_identity;
01164
01165 }
01166 read_save_names();
01167 return true;
01168 }
01169
01170
01171
01172
01173
01174
01175
01176 void Game_window::write
01177 (
01178 )
01179 {
01180
01181
01182 int width = get_width();
01183 int centre_x = width/2;
01184 int height = get_height();
01185 int centre_y = height/2;
01186 int text_height = shape_man->get_text_height(0);
01187 int text_width = shape_man->get_text_width(0, "Saving Game");
01188
01189 win->fill_translucent8(0, width, height, 0, 0,
01190 shape_man->get_xform(2));
01191 shape_man->paint_text(0, "Saving Game", centre_x-text_width/2,
01192 centre_y-text_height);
01193 show(true);
01194 map->write_ireg();
01195 write_npcs();
01196 usecode->write();
01197 write_gwin();
01198 write_saveinfo();
01199 }
01200
01201
01202
01203
01204
01205
01206
01207 void Game_window::read
01208 (
01209 )
01210 {
01211 Audio::get_ptr()->cancel_streams();
01212 #ifdef RED_PLASMA
01213
01214 setup_load_palette();
01215 #endif
01216
01217 clear_world();
01218 read_gwin();
01219
01220
01221 setup_game();
01222 }
01223
01224
01225
01226
01227
01228
01229
01230 void Game_window::write_gwin
01231 (
01232 )
01233 {
01234 ofstream gout_stream;
01235 U7open(gout_stream, GWINDAT);
01236 StreamDataSource gout(&gout_stream);
01237
01238 gout.write2(get_scrolltx());
01239 gout.write2(get_scrollty());
01240
01241 gout.write2(clock->get_day());
01242 gout.write2(clock->get_hour());
01243 gout.write2(clock->get_minute());
01244 gout.write4(special_light);
01245 MyMidiPlayer *player = Audio::get_ptr()->get_midi();
01246 if (player) {
01247 gout.write4(static_cast<uint32>(player->get_current_track()));
01248 gout.write4(static_cast<uint32>(player->is_repeating()));
01249 } else {
01250 gout.write4(static_cast<uint32>(-1));
01251 gout.write4(0);
01252 }
01253 gout.write1(armageddon ? 1 : 0);
01254 gout_stream.flush();
01255 if (!gout_stream.good())
01256 throw file_write_exception(GWINDAT);
01257 }
01258
01259
01260
01261
01262
01263
01264
01265 void Game_window::read_gwin
01266 (
01267 )
01268 {
01269 if (!clock->in_queue())
01270 tqueue->add(Game::get_ticks(), clock,
01271 reinterpret_cast<long>(this));
01272 ifstream gin_stream;
01273 try
01274 {
01275 U7open(gin_stream, GWINDAT);
01276 } catch (const file_open_exception&)
01277 {
01278 return;
01279 }
01280
01281 StreamDataSource gin(&gin_stream);
01282
01283
01284 scrolltx = gin.read2();
01285 scrollty = gin.read2();
01286
01287 clock->set_day(gin.read2());
01288 clock->set_hour(gin.read2());
01289 clock->set_minute(gin.read2());
01290 if (!gin_stream.good())
01291 throw file_read_exception(GWINDAT);
01292 special_light = gin.read4();
01293 armageddon = false;
01294
01295 if (!gin_stream.good())
01296 {
01297 special_light = 0;
01298 return;
01299 }
01300
01301 int track_num = gin.read4();
01302 int repeat = gin.read4();
01303 if (!gin_stream.good())
01304 {
01305 Audio::get_ptr()->stop_music();
01306 return;
01307 }
01308
01309 Audio::get_ptr()->start_music(track_num, repeat != false);
01310 armageddon = gin.read1() == 1 ? true : false;
01311 if (!gin_stream.good())
01312 armageddon = false;
01313
01314 }
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325 void Game_window::write_map
01326 (
01327 )
01328 {
01329 map->write_static();
01330 write();
01331 save_gamedat(PATCH_INITGAME, "Saved map");
01332 }
01333
01334
01335
01336
01337
01338 void Game_window::read_map
01339 (
01340 )
01341 {
01342 init_gamedat(true);
01343 read();
01344 }
01345
01346
01347
01348
01349
01350 void Game_window::reload_usecode
01351 (
01352 )
01353 {
01354
01355 if (is_system_path_defined("<PATCH>") && U7exists(PATCH_USECODE))
01356 {
01357 ifstream file;
01358 U7open(file, PATCH_USECODE);
01359 usecode->read_usecode(file, true);
01360 file.close();
01361 }
01362 }
01363
01364
01365
01366
01367
01368 void Game_window::view_right
01369 (
01370 )
01371 {
01372 int w = get_width(), h = get_height();
01373
01374 int old_rcx = ((scrolltx + (w - 1)/c_tilesize)/c_tiles_per_chunk)%
01375 c_num_chunks;
01376 scrolltx = INCR_TILE(scrolltx);
01377 scroll_bounds.x = INCR_TILE(scroll_bounds.x);
01378 if (gump_man->showing_gumps())
01379 {
01380 paint();
01381 return;
01382 }
01383 map->read_map_data();
01384 #ifdef HAVE_OPENGL
01385 if (GL_manager::get_instance())
01386 paint();
01387 else
01388 #endif
01389 {
01390
01391 win->copy(c_tilesize, 0, w - c_tilesize, h, 0, 0);
01392
01393 paint(w - c_tilesize, 0, c_tilesize, h);
01394 }
01395 dirty.x -= c_tilesize;
01396 dirty = clip_to_win(dirty);
01397
01398 int new_rcx = ((scrolltx + (w - 1)/c_tilesize)/c_tiles_per_chunk)%
01399 c_num_chunks;
01400 if (new_rcx != old_rcx)
01401 Send_location(this);
01402 }
01403 void Game_window::view_left
01404 (
01405 )
01406 {
01407 int old_lcx = (scrolltx/c_tiles_per_chunk)%c_num_chunks;
01408
01409 scrolltx = DECR_TILE(scrolltx);
01410 scroll_bounds.x = DECR_TILE(scroll_bounds.x);
01411 if (gump_man->showing_gumps())
01412 {
01413 paint();
01414 return;
01415 }
01416 map->read_map_data();
01417 #ifdef HAVE_OPENGL
01418 if (GL_manager::get_instance())
01419 paint();
01420 else
01421 #endif
01422 {
01423 win->copy(0, 0, get_width() - c_tilesize, get_height(),
01424 c_tilesize, 0);
01425 int h = get_height();
01426 paint(0, 0, c_tilesize, h);
01427 }
01428 dirty.x += c_tilesize;
01429 dirty = clip_to_win(dirty);
01430
01431 int new_lcx = (scrolltx/c_tiles_per_chunk)%c_num_chunks;
01432 if (new_lcx != old_lcx)
01433 Send_location(this);
01434 }
01435 void Game_window::view_down
01436 (
01437 )
01438 {
01439 int w = get_width(), h = get_height();
01440
01441 int old_bcy = ((scrollty + (h - 1)/c_tilesize)/c_tiles_per_chunk)%
01442 c_num_chunks;
01443 scrollty = INCR_TILE(scrollty);
01444 scroll_bounds.y = INCR_TILE(scroll_bounds.y);
01445 if (gump_man->showing_gumps())
01446 {
01447 paint();
01448 return;
01449 }
01450 map->read_map_data();
01451 #ifdef HAVE_OPENGL
01452 if (GL_manager::get_instance())
01453 paint();
01454 else
01455 #endif
01456 {
01457 win->copy(0, c_tilesize, w, h - c_tilesize, 0, 0);
01458 paint(0, h - c_tilesize, w, c_tilesize);
01459 }
01460 dirty.y -= c_tilesize;
01461 dirty = clip_to_win(dirty);
01462
01463 int new_bcy = ((scrollty + (h - 1)/c_tilesize)/c_tiles_per_chunk)%
01464 c_num_chunks;
01465 if (new_bcy != old_bcy)
01466 Send_location(this);
01467 }
01468 void Game_window::view_up
01469 (
01470 )
01471 {
01472 int old_tcy = (scrollty/c_tiles_per_chunk)%c_num_chunks;
01473
01474 scrollty = DECR_TILE(scrollty);
01475 scroll_bounds.y = DECR_TILE(scroll_bounds.y);
01476 if (gump_man->showing_gumps())
01477 {
01478 paint();
01479 return;
01480 }
01481 map->read_map_data();
01482 #ifdef HAVE_OPENGL
01483 if (GL_manager::get_instance())
01484 paint();
01485 else
01486 #endif
01487 {
01488 int w = get_width();
01489 win->copy(0, 0, w, get_height() - c_tilesize, 0, c_tilesize);
01490 paint(0, 0, w, c_tilesize);
01491 }
01492 dirty.y += c_tilesize;
01493 dirty = clip_to_win(dirty);
01494
01495 int new_tcy = (scrollty/c_tiles_per_chunk)%c_num_chunks;
01496 if (new_tcy != old_tcy)
01497 Send_location(this);
01498 }
01499
01500
01501
01502
01503
01504 Gump *Game_window::get_dragging_gump
01505 (
01506 )
01507 {
01508 return dragging ? dragging->gump : 0;
01509 }
01510
01511
01512
01513
01514
01515 void Game_window::start_actor_alt
01516 (
01517 int winx, int winy,
01518 int speed
01519 )
01520 {
01521 int ax, ay;
01522 int nlift;
01523 int blocked[8];
01524 get_shape_location(main_actor, ax, ay);
01525 int height = main_actor->get_info().get_3d_height();
01526
01527 Tile_coord start = main_actor->get_tile();
01528 int dir;
01529
01530 for (dir = 0; dir < 8; dir++)
01531 {
01532 Tile_coord dest = start.get_neighbor(dir);
01533 int cx = dest.tx/c_tiles_per_chunk, cy = dest.ty/c_tiles_per_chunk;
01534 int tx = dest.tx%c_tiles_per_chunk, ty = dest.ty%c_tiles_per_chunk;
01535
01536 Map_chunk *clist = map->get_chunk_safely(cx, cy);
01537 clist->setup_cache();
01538 blocked[dir] = clist->is_blocked (height,
01539 main_actor->get_lift(), tx, ty, nlift,
01540 main_actor->get_type_flags(), 1);
01541 }
01542
01543 dir = Get_direction (ay - winy, winx - ax);
01544
01545 if (blocked[dir] && !blocked[(dir+1)%8])
01546 dir = (dir+1)%8;
01547 else if (blocked[dir] && !blocked[(dir+7)%8])
01548 dir = (dir+7)%8;
01549 else if (blocked[dir])
01550 {
01551 Game_object *block = main_actor->is_moving() ? 0
01552 : Game_object::find_blocking(start.get_neighbor(dir));
01553 if (block == main_actor || !block || !block->move_aside(
01554 main_actor, dir))
01555 {
01556 stop_actor();
01557 if (main_actor->get_lift()%5)
01558 {
01559 int savetz = start.tz;
01560 if (!Map_chunk::is_blocked(start, 1,
01561 MOVE_WALK, 100) &&
01562 start.tz < savetz)
01563 main_actor->move(start.tx, start.ty,
01564 start.tz);
01565 }
01566 return;
01567 }
01568 }
01569
01570 const int delta = step_tile_delta*c_tilesize;
01571
01572 switch (dir)
01573 {
01574 case north:
01575
01576 ay -= delta;
01577 break;
01578
01579 case northeast:
01580
01581 ay -= delta;
01582 ax += delta;
01583 break;
01584
01585 case east:
01586
01587 ax += delta;
01588 break;
01589
01590 case southeast:
01591
01592 ay += delta;
01593 ax += delta;
01594 break;
01595
01596 case south:
01597
01598 ay += delta;
01599 break;
01600
01601 case southwest:
01602
01603 ay += delta;
01604 ax -= delta;
01605 break;
01606
01607 case west:
01608
01609 ax -= delta;
01610 break;
01611
01612 case northwest:
01613
01614 ay -= delta;
01615 ax -= delta;
01616 break;
01617 }
01618
01619 int lift = main_actor->get_lift();
01620 int liftpixels = 4*lift;
01621 int tx = get_scrolltx() + (ax + liftpixels)/c_tilesize,
01622 ty = get_scrollty() + (ay + liftpixels)/c_tilesize;
01623
01624 tx = (tx + c_num_tiles)%c_num_tiles;
01625 ty = (ty + c_num_tiles)%c_num_tiles;
01626 main_actor->walk_to_tile(tx, ty, lift, speed, 0);
01627 if (walk_in_formation && main_actor->get_action())
01628
01629
01630 main_actor->get_action()->set_get_party(true);
01631 else
01632 main_actor->get_followers();
01633 }
01634
01635
01636
01637
01638
01639 void Game_window::start_actor
01640 (
01641 int winx, int winy,
01642 int speed
01643 )
01644 {
01645 if (main_actor->Actor::get_flag(Obj_flags::asleep) ||
01646 main_actor->Actor::get_flag(Obj_flags::paralyzed) ||
01647 main_actor->get_schedule_type() == Schedule::sleep)
01648 return;
01649 if (main_actor_dont_move() || (gump_man->gump_mode() && !gump_man->gumps_dont_pause_game()))
01650 return;
01651
01652 if (moving_barge)
01653 {
01654 int lift = main_actor->get_lift();
01655 int liftpixels = 4*lift;
01656 int tx = get_scrolltx() + (winx + liftpixels)/c_tilesize,
01657 ty = get_scrollty() + (winy + liftpixels)/c_tilesize;
01658
01659 tx = (tx + c_num_tiles)%c_num_tiles;
01660 ty = (ty + c_num_tiles)%c_num_tiles;
01661 Tile_coord atile = moving_barge->get_center(),
01662 btile = moving_barge->get_tile();
01663
01664 moving_barge->travel_to_tile(
01665 Tile_coord(tx + btile.tx - atile.tx,
01666 ty + btile.ty - atile.ty, btile.tz),
01667 speed/2);
01668 }
01669 else
01670 {
01671
01672
01673
01674
01675
01676 int sched = main_actor->get_schedule_type();
01677 if (sched != Schedule::follow_avatar &&
01678 sched != Schedule::combat &&
01679 !main_actor->get_flag(Obj_flags::asleep))
01680 main_actor->set_schedule_type(Schedule::follow_avatar);
01681
01682 start_actor_alt (winx, winy, speed);
01683 }
01684 }
01685
01686
01687
01688
01689
01690 void Game_window::start_actor_along_path
01691 (
01692 int winx, int winy,
01693 int speed
01694 )
01695 {
01696 if (main_actor->Actor::get_flag(Obj_flags::asleep) ||
01697 main_actor->Actor::get_flag(Obj_flags::paralyzed) ||
01698 main_actor->get_schedule_type() == Schedule::sleep ||
01699 moving_barge)
01700 return;
01701
01702 if (main_actor_dont_move())
01703 return;
01704
01705 int lift = main_actor->get_lift();
01706 int liftpixels = 4*lift;
01707 Tile_coord dest(get_scrolltx() + (winx + liftpixels)/c_tilesize,
01708 get_scrollty() + (winy + liftpixels)/c_tilesize, lift);
01709 if (!main_actor->walk_path_to_tile(dest, speed))
01710 cout << "Couldn't find path for Avatar." << endl;
01711 else
01712 main_actor->get_followers();
01713 }
01714
01715
01716
01717
01718
01719 void Game_window::stop_actor
01720 (
01721 )
01722 {
01723 if (moving_barge)
01724 moving_barge->stop();
01725 else
01726 {
01727 main_actor->stop();
01728 if (!gump_man->gump_mode() ||gump_man->gumps_dont_pause_game())
01729
01730
01731 main_actor->get_followers();
01732 }
01733 }
01734
01735
01736
01737
01738
01739 void Game_window::teleport_party
01740 (
01741 Tile_coord t,
01742 bool skip_eggs
01743 )
01744 {
01745 Tile_coord oldpos = main_actor->get_tile();
01746 main_actor->set_action(0);
01747
01748 moving_barge = 0;
01749 main_actor->move(t.tx, t.ty, t.tz);
01750 center_view(t);
01751
01752
01753 int cnt = party_man->get_count();
01754 for (int i = 0; i < cnt; i++)
01755 {
01756 int party_member=party_man->get_member(i);
01757 Actor *person = get_npc(party_member);
01758 if (person && !person->is_dead() &&
01759 person->get_schedule_type() != Schedule::wait)
01760 {
01761 person->set_action(0);
01762 Tile_coord t1 = Map_chunk::find_spot(t, 8,
01763 person->get_shapenum(), person->get_framenum(),
01764 1);
01765 if (t1.tx != -1)
01766 person->move(t1);
01767 }
01768 }
01769 main_actor->get_followers();
01770 if (!skip_eggs)
01771 Map_chunk::try_all_eggs(main_actor, t.tx, t.ty, t.tz,
01772 oldpos.tx, oldpos.ty);
01773
01774
01775 int x, y;
01776 SDL_GetMouseState(&x, &y);
01777 SDL_WarpMouse(x, y);
01778 }
01779
01780
01781
01782
01783
01784
01785
01786 int Game_window::get_party
01787 (
01788 Actor **a_list,
01789 int avatar_too
01790 )
01791 {
01792 int n = 0;
01793 if (avatar_too && main_actor)
01794 a_list[n++] = main_actor;
01795 int cnt = party_man->get_count();
01796 for (int i = 0; i < cnt; i++)
01797 {
01798 int party_member = party_man->get_member(i);
01799 Actor *person = get_npc(party_member);
01800 if (person)
01801 a_list[n++] = person;
01802 }
01803 return n;
01804 }
01805
01806
01807
01808
01809
01810
01811
01812
01813 bool Game_window::activate_item
01814 (
01815 int shnum,
01816 int frnum,
01817 int qual
01818 )
01819 {
01820 Actor *party[9];
01821 int cnt = get_party(party, 1);
01822 for (int i = 0; i < cnt; i++)
01823 {
01824 Actor *person = party[i];
01825 Game_object *obj = person->find_item(shnum, qual, frnum);
01826 if (obj)
01827 {
01828 obj->activate();
01829 return true;
01830 }
01831 }
01832 return false;
01833 }
01834
01835
01836
01837
01838
01839
01840
01841 Game_object *Game_window::find_object
01842 (
01843 int x, int y
01844 )
01845 {
01846 #ifdef DEBUG
01847 cout << "Clicked at tile (" << get_scrolltx() + x/c_tilesize << ", " <<
01848 get_scrollty() + y/c_tilesize << ")"<<endl;
01849 #endif
01850 int not_above = get_render_skip_lift();
01851
01852 int start_cx = ((scrolltx +
01853 x/c_tilesize)/c_tiles_per_chunk)%c_num_chunks;
01854 int start_cy = ((scrollty +
01855 y/c_tilesize)/c_tiles_per_chunk)%c_num_chunks;
01856
01857 int stop_cx = (2 + (scrolltx +
01858 (x + 4*not_above)/c_tilesize)/c_tiles_per_chunk)%c_num_chunks;
01859 int stop_cy = (2 + (scrollty +
01860 (y + 4*not_above)/c_tilesize)/c_tiles_per_chunk)%c_num_chunks;
01861
01862 Game_object *best = 0;
01863 bool trans = true;
01864
01865 for (int cy = start_cy; cy != stop_cy; cy = INCR_CHUNK(cy))
01866 for (int cx = start_cx; cx != stop_cx; cx = INCR_CHUNK(cx))
01867 {
01868 Map_chunk *olist = map->get_chunk(cx, cy);
01869 if (!olist)
01870 continue;
01871 Object_iterator next(olist->get_objects());
01872 Game_object *obj;
01873 while ((obj = next.get_next()) != 0)
01874 {
01875 if (obj->get_lift() >= not_above ||
01876 !get_shape_rect(obj).has_point(x, y) ||
01877 !obj->is_findable())
01878 continue;
01879
01880 Shape_frame *s = obj->get_shape();
01881 int ox, oy;
01882 get_shape_location(obj, ox, oy);
01883 if (!s->has_point(x - ox, y - oy))
01884 continue;
01885 if (!best || best->lt(*obj) == 1 || trans)
01886 {
01887 bool ftrans = obj->get_info().is_transparent() != 0;
01888 if (!ftrans || trans)
01889 {
01890 best = obj;
01891 trans = ftrans;
01892 }
01893 }
01894 }
01895 }
01896 return (best);
01897 }
01898
01899
01900
01901
01902
01903 void Game_window::show_items
01904 (
01905 int x, int y,
01906 bool ctrl
01907 )
01908 {
01909
01910 Gump *gump = gump_man->find_gump(x, y);
01911 Game_object *obj;
01912 if (gump)
01913 {
01914 obj = gump->find_object(x, y);
01915 if (!obj) obj = gump->get_cont_or_actor(x, y);
01916 }
01917 else
01918 obj = find_object(x, y);
01919
01920 if (obj && cheat.in_map_editor())
01921 {
01922
01923 if (ctrl)
01924 cheat.toggle_selected(obj);
01925 else
01926 {
01927 cheat.clear_selected();
01928 if (cheat.get_edit_mode() == Cheat::move)
01929 cheat.append_selected(obj);
01930 }
01931 }
01932 else
01933 cheat.clear_selected();
01934
01935
01936 Actor *npc = obj ? obj->as_actor() : 0;
01937 if (npc && cheat.number_npcs() &&
01938 (npc->get_npc_num() > 0 || npc==main_actor))
01939 {
01940 char str[64];
01941 std::string namestr = obj->get_name();
01942 snprintf (str, 64, "(%i) %s", npc->get_npc_num(),
01943 namestr.c_str());
01944 effects->add_text(str, obj);
01945 }
01946 else if (obj)
01947 {
01948 std::string namestr = obj->get_name();
01949 const char *objname = namestr.c_str();
01950 Actor *actor;
01951 if (in_combat() && Combat::mode != Combat::original &&
01952 (actor = obj->as_actor()) != 0)
01953 {
01954 char buf[128];
01955 sprintf(buf, "%s (%d)", objname,
01956 actor->get_property(Actor::health));
01957 objname = &buf[0];
01958 }
01959 effects->add_text(objname, obj);
01960 }
01961 else if (cheat.in_map_editor() && skip_lift > 0)
01962 {
01963 ShapeID id = get_flat(x, y);
01964 char str[12];
01965 snprintf(str, 12, "Flat %d:%d", id.get_shapenum(),
01966 id.get_framenum());
01967 effects->add_text(str, x, y);
01968 }
01969
01970 if (npc && cheat.grabbing_actor() &&
01971 (npc->get_npc_num() || npc==main_actor))
01972 cheat.set_grabbed_actor (npc);
01973
01974 #ifdef DEBUG
01975 int shnum, frnum;
01976 if (obj)
01977 {
01978 shnum = obj->get_shapenum(), frnum = obj->get_framenum();
01979 Shape_info& info = obj->get_info();
01980 cout << "Object " << shnum << ':' << frnum <<
01981 " has 3d tiles (x, y, z): " <<
01982 info.get_3d_xtiles(frnum) << ", " <<
01983 info.get_3d_ytiles(frnum) << ", " <<
01984 info.get_3d_height();
01985 Actor *npc = obj->as_actor();
01986 if (npc)
01987 cout << ", sched = " <<
01988 npc->get_schedule_type() << ", align = " <<
01989 npc->get_alignment() << ", npcnum = " <<
01990 npc->get_npc_num();
01991 cout << endl;
01992 Tile_coord t = obj->get_tile();
01993 cout << "tx = " << t.tx << ", ty = " << t.ty << ", tz = " <<
01994 t.tz << ", quality = " <<
01995 obj->get_quality() <<
01996 ", okay_to_take = " <<
01997 static_cast<int>(obj->get_flag(Obj_flags::okay_to_take)) <<
01998 ", flag0x1d = " << static_cast<int>(obj->get_flag(0x1d)) <<
01999 ", hp = " << obj->get_obj_hp() << ", weight = "<< obj->get_weight()
02000 << ", volume = " << obj->get_volume()
02001 << endl;
02002 cout << "obj = " << (void *) obj << endl;
02003 if (obj->get_flag(Obj_flags::asleep))
02004 cout << "ASLEEP" << endl;
02005 if (obj->is_egg())
02006 ((Egg_object *)obj)->print_debug();
02007 }
02008 else
02009 {
02010 ShapeID id = get_flat(x, y);
02011 shnum = id.get_shapenum();
02012 cout << "Clicked on flat shape " <<
02013 shnum << ':' << id.get_framenum() << endl;
02014
02015 #ifdef CHUNK_OBJ_DUMP
02016 Map_chunk *chunk = map->get_chunk_safely(x/c_tiles_per_chunk, y/c_tiles_per_chunk);
02017 Object_iterator it(chunk->get_objects());
02018 Game_object *each;
02019 cout << "Chunk Contents: " << endl;
02020 while ((each = it.get_next()) != 0)
02021 cout << " " << each->get_name() << ":" << each->get_shapenum() << ":" << each->get_framenum() << endl;
02022 #endif
02023 if (id.is_invalid())
02024 return;
02025 }
02026 Shape_info& info = ShapeID::get_info(shnum);
02027 cout << "TFA[1][0-6]= " << ((static_cast<int>(info.get_tfa(1)))&127) << endl;
02028 cout << "TFA[0][0-1]= " << ((static_cast<int>(info.get_tfa(0))&3)) << endl;
02029 cout << "TFA[0][3-4]= " << ((static_cast<int>((info.get_tfa(0)>>3))&3)) << endl;
02030 if (info.is_animated())
02031 cout << "Object is ANIMATED" << endl;
02032 if (info.has_translucency())
02033 cout << "Object has TRANSLUCENCY" << endl;
02034 if (info.is_transparent())
02035 cout << "Object is TRANSPARENT" << endl;
02036 if (info.is_light_source())
02037 cout << "Object is LIGHT_SOURCE" << endl;
02038 if (info.is_door())
02039 cout << "Object is a DOOR" << endl;
02040 if (info.is_solid())
02041 cout << "Object is SOLID" << endl;
02042 #endif
02043 }
02044
02045
02046
02047
02048
02049
02050 void Game_window::paused_combat_select
02051 (
02052 int x, int y
02053 )
02054 {
02055 Gump *gump = gump_man->find_gump(x, y);
02056 if (gump)
02057 return;
02058 Game_object *obj = find_object(x, y);
02059 Actor *npc = obj ? obj->as_actor() : 0;
02060 if (!npc || !npc->is_in_party() ||
02061 npc->get_flag(Obj_flags::asleep) || npc->is_dead() ||
02062 npc->get_flag(Obj_flags::paralyzed))
02063 return;
02064 npc->paint_outline(PROTECT_PIXEL);
02065 show(true);
02066 SDL_Delay(100);
02067 npc->add_dirty();
02068 paint_dirty();
02069 show();
02070
02071 if (!Get_click(x, y, Mouse::greenselect, 0, true))
02072 return;
02073 obj = find_object(x, y);
02074 if (!obj)
02075 {
02076 int lift = npc->get_lift();
02077 int liftpixels = 4*lift;
02078 Tile_coord dest(scrolltx + (x + liftpixels)/c_tilesize,
02079 scrollty + (y + liftpixels)/c_tilesize, lift);
02080
02081 if (!npc->walk_path_to_tile(dest, std_delay, 0, 1))
02082 Mouse::mouse->flash_shape(Mouse::blocked);
02083 else
02084 npc->set_target(0, true);
02085 return;
02086 }
02087 Actor *target = obj->as_actor();
02088
02089 if ((target && target->is_in_party()) || Is_body(obj->get_shapenum()))
02090 {
02091 Mouse::mouse->flash_shape(Mouse::redx);
02092 return;
02093 }
02094 npc->set_target(obj, true);
02095 obj->paint_outline(HIT_PIXEL);
02096 show(true);
02097 SDL_Delay(100);
02098 add_dirty(obj);
02099 paint_dirty();
02100 show();
02101 }
02102
02103
02104
02105
02106
02107 ShapeID Game_window::get_flat
02108 (
02109 int x, int y
02110 )
02111 {
02112 int tx = (get_scrolltx() + x/c_tilesize)%c_num_tiles;
02113 int ty = (get_scrollty() + y/c_tilesize)%c_num_tiles;
02114 int cx = tx/c_tiles_per_chunk, cy = ty/c_tiles_per_chunk;
02115 tx = tx%c_tiles_per_chunk;
02116 ty = ty%c_tiles_per_chunk;
02117 Map_chunk *chunk = map->get_chunk(cx, cy);
02118 ShapeID id = chunk->get_flat(tx, ty);
02119 return id;
02120 }
02121
02122
02123
02124
02125
02126 void Game_window::delete_object
02127 (
02128 Game_object *obj
02129 )
02130 {
02131 obj->set_invalid();
02132 if (!obj->is_monster())
02133 removed->insert(obj);
02134 }
02135
02136
02137
02138
02139
02140 static bool Is_sign
02141 (
02142 int shnum
02143 )
02144 {
02145 switch(shnum)
02146 {
02147 case 820:
02148 case 360:
02149 case 361:
02150 case 379:
02151 return true;
02152 default:
02153 return false;
02154 }
02155 }
02156
02157
02158
02159
02160
02161 void Game_window::double_clicked
02162 (
02163 int x, int y
02164 )
02165 {
02166 #if 0
02167
02168 static int ncnt = 0;
02169 cout << "Showing xform for ncnt = " << ncnt << endl;
02170 std::size_t nxforms = sizeof(xforms)/sizeof(xforms[0]);
02171 pal->load(PALETTES_FLX, 0, XFORMTBL, nxforms - 1 - ncnt);
02172 pal->apply(false);
02173 ncnt = (ncnt + 1)%nxforms;
02174
02175 #endif
02176
02177 if (main_actor_dont_move())
02178 return;
02179
02180 if (!Usecode_script::get_count())
02181 removed->flush();
02182
02183 Game_object *obj = 0;
02184 bool gump = gump_man->double_clicked(x, y, obj);
02185
02186
02187 if (!gump)
02188 {
02189 obj = find_object(x, y);
02190 #ifdef USE_EXULTSTUDIO
02191
02192 if (cheat.in_map_editor() && cheat.get_edit_mode() ==
02193 Cheat::combo_pick && client_socket >= 0)
02194 {
02195 ShapeID id = obj ? *obj : get_flat(x, y);
02196 Tile_coord t = obj ? obj->get_tile() :
02197 Tile_coord((scrolltx + x/c_tilesize)%c_num_tiles,
02198 (scrollty + y/c_tilesize)%c_num_tiles,
02199 0);
02200 std::string name = item_names[id.get_shapenum()];
02201 if (Object_out(client_socket, Exult_server::combo_pick,
02202 0, t.tx, t.ty, t.tz, id.get_shapenum(),
02203 id.get_framenum(), 0, name) == -1)
02204 cout << "Error sending shape to ExultStudio"
02205 << endl;
02206 return;
02207 }
02208 #endif
02209
02210 if (obj && !obj->as_actor() &&
02211 !cheat.in_hack_mover() &&
02212 !Is_sign(obj->get_shapenum()) &&
02213 !Fast_pathfinder_client::is_grabable(
02214 main_actor->get_tile(),
02215 obj->get_tile()))
02216 {
02217 Mouse::mouse->flash_shape(Mouse::blocked);
02218 return;
02219 }
02220 }
02221 if (!obj)
02222 return;
02223 if (combat && !gump &&
02224 !Combat::is_paused() &&
02225 (!gump_man->gump_mode() || gump_man->gumps_dont_pause_game()))
02226 {
02227 Actor *npc = obj->as_actor();
02228
02229 if ((!npc || !npc->is_in_party()) &&
02230
02231 !Is_body(obj->get_shapenum()))
02232 {
02233
02234 combat = 0;
02235 main_actor->set_target(obj);
02236 toggle_combat();
02237 return;
02238 }
02239 }
02240 effects->remove_text_effects();
02241 #ifdef DEBUG
02242 cout << "Object name is " << obj->get_name() << endl;
02243 #endif
02244 usecode->init_conversation();
02245 obj->activate();
02246 npc_prox->wait(4);
02247 }
02248
02249
02250
02251
02252
02253
02254 void Game_window::add_nearby_npc
02255 (
02256 Npc_actor *npc
02257 )
02258 {
02259 if (!npc->is_nearby())
02260 {
02261 npc->set_nearby();
02262 npc_prox->add(Game::get_ticks(), npc);
02263 }
02264 }
02265
02266
02267
02268
02269
02270 void Game_window::remove_nearby_npc
02271 (
02272 Npc_actor *npc
02273 )
02274 {
02275 if (npc->is_nearby())
02276 npc_prox->remove(npc);
02277 }
02278
02279
02280
02281
02282
02283 void Game_window::get_nearby_npcs
02284 (
02285 Actor_queue& a_list
02286 )
02287 {
02288 npc_prox->get_all(a_list);
02289 }
02290
02291
02292
02293
02294
02295 void Game_window::schedule_npcs
02296 (
02297 int hour3,
02298 int backwards,
02299 bool repaint
02300 )
02301 {
02302
02303 for (Actor_vector::iterator it = npcs.begin() + 1;
02304 it != npcs.end(); it++)
02305 {
02306 Npc_actor *npc = (Npc_actor *) *it;
02307
02308 if (npc && npc->get_schedule_type() != Schedule::wait)
02309 npc->update_schedule(hour3, backwards);
02310 }
02311
02312 if (repaint)
02313 paint();
02314 }
02315
02316
02317
02318
02319
02320 void Game_window::mend_npcs
02321 (
02322 )
02323 {
02324
02325 for (Actor_vector::iterator it = npcs.begin();
02326 it != npcs.end(); it++)
02327 {
02328 Npc_actor *npc = (Npc_actor *) *it;
02329 if (npc)
02330 npc->mend_hourly();
02331 }
02332 }
02333
02334
02335
02336
02337
02338 int Get_guard_shape
02339 (
02340 Tile_coord pos
02341 )
02342 {
02343 if (!GAME_SI)
02344 return (0x3b2);
02345
02346 if (pos.tx >= 2054 && pos.ty >= 1698 &&
02347 pos.tx < 2590 && pos.ty < 2387)
02348 return 0x103;
02349
02350 if (pos.tx >= 895 && pos.ty >= 1604 &&
02351 pos.tx < 1173 && pos.ty < 1960)
02352 return 0x17d;
02353 return 0xe4;
02354 }
02355
02356
02357
02358
02359
02360
02361
02362
02363 Actor *Game_window::find_witness
02364 (
02365 Actor *& closest_npc
02366 )
02367 {
02368 Actor_vector npcs;
02369 main_actor->find_nearby_actors(npcs, c_any_shapenum, 12);
02370 closest_npc = 0;
02371 int closest_dist = 5000;
02372 Actor *witness = 0;
02373 int closest_witness_dist = 5000;
02374 for (Actor_vector::const_iterator it = npcs.begin();
02375 it != npcs.end();++it)
02376 {
02377 Actor *npc = *it;
02378 if (npc->is_monster() || npc->is_in_party() ||
02379 (npc->get_framenum()&15) == Actor::sleep_frame ||
02380 npc->get_npc_num() >= num_npcs1)
02381 continue;
02382 int dist = npc->distance(main_actor);
02383 if (dist >= closest_witness_dist ||
02384 !Fast_pathfinder_client::is_grabable(
02385 npc->get_tile(), main_actor->get_tile()))
02386 continue;
02387
02388 int dir = npc->get_direction(main_actor);
02389 int facing = npc->get_dir_facing();
02390 int dirdiff = (dir - facing + 8)%8;
02391 if (dirdiff < 3 || dirdiff > 5)
02392 {
02393 witness = npc;
02394 closest_witness_dist = dist;
02395 }
02396 else if (dist < closest_dist)
02397 {
02398 closest_npc = npc;
02399 closest_dist = dist;
02400 }
02401 }
02402 return witness;
02403 }
02404
02405
02406
02407
02408
02409 void Game_window::theft
02410 (
02411 )
02412 {
02413
02414 int cx = main_actor->get_cx(), cy = main_actor->get_cy();
02415 if (cx != theft_cx || cy != theft_cy)
02416 {
02417 theft_cx = cx;
02418 theft_cy = cy;
02419 theft_warnings = 0;
02420 }
02421 Actor *closest_npc;
02422 Actor *witness = find_witness(closest_npc);
02423 if (!witness)
02424 {
02425 if (closest_npc && rand()%2)
02426 closest_npc->say(item_names[heard_something]);
02427 return;
02428 }
02429 int dir = witness->get_direction(main_actor);
02430
02431 witness->change_frame(witness->get_dir_framenum(dir,
02432 Actor::standing));
02433 theft_warnings++;
02434 if (theft_warnings < 2 + rand()%3)
02435 {
02436 witness->say(first_theft, last_theft);
02437 return;
02438 }
02439 gump_man->close_all_gumps();
02440 call_guards(witness);
02441 }
02442
02443
02444
02445
02446
02447 void Game_window::call_guards
02448 (
02449 Actor *witness
02450 )
02451 {
02452 Actor *closest;
02453 if (!witness && !(witness = find_witness(closest)))
02454 return;
02455 witness->say(first_call_guards, last_call_guards);
02456
02457 int gshape = Get_guard_shape(main_actor->get_tile());
02458
02459 Monster_actor *guard = Monster_actor::create(gshape,
02460 main_actor->get_tile() + Tile_coord(128, 128, 0));
02461 add_nearby_npc(guard);
02462 Tile_coord actloc = main_actor->get_tile();
02463 Tile_coord dest = Map_chunk::find_spot(actloc, 5,
02464 guard->get_shapenum(), guard->get_framenum(), 1);
02465 if (dest.tx != -1)
02466 {
02467 int dir = Get_direction(dest.ty - actloc.ty,
02468 actloc.tx - dest.tx);
02469
02470 signed char frames[2];
02471 frames[0] = guard->get_dir_framenum(dir, Actor::standing);
02472 frames[1] = guard->get_dir_framenum(dir, 3);
02473 Actor_action *action = new Sequence_actor_action(
02474 new Frames_actor_action(frames, 2),
02475 new Usecode_actor_action(0x625, guard,
02476 Usecode_machine::double_click));
02477 Schedule::set_action_sequence(guard, dest, action, true);
02478 }
02479 }
02480
02481
02482
02483
02484
02485 void Game_window::attack_avatar
02486 (
02487 int create_guards
02488 )
02489 {
02490 int gshape = Get_guard_shape(main_actor->get_tile());
02491 while (create_guards--)
02492 {
02493
02494 Monster_actor *guard = Monster_actor::create(gshape,
02495 main_actor->get_tile() + Tile_coord(128, 128, 0));
02496 add_nearby_npc(guard);
02497 guard->set_target(main_actor, true);
02498 guard->approach_another(main_actor);
02499 }
02500
02501 Actor_vector npcs;
02502 main_actor->find_nearby_actors(npcs, c_any_shapenum, 20);
02503 for (Actor_vector::const_iterator it = npcs.begin();
02504 it != npcs.end();++it)
02505 {
02506 Actor *npc = (Actor *) *it;
02507
02508 if ((npc->get_shapenum() == gshape || !npc->is_monster()) &&
02509 !npc->is_in_party())
02510 npc->set_target(main_actor, true);
02511 }
02512 }
02513
02514
02515
02516
02517
02518 void Game_window::get_focus
02519 (
02520 )
02521 {
02522 cout << "Game resumed" << endl;
02523 Audio::get_ptr()->resume_audio();
02524 focus = 1;
02525 tqueue->resume(Game::get_ticks());
02526 }
02527 void Game_window::lose_focus
02528 (
02529 )
02530 {
02531 if (!focus)
02532 return;
02533 cout << "Game paused" << endl;
02534
02535 string str;
02536 config->value("config/audio/disablepause", str, "no");
02537 if (str == "no")
02538 Audio::get_ptr()->pause_audio();
02539
02540 focus = false;
02541 tqueue->pause(Game::get_ticks());
02542 }
02543
02544
02545
02546
02547
02548
02549 void Game_window::setup_game
02550 (
02551 )
02552 {
02553 map->init();
02554
02555 Game::set_ticks(SDL_GetTicks());
02556 init_actors();
02557
02558
02559
02560 CYCLE_RED_PLASMA();
02561
02562 usecode->read();
02563 CYCLE_RED_PLASMA();
02564
02565 if (Game::get_game_type() == BLACK_GATE)
02566 {
02567 string yn;
02568
02569 config->value("config/gameplay/skip_intro", yn, "no");
02570 if (yn == "yes")
02571 usecode->set_global_flag(
02572 Usecode_machine::did_first_scene, 1);
02573
02574
02575 if (usecode->get_global_flag(Usecode_machine::did_first_scene))
02576 main_actor->clear_flag(Obj_flags::dont_move);
02577 else
02578 main_actor->set_flag(Obj_flags::dont_move);
02579 }
02580
02581 CYCLE_RED_PLASMA();
02582
02583
02584 pal->fade_out(c_fade_out_time);
02585 clear_screen(true);
02586 #ifdef RED_PLASMA
02587 load_palette_timer = 0;
02588 #endif
02589
02590
02591
02592
02593
02594 Actor *party[9];
02595 int cnt = get_party(party, 1);
02596 for (int i = 0; i < cnt; i++)
02597 {
02598 party[i]->init_readied();
02599 }
02600 time_stopped = 0;
02601
02602
02603
02604 Map_chunk *olist = main_actor->get_chunk();
02605 olist->setup_cache();
02606
02607 Tile_coord t = main_actor->get_tile();
02608
02609 olist->activate_eggs(main_actor, t.tx, t.ty, t.tz, -1, -1, true);
02610
02611
02612 set_all_dirty();
02613 painted = true;
02614 gump_man->close_all_gumps(true);
02615 Face_stats::load_config(config);
02616
02617
02618 clock->set_palette();
02619 pal->fade(6, 1, -1);
02620 }
02621
02622
02623
02624 void Game_window::plasma(int w, int h, int x, int y, int startc, int endc)
02625 {
02626 Image_buffer8 *ibuf = get_win()->get_ib8();
02627
02628 ibuf->fill8(startc, w, h, x, y);
02629
02630 for (int i=0; i < w*h; i++) {
02631 Uint8 pc = startc + rand()%(endc-startc+1);
02632 int px = x + rand()%w;
02633 int py = y + rand()%h;
02634
02635 for (int j=0; j < 6; j++) {
02636 int px2 = px + rand()%17 - 8;
02637 int py2 = py + rand()%17 - 8;
02638 ibuf->fill8(pc, 3, 1, px2 - 1, py2);
02639 ibuf->fill8(pc, 1, 3, px2, py2 - 1);
02640 }
02641 }
02642 painted = true;
02643 }
02644
02645
02646
02647
02648
02649 void Game_window::emulate_cache(int oldx, int oldy, int newx, int newy)
02650 {
02651 if (oldx == -1 || oldy == -1)
02652 return;
02653
02654
02655 effects->remove_weather_effects(120);
02656
02657 Usecode_script::purge(Tile_coord(newx*c_tiles_per_chunk,
02658 newy*c_tiles_per_chunk, 0), 4*c_tiles_per_chunk);
02659 int nearby[5][5];
02660
02661
02662
02663 memset(reinterpret_cast<char*>(nearby), 0, sizeof(nearby));
02664
02665 int old_minx = c_num_chunks + oldx - 2,
02666 old_maxx = c_num_chunks + oldx + 2;
02667 int old_miny = c_num_chunks + oldy - 2,
02668 old_maxy = c_num_chunks + oldy + 2;
02669
02670 int new_minx = c_num_chunks + newx - 2,
02671 new_maxx = c_num_chunks + newx + 2;
02672 int new_miny = c_num_chunks + newy - 2,
02673 new_maxy = c_num_chunks + newy + 2;
02674
02675 int x, y;
02676 for (y = new_miny; y <= new_maxy; y++)
02677 {
02678 if (y > old_maxy)
02679 break;
02680 int dy = y - old_miny;
02681 if (dy < 0)
02682 continue;
02683 assert(dy < 5);
02684 for (x = new_minx; x <= new_maxx; x++)
02685 {
02686 if (x > old_maxx)
02687 break;
02688 int dx = x - old_minx;
02689 if (dx >= 0)
02690 {
02691 assert(dx < 5);
02692 nearby[dx][dy] = 1;
02693 }
02694 }
02695 }
02696
02697 Game_object_vector removes;
02698 for (y = 0; y < 5; y++)
02699 for (x = 0; x < 5; x++)
02700 {
02701 if (nearby[x][y] != 0)
02702 continue;
02703 Map_chunk *list = map->get_chunk_safely(
02704 (old_minx + x)%c_num_chunks,
02705 (old_miny + y)%c_num_chunks);
02706 if (!list) continue;
02707 Object_iterator it(list->get_objects());
02708 Game_object *each;
02709 while ((each = it.get_next()) != 0)
02710 {
02711 if (each->is_egg())
02712 ((Egg_object *) each)->reset();
02713 else if (each->get_flag(Obj_flags::is_temporary))
02714 removes.push_back(each);
02715 }
02716 }
02717 for (Game_object_vector::const_iterator it=removes.begin();
02718 it!=removes.end(); ++it)
02719 {
02720 #ifdef DEBUG
02721 Tile_coord t = (*it)->get_tile();
02722 cout << "Culling object: " << (*it)->get_name() <<
02723 '(' << (void *)(*it) << ")@" <<
02724 t.tx << "," << t.ty << "," << t.tz <<endl;
02725 #endif
02726 (*it)->delete_contents();
02727 (*it)->remove_this(0);
02728 }
02729
02730 get_map()->cache_out(newx, newy);
02731
02732
02733 removed->flush();
02734 }
02735
02736
02737 bool Game_window::emulate_is_move_allowed(int tx, int ty)
02738 {
02739 int ax = camera_actor->get_cx() / c_chunks_per_schunk;
02740 int ay = camera_actor->get_cy() / c_chunks_per_schunk;
02741 tx /= c_tiles_per_schunk;
02742 ty /= c_tiles_per_schunk;
02743
02744 int difx = ax - tx;
02745 int dify = ay - ty;
02746
02747 if (difx < 0) difx = -difx;
02748 if (dify < 0) dify = -dify;
02749
02750
02751 if ((!difx || difx == 1 || difx == c_num_schunks || difx == c_num_schunks-1) &&
02752 (!dify || dify == 1 || dify == c_num_schunks || dify == c_num_schunks-1))
02753 return true;
02754
02755 return false;
02756 }
02757
02758
02759 Shape_file* Game_window::create_mini_screenshot()
02760 {
02761 Shape_file* sh = 0;
02762 Shape_frame* fr = 0;
02763 unsigned char* img = 0;
02764
02765 set_all_dirty();
02766 render->paint_map(0, 0, get_width(), get_height());
02767
02768 img = win->mini_screenshot();
02769
02770 if (img) {
02771 fr = new Shape_frame();
02772 fr->xleft = 0;
02773 fr->yabove = 0;
02774 fr->xright = 95;
02775 fr->ybelow = 59;
02776 fr->create_rle(img, 96, 60);
02777 fr->rle = 1;
02778 delete [] img;
02779
02780 sh = new Shape_file(fr);
02781 }
02782
02783 set_all_dirty();
02784 paint();
02785 return sh;
02786 }
02787
02788 #ifdef RED_PLASMA
02789
02790 #define BG_PLASMA_START_COLOR 128
02791 #define BG_PLASMA_CYCLE_RANGE 80
02792
02793 #define SI_PLASMA_START_COLOR 16
02794 #define SI_PLASMA_CYCLE_RANGE 96
02795
02796 void Game_window::setup_load_palette()
02797 {
02798 if (load_palette_timer != 0)
02799 return;
02800
02801 if (Game::get_game_type()==BLACK_GATE)
02802 {
02803 plasma_start_color = BG_PLASMA_START_COLOR;
02804 plasma_cycle_range = BG_PLASMA_CYCLE_RANGE;
02805 }
02806 else
02807 {
02808 plasma_start_color = SI_PLASMA_START_COLOR;
02809 plasma_cycle_range = SI_PLASMA_CYCLE_RANGE;
02810 }
02811
02812
02813 plasma(get_width(), get_height(), 0, 0, plasma_start_color, plasma_start_color+plasma_cycle_range-1);
02814
02815
02816 if (Game::get_game_type()==BLACK_GATE)
02817 pal->load("<STATIC>/intropal.dat",2);
02818 else if (Game::get_game_type()==SERPENT_ISLE)
02819 pal->load(MAINSHP_FLX,1);
02820
02821 pal->apply();
02822 load_palette_timer = SDL_GetTicks();
02823 }
02824
02825 void Game_window::cycle_load_palette()
02826 {
02827 if (load_palette_timer == 0)
02828 return;
02829 uint32 ticks = SDL_GetTicks();
02830 if(ticks > load_palette_timer+75)
02831 {
02832 for(int i = 0; i < 4; ++i)
02833 get_win()->rotate_colors(plasma_start_color, plasma_cycle_range, 1);
02834 show(true);
02835
02836
02837
02838 load_palette_timer = SDL_GetTicks();
02839 }
02840 }
02841 #endif