00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifdef HAVE_CONFIG_H
00026 # include <config.h>
00027 #endif
00028
00029 #include "barge.h"
00030 #include "gamewin.h"
00031 #include "gamemap.h"
00032 #include "actors.h"
00033 #include "Zombie.h"
00034 #include "citerate.h"
00035 #include "dir.h"
00036 #include "chunks.h"
00037 #include "objiter.h"
00038 #include "game.h"
00039 #include "databuf.h"
00040 #include "ucsched.h"
00041
00042 using std::ostream;
00043
00044
00045
00046
00047
00048
00049
00050
00051 inline Tile_coord Rotate90r
00052 (
00053 Tile_coord t,
00054 Tile_coord c
00055 )
00056 {
00057
00058 int rx = t.tx - c.tx, ry = c.ty - t.ty;
00059 return Tile_coord(c.tx + ry, c.ty + rx, t.tz);
00060 }
00061
00062
00063
00064
00065
00066
00067
00068
00069 inline Tile_coord Rotate90l
00070 (
00071 Tile_coord t,
00072 Tile_coord c
00073 )
00074 {
00075
00076 int rx = t.tx - c.tx, ry = c.ty - t.ty;
00077 return Tile_coord(c.tx - ry, c.ty - rx, t.tz);
00078 }
00079
00080
00081
00082
00083
00084
00085
00086
00087 inline Tile_coord Rotate180
00088 (
00089 Tile_coord t,
00090 Tile_coord c
00091 )
00092 {
00093
00094 int rx = t.tx - c.tx, ry = c.ty - t.ty;
00095 return Tile_coord(c.tx - rx, c.ty + ry, t.tz);
00096 }
00097
00098
00099
00100
00101
00102
00103
00104 inline Tile_coord Rotate90r
00105 (
00106 Game_window *gwin,
00107 Game_object *obj,
00108 int xtiles, int ytiles,
00109 Tile_coord c
00110 )
00111 {
00112
00113 Tile_coord r = Rotate90r(obj->get_tile(), c);
00114
00115
00116 r.tx = (r.tx + ytiles + c_num_tiles)%c_num_tiles;
00117 r.ty = (r.ty + c_num_tiles)%c_num_tiles;
00118 return r;
00119 }
00120
00121
00122
00123
00124
00125
00126 inline Tile_coord Rotate90l
00127 (
00128 Game_window *gwin,
00129 Game_object *obj,
00130 int xtiles, int ytiles,
00131 Tile_coord c
00132 )
00133 {
00134
00135 Tile_coord r = Rotate90l(obj->get_tile(), c);
00136
00137 r.ty = (r.ty + xtiles + c_num_tiles)%c_num_tiles;
00138 r.tx = (r.tx + c_num_tiles)%c_num_tiles;
00139 return r;
00140 }
00141
00142
00143
00144
00145
00146
00147 inline Tile_coord Rotate180
00148 (
00149 Game_window *gwin,
00150 Game_object *obj,
00151 int xtiles, int ytiles,
00152 Tile_coord c
00153 )
00154 {
00155
00156 Tile_coord r = Rotate180(obj->get_tile(), c);
00157
00158
00159 r.tx = (r.tx + xtiles + c_num_tiles)%c_num_tiles;
00160 r.ty = (r.ty + ytiles + c_num_tiles)%c_num_tiles;
00161 return r;
00162 }
00163
00164
00165
00166
00167
00168 inline void Barge_object::swap_dims
00169 (
00170 )
00171 {
00172 int tmp = xtiles;
00173 xtiles = ytiles;
00174 ytiles = tmp;
00175 }
00176
00177
00178
00179
00180
00181 Rectangle Barge_object::get_tile_footprint
00182 (
00183 )
00184 {
00185 Tile_coord pos = get_tile();
00186 int xts = get_xtiles(), yts = get_ytiles();
00187 Rectangle foot((pos.tx - xts + 1 + c_num_tiles)%c_num_tiles,
00188 (pos.ty - yts + 1 + c_num_tiles)%c_num_tiles, xts, yts);
00189 return foot;
00190 }
00191
00192
00193
00194
00195
00196 inline void Barge_object::set_center
00197 (
00198 )
00199 {
00200 center = get_tile();
00201 center.tx = (center.tx - xtiles/2 + c_num_tiles)%c_num_tiles;
00202 center.ty = (center.ty - ytiles/2 + c_num_tiles)%c_num_tiles;
00203 }
00204
00205
00206
00207
00208
00209
00210 int Barge_object::okay_to_rotate
00211 (
00212 Tile_coord pos
00213 )
00214 {
00215 int lift = get_lift();
00216
00217 int move_type = (lift >= 10) ? (MOVE_LEVITATE) : MOVE_ALL_TERRAIN;
00218
00219 Rectangle foot = get_tile_footprint();
00220 int xts = get_xtiles(), yts = get_ytiles();
00221
00222 Rectangle newfoot(pos.tx - yts + 1, pos.ty - xts + 1, yts, xts);
00223 int new_lift;
00224 if (newfoot.y < foot.y)
00225
00226 if (Map_chunk::is_blocked(4, lift,
00227 newfoot.x, newfoot.y, newfoot.w, foot.y - newfoot.y,
00228 new_lift, move_type, 0) || new_lift != lift)
00229 return 0;
00230 if (foot.y + foot.h < newfoot.y + newfoot.h)
00231
00232 if (Map_chunk::is_blocked(4, lift,
00233 newfoot.x, foot.y + foot.h, newfoot.w,
00234 newfoot.y + newfoot.h - (foot.y + foot.h),
00235 new_lift, move_type, 0) || new_lift != lift)
00236 return 0;
00237 if (newfoot.x < foot.x)
00238 if (Map_chunk::is_blocked(4, lift,
00239 newfoot.x, newfoot.y, foot.x - newfoot.x, newfoot.h,
00240 new_lift, move_type, 0) || new_lift != lift)
00241 return 0;
00242 if (foot.x + foot.w < newfoot.x + newfoot.w)
00243
00244 if (Map_chunk::is_blocked(4, lift,
00245 foot.x + foot.w, newfoot.y,
00246 newfoot.x + newfoot.w - (foot.x + foot.w), newfoot.h,
00247 new_lift, move_type, 0) || new_lift != lift)
00248 return 0;
00249 return 1;
00250 }
00251
00252
00253
00254
00255
00256 Barge_object::~Barge_object
00257 (
00258 )
00259 {
00260 delete path;
00261 }
00262
00263
00264
00265
00266
00267
00268 void Barge_object::gather
00269 (
00270 )
00271 {
00272 if (!gmap->get_chunk_safely(get_cx(), get_cy()))
00273 return;
00274 ice_raft = false;
00275 objects.resize(perm_count);
00276
00277 Rectangle foot = get_tile_footprint();
00278 int lift = get_lift();
00279
00280 Chunk_intersect_iterator next_chunk(foot);
00281 Rectangle tiles;
00282 int cx, cy;
00283 bool si = Game::get_game_type() == SERPENT_ISLE;
00284 while (next_chunk.get_next(tiles, cx, cy))
00285 {
00286 Map_chunk *chunk = gmap->get_chunk(cx, cy);
00287 tiles.x += cx*c_tiles_per_chunk;
00288 tiles.y += cy*c_tiles_per_chunk;
00289 Game_object *obj;
00290 Object_iterator next(chunk->get_objects());
00291 while ((obj = next.get_next()) != 0)
00292 {
00293 if (obj == this)
00294 continue;
00295 if (obj->is_egg())
00296 continue;
00297 Tile_coord t = obj->get_tile();
00298 Shape_info& info = obj->get_info();
00299
00300 if (tiles.has_point(t.tx, t.ty) &&
00301 t.tz >= lift - 1 &&
00302 t.tz + info.get_3d_height() > lift &&
00303 (info.is_barge_part() || t.tz < lift + 5) &&
00304 obj->get_owner() != this)
00305 {
00306 objects.append(obj);
00307 if (si)
00308 {
00309 if (obj->get_shapenum() == 0x1f8)
00310 ice_raft = true;
00311
00312 else if (obj->get_shapenum() == 0xd7)
00313 xtiles = 20;
00314 }
00315 }
00316 }
00317 }
00318 set_center();
00319
00320 Map_chunk *chunk = gmap->get_chunk_safely(
00321 center.tx/c_tiles_per_chunk, center.ty/c_tiles_per_chunk);
00322 if (boat == -1 && chunk != 0)
00323 {
00324 ShapeID flat = chunk->get_flat(center.tx%c_tiles_per_chunk,
00325 center.ty%c_tiles_per_chunk);
00326 if (flat.is_invalid())
00327 boat = 0;
00328 else
00329 {
00330 Shape_info& info = flat.get_info();
00331 boat = info.is_water();
00332 }
00333 }
00334 gathered = true;
00335 }
00336
00337
00338
00339
00340
00341 void Barge_object::add_dirty
00342 (
00343 )
00344 {
00345 int x, y;
00346 gwin->get_shape_location(this, x, y);
00347 int w = xtiles*c_tilesize, h = ytiles*c_tilesize;
00348 Rectangle box(x - w, y - h, w, h);
00349 box.enlarge(10);
00350 if (dir%2)
00351 { box.x -= 18; box.w += 36; }
00352 else
00353 { box.y -= 18; box.h += 36; }
00354 box = gwin->clip_to_win(box);
00355 gwin->add_dirty(box);
00356 }
00357
00358
00359
00360
00361
00362
00363 void Barge_object::finish_move
00364 (
00365 Tile_coord *positions
00366 )
00367 {
00368 set_center();
00369 int cnt = objects.size();
00370 for (int i = 0; i < cnt; i++)
00371 {
00372 Game_object *obj = get_object(i);
00373 if (i < perm_count)
00374 obj->set_owner(this);
00375 obj->move(positions[i]);
00376 }
00377 delete [] positions;
00378
00379 gwin->scroll_if_needed(center);
00380 }
00381
00382
00383
00384
00385
00386 void Barge_object::face_direction
00387 (
00388 int ndir
00389 )
00390 {
00391 ndir /= 2;
00392 switch ((4 + ndir - dir)%4)
00393 {
00394 case 1:
00395 turn_right();
00396 break;
00397 case 2:
00398 turn_around();
00399 break;
00400 case 3:
00401 turn_left();
00402 break;
00403 default:
00404 break;
00405 }
00406 }
00407
00408
00409
00410
00411
00412 void Barge_object::travel_to_tile
00413 (
00414 Tile_coord dest,
00415 int speed
00416 )
00417 {
00418 if (!path)
00419 path = new Zombie();
00420
00421 if (path->NewPath(get_tile(), dest, 0))
00422 {
00423 frame_time = speed;
00424
00425 Tile_coord cur = get_tile();
00426 int dy = Tile_coord::delta(cur.ty, dest.ty),
00427 dx = Tile_coord::delta(cur.tx, dest.tx);
00428 int ndir = Get_direction4(-dy, dx);
00429 if (!ice_raft)
00430 face_direction(ndir);
00431 if (!in_queue())
00432 gwin->get_tqueue()->add(Game::get_ticks(), this, 0L);
00433 }
00434 else
00435 frame_time = 0;
00436 }
00437
00438
00439
00440
00441
00442 void Barge_object::turn_right
00443 (
00444 )
00445 {
00446 add_dirty();
00447
00448 Tile_coord rot = Rotate90r(gwin, this, xtiles, ytiles, center);
00449 if (!okay_to_rotate(rot))
00450 return;
00451 Container_game_object::move(rot.tx, rot.ty, rot.tz);
00452 swap_dims();
00453 dir = (dir + 1)%4;
00454 int cnt = objects.size();
00455
00456 Tile_coord *positions = new Tile_coord[cnt];
00457 for (int i = 0; i < cnt; i++)
00458 {
00459 Game_object *obj = get_object(i);
00460 int frame = obj->get_framenum();
00461 Shape_info& info = obj->get_info();
00462 positions[i] = Rotate90r(gwin, obj, info.get_3d_xtiles(frame),
00463 info.get_3d_ytiles(frame), center);
00464 obj->remove_this(1);
00465
00466 obj->set_frame(obj->get_rotated_frame(1));
00467 obj->set_invalid();
00468 }
00469 finish_move(positions);
00470 }
00471
00472
00473
00474
00475
00476 void Barge_object::turn_left
00477 (
00478 )
00479 {
00480 add_dirty();
00481
00482 Tile_coord rot = Rotate90l(gwin, this, xtiles, ytiles, center);
00483 if (!okay_to_rotate(rot))
00484 return;
00485 Container_game_object::move(rot.tx, rot.ty, rot.tz);
00486 swap_dims();
00487 dir = (dir + 3)%4;
00488 int cnt = objects.size();
00489
00490 Tile_coord *positions = new Tile_coord[cnt];
00491 for (int i = 0; i < cnt; i++)
00492 {
00493 Game_object *obj = get_object(i);
00494 int frame = obj->get_framenum();
00495 Shape_info& info = obj->get_info();
00496 positions[i] = Rotate90l(gwin, obj, info.get_3d_xtiles(frame),
00497 info.get_3d_ytiles(frame), center);
00498 obj->remove_this(1);
00499
00500 obj->set_frame(obj->get_rotated_frame(3));
00501 obj->set_invalid();
00502 }
00503 finish_move(positions);
00504 }
00505
00506
00507
00508
00509
00510 void Barge_object::turn_around
00511 (
00512 )
00513 {
00514 add_dirty();
00515
00516 Tile_coord rot = Rotate180(gwin, this, xtiles, ytiles, center);
00517 Container_game_object::move(rot.tx, rot.ty, rot.tz);
00518 dir = (dir + 2)%4;
00519 int cnt = objects.size();
00520
00521 Tile_coord *positions = new Tile_coord[cnt];
00522 for (int i = 0; i < cnt; i++)
00523 {
00524 Game_object *obj = get_object(i);
00525 int frame = obj->get_framenum();
00526 Shape_info& info = obj->get_info();
00527 positions[i] = Rotate180(gwin, obj, info.get_3d_xtiles(frame),
00528 info.get_3d_ytiles(frame), center);
00529 obj->remove_this(1);
00530
00531 obj->set_frame(obj->get_rotated_frame(2));
00532 obj->set_invalid();
00533 }
00534 finish_move(positions);
00535 }
00536
00537
00538
00539
00540
00541 void Barge_object::done
00542 (
00543 )
00544 {
00545 gathered = false;
00546 static int norecurse = 0;
00547 if (norecurse > 0)
00548 return;
00549 norecurse++;
00550 if (boat == 1)
00551 {
00552 int cnt = objects.size();
00553 for (int i = 0; i < cnt; i++)
00554 {
00555 Game_object *obj = objects[i];
00556 if (obj->get_shapenum() == 251 &&
00557 (obj->get_framenum()&7) < 4)
00558 {
00559 obj->activate();
00560 break;
00561 }
00562 }
00563 }
00564 norecurse--;
00565 }
00566
00567
00568
00569
00570
00571 int Barge_object::okay_to_land
00572 (
00573 )
00574 {
00575 Rectangle foot = get_tile_footprint();
00576 int lift = get_lift();
00577
00578 Chunk_intersect_iterator next_chunk(foot);
00579 Rectangle tiles;
00580 int cx, cy;
00581 while (next_chunk.get_next(tiles, cx, cy))
00582 {
00583 Map_chunk *chunk = gmap->get_chunk(cx, cy);
00584 for (int ty = tiles.y; ty < tiles.y + tiles.h; ty++)
00585 for (int tx = tiles.x; tx < tiles.x + tiles.w; tx++)
00586 if (chunk->get_highest_blocked(lift, tx, ty)
00587 != -1)
00588 return (0);
00589 }
00590 return (1);
00591 }
00592
00593
00594
00595
00596
00597 void Barge_object::handle_event
00598 (
00599 unsigned long curtime,
00600 long udata
00601 )
00602 {
00603 if (!path || !frame_time || gwin->get_moving_barge() != this)
00604 return;
00605 Tile_coord tile;
00606
00607 if (!path->GetNextStep(tile) || !step(tile))
00608 frame_time = 0;
00609
00610 else if (!first_step && (!path->GetNextStep(tile) || !step(tile)))
00611 frame_time = 0;
00612 else
00613 gwin->get_tqueue()->add(curtime + frame_time, this, udata);
00614 first_step = false;
00615 }
00616
00617
00618
00619
00620
00621 void Barge_object::move
00622 (
00623 int newtx,
00624 int newty,
00625 int newlift
00626 )
00627 {
00628 if (!gathered)
00629 gather();
00630
00631 add_dirty();
00632
00633 Tile_coord old = get_tile();
00634
00635 Container_game_object::move(newtx, newty, newlift);
00636
00637 int dx = newtx - old.tx, dy = newty - old.ty, dz = newlift - old.tz;
00638 int cnt = objects.size();
00639
00640 Tile_coord *positions = new Tile_coord[cnt];
00641 int i;
00642 for (i = 0; i < cnt; i++)
00643 {
00644 Game_object *obj = get_object(i);
00645 Tile_coord ot = obj->get_tile();
00646
00647 positions[i] = Tile_coord(
00648 (ot.tx + dx + c_num_tiles)%c_num_tiles,
00649 (ot.ty + dy + c_num_tiles)%c_num_tiles,
00650 ot.tz + dz);
00651 obj->remove_this(1);
00652 obj->set_invalid();
00653
00654 int frame = obj->get_framenum();
00655 switch (obj->get_shapenum())
00656 {
00657 case 774:
00658 obj->set_frame(((frame + 1)&3)|(frame&32));
00659 break;
00660 case 796:
00661 obj->set_frame(((frame + 4)&15)|(frame&32));
00662 break;
00663 }
00664 }
00665 finish_move(positions);
00666 }
00667
00668
00669
00670
00671
00672 void Barge_object::remove
00673 (
00674 Game_object *obj
00675 )
00676 {
00677 obj->set_owner(0);
00678 obj->remove_this(1);
00679 }
00680
00681
00682
00683
00684
00685
00686
00687 bool Barge_object::add
00688 (
00689 Game_object *obj,
00690 bool dont_check,
00691 bool combine
00692
00693 )
00694 {
00695 objects.append(obj);
00696 return (false);
00697 }
00698
00699
00700
00701
00702
00703
00704
00705 int Barge_object::drop
00706 (
00707 Game_object *obj
00708 )
00709 {
00710 return 0;
00711 }
00712
00713
00714
00715
00716
00717 void Barge_object::paint
00718 (
00719 )
00720 {
00721
00722
00723 if(gwin->paint_eggs)
00724 Container_game_object::paint();
00725 }
00726
00727
00728
00729
00730
00731
00732
00733
00734 int Barge_object::step
00735 (
00736 Tile_coord t,
00737 int
00738 )
00739 {
00740 if (!gathered)
00741 gather();
00742 Tile_coord cur = get_tile();
00743
00744 int move_type;
00745 if (cur.tz >= 10)
00746 {
00747 move_type = MOVE_LEVITATE;
00748 boat = 0;
00749 }
00750 else if (boat)
00751 {
00752 move_type = MOVE_SWIM;
00753
00754 if (Game::get_game_type() == SERPENT_ISLE)
00755 {
00756 int sx = cur.tx/c_tiles_per_schunk,
00757 sy = cur.ty/c_tiles_per_schunk;
00758 if (sx == 8 && sy == 9)
00759 move_type |= MOVE_WALK;
00760 }
00761 }
00762 else move_type = MOVE_WALK;
00763
00764 if (Map_chunk::is_blocked(get_xtiles(), get_ytiles(),
00765 4, cur, t, move_type, 0, 0))
00766 return (0);
00767 move(t.tx, t.ty, t.tz);
00768
00769 Map_chunk *nlist = gmap->get_chunk(get_cx(), get_cy());
00770 nlist->activate_eggs(gwin->get_main_actor(), t.tx, t.ty, t.tz,
00771 cur.tx, cur.ty);
00772 return (1);
00773 }
00774
00775
00776
00777
00778
00779 void Barge_object::write_ireg
00780 (
00781 DataSource *out
00782 )
00783 {
00784 unsigned char buf[13];
00785 buf[0] = 12;
00786 unsigned char *ptr = &buf[1];
00787 write_common_ireg(ptr);
00788 ptr += 4;
00789
00790 *ptr++ = xtiles;
00791 *ptr++ = ytiles;
00792 *ptr++ = 0;
00793
00794
00795 *ptr++ = (dir<<1) | ((gwin->get_moving_barge() == this)<<3);
00796 *ptr++ = 0;
00797 *ptr++ = (get_lift()&15)<<4;
00798 *ptr++ = 0;
00799 *ptr++ = 0;
00800 out->write((char*)buf, sizeof(buf));
00801
00802 for (int i = 0; i < perm_count; i++)
00803 {
00804 Game_object *obj = get_object(i);
00805 obj->write_ireg(out);
00806 }
00807 out->write1(0x01);
00808
00809 Game_map::write_scheduled(out, this);
00810 }
00811
00812
00813 int Barge_object::get_ireg_size()
00814 {
00815
00816 if (gwin->get_moving_barge() == this || Usecode_script::find(this))
00817 return -1;
00818
00819 int total_size = 13;
00820
00821 for (int i = 0; i < perm_count; i++)
00822 {
00823 Game_object *obj = get_object(i);
00824 int size = obj->get_ireg_size();
00825
00826 if (size < 0) return -1;
00827
00828 total_size += size;
00829 }
00830
00831 total_size += 1;
00832
00833 return total_size;
00834 }
00835
00836
00837
00838
00839
00840 void Barge_object::elements_read
00841 (
00842 )
00843 {
00844 perm_count = 0;
00845 complete = true;
00846 }
00847