Index: station_cmd.c =================================================================== --- station_cmd.c (revision 4143) +++ station_cmd.c (working copy) @@ -87,15 +87,14 @@ static void InitializeRoadStop(RoadStop *road_stop, RoadStop *previous, TileIndex tile, StationID index) { - int i; road_stop->xy = tile; road_stop->used = true; road_stop->status = 3; //stop is free road_stop->next = NULL; road_stop->prev = previous; road_stop->station = index; - - for (i = 0; i < NUM_SLOTS; i++) road_stop->slot[i] = INVALID_VEHICLE; + road_stop->num_vehicles = 0; + road_stop->num_bays = 2; } RoadStop* GetPrimaryRoadStop(const Station* st, RoadStopType type) @@ -1412,17 +1411,8 @@ if (!EnsureNoVehicle(tile)) return CMD_ERROR; if (flags & DC_EXEC) { - uint i; DoClearSquare(tile); - /* Clear all vehicles destined for this station */ - for (i = 0; i != NUM_SLOTS; i++) { - if (cur_stop->slot[i] != INVALID_VEHICLE) { - Vehicle *v = GetVehicle(cur_stop->slot[i]); - ClearSlot(v); - } - } - cur_stop->used = false; if (cur_stop->prev != NULL) cur_stop->prev->next = cur_stop->next; if (cur_stop->next != NULL) cur_stop->next->prev = cur_stop->prev; @@ -2257,27 +2247,6 @@ } } -static void CheckOrphanedSlots(const Station *st, RoadStopType rst) -{ - RoadStop *rs; - uint k; - - for (rs = GetPrimaryRoadStop(st, rst); rs != NULL; rs = rs->next) { - for (k = 0; k < NUM_SLOTS; k++) { - if (rs->slot[k] != INVALID_VEHICLE) { - const Vehicle *v = GetVehicle(rs->slot[k]); - - if (v->type != VEH_Road || v->u.road.slot != rs) { - DEBUG(ms, 0) ( - "Multistop: Orphaned %s slot at 0x%X of station %d (don't panic)", - (rst == RS_BUS) ? "bus" : "truck", rs->xy, st->index); - rs->slot[k] = INVALID_VEHICLE; - } - } - } - } -} - /* this function is called for one station each tick */ static void StationHandleBigTick(Station *st) { @@ -2285,9 +2254,6 @@ if (st->facilities == 0 && ++st->delete_ctr >= 8) DeleteStation(st); - // Here we saveguard against orphaned slots - CheckOrphanedSlots(st, RS_BUS); - CheckOrphanedSlots(st, RS_TRUCK); } static inline void byte_inc_sat(byte *p) { byte b = *p + 1; if (b != 0) *p = b; } @@ -2786,7 +2752,8 @@ SLE_REF(RoadStop,next, REF_ROADSTOPS), SLE_REF(RoadStop,prev, REF_ROADSTOPS), - SLE_ARR(RoadStop,slot, SLE_UINT16, NUM_SLOTS), + SLE_CONDNULL(4, 0, 23), + SLE_CONDVAR(RoadStop, num_vehicles, SLE_UINT8, 24, SL_MAX_VERSION), SLE_END() }; @@ -2955,7 +2922,9 @@ error("RoadStops: failed loading savegame: too many RoadStops"); rs = GetRoadStop(index); + rs->num_vehicles = 0; SlObject(rs, _roadstop_desc); + rs->num_bays = 2; } } Index: oldloader.c =================================================================== --- oldloader.c (revision 4143) +++ oldloader.c (working copy) @@ -356,7 +356,6 @@ static void FixOldStations(void) { Station *st; - int i; FOR_ALL_STATIONS(st) { /* Check if we need to swap width and height for the station */ @@ -373,7 +372,8 @@ st->bus_stops->station = st->index; st->bus_stops->next = NULL; st->bus_stops->prev = NULL; - for (i = 0; i < NUM_SLOTS; i++) st->bus_stops->slot[i] = INVALID_VEHICLE; + st->bus_stops->num_bays = 2; + st->bus_stops->num_vehicles = 0; } if (st->lorry_tile_obsolete != 0) { @@ -384,7 +384,8 @@ st->truck_stops->station = st->index; st->truck_stops->next = NULL; st->truck_stops->prev = NULL; - for (i = 0; i < NUM_SLOTS; i++) st->truck_stops->slot[i] = INVALID_VEHICLE; + st->truck_stops->num_bays = 2; + st->truck_stops->num_vehicles = 0; } } } Index: lang/english.txt =================================================================== --- lang/english.txt (revision 4143) +++ lang/english.txt (working copy) @@ -2491,7 +2491,6 @@ STR_8861_STOPPED :{RED}Stopped STR_8862_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Can't make train pass signal at danger... STR_8863_CRASHED :{RED}Crashed! -STR_8864_WAIT_FOR_SLOT :{YELLOW}Waiting for a free stop STR_8865_NAME_TRAIN :{WHITE}Name train STR_8866_CAN_T_NAME_TRAIN :{WHITE}Can't name train... Index: roadveh_cmd.c =================================================================== --- roadveh_cmd.c (revision 4143) +++ roadveh_cmd.c (working copy) @@ -164,10 +164,6 @@ // v->u.road.unk2 = 0; // v->u.road.overtaking = 0; - v->u.road.slot = NULL; - v->u.road.slotindex = 0; - v->u.road.slot_age = 0; - v->last_station_visited = INVALID_STATION; v->max_speed = rvi->max_speed; v->engine_type = (byte)p1; @@ -238,10 +234,11 @@ v->u.road.slot = NULL; v->u.road.slot_age = 0; - // check that the slot is indeed assigned to the same vehicle - assert(rs->slot[v->u.road.slotindex] == v->index); - rs->slot[v->u.road.slotindex] = INVALID_VEHICLE; - DEBUG(ms, 3) ("Multistop: Clearing slot %d at 0x%x", v->u.road.slotindex, rs->xy); + //on saveload, we might not yet have the new slotting system, so num_vehicles might be zero before + //this, yet a vehicle leaves. Compensate + if (rs->num_vehicles > 0) rs->num_vehicles--; + + DEBUG(ms, 3) ("Multistop: Clearing slot at 0x%x", rs->xy); } /** Sell a road vehicle. @@ -382,7 +379,6 @@ if (flags & DC_EXEC) { ClearSlot(v); - v->vehstatus &= ~VS_WAIT_FOR_SLOT; v->current_order.type = OT_GOTO_DEPOT; v->current_order.flags = OF_NON_STOP | OF_HALT_IN_DEPOT; v->current_order.station = dep->index; @@ -408,7 +404,7 @@ if (v->type != VEH_Road || !CheckOwnership(v->owner)) return CMD_ERROR; - if (v->vehstatus & (VS_HIDDEN | VS_STOPPED | VS_WAIT_FOR_SLOT) || + if (v->vehstatus & (VS_HIDDEN | VS_STOPPED) || v->u.road.crashed_ctr != 0 || v->breakdown_ctr != 0 || v->u.road.overtaking != 0 || @@ -633,7 +629,6 @@ v->current_order.flags = 0; v->dest_tile = 0; ClearSlot(v); - v->vehstatus &= ~VS_WAIT_FOR_SLOT; return; } @@ -645,8 +640,6 @@ v->current_order = *order; v->dest_tile = 0; - /* We have changed the destination STATION, so resume movement */ - v->vehstatus &= ~VS_WAIT_FOR_SLOT; if (order->type == OT_GOTO_STATION) { const Station* st = GetStation(order->station); @@ -907,7 +900,7 @@ od.u = u; if (u->max_speed >= v->max_speed && - !(u->vehstatus & (VS_STOPPED | VS_WAIT_FOR_SLOT)) && + !(u->vehstatus & VS_STOPPED) && u->cur_speed != 0) { return; } @@ -929,7 +922,7 @@ od.tile = v->tile + TileOffsByDir(DirToDiagDir(v->direction)); if (FindRoadVehToOvertake(&od)) return; - if (od.u->cur_speed == 0 || od.u->vehstatus& (VS_STOPPED | VS_WAIT_FOR_SLOT)) { + if (od.u->cur_speed == 0 || od.u->vehstatus& VS_STOPPED) { v->u.road.overtaking_ctr = 0x11; v->u.road.overtaking = 0x10; } else { @@ -1191,7 +1184,7 @@ v->breakdown_ctr--; } - if (v->vehstatus & (VS_STOPPED | VS_WAIT_FOR_SLOT)) return; + if (v->vehstatus & VS_STOPPED) return; ProcessRoadVehOrder(v); HandleRoadVehLoading(v); @@ -1454,7 +1447,6 @@ v->current_order.type = OT_NOTHING; v->current_order.flags = 0; ClearSlot(v); - v->vehstatus &= ~VS_WAIT_FOR_SLOT; } SETBIT(rs->status, 7); @@ -1560,7 +1552,7 @@ if (_patches.servint_roadveh == 0) return; if (!VehicleNeedsService(v)) return; - if (v->vehstatus & (VS_STOPPED | VS_WAIT_FOR_SLOT)) return; + if (v->vehstatus & VS_STOPPED) return; if (_patches.gotodepot && VehicleHasDepotOrders(v)) return; // Don't interfere with a depot visit scheduled by the user, or a @@ -1596,6 +1588,18 @@ InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); } +static uint RoadFindPathToStop(const Vehicle *v, TileIndex tile) +{ + NPFFindStationOrTileData fstd; + byte trackdir = GetVehicleTrackdir(v); + assert(trackdir != 0xFF); + + fstd.dest_coords = tile; + fstd.station_index = -1; // indicates that the destination is a tile, not a station + + return NPFRouteToStationOrTile(v->tile, trackdir, &fstd, TRANSPORT_ROAD, v->owner, INVALID_RAILTYPE).best_path_dist; +} + void OnNewDay_RoadVeh(Vehicle *v) { int32 cost; @@ -1610,83 +1614,61 @@ CheckOrders(v); //Current slot has expired - if (v->u.road.slot_age-- == 0 && v->u.road.slot != NULL) { - DEBUG(ms, 2) ("Multistop: Slot %d expired for vehicle %d (index %d) at stop 0x%x", - v->u.road.slotindex, v->unitnumber, v->index, v->u.road.slot->xy - ); + if (v->current_order.type == OT_GOTO_STATION && v->u.road.slot_age-- == 0 && v->u.road.slot != NULL) { + DEBUG(ms, 2) ("Multistop: Slot expired for vehicle %d (index %d) at stop 0x%x", + v->unitnumber, v->index, v->u.road.slot->xy); ClearSlot(v); } if (v->vehstatus & VS_STOPPED) return; /* update destination */ - if (v->current_order.type == OT_GOTO_STATION && - v->u.road.slot == NULL && - !IsLevelCrossing(v->tile) && - v->u.road.overtaking == 0 && - !(v->vehstatus & VS_CRASHED)) { + if (v->current_order.type == OT_GOTO_STATION && v->u.road.slot == NULL && !(v->vehstatus & VS_CRASHED)) { RoadStopType type = (v->cargo_type == CT_PASSENGERS) ? RS_BUS : RS_TRUCK; RoadStop *rs; - uint mindist = 0xFFFFFFFF; - int i; - RoadStop *nearest = NULL; + RoadStop *best = NULL; st = GetStation(v->current_order.station); rs = GetPrimaryRoadStop(st, type); if (rs != NULL) { if (DistanceManhattan(v->tile, st->xy) < 16) { - int new_slot = -1; + uint vehicles; + uint dist; + uint minbadness = 0xFFFFFFFF; + uint badness; DEBUG(ms, 2) ("Multistop: Attempting to obtain a slot for vehicle %d (index %d) at station %d (0x%x)", v->unitnumber, v->index, st->index, st->xy); /* Now we find the nearest road stop that has a free slot */ - for (i = 0; rs != NULL; rs = rs->next, i++) { - uint dist = 0xFFFFFFFF; - bool is_slot_free = false; - int k; - int last_free = -1; - - for (k = 0; k < NUM_SLOTS; k++) - if (rs->slot[k] == INVALID_VEHICLE) { - is_slot_free = true; - last_free = k; - dist = DistanceManhattan(v->tile, st->xy); - break; - } - - if (!is_slot_free) { - DEBUG(ms, 4) ("Multistop: ---- stop %d is full", i); + for (; rs != NULL; rs = rs->next) { + dist = RoadFindPathToStop(v, rs->xy); + if (dist == 0xFFFFFFFF) { + DEBUG(ms, 4) (" ---- stop 0x%x is not reachable", rs->xy); + DEBUG(ms, 4) (" -- Badness MAX"); continue; } + vehicles = rs->num_vehicles + 1; + badness = vehicles * vehicles + dist / 100; - DEBUG(ms, 4) ("Multistop: ---- distance to stop %d is %d", i, dist); - if (dist < mindist) { - nearest = rs; - mindist = dist; - new_slot = last_free; + DEBUG(ms, 4) (" ---- stop 0x%x has %d vehicle%s waiting", rs->xy, rs->num_vehicles, rs->num_vehicles == 1 ? "":"s"); + DEBUG(ms, 4) (" ---- Distance is %u", dist); + DEBUG(ms, 4) (" -- Badness %u", badness); + + if (badness < minbadness) { + best = rs; + minbadness = badness; } } - if (nearest != NULL) { /* We have a suitable stop */ - DEBUG(ms, 3) ("Multistop: -- Slot %d of stop at 0x%x assinged.", new_slot, nearest->xy); - nearest->slot[new_slot] = v->index; + if (best != NULL) { + best->num_vehicles++; + DEBUG(ms, 3) (" -- Assigned to stop 0x%x", best->xy); - v->u.road.slot = nearest; - v->dest_tile = nearest->xy; + v->u.road.slot = best; + v->dest_tile = best->xy; v->u.road.slot_age = 14; - v->u.road.slotindex = new_slot; - - if (v->vehstatus & VS_WAIT_FOR_SLOT) { - DEBUG(ms, 4) ("Multistop: ---- stopped vehicle got a slot. resuming movement"); - v->vehstatus &= ~VS_WAIT_FOR_SLOT; - InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); - } - } else { - DEBUG(ms, 2) ("Multistop -- No free slot at station. Waiting"); - v->vehstatus |= VS_WAIT_FOR_SLOT; - InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); - } + } else DEBUG(ms, 3) (" -- Could not find a suitable stop"); } else { DEBUG(ms, 5) ("Multistop: --- Distance from station too far. Postponing slotting for vehicle %d (index %d) at station %d, (0x%x)", v->unitnumber, v->index, st->index, st->xy); Index: openttd.c =================================================================== --- openttd.c (revision 4143) +++ openttd.c (working copy) @@ -1317,6 +1317,13 @@ if (CheckSavegameVersion(22)) UpdatePatches(); + if (CheckSavegameVersion(23)) { + Vehicle *v; + FOR_ALL_VEHICLES(v) { + if (v->type == VEH_Road) v->vehstatus &= ~0x40; + } + } + FOR_ALL_PLAYERS(p) p->avail_railtypes = GetPlayerRailtypes(p->index); return true; Index: vehicle.c =================================================================== --- vehicle.c (revision 4143) +++ vehicle.c (working copy) @@ -2194,7 +2194,7 @@ SLE_VARX(offsetof(Vehicle,u)+offsetof(VehicleRoad,reverse_ctr), SLE_UINT8), SLE_CONDREFX(offsetof(Vehicle,u)+offsetof(VehicleRoad,slot), REF_ROADSTOPS, 6, SL_MAX_VERSION), - SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRoad,slotindex), SLE_UINT8, 6, SL_MAX_VERSION), + SLE_CONDNULL(1, 6, SL_MAX_VERSION), SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRoad,slot_age), SLE_UINT8, 6, SL_MAX_VERSION), // reserve extra space in savegame here. (currently 16 bytes) SLE_CONDNULL(16, 2, SL_MAX_VERSION), Index: vehicle.h =================================================================== --- vehicle.h (revision 4143) +++ vehicle.h (working copy) @@ -24,7 +24,6 @@ VS_TRAIN_SLOWING = 0x10, VS_DISASTER = 0x20, VS_AIRCRAFT_BROKEN = 0x40, - VS_WAIT_FOR_SLOT = 0x40, VS_CRASHED = 0x80, }; @@ -110,7 +109,6 @@ uint16 crashed_ctr; byte reverse_ctr; struct RoadStop *slot; - byte slotindex; byte slot_age; } VehicleRoad; Index: roadveh_gui.c =================================================================== --- roadveh_gui.c (revision 4143) +++ roadveh_gui.c (working copy) @@ -247,8 +247,6 @@ str = STR_885C_BROKEN_DOWN; } else if (v->vehstatus & VS_STOPPED) { str = STR_8861_STOPPED; - } else if (v->vehstatus & VS_WAIT_FOR_SLOT) { - str = STR_8864_WAIT_FOR_SLOT; } else { switch (v->current_order.type) { case OT_GOTO_STATION: { Index: station.h =================================================================== --- station.h (revision 4143) +++ station.h (working copy) @@ -28,7 +28,6 @@ enum { INVALID_STATION = 0xFFFF, - NUM_SLOTS = 2, ROAD_STOP_LIMIT = 16, }; @@ -37,7 +36,8 @@ bool used; byte status; uint32 index; - VehicleID slot[NUM_SLOTS]; + byte num_vehicles; + byte num_bays; StationID station; uint8 type; struct RoadStop *next; Index: console_cmds.c =================================================================== --- console_cmds.c (revision 4143) +++ console_cmds.c (working copy) @@ -92,30 +92,6 @@ IConsolePrintF(_icolour_warn, "- %s", str); } -DEF_CONSOLE_CMD(ConResetSlots) -{ - Vehicle *v; - RoadStop *rs; - if (argc == 0) { - IConsoleHelp("Resets all slots in the game. For debugging only. Usage: 'clearslots'"); - return true; - } - - FOR_ALL_VEHICLES(v) { - if (IsValidVehicle(v)) { - if (v->type == VEH_Road) - ClearSlot(v); - } - } - - FOR_ALL_ROADSTOPS(rs) { - int i; - for (i = 0; i < NUM_SLOTS; i++) rs->slot[i] = INVALID_VEHICLE; - } - - return true; -} - DEF_CONSOLE_CMD(ConStopAllVehicles) { Vehicle* v; @@ -1389,7 +1365,6 @@ IConsoleCmdRegister("cd", ConChangeDirectory); IConsoleCmdRegister("pwd", ConPrintWorkingDirectory); IConsoleCmdRegister("clear", ConClearBuffer); - IConsoleCmdRegister("clearslots", ConResetSlots); IConsoleCmdRegister("stopall", ConStopAllVehicles); IConsoleAliasRegister("dir", "ls");