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 "gamewin.h"
00026 #include "actions.h"
00027 #include "actors.h"
00028 #include "Zombie.h"
00029 #include "Astar.h"
00030 #include "paths.h"
00031 #include "dir.h"
00032 #include "ucmachine.h"
00033 #include "frameseq.h"
00034 #include "ucmachine.h"
00035 #include "cheat.h"
00036 #include "party.h"
00037
00038 using std::cout;
00039 using std::endl;
00040
00041 long Actor_action::seqcnt = 0;
00042
00043
00044
00045
00046
00047
00048
00049 int Actor_action::handle_event_safely
00050 (
00051 Actor *actor,
00052 bool& deleted
00053 )
00054 {
00055 Actor_action *old_action = actor->get_action();
00056 long old_seq = old_action->seq;
00057
00058 int delay = handle_event(actor);
00059 if (actor->get_action() != old_action ||
00060 old_action->seq != old_seq)
00061 {
00062 deleted = true;
00063 return 0;
00064 }
00065 deleted = false;
00066 return delay;
00067 }
00068
00069
00070
00071
00072
00073
00074
00075 Actor_action *Actor_action::walk_to_tile
00076 (
00077 Actor * ,
00078 Tile_coord src,
00079 Tile_coord dest,
00080 int
00081 )
00082 {
00083 Zombie *path = new Zombie();
00084 get_party = false;
00085
00086 if (path->NewPath(src, dest, 0))
00087 return (new Path_walking_actor_action(path));
00088 else
00089 {
00090 delete path;
00091 return (0);
00092 }
00093 }
00094
00095
00096
00097
00098
00099
00100
00101
00102 Actor_action *Actor_action::create_action_sequence
00103 (
00104 Actor *actor,
00105 Tile_coord dest,
00106 Actor_action *when_there,
00107 bool from_off_screen
00108 )
00109 {
00110 Actor_action *act = when_there;
00111 Tile_coord actloc = actor->get_tile();
00112 if (from_off_screen)
00113 actloc.tx = actloc.ty = -1;
00114 if (dest != actloc)
00115 {
00116 Actor_action *w = new Path_walking_actor_action(new Astar());
00117 Actor_action *w2 = w->walk_to_tile(actor, actloc, dest);
00118 if (w2 != w)
00119 delete w;
00120 if (!w2)
00121 w2 = new Move_actor_action(dest);
00122
00123 Actor_action *tel = new Move_actor_action(dest);
00124
00125 Sequence_actor_action *seq;
00126 act = seq = new Sequence_actor_action(w2, tel, act);
00127 seq->set_speed(0);
00128 }
00129 return act;
00130 }
00131
00132
00133
00134
00135
00136 int Null_action::handle_event
00137 (
00138 Actor *actor
00139 )
00140 {
00141 return 0;
00142 }
00143
00144
00145
00146
00147
00148 Path_walking_actor_action::Path_walking_actor_action
00149 (
00150 PathFinder *p,
00151 int maxblk
00152 ) : reached_end(false), path(p), from_offscreen(false),
00153 subseq(0), blocked(0), max_blocked(maxblk)
00154 {
00155 if (!path)
00156 path = new Astar();
00157 Tile_coord src = path->get_src(), dest = path->get_dest();
00158 original_dir = static_cast<int>(Get_direction4(
00159 src.ty - dest.ty, dest.tx - src.tx));
00160 }
00161
00162
00163
00164
00165
00166 Path_walking_actor_action::~Path_walking_actor_action
00167 (
00168 )
00169 {
00170 delete path;
00171 delete subseq;
00172 subseq = 0;
00173 original_dir = -1;
00174 }
00175
00176
00177
00178
00179
00180
00181
00182
00183 Path_walking_actor_action *Path_walking_actor_action::create_path
00184 (
00185 Tile_coord src,
00186 Tile_coord dest,
00187 Pathfinder_client& cost
00188 )
00189 {
00190 Astar *path = new Astar();
00191
00192 if (path->NewPath(src, dest, &cost))
00193 return new Path_walking_actor_action(path);
00194 else
00195 {
00196 delete path;
00197 return 0;
00198 }
00199 }
00200
00201
00202
00203
00204
00205
00206
00207 int Path_walking_actor_action::handle_event
00208 (
00209 Actor *actor
00210 )
00211 {
00212 if (subseq)
00213 {
00214 int delay = subseq->handle_event(actor);
00215 if (delay)
00216 return delay;
00217 set_subseq(0);
00218
00219 actor->set_frame_time(speed);
00220 return speed;
00221 }
00222 Tile_coord tile;
00223 if (blocked)
00224 {
00225 #if 0
00226 std::cout << "Actor " << actor->get_name() << " blocked. Retrying." << std::endl;
00227 #endif
00228 if (actor->step(blocked_tile, blocked_frame))
00229 {
00230 blocked = 0;
00231
00232 actor->set_frame_time(speed);
00233 return speed;
00234 }
00235
00236 return (blocked++ > max_blocked ? 0
00237 : 100 + blocked*(std::rand()%500));
00238 }
00239 speed = actor->get_frame_time();
00240 if (!speed)
00241 return 0;
00242 bool done;
00243 if (!path->GetNextStep(tile, done))
00244 {
00245 reached_end = true;
00246 return (0);
00247 }
00248 if (done)
00249 reached_end = true;
00250 Tile_coord cur = actor->get_tile();
00251 int newdir = static_cast<int>(Get_direction4(cur.ty - tile.ty,
00252 tile.tx - cur.tx));
00253 Frames_sequence *frames = actor->get_frames(newdir);
00254 int& step_index = actor->get_step_index();
00255 if (!step_index)
00256 step_index = frames->find_unrotated(actor->get_framenum());
00257
00258 int frame = frames->get_next(step_index);
00259 int cur_speed = speed;
00260 if (from_offscreen)
00261 {
00262 from_offscreen = false;
00263 actor->move(tile.tx, tile.ty, tile.tz);
00264 return cur_speed;
00265 }
00266 else if (actor->step(tile, frame))
00267 {
00268 if (get_party)
00269 Game_window::get_instance()->get_party_man()->
00270 get_followers(newdir);
00271 if (done)
00272 return (0);
00273 return cur_speed;
00274 }
00275 reached_end = false;
00276 frames->decrement(step_index);
00277
00278 if (actor->get_tile().distance(tile) == 1 &&
00279 !cheat.in_map_editor())
00280
00281 {
00282 Game_object *door = Game_object::find_door(tile);
00283 if (door != 0 && door->is_closed_door() &&
00284
00285 door->get_framenum()%4 < 2)
00286
00287
00288 {
00289 if (open_door(actor, door))
00290 return speed;
00291 }
00292 }
00293 if (!max_blocked ||
00294 actor->is_dormant())
00295 return 0;
00296 blocked = 1;
00297 blocked_tile = tile;
00298 blocked_frame = frame;
00299 return (100 + std::rand()%500);
00300 }
00301
00302
00303
00304
00305
00306
00307
00308
00309 int Path_walking_actor_action::open_door
00310 (
00311 Actor *actor,
00312 Game_object *door
00313 )
00314 {
00315 Game_window *gwin = Game_window::get_instance();
00316 Tile_coord cur = actor->get_tile();
00317
00318 Rectangle foot = door->get_footprint();
00319
00320
00321 int savequal = door->get_quality();
00322 door->set_quality(0);
00323 door->activate();
00324 door->set_quality(savequal);
00325 Tile_coord past;
00326 past.tz = cur.tz;
00327 int dir;
00328 if (foot.w > foot.h)
00329 {
00330 past.tx = foot.x + foot.w/2;
00331 if (cur.ty <= foot.y)
00332 {
00333 past.ty = foot.y + foot.h;
00334 dir = 0;
00335 }
00336 else
00337 {
00338 past.ty = foot.y - 1;
00339 dir = 4;
00340 }
00341 }
00342 else
00343 {
00344 past.ty = foot.y + foot.h/2;
00345 if (cur.tx <= foot.x)
00346 {
00347 past.tx = foot.x + foot.w;
00348 dir = 6;
00349 }
00350 else
00351 {
00352 past.tx = foot.x - 1;
00353 dir = 2;
00354 }
00355 }
00356 Tile_coord tmp = Map_chunk::find_spot(past, 1, actor, 1);
00357 if (past.tx != -1)
00358 {
00359 #ifdef DEBUG
00360 cout << "Path_walking_actor_action::open_door()" << endl;
00361 #endif
00362 signed char frames[2];
00363 frames[0] = actor->get_dir_framenum(dir, Actor::standing);
00364 frames[1] = actor->get_dir_framenum(dir, 3);
00365 signed char standframe = frames[0];
00366 set_subseq(create_action_sequence(actor, past,
00367 new Sequence_actor_action(
00368 new Frames_actor_action(frames,
00369 sizeof(frames)),
00370 new Activate_actor_action(door),
00371 new Frames_actor_action(&standframe, 1))));
00372 return 1;
00373 }
00374 return 0;
00375 }
00376
00377
00378
00379
00380
00381 void Path_walking_actor_action::stop
00382 (
00383 Actor *actor
00384 )
00385 {
00386
00387 if (!actor->get_info().has_strange_movement())
00388 {
00389 Frames_sequence *frames = actor->get_frames(original_dir);
00390 actor->change_frame(frames->get_resting());
00391 }
00392 }
00393
00394
00395
00396
00397
00398
00399
00400 Actor_action *Path_walking_actor_action::walk_to_tile
00401 (
00402 Actor *npc,
00403 Tile_coord src,
00404 Tile_coord dest,
00405 int dist
00406 )
00407 {
00408 Game_window *gwin = Game_window::get_instance();
00409 blocked = 0;
00410 reached_end = false;
00411 get_party = false;
00412 from_offscreen = false;
00413
00414
00415
00416 if (dest.tx == -1 || dest.ty == -1)
00417 {
00418 if (dest.tx == dest.ty)
00419 {
00420 Offscreen_pathfinder_client cost(npc);
00421 if (!path->NewPath(src, dest, &cost))
00422 return (0);
00423 }
00424 else
00425 {
00426 Onecoord_pathfinder_client cost(npc);
00427 if (!path->NewPath(src, dest, &cost))
00428 return (0);
00429 }
00430 }
00431
00432 else if (src.tx == -1 || src.ty == -1)
00433 {
00434 if (src.tx == src.ty)
00435 {
00436 Offscreen_pathfinder_client cost(npc, npc->get_tile());
00437 if (!path->NewPath(dest, src, &cost))
00438 return (0);
00439 }
00440 else
00441 {
00442 Onecoord_pathfinder_client cost(npc);
00443 if (!path->NewPath(dest, src, &cost))
00444 return (0);
00445 }
00446 from_offscreen = true;
00447
00448 if (!path->set_backwards())
00449 return (0);
00450 }
00451 else
00452 {
00453 Actor_pathfinder_client cost(npc, dist);
00454 if (!path->NewPath(src, dest, &cost))
00455 return (0);
00456 }
00457
00458 original_dir = static_cast<int>(Get_direction4(
00459 src.ty - dest.ty, dest.tx - src.tx));
00460 return (this);
00461 }
00462
00463
00464
00465
00466
00467
00468
00469 int Path_walking_actor_action::get_dest
00470 (
00471 Tile_coord& dest
00472 )
00473 {
00474 dest = path->get_dest();
00475 return (1);
00476 }
00477
00478
00479
00480
00481
00482 int Path_walking_actor_action::following_smart_path
00483 (
00484 )
00485 {
00486 return path != 0 && path->following_smart_path();
00487 }
00488
00489
00490
00491
00492
00493 Approach_actor_action::Approach_actor_action
00494 (
00495 PathFinder *p,
00496 Game_object *d
00497 ) : Path_walking_actor_action(p, 0),
00498 dest_obj(d), orig_dest_pos(d->get_tile()), cur_step(0)
00499 {
00500
00501 int nsteps = path->get_num_steps();
00502 if (nsteps >= 6)
00503 check_step = nsteps > 18 ? 9 : nsteps/2;
00504 else
00505 check_step = 10000;
00506 }
00507
00508
00509
00510
00511
00512
00513
00514 int Approach_actor_action::handle_event
00515 (
00516 Actor *actor
00517 )
00518 {
00519 int delay = Path_walking_actor_action::handle_event(actor);
00520 if (!delay)
00521 return 0;
00522 if (++cur_step == check_step)
00523 {
00524 if (dest_obj->get_tile().distance(orig_dest_pos) > 2)
00525 return 0;
00526
00527 int nsteps = path->get_num_steps();
00528 if (nsteps >= 6)
00529 check_step += nsteps/2;
00530 }
00531 return delay;
00532 }
00533
00534
00535
00536
00537
00538 If_else_path_actor_action::If_else_path_actor_action
00539 (
00540 Actor *actor,
00541 Tile_coord dest,
00542 Actor_action *s,
00543 Actor_action *f
00544 ) : Path_walking_actor_action(0, 6),
00545 succeeded(false), failed(false), done(false),
00546 success(s), failure(f)
00547 {
00548 if (!walk_to_tile(actor, actor->get_tile(), dest))
00549 {
00550 done = failed = true;
00551 }
00552 }
00553
00554
00555
00556
00557
00558 If_else_path_actor_action::~If_else_path_actor_action
00559 (
00560 )
00561 {
00562 delete success;
00563 delete failure;
00564 }
00565
00566
00567
00568
00569
00570 void If_else_path_actor_action::set_failure
00571 (
00572 Actor_action *f
00573 )
00574 {
00575 delete failure;
00576 failure = f;
00577 done = false;
00578 }
00579
00580
00581
00582
00583
00584
00585
00586 int If_else_path_actor_action::handle_event
00587 (
00588 Actor *actor
00589 )
00590 {
00591 if (done)
00592 return 0;
00593 bool del;
00594 int delay;
00595 if (succeeded)
00596 {
00597 if ((delay = success->handle_event_safely(actor, del)) == 0 &&
00598 !del)
00599 done = true;
00600 return delay;
00601 }
00602 else if (failed)
00603 {
00604 if ((delay = failure->handle_event_safely(actor, del)) == 0 &&
00605 !del)
00606 done = true;
00607 return delay;
00608 }
00609 delay = Path_walking_actor_action::handle_event(actor);
00610 if (delay)
00611 return delay;
00612 if (!reached_end)
00613 {
00614 if (failure)
00615 {
00616 failed = true;
00617 #if DEBUG
00618 cout << "Executing 'failure' path usecode" << endl;
00619 #endif
00620 delay = failure->handle_event_safely(actor, del);
00621 if (del)
00622 return 0;
00623 }
00624 }
00625 else
00626 {
00627 if (success)
00628 {
00629 succeeded = true;
00630 delay = success->handle_event_safely(actor, del);
00631 if (del)
00632 return 0;
00633 }
00634 }
00635 if (!delay)
00636 done = true;
00637 return delay;
00638 }
00639
00640
00641
00642
00643
00644
00645
00646 int Move_actor_action::handle_event
00647 (
00648 Actor *actor
00649 )
00650 {
00651 if (dest.tx < 0 || actor->get_tile() == dest)
00652 return (0);
00653 actor->move(dest);
00654 Game_window *gwin = Game_window::get_instance();
00655 if (actor == gwin->get_main_actor())
00656
00657 gwin->center_view(dest);
00658 dest.tx = -1;
00659 return (100);
00660 }
00661
00662
00663
00664
00665
00666
00667
00668 int Activate_actor_action::handle_event
00669 (
00670 Actor *actor
00671 )
00672 {
00673 obj->activate();
00674 return 0;
00675 }
00676
00677
00678
00679
00680
00681
00682
00683 int Usecode_actor_action::handle_event
00684 (
00685 Actor *actor
00686 )
00687 {
00688 Game_window *gwin = Game_window::get_instance();
00689 gwin->get_usecode()->call_usecode(fun, item,
00690 (Usecode_machine::Usecode_events) eventid);
00691 gwin->set_all_dirty();
00692 return 0;
00693 }
00694
00695
00696
00697
00698
00699 Frames_actor_action::Frames_actor_action
00700 (
00701 signed char *f,
00702 int c,
00703 int spd,
00704 Game_object *o
00705 ) : cnt(c), index(0), speed(spd), obj(o)
00706 {
00707 frames = new signed char[cnt];
00708 std::memcpy(frames, f, cnt);
00709 }
00710
00711
00712
00713
00714
00715
00716
00717 int Frames_actor_action::handle_event
00718 (
00719 Actor *actor
00720 )
00721 {
00722 Game_object *o = obj;
00723 if (index == cnt)
00724 return (0);
00725 int frnum = frames[index++];
00726 if (frnum >= 0)
00727 {
00728 Game_window *gwin = Game_window::get_instance();
00729 if (o)
00730 o->change_frame(frnum);
00731 else
00732 actor->change_frame(frnum);
00733 }
00734 return (speed);
00735 }
00736
00737
00738
00739
00740
00741 Sequence_actor_action::Sequence_actor_action
00742 (
00743 Actor_action *a0,
00744 Actor_action *a1,
00745 Actor_action *a2,
00746 Actor_action *a3
00747 ) : index(0), speed(100)
00748 {
00749 actions = new Actor_action *[5];
00750 actions[0] = a0;
00751 actions[1] = a1;
00752 actions[2] = a2;
00753 actions[3] = a3;
00754 actions[4] = 0;
00755 }
00756
00757
00758
00759
00760
00761 Sequence_actor_action::~Sequence_actor_action
00762 (
00763 )
00764 {
00765 for (int i = 0; actions[i]; i++)
00766 delete actions[i];
00767 delete [] actions;
00768 }
00769
00770
00771
00772
00773
00774
00775
00776 int Sequence_actor_action::handle_event
00777 (
00778 Actor *actor
00779 )
00780 {
00781 if (!actions[index])
00782 return (0);
00783
00784 bool deleted;
00785 int delay = actions[index]->handle_event_safely(actor, deleted);
00786 if (deleted)
00787 return 0;
00788 if (!delay)
00789 {
00790 index++;
00791 if (!speed)
00792 return handle_event(actor);
00793 delay = speed;
00794 }
00795 return (delay);
00796 }
00797
00798
00799
00800
00801 Object_animate_actor_action::Object_animate_actor_action
00802 (
00803 Game_object *o,
00804 int cy,
00805 int spd
00806 ) : obj(o), cycles(cy), speed(spd)
00807 {
00808 Game_window *gwin = Game_window::get_instance();
00809 nframes = obj->get_num_frames();
00810 }
00811
00812 Object_animate_actor_action::Object_animate_actor_action
00813 (
00814 Game_object *o,
00815 int nfr,
00816 int cy,
00817 int spd
00818 ) : obj(o), nframes(nfr), cycles(cy), speed(spd)
00819 { }
00820
00821
00822
00823
00824
00825
00826 int Object_animate_actor_action::handle_event
00827 (
00828 Actor *actor
00829 )
00830 {
00831 if (!cycles) return 0;
00832 int frnum = (obj->get_framenum() + 1) % nframes;
00833 if (!frnum)
00834 --cycles;
00835 obj->change_frame(frnum);
00836 return (cycles ? speed : 0);
00837 }
00838
00839
00840
00841
00842 Pickup_actor_action::Pickup_actor_action(Game_object *o, int spd)
00843 : obj(o), pickup(1), speed(spd), cnt(0),
00844 objpos(obj->get_tile()), dir(0)
00845 {
00846 }
00847
00848 Pickup_actor_action::Pickup_actor_action(Game_object *o, Tile_coord opos,
00849 int spd)
00850 : obj(o), pickup(0), speed(spd), cnt(0), objpos(opos), dir(0)
00851 {
00852 }
00853
00854
00855
00856
00857
00858 int Pickup_actor_action::handle_event
00859 (
00860 Actor *actor
00861 )
00862 {
00863 Game_window *gwin = Game_window::get_instance();
00864 int frnum = -1;
00865 switch (cnt)
00866 {
00867 case 0:
00868 dir = actor->get_direction(objpos);
00869 frnum = actor->get_dir_framenum(dir, Actor::standing);
00870 cnt++;
00871 break;
00872 case 1:
00873 frnum = actor->get_dir_framenum(dir, Actor::bow_frame);
00874 cnt++;
00875 if (pickup)
00876 {
00877 if (actor->distance(obj) > 8)
00878 {
00879 actor->notify_object_gone(obj);
00880 break;
00881 }
00882 gwin->add_dirty(obj);
00883 obj->remove_this(1);
00884 actor->add(obj, 1);
00885 }
00886 else
00887 {
00888 obj->remove_this(1);
00889 obj->move(objpos);
00890 gwin->add_dirty(obj);
00891 }
00892 break;
00893 default:
00894 return 0;
00895 }
00896 actor->change_frame(frnum);
00897 return speed;
00898 }
00899
00900
00901
00902
00903
00904 Face_pos_actor_action::Face_pos_actor_action(Tile_coord p, int spd)
00905 : speed(spd), pos(p)
00906 {
00907 }
00908 Face_pos_actor_action::Face_pos_actor_action(Game_object *o, int spd)
00909 : speed(spd),
00910 pos(o->get_tile())
00911 {
00912 }
00913
00914
00915
00916
00917
00918 int Face_pos_actor_action::handle_event
00919 (
00920 Actor *actor
00921 )
00922 {
00923 Game_window *gwin = Game_window::get_instance();
00924 int dir = actor->get_direction(pos);
00925 int frnum = actor->get_dir_framenum(dir, Actor::standing);
00926 if (actor->get_framenum() == frnum)
00927 return 0;
00928 actor->change_frame(frnum);
00929 return speed;
00930 }
00931