From 12a95e1cd8017f3b912b46db450cf314333fcc07 Mon Sep 17 00:00:00 2001 From: klei1984 <53688147+klei1984@users.noreply.github.com> Date: Sun, 10 Nov 2024 16:26:45 +0100 Subject: [PATCH] Fixed defect 220. - Air transporters were able to unload land units onto the sea surface. - Air transporters were able to unload units on top of each other. - Personnel carriers used too restrictive caution levels. - Unified finish transport event handling in TaskTransport and TaskAssistMove tasks. - Renamed an API function. --- src/paths.cpp | 21 +++++++- src/paths.hpp | 5 ++ src/paths_manager.cpp | 5 +- src/taskassistmove.cpp | 23 +-------- src/tasktransport.cpp | 109 ++++++++++++++++++++--------------------- src/tasktransport.hpp | 1 + src/units_manager.cpp | 9 +++- 7 files changed, 92 insertions(+), 81 deletions(-) diff --git a/src/paths.cpp b/src/paths.cpp index 9bd9064..36242fa 100644 --- a/src/paths.cpp +++ b/src/paths.cpp @@ -47,6 +47,8 @@ static void Paths_FinishMove(UnitInfo* unit); static void Paths_TakeStep(UnitInfo* unit, int32_t cost); static bool Paths_CalculateStep(UnitInfo* unit, int32_t cost, bool is_diagonal_step); +SmartObjectArray Paths_SiteReservations; + static uint16_t Paths_AirPath_TypeIndex; static RegisterClass Paths_AirPath_ClassRegister("AirPath", &Paths_AirPath_TypeIndex, &AirPath::Allocate); @@ -586,7 +588,8 @@ int32_t GroundPath::GetMovementCost(UnitInfo* unit) { grid_x += step->x; grid_y += step->y; - step_cost = Access_IsAccessible(unit->GetUnitType(), unit->team, grid_x, grid_y, AccessModifier_NoModifiers); + step_cost = + Access_IsAccessible(unit->GetUnitType(), unit->team, grid_x, grid_y, AccessModifier_NoModifiers); if (step->x && step->y) { step_cost = (step_cost * 3) / 2; @@ -1626,3 +1629,19 @@ bool Paths_IsOccupied(int32_t grid_x, int32_t grid_y, int32_t angle, int32_t tea return false; } + +void Paths_ReserveSite(const Point site) noexcept { Paths_SiteReservations.PushBack(&site); } + +void Paths_RemoveSiteReservation(const Point site) noexcept { + const int32_t position{Paths_SiteReservations->Find(&site)}; + + SDL_assert(position != -1); + + if (position != -1) { + Paths_SiteReservations.Remove(position); + } +} + +void Paths_ClearSiteReservations() noexcept { Paths_SiteReservations.Clear(); } + +[[nodiscard]] bool Paths_IsSiteReserved(const Point site) noexcept { return Paths_SiteReservations->Find(&site) != -1; } diff --git a/src/paths.hpp b/src/paths.hpp index c83fcdf..c1a2d93 100644 --- a/src/paths.hpp +++ b/src/paths.hpp @@ -154,6 +154,11 @@ void Paths_DrawMarker(WindowInfo* window, int32_t angle, int32_t grid_x, int32_t void Paths_DrawShots(WindowInfo* window, int32_t grid_x, int32_t grid_y, int32_t shots); bool Paths_IsOccupied(int32_t grid_x, int32_t grid_y, int32_t angle, int32_t team); +void Paths_ReserveSite(const Point site) noexcept; +void Paths_RemoveSiteReservation(const Point site) noexcept; +void Paths_ClearSiteReservations() noexcept; +[[nodiscard]] bool Paths_IsSiteReserved(const Point site) noexcept; + extern const Point Paths_8DirPointsArray[8]; extern const int16_t Paths_8DirPointsArrayX[8]; extern const int16_t Paths_8DirPointsArrayY[8]; diff --git a/src/paths_manager.cpp b/src/paths_manager.cpp index 7f68abe..609f4bc 100644 --- a/src/paths_manager.cpp +++ b/src/paths_manager.cpp @@ -316,7 +316,10 @@ void PathsManager_PushFront(PathRequest &object) { PathsManager_Instance.PushFro void PathsManager_EvaluateTiles() { PathsManager_Instance.EvaluateTiles(); } -void PathsManager_Clear() { PathsManager_Instance.Clear(); } +void PathsManager_Clear() { + PathsManager_Instance.Clear(); + Paths_ClearSiteReservations(); +} bool PathsManager_HasRequest(UnitInfo *unit) { return PathsManager_Instance.HasRequest(unit); } diff --git a/src/taskassistmove.cpp b/src/taskassistmove.cpp index 9dddb05..70f9604 100644 --- a/src/taskassistmove.cpp +++ b/src/taskassistmove.cpp @@ -67,28 +67,7 @@ void TaskAssistMove::RequestTransport(UnitInfo* transporter, UnitInfo* client) { } void TaskAssistMove::CompleteTransport(UnitInfo* transporter, UnitInfo* client, Point site) { - if (GameManager_IsActiveTurn(team)) { - if (Access_GetTeamUnit(site.x, site.y, team, MOBILE_SEA_UNIT | MOBILE_LAND_UNIT)) { - SmartPointer zone = new (std::nothrow) Zone(client, this); - - zone->Add(&site); - - AiPlayer_Teams[team].ClearZone(&*zone); - - } else { - transporter->target_grid_x = site.x; - transporter->target_grid_y = site.y; - - transporter->SetParent(client); - - if (transporter->GetUnitType() == AIRTRANS) { - UnitsManager_SetNewOrder(transporter, ORDER_UNLOAD, ORDER_STATE_INIT); - - } else { - UnitsManager_SetNewOrder(transporter, ORDER_ACTIVATE, ORDER_STATE_EXECUTING_ORDER); - } - } - } + TaskTransport_FinishTransport(this, transporter, client, site); } bool TaskAssistMove::Task_vfunc1(UnitInfo& unit) { return unit.storage == 0; } diff --git a/src/tasktransport.cpp b/src/tasktransport.cpp index db6738f..c8d0f36 100644 --- a/src/tasktransport.cpp +++ b/src/tasktransport.cpp @@ -489,30 +489,24 @@ bool TaskTransport::Execute(UnitInfo& unit) { result = true; } else if (ChooseNewTask()) { - int32_t distance; - - if (transporter_unit_type == AIRTRANS) { - distance = 0; - - } else { - distance = 3; - } + int32_t distance = (transporter_unit_type == AIRTRANS) ? 0 : 3; if (task_move->GetPassenger()->GetOrder() == ORDER_IDLE) { if (unit.storage > 0) { - Point destination = task_move->GetDestination(); + const Point destination = task_move->GetDestination(); - if (destination.x >= 0) { - if (TaskManager_GetDistance(Point(unit_transporter->grid_x, unit_transporter->grid_y), - task_move->GetDestination()) > distance) { - SmartPointer move = new (std::nothrow) - TaskMove(&*unit_transporter, this, distance, CAUTION_LEVEL_AVOID_ALL_DAMAGE, - task_move->GetDestination(), &MoveFinishedCallback2); - - TaskManager.AppendTask(*move); + if (destination.x >= 0 && destination.y >= 0) { + if (Access_GetDistance(unit_transporter.Get(), destination) <= distance) { + UnloadUnit(task_move->GetPassenger()); } else { - UnloadUnit(task_move->GetPassenger()); + SmartPointer move = new (std::nothrow) TaskMove( + &*unit_transporter, this, distance, + unit_transporter->GetUnitType() == CLNTRANS ? CAUTION_LEVEL_AVOID_NEXT_TURNS_FIRE + : CAUTION_LEVEL_AVOID_ALL_DAMAGE, + destination, &MoveFinishedCallback2); + + TaskManager.AppendTask(*move); } result = true; @@ -706,6 +700,45 @@ void TaskTransport_MoveFinishedCallback(Task* task, UnitInfo* unit, char result) } } +void TaskTransport_FinishTransport(Task* const task, UnitInfo* const transporter, UnitInfo* const client, Point site) { + if (GameManager_IsActiveTurn(task->GetTeam())) { + AiLog log("TaskAssistMove: Unload %s.", UnitsManager_BaseUnits[client->GetUnitType()].singular_name); + + auto unit_in_the_way = Access_GetTeamUnit(site.x, site.y, task->GetTeam(), MOBILE_SEA_UNIT | MOBILE_LAND_UNIT); + + if (unit_in_the_way) { + if (Task_IsReadyToTakeOrders(unit_in_the_way)) { + SmartPointer zone = new (std::nothrow) Zone(client, task); + + log.Log("Must clear landing zone first."); + + zone->Add(&site); + + AiPlayer_Teams[task->GetTeam()].ClearZone(zone.Get()); + } + + } else if (Access_IsAccessible(client->GetUnitType(), task->GetTeam(), site.x, site.y, + AccessModifier_SameClassBlocks)) { + transporter->target_grid_x = site.x; + transporter->target_grid_y = site.y; + + transporter->SetParent(client); + + if (transporter->GetUnitType() == AIRTRANS) { + UnitsManager_SetNewOrder(transporter, ORDER_UNLOAD, ORDER_STATE_INIT); + + } else { + UnitsManager_SetNewOrder(transporter, ORDER_ACTIVATE, ORDER_STATE_EXECUTING_ORDER); + } + + } else { + SDL_assert(client->GetTask()->GetType() == TaskType_TaskMove); + + dynamic_cast(client->GetTask())->SetDestination(Point(-1, -1)); + } + } +} + bool TaskTransport::LoadUnit(UnitInfo* unit) { bool result; @@ -776,44 +809,8 @@ bool TaskTransport::LoadUnit(UnitInfo* unit) { return result; } -void TaskTransport::UnloadUnit(UnitInfo* unit) { - AiLog log("Transport: Unload %s.", UnitsManager_BaseUnits[unit->GetUnitType()].singular_name); - - if (GameManager_IsActiveTurn(team)) { - Point destination = task_move->GetDestination(); - - if (destination.x >= 0 && unit_transporter == unit->GetParent()) { - UnitInfo* unit_in_the_way = - Access_GetTeamUnit(destination.x, destination.y, team, MOBILE_SEA_UNIT | MOBILE_LAND_UNIT); - - if (unit_in_the_way) { - SmartPointer zone = new (std::nothrow) Zone(unit, this); - - log.Log("Must clear landing zone first."); - - zone->Add(&destination); - - if (Task_IsReadyToTakeOrders(unit_in_the_way)) { - AiPlayer_Teams[team].ClearZone(&*zone); - } - - } else { - unit_transporter->target_grid_x = destination.x; - unit_transporter->target_grid_y = destination.y; - - unit_transporter->SetParent(unit); - - SDL_assert(GameManager_IsActiveTurn(team)); - - if (unit_transporter->GetUnitType() == AIRTRANS) { - UnitsManager_SetNewOrder(&*unit_transporter, ORDER_UNLOAD, ORDER_STATE_INIT); - - } else { - UnitsManager_SetNewOrder(&*unit_transporter, ORDER_ACTIVATE, ORDER_STATE_EXECUTING_ORDER); - } - } - } - } +void TaskTransport::UnloadUnit(UnitInfo* client) { + TaskTransport_FinishTransport(this, unit_transporter.Get(), client, task_move->GetDestination()); } ResourceID TaskTransport::GetTransporterType() const { return transporter_unit_type; } diff --git a/src/tasktransport.hpp b/src/tasktransport.hpp index 1048b88..0b8b627 100644 --- a/src/tasktransport.hpp +++ b/src/tasktransport.hpp @@ -72,5 +72,6 @@ class TaskTransport : public Task { bool TaskTransport_Search(UnitInfo* transporter, UnitInfo* client, TransporterMap* map); void TaskTransport_MoveFinishedCallback(Task* task, UnitInfo* unit, char result); +void TaskTransport_FinishTransport(Task* const task, UnitInfo* const transporter, UnitInfo* const client, Point site); #endif /* TASKTRANSPORT_HPP */ diff --git a/src/units_manager.cpp b/src/units_manager.cpp index 64e2559..7c1e01e 100644 --- a/src/units_manager.cpp +++ b/src/units_manager.cpp @@ -4701,11 +4701,14 @@ void UnitsManager_ProcessOrderUnload(UnitInfo* unit) { unit->moved = 0; unit->SetOrderState(ORDER_STATE_UNLOADING_IN_PROGRESS); - if (Paths_IsOccupied(unit->grid_x, unit->grid_y, 0, unit->team)) { + const Point site{unit->grid_x, unit->grid_y}; + + if (Paths_IsSiteReserved(site) || Paths_IsOccupied(unit->grid_x, unit->grid_y, 0, unit->team)) { unit->SetOrder(ORDER_AWAIT); unit->SetOrderState(ORDER_STATE_EXECUTING_ORDER); } else { + Paths_ReserveSite(site); UnitsManager_ProgressUnloading(unit); } } break; @@ -5934,6 +5937,10 @@ void UnitsManager_ProgressUnloading(UnitInfo* unit) { unit->SetOrderState(ORDER_STATE_FINISH_UNLOADING); + const Point site{client->grid_x, client->grid_y}; + + Paths_RemoveSiteReservation(site); + if (GameManager_SelectedUnit == unit) { GameManager_UpdateInfoDisplay(unit); }