summaryrefslogtreecommitdiff
path: root/roadveh_cmd.c
diff options
context:
space:
mode:
authorcelestar <celestar@openttd.org>2005-01-29 19:41:44 +0000
committercelestar <celestar@openttd.org>2005-01-29 19:41:44 +0000
commit752b3f0dd614217d68f361e2d0b2cc599a37c860 (patch)
treefcefcecfa2ec7dd8e9178d5206788bd62dcf3c53 /roadveh_cmd.c
parent885fd2b15c1ae9a1422f82b8bcdd9d1a287c3aa6 (diff)
downloadopenttd-752b3f0dd614217d68f361e2d0b2cc599a37c860.tar.xz
(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.
Diffstat (limited to 'roadveh_cmd.c')
-rw-r--r--roadveh_cmd.c190
1 files changed, 171 insertions, 19 deletions
diff --git a/roadveh_cmd.c b/roadveh_cmd.c
index 9e34c797f..445530008 100644
--- a/roadveh_cmd.c
+++ b/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)