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 <iostream>
00026 #include "gamewin.h"
00027 #include "gamemap.h"
00028 #include "drag.h"
00029 #include "Gump_button.h"
00030 #include "Gump.h"
00031 #include "mouse.h"
00032 #include "paths.h"
00033 #include "actors.h"
00034 #include "cheat.h"
00035 #include "chunks.h"
00036 #include "Audio.h"
00037 #include "Gump_manager.h"
00038 #include "ucmachine.h"
00039 #include "barge.h"
00040
00041 using std::cout;
00042 using std::endl;
00043
00044
00045
00046
00047
00048 Dragging_info::Dragging_info
00049 (
00050 Game_object *newobj
00051
00052 ) : obj(newobj), is_new(true), gump(0), button(0), old_pos(-1, -1, -1),
00053 old_foot(0, 0, 0, 0), old_lift(-1), quantity(obj->get_quantity()),
00054 paintx(-1000), painty(-1000),
00055 readied_index(-1), mousex(-1), mousey(-1), rect(0, 0, 0, 0),
00056 save(0), okay(true), possible_theft(false)
00057 {
00058 rect = gwin->get_shape_rect(obj);
00059 rect.enlarge(8);
00060
00061 save = gwin->get_win()->create_buffer(rect.w, rect.h);
00062 }
00063
00064
00065
00066
00067
00068 Dragging_info::Dragging_info
00069 (
00070 int x, int y
00071 ) : obj(0), is_new(false), gump(0), button(0), old_pos(-1, -1, -1),
00072 old_foot(0, 0, 0, 0), old_lift(-1), quantity(0),
00073 readied_index(-1), mousex(x), mousey(y), rect(0, 0, 0, 0),
00074 save(0), okay(false), possible_theft(false)
00075 {
00076
00077 gump = gumpman->find_gump(x, y);
00078 if (gump)
00079 {
00080 obj = gump->find_object(x, y);
00081 if (obj)
00082 {
00083 gump->get_shape_location(obj, paintx, painty);
00084 old_pos = Tile_coord(obj->get_cx(), obj->get_cy(), 0);
00085 }
00086 else if ((button = gump->on_button(x, y)) != 0)
00087 {
00088 gump = 0;
00089 if (!button->is_draggable())
00090 return;
00091 button->push();
00092
00093 Audio::get_ptr()->play_sound_effect(
00094 Audio::game_sfx(96));
00095 gwin->set_painted();
00096 }
00097 else if (gump->is_draggable())
00098 {
00099 paintx = gump->get_x();
00100 painty = gump->get_y();
00101 cout << "(x,y) rel. to gump is (" << (x-paintx) << ", " <<
00102 (y-painty) << ")"<<endl;
00103 }
00104 else
00105 return;
00106 }
00107 else
00108 {
00109 obj = gwin->find_object(x, y);
00110 if (!obj)
00111 return;
00112
00113 gwin->get_shape_location(obj, paintx, painty);
00114 old_pos = obj->get_tile();
00115 old_foot = obj->get_footprint();
00116 }
00117 if (obj)
00118 {
00119 quantity = obj->get_quantity();
00120
00121 old_lift = obj->get_outermost()->get_lift();
00122 }
00123 okay = true;
00124 }
00125
00126
00127
00128
00129
00130 Dragging_info::~Dragging_info
00131 (
00132 )
00133 {
00134 delete save;
00135 }
00136
00137
00138
00139
00140
00141
00142
00143 bool Dragging_info::start
00144 (
00145 int x, int y
00146 )
00147 {
00148 if (x - mousex <= 2 && mousex - x <= 2 &&
00149 y - mousey <= 2 && mousey - y <= 2)
00150 return (false);
00151 if (obj)
00152 {
00153 if (!cheat.in_hack_mover() && !obj->is_dragable() &&
00154 !obj->get_owner())
00155 {
00156 Mouse::mouse->flash_shape(Mouse::tooheavy);
00157 obj = 0;
00158 gump = 0;
00159 okay = false;
00160 return (false);
00161 }
00162 Game_object *owner = obj->get_outermost();
00163 if (owner == obj)
00164 {
00165 if (!cheat.in_hack_mover() &&
00166 !Fast_pathfinder_client::is_grabable(
00167 gwin->get_main_actor()->get_tile(),
00168 obj->get_tile()))
00169 {
00170 Mouse::mouse->flash_shape(Mouse::blocked);
00171 obj = 0;
00172 okay = false;
00173 return (false);
00174 }
00175 }
00176 }
00177
00178 rect = gump ? (obj ? gump->get_shape_rect(obj) : gump->get_dirty())
00179 : gwin->get_shape_rect(obj);
00180 if (gump)
00181 if (obj)
00182 {
00183 Container_game_object *owner = gump->get_cont_or_actor(x,y);
00184 if (owner)
00185 readied_index = owner->find_readied(obj);
00186 gump->remove(obj);
00187 }
00188 else
00189 gumpman->remove_gump(gump);
00190 else
00191 obj->remove_this(true);
00192
00193 rect.enlarge(obj ? 8 : 12);
00194 Rectangle crect = gwin->clip_to_win(rect);
00195 gwin->paint(crect);
00196
00197 save = gwin->get_win()->create_buffer(rect.w, rect.h);
00198 return true;
00199 }
00200
00201
00202
00203
00204
00205
00206
00207 bool Dragging_info::moved
00208 (
00209 int x, int y
00210 )
00211 {
00212 if (!obj && !gump)
00213 return (false);
00214 if (rect.w == 0)
00215 {
00216 if (!start(x, y))
00217 return false;
00218 }
00219 else
00220 gwin->get_win()->put(save, rect.x, rect.y);
00221 gwin->set_painted();
00222 int deltax = x - mousex, deltay = y - mousey;
00223 mousex = x;
00224 mousey = y;
00225
00226 rect.shift(deltax, deltay);
00227 paintx += deltax;
00228 painty += deltay;
00229 if (gump && !obj)
00230 gump->set_pos(paintx, painty);
00231 gwin->add_dirty(gwin->clip_to_win(rect));
00232 return (true);
00233 }
00234
00235
00236
00237
00238
00239 void Dragging_info::paint
00240 (
00241 )
00242 {
00243 if (!rect.w)
00244 return;
00245 if (save)
00246 gwin->get_win()->get(save, rect.x, rect.y);
00247 if (obj)
00248 {
00249 if (obj->get_flag(Obj_flags::invisible))
00250 obj->paint_invisible(paintx, painty);
00251 else
00252 obj->paint_shape(paintx, painty);
00253 }
00254 else if (gump)
00255 {
00256 gump->paint();
00257 }
00258 }
00259
00260
00261
00262
00263
00264
00265
00266 bool Dragging_info::drop
00267 (
00268 int x, int y,
00269 bool moved
00270 )
00271 {
00272 bool handled = moved;
00273 if (button)
00274 {
00275 button->unpush();
00276 if (button->on_button(x, y))
00277
00278 button->activate();
00279 handled = true;
00280 }
00281 else if (!obj)
00282 {
00283 if (!gump)
00284 return handled;
00285 if (!moved)
00286 gumpman->remove_gump(gump);
00287 gumpman->add_gump(gump);
00288 }
00289 else if (!moved)
00290 return handled;
00291 else if (!drop(x, y))
00292 put_back();
00293 obj = 0;
00294 gump = 0;
00295 gwin->paint();
00296 return handled;
00297 }
00298
00299
00300
00301
00302
00303
00304
00305 static bool Check_weight
00306 (
00307 Game_window *gwin,
00308 Game_object *to_drop,
00309 Game_object *owner
00310 )
00311 {
00312 if (cheat.in_hack_mover())
00313 return true;
00314
00315 if (!owner)
00316 return true;
00317 owner = owner->get_outermost();
00318 if (!owner->get_flag(Obj_flags::in_party))
00319 return true;
00320 int wt = owner->get_weight() + to_drop->get_weight();
00321 if (wt/10 > owner->get_max_weight())
00322 {
00323 Mouse::mouse->flash_shape(Mouse::tooheavy);
00324 return false;
00325 }
00326 return true;
00327 }
00328
00329
00330
00331
00332
00333 void Dragging_info::put_back
00334 (
00335 )
00336 {
00337 if (gump)
00338 {
00339 obj->set_chunk(old_pos.tx, old_pos.ty);
00340 gump->add(obj, -2, -2, -2, -2, true);
00341 }
00342 else if (is_new)
00343 {
00344 obj->set_invalid();
00345 obj->remove_this();
00346 }
00347 else
00348 obj->move(old_pos);
00349 obj = 0;
00350 is_new = false;
00351 }
00352
00353
00354
00355
00356
00357
00358
00359 bool Dragging_info::drop_on_gump
00360 (
00361 int x, int y,
00362 Game_object *to_drop,
00363 Gump *on_gump
00364 )
00365 {
00366 if (!Check_weight(gwin, to_drop, on_gump->get_cont_or_actor(x,y)))
00367 return false;
00368 if (on_gump != gump)
00369 possible_theft = true;
00370
00371 if (!on_gump->add(to_drop, x, y, paintx, painty, false, true))
00372 {
00373 if (to_drop != obj)
00374 {
00375 int nq = to_drop->get_quantity();
00376 if (nq < quantity)
00377 obj->modify_quantity(quantity - nq);
00378 }
00379 Mouse::mouse->flash_shape(Mouse::wontfit);
00380 return false;
00381 }
00382 return true;
00383 }
00384
00385
00386
00387
00388
00389
00390
00391 bool Dragging_info::drop_on_map
00392 (
00393 int x, int y,
00394 Game_object *to_drop
00395 )
00396 {
00397 int max_lift = cheat.in_hack_mover() ? 13 :
00398 gwin->get_main_actor()->get_lift() + 5;
00399 int skip = gwin->get_render_skip_lift();
00400 if (max_lift >= skip)
00401 max_lift = skip - 1;
00402
00403 int posx = paintx, posy = painty;
00404 if (posx == -1000)
00405 { posx = x; posy = y; }
00406 int lift;
00407
00408 Game_object *found = gwin->find_object(x, y);
00409 bool dropped = false;
00410 if (found && found != obj)
00411 {
00412 if (!Check_weight(gwin, to_drop, found))
00413 return false;
00414 if (found->drop(to_drop))
00415 dropped = possible_theft = true;
00416
00417 else if ((lift = found->get_lift() +
00418 found->get_info().get_3d_height()) <= max_lift)
00419 dropped = gwin->drop_at_lift(to_drop,posx, posy, lift);
00420 else
00421 {
00422 Mouse::mouse->flash_shape(Mouse::redx);
00423 Audio::get_ptr()->play_sound_effect(
00424 Audio::game_sfx(76));
00425 return false;
00426 }
00427 }
00428
00429 for (lift = old_lift; !dropped && lift <= max_lift; lift++)
00430 dropped = gwin->drop_at_lift(to_drop, posx, posy, lift);
00431 if (!dropped)
00432 {
00433 Mouse::mouse->flash_shape(Mouse::blocked);
00434 Audio::get_ptr()->play_sound_effect(Audio::game_sfx(76));
00435 return false;
00436 }
00437
00438 if (!gump && to_drop->get_tile().distance(old_pos) > 2)
00439 possible_theft = true;
00440 return true;
00441 }
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452 bool Dragging_info::drop
00453 (
00454 int x, int y
00455 )
00456 {
00457
00458 int oldcx = old_pos.tx/c_tiles_per_chunk,
00459 oldcy = old_pos.ty/c_tiles_per_chunk;
00460 Game_object *to_drop = obj;
00461
00462 int okay_to_move = to_drop->get_flag(Obj_flags::okay_to_take);
00463 int old_top = old_pos.tz + obj->get_info().get_3d_height();
00464
00465 Gump *on_gump = gumpman->find_gump(x, y);
00466
00467 if (quantity > 1 && (!on_gump || on_gump != gump))
00468 quantity = gumpman->prompt_for_number(0, quantity,
00469 1, quantity);
00470 if (quantity <= 0)
00471 return false;
00472 if (quantity < obj->get_quantity())
00473 {
00474 to_drop = gmap->create_ireg_object(
00475 obj->get_shapenum(), obj->get_framenum());
00476 to_drop->modify_quantity(quantity - 1);
00477 if (okay_to_move)
00478 to_drop->set_flag(Obj_flags::okay_to_take);
00479 }
00480
00481 if (!(on_gump ? drop_on_gump(x, y, to_drop, on_gump)
00482 : drop_on_map(x, y, to_drop)))
00483 return false;
00484
00485 Audio::get_ptr()->play_sound_effect(Audio::game_sfx(74));
00486 if (!gump)
00487 gmap->get_chunk(oldcx, oldcy)->activate_eggs(obj,
00488 old_pos.tx, old_pos.ty, old_pos.tz,
00489 old_pos.tx, old_pos.ty);
00490
00491 else if (readied_index >= 0 && obj->get_shapenum() == 806)
00492
00493 gump->get_cont_or_actor(x,y)->call_readied_usecode(
00494 readied_index, obj, Usecode_machine::unreadied);
00495 if (on_gump)
00496 {
00497 Container_game_object *owner = on_gump->get_cont_or_actor(x,y);
00498 int index = owner ? owner->find_readied(obj) : -1;
00499 if (index >= 0)
00500 owner->call_readied_usecode(index,
00501 obj, Usecode_machine::readied);
00502 }
00503
00504 Barge_object *barge = gwin->get_moving_barge();
00505 if (barge)
00506 barge->set_to_gather();
00507
00508 if (!okay_to_move && !cheat.in_hack_mover() && possible_theft &&
00509 !gwin->is_in_dungeon())
00510 gwin->theft();
00511 if (to_drop == obj)
00512 {
00513 if (old_foot.w > 0)
00514 Map_chunk::gravity(old_foot, old_top);
00515 return true;
00516 }
00517
00518 obj->modify_quantity(-quantity);
00519 return false;
00520 }
00521
00522
00523
00524
00525
00526
00527
00528
00529 bool Game_window::start_dragging
00530 (
00531 int x, int y
00532 )
00533 {
00534 delete dragging;
00535 dragging = new Dragging_info(x, y);
00536 if (dragging->okay)
00537 return (true);
00538 delete dragging;
00539 dragging = 0;
00540 return false;
00541 }
00542
00543
00544
00545
00546
00547 bool Game_window::drag
00548 (
00549 int x, int y
00550 )
00551 {
00552 return dragging ? dragging->moved(x, y) : false;
00553 }
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563 bool Game_window::drop_dragged
00564 (
00565 int x, int y,
00566 bool moved
00567 )
00568 {
00569 if (!dragging)
00570 return false;
00571 bool handled = dragging->drop(x, y, moved);
00572 delete dragging;
00573 dragging = 0;
00574 return handled;
00575 }
00576
00577
00578
00579
00580
00581
00582
00583
00584 bool Game_window::drop_at_lift
00585 (
00586 Game_object *to_drop,
00587 int x, int y,
00588 int at_lift
00589 )
00590 {
00591 x += at_lift*4 - 1;
00592 y += at_lift*4 - 1;
00593 int tx = (scrolltx + x/c_tilesize)%c_num_tiles;
00594 int ty = (scrollty + y/c_tilesize)%c_num_tiles;
00595 int cx = tx/c_tiles_per_chunk;
00596 int cy = ty/c_tiles_per_chunk;
00597 Map_chunk *chunk = map->get_chunk(cx, cy);
00598 int lift;
00599 Shape_info& info = to_drop->get_info();
00600 int xtiles = info.get_3d_xtiles(), ytiles = info.get_3d_ytiles();
00601 int max_drop, move_flags;
00602 if (cheat.in_hack_mover())
00603 {
00604 max_drop = at_lift - cheat.get_edit_lift();
00605
00606 if (max_drop < 0)
00607 return false;
00608 move_flags = MOVE_WALK|MOVE_MAPEDIT;
00609 }
00610 else
00611 {
00612 max_drop = 5;
00613 move_flags = MOVE_WALK;
00614 }
00615 if (!Map_chunk::is_blocked(info.get_3d_height(), at_lift,
00616 tx - xtiles + 1, ty - ytiles + 1, xtiles, ytiles,
00617 lift, move_flags, max_drop) &&
00618 (cheat.in_hack_mover() ||
00619
00620 Fast_pathfinder_client::is_grabable(
00621 main_actor->get_tile(), Tile_coord(tx, ty, lift))))
00622 {
00623 to_drop->set_invalid();
00624 to_drop->move(tx, ty, lift);
00625 #ifdef DEBUG
00626 cout << "Dropping object at (" << tx << ", " << ty << ", " << lift
00627 << ")"<<endl;
00628 #endif
00629
00630 chunk->activate_eggs(to_drop, tx, ty, lift, tx, ty);
00631
00632 if (to_drop == main_actor) {
00633 center_view(to_drop->get_tile());
00634 paint();
00635 }
00636
00637 return (true);
00638 }
00639 return (false);
00640 }
00641