diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp index 8bcc41455d..5e691d1dbe 100644 --- a/src/ai/ai_gui.cpp +++ b/src/ai/ai_gui.cpp @@ -853,7 +853,7 @@ struct AIConfigWindow : public Window { case WID_AIC_GAMELIST: { this->selected_slot = OWNER_DEITY; this->InvalidateData(); - if (click_count > 1 && this->selected_slot != INVALID_COMPANY) ShowAIListWindow((CompanyID)this->selected_slot); + if (click_count > 1 && this->selected_slot != INVALID_COMPANY && _game_mode != GM_NORMAL) ShowAIListWindow((CompanyID)this->selected_slot); break; } diff --git a/src/economy.cpp b/src/economy.cpp index 65709e60b4..4f890b01d2 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -19,6 +19,7 @@ #include "network/network_func.h" #include "ai/ai.hpp" #include "aircraft.h" +#include "train.h" #include "newgrf_engine.h" #include "engine_base.h" #include "ground_vehicle.hpp" @@ -1338,21 +1339,135 @@ static void ReserveConsist(Station *st, Vehicle *u, CargoArray *consist_capleft, } /** - * Checks whether an articulated vehicle is empty. - * @param v Vehicle - * @return true if all parts are empty. + * Iterate the articulated parts of a vehicle, also considering the special cases of "normal" + * aircraft and double headed trains. Apply an action to each vehicle and immediately return false + * if that action does so. Otherwise return true. + * @tparam Taction Class of action to be applied. Must implement bool operator()([const] Vehicle *). + * @param v First articulated part. + * @param action Instance of Taction. + * @return false if any of the action invocations returned false, true otherwise. */ -static bool IsArticulatedVehicleEmpty(Vehicle *v) +template +bool IterateVehicleParts(Vehicle *v, Taction action) { - v = v->GetFirstEnginePart(); - - for (; v != NULL; v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : NULL) { - if (v->cargo.StoredCount() != 0) return false; + for (Vehicle *w = v; w != NULL; + w = w->HasArticulatedPart() ? w->GetNextArticulatedPart() : NULL) { + if (!action(w)) return false; + if (w->type == VEH_TRAIN) { + Train *train = Train::From(w); + if (train->IsMultiheaded() && !action(train->other_multiheaded_part)) return false; + } } - + if (v->type == VEH_AIRCRAFT && Aircraft::From(v)->IsNormalAircraft()) return action(v->Next()); return true; } +/** + * Action to check if a vehicle has no stored cargo. + */ +struct IsEmptyAction +{ + /** + * Checks if the vehicle has stored cargo. + * @param v Vehicle to be checked. + * @return true if v is either empty or has only reserved cargo, false otherwise. + */ + bool operator()(const Vehicle *v) + { + return v->cargo.StoredCount() == 0; + } +}; + +/** + * Refit preparation action. + */ +struct PrepareRefitAction +{ + CargoArray &consist_capleft; ///< Capacities left in the consist. + uint32 &refit_mask; ///< Bitmask of possible refit cargoes. + + /** + * Create a refit preparation action. + * @param consist_capleft Capacities left in consist, to be updated here. + * @param refit_mask Refit mask to be constructed from refit information of vehicles. + */ + PrepareRefitAction(CargoArray &consist_capleft, uint32 &refit_mask) : + consist_capleft(consist_capleft), refit_mask(refit_mask) {} + + /** + * Prepares for refitting of a vehicle, subtracting its free capacity from consist_capleft and + * adding the cargoes it can refit to to the refit mask. + * @param v The vehicle to be refitted. + * @return true. + */ + bool operator()(const Vehicle *v) + { + this->consist_capleft[v->cargo_type] -= v->cargo_cap - v->cargo.ReservedCount(); + this->refit_mask |= EngInfo(v->engine_type)->refit_mask; + return true; + } +}; + +/** + * Action for returning reserved cargo. + */ +struct ReturnCargoAction +{ + Station *st; ///< Station to give the returned cargo to. + StationID next_hop; ///< Next hop the cargo should be assigned to. + + /** + * Construct a cargo return action. + * @param st Station to give the returned cargo to. + * @param next_one Next hop the cargo should be assigned to. + */ + ReturnCargoAction(Station *st, StationID next_one) : st(st), next_hop(next_one) {} + + /** + * Return all reserved cargo from a vehicle. + * @param v Vehicle to return cargo from. + * @return true. + */ + bool operator()(Vehicle *v) + { + v->cargo.Return(UINT_MAX, &this->st->goods[v->cargo_type].cargo, this->next_hop); + return true; + } +}; + +/** + * Action for finalizing a refit. + */ +struct FinalizeRefitAction +{ + CargoArray &consist_capleft; ///< Capacities left in the consist. + Station *st; ///< Station to reserve cargo from. + StationIDStack &next_station; ///< Next hops to reserve cargo for. + + /** + * Create a finalizing action. + * @param consist_capleft Capacities left in the consist. + * @param st Station to reserve cargo from. + * @param next_station Next hops to reserve cargo for. + */ + FinalizeRefitAction(CargoArray &consist_capleft, Station *st, StationIDStack &next_station) : + consist_capleft(consist_capleft), st(st), next_station(next_station) {} + + /** + * Reserve cargo from the station and update the remaining consist capacities with the + * vehicle's remaining free capacity. + * @param v Vehicle to be finalized. + * @return true. + */ + bool operator()(Vehicle *v) + { + this->st->goods[v->cargo_type].cargo.Reserve(v->cargo_cap - v->cargo.RemainingCount(), + &v->cargo, st->xy, next_station); + this->consist_capleft[v->cargo_type] += v->cargo_cap - v->cargo.RemainingCount(); + return true; + } +}; + /** * Refit a vehicle in a station. * @param v Vehicle to be refitted. @@ -1363,32 +1478,15 @@ static bool IsArticulatedVehicleEmpty(Vehicle *v) */ static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station *st, StationIDStack next_station, CargoID new_cid) { - if (v->type == VEH_AIRCRAFT && (!Aircraft::From(v)->IsNormalAircraft() || v->Next()->cargo.StoredCount() > 0)) { - return; - } - - bool is_normal_aircraft = (v->type == VEH_AIRCRAFT && Aircraft::From(v)->IsNormalAircraft()); Vehicle *v_start = v->GetFirstEnginePart(); - - /* Remove old capacity from consist capacity */ - consist_capleft[v_start->cargo_type] -= (v_start->cargo_cap - v_start->cargo.ReservedCount()); - for (Vehicle *w = v_start; w->HasArticulatedPart(); ) { - w = w->GetNextArticulatedPart(); - consist_capleft[w->cargo_type] -= (w->cargo_cap - w->cargo.ReservedCount()); - } - if (is_normal_aircraft) { - consist_capleft[v->Next()->cargo_type] -= (v->Next()->cargo_cap - v->Next()->cargo.ReservedCount()); - } + if (!IterateVehicleParts(v_start, IsEmptyAction())) return; Backup cur_company(_current_company, v->owner, FILE_LINE); - /* Check if all articulated parts are empty and collect refit mask. */ uint32 refit_mask = v->GetEngine()->info.refit_mask; - Vehicle *w = v_start; - while (w->HasArticulatedPart()) { - w = w->GetNextArticulatedPart(); - refit_mask |= EngInfo(w->engine_type)->refit_mask; - } + + /* Remove old capacity from consist capacity and collect refit mask. */ + IterateVehicleParts(v_start, PrepareRefitAction(consist_capleft, refit_mask)); if (new_cid == CT_AUTO_REFIT) { /* Get a refittable cargo type with waiting cargo for next_station or INVALID_STATION. */ @@ -1416,31 +1514,13 @@ static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station /* Refit if given a valid cargo. */ if (new_cid < NUM_CARGO && new_cid != v_start->cargo_type) { - StationID next_one = StationIDStack(next_station).Pop(); - v_start->cargo.Return(UINT_MAX, &st->goods[v_start->cargo_type].cargo, next_one); - for (w = v_start; w->HasArticulatedPart();) { - w = w->GetNextArticulatedPart(); - w->cargo.Return(UINT_MAX, &st->goods[w->cargo_type].cargo, next_one); - } - if (is_normal_aircraft) { - v->Next()->cargo.Return(UINT_MAX, &st->goods[v->Next()->cargo_type].cargo, next_one); - } + IterateVehicleParts(v_start, ReturnCargoAction(st, StationIDStack(next_station).Pop())); CommandCost cost = DoCommand(v_start->tile, v_start->index, new_cid | 1U << 6 | 0xFF << 8 | 1U << 16, DC_EXEC, GetCmdRefitVeh(v_start)); // Auto-refit and only this vehicle including artic parts. if (cost.Succeeded()) v->First()->profit_this_year -= cost.GetCost() << 8; } /* Add new capacity to consist capacity and reserve cargo */ - w = v_start; - do { - st->goods[w->cargo_type].cargo.Reserve(w->cargo_cap - w->cargo.RemainingCount(), &w->cargo, st->xy, next_station); - consist_capleft[w->cargo_type] += w->cargo_cap - w->cargo.RemainingCount(); - w = w->HasArticulatedPart() ? w->GetNextArticulatedPart() : NULL; - } while (w != NULL); - if (is_normal_aircraft) { - w = v->Next(); - st->goods[w->cargo_type].cargo.Reserve(w->cargo_cap - w->cargo.RemainingCount(), &w->cargo, st->xy, next_station); - consist_capleft[w->cargo_type] += w->cargo_cap - w->cargo.RemainingCount(); - } + IterateVehicleParts(v_start, FinalizeRefitAction(consist_capleft, st, next_station)); cur_company.Restore(); } @@ -1572,7 +1652,7 @@ static void LoadUnloadVehicle(Vehicle *front) if (front->current_order.GetLoadType() & OLFB_NO_LOAD || HasBit(front->vehicle_flags, VF_STOP_LOADING)) continue; /* This order has a refit, if this is the first vehicle part carrying cargo and the whole vehicle is empty, try refitting. */ - if (front->current_order.IsRefit() && artic_part == 1 && IsArticulatedVehicleEmpty(v)) { + if (front->current_order.IsRefit() && artic_part == 1) { HandleStationRefit(v, consist_capleft, st, next_station, front->current_order.GetRefitCargo()); ge = &st->goods[v->cargo_type]; } diff --git a/src/saveload/company_sl.cpp b/src/saveload/company_sl.cpp index 5878f31ead..e3d9c090cc 100644 --- a/src/saveload/company_sl.cpp +++ b/src/saveload/company_sl.cpp @@ -256,7 +256,7 @@ static const SaveLoad _company_desc[] = { SLE_VAR(CompanyProperties, colour, SLE_UINT8), SLE_VAR(CompanyProperties, money_fraction, SLE_UINT8), - SLE_CONDVAR(CompanyProperties, avail_railtypes, SLE_UINT8, 0, 57), + SLE_CONDVAR(CompanyProperties, avail_railtypes, SLE_VAR_I32 | SLE_FILE_I8, 0, 57), SLE_VAR(CompanyProperties, block_preview, SLE_UINT8), SLE_CONDNULL(2, 0, 93), ///< cargo_types diff --git a/src/saveload/goal_sl.cpp b/src/saveload/goal_sl.cpp index 1c260503e8..38e92746db 100644 --- a/src/saveload/goal_sl.cpp +++ b/src/saveload/goal_sl.cpp @@ -15,8 +15,8 @@ #include "saveload.h" static const SaveLoad _goals_desc[] = { - SLE_VAR(Goal, company, SLE_UINT16), - SLE_VAR(Goal, type, SLE_UINT16), + SLE_VAR(Goal, company, SLE_FILE_U16 | SLE_VAR_U8), + SLE_VAR(Goal, type, SLE_FILE_U16 | SLE_VAR_U8), SLE_VAR(Goal, dst, SLE_UINT32), SLE_STR(Goal, text, SLE_STR | SLF_ALLOW_CONTROL, 0), SLE_CONDSTR(Goal, progress, SLE_STR | SLF_ALLOW_CONTROL, 0, 182, SL_MAX_VERSION), diff --git a/src/saveload/linkgraph_sl.cpp b/src/saveload/linkgraph_sl.cpp index f0dcb1dd45..119fccd0c5 100644 --- a/src/saveload/linkgraph_sl.cpp +++ b/src/saveload/linkgraph_sl.cpp @@ -21,7 +21,7 @@ typedef LinkGraph::BaseEdge Edge; const SettingDesc *GetSettingDescription(uint index); -static uint _num_nodes; +static uint16 _num_nodes; /** * Get a SaveLoad array for a link graph. diff --git a/src/station_base.h b/src/station_base.h index 1b97b0258c..40bbf585b6 100644 --- a/src/station_base.h +++ b/src/station_base.h @@ -301,7 +301,7 @@ struct Airport : public TileArea { uint64 flags; ///< stores which blocks on the airport are taken. was 16 bit earlier on, then 32 byte type; ///< Type of this airport, @see AirportTypes byte layout; ///< Airport layout number. - Direction rotation; ///< How this airport is rotated. + DirectionByte rotation; ///< How this airport is rotated. PersistentStorage *psa; ///< Persistent storage for NewGRF airports.