mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 05:38:56 +00:00
AGS: Engine: implement add_waypoint_direct(), fix AddWaypoint's resolution
This fixes Character.AddWaypoint not applying room<->mask resolution conversion, which result in character's speed being different if room has non 1:1 mask resolution. Hide calculate_move_stage() inside pathfinder, and expose add_waypoint_direct() in the pathfinder interface instead. From upstream 093354d78849dc3b4f13a244d4400c4e71f7d687
This commit is contained in:
parent
dacccc343e
commit
0b50067abb
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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]);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user