00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifdef HAVE_CONFIG_H
00023 # include <config.h>
00024 #endif
00025
00026 #include "objs.h"
00027 #include "chunks.h"
00028 #include "objiter.h"
00029 #include "egg.h"
00030 #include "gamewin.h"
00031 #include "gamemap.h"
00032 #include "actors.h"
00033 #include "ucmachine.h"
00034 #include "items.h"
00035 #include "dir.h"
00036 #include "ordinfo.h"
00037 #include "game.h"
00038 #include "Gump_manager.h"
00039 #include "effects.h"
00040 #include "databuf.h"
00041
00042 #ifndef ALPHA_LINUX_CXX
00043 # include <cstring>
00044 # include <cstdio>
00045 #endif
00046 #include <algorithm>
00047
00048 #ifdef USE_EXULTSTUDIO
00049 #include "cheat.h"
00050 #include "server.h"
00051 #include "objserial.h"
00052 #include "servemsg.h"
00053 #endif
00054
00055 #ifndef UNDER_CE
00056 using std::cerr;
00057 using std::cout;
00058 using std::endl;
00059 using std::memcpy;
00060 using std::memset;
00061 using std::rand;
00062 using std::ostream;
00063 using std::strchr;
00064 using std::string;
00065 #endif
00066
00067
00068 short Tile_coord::neighbors[16] = {0,-1, 1,-1, 1,0, 1,1, 0,1,
00069 -1,1, -1,0, -1,-1 };
00070 Game_object *Game_object::editing = 0;
00071
00072 unsigned char Game_object::rotate[8] = { 0, 0, 48, 48, 16, 16, 32, 32};
00073
00074 extern bool combat_trace;
00075
00076
00077
00078
00079
00080 int Game_object::get_direction
00081 (
00082 Game_object *o2
00083 ) const
00084 {
00085 Tile_coord t1 = get_tile();
00086 Tile_coord t2 = o2->get_tile();
00087
00088 return (int) Get_direction(t1.ty - t2.ty, t2.tx - t1.tx);
00089 }
00090
00091
00092
00093
00094
00095 int Game_object::get_direction
00096 (
00097 Tile_coord t2
00098 ) const
00099 {
00100 Tile_coord t1 = get_tile();
00101
00102 return (int) Get_direction(t1.ty - t2.ty, t2.tx - t1.tx);
00103 }
00104
00105
00106
00107
00108
00109 Map_chunk *Game_object::get_chunk
00110 (
00111 )
00112 {
00113 return gmap->get_chunk(cx, cy);
00114 }
00115
00116
00117
00118
00119 static int Has_quantity
00120 (
00121 int shnum
00122 )
00123 {
00124 Shape_info& info = ShapeID::get_info(shnum);
00125 return info.has_quantity();
00126 }
00127
00128 static int Has_hitpoints(int shnum)
00129 {
00130 Shape_info& info = ShapeID::get_info(shnum);
00131 return ((info.get_shape_class() == Shape_info::has_hp) ||
00132 (info.get_shape_class() == Shape_info::container));
00133
00134
00135 }
00136
00137 const int MAX_QUANTITY = 100;
00138
00139
00140
00141
00142
00143 int Game_object::get_quantity
00144 (
00145 ) const
00146 {
00147 int shnum = get_shapenum();
00148 if (Has_quantity(shnum))
00149 {
00150 int qual = quality & 0x7f;
00151 return qual ? qual : 1;
00152 }
00153 else
00154 return 1;
00155 }
00156
00157 int Game_object::get_obj_hp() const
00158 {
00159 int shnum = get_shapenum();
00160 if (Has_hitpoints(shnum))
00161 return quality;
00162 else
00163 return 0;
00164 }
00165
00166 void Game_object::set_obj_hp(int hp)
00167 {
00168 int shnum = get_shapenum();
00169 if (Has_hitpoints(shnum))
00170 set_quality(hp);
00171 }
00172
00173
00174
00175
00176
00177 int Game_object::get_volume
00178 (
00179 ) const
00180 {
00181 int vol = get_info().get_volume();
00182 return vol;
00183 }
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193 int Game_object::modify_quantity
00194 (
00195 int delta,
00196 bool *del
00197 )
00198 {
00199 if (del)
00200 *del = false;
00201 if (!Has_quantity(get_shapenum()))
00202 {
00203 if (delta > 0)
00204 return (delta);
00205 remove_this();
00206 if (del)
00207 *del = true;
00208 return (delta + 1);
00209 }
00210 int quant = quality&0x7f;
00211 if (!quant)
00212 quant = 1;
00213 int newquant = quant + delta;
00214 if (delta >= 0)
00215 {
00216 if (newquant > MAX_QUANTITY)
00217 newquant = MAX_QUANTITY;
00218 }
00219 else if (newquant <= 0)
00220 {
00221 remove_this();
00222 if (del)
00223 *del = true;
00224 return (delta + quant);
00225 }
00226 int oldvol = get_volume();
00227 quality = (char) newquant;
00228 int shapenum = get_shapenum();
00229
00230 int num_frames = get_num_frames();
00231 int new_frame = newquant - 1;
00232 if (new_frame > 7)
00233 new_frame = 7;
00234 if (shapenum == 565 ||
00235 shapenum == 636)
00236 set_frame(0);
00237 else if (shapenum != 842)
00238
00239 set_frame(num_frames == 32 ? 24 + new_frame : new_frame);
00240
00241 Container_game_object *owner = get_owner();
00242 if (owner)
00243 owner->modify_volume_used(get_volume() - oldvol);
00244 return (delta - (newquant - quant));
00245 }
00246
00247
00248
00249
00250
00251
00252 int Game_object::get_dir_facing
00253 (
00254 ) const
00255 {
00256 int reflect = get_framenum()&(16 | 32);
00257 switch (reflect)
00258 {
00259 case 0:
00260 return (int) north;
00261 case 48:
00262 return (int) east;
00263 case 16:
00264 return (int) south;
00265 case 32:
00266 default:
00267 return (int) west;
00268 }
00269 }
00270
00271
00272
00273
00274
00275
00276 void Game_object::move
00277 (
00278 int newtx,
00279 int newty,
00280 int newlift
00281 )
00282 {
00283
00284 int newcx = newtx/c_tiles_per_chunk, newcy = newty/c_tiles_per_chunk;
00285 Map_chunk *newchunk = gmap->get_chunk_safely(newcx, newcy);
00286 if (!newchunk)
00287 return;
00288
00289 Map_chunk *oldchunk = gmap->get_chunk_safely(cx, cy);
00290 if (oldchunk)
00291 {
00292 gwin->add_dirty(this);
00293 oldchunk->remove(this);
00294 }
00295 set_lift(newlift);
00296 shape_pos = ((newtx%c_tiles_per_chunk) << 4) + newty%c_tiles_per_chunk;
00297 newchunk->add(this);
00298 gwin->add_dirty(this);
00299 }
00300
00301
00302
00303
00304
00305 void Game_object::change_frame
00306 (
00307 int frnum
00308 )
00309 {
00310 gwin->add_dirty(this);
00311 set_frame(frnum);
00312 gwin->add_dirty(this);
00313 }
00314
00315
00316
00317
00318
00319
00320
00321 int Game_object::swap_positions
00322 (
00323 Game_object *obj2
00324 )
00325 {
00326 Shape_info& inf1 = get_info();
00327 Shape_info& inf2 = obj2->get_info();
00328 if (inf1.get_3d_xtiles() != inf2.get_3d_xtiles() ||
00329 inf1.get_3d_ytiles() != inf2.get_3d_ytiles())
00330 return 0;
00331 Tile_coord p1 = get_tile();
00332 Tile_coord p2 = obj2->get_tile();
00333 remove_this(1);
00334 set_invalid();
00335 obj2->remove_this(1);
00336 obj2->set_invalid();
00337 move(p2.tx, p2.ty, p2.tz);
00338 obj2->move(p1.tx, p1.ty, p1.tz);
00339 return (1);
00340 }
00341
00342
00343
00344
00345
00346 void Game_object::clear_dependencies
00347 (
00348 )
00349 {
00350 Game_object_vector::const_iterator X;
00351
00352
00353 for(X = dependencies.begin(); X != dependencies.end(); ++X )
00354 (**X).dependors.remove(this);
00355 dependencies.clear();
00356
00357
00358 for(X = dependors.begin(); X != dependors.end(); ++X )
00359 (**X).dependencies.remove(this);
00360 dependors.clear();
00361 }
00362
00363
00364
00365
00366
00367
00368 static int Check_mask
00369 (
00370 Game_window *gwin,
00371 Game_object *obj,
00372 int mask
00373 )
00374 {
00375 Shape_info& info = obj->get_info();
00376 if ((mask&(4|8)) &&
00377 !info.is_npc())
00378 return 0;
00379 Shape_info::Shape_class sclass = info.get_shape_class();
00380
00381 if ((sclass == Shape_info::hatchable || sclass == Shape_info::barge) &&
00382 !(mask&0x10))
00383 return 0;
00384 if (info.is_transparent() &&
00385 !(mask&0x80))
00386 return 0;
00387
00388 if (obj->get_flag(Obj_flags::invisible))
00389 if (!(mask&20))
00390 {
00391 if (!(mask&0x40))
00392 return 0;
00393 if (!obj->get_flag(Obj_flags::in_party))
00394 return 0;
00395 }
00396 return 1;
00397 }
00398
00399
00400
00401
00402
00403
00404
00405 #define FN_VECTOR Egg_vector
00406 #define FN_OBJECT Egg_object
00407 #define FN_CAST ->as_egg()
00408 #include "find_nearby.h"
00409
00410 int Game_object::find_nearby_eggs
00411 (
00412 Egg_vector& vec,
00413 int shapenum,
00414 int delta,
00415 int qual,
00416 int frnum
00417 ) const
00418 {
00419 return Game_object::find_nearby (vec, get_tile(), shapenum,
00420 delta, 16, qual, frnum);
00421 }
00422
00423 #define FN_VECTOR Actor_vector
00424 #define FN_OBJECT Actor
00425 #define FN_CAST ->as_actor()
00426 #include "find_nearby.h"
00427
00428 int Game_object::find_nearby_actors
00429 (
00430 Actor_vector& vec,
00431 int shapenum,
00432 int delta
00433 ) const
00434 {
00435 return Game_object::find_nearby(vec, get_tile(), shapenum,
00436 delta, 8, c_any_qual, c_any_framenum);
00437 }
00438
00439 #define FN_VECTOR Game_object_vector
00440 #define FN_OBJECT Game_object
00441 #define FN_CAST
00442 #include "find_nearby.h"
00443
00444 int Game_object::find_nearby
00445 (
00446 Game_object_vector& vec,
00447 int shapenum,
00448 int delta,
00449 int mask,
00450 int qual,
00451 int framenum
00452 ) const
00453 {
00454 return Game_object::find_nearby(vec, get_tile(), shapenum,
00455 delta, mask, qual, framenum);
00456 }
00457
00458
00459
00460
00461 class Object_closest_sorter
00462 {
00463 Tile_coord pos;
00464 public:
00465 Object_closest_sorter(Tile_coord p) : pos(p)
00466 { }
00467 bool operator()(const Game_object *o1, const Game_object *o2)
00468 {
00469 Tile_coord t1 = o1->get_tile(),
00470 t2 = o2->get_tile();
00471 return t1.distance(pos) < t2.distance(pos);
00472 }
00473 };
00474
00475
00476
00477
00478
00479
00480
00481 Game_object *Game_object::find_closest
00482 (
00483 Game_object_vector& vec,
00484 int *shapenums,
00485
00486 int num_shapes,
00487 int dist
00488 )
00489 {
00490 int i;
00491 for (i = 0; i < num_shapes; i++)
00492
00493 find_nearby(vec, shapenums[i], dist, 0xb0);
00494 int cnt = vec.size();
00495 if (!cnt)
00496 return (0);
00497 if (cnt > 1)
00498 std::sort(vec.begin(), vec.end(),
00499 Object_closest_sorter(get_tile()));
00500 return *(vec.begin());
00501 }
00502
00503
00504
00505
00506
00507
00508
00509 Game_object *Game_object::find_closest
00510 (
00511 int *shapenums,
00512
00513 int num_shapes,
00514 int dist
00515 )
00516 {
00517 Game_object_vector vec;
00518 int i;
00519 for (i = 0; i < num_shapes; i++)
00520
00521 find_nearby(vec, shapenums[i], dist, 0xb0);
00522 int cnt = vec.size();
00523 if (!cnt)
00524 return (0);
00525 Game_object *closest = 0;
00526 int best_dist = 10000;
00527
00528 Tile_coord loc = get_tile();
00529 for (Game_object_vector::const_iterator it = vec.begin();
00530 it != vec.end(); ++it)
00531 {
00532 Game_object *obj = *it;
00533 int dist = obj->get_tile().distance(loc);
00534 if (dist < best_dist)
00535 {
00536 closest = obj;
00537 best_dist = dist;
00538 }
00539 }
00540 return (closest);
00541 }
00542
00543
00544
00545
00546
00547 Rectangle Game_object::get_footprint
00548 (
00549 )
00550 {
00551 Shape_info& info = get_info();
00552
00553 int frame = get_framenum();
00554 int xtiles = info.get_3d_xtiles(frame);
00555 int ytiles = info.get_3d_ytiles(frame);
00556 Tile_coord t = get_tile();
00557 Rectangle foot((t.tx - xtiles + 1 + c_num_tiles)%c_num_tiles,
00558 (t.ty - ytiles + 1 + c_num_tiles)%c_num_tiles,
00559 xtiles, ytiles);
00560 return foot;
00561 }
00562
00563
00564
00565
00566
00567 bool Game_object::blocks
00568 (
00569 Tile_coord tile
00570 )
00571 {
00572 Tile_coord t = get_tile();
00573 if (t.tx < tile.tx || t.ty < tile.ty || t.tz > tile.tz)
00574 return false;
00575 Shape_info& info = get_info();
00576 int ztiles = info.get_3d_height();
00577 if (!ztiles || !info.is_solid())
00578 return false;
00579
00580 int frame = get_framenum();
00581 if (tile.tx > t.tx - info.get_3d_xtiles(frame) &&
00582 tile.ty > t.ty - info.get_3d_ytiles(frame) &&
00583 tile.tz < t.tz + ztiles)
00584 return true;
00585 return false;
00586 }
00587
00588
00589
00590
00591
00592
00593
00594 Game_object *Game_object::find_blocking
00595 (
00596 Tile_coord tile
00597 )
00598 {
00599 Map_chunk *chunk = gmap->get_chunk(tile.tx/c_tiles_per_chunk,
00600 tile.ty/c_tiles_per_chunk);
00601 Game_object *obj;
00602 Object_iterator next(chunk->get_objects());
00603 while ((obj = next.get_next()) != 0)
00604 if (obj->blocks(tile))
00605 return obj;
00606 return (0);
00607 }
00608
00609
00610
00611
00612
00613
00614
00615 Game_object *Game_object::find_door
00616 (
00617 Tile_coord tile
00618 )
00619 {
00620 Map_chunk *chunk = gmap->get_chunk(tile.tx/c_tiles_per_chunk,
00621 tile.ty/c_tiles_per_chunk);
00622 return chunk->find_door(tile);
00623 }
00624
00625
00626
00627
00628
00629 int Game_object::is_closed_door
00630 (
00631 ) const
00632 {
00633 Shape_info& info = get_info();
00634 if (!info.is_door())
00635 return 0;
00636
00637 int xtiles = info.get_3d_xtiles(), ytiles = info.get_3d_ytiles();
00638
00639 Tile_coord doortile = get_tile();
00640 Tile_coord before, after;
00641 if (xtiles > ytiles)
00642 {
00643 before = doortile + Tile_coord(-xtiles, 0, 0);
00644 after = doortile + Tile_coord(1, 0, 0);
00645 }
00646 else
00647 {
00648 before = doortile + Tile_coord(0, -ytiles, 0);
00649 after = doortile + Tile_coord(0, 1, 0);
00650 }
00651
00652 return (Map_chunk::is_blocked(before) &&
00653 Map_chunk::is_blocked(after));
00654 }
00655
00656
00657
00658
00659
00660
00661
00662 Game_object *Game_object::get_outermost
00663 (
00664 )
00665 {
00666 Game_object *top = this;
00667 Game_object *above;
00668 while ((above = top->get_owner()) != 0)
00669 top = above;
00670 return top;
00671 }
00672
00673
00674
00675
00676
00677 void Game_object::say
00678 (
00679 const char *text
00680 )
00681 {
00682 eman->add_text(text, this);
00683 }
00684
00685
00686
00687
00688
00689 void Game_object::say
00690 (
00691 int from, int to
00692 )
00693 {
00694 if (from > to) return;
00695 int offset = rand()%(to - from + 1);
00696 if (from + offset < num_item_names)
00697 say(item_names[from + offset]);
00698 }
00699
00700
00701
00702
00703
00704 void Game_object::paint
00705 (
00706 )
00707 {
00708 int x, y;
00709 gwin->get_shape_location(this, x, y);
00710 paint_shape(x, y);
00711 }
00712
00713
00714
00715
00716
00717 void Game_object::paint_outline
00718 (
00719 Pixel_colors pix
00720 )
00721 {
00722 int x, y;
00723 gwin->get_shape_location(this, x, y);
00724 ShapeID::paint_outline(x, y, pix);
00725 }
00726
00727
00728
00729
00730
00731 void Game_object::activate
00732 (
00733 int event
00734 )
00735 {
00736 if (edit())
00737 return;
00738 int usefun = get_shapenum();
00739
00740 if (usefun == 0x2cb && Game::get_game_type() == SERPENT_ISLE)
00741 {
00742 gumpman->add_gump(this, 65);
00743 return;
00744 }
00745
00746 if (usefun == 0x282 && get_quality() >= 100 && get_quality() < 180)
00747 usefun = 0x638;
00748 else if (usefun == 0x282 && get_quality() >= 180 &&
00749 Game::get_game_type() == SERPENT_ISLE )
00750 usefun = 0x63b;
00751 else if (usefun == 0x2c1 && get_quality() >= 213 &&
00752 Game::get_game_type() == SERPENT_ISLE )
00753 usefun = 0x62a;
00754 ucmachine->call_usecode(usefun, this,
00755 (Usecode_machine::Usecode_events) event);
00756 }
00757
00758
00759
00760
00761
00762 bool Game_object::edit
00763 (
00764 )
00765 {
00766 #ifdef USE_EXULTSTUDIO
00767 if (client_socket >= 0 &&
00768 cheat.in_map_editor())
00769 {
00770 editing = 0;
00771 Tile_coord t = get_tile();
00772 unsigned long addr = (unsigned long) this;
00773 std::string name = get_name();
00774 if (Object_out(client_socket, Exult_server::obj,
00775 addr, t.tx, t.ty, t.tz,
00776 get_shapenum(), get_framenum(), get_quality(),
00777 name) != -1)
00778 {
00779 cout << "Sent object data to ExultStudio" << endl;
00780 editing = this;
00781 }
00782 else
00783 cout << "Error sending object to ExultStudio" <<endl;
00784 return true;
00785 }
00786 #endif
00787 return false;
00788 }
00789
00790
00791
00792
00793
00794 void Game_object::update_from_studio
00795 (
00796 unsigned char *data,
00797 int datalen
00798 )
00799 {
00800 #ifdef USE_EXULTSTUDIO
00801 unsigned long addr;
00802 int tx, ty, tz;
00803 int shape, frame, quality;
00804 std::string name;
00805 if (!Object_in(data, datalen, addr, tx, ty, tz, shape, frame,
00806 quality, name))
00807 {
00808 cout << "Error decoding object" << endl;
00809 return;
00810 }
00811 Game_object *obj = (Game_object *) addr;
00812 if (!editing || obj != editing)
00813 {
00814 cout << "Obj from ExultStudio is not being edited" << endl;
00815 return;
00816 }
00817
00818 gwin->add_dirty(obj);
00819 obj->set_shape(shape, frame);
00820 gwin->add_dirty(obj);
00821 obj->set_quality(quality);
00822
00823 Tile_coord oldt = obj->get_tile();
00824 if (oldt.tx != tx || oldt.ty != ty || oldt.tz != tz)
00825 obj->move(tx, ty, tz);
00826 cout << "Object updated" << endl;
00827 #endif
00828 }
00829
00830
00831
00832
00833
00834
00835 void Game_object::remove_this
00836 (
00837 int nodel
00838 )
00839 {
00840 Map_chunk *chunk = gmap->get_chunk_safely(cx, cy);
00841 if (chunk)
00842 chunk->remove(this);
00843 if (!nodel)
00844 gwin->delete_object(this);
00845 }
00846
00847
00848
00849
00850
00851 int Game_object::is_dragable
00852 (
00853 ) const
00854 {
00855 return (0);
00856 }
00857
00858
00859
00860
00861
00862 int Game_object::get_weight
00863 (
00864 int shnum,
00865 int quant
00866 )
00867 {
00868 int wt = quant * ShapeID::get_info(shnum).get_weight();
00869
00870 if (shnum == 842 || shnum == 644 ||
00871 (Game::get_game_type() == SERPENT_ISLE &&
00872
00873 (shnum == 951 || shnum == 952 || shnum == 948)))
00874 {
00875 wt /= 10;
00876 if (wt <= 0) wt = 1;
00877 }
00878
00879 if (Has_quantity(shnum))
00880 if (wt <= 0) wt = 1;
00881
00882 return wt;
00883 }
00884
00885
00886
00887
00888
00889 int Game_object::get_weight
00890 (
00891 )
00892 {
00893 return get_weight(get_shapenum(), get_quantity());
00894 }
00895
00896
00897
00898
00899
00900
00901
00902 int Game_object::get_max_weight
00903 (
00904 )
00905 {
00906
00907 Container_game_object *own = get_owner();
00908 return own ? own->get_max_weight() : 0;
00909 }
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920 bool Game_object::add
00921 (
00922 Game_object *obj,
00923 bool dont_check,
00924 bool combine
00925
00926 )
00927 {
00928 return combine ? drop(obj)!=0 : false;
00929 }
00930
00931
00932
00933
00934
00935
00936
00937 int Game_object::drop
00938 (
00939 Game_object *obj
00940 )
00941 {
00942 int shapenum = get_shapenum();
00943 if (obj->get_shapenum() != shapenum ||
00944 !Has_quantity(shapenum) ||
00945
00946
00947
00948 (shapenum == 842 && get_framenum() != obj->get_framenum()))
00949 return (0);
00950 int objq = obj->get_quantity();
00951 int total_quant = get_quantity() + objq;
00952 if (total_quant > MAX_QUANTITY)
00953 return (0);
00954 modify_quantity(objq);
00955 obj->remove_this();
00956 return (1);
00957 }
00958
00959
00960 #ifdef DEBUGLT
00961 static int rx1 = -1, ry1 = -1, rx2 = -1, ry2 = -1;
00962
00963 static void Debug_lt
00964 (
00965 int tx1, int ty1,
00966 int tx2, int ty2
00967 )
00968 {
00969 if (tx1 == rx1 && ty1 == ry1)
00970 {
00971 if (tx2 == rx2 && ty2 == ry2)
00972 cout << "Debug_lt" << endl;
00973 }
00974 }
00975 #endif
00976
00977
00978
00979
00980 inline void Compare_ranges
00981 (
00982 int from1, int to1,
00983 int from2, int to2,
00984
00985 int& cmp,
00986
00987 bool& overlap
00988 )
00989 {
00990 if (to1 < from2)
00991 {
00992 overlap = false;
00993 cmp = -1;
00994 }
00995 else if (to2 < from1)
00996 {
00997 overlap = false;
00998 cmp = 1;
00999 }
01000 else
01001 {
01002 overlap = true;
01003 if (from1 < from2)
01004 cmp = -1;
01005 else if (from1 > from2)
01006 cmp = 1;
01007 else if (to1 - from1 < to2 - from2)
01008 cmp = 1;
01009 else if (to1 - from1 > to2 - from2)
01010 cmp = -1;
01011 else
01012 cmp = 0;
01013 }
01014 }
01015
01016
01017
01018
01019
01020
01021
01022 int Game_object::compare
01023 (
01024 Ordering_info& inf1,
01025 Game_object *obj2
01026 )
01027 {
01028
01029 Rectangle r2 = gwin->get_shape_rect(obj2);
01030 if (!inf1.area.intersects(r2))
01031 return (0);
01032 Ordering_info inf2(gwin, obj2, r2);
01033 #ifdef DEBUGLT
01034 Debug_lt(inf1.tx, inf1.ty, inf2.tx, inf2.ty);
01035 #endif
01036 int xcmp, ycmp, zcmp;
01037
01038
01039 bool xover, yover, zover;
01040 Compare_ranges(inf1.xleft, inf1.xright, inf2.xleft, inf2.xright,
01041 xcmp, xover);
01042 Compare_ranges(inf1.yfar, inf1.ynear, inf2.yfar, inf2.ynear,
01043 ycmp, yover);
01044 Compare_ranges(inf1.zbot, inf1.ztop, inf2.zbot, inf2.ztop,
01045 zcmp, zover);
01046 if (!xcmp && !ycmp && !zcmp)
01047
01048
01049
01050 return (inf1.area.w < inf2.area.w &&
01051 inf1.area.h < inf2.area.h) ? -1 :
01052 (inf1.area.w > inf2.area.w &&
01053 inf1.area.h > inf2.area.h) ? 1 : 0;
01054
01055 if (xover & yover & zover)
01056 if (!inf1.zs)
01057 return !inf2.zs ? 0 : -1;
01058 else if (!inf2.zs)
01059 return 1;
01060 if (xcmp >= 0 && ycmp >= 0 && zcmp >= 0)
01061 return 1;
01062 if (xcmp <= 0 && ycmp <= 0 && zcmp <= 0)
01063 return -1;
01064 if (yover)
01065 {
01066 if (xover)
01067 return zcmp;
01068 else if (zover)
01069 return xcmp;
01070
01071 else if (!zcmp)
01072 return xcmp;
01073 else
01074 if (xcmp == zcmp)
01075 return xcmp;
01076 #if 1
01077
01078
01079 else if (inf1.ztop/5 < inf2.zbot/5 && inf2.info.occludes())
01080 return -1;
01081 else if (inf2.ztop/5 < inf1.zbot/5 && inf1.info.occludes())
01082 return 1;
01083 #endif
01084 else
01085 return 0;
01086 }
01087 else if (xover)
01088 {
01089 if (zover)
01090 return ycmp;
01091 else if (!zcmp)
01092 return ycmp;
01093 else
01094 return ycmp == zcmp ? ycmp : 0;
01095 }
01096
01097 else if (xcmp == -1)
01098 {
01099 if (ycmp == -1)
01100
01101 return (zover || zcmp <= 0) ? -1 : 0;
01102 }
01103 else if (ycmp == 1)
01104 if (zover || zcmp >= 0)
01105 return 1;
01106 #if 1
01107
01108
01109 else if (inf1.ztop/5 < inf2.zbot/5)
01110 return -1;
01111 else
01112 #endif
01113 return 0;
01114 return 0;
01115 }
01116
01117
01118
01119
01120
01121
01122
01123
01124 int Game_object::lt
01125 (
01126 Game_object& obj2
01127 )
01128 {
01129 Ordering_info ord(gwin, this);
01130 int cmp = compare(ord, &obj2);
01131 return cmp == -1 ? 1 : cmp == 1 ? 0 : -1;
01132 }
01133
01134
01135
01136
01137
01138
01139
01140 int Game_object::get_rotated_frame
01141 (
01142 int quads
01143 )
01144 {
01145 int curframe = get_framenum();
01146 int shapenum = get_shapenum();
01147 Shape_info& info = get_info();
01148 if (shapenum == 292)
01149 {
01150 int dir = curframe%4;
01151 return (curframe - dir) + (dir + quads)%4;
01152 }
01153 else if (info.is_barge_part())
01154 switch (quads)
01155 {
01156 case 1:
01157 return (curframe^32)^((curframe&32) ? 3 : 1);
01158 case 2:
01159 return curframe^2;
01160 case 3:
01161 return (curframe^32)^((curframe&32) ? 1 : 3);
01162 default:
01163 return curframe;
01164 }
01165 else
01166
01167 return curframe ^ ((quads%2)<<5);
01168 }
01169
01170
01171
01172
01173
01174
01175 int Game_object::attack_object
01176 (
01177 Actor *attacker,
01178 int weapon_shape,
01179 int ammo_shape
01180 )
01181 {
01182 int wpoints = 0;
01183 Weapon_info *winf;
01184 if (weapon_shape > 0)
01185 winf = ShapeID::get_info(weapon_shape).get_weapon_info();
01186 else if (ammo_shape > 0)
01187 winf = ShapeID::get_info(ammo_shape).get_weapon_info();
01188 else
01189 winf = attacker->get_weapon(wpoints);
01190 int usefun;
01191 if (winf && (usefun = winf->get_usecode()) != 0)
01192 ucmachine->call_usecode(usefun, this,
01193 Usecode_machine::weapon);
01194 if (!wpoints && winf)
01195 wpoints = winf->get_damage();
01196 if (!wpoints)
01197 return 0;
01198 if (attacker)
01199 wpoints += attacker->get_level() +
01200 attacker->get_effective_prop((int) Actor::strength);
01201 return wpoints;
01202 }
01203
01204
01205
01206
01207
01208
01209
01210 Game_object *Game_object::attacked
01211 (
01212 Actor *attacker,
01213 int weapon_shape,
01214
01215 int ammo_shape
01216 )
01217 {
01218 if (weapon_shape < 0)
01219 weapon_shape = -weapon_shape;
01220 int wpoints = attack_object(attacker, weapon_shape, ammo_shape);
01221 int shnum = get_shapenum();
01222 int frnum = get_framenum();
01223
01224 int hp = get_obj_hp();
01225
01226 if (!hp) {
01227
01228
01229
01230
01231 if (shnum == 432 || shnum == 433)
01232 {
01233 if (get_quality()==0 || weapon_shape==704)
01234
01235 if (frnum != 3 && frnum < 7)
01236 hp = 6;
01237 }
01238 else if (shnum == 270 || shnum == 376)
01239 {
01240 if (get_quality()==0 || weapon_shape==704)
01241
01242 if (frnum < 3 || (frnum >= 8 && frnum <= 10) ||
01243 (frnum >= 16 && frnum <= 18))
01244 hp = 6;
01245 }
01246
01247 else if (shnum == 743 && Game::get_game_type() == SERPENT_ISLE)
01248 hp = 1;
01249 else if (shnum == 704 && weapon_shape == 704) {
01250
01251
01252
01253 if (get_quality()==0) {
01254 Tile_coord pos = get_tile();
01255 eman->add_effect(
01256 new Explosion_effect(pos, this));
01257 }
01258 }
01259
01260 else if (shnum == 735 && ammo_shape == 722) {
01261 int newframe = !frnum ? (3*(rand()%8) + 1)
01262 : ((frnum%3) != 0 ? frnum + 1 : frnum);
01263 change_frame(newframe);
01264 }
01265 #if 0
01266 else if (shnum == 522 && frnum < 2) {
01267 if (get_quality() == 0 || get_quality() == 255)
01268 hp = 6;
01269 }
01270 #endif
01271
01272 }
01273
01274 string name = "<trap>";
01275 if (attacker)
01276 name = attacker->get_name();
01277
01278
01279 if (hp == 0) {
01280 if (combat_trace) {
01281 cout << name << " attacks " << get_name()
01282 << ". No effect." << endl;
01283 }
01284 return this;
01285 }
01286
01287 if (combat_trace) {
01288 cout << name << " hits " << get_name()
01289 << " for " << wpoints << " hit points, leaving "
01290 << hp - wpoints << " remaining" << endl;
01291 }
01292
01293 if (wpoints >= hp) {
01294
01295 eman->remove_text_effect(this);
01296 ucmachine->call_usecode(0x626, this, Usecode_machine::weapon);
01297 return 0;
01298 } else {
01299 set_obj_hp(hp - wpoints);
01300
01301 return this;
01302 }
01303 }
01304
01305
01306
01307
01308
01309 void Game_object::write_common_ireg
01310 (
01311 unsigned char *buf
01312 )
01313 {
01314
01315 buf[0] = ((get_cx()%16) << 4) | get_tx();
01316 buf[1] = ((get_cy()%16) << 4) | get_ty();
01317 int shapenum = get_shapenum(), framenum = get_framenum();
01318 buf[2] = shapenum&0xff;
01319 buf[3] = ((shapenum>>8)&3) | (framenum<<2);
01320 }
01321
01322
01323
01324
01325
01326 void Terrain_game_object::paint_terrain
01327 (
01328 )
01329 {
01330 paint();
01331 }
01332
01333
01334
01335
01336
01337
01338 void Ifix_game_object::move
01339 (
01340 int newtx,
01341 int newty,
01342 int newlift
01343 )
01344 {
01345 Game_object::move(newtx, newty, newlift);
01346
01347 int cx = get_cx(), cy = get_cy();
01348 if (cx >= 0 && cx < c_num_chunks &&
01349 cy >= 0 && cy < c_num_chunks)
01350 gmap->set_ifix_modified(cx, cy);
01351 }
01352
01353
01354
01355
01356
01357
01358 void Ifix_game_object::remove_this
01359 (
01360 int nodel
01361 )
01362 {
01363
01364 int cx = get_cx(), cy = get_cy();
01365 if (cx >= 0 && cx < c_num_chunks &&
01366 cy >= 0 && cy < c_num_chunks)
01367 gmap->set_ifix_modified(cx, cy);
01368 Game_object::remove_this(nodel);
01369 }
01370
01371
01372
01373
01374
01375 void Ifix_game_object::write_ifix
01376 (
01377 DataSource *ifix
01378 )
01379 {
01380 unsigned char buf[4];
01381 buf[0] = shape_pos;
01382 buf[1] = lift;
01383 int shapenum = get_shapenum(), framenum = get_framenum();
01384 buf[2] = shapenum&0xff;
01385 buf[3] = ((shapenum>>8)&3) | (framenum<<2);
01386 ifix->write((char*)buf, sizeof(buf));
01387 }
01388
01389
01390
01391
01392