diff --git a/engines/ags/engine/ac/character.cpp b/engines/ags/engine/ac/character.cpp index 246da2276cc..2b3ae923285 100644 --- a/engines/ags/engine/ac/character.cpp +++ b/engines/ags/engine/ac/character.cpp @@ -153,9 +153,8 @@ void Character_AddWaypoint(CharacterInfo *chaa, int x, int y) { return; } - cmls->pos[cmls->numstage] = (x << 16) + y; // They're already walking there anyway - if (cmls->pos[cmls->numstage] == cmls->pos[cmls->numstage - 1]) + if (cmls->lastx == x && cmls->lasty == y) return; int move_speed_x, move_speed_y; @@ -164,8 +163,17 @@ void Character_AddWaypoint(CharacterInfo *chaa, int x, int y) { debug_script_warn("Character::AddWaypoint: called for '%s' with walk speed 0", chaa->scrname); } - calculate_move_stage(cmls, cmls->numstage - 1, move_speed_x, move_speed_y); - cmls->numstage++; + // There's an issue: the existing movelist is converted to room resolution, + // so we do this trick: convert last step to mask resolution, before calling + // a pathfinder api, and then we'll convert old and new last step back. + // TODO: figure out a better way of processing this! + const int last_stage = cmls->numstage - 1; + cmls->pos[last_stage] = ((room_to_mask_coord(cmls->pos[last_stage] >> 16)) << 16) | ((room_to_mask_coord(cmls->pos[last_stage] & 0xFFFF)) & 0xFFFF); + const int dst_x = room_to_mask_coord(x); + const int dst_y = room_to_mask_coord(y); + if (add_waypoint_direct(cmls, dst_x, dst_y, move_speed_x, move_speed_y)) { + convert_move_path_to_room_resolution(cmls, last_stage, last_stage + 1); + } } void Character_AnimateEx(CharacterInfo *chaa, int loop, int delay, int repeat, @@ -1592,13 +1600,7 @@ void walk_character(int chac, int tox, int toy, int ignwal, bool autoWalkAnims) chin->flags &= ~CHF_MOVENOTWALK; - int toxPassedIn = tox, toyPassedIn = toy; - int charX = room_to_mask_coord(chin->x); - int charY = room_to_mask_coord(chin->y); - tox = room_to_mask_coord(tox); - toy = room_to_mask_coord(toy); - - if ((tox == charX) && (toy == charY)) { + if ((tox == chin->x) && (toy == chin->y)) { StopMoving(chac); debug_script_log("%s already at destination, not moving", chin->scrname); return; @@ -1626,7 +1628,7 @@ void walk_character(int chac, int tox, int toy, int ignwal, bool autoWalkAnims) chin->frame = oldframe; // use toxPassedIn cached variable so the hi-res co-ordinates // are still displayed as such - debug_script_log("%s: Start move to %d,%d", chin->scrname, toxPassedIn, toyPassedIn); + debug_script_log("%s: Start move to %d,%d", chin->scrname, tox, toy); int move_speed_x, move_speed_y; chin->get_effective_walkspeeds(move_speed_x, move_speed_y); @@ -1634,8 +1636,13 @@ void walk_character(int chac, int tox, int toy, int ignwal, bool autoWalkAnims) debug_script_warn("MoveCharacter: called for '%s' with walk speed 0", chin->scrname); } - int mslot = find_route(charX, charY, tox, toy, move_speed_x, move_speed_y, - prepare_walkable_areas(chac), chac + CHMLSOFFS, 1, ignwal); + // Convert src and dest coords to the mask resolution, for pathfinder + const int src_x = room_to_mask_coord(chin->x); + const int src_y = room_to_mask_coord(chin->y); + const int dst_x = room_to_mask_coord(tox); + const int dst_y = room_to_mask_coord(toy); + + int mslot = find_route(src_x, src_y, dst_x, dst_y, move_speed_x, move_speed_y, prepare_walkable_areas(chac), chac + CHMLSOFFS, 1, ignwal); if (mslot > 0) { chin->walking = mslot; diff --git a/engines/ags/engine/ac/object.cpp b/engines/ags/engine/ac/object.cpp index cf8530a762f..1ac2ec86b82 100644 --- a/engines/ags/engine/ac/object.cpp +++ b/engines/ags/engine/ac/object.cpp @@ -413,12 +413,13 @@ void move_object(int objj, int tox, int toy, int spee, int ignwal) { debug_script_log("Object %d start move to %d,%d", objj, tox, toy); - int objX = room_to_mask_coord(_G(objs)[objj].x); - int objY = room_to_mask_coord(_G(objs)[objj].y); - tox = room_to_mask_coord(tox); - toy = room_to_mask_coord(toy); + // Convert src and dest coords to the mask resolution, for pathfinder + const int src_x = room_to_mask_coord(_G(objs)[objj].x); + const int src_y = room_to_mask_coord(_G(objs)[objj].y); + const int dst_x = room_to_mask_coord(tox); + const int dst_y = room_to_mask_coord(toy); - int mslot = find_route(objX, objY, tox, toy, spee, spee, prepare_walkable_areas(-1), objj + 1, 1, ignwal); + int mslot = find_route(src_x, src_y, dst_x, dst_y, spee, spee, prepare_walkable_areas(-1), objj + 1, 1, ignwal); if (mslot > 0) { _G(objs)[objj].moving = mslot; diff --git a/engines/ags/engine/ac/room.cpp b/engines/ags/engine/ac/room.cpp index ddf4ee0e378..833ae6db21f 100644 --- a/engines/ags/engine/ac/room.cpp +++ b/engines/ags/engine/ac/room.cpp @@ -1006,33 +1006,42 @@ AGS_INLINE int mask_to_room_coord(int coord) { return coord * _GP(thisroom).MaskResolution / _GP(game).GetDataUpscaleMult(); } -void convert_move_path_to_room_resolution(MoveList *ml) { +void convert_move_path_to_room_resolution(MoveList *ml, int from_step, int to_step) { + if (to_step < 0) + to_step = ml->numstage; + to_step = CLIP(to_step, 0, ml->numstage - 1); + from_step = CLIP(from_step, 0, to_step); + + // If speed is independent from MaskResolution... if ((_GP(game).options[OPT_WALKSPEEDABSOLUTE] != 0) && _GP(game).GetDataUpscaleMult() > 1) { - // Speeds are independent from MaskResolution - for (int i = 0; i < ml->numstage; i++) { - // ...so they are not multiplied by MaskResolution factor when converted to room coords + for (int i = from_step; i <= to_step; i++) { // ...so they are not multiplied by MaskResolution factor when converted to room coords ml->xpermove[i] = ml->xpermove[i] / _GP(game).GetDataUpscaleMult(); ml->ypermove[i] = ml->ypermove[i] / _GP(game).GetDataUpscaleMult(); } } + // Skip the conversion if these are equal, as they are multiplier and divisor if (_GP(thisroom).MaskResolution == _GP(game).GetDataUpscaleMult()) return; - ml->fromx = mask_to_room_coord(ml->fromx); - ml->fromy = mask_to_room_coord(ml->fromy); - ml->lastx = mask_to_room_coord(ml->lastx); - ml->lasty = mask_to_room_coord(ml->lasty); + if (from_step == 0) { + ml->fromx = mask_to_room_coord(ml->fromx); + ml->fromy = mask_to_room_coord(ml->fromy); + } + if (to_step == ml->numstage - 1) { + ml->lastx = mask_to_room_coord(ml->lastx); + ml->lasty = mask_to_room_coord(ml->lasty); + } - for (int i = 0; i < ml->numstage; i++) { + for (int i = from_step; i <= to_step; i++) { uint16_t lowPart = mask_to_room_coord(ml->pos[i] & 0x0000ffff); uint16_t highPart = mask_to_room_coord((ml->pos[i] >> 16) & 0x0000ffff); ml->pos[i] = ((int)highPart << 16) | (lowPart & 0x0000ffff); } + // If speed is scaling with MaskResolution... if (_GP(game).options[OPT_WALKSPEEDABSOLUTE] == 0) { - // Speeds are scaling with MaskResolution - for (int i = 0; i < ml->numstage; i++) { + for (int i = from_step; i <= to_step; i++) { ml->xpermove[i] = mask_to_room_coord(ml->xpermove[i]); ml->ypermove[i] = mask_to_room_coord(ml->ypermove[i]); } diff --git a/engines/ags/engine/ac/room.h b/engines/ags/engine/ac/room.h index bfae9f72d97..58174c83e01 100644 --- a/engines/ags/engine/ac/room.h +++ b/engines/ags/engine/ac/room.h @@ -70,8 +70,6 @@ void croom_ptr_clear(); // In legacy games with low-res data resolution there's additional conversion // between data and room coordinates. // -// gets multiplier for converting from room mask to data coordinate -extern AGS_INLINE int get_roommask_to_data_mul(); // coordinate conversion data ---> room ---> mask extern AGS_INLINE int room_to_mask_coord(int coord); // coordinate conversion mask ---> room ---> data @@ -79,7 +77,7 @@ extern AGS_INLINE int mask_to_room_coord(int coord); struct MoveList; // Convert move path from room's mask resolution to room resolution -void convert_move_path_to_room_resolution(MoveList *ml); +void convert_move_path_to_room_resolution(MoveList *ml, int from_step = 0, int to_step = -1); } // namespace AGS3 diff --git a/engines/ags/engine/ac/route_finder.cpp b/engines/ags/engine/ac/route_finder.cpp index ed8882e4fcc..d936f969815 100644 --- a/engines/ags/engine/ac/route_finder.cpp +++ b/engines/ags/engine/ac/route_finder.cpp @@ -51,8 +51,8 @@ public: int find_route(short srcx, short srcy, short xx, short yy, int move_speed_x, int move_speed_y, Bitmap *onscreen, int movlst, int nocross = 0, int ignore_walls = 0) override { return AGS::Engine::RouteFinder::find_route(srcx, srcy, xx, yy, move_speed_x, move_speed_y, onscreen, movlst, nocross, ignore_walls); } - void calculate_move_stage(MoveList *mlsp, int aaa, int move_speed_x, int move_speed_y) override { - AGS::Engine::RouteFinder::calculate_move_stage(mlsp, aaa, move_speed_x, move_speed_y); + bool add_waypoint_direct(MoveList *mlsp, short x, short y, int move_speed_x, int move_speed_y) override { + return AGS::Engine::RouteFinder::add_waypoint_direct(mlsp, x, y, move_speed_x, move_speed_y); } }; @@ -78,8 +78,8 @@ public: int find_route(short srcx, short srcy, short xx, short yy, int move_speed_x, int move_speed_y, Bitmap *onscreen, int movlst, int nocross = 0, int ignore_walls = 0) override { return AGS::Engine::RouteFinderLegacy::find_route(srcx, srcy, xx, yy, move_speed_x, move_speed_y, onscreen, movlst, nocross, ignore_walls); } - void calculate_move_stage(MoveList *mlsp, int aaa, int move_speed_x, int move_speed_y) override { - AGS::Engine::RouteFinderLegacy::calculate_move_stage(mlsp, aaa, move_speed_x, move_speed_y); + bool add_waypoint_direct(MoveList *mlsp, short x, short y, int move_speed_x, int move_speed_y) override { + return AGS::Engine::RouteFinder::add_waypoint_direct(mlsp, x, y, move_speed_x, move_speed_y); } }; @@ -116,8 +116,8 @@ int find_route(short srcx, short srcy, short xx, short yy, int move_speed_x, int return _GP(route_finder_impl)->find_route(srcx, srcy, xx, yy, move_speed_x, move_speed_y, onscreen, movlst, nocross, ignore_walls); } -void calculate_move_stage(MoveList *mlsp, int aaa, int move_speed_x, int move_speed_y) { - _GP(route_finder_impl)->calculate_move_stage(mlsp, aaa, move_speed_x, move_speed_y); +bool add_waypoint_direct(MoveList *mlsp, short x, short y, int move_speed_x, int move_speed_y) { + return _GP(route_finder_impl)->add_waypoint_direct(mlsp, x, y, move_speed_x, move_speed_y); } } // namespace AGS3 diff --git a/engines/ags/engine/ac/route_finder.h b/engines/ags/engine/ac/route_finder.h index 5d23971ee60..f52d112737d 100644 --- a/engines/ags/engine/ac/route_finder.h +++ b/engines/ags/engine/ac/route_finder.h @@ -46,7 +46,7 @@ public: virtual int can_see_from(int x1, int y1, int x2, int y2) = 0; virtual void get_lastcpos(int &lastcx, int &lastcy) = 0; virtual int find_route(short srcx, short srcy, short xx, short yy, int move_speed_x, int move_speed_y, AGS::Shared::Bitmap *onscreen, int movlst, int nocross = 0, int ignore_walls = 0) = 0; - virtual void calculate_move_stage(MoveList *mlsp, int aaa, int move_speed_x, int move_speed_y) = 0; + virtual bool add_waypoint_direct(MoveList *mlsp, short x, short y, int move_speed_x, int move_speed_y) = 0; }; void init_pathfinder(GameDataVersion game_file_version); @@ -58,7 +58,8 @@ int can_see_from(int x1, int y1, int x2, int y2); void get_lastcpos(int &lastcx, int &lastcy); int find_route(short srcx, short srcy, short xx, short yy, int move_speed_x, int move_speed_y, AGS::Shared::Bitmap *onscreen, int movlst, int nocross = 0, int ignore_walls = 0); -void calculate_move_stage(MoveList *mlsp, int aaa, int move_speed_x, int move_speed_y); +// Append a waypoint to the move list, skip pathfinding +bool add_waypoint_direct(MoveList *mlsp, short x, short y, int move_speed_x, int move_speed_y); } // namespace AGS3 diff --git a/engines/ags/engine/ac/route_finder_impl.cpp b/engines/ags/engine/ac/route_finder_impl.cpp index b85f2fd5059..fb9bafeaaf5 100644 --- a/engines/ags/engine/ac/route_finder_impl.cpp +++ b/engines/ags/engine/ac/route_finder_impl.cpp @@ -117,7 +117,7 @@ inline fixed input_speed_to_fixed(int speed_val) { } // Calculates the X and Y per game loop, for this stage of the movelist -void calculate_move_stage_intern(MoveList *mlsp, int aaa, fixed move_speed_x, fixed move_speed_y) { +void calculate_move_stage(MoveList *mlsp, int aaa, fixed move_speed_x, fixed move_speed_y) { // work out the x & y per move. First, opp/adj=tan, so work out the angle if (mlsp->pos[aaa] == mlsp->pos[aaa + 1]) { mlsp->xpermove[aaa] = 0; @@ -189,10 +189,6 @@ void calculate_move_stage_intern(MoveList *mlsp, int aaa, fixed move_speed_x, fi mlsp->ypermove[aaa] = newymove; } -void calculate_move_stage(MoveList *mlsp, int aaa, int move_speed_x, int move_speed_y) { - calculate_move_stage_intern(mlsp, aaa, input_speed_to_fixed(move_speed_x), input_speed_to_fixed(move_speed_y)); -} - int find_route(short srcx, short srcy, short xx, short yy, int move_speed_x, int move_speed_y, Bitmap *onscreen, int movlst, int nocross, int ignore_walls) { _G(wallscreen) = onscreen; @@ -233,7 +229,7 @@ int find_route(short srcx, short srcy, short xx, short yy, int move_speed_x, int const fixed fix_speed_x = input_speed_to_fixed(move_speed_x); const fixed fix_speed_y = input_speed_to_fixed(move_speed_y); for (int i = 0; i < _G(num_navpoints) - 1; i++) { - calculate_move_stage_intern(&_GP(mls)[mlist], i, fix_speed_x, fix_speed_y); + calculate_move_stage(&_GP(mls)[mlist], i, fix_speed_x, fix_speed_y); } _GP(mls)[mlist].fromx = srcx; @@ -246,6 +242,20 @@ int find_route(short srcx, short srcy, short xx, short yy, int move_speed_x, int return mlist; } +bool add_waypoint_direct(MoveList *mlsp, short x, short y, int move_speed_x, int move_speed_y) { + if (mlsp->numstage >= MAXNEEDSTAGES) + return false; + + const fixed fix_speed_x = input_speed_to_fixed(move_speed_x); + const fixed fix_speed_y = input_speed_to_fixed(move_speed_y); + mlsp->pos[mlsp->numstage] = MAKE_INTCOORD(x, y); + calculate_move_stage(mlsp, mlsp->numstage - 1, fix_speed_x, fix_speed_y); + mlsp->numstage++; + mlsp->lastx = x; + mlsp->lasty = y; + return true; +} + } // namespace RouteFinder } // namespace Engine } // namespace AGS diff --git a/engines/ags/engine/ac/route_finder_impl.h b/engines/ags/engine/ac/route_finder_impl.h index 7389f66d25e..03683611662 100644 --- a/engines/ags/engine/ac/route_finder_impl.h +++ b/engines/ags/engine/ac/route_finder_impl.h @@ -48,7 +48,7 @@ int can_see_from(int x1, int y1, int x2, int y2); void get_lastcpos(int &lastcx, int &lastcy); int find_route(short srcx, short srcy, short xx, short yy, int move_speed_x, int move_speed_y, AGS::Shared::Bitmap *onscreen, int movlst, int nocross = 0, int ignore_walls = 0); -void calculate_move_stage(MoveList *mlsp, int aaa, int move_speed_x, int move_speed_y); +bool add_waypoint_direct(MoveList *mlsp, short x, short y, int move_speed_x, int move_speed_y); } // namespace RouteFinder } // namespace Engine diff --git a/engines/ags/engine/ac/route_finder_impl_legacy.cpp b/engines/ags/engine/ac/route_finder_impl_legacy.cpp index 967b1825237..15b8ba40a2e 100644 --- a/engines/ags/engine/ac/route_finder_impl_legacy.cpp +++ b/engines/ags/engine/ac/route_finder_impl_legacy.cpp @@ -637,7 +637,7 @@ inline fixed input_speed_to_fixed(int speed_val) { } // Calculates the X and Y per game loop, for this stage of the movelist -void calculate_move_stage_intern(MoveList *mlsp, int aaa, fixed move_speed_x, fixed move_speed_y) { +void calculate_move_stage(MoveList *mlsp, int aaa, fixed move_speed_x, fixed move_speed_y) { assert(mlsp != nullptr); // work out the x & y per move. First, opp/adj=tan, so work out the angle @@ -717,10 +717,6 @@ void calculate_move_stage_intern(MoveList *mlsp, int aaa, fixed move_speed_x, fi #endif } -void calculate_move_stage(MoveList *mlsp, int aaa, int move_speed_x, int move_speed_y) { - calculate_move_stage_intern(mlsp, aaa, input_speed_to_fixed(move_speed_x), input_speed_to_fixed(move_speed_y)); -} - #define MAKE_INTCOORD(x,y) (((unsigned short)x << 16) | ((unsigned short)y)) int find_route(short srcx, short srcy, short xx, short yy, int move_speed_x, int move_speed_y, Bitmap *onscreen, int movlst, int nocross, int ignore_walls) { @@ -844,7 +840,7 @@ stage_again: const fixed fix_speed_x = input_speed_to_fixed(move_speed_x); const fixed fix_speed_y = input_speed_to_fixed(move_speed_y); for (aaa = 0; aaa < numstages - 1; aaa++) { - calculate_move_stage_intern(&_GP(mls)[mlist], aaa, fix_speed_x, fix_speed_y); + calculate_move_stage(&_GP(mls)[mlist], aaa, fix_speed_x, fix_speed_y); } _GP(mls)[mlist].fromx = orisrcx; @@ -868,6 +864,20 @@ stage_again: #endif } +bool add_waypoint_direct(MoveList *mlsp, short x, short y, int move_speed_x, int move_speed_y) { + if (mlsp->numstage >= MAXNEEDSTAGES) + return false; + + const fixed fix_speed_x = input_speed_to_fixed(move_speed_x); + const fixed fix_speed_y = input_speed_to_fixed(move_speed_y); + mlsp->pos[mlsp->numstage] = MAKE_INTCOORD(x, y); + calculate_move_stage(mlsp, mlsp->numstage - 1, fix_speed_x, fix_speed_y); + mlsp->numstage++; + mlsp->lastx = x; + mlsp->lasty = y; + return true; +} + void shutdown_pathfinder() { if (pathbackx != nullptr) { free(pathbackx); diff --git a/engines/ags/engine/ac/route_finder_impl_legacy.h b/engines/ags/engine/ac/route_finder_impl_legacy.h index fc29fee79d9..cd7ce505a22 100644 --- a/engines/ags/engine/ac/route_finder_impl_legacy.h +++ b/engines/ags/engine/ac/route_finder_impl_legacy.h @@ -46,7 +46,7 @@ int can_see_from(int x1, int y1, int x2, int y2); void get_lastcpos(int &lastcx, int &lastcy); int find_route(short srcx, short srcy, short xx, short yy, int move_speed_x, int move_speed_y, AGS::Shared::Bitmap *onscreen, int movlst, int nocross = 0, int ignore_walls = 0); -void calculate_move_stage(MoveList *mlsp, int aaa, int move_speed_x, int move_speed_y); +bool add_waypoint_direct(MoveList *mlsp, short x, short y, int move_speed_x, int move_speed_y); } // namespace RouteFinderLegacy } // namespace Engine