(svn r1721) -Feature: It is now possible to build multiple road stations (up to 8) on
a single station. Thanks to: Truelight for the saveload code, Darkvater and Hackykid for network testing and Tron for proof-reading 1500 lines of diff.
This commit is contained in:
190
roadveh_cmd.c
190
roadveh_cmd.c
@@ -164,6 +164,10 @@ int32 CmdBuildRoadVeh(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
||||
// 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 = 0xFFFF;
|
||||
v->max_speed = rvi->max_speed;
|
||||
v->engine_type = (byte)p1;
|
||||
@@ -409,10 +413,10 @@ static void UpdateRoadVehDeltaXY(Vehicle *v)
|
||||
static void ClearCrashedStation(Vehicle *v)
|
||||
{
|
||||
uint tile = v->tile;
|
||||
Station *st = GetStation(_map2[tile]);
|
||||
byte *b, bb;
|
||||
|
||||
b = (_map5[tile] >= 0x47) ? &st->bus_stop_status : &st->truck_stop_status;
|
||||
RoadStop *rs = GetRoadStopByTile(tile, GetRoadStopType(tile));
|
||||
b = &rs->status;
|
||||
|
||||
bb = *b;
|
||||
|
||||
@@ -607,9 +611,34 @@ static void ProcessRoadVehOrder(Vehicle *v)
|
||||
if (order->type == OT_GOTO_STATION) {
|
||||
if (order->station == v->last_station_visited)
|
||||
v->last_station_visited = 0xFFFF;
|
||||
|
||||
st = GetStation(order->station);
|
||||
v->dest_tile = v->cargo_type == CT_PASSENGERS ? st->bus_tile : st->lorry_tile;
|
||||
|
||||
{
|
||||
int32 *dist;
|
||||
int32 mindist = 0xFFFFFFFF;
|
||||
int num;
|
||||
RoadStopType type;
|
||||
RoadStop *rs;
|
||||
|
||||
type = (v->cargo_type == CT_PASSENGERS) ? RS_BUS : RS_TRUCK;
|
||||
num = GetNumRoadStops(st, type);
|
||||
rs = GetPrimaryRoadStop(st, type);
|
||||
|
||||
assert (rs != NULL);
|
||||
|
||||
dist = malloc(num * sizeof(int32));
|
||||
|
||||
do {
|
||||
*dist = GetTileDistAdv(v->tile, rs->xy);
|
||||
if (*dist < mindist) {
|
||||
v->dest_tile = rs->xy;
|
||||
}
|
||||
rs = rs->next;
|
||||
} while ( rs != NULL );
|
||||
|
||||
free(dist);
|
||||
dist = NULL;
|
||||
}
|
||||
} else if (order->type == OT_GOTO_DEPOT) {
|
||||
v->dest_tile = _depots[order->station].xy;
|
||||
}
|
||||
@@ -990,10 +1019,10 @@ static int RoadFindPathToDest(Vehicle *v, uint tile, int direction)
|
||||
Station *st = GetStation(_map2[tile]);
|
||||
byte val = _map5[tile];
|
||||
if (v->cargo_type != CT_PASSENGERS) {
|
||||
if (IS_BYTE_INSIDE(val, 0x43, 0x47) && (_patches.roadveh_queue || st->truck_stop_status&3))
|
||||
if (IS_BYTE_INSIDE(val, 0x43, 0x47) && (_patches.roadveh_queue || st->truck_stops->status&3))
|
||||
bitmask |= _road_veh_fp_ax_or[(val-0x43)&3];
|
||||
} else {
|
||||
if (IS_BYTE_INSIDE(val, 0x47, 0x4B) && (_patches.roadveh_queue || st->bus_stop_status&3))
|
||||
if (IS_BYTE_INSIDE(val, 0x47, 0x4B) && (_patches.roadveh_queue || st->bus_stops->status&3))
|
||||
bitmask |= _road_veh_fp_ax_or[(val-0x47)&3];
|
||||
}
|
||||
}
|
||||
@@ -1073,6 +1102,29 @@ found_best_track:;
|
||||
return best_track;
|
||||
}
|
||||
|
||||
static int RoadFindPathToStation(const Vehicle *v, TileIndex tile)
|
||||
{
|
||||
FindRoadToChooseData frd;
|
||||
int i, best_track = -1;
|
||||
uint best_dist = (uint) -1, best_maxlen = (uint) -1;
|
||||
|
||||
frd.dest = tile;
|
||||
frd.maxtracklen = (uint) -1;
|
||||
frd.mindist = (uint) -1;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
FollowTrack(v->tile, 0x2000 | TRANSPORT_ROAD, i, (TPFEnumProc*)EnumRoadTrackFindDist, NULL, &frd);
|
||||
|
||||
if (frd.mindist < best_dist || (frd.mindist == best_dist && frd.maxtracklen < best_maxlen )) {
|
||||
best_dist = frd.mindist;
|
||||
best_maxlen = frd.maxtracklen;
|
||||
best_track = i;
|
||||
}
|
||||
}
|
||||
return best_maxlen;
|
||||
}
|
||||
|
||||
|
||||
typedef struct RoadDriveEntry {
|
||||
byte x,y;
|
||||
} RoadDriveEntry;
|
||||
@@ -1088,6 +1140,13 @@ static const byte _road_veh_data_1[] = {
|
||||
|
||||
static const byte _roadveh_data_2[4] = { 0,1,8,9 };
|
||||
|
||||
static inline void ClearSlot(Vehicle *v, RoadStop *rs)
|
||||
{
|
||||
v->u.road.slot = NULL;
|
||||
v->u.road.slot_age = 0;
|
||||
rs->slot[v->u.road.slotindex] = INVALID_SLOT;
|
||||
}
|
||||
|
||||
static void RoadVehEventHandler(Vehicle *v)
|
||||
{
|
||||
GetNewVehiclePosResult gp;
|
||||
@@ -1247,15 +1306,12 @@ again:
|
||||
if (IS_BYTE_INSIDE(v->u.road.state, 0x20, 0x30) && IsTileType(v->tile, MP_STATION)) {
|
||||
if ((tmp&7) >= 6) { v->cur_speed = 0; return; }
|
||||
if (IS_BYTE_INSIDE(_map5[v->tile], 0x43, 0x4B)) {
|
||||
Station *st = GetStation(_map2[v->tile]);
|
||||
byte *b;
|
||||
RoadStop *rs = GetRoadStopByTile(v->tile, GetRoadStopType(v->tile));
|
||||
byte *b = &rs->status;
|
||||
|
||||
if (_map5[v->tile] >= 0x47) {
|
||||
b = &st->bus_stop_status;
|
||||
} else {
|
||||
b = &st->truck_stop_status;
|
||||
}
|
||||
*b = (*b | ((v->u.road.state&2)?2:1)) & 0x7F;
|
||||
//we have reached a loading bay, mark it as used
|
||||
//and clear the usage bit (0x80) of the stop
|
||||
*b = (*b | ((v->u.road.state&2)?2:1)) & ~0x80;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1341,10 +1397,10 @@ again:
|
||||
|
||||
if (v->u.road.state >= 0x20 &&
|
||||
_road_veh_data_1[v->u.road.state - 0x20 + (_opt.road_side<<4)] == v->u.road.frame) {
|
||||
byte *b;
|
||||
RoadStop *rs = GetRoadStopByTile(v->tile, GetRoadStopType(v->tile));
|
||||
byte *b = &rs->status;
|
||||
|
||||
st = GetStation(_map2[v->tile]);
|
||||
b = IS_BYTE_INSIDE(_map5[v->tile], 0x43, 0x47) ? &st->truck_stop_status : &st->bus_stop_status;
|
||||
|
||||
if (v->current_order.type != OT_LEAVESTATION &&
|
||||
v->current_order.type != OT_GOTO_DEPOT) {
|
||||
@@ -1385,6 +1441,17 @@ again:
|
||||
}
|
||||
*b |= 0x80;
|
||||
|
||||
if (rs == v->u.road.slot) {
|
||||
//we have arrived at the correct station
|
||||
ClearSlot(v, rs);
|
||||
} else if (v->u.road.slot != NULL) {
|
||||
//we have arrived at the wrong station
|
||||
//XXX The question is .. what to do? Actually we shouldn't be here
|
||||
//but I guess we need to clear the slot
|
||||
DEBUG(misc, 2) ("Multistop: Wrong station, force a slot clearing");
|
||||
ClearSlot(v, rs);
|
||||
}
|
||||
|
||||
StartRoadVehSound(v);
|
||||
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
|
||||
}
|
||||
@@ -1482,6 +1549,10 @@ static void CheckIfRoadVehNeedsService(Vehicle *v)
|
||||
(v->current_order.flags & (OF_FULL_LOAD | OF_UNLOAD)) != 0)
|
||||
return;
|
||||
|
||||
//If we already got a slot at a stop, use that FIRST, and go to a depot later
|
||||
if (v->u.road.slot != NULL)
|
||||
return;
|
||||
|
||||
i = FindClosestRoadDepot(v);
|
||||
|
||||
if (i < 0 || GetTileDist(v->tile, (&_depots[i])->xy) > 12) {
|
||||
@@ -1508,11 +1579,15 @@ static void CheckIfRoadVehNeedsService(Vehicle *v)
|
||||
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
|
||||
}
|
||||
|
||||
int dist_compare(const void *a, const void *b)
|
||||
{
|
||||
return ( *(const uint32 *)a) - ( *(const uint32 *) b);
|
||||
}
|
||||
|
||||
void OnNewDay_RoadVeh(Vehicle *v)
|
||||
{
|
||||
int32 cost;
|
||||
Station *st;
|
||||
uint tile;
|
||||
|
||||
if ((++v->day_counter & 7) == 0)
|
||||
DecreaseVehicleValue(v);
|
||||
@@ -1527,9 +1602,86 @@ void OnNewDay_RoadVeh(Vehicle *v)
|
||||
|
||||
/* update destination */
|
||||
if (v->current_order.type == OT_GOTO_STATION) {
|
||||
RoadStop *rs;
|
||||
uint32 mindist = 0xFFFFFFFF;
|
||||
int num;
|
||||
RoadStopType type = (v->cargo_type == CT_PASSENGERS) ? RS_BUS : RS_TRUCK;
|
||||
|
||||
typedef struct {
|
||||
uint32 dist;
|
||||
RoadStop *rs;
|
||||
} StopStruct;
|
||||
|
||||
StopStruct *stop, *firststop;
|
||||
|
||||
st = GetStation(v->current_order.station);
|
||||
if ((tile=(v->cargo_type==CT_PASSENGERS ? st->bus_tile : st->lorry_tile)) != 0)
|
||||
v->dest_tile = tile;
|
||||
rs = GetPrimaryRoadStop(st, type);
|
||||
num = GetNumRoadStops(st, type);
|
||||
|
||||
firststop = stop = malloc(num * sizeof(StopStruct));
|
||||
|
||||
//Current slot has expired
|
||||
if ( (v->u.road.slot_age++ <= 0) && (v->u.road.slot != NULL)) {
|
||||
ClearSlot(v, v->u.road.slot);
|
||||
}
|
||||
|
||||
//We do not have a slot, so make one
|
||||
if (v->u.road.slot == NULL) {
|
||||
//first we need to find out how far our stations are away.
|
||||
assert( rs != NULL);
|
||||
|
||||
do {
|
||||
stop->dist = 0xFFFFFFFF;
|
||||
|
||||
//FIXME This doesn't fully work yet, as it only goes
|
||||
//to one tile BEFORE the stop in question and doesn't
|
||||
//regard the direction of the exit
|
||||
stop->dist = RoadFindPathToStation(v, rs->xy);
|
||||
stop->rs = rs;
|
||||
|
||||
if (stop->dist < mindist) {
|
||||
mindist = stop->dist;
|
||||
}
|
||||
|
||||
stop++;
|
||||
rs = rs->next;
|
||||
} while (rs != NULL);
|
||||
|
||||
if (mindist < 120) { //if we're reasonably close, get us a slot
|
||||
int k;
|
||||
bubblesort(firststop, num, sizeof(StopStruct), dist_compare);
|
||||
|
||||
stop = firststop;
|
||||
for (k = 0; k < num; k++) {
|
||||
int i;
|
||||
for (i = 0; i < NUM_SLOTS; i++) {
|
||||
if ((stop->rs->slot[i] == INVALID_SLOT) && (stop->dist < 120)) {
|
||||
|
||||
//Hooray we found a free slot. Assign it
|
||||
stop->rs->slot[i] = v->index;
|
||||
v->u.road.slot = stop->rs;
|
||||
|
||||
v->dest_tile = stop->rs->xy;
|
||||
v->u.road.slot_age = -30;
|
||||
v->u.road.slotindex = i;
|
||||
|
||||
goto have_slot; //jump out of BOTH loops
|
||||
|
||||
}
|
||||
}
|
||||
stop++;
|
||||
}
|
||||
}
|
||||
|
||||
have_slot:
|
||||
//now we couldn't assign a slot for one reason or another.
|
||||
//so we just go to the nearest station
|
||||
if (v->u.road.slot == NULL)
|
||||
v->dest_tile = firststop->rs->xy;
|
||||
}
|
||||
|
||||
free(firststop);
|
||||
firststop = stop = NULL;
|
||||
}
|
||||
|
||||
if (v->vehstatus & VS_STOPPED)
|
||||
|
||||
Reference in New Issue
Block a user