diff --git a/aircraft_cmd.c b/aircraft_cmd.c --- a/aircraft_cmd.c +++ b/aircraft_cmd.c @@ -396,6 +396,7 @@ int32 CmdBuildAircraft(TileIndex tile, u w->u.air.state = HRS_ROTOR_STOPPED; VehiclePositionChanged(w); } + GetPlayer(_current_player)->num_engines[p1]++; InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); RebuildVehicleLists(); diff --git a/openttd.c b/openttd.c --- a/openttd.c +++ b/openttd.c @@ -1456,6 +1456,20 @@ bool AfterLoadGame(void) if (!CheckSavegameVersion(27)) AfterLoadStations(); + { + /* Set up the engine count for all players */ + Player *players[MAX_PLAYERS]; + int i; + const Vehicle *v; + + for (i = 0; i < MAX_PLAYERS; i++) players[i] = GetPlayer(i); + + FOR_ALL_VEHICLES(v) { + if (!IsEngineCountable(v)) continue; + players[v->owner]->num_engines[v->engine_type]++; + } + } + /* Time starts at 0 instead of 1920. * Account for this in older games by adding an offset */ if (CheckSavegameVersion(31)) { diff --git a/player.h b/player.h --- a/player.h +++ b/player.h @@ -194,6 +194,7 @@ typedef struct Player { bool renew_keep_length; int16 engine_renew_months; uint32 engine_renew_money; + uint16 num_engines[TOTAL_NUM_ENGINES]; // caches the number of engines of each type the player owns (no need to save this) } Player; uint16 GetDrawStringPlayerColor(PlayerID player); diff --git a/players.c b/players.c --- a/players.c +++ b/players.c @@ -520,6 +520,8 @@ Player *DoStartupNewPlayer(bool is_ai) if (is_ai && (!_networking || _network_server) && _ai.enabled) AI_StartNewAI(p->index); + memset(p->num_engines, 0, TOTAL_NUM_ENGINES); + return p; } diff --git a/roadveh_cmd.c b/roadveh_cmd.c --- a/roadveh_cmd.c +++ b/roadveh_cmd.c @@ -191,6 +191,7 @@ int32 CmdBuildRoadVeh(TileIndex tile, ui v->random_bits = VehicleRandomBits(); VehiclePositionChanged(v); + GetPlayer(_current_player)->num_engines[p1]++; InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); RebuildVehicleLists(); diff --git a/ship_cmd.c b/ship_cmd.c --- a/ship_cmd.c +++ b/ship_cmd.c @@ -914,6 +914,7 @@ int32 CmdBuildShip(TileIndex tile, uint3 v->random_bits = VehicleRandomBits(); VehiclePositionChanged(v); + GetPlayer(_current_player)->num_engines[p1]++; InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); RebuildVehicleLists(); diff --git a/train_cmd.c b/train_cmd.c --- a/train_cmd.c +++ b/train_cmd.c @@ -635,6 +635,7 @@ static int32 CmdBuildRailWagon(EngineID VehiclePositionChanged(v); TrainConsistChanged(GetFirstVehicleInChain(v)); + GetPlayer(_current_player)->num_engines[engine]++; InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); if (IsLocalPlayer()) { @@ -815,6 +816,7 @@ int32 CmdBuildRailVehicle(TileIndex tile NormalizeTrainVehInDepot(v); } + GetPlayer(_current_player)->num_engines[p1]++; InvalidateWindow(WC_VEHICLE_DEPOT, tile); RebuildVehicleLists(); InvalidateWindow(WC_COMPANY, v->owner); diff --git a/vehicle.c b/vehicle.c --- a/vehicle.c +++ b/vehicle.c @@ -535,8 +535,28 @@ uint CountVehiclesInChain(const Vehicle* return count; } +/** Check if a vehicle is counted in num_engines in each player struct + * @param *v Vehicle to test + * @return true if the vehicle is counted in num_engines + */ +bool IsEngineCountable(const Vehicle *v) +{ + switch (v->type) { + case VEH_Aircraft: return (v->subtype <= 2); // don't count plane shadows and helicopter rotors + case VEH_Train: + return !IsArticulatedPart(v) && // tenders and other articulated parts + (!IsMultiheaded(v) || IsTrainEngine(v)); // rear parts of multiheaded engines + case VEH_Road: + case VEH_Ship: + return true; + default: return false; // Only count player buildable vehicles + } +} + void DestroyVehicle(Vehicle *v) { + if (IsEngineCountable(v)) GetPlayer(v->owner)->num_engines[v->engine_type]--; + DeleteVehicleNews(v->index, INVALID_STRING_ID); DeleteName(v->string_id); diff --git a/vehicle.h b/vehicle.h --- a/vehicle.h +++ b/vehicle.h @@ -255,6 +255,7 @@ Vehicle *GetLastVehicleInChain(Vehicle * Vehicle *GetPrevVehicleInChain(const Vehicle *v); Vehicle *GetFirstVehicleInChain(const Vehicle *v); uint CountVehiclesInChain(const Vehicle* v); +bool IsEngineCountable(const Vehicle *v); void DeleteVehicleChain(Vehicle *v); void *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc); void CallVehicleTicks(void); diff --git a/vehicle_gui.c b/vehicle_gui.c --- a/vehicle_gui.c +++ b/vehicle_gui.c @@ -49,7 +49,6 @@ static uint32 _internal_name_sorter_id; static const Vehicle* _last_vehicle; // cached vehicle to hopefully speed up name-sorting static bool _internal_sort_order; // descending/ascending -static uint16 _player_num_engines[TOTAL_NUM_ENGINES]; static RailType _railtype_selected_in_replace_gui; @@ -443,7 +442,7 @@ static void train_engine_drawing_loop(in const RailVehicleInfo *rvi = RailVehInfo(i); const EngineInfo *info = EngInfo(i); - if (!EngineHasReplacementForPlayer(p, i) && _player_num_engines[i] == 0 && show_outdated) continue; + if (!EngineHasReplacementForPlayer(p, i) && p->num_engines[i] == 0 && show_outdated) continue; if ((rvi->power == 0 && !show_cars) || (rvi->power != 0 && show_cars)) // show wagons or engines (works since wagons do not have power) continue; @@ -470,10 +469,10 @@ static void train_engine_drawing_loop(in DrawString(*x + 59, *y + 2, GetCustomEngineName(i), colour); // show_outdated is true only for left side, which is where we show old replacements - DrawTrainEngine(*x + 29, *y + 6, i, (_player_num_engines[i] == 0 && show_outdated) ? + DrawTrainEngine(*x + 29, *y + 6, i, (p->num_engines[i] == 0 && show_outdated) ? PALETTE_CRASH : GetEnginePalette(i, _local_player)); if ( show_outdated ) { - SetDParam(0, _player_num_engines[i]); + SetDParam(0, p->num_engines[i]); DrawStringRightAligned(213, *y+5, STR_TINY_BLACK, 0); } *y += 14; @@ -510,7 +509,7 @@ static void SetupScrollStuffForReplaceWi // left window contains compatible engines while right window only contains engines of the selected type if (ENGINE_AVAILABLE && (RailVehInfo(eid)->power != 0) == (WP(w, replaceveh_d).wagon_btnstate != 0)) { - if (IsCompatibleRail(e->railtype, railtype) && (_player_num_engines[eid] > 0 || EngineHasReplacementForPlayer(p, eid))) { + if (IsCompatibleRail(e->railtype, railtype) && (p->num_engines[eid] > 0 || EngineHasReplacementForPlayer(p, eid))) { if (sel[0] == count) selected_id[0] = eid; count++; } @@ -525,7 +524,7 @@ static void SetupScrollStuffForReplaceWi case VEH_Road: { for (i = ROAD_ENGINES_INDEX; i < ROAD_ENGINES_INDEX + NUM_ROAD_ENGINES; i++) { - if (_player_num_engines[i] > 0 || EngineHasReplacementForPlayer(p, i)) { + if (p->num_engines[i] > 0 || EngineHasReplacementForPlayer(p, i)) { if (sel[0] == count) selected_id[0] = i; count++; } @@ -547,7 +546,7 @@ static void SetupScrollStuffForReplaceWi case VEH_Ship: { for (i = SHIP_ENGINES_INDEX; i < SHIP_ENGINES_INDEX + NUM_SHIP_ENGINES; i++) { - if (_player_num_engines[i] > 0 || EngineHasReplacementForPlayer(p, i)) { + if (p->num_engines[i] > 0 || EngineHasReplacementForPlayer(p, i)) { if (sel[0] == count) selected_id[0] = i; count++; } @@ -573,7 +572,7 @@ static void SetupScrollStuffForReplaceWi case VEH_Aircraft: { for (i = AIRCRAFT_ENGINES_INDEX; i < AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES; i++) { - if (_player_num_engines[i] > 0 || EngineHasReplacementForPlayer(p, i)) { + if (p->num_engines[i] > 0 || EngineHasReplacementForPlayer(p, i)) { if (sel[0] == count) selected_id[0] = i; count++; } @@ -650,11 +649,11 @@ static void DrawEngineArrayInReplaceWind cargo = RoadVehInfo(selected_id[0])->cargo_type; do { - if (_player_num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) { + if (p->num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) { if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) { DrawString(x+59, y+2, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10); - DrawRoadVehEngine(x+29, y+6, engine_id, _player_num_engines[engine_id] > 0 ? GetEnginePalette(engine_id, _local_player) : PALETTE_CRASH); - SetDParam(0, _player_num_engines[engine_id]); + DrawRoadVehEngine(x+29, y+6, engine_id, p->num_engines[engine_id] > 0 ? GetEnginePalette(engine_id, _local_player) : PALETTE_CRASH); + SetDParam(0, p->num_engines[engine_id]); DrawStringRightAligned(213, y+5, STR_TINY_BLACK, 0); y += 14; } @@ -685,11 +684,11 @@ static void DrawEngineArrayInReplaceWind refittable = ShipVehInfo(selected_id[0])->refittable; do { - if (_player_num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) { + if (p->num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) { if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) { DrawString(x+75, y+7, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10); - DrawShipEngine(x+35, y+10, engine_id, _player_num_engines[engine_id] > 0 ? GetEnginePalette(engine_id, _local_player) : PALETTE_CRASH); - SetDParam(0, _player_num_engines[engine_id]); + DrawShipEngine(x+35, y+10, engine_id, p->num_engines[engine_id] > 0 ? GetEnginePalette(engine_id, _local_player) : PALETTE_CRASH); + SetDParam(0, p->num_engines[engine_id]); DrawStringRightAligned(213, y+15, STR_TINY_BLACK, 0); y += 24; } @@ -718,12 +717,12 @@ static void DrawEngineArrayInReplaceWind byte subtype = AircraftVehInfo(selected_id[0])->subtype; do { - if (_player_num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) { + if (p->num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) { if (sel[0] == 0) selected_id[0] = engine_id; if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) { DrawString(x+62, y+7, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10); - DrawAircraftEngine(x+29, y+10, engine_id, _player_num_engines[engine_id] > 0 ? GetEnginePalette(engine_id, _local_player) : PALETTE_CRASH); - SetDParam(0, _player_num_engines[engine_id]); + DrawAircraftEngine(x+29, y+10, engine_id, p->num_engines[engine_id] > 0 ? GetEnginePalette(engine_id, _local_player) : PALETTE_CRASH); + SetDParam(0, p->num_engines[engine_id]); DrawStringRightAligned(213, y+15, STR_TINY_BLACK, 0); y += 24; } @@ -758,7 +757,7 @@ static void ReplaceVehicleWndProc(Window switch (e->event) { case WE_PAINT: { - const Player *p = GetPlayer(_local_player); + Player *p = GetPlayer(_local_player); int pos = w->vscroll.pos; EngineID selected_id[2] = { INVALID_ENGINE, INVALID_ENGINE }; int x = 1; @@ -770,28 +769,6 @@ static void ReplaceVehicleWndProc(Window sel[0] = WP(w,replaceveh_d).sel_index[0]; sel[1] = WP(w,replaceveh_d).sel_index[1]; - { - uint i; - const Vehicle *vehicle; - /* compiler optimisation tend to prefer to keep local variables in the registers instead of global ones, - * so we cache often used and unchanging variables in local variables to increase the loop speed */ - const byte vehicle_type = w->window_number; - const PlayerID player = _local_player; - - for (i = 0; i < lengthof(_player_num_engines); i++) { - _player_num_engines[i] = 0; - } - FOR_ALL_VEHICLES(vehicle) { - if (vehicle->owner == player && vehicle->type == vehicle_type) { - if (vehicle_type == VEH_Aircraft && vehicle->subtype > 2) continue; // plane shadows and helicopter rotors - if (vehicle_type == VEH_Train && ( - IsArticulatedPart(vehicle) || // tenders and other articulated parts - (IsMultiheaded(vehicle) && !IsTrainEngine(vehicle)))) continue; // rear parts of multiheaded engines - _player_num_engines[vehicle->engine_type]++; - } - } - } - SetupScrollStuffForReplaceWindow(w); selected_id[0] = WP(w,replaceveh_d).sel_engine[0];