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 "paths.h"
00026 #include "Astar.h"
00027 #include "Zombie.h"
00028 #include "gamewin.h"
00029 #include "gamemap.h"
00030 #include "actors.h"
00031
00032
00033
00034
00035
00036 Actor_pathfinder_client::Actor_pathfinder_client
00037 (
00038 Actor *n,
00039 int d
00040 ) : dist(d), npc(n)
00041 {
00042
00043 set_move_flags(npc->get_type_flags());
00044 }
00045
00046
00047
00048
00049
00050 int Actor_pathfinder_client::get_max_cost
00051 (
00052 int cost_to_goal
00053 )
00054 {
00055 int max_cost = 3*cost_to_goal;
00056 Game_window *gwin = Game_window::get_instance();
00057
00058 int min_max_cost = (gwin->get_width()/c_tilesize)*2*3;
00059 return max_cost > min_max_cost ? max_cost : min_max_cost;
00060 }
00061
00062
00063
00064
00065
00066
00067
00068
00069 int Actor_pathfinder_client::get_step_cost
00070 (
00071 Tile_coord from,
00072 Tile_coord& to
00073
00074 )
00075 {
00076 Game_window *gwin = Game_window::get_instance();
00077 int cx = to.tx/c_tiles_per_chunk, cy = to.ty/c_tiles_per_chunk;
00078 Map_chunk *olist = gwin->get_map()->get_chunk(cx, cy);
00079 int tx = to.tx%c_tiles_per_chunk;
00080 int ty = to.ty%c_tiles_per_chunk;
00081 int cost = 1;
00082 olist->setup_cache();
00083 int water, poison;
00084 Actor::get_tile_info(0, gwin, olist, tx, ty, water, poison);
00085 int old_lift = to.tz;
00086 if (npc->is_blocked(to, &from))
00087 {
00088 Game_object *block = Game_object::find_door(to);
00089 if (!block)
00090 return -1;
00091 if (!block->is_closed_door() ||
00092
00093 block->get_framenum()%4 >= 2)
00094 return -1;
00095
00096 Rectangle foot = block->get_footprint();
00097 if (foot.h == 1 && (to.tx == foot.x || to.tx == foot.x +
00098 foot.w - 1))
00099 return -1;
00100 else if (foot.w == 1 && (to.ty == foot.y || to.ty == foot.y +
00101 foot.h - 1))
00102 return -1;
00103 if (foot.has_point(from.tx, from.ty))
00104 return -1;
00105 cost++;
00106 }
00107 if (old_lift != to.tz)
00108 cost++;
00109
00110 if (from.tx != to.tx || from.ty != to.ty)
00111 cost *= 3;
00112 else
00113 cost *= 2;
00114 if (poison && to.tz == 0)
00115 cost *= 2;
00116
00117 ShapeID flat = olist->get_flat(tx, ty);
00118 int shapenum = flat.get_shapenum();
00119 if (shapenum == 24)
00120 {
00121 int framenum = flat.get_framenum();
00122 if (framenum <= 1)
00123 cost--;
00124 }
00125 return (cost);
00126 }
00127
00128
00129
00130
00131
00132 int Actor_pathfinder_client::estimate_cost
00133 (
00134 Tile_coord& from,
00135 Tile_coord& to
00136 )
00137 {
00138 int dx = to.tx - from.tx;
00139 if (dx < -c_num_tiles/2)
00140 dx += c_num_tiles;
00141 else if (dx < 0)
00142 dx = -dx;
00143 int dy = to.ty - from.ty;
00144 if (dy < -c_num_tiles/2)
00145 dy += c_num_tiles;
00146 else if (dy < 0)
00147 dy = -dy;
00148 int larger, smaller;
00149 if (dy <= dx)
00150 {
00151 larger = dx;
00152 smaller = dy;
00153 }
00154 else
00155 {
00156 larger = dy;
00157 smaller = dx;
00158 }
00159 return (2*larger + smaller);
00160 }
00161
00162
00163
00164
00165
00166 int Actor_pathfinder_client::at_goal
00167 (
00168 Tile_coord& tile,
00169 Tile_coord& goal
00170 )
00171 {
00172 return tile.distance(goal) <= dist &&
00173 (goal.tz == -1 || tile.tz == goal.tz);
00174 }
00175
00176
00177
00178
00179
00180 int Onecoord_pathfinder_client::estimate_cost
00181 (
00182 Tile_coord& from,
00183 Tile_coord& to
00184 )
00185 {
00186 if (to.tx == -1)
00187 {
00188 int dy = to.ty - from.ty;
00189 if (dy < -c_num_tiles/2)
00190 dy += c_num_tiles;
00191 else if (dy < 0)
00192 dy = -dy;
00193 return (2*dy);
00194 }
00195 else if (to.ty == -1)
00196 {
00197 int dx = to.tx - from.tx;
00198 if (dx < -c_num_tiles/2)
00199 dx += c_num_tiles;
00200 else if (dx < 0)
00201 dx = -dx;
00202 return (2*dx);
00203 }
00204 else
00205 return Actor_pathfinder_client::estimate_cost(from, to);
00206 }
00207
00208
00209
00210
00211
00212 int Onecoord_pathfinder_client::at_goal
00213 (
00214 Tile_coord& tile,
00215 Tile_coord& goal
00216 )
00217 {
00218 return ((goal.tx == -1 || tile.tx == goal.tx) &&
00219 (goal.ty == -1 || tile.ty == goal.ty) &&
00220 (goal.tz == -1 || tile.tz == goal.tz));
00221 }
00222
00223
00224
00225
00226
00227 Offscreen_pathfinder_client::Offscreen_pathfinder_client
00228 (
00229 Actor *n
00230 ) : Actor_pathfinder_client(n), screen(
00231 Game_window::get_instance()->get_win_tile_rect().enlarge(3)),
00232 best(-1, -1, -1)
00233 {
00234 }
00235
00236
00237
00238
00239
00240 Offscreen_pathfinder_client::Offscreen_pathfinder_client
00241 (
00242 Actor *n,
00243 Tile_coord b
00244 ) : Actor_pathfinder_client(n), screen(
00245 Game_window::get_instance()->get_win_tile_rect().enlarge(3)),
00246 best(b)
00247 {
00248 if (best.tx != -1)
00249 {
00250 Rectangle scr =
00251 Game_window::get_instance()->get_win_tile_rect();
00252
00253 int cx = scr.x + scr.w/2, cy = scr.y + scr.h/2;
00254
00255 if (best.distance(Tile_coord(cx, cy, 0)) > 4*scr.w)
00256 {
00257 best.tx = best.ty = -1;
00258 return;
00259 }
00260 if (best.tx > cx + scr.w)
00261
00262 best.tx = scr.x + scr.w + 1;
00263 else if (best.tx < cx - scr.w)
00264 best.tx = scr.x - 1;
00265 if (best.ty > cy + scr.h)
00266 best.ty = scr.y + scr.h + 1;
00267 else if (best.ty < cy - scr.h)
00268 best.ty = scr.y - 1;
00269
00270 if (best.distance(Tile_coord(cx, cy, 0)) > scr.w)
00271 best.tx = best.ty = -1;
00272 }
00273 }
00274
00275
00276
00277
00278
00279
00280
00281
00282 int Offscreen_pathfinder_client::get_step_cost
00283 (
00284 Tile_coord from,
00285 Tile_coord& to
00286
00287 )
00288 {
00289 int cost = Actor_pathfinder_client::get_step_cost(from, to);
00290 if (cost == -1)
00291 return cost;
00292 if (best.tx != -1)
00293 {
00294 if ((to.tx - from.tx)*(best.tx - from.tx) < 0)
00295 cost++;
00296 if ((to.ty - from.ty)*(best.ty - from.ty) < 0)
00297 cost++;
00298 }
00299 return cost;
00300 }
00301
00302
00303
00304
00305
00306 int Offscreen_pathfinder_client::estimate_cost
00307 (
00308 Tile_coord& from,
00309 Tile_coord& to
00310 )
00311 {
00312 if (best.tx != -1)
00313 return Actor_pathfinder_client::estimate_cost(from, best);
00314
00315 int dx = from.tx - screen.x;
00316 int dx1 = screen.x + screen.w - from.tx;
00317 if (dx1 < dx)
00318 dx = dx1;
00319 int dy = from.ty - screen.y;
00320 int dy1 = screen.y + screen.h - from.ty;
00321 if (dy1 < dy)
00322 dy = dy1;
00323 int cost = dx < dy ? dx : dy;
00324 if (cost < 0)
00325 cost = 0;
00326 if (to.tz != -1 && from.tz != to.tz)
00327 cost++;
00328 return 2*cost;
00329 }
00330
00331
00332
00333
00334
00335 int Offscreen_pathfinder_client::at_goal
00336 (
00337 Tile_coord& tile,
00338 Tile_coord& goal
00339 )
00340 {
00341 return !screen.has_point(tile.tx - tile.tz/2, tile.ty - tile.tz/2);
00342
00343
00344 }
00345
00346
00347
00348
00349
00350 int Fast_pathfinder_client::get_max_cost
00351 (
00352 int cost_to_goal
00353 )
00354 {
00355 int max_cost = 2*cost_to_goal;
00356 if (max_cost < 8)
00357 max_cost = 8;
00358 else if (max_cost > 64)
00359 max_cost = 64;
00360 return max_cost;
00361 }
00362
00363
00364
00365
00366
00367
00368
00369
00370 int Fast_pathfinder_client::get_step_cost
00371 (
00372 Tile_coord from,
00373 Tile_coord& to
00374
00375 )
00376 {
00377 Game_window *gwin = Game_window::get_instance();
00378 int cx = to.tx/c_tiles_per_chunk, cy = to.ty/c_tiles_per_chunk;
00379 Map_chunk *olist = gwin->get_map()->get_chunk(cx, cy);
00380 int tx = to.tx%c_tiles_per_chunk;
00381 int ty = to.ty%c_tiles_per_chunk;
00382 olist->setup_cache();
00383 int new_lift;
00384
00385
00386
00387 if (olist->is_blocked(1, to.tz, tx, ty, new_lift, get_move_flags(),
00388 2, 2))
00389 return -1;
00390 to.tz = new_lift;
00391
00392 return 1;
00393 }
00394
00395
00396
00397
00398
00399 int Fast_pathfinder_client::estimate_cost
00400 (
00401 Tile_coord& from,
00402 Tile_coord& to
00403 )
00404 {
00405 return from.distance(to);
00406 }
00407
00408
00409
00410
00411
00412 int Fast_pathfinder_client::at_goal
00413 (
00414 Tile_coord& tile,
00415 Tile_coord& goal
00416 )
00417 {
00418 if (tile.distance(goal) > dist)
00419 return 0;
00420 int dz = tile.tz - goal.tz;
00421 return dz <= 5 && dz >= -5;
00422 }
00423
00424
00425
00426
00427
00428 int Fast_pathfinder_client::is_grabable
00429 (
00430 Tile_coord from,
00431 Tile_coord to
00432 )
00433 {
00434
00435 if (from.distance(to) <= 1)
00436 return 1;
00437 Fast_pathfinder_client client(1,
00438 Game_window::get_instance()->get_main_actor()->get_type_flags());
00439 Astar path;
00440 return path.NewPath(from, to, &client);
00441 }
00442
00443
00444
00445
00446
00447
00448
00449 int Fast_pathfinder_client::is_straight_path
00450 (
00451 Tile_coord from,
00452 Tile_coord to
00453 )
00454 {
00455 to.tz = from.tz;
00456 Zombie path;
00457 if (!path.NewPath(from, to, 0))
00458 return 0;
00459 Tile_coord t;
00460 bool done;
00461 while (path.GetNextStep(t, done))
00462 if (t != from && t != to && Map_chunk::is_blocked(t))
00463 return 0;
00464 return 1;
00465 }
00466
00467
00468
00469
00470
00471
00472 Monster_pathfinder_client::Monster_pathfinder_client
00473 (
00474 Actor *npc,
00475 Tile_coord dest,
00476 int dist
00477 ) : Fast_pathfinder_client(dist), destbox(dest.tx, dest.ty, 0, 0)
00478 {
00479 intelligence = npc->get_property(Actor::intelligence);
00480 Shape_info& info1 = npc->get_info();
00481 axtiles = info1.get_3d_xtiles();
00482 aytiles = info1.get_3d_ytiles();
00483 aztiles = info1.get_3d_height();
00484 set_move_flags(npc->get_type_flags());
00485 destbox.enlarge(dist);
00486 }
00487
00488
00489
00490
00491
00492 Monster_pathfinder_client::Monster_pathfinder_client
00493 (
00494 Actor *attacker,
00495 int reach,
00496 Game_object *opponent
00497 ) : Fast_pathfinder_client(reach), destbox(0, 0, 0, 0)
00498 {
00499 intelligence = attacker->get_property(Actor::intelligence);
00500 Shape_info& info1 = attacker->get_info();
00501 axtiles = info1.get_3d_xtiles();
00502 aytiles = info1.get_3d_ytiles();
00503 aztiles = info1.get_3d_height();
00504 if (!opponent)
00505 return;
00506 set_move_flags(attacker->get_type_flags());
00507 Shape_info& info2 = opponent->get_info();
00508 Tile_coord opos = opponent->get_tile();
00509 int oxtiles = info2.get_3d_xtiles(), oytiles = info2.get_3d_ytiles();
00510 destbox = Rectangle(opos.tx - oxtiles + 1, opos.ty - oytiles + 1,
00511 oxtiles, oytiles);
00512 destbox.enlarge(reach);
00513 }
00514
00515
00516
00517
00518
00519 int Monster_pathfinder_client::get_max_cost
00520 (
00521 int cost_to_goal
00522 )
00523 {
00524 int max_cost = 2*cost_to_goal;
00525 int icost = 2 + 2*intelligence;
00526 if (max_cost > icost)
00527 max_cost = icost;
00528 Game_window *gwin = Game_window::get_instance();
00529
00530 int scost = ((3*gwin->get_width())/4)/c_tilesize;
00531 if (max_cost > scost)
00532 max_cost = scost;
00533 if (max_cost < 15)
00534 max_cost = 15;
00535 return max_cost;
00536 }
00537
00538
00539
00540
00541
00542 int Monster_pathfinder_client::at_goal
00543 (
00544 Tile_coord& tile,
00545 Tile_coord& goal
00546 )
00547 {
00548 int dz = tile.tz - goal.tz;
00549 if (dz/5 != 0)
00550 return 0;
00551 Rectangle abox(tile.tx - axtiles + 1, tile.ty - aytiles + 1,
00552 axtiles, aytiles);
00553 return abox.intersects(destbox);
00554 }
00555
00556
00557
00558
00559
00560
00561
00562
00563 int Monster_pathfinder_client::get_step_cost
00564 (
00565 Tile_coord from,
00566 Tile_coord& to
00567
00568 )
00569 {
00570 if (Map_chunk::is_blocked(axtiles, aytiles, aztiles,
00571 from, to, get_move_flags()))
00572 return -1;
00573 else
00574 return 1;
00575 }
00576
00577