diff --git a/CMakeLists.txt b/CMakeLists.txt index 0fa9fa1c93..118491dc41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,9 +50,9 @@ set(OBJECTS_VERSION "1.2.1") set(OBJECTS_URL "https://github.com/OpenRCT2/objects/releases/download/v${OBJECTS_VERSION}/objects.zip") set(OBJECTS_SHA1 "540e004abc683b3fe22211f5234e3d78ab023c5f") -set(REPLAYS_VERSION "0.0.43") +set(REPLAYS_VERSION "0.0.44") set(REPLAYS_URL "https://github.com/OpenRCT2/replays/releases/download/v${REPLAYS_VERSION}/replays.zip") -set(REPLAYS_SHA1 "269E4FC432A73AE9A5D601EC2A1C882F3D9BDF3C") +set(REPLAYS_SHA1 "586F3930DE8D2C3880AAFD30ABC4D81ABC0B64A4") option(FORCE32 "Force 32-bit build. It will add `-m32` to compiler flags.") option(WITH_TESTS "Build tests") diff --git a/data/language/fi-FI.txt b/data/language/fi-FI.txt index fb3ca39e84..3f077759f1 100644 --- a/data/language/fi-FI.txt +++ b/data/language/fi-FI.txt @@ -3689,6 +3689,20 @@ STR_6436 :Näkymättömyys päälle/pois STR_6437 :Näkymätön STR_6438 :N STR_6439 :Ruututyökalu: Näkymättömyys päälle/pois +STR_6440 :Läpinäkyvä vesi +STR_6441 :Ainakin yhden polunpinnan tulee olla valittu. +STR_6442 :Ainakin yhden jonotusaluepinnan tulee olla valittu. +STR_6443 :Ainakin yhden polunkaiteen tulee olla valittu. +STR_6444 :Polun pinnat +STR_6445 :Polun kaiteet +STR_6446 :{WINDOW_COLOUR_2}Pinnan nimi: {BLACK}{STRINGID} +STR_6447 :{WINDOW_COLOUR_2}Kaiteen nimi: {BLACK}{STRINGID} +STR_6448 :Esineen muotoa ei tueta +STR_6449 :{WINDOW_COLOUR_2}Raidat: +STR_6450 :{BLACK}”{STRING}” +STR_6451 :{BLACK}”{STRING}” - {STRING} +STR_6452 :{WINDOW_COLOUR_2}Myy: {BLACK}{STRING} +STR_6453 :Kopioi versiotiedot ############# # Scenarios # diff --git a/data/language/ko-KR.txt b/data/language/ko-KR.txt index 32dd21608e..b4c2b7b49a 100644 --- a/data/language/ko-KR.txt +++ b/data/language/ko-KR.txt @@ -2408,7 +2408,7 @@ STR_3308 :{WINDOW_COLOUR_2}흥미도: STR_3309 :{WINDOW_COLOUR_2}{COMMA16} STR_3310 :{WINDOW_COLOUR_2}{LENGTH} STR_3311 :{WINDOW_COLOUR_2}{COMMA2DP32} -STR_3312 :{WINDOW_COLOUR_2}파괴할 수 없는 놀이기구/시설: +STR_3312 :{WINDOW_COLOUR_2}수정·파괴할 수 없는 놀이기구/시설: STR_3313 :시나리오 이름 STR_3314 :시나리오 이름을 입력하세요: STR_3315 :공원/시나리오 상세 설명 diff --git a/src/openrct2/GameStateSnapshots.cpp b/src/openrct2/GameStateSnapshots.cpp index 9923545461..92bdad00d9 100644 --- a/src/openrct2/GameStateSnapshots.cpp +++ b/src/openrct2/GameStateSnapshots.cpp @@ -253,7 +253,10 @@ struct GameStateSnapshots final : public IGameStateSnapshots COMPARE_FIELD(Peep, InteractionRideIndex); COMPARE_FIELD(Peep, Id); COMPARE_FIELD(Peep, PathCheckOptimisation); - COMPARE_FIELD(Peep, PathfindGoal); + COMPARE_FIELD(Peep, PathfindGoal.x); + COMPARE_FIELD(Peep, PathfindGoal.y); + COMPARE_FIELD(Peep, PathfindGoal.z); + COMPARE_FIELD(Peep, PathfindGoal.direction); for (int i = 0; i < 4; i++) { COMPARE_FIELD(Peep, PathfindHistory[i].x); diff --git a/src/openrct2/actions/PlaceParkEntranceAction.cpp b/src/openrct2/actions/PlaceParkEntranceAction.cpp index af9706f527..109fa8940d 100644 --- a/src/openrct2/actions/PlaceParkEntranceAction.cpp +++ b/src/openrct2/actions/PlaceParkEntranceAction.cpp @@ -59,7 +59,8 @@ GameActions::Result::Ptr PlaceParkEntranceAction::Query() const if (!CheckMapCapacity(3)) { - return std::make_unique(GameActions::Status::NoFreeElements, STR_CANT_BUILD_THIS_HERE, STR_NONE); + return std::make_unique( + GameActions::Status::NoFreeElements, STR_CANT_BUILD_THIS_HERE, STR_ERR_LANDSCAPE_DATA_AREA_FULL); } if (gParkEntrances.size() >= MAX_PARK_ENTRANCES) diff --git a/src/openrct2/core/DataSerialiserTraits.h b/src/openrct2/core/DataSerialiserTraits.h index 14d0ee1736..1072dd83fc 100644 --- a/src/openrct2/core/DataSerialiserTraits.h +++ b/src/openrct2/core/DataSerialiserTraits.h @@ -870,3 +870,32 @@ template<> struct DataSerializerTraits_t stream->Write(msg, strlen(msg)); } }; + +template<> struct DataSerializerTraits_t +{ + static void encode(OpenRCT2::IStream* stream, const TileCoordsXYZD& coord) + { + stream->WriteValue(ByteSwapBE(coord.x)); + stream->WriteValue(ByteSwapBE(coord.y)); + stream->WriteValue(ByteSwapBE(coord.z)); + stream->WriteValue(ByteSwapBE(coord.direction)); + } + + static void decode(OpenRCT2::IStream* stream, TileCoordsXYZD& coord) + { + auto x = ByteSwapBE(stream->ReadValue()); + auto y = ByteSwapBE(stream->ReadValue()); + auto z = ByteSwapBE(stream->ReadValue()); + auto d = ByteSwapBE(stream->ReadValue()); + coord = TileCoordsXYZD{ x, y, z, d }; + } + + static void log(OpenRCT2::IStream* stream, const TileCoordsXYZD& coord) + { + char msg[128] = {}; + snprintf( + msg, sizeof(msg), "TileCoordsXYZD(x = %d, y = %d, z = %d, direction = %d)", coord.x, coord.y, coord.z, + coord.direction); + stream->Write(msg, strlen(msg)); + } +}; diff --git a/src/openrct2/peep/GuestPathfinding.cpp b/src/openrct2/peep/GuestPathfinding.cpp index 9bf83c9a7f..8a2f474810 100644 --- a/src/openrct2/peep/GuestPathfinding.cpp +++ b/src/openrct2/peep/GuestPathfinding.cpp @@ -700,8 +700,7 @@ static void peep_pathfind_heuristic_search( /* If this is where the search started this is a search loop and the * current search path ends here. * Return without updating the parameters (best result so far). */ - if ((_peepPathFindHistory[0].location.x == static_cast(loc.x)) - && (_peepPathFindHistory[0].location.y == static_cast(loc.y)) && (_peepPathFindHistory[0].location.z == loc.z)) + if (_peepPathFindHistory[0].location == loc) { #if defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2 if (gPathFindDebug) @@ -1076,7 +1075,7 @@ static void peep_pathfind_heuristic_search( * already been visited by the peep while heading for this goal. */ for (auto& pathfindHistory : peep->PathfindHistory) { - if (pathfindHistory.x == loc.x && pathfindHistory.y == loc.y && pathfindHistory.z == loc.z) + if (pathfindHistory == loc) { if (pathfindHistory.direction == 0) { @@ -1103,9 +1102,7 @@ static void peep_pathfind_heuristic_search( for (int32_t junctionNum = _peepPathFindNumJunctions + 1; junctionNum <= _peepPathFindMaxJunctions; junctionNum++) { - if ((_peepPathFindHistory[junctionNum].location.x == static_cast(loc.x)) - && (_peepPathFindHistory[junctionNum].location.y == static_cast(loc.y)) - && (_peepPathFindHistory[junctionNum].location.z == loc.z)) + if (_peepPathFindHistory[junctionNum].location == loc) { pathLoop = true; break; @@ -1144,9 +1141,7 @@ static void peep_pathfind_heuristic_search( for (uint8_t junctInd = 0; junctInd < *endJunctions; junctInd++) { uint8_t histIdx = _peepPathFindMaxJunctions - junctInd; - junctionList[junctInd].x = _peepPathFindHistory[histIdx].location.x; - junctionList[junctInd].y = _peepPathFindHistory[histIdx].location.y; - junctionList[junctInd].z = _peepPathFindHistory[histIdx].location.z; + junctionList[junctInd] = _peepPathFindHistory[histIdx].location; directionList[junctInd] = _peepPathFindHistory[histIdx].direction; } } @@ -1163,9 +1158,7 @@ static void peep_pathfind_heuristic_search( /* This junction was NOT previously visited in the current * search path, so add the junction to the history. */ - _peepPathFindHistory[_peepPathFindNumJunctions].location.x = static_cast(loc.x); - _peepPathFindHistory[_peepPathFindNumJunctions].location.y = static_cast(loc.y); - _peepPathFindHistory[_peepPathFindNumJunctions].location.z = loc.z; + _peepPathFindHistory[_peepPathFindNumJunctions].location = loc; // .direction take is added below. _peepPathFindNumJunctions--; @@ -1334,7 +1327,7 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) permitted_edges &= 0xF; uint8_t edges = permitted_edges; - if (isThin && peep->PathfindGoal.x == goal.x && peep->PathfindGoal.y == goal.y && peep->PathfindGoal.z == goal.z) + if (isThin && peep->PathfindGoal == goal) { /* Use of peep->PathfindHistory[]: * When walking to a goal, the peep PathfindHistory stores @@ -1353,7 +1346,7 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) * directions it has not yet tried. */ for (auto& pathfindHistory : peep->PathfindHistory) { - if (pathfindHistory.x == loc.x && pathfindHistory.y == loc.y && pathfindHistory.z == loc.z) + if (pathfindHistory == loc) { /* Fix broken PathfindHistory[i].direction * which have untried directions that are not @@ -1401,16 +1394,15 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) /* If this is a new goal for the peep. Store it and reset the peep's * PathfindHistory. */ - if (!direction_valid(peep->PathfindGoal.direction) || peep->PathfindGoal.x != goal.x || peep->PathfindGoal.y != goal.y - || peep->PathfindGoal.z != goal.z) + if (!direction_valid(peep->PathfindGoal.direction) || peep->PathfindGoal != goal) { - peep->PathfindGoal.x = goal.x; - peep->PathfindGoal.y = goal.y; - peep->PathfindGoal.z = goal.z; - peep->PathfindGoal.direction = 0; + peep->PathfindGoal = { goal, 0 }; // Clear pathfinding history - std::fill(std::begin(peep->PathfindHistory), std::end(peep->PathfindHistory), rct12_xyzd8{ 0xFF, 0xFF, 0xFF, 0xFF }); + TileCoordsXYZD nullPos; + nullPos.setNull(); + + std::fill(std::begin(peep->PathfindHistory), std::end(peep->PathfindHistory), nullPos); #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 if (_pathFindDebug) { @@ -1466,14 +1458,17 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) _peepPathFindNumJunctions = _peepPathFindMaxJunctions; // Initialise _peepPathFindHistory. - std::memset(static_cast(_peepPathFindHistory), 0xFF, sizeof(_peepPathFindHistory)); + + for (auto& entry : _peepPathFindHistory) + { + entry.location.setNull(); + entry.direction = INVALID_DIRECTION; + } /* The pathfinding will only use elements * 1.._peepPathFindMaxJunctions, so the starting point * is placed in element 0 */ - _peepPathFindHistory[0].location.x = static_cast(loc.x); - _peepPathFindHistory[0].location.y = static_cast(loc.y); - _peepPathFindHistory[0].location.z = loc.z; + _peepPathFindHistory[0].location = loc; _peepPathFindHistory[0].direction = 0xF; uint16_t score = 0xFFFF; @@ -1586,8 +1581,7 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) { for (int32_t i = 0; i < 4; ++i) { - if (peep->PathfindHistory[i].x == loc.x && peep->PathfindHistory[i].y == loc.y - && peep->PathfindHistory[i].z == loc.z) + if (peep->PathfindHistory[i] == loc) { /* Peep remembers this junction, so remove the * chosen_edge from those left to try. */ @@ -1611,10 +1605,7 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) * and remember this junction. */ int32_t i = peep->PathfindGoal.direction++; peep->PathfindGoal.direction &= 3; - peep->PathfindHistory[i].x = static_cast(loc.x); - peep->PathfindHistory[i].y = static_cast(loc.y); - peep->PathfindHistory[i].z = loc.z; - peep->PathfindHistory[i].direction = permitted_edges; + peep->PathfindHistory[i] = { loc, permitted_edges }; /* Remove the chosen_edge from those left to try. */ peep->PathfindHistory[i].direction &= ~(1 << chosen_edge); /* Also remove the edge through which the peep @@ -2312,9 +2303,7 @@ void Peep::ResetPathfindGoal() } #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - PathfindGoal.x = 0xFF; - PathfindGoal.y = 0xFF; - PathfindGoal.z = 0xFF; + PathfindGoal.setNull(); PathfindGoal.direction = INVALID_DIRECTION; } diff --git a/src/openrct2/peep/Peep.h b/src/openrct2/peep/Peep.h index 5783aab897..7a4a714c91 100644 --- a/src/openrct2/peep/Peep.h +++ b/src/openrct2/peep/Peep.h @@ -616,8 +616,8 @@ struct Peep : SpriteBase ride_id_t InteractionRideIndex; uint32_t Id; uint8_t PathCheckOptimisation; // see peep.checkForPath - rct12_xyzd8 PathfindGoal; - std::array PathfindHistory; + TileCoordsXYZD PathfindGoal; + std::array PathfindHistory; uint8_t WalkingFrameNum; uint32_t PeepFlags; diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index 9bf9f9bdc5..342c545755 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -1366,6 +1366,10 @@ public: void ImportEntityPeep(Peep* dst, const RCT2SpritePeep* src) { + const auto isNullLocation = [](const rct12_xyzd8& pos) { + return pos.x == 0xFF && pos.y == 0xFF && pos.z == 0xFF && pos.direction == INVALID_DIRECTION; + }; + ImportEntityCommonProperties(static_cast(dst), src); if (is_user_string_id(src->name_string_idx)) { @@ -1402,10 +1406,28 @@ public: dst->Id = src->id; dst->PathCheckOptimisation = src->path_check_optimisation; dst->PeepFlags = src->peep_flags; - dst->PathfindGoal = src->pathfind_goal; + if (isNullLocation(src->pathfind_goal)) + { + dst->PathfindGoal.setNull(); + dst->PathfindGoal.direction = INVALID_DIRECTION; + } + else + { + dst->PathfindGoal = { src->pathfind_goal.x, src->pathfind_goal.y, src->pathfind_goal.z, + src->pathfind_goal.direction }; + } for (size_t i = 0; i < std::size(src->pathfind_history); i++) { - dst->PathfindHistory[i] = src->pathfind_history[i]; + if (isNullLocation(src->pathfind_history[i])) + { + dst->PathfindHistory[i].setNull(); + dst->PathfindHistory[i].direction = INVALID_DIRECTION; + } + else + { + dst->PathfindHistory[i] = { src->pathfind_history[i].x, src->pathfind_history[i].y, src->pathfind_history[i].z, + src->pathfind_history[i].direction }; + } } dst->WalkingFrameNum = src->no_action_frame_num; } diff --git a/src/openrct2/world/Location.hpp b/src/openrct2/world/Location.hpp index 7fd725fffa..19e5ff9952 100644 --- a/src/openrct2/world/Location.hpp +++ b/src/openrct2/world/Location.hpp @@ -268,6 +268,12 @@ struct CoordsXYZ : public CoordsXY { return ToTileStart() + CoordsXYZ{ COORDS_XY_HALF_TILE, COORDS_XY_HALF_TILE, 0 }; } + + void setNull() + { + CoordsXY::setNull(); + z = 0; + } }; struct CoordsXYRangedZ : public CoordsXY @@ -459,6 +465,12 @@ struct TileCoordsXYZ : public TileCoordsXY } return { x * COORDS_XY_STEP, y * COORDS_XY_STEP, z * COORDS_Z_STEP }; } + + void setNull() + { + TileCoordsXY::setNull(); + z = 0; + } }; /** @@ -615,6 +627,12 @@ struct TileCoordsXYZD : public TileCoordsXYZ { } + TileCoordsXYZD(const TileCoordsXYZ& t_, Direction d_) + : TileCoordsXYZ(t_) + , direction(d_) + { + } + TileCoordsXYZD(const TileCoordsXY& t_, int32_t z_, Direction d_) : TileCoordsXYZ(t_, z_) , direction(d_) @@ -649,6 +667,12 @@ struct TileCoordsXYZD : public TileCoordsXYZ } return { x * COORDS_XY_STEP, y * COORDS_XY_STEP, z * COORDS_Z_STEP, direction }; } + + void setNull() + { + TileCoordsXYZ::setNull(); + direction = INVALID_DIRECTION; + } }; /**