mirror of https://github.com/OpenTTD/OpenTTD
(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.release/0.4.5
parent
885fd2b15c
commit
752b3f0dd6
8
ai.c
8
ai.c
|
@ -2567,10 +2567,10 @@ static int32 AiDoBuildDefaultRoadBlock(TileIndex tile, const AiDefaultBlockData
|
|||
} else if (p->mode == 1) {
|
||||
if (_want_road_truck_station) {
|
||||
// Truck station
|
||||
r = DoCommandByTile(c, p->attr, 0, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_TRUCK_STATION);
|
||||
r = DoCommandByTile(c, p->attr, RS_TRUCK, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_ROAD_STOP);
|
||||
} else {
|
||||
// Bus station
|
||||
r = DoCommandByTile(c, p->attr, 0, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_BUS_STATION);
|
||||
r = DoCommandByTile(c, p->attr, RS_BUS, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_ROAD_STOP);
|
||||
}
|
||||
clear_town_stuff:;
|
||||
|
||||
|
@ -3627,8 +3627,8 @@ static void AiStateRemoveStation(Player *p)
|
|||
used=in_use;
|
||||
FOR_ALL_STATIONS(st) {
|
||||
if (st->xy != 0 && st->owner == _current_player && !*used &&
|
||||
((tile = st->bus_tile) != 0 ||
|
||||
(tile = st->lorry_tile) != 0 ||
|
||||
( (st->bus_stops != NULL && (tile = st->bus_stops->xy) != 0) ||
|
||||
(st->truck_stops != NULL && (tile = st->truck_stops->xy)) != 0 ||
|
||||
(tile = st->train_tile) != 0 ||
|
||||
(tile = st->dock_tile) != 0 ||
|
||||
(tile = st->airport_tile) != 0)) {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "command.h"
|
||||
#include "ai.h"
|
||||
#include "engine.h"
|
||||
#include "station.h"
|
||||
|
||||
// Build HQ
|
||||
// Params:
|
||||
|
@ -28,9 +29,9 @@ int AiNew_Build_Station(Player *p, byte type, uint tile, byte length, byte numtr
|
|||
if (type == AI_TRAIN)
|
||||
return DoCommandByTile(tile, direction + (numtracks << 8) + (length << 16), 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_RAILROAD_STATION);
|
||||
else if (type == AI_BUS)
|
||||
return DoCommandByTile(tile, direction, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_BUS_STATION);
|
||||
return DoCommandByTile(tile, direction, RS_BUS, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_STOP);
|
||||
else
|
||||
return DoCommandByTile(tile, direction, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_TRUCK_STATION);
|
||||
return DoCommandByTile(tile, direction, RS_TRUCK, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_STOP);
|
||||
}
|
||||
|
||||
// Builds a brdige. The second best out of the ones available for this player
|
||||
|
|
|
@ -37,9 +37,7 @@ DEF_COMMAND(CmdBuildTrainWaypoint);
|
|||
DEF_COMMAND(CmdRenameWaypoint);
|
||||
DEF_COMMAND(CmdRemoveTrainWaypoint);
|
||||
|
||||
DEF_COMMAND(CmdBuildTruckStation);
|
||||
|
||||
DEF_COMMAND(CmdBuildBusStation);
|
||||
DEF_COMMAND(CmdBuildRoadStop);
|
||||
|
||||
DEF_COMMAND(CmdBuildLongRoad);
|
||||
DEF_COMMAND(CmdRemoveLongRoad);
|
||||
|
@ -190,9 +188,9 @@ static CommandProc * const _command_proc_table[] = {
|
|||
CmdBuildTrainWaypoint, /* 16 */
|
||||
CmdRenameWaypoint, /* 17 */
|
||||
CmdRemoveTrainWaypoint, /* 18 */
|
||||
CmdBuildTruckStation, /* 19 */
|
||||
NULL, /* 19 */
|
||||
NULL, /* 20 */
|
||||
CmdBuildBusStation, /* 21 */
|
||||
CmdBuildRoadStop, /* 21 */
|
||||
NULL, /* 22 */
|
||||
CmdBuildLongRoad, /* 23 */
|
||||
CmdRemoveLongRoad, /* 24 */
|
||||
|
|
|
@ -24,8 +24,7 @@ enum {
|
|||
CMD_RENAME_WAYPOINT = 17,
|
||||
CMD_REMOVE_TRAIN_WAYPOINT = 18,
|
||||
|
||||
CMD_BUILD_TRUCK_STATION = 19,
|
||||
CMD_BUILD_BUS_STATION = 21,
|
||||
CMD_BUILD_ROAD_STOP = 21,
|
||||
CMD_BUILD_LONG_ROAD = 23,
|
||||
CMD_REMOVE_LONG_ROAD = 24,
|
||||
CMD_BUILD_ROAD = 25,
|
||||
|
|
|
@ -290,4 +290,5 @@ byte GetOSVersion(void);
|
|||
void DeterminePaths(void);
|
||||
char * CDECL str_fmt(const char *str, ...);
|
||||
|
||||
void bubblesort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));
|
||||
#endif /* FUNCTIONS_H */
|
||||
|
|
|
@ -1616,6 +1616,8 @@ STR_3005_TOO_CLOSE_TO_ANOTHER_RAILROAD :{WHITE}Too close to another railway s
|
|||
STR_3006_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Adjoins more than one existing station/loading area
|
||||
STR_3007_TOO_MANY_STATIONS_LOADING :{WHITE}Too many stations/loading areas in this town
|
||||
STR_3008_TOO_MANY_STATIONS_LOADING :{WHITE}Too many stations/loading areas
|
||||
STR_3008A_TOO_MANY_BUS_STOPS :{WHITE}Too many bus stops
|
||||
STR_3008B_TOO_MANY_TRUCK_STOPS :{WHITE}Too many lorry stations
|
||||
STR_3009_TOO_CLOSE_TO_ANOTHER_STATION :{WHITE}Too close to another station/loading area
|
||||
STR_300A_0 :{WHITE}{STATION} {STRINL 0x30D1}
|
||||
STR_300B_MUST_DEMOLISH_RAILROAD :{WHITE}Must demolish railway station first
|
||||
|
|
29
misc.c
29
misc.c
|
@ -743,6 +743,35 @@ int FindFirstBit(uint32 value)
|
|||
return i;
|
||||
}
|
||||
|
||||
//!We're writing an own sort algorithm here, as
|
||||
//!qsort isn't stable
|
||||
//!Since the number of elements will be low, a
|
||||
//!simple bubble sort will have to do :)
|
||||
|
||||
void bubblesort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *))
|
||||
{
|
||||
uint i,k;
|
||||
void *buffer = malloc(size);
|
||||
char *start = base;
|
||||
|
||||
nmemb--;
|
||||
|
||||
for (i = 0; i < nmemb; i++) {
|
||||
for (k = 0; k < nmemb; k++) {
|
||||
void *a, *b;
|
||||
a = start + size * k;
|
||||
b = start + size * (k + 1);
|
||||
if (compar(a, b) > 0) {
|
||||
memcpy(buffer, a, size);
|
||||
memcpy(a, b, size);
|
||||
memcpy(b, buffer, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
buffer = NULL;
|
||||
}
|
||||
|
||||
static void Save_NAME(void)
|
||||
{
|
||||
|
|
18
oldloader.c
18
oldloader.c
|
@ -711,8 +711,16 @@ static void FixStation(OldStation *o, int num)
|
|||
|
||||
s->xy = o->xy;
|
||||
s->town = REMAP_TOWN_PTR(o->town);
|
||||
s->bus_tile = o->bus_tile;
|
||||
s->lorry_tile = o->lorry_tile;
|
||||
if (o->bus_tile != 0) {
|
||||
s->bus_stops = GetFirstFreeRoadStop();
|
||||
s->bus_stops->xy = o->bus_tile;
|
||||
} else
|
||||
s->bus_stops = NULL;
|
||||
if (o->lorry_tile != 0) {
|
||||
s->truck_stops = GetFirstFreeRoadStop();
|
||||
s->truck_stops->xy = o->lorry_tile;
|
||||
} else
|
||||
s->truck_stops = 0;
|
||||
s->train_tile = o->train_tile;
|
||||
s->airport_tile = o->airport_tile;
|
||||
s->dock_tile = o->dock_tile;
|
||||
|
@ -734,8 +742,10 @@ static void FixStation(OldStation *o, int num)
|
|||
s->owner = o->owner;
|
||||
s->facilities = o->facilities;
|
||||
s->airport_type = o->airport_type;
|
||||
s->truck_stop_status = o->truck_stop_status;
|
||||
s->bus_stop_status = o->bus_stop_status;
|
||||
if (s->truck_stops != NULL)
|
||||
s->truck_stops->status = o->truck_stop_status;
|
||||
if (s->bus_stops != NULL)
|
||||
s->bus_stops->status = o->bus_stop_status;
|
||||
s->blocked_months_obsolete = o->blocked_months_obsolete;
|
||||
s->airport_flags = o->airport_flags;
|
||||
s->last_vehicle = o->last_vehicle;
|
||||
|
|
|
@ -332,6 +332,12 @@ int32 CmdSkipOrder(int x, int y, uint32 flags, uint32 vehicle_id, uint32 not_use
|
|||
|
||||
if (v->type == VEH_Train)
|
||||
v->u.rail.days_since_order_progr = 0;
|
||||
|
||||
if (v->type == VEH_Road && v->u.road.slot != NULL) {
|
||||
//Clear the slot
|
||||
v->u.road.slot->slot[v->u.road.slotindex] = 0;
|
||||
v->u.road.slot = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* NON-stop flag is misused to see if a train is in a station that is
|
||||
|
@ -482,7 +488,7 @@ int32 CmdCloneOrder(int x, int y, uint32 flags, uint32 veh1_veh2, uint32 mode)
|
|||
FOR_VEHICLE_ORDERS(src, order) {
|
||||
if (order->type == OT_GOTO_STATION) {
|
||||
const Station *st = GetStation(order->station);
|
||||
required_dst = (dst->cargo_type == CT_PASSENGERS) ? st->bus_tile : st->lorry_tile;
|
||||
required_dst = (dst->cargo_type == CT_PASSENGERS) ? st->bus_stops->xy : st->truck_stops->xy;
|
||||
/* This station has not the correct road-bay, so we can't copy! */
|
||||
if (!required_dst)
|
||||
return CMD_ERROR;
|
||||
|
|
|
@ -89,12 +89,12 @@ static void PlaceRoad_Depot(uint tile)
|
|||
|
||||
static void PlaceRoad_BusStation(uint tile)
|
||||
{
|
||||
DoCommandP(tile, _road_station_picker_orientation, 0, CcRoadDepot, CMD_BUILD_BUS_STATION | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1808_CAN_T_BUILD_BUS_STATION));
|
||||
DoCommandP(tile, _road_station_picker_orientation, RS_BUS, CcRoadDepot, CMD_BUILD_ROAD_STOP | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1808_CAN_T_BUILD_BUS_STATION));
|
||||
}
|
||||
|
||||
static void PlaceRoad_TruckStation(uint tile)
|
||||
{
|
||||
DoCommandP(tile, _road_station_picker_orientation, 0, CcRoadDepot, CMD_BUILD_TRUCK_STATION | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1809_CAN_T_BUILD_TRUCK_STATION));
|
||||
DoCommandP(tile, _road_station_picker_orientation, RS_TRUCK, CcRoadDepot, CMD_BUILD_ROAD_STOP | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1809_CAN_T_BUILD_TRUCK_STATION));
|
||||
}
|
||||
|
||||
static void PlaceRoad_DemolishArea(uint tile)
|
||||
|
|
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)
|
||||
|
|
11
saveload.c
11
saveload.c
|
@ -7,8 +7,8 @@
|
|||
#include "saveload.h"
|
||||
|
||||
enum {
|
||||
SAVEGAME_MAJOR_VERSION = 5,
|
||||
SAVEGAME_MINOR_VERSION = 2,
|
||||
SAVEGAME_MAJOR_VERSION = 6,
|
||||
SAVEGAME_MINOR_VERSION = 0,
|
||||
|
||||
SAVEGAME_LOADABLE_VERSION = (SAVEGAME_MAJOR_VERSION << 8) + SAVEGAME_MINOR_VERSION
|
||||
};
|
||||
|
@ -918,6 +918,10 @@ static uint ReferenceToInt(void *v, uint t)
|
|||
case REF_TOWN: return ((Town *)v)->index + 1;
|
||||
case REF_ORDER: return ((Order *)v)->index + 1;
|
||||
|
||||
case REF_ROADSTOPS:
|
||||
//return ((byte*)v - (byte*)_roadstops) / sizeof(_roadstops[0]) + 1;
|
||||
return (RoadStop *)v - _roadstops + 1;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
|
@ -942,6 +946,9 @@ static void *IntToReference(uint r, uint t)
|
|||
case REF_STATION: return GetStation(r - 1);
|
||||
case REF_TOWN: return GetTown(r - 1);
|
||||
|
||||
case REF_ROADSTOPS:
|
||||
//return (byte*)_roadstops + (r - 1) * sizeof(_roadstops[0]);
|
||||
return &_roadstops[r - 1];
|
||||
case REF_VEHICLE_OLD: {
|
||||
/* Old vehicles were saved differently: invalid vehicle was 0xFFFF,
|
||||
and the index was not - 1.. correct for this */
|
||||
|
|
|
@ -74,7 +74,8 @@ enum {
|
|||
REF_VEHICLE = 1,
|
||||
REF_STATION = 2,
|
||||
REF_TOWN = 3,
|
||||
REF_VEHICLE_OLD = 4
|
||||
REF_VEHICLE_OLD = 4,
|
||||
REF_ROADSTOPS = 5
|
||||
};
|
||||
|
||||
|
||||
|
@ -151,7 +152,7 @@ enum {
|
|||
#define SLE_VARX(t,c) 0x00 | ((t) & 0xF), (t) >> 4, c
|
||||
#define SLE_REFX(t,c) 0x10 | ((t) & 0xF), (t) >> 4, c
|
||||
#define SLE_CONDVARX(t,c,from,to) 0x40 | ((t) & 0xF), (t) >> 4, c, from, to
|
||||
#define SLE_CONDREFX(t,c,co) 0x50 | ((t) & 0xF), (t) >> 4, c, co
|
||||
#define SLE_CONDREFX(t,c,from,to) 0x50 | ((t) & 0xF), (t) >> 4, c, from, to
|
||||
#define SLE_WRITEBYTEX(t,b) 0x80 | ((t) & 0xF), (t) >> 4, b
|
||||
#define SLE_INCLUDEX(t,c) 0x90 | ((t) & 0xF), (t) >> 4, c
|
||||
|
||||
|
|
47
station.h
47
station.h
|
@ -14,10 +14,32 @@ typedef struct GoodsEntry {
|
|||
byte last_age;
|
||||
} GoodsEntry;
|
||||
|
||||
typedef enum RoadStopType {
|
||||
RS_BUS,
|
||||
RS_TRUCK
|
||||
} RoadStopType;
|
||||
|
||||
enum { NUM_ROAD_STOPS = 250 };
|
||||
enum { ROAD_STOP_LIMIT = 8 };
|
||||
enum { NUM_SLOTS = 2 };
|
||||
enum { INVALID_SLOT = 0xFFFF };
|
||||
|
||||
typedef struct RoadStop {
|
||||
TileIndex xy;
|
||||
bool used;
|
||||
byte status;
|
||||
uint32 index;
|
||||
uint16 slot[NUM_SLOTS];
|
||||
uint16 station; //XXX should be StationIndex
|
||||
uint8 type;
|
||||
struct RoadStop *next;
|
||||
struct RoadStop *prev;
|
||||
} RoadStop;
|
||||
|
||||
struct Station {
|
||||
TileIndex xy;
|
||||
TileIndex bus_tile;
|
||||
TileIndex lorry_tile;
|
||||
RoadStop *bus_stops;
|
||||
RoadStop *truck_stops;
|
||||
TileIndex train_tile;
|
||||
TileIndex airport_tile;
|
||||
TileIndex dock_tile;
|
||||
|
@ -36,9 +58,6 @@ struct Station {
|
|||
byte owner;
|
||||
byte facilities;
|
||||
byte airport_type;
|
||||
byte truck_stop_status;
|
||||
byte bus_stop_status;
|
||||
byte blocked_months_obsolete;
|
||||
|
||||
// trainstation width/height
|
||||
byte trainst_w, trainst_h;
|
||||
|
@ -53,6 +72,14 @@ struct Station {
|
|||
|
||||
VehicleID last_vehicle;
|
||||
GoodsEntry goods[NUM_CARGO];
|
||||
|
||||
/* Stuff that is no longer used, but needed for conversion */
|
||||
TileIndex bus_tile_obsolete;
|
||||
TileIndex lorry_tile_obsolete;
|
||||
|
||||
byte truck_stop_status_obsolete;
|
||||
byte bus_stop_status_obsolete;
|
||||
byte blocked_months_obsolete;
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -68,7 +95,7 @@ enum {
|
|||
HVOT_TRAIN = 1<<1,
|
||||
HVOT_BUS = 1 << 2,
|
||||
HVOT_TRUCK = 1 << 3,
|
||||
HVOT_AIRCRAFT = 1<<4,
|
||||
HVOT_AIRCRAFT = 1 << 4,
|
||||
HVOT_SHIP = 1 << 5,
|
||||
HVOT_BUOY = 1 << 6
|
||||
};
|
||||
|
@ -93,7 +120,9 @@ TileIndex GetStationTileForVehicle(const Vehicle *v, const Station *st);
|
|||
void ShowStationViewWindow(int station);
|
||||
void UpdateAllStationVirtCoord(void);
|
||||
|
||||
VARDEF RoadStop _roadstops[NUM_ROAD_STOPS * 2];
|
||||
VARDEF Station _stations[250];
|
||||
VARDEF uint _roadstops_size;
|
||||
VARDEF uint _stations_size;
|
||||
|
||||
VARDEF SortStruct *_station_sort;
|
||||
|
@ -189,4 +218,10 @@ struct StationSpec *GetCustomStation(enum StationClass sclass, byte stid);
|
|||
uint32 GetCustomStationRelocation(struct StationSpec *spec, struct Station *stat, byte ctype);
|
||||
int GetCustomStationsCount(enum StationClass sclass);
|
||||
|
||||
RoadStop * GetRoadStopByTile(TileIndex tile, RoadStopType type);
|
||||
inline int GetRoadStopType(TileIndex tile);
|
||||
uint GetNumRoadStops(const Station *st, RoadStopType type);
|
||||
RoadStop * GetPrimaryRoadStop(const Station *st, RoadStopType type);
|
||||
RoadStop * GetFirstFreeRoadStop( void );
|
||||
|
||||
#endif /* STATION_H */
|
||||
|
|
458
station_cmd.c
458
station_cmd.c
|
@ -43,14 +43,79 @@ static void MarkStationDirty(Station *st)
|
|||
}
|
||||
}
|
||||
|
||||
static void InitializeRoadStop(RoadStop *road_stop, RoadStop *previous, TileIndex tile, uint index)
|
||||
{
|
||||
road_stop->xy = tile;
|
||||
road_stop->used = true;
|
||||
road_stop->status = 3; //stop is free
|
||||
road_stop->slot[0] = road_stop->slot[1] = INVALID_SLOT;
|
||||
road_stop->next = NULL;
|
||||
road_stop->prev = previous;
|
||||
road_stop->station = index;
|
||||
}
|
||||
|
||||
inline int GetRoadStopType(TileIndex tile)
|
||||
{
|
||||
return (_map5[tile] < 0x47) ? RS_TRUCK : RS_BUS;
|
||||
}
|
||||
|
||||
RoadStop * GetPrimaryRoadStop(const Station *st, RoadStopType type)
|
||||
{
|
||||
switch (type) {
|
||||
case RS_BUS: return st->bus_stops;
|
||||
case RS_TRUCK: return st->truck_stops;
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RoadStop * GetRoadStopByTile(TileIndex tile, RoadStopType type)
|
||||
{
|
||||
const Station *st = GetStation(_map2[tile]);
|
||||
RoadStop *rs;
|
||||
|
||||
for ( rs = GetPrimaryRoadStop(st, type); rs->xy != tile; rs = rs->next)
|
||||
assert(rs->next != NULL);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
uint GetNumRoadStops(const Station *st, RoadStopType type)
|
||||
{
|
||||
int num = 0;
|
||||
const RoadStop *rs;
|
||||
|
||||
assert(st != NULL);
|
||||
for ( rs = GetPrimaryRoadStop(st, type); rs != NULL; num++, rs = rs->next);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
RoadStop * GetFirstFreeRoadStop( void )
|
||||
{
|
||||
RoadStop *rs = _roadstops;
|
||||
int i = 0;
|
||||
|
||||
for ( i = 0; i < NUM_ROAD_STOPS; i++, rs++) {
|
||||
if (!rs->used) {
|
||||
rs->index = i;
|
||||
return rs;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Calculate the radius of the station. Basicly it is the biggest
|
||||
radius that is available within the station */
|
||||
static byte FindCatchmentRadius(Station *st)
|
||||
{
|
||||
byte ret = 0;
|
||||
|
||||
if (st->bus_tile) ret = max(ret, CA_BUS);
|
||||
if (st->lorry_tile) ret = max(ret, CA_TRUCK);
|
||||
if (st->bus_stops != NULL) ret = max(ret, CA_BUS);
|
||||
if (st->truck_stops != NULL) ret = max(ret, CA_TRUCK);
|
||||
if (st->train_tile) ret = max(ret, CA_TRAIN);
|
||||
if (st->dock_tile) ret = max(ret, CA_DOCK);
|
||||
|
||||
|
@ -101,7 +166,7 @@ TileIndex GetStationTileForVehicle(const Vehicle *v, const Station *st)
|
|||
case VEH_Train: return st->train_tile;
|
||||
case VEH_Aircraft: return st->airport_tile;
|
||||
case VEH_Ship: return st->dock_tile;
|
||||
case VEH_Road: return (v->cargo_type == CT_PASSENGERS) ? st->bus_tile : st->lorry_tile;
|
||||
case VEH_Road: return (v->cargo_type == CT_PASSENGERS) ? st->bus_stops->xy : st->truck_stops->xy;
|
||||
default:
|
||||
assert(false);
|
||||
return 0;
|
||||
|
@ -326,7 +391,8 @@ static void StationInitialize(Station *st, TileIndex tile)
|
|||
GoodsEntry *ge;
|
||||
|
||||
st->xy = tile;
|
||||
st->bus_tile = st->lorry_tile = st->airport_tile = st->dock_tile = st->train_tile = 0;
|
||||
st->airport_tile = st->dock_tile = st->train_tile = 0;
|
||||
st->bus_stops = st->truck_stops = NULL;
|
||||
st->had_vehicle_of_type = 0;
|
||||
st->time_since_load = 255;
|
||||
st->time_since_unload = 255;
|
||||
|
@ -352,8 +418,9 @@ static void StationInitialize(Station *st, TileIndex tile)
|
|||
static void UpdateStationVirtCoord(Station *st)
|
||||
{
|
||||
Point pt = RemapCoords2(TileX(st->xy) * 16, TileY(st->xy) * 16);
|
||||
|
||||
pt.y -= 32;
|
||||
if (st->facilities&FACIL_AIRPORT && st->airport_type==AT_OILRIG) pt.y -= 16;
|
||||
if (st->facilities & FACIL_AIRPORT && st->airport_type == AT_OILRIG) pt.y -= 16;
|
||||
|
||||
SetDParam(0, st->index);
|
||||
SetDParam(1, st->facilities);
|
||||
|
@ -498,10 +565,13 @@ void GetAcceptanceAroundTiles(uint *accepts, uint tile, int w, int h, int rad)
|
|||
static void UpdateStationAcceptance(Station *st, bool show_msg)
|
||||
{
|
||||
uint old_acc, new_acc;
|
||||
TileIndex span[1+1+2+2+1];
|
||||
TileIndex *span;
|
||||
RoadStop *cur_rs;
|
||||
int i;
|
||||
int min_x, min_y, max_x, max_y;
|
||||
int rad = 4; //Put this to surpress a compiler warning
|
||||
int num = 0;
|
||||
int num_bus, num_truck;
|
||||
uint accepts[NUM_CARGO];
|
||||
|
||||
// Don't update acceptance for a buoy
|
||||
|
@ -511,33 +581,62 @@ static void UpdateStationAcceptance(Station *st, bool show_msg)
|
|||
/* old accepted goods types */
|
||||
old_acc = GetAcceptanceMask(st);
|
||||
|
||||
if (st->train_tile != 0) num += 2;
|
||||
if (st->airport_tile != 0) num += 2;
|
||||
if (st->dock_tile != 0) num++;
|
||||
|
||||
num_bus = GetNumRoadStops(st, RS_BUS);
|
||||
num_truck = GetNumRoadStops(st, RS_TRUCK);
|
||||
|
||||
num += (num_bus + num_truck);
|
||||
|
||||
span = malloc(num * sizeof(*span));
|
||||
if (span == NULL)
|
||||
error("UpdateStationAcceptance: Could not allocate memory");
|
||||
|
||||
// Put all the tiles that span an area in the table.
|
||||
span[3] = span[5] = 0;
|
||||
span[0] = st->bus_tile;
|
||||
span[1] = st->lorry_tile;
|
||||
span[2] = st->train_tile;
|
||||
if (st->train_tile != 0) {
|
||||
span[3] = st->train_tile + TILE_XY(st->trainst_w-1, st->trainst_h-1);
|
||||
*span++ = st->train_tile;
|
||||
*span++ = st->train_tile + TILE_XY(st->trainst_w-1, st->trainst_h-1);
|
||||
}
|
||||
span[4] = st->airport_tile;
|
||||
|
||||
if (st->airport_tile != 0) {
|
||||
span[5] = st->airport_tile + TILE_XY(_airport_size_x[st->airport_type]-1, _airport_size_y[st->airport_type]-1);
|
||||
*span++ = st->airport_tile;
|
||||
*span++ = st->airport_tile + TILE_XY(_airport_size_x[st->airport_type]-1, _airport_size_y[st->airport_type]-1);
|
||||
}
|
||||
|
||||
if (st->dock_tile != 0)
|
||||
*span++ = st->dock_tile;
|
||||
|
||||
cur_rs = st->bus_stops;
|
||||
for (i = 0; i < num_bus; i++) {
|
||||
*span++ = cur_rs->xy;
|
||||
cur_rs = cur_rs->next;
|
||||
}
|
||||
|
||||
cur_rs = st->truck_stops;
|
||||
for (i = 0; i < num_truck; i++) {
|
||||
*span++ = cur_rs->xy;
|
||||
cur_rs = cur_rs->next;
|
||||
}
|
||||
span[6] = st->dock_tile;
|
||||
|
||||
// Construct a rectangle from those points
|
||||
min_x = min_y = 0x7FFFFFFF;
|
||||
max_x = max_y = 0;
|
||||
|
||||
for(i=0; i!=7; i++) {
|
||||
uint tile = span[i];
|
||||
if (tile) {
|
||||
for(; num != 0; num--) {
|
||||
TileIndex tile = *(--span);
|
||||
if (tile != 0) { //assume there is no station at (0, 0)
|
||||
min_x = min(min_x, TileX(tile));
|
||||
max_x = max(max_x, TileX(tile));
|
||||
min_y = min(min_y, TileY(tile));
|
||||
max_y = max(max_y, TileY(tile));
|
||||
}
|
||||
}
|
||||
|
||||
free(span);
|
||||
span = NULL;
|
||||
|
||||
if (_patches.modified_catchment) {
|
||||
rad = FindCatchmentRadius(st);
|
||||
} else {
|
||||
|
@ -546,7 +645,7 @@ static void UpdateStationAcceptance(Station *st, bool show_msg)
|
|||
|
||||
// And retrieve the acceptance.
|
||||
if (max_x != 0) {
|
||||
GetAcceptanceAroundTiles(accepts, TILE_XY(min_x, min_y), max_x - min_x + 1, max_y-min_y+1,rad);
|
||||
GetAcceptanceAroundTiles(accepts, TILE_XY(min_x, min_y), max_x - min_x + 1, max_y-min_y+1, rad);
|
||||
} else {
|
||||
memset(accepts, 0, sizeof(accepts));
|
||||
}
|
||||
|
@ -1127,10 +1226,10 @@ ResolveStationSpriteGroup(struct SpriteGroup *spritegroup, struct Station *stat)
|
|||
value = stat->airport_type;
|
||||
break;
|
||||
case 0x82:
|
||||
value = stat->truck_stop_status;
|
||||
value = stat->truck_stops->status;
|
||||
break;
|
||||
case 0x83:
|
||||
value = stat->bus_stop_status;
|
||||
value = stat->bus_stops->status;
|
||||
break;
|
||||
case 0x86:
|
||||
value = stat->airport_flags & 0xFFFF;
|
||||
|
@ -1260,16 +1359,47 @@ int32 DoConvertStationRail(uint tile, uint totype, bool exec)
|
|||
return _price.build_rail >> 1;
|
||||
}
|
||||
|
||||
void FindRoadStationSpot(bool truck_station, Station *st, RoadStop ***currstop, RoadStop **prev)
|
||||
{
|
||||
RoadStop **primary_stop;
|
||||
|
||||
primary_stop = (truck_station) ? &st->truck_stops : &st->bus_stops;
|
||||
|
||||
if (*primary_stop == NULL) {
|
||||
//we have no station of the type yet, so write a "primary station"
|
||||
//(the one at st->foo_stops)
|
||||
*currstop = primary_stop;
|
||||
} else {
|
||||
//there are stops already, so append to the end of the list
|
||||
*prev = *primary_stop;
|
||||
*currstop = &(*primary_stop)->next;
|
||||
while (**currstop != NULL) {
|
||||
*prev = (*prev)->next;
|
||||
*currstop = &(**currstop)->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Build a bus station
|
||||
* p1 - direction
|
||||
* p2 - unused
|
||||
* direction - direction of the stop exit
|
||||
* type - 0 for Bus stops, 1 for truck stops
|
||||
*/
|
||||
|
||||
int32 CmdBuildBusStation(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
||||
int32 CmdBuildRoadStop(int x, int y, uint32 flags, uint32 direction, uint32 type)
|
||||
{
|
||||
RoadStop *road_stop;
|
||||
RoadStop **currstop;
|
||||
RoadStop *prev = NULL;
|
||||
uint tile;
|
||||
int32 cost;
|
||||
Station *st;
|
||||
//Bus stops have a _map5 value of 0x47 + direction
|
||||
//Truck stops have 0x43 + direction
|
||||
byte gfxbase = (type) ? 0x43 : 0x47;
|
||||
|
||||
//saveguard the parameters
|
||||
if (direction > 3 || type > 1)
|
||||
return CMD_ERROR;
|
||||
|
||||
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
|
||||
|
||||
|
@ -1278,7 +1408,8 @@ int32 CmdBuildBusStation(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
|||
if (!(flags & DC_NO_TOWN_RATING) && !CheckIfAuthorityAllows(tile))
|
||||
return CMD_ERROR;
|
||||
|
||||
if ((cost=CheckFlatLandBelow(tile, 1, 1, flags, 1 << p1, NULL)) == CMD_ERROR)
|
||||
cost = CheckFlatLandBelow(tile, 1, 1, flags, 1 << direction, NULL);
|
||||
if (cost == CMD_ERROR)
|
||||
return CMD_ERROR;
|
||||
|
||||
st = GetStationAround(tile, 1, 1, -1);
|
||||
|
@ -1291,6 +1422,14 @@ int32 CmdBuildBusStation(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
|||
if (st!=NULL && st->facilities) st = NULL;
|
||||
}
|
||||
|
||||
//give us a road stop in the list, and check if something went wrong
|
||||
road_stop = GetFirstFreeRoadStop();
|
||||
if (road_stop == NULL)
|
||||
return_cmd_error( (type) ? STR_3008B_TOO_MANY_TRUCK_STOPS : STR_3008A_TOO_MANY_BUS_STOPS);
|
||||
|
||||
if ( st != NULL && (GetNumRoadStops(st, RS_BUS) + GetNumRoadStops(st, RS_TRUCK) >= ROAD_STOP_LIMIT))
|
||||
return_cmd_error( (type) ? STR_3008B_TOO_MANY_TRUCK_STOPS : STR_3008A_TOO_MANY_BUS_STOPS);
|
||||
|
||||
if (st != NULL) {
|
||||
if (st->owner != OWNER_NONE && st->owner != _current_player)
|
||||
return_cmd_error(STR_3009_TOO_CLOSE_TO_ANOTHER_STATION);
|
||||
|
@ -1298,8 +1437,7 @@ int32 CmdBuildBusStation(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
|||
if (!CheckStationSpreadOut(st, tile, 1, 1))
|
||||
return CMD_ERROR;
|
||||
|
||||
if (st->bus_tile != 0)
|
||||
return_cmd_error(STR_3044_TOO_CLOSE_TO_ANOTHER_BUS);
|
||||
FindRoadStationSpot(type, st, &currstop, &prev);
|
||||
} else {
|
||||
Town *t;
|
||||
|
||||
|
@ -1309,6 +1447,8 @@ int32 CmdBuildBusStation(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
|||
|
||||
st->town = t = ClosestTownFromTile(tile, (uint)-1);
|
||||
|
||||
FindRoadStationSpot(type, st, &currstop, &prev);
|
||||
|
||||
if (_current_player < MAX_PLAYERS && flags&DC_EXEC)
|
||||
SETBIT(t->have_ratings, _current_player);
|
||||
|
||||
|
@ -1321,13 +1461,17 @@ int32 CmdBuildBusStation(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
|||
StationInitialize(st, tile);
|
||||
}
|
||||
|
||||
cost += _price.build_bus_station;
|
||||
cost += (type) ? _price.build_truck_station : _price.build_bus_station;
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
st->bus_tile = tile;
|
||||
//point to the correct item in the _busstops or _truckstops array
|
||||
*currstop = road_stop;
|
||||
|
||||
//initialize an empty station
|
||||
InitializeRoadStop(road_stop, prev, tile, st->index);
|
||||
(*currstop)->type = type;
|
||||
if (!st->facilities) st->xy = tile;
|
||||
st->facilities |= FACIL_BUS_STOP;
|
||||
st->bus_stop_status = 3;
|
||||
st->facilities |= (type) ? FACIL_TRUCK_STOP : FACIL_BUS_STOP;
|
||||
st->owner = _current_player;
|
||||
|
||||
st->build_date = _date;
|
||||
|
@ -1336,7 +1480,7 @@ int32 CmdBuildBusStation(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
|||
MP_SETTYPE(MP_STATION) | MP_MAPOWNER_CURRENT |
|
||||
MP_MAP2 | MP_MAP5 | MP_MAP3LO_CLEAR | MP_MAP3HI_CLEAR,
|
||||
st->index, /* map2 parameter */
|
||||
p1 + 0x47 /* map5 parameter */
|
||||
gfxbase + direction /* map5 parameter */
|
||||
);
|
||||
|
||||
UpdateStationVirtCoordDirty(st);
|
||||
|
@ -1347,126 +1491,24 @@ int32 CmdBuildBusStation(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
|||
}
|
||||
|
||||
// Remove a bus station
|
||||
static int32 RemoveBusStation(Station *st, uint32 flags)
|
||||
static int32 RemoveRoadStop(Station *st, uint32 flags, TileIndex tile)
|
||||
{
|
||||
uint tile;
|
||||
RoadStop **primary_stop;
|
||||
RoadStop *cur_stop;
|
||||
bool is_truck = _map5[tile] < 0x47;
|
||||
|
||||
if (_current_player != OWNER_WATER && !CheckOwnership(st->owner))
|
||||
return CMD_ERROR;
|
||||
|
||||
tile = st->bus_tile;
|
||||
|
||||
if (!EnsureNoVehicle(tile))
|
||||
return CMD_ERROR;
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
DoClearSquare(tile);
|
||||
|
||||
st->bus_tile = 0;
|
||||
st->facilities &= ~FACIL_BUS_STOP;
|
||||
|
||||
UpdateStationVirtCoordDirty(st);
|
||||
DeleteStationIfEmpty(st);
|
||||
}
|
||||
|
||||
return _price.remove_bus_station;
|
||||
}
|
||||
|
||||
|
||||
/* Build a truck station
|
||||
* p1 - direction
|
||||
* p2 - unused
|
||||
*/
|
||||
int32 CmdBuildTruckStation(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
||||
{
|
||||
uint tile;
|
||||
int32 cost = 0;
|
||||
Station *st;
|
||||
|
||||
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
|
||||
|
||||
tile = TILE_FROM_XY(x,y);
|
||||
|
||||
if (!(flags & DC_NO_TOWN_RATING) && !CheckIfAuthorityAllows(tile))
|
||||
return CMD_ERROR;
|
||||
|
||||
if ((cost=CheckFlatLandBelow(tile, 1, 1, flags, 1 << p1, NULL)) == CMD_ERROR)
|
||||
return CMD_ERROR;
|
||||
|
||||
st = GetStationAround(tile, 1, 1, -1);
|
||||
if (st == CHECK_STATIONS_ERR)
|
||||
return CMD_ERROR;
|
||||
|
||||
/* Find a station close to us */
|
||||
if (st == NULL) {
|
||||
st = GetClosestStationFromTile(tile, 8, _current_player);
|
||||
if (st!=NULL && st->facilities) st = NULL;
|
||||
}
|
||||
|
||||
if (st != NULL) {
|
||||
if (st->owner != OWNER_NONE && st->owner != _current_player)
|
||||
return_cmd_error(STR_3009_TOO_CLOSE_TO_ANOTHER_STATION);
|
||||
|
||||
if (!CheckStationSpreadOut(st, tile, 1, 1))
|
||||
return CMD_ERROR;
|
||||
|
||||
if (st->lorry_tile != 0)
|
||||
return_cmd_error(STR_3045_TOO_CLOSE_TO_ANOTHER_TRUCK);
|
||||
if (is_truck) { //truck stop
|
||||
primary_stop = &st->truck_stops;
|
||||
cur_stop = GetRoadStopByTile(tile, RS_TRUCK);
|
||||
} else {
|
||||
Town *t;
|
||||
|
||||
st = AllocateStation();
|
||||
if (st == NULL)
|
||||
return CMD_ERROR;
|
||||
|
||||
st->town = t = ClosestTownFromTile(tile, (uint)-1);
|
||||
|
||||
if (_current_player < MAX_PLAYERS && flags&DC_EXEC)
|
||||
SETBIT(t->have_ratings, _current_player);
|
||||
|
||||
st->sign.width_1 = 0;
|
||||
|
||||
if (!GenerateStationName(st, tile, 0))
|
||||
return CMD_ERROR;
|
||||
|
||||
if (flags & DC_EXEC)
|
||||
StationInitialize(st, tile);
|
||||
primary_stop = &st->bus_stops;
|
||||
cur_stop = GetRoadStopByTile(tile, RS_BUS);
|
||||
}
|
||||
|
||||
cost += _price.build_truck_station;
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
st->lorry_tile = tile;
|
||||
if (!st->facilities) st->xy = tile;
|
||||
st->facilities |= FACIL_TRUCK_STOP;
|
||||
st->truck_stop_status = 3;
|
||||
st->owner = _current_player;
|
||||
|
||||
st->build_date = _date;
|
||||
|
||||
ModifyTile(tile,
|
||||
MP_SETTYPE(MP_STATION) | MP_MAPOWNER_CURRENT |
|
||||
MP_MAP2 | MP_MAP3LO_CLEAR | MP_MAP3HI_CLEAR | MP_MAP5,
|
||||
st->index, /* map2 parameter */
|
||||
p1 + 0x43 /* map5 parameter */
|
||||
);
|
||||
|
||||
UpdateStationVirtCoordDirty(st);
|
||||
UpdateStationAcceptance(st, false);
|
||||
InvalidateWindow(WC_STATION_LIST, st->owner);
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
||||
// Remove a truck station
|
||||
static int32 RemoveTruckStation(Station *st, uint32 flags)
|
||||
{
|
||||
uint tile;
|
||||
|
||||
if (_current_player != OWNER_WATER && !CheckOwnership(st->owner))
|
||||
return CMD_ERROR;
|
||||
|
||||
tile = st->lorry_tile;
|
||||
assert(cur_stop != NULL);
|
||||
|
||||
if (!EnsureNoVehicle(tile))
|
||||
return CMD_ERROR;
|
||||
|
@ -1474,16 +1516,35 @@ static int32 RemoveTruckStation(Station *st, uint32 flags)
|
|||
if (flags & DC_EXEC) {
|
||||
DoClearSquare(tile);
|
||||
|
||||
st->lorry_tile = 0;
|
||||
st->facilities &= ~FACIL_TRUCK_STOP;
|
||||
cur_stop->used = false;
|
||||
if (cur_stop->prev != NULL) //alter previous stop
|
||||
cur_stop->prev->next = cur_stop->next;
|
||||
|
||||
if (cur_stop->next != NULL) //alter next stop
|
||||
cur_stop->next->prev = cur_stop->prev;
|
||||
|
||||
//we only had one stop left
|
||||
if (cur_stop->next == NULL && cur_stop->prev == NULL) {
|
||||
|
||||
//so we remove ALL stops
|
||||
*primary_stop = NULL;
|
||||
st->facilities &= (is_truck) ? ~FACIL_TRUCK_STOP : ~FACIL_BUS_STOP;
|
||||
|
||||
} else if (cur_stop == *primary_stop) {
|
||||
//removed the first stop in the list
|
||||
//need to set the primary element to the next stop
|
||||
*primary_stop = (*primary_stop)->next;
|
||||
}
|
||||
|
||||
UpdateStationVirtCoordDirty(st);
|
||||
DeleteStationIfEmpty(st);
|
||||
}
|
||||
|
||||
return _price.remove_truck_station;
|
||||
return (is_truck) ? _price.remove_truck_station : _price.remove_bus_station;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// FIXME -- need to move to its corresponding Airport variable
|
||||
// Country Airfield (small)
|
||||
static const byte _airport_map5_tiles_country[] = {
|
||||
|
@ -2215,7 +2276,7 @@ static const byte _enter_station_speedtable[12] = {
|
|||
|
||||
static uint32 VehicleEnter_Station(Vehicle *v, uint tile, int x, int y)
|
||||
{
|
||||
uint16 station_id;
|
||||
uint16 station_id; //XXX should be stationindex
|
||||
byte dir;
|
||||
uint16 spd;
|
||||
|
||||
|
@ -2252,12 +2313,12 @@ static uint32 VehicleEnter_Station(Vehicle *v, uint tile, int x, int y)
|
|||
}
|
||||
} else if (v->type == VEH_Road) {
|
||||
if (v->u.road.state < 16 && (v->u.road.state&4)==0 && v->u.road.frame==0) {
|
||||
Station *st = GetStation(_map2[tile]);
|
||||
byte m5 = _map5[tile];
|
||||
byte *b, bb,state;
|
||||
|
||||
if (IS_BYTE_INSIDE(m5, 0x43, 0x4B)) {
|
||||
b = (m5 >= 0x47) ? &st->bus_stop_status : &st->truck_stop_status;
|
||||
RoadStop *rs = GetRoadStopByTile(tile, GetRoadStopType(tile));
|
||||
b = &rs->status;
|
||||
|
||||
bb = *b;
|
||||
|
||||
|
@ -2275,6 +2336,8 @@ static uint32 VehicleEnter_Station(Vehicle *v, uint tile, int x, int y)
|
|||
bb &= ~2;
|
||||
state += 2;
|
||||
}
|
||||
|
||||
bb |= 0x80;
|
||||
*b = bb;
|
||||
v->u.road.state = state;
|
||||
}
|
||||
|
@ -2625,7 +2688,8 @@ uint MoveGoodsToStation(uint tile, int w, int h, int type, uint amount)
|
|||
/* several stations around, find the two with the highest rating */
|
||||
st2 = st1 = NULL;
|
||||
best_rating = best_rating2 = 0;
|
||||
for(i=0; i!=8 && around[i] != 0xFF; i++) {
|
||||
|
||||
for( i = 0; i != 8 && around[i] != 0xFF; i++) {
|
||||
if (around_ptr[i]->goods[type].rating >= best_rating) {
|
||||
best_rating2 = best_rating;
|
||||
st2 = st1;
|
||||
|
@ -2686,8 +2750,8 @@ void BuildOilRig(uint tile)
|
|||
st->airport_flags = 0;
|
||||
st->airport_type = AT_OILRIG;
|
||||
st->xy = tile;
|
||||
st->bus_tile = 0;
|
||||
st->lorry_tile = 0;
|
||||
st->bus_stops = NULL;
|
||||
st->truck_stops = NULL;
|
||||
st->airport_tile = tile;
|
||||
st->dock_tile = tile;
|
||||
st->train_tile = 0;
|
||||
|
@ -2768,11 +2832,8 @@ static int32 ClearTile_Station(uint tile, byte flags) {
|
|||
if (m5 < 0x43 || ( m5 >= 83 && m5 <= 114) )
|
||||
return RemoveAirport(st, flags);
|
||||
|
||||
if (m5 < 0x47)
|
||||
return RemoveTruckStation(st, flags);
|
||||
|
||||
if (m5 < 0x4B)
|
||||
return RemoveBusStation(st, flags);
|
||||
return RemoveRoadStop(st, flags, tile);
|
||||
|
||||
if (m5 == 0x52)
|
||||
return RemoveBuoy(st, flags);
|
||||
|
@ -2789,6 +2850,7 @@ void InitializeStations(void)
|
|||
int i;
|
||||
Station *s;
|
||||
|
||||
memset(_roadstops, 0, sizeof(_roadstops));
|
||||
memset(_stations, 0, sizeof(_stations[0]) * _stations_size);
|
||||
|
||||
i = 0;
|
||||
|
@ -2820,14 +2882,27 @@ const TileTypeProcs _tile_type_station_procs = {
|
|||
GetSlopeTileh_Station, /* get_slope_tileh_proc */
|
||||
};
|
||||
|
||||
static const byte _roadstop_desc[] = {
|
||||
SLE_VAR(RoadStop,xy, SLE_UINT32),
|
||||
SLE_VAR(RoadStop,used, SLE_UINT8),
|
||||
SLE_VAR(RoadStop,status, SLE_UINT8),
|
||||
SLE_VAR(RoadStop,index, SLE_UINT32),
|
||||
SLE_VAR(RoadStop,station, SLE_UINT16),
|
||||
SLE_VAR(RoadStop,type, SLE_UINT8),
|
||||
|
||||
SLE_REF(RoadStop,next, REF_ROADSTOPS),
|
||||
SLE_REF(RoadStop,prev, REF_ROADSTOPS),
|
||||
|
||||
SLE_ARR(RoadStop,slot, SLE_UINT16, NUM_SLOTS),
|
||||
|
||||
SLE_END()
|
||||
};
|
||||
|
||||
static const byte _station_desc[] = {
|
||||
SLE_CONDVAR(Station, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
|
||||
SLE_CONDVAR(Station, xy, SLE_UINT32, 6, 255),
|
||||
SLE_CONDVAR(Station, bus_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
|
||||
SLE_CONDVAR(Station, bus_tile, SLE_UINT32, 6, 255),
|
||||
SLE_CONDVAR(Station, lorry_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
|
||||
SLE_CONDVAR(Station, lorry_tile, SLE_UINT32, 6, 255),
|
||||
SLE_CONDVAR(Station, bus_tile_obsolete, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
|
||||
SLE_CONDVAR(Station, lorry_tile_obsolete, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
|
||||
SLE_CONDVAR(Station, train_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
|
||||
SLE_CONDVAR(Station, train_tile, SLE_UINT32, 6, 255),
|
||||
SLE_CONDVAR(Station, airport_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
|
||||
|
@ -2850,8 +2925,10 @@ static const byte _station_desc[] = {
|
|||
SLE_VAR(Station,owner, SLE_UINT8),
|
||||
SLE_VAR(Station,facilities, SLE_UINT8),
|
||||
SLE_VAR(Station,airport_type, SLE_UINT8),
|
||||
SLE_VAR(Station,truck_stop_status, SLE_UINT8),
|
||||
SLE_VAR(Station,bus_stop_status, SLE_UINT8),
|
||||
|
||||
// truck/bus_stop_status was stored here in savegame format 0 - 6
|
||||
SLE_CONDVAR(Station,truck_stop_status_obsolete, SLE_UINT8, 0, 5),
|
||||
SLE_CONDVAR(Station,bus_stop_status_obsolete, SLE_UINT8, 0, 5),
|
||||
|
||||
// blocked_months was stored here in savegame format 0 - 4.0
|
||||
SLE_CONDVAR(Station,blocked_months_obsolete, SLE_UINT8, 0, 4),
|
||||
|
@ -2865,7 +2942,10 @@ static const byte _station_desc[] = {
|
|||
SLE_CONDVAR(Station,stat_id, SLE_UINT8, 3, 255),
|
||||
SLE_CONDVAR(Station,build_date, SLE_UINT16, 3, 255),
|
||||
|
||||
// reserve extra space in savegame here. (currently 32 bytes)
|
||||
SLE_CONDREF(Station,bus_stops, REF_ROADSTOPS, 6, 255),
|
||||
SLE_CONDREF(Station,truck_stops, REF_ROADSTOPS, 6, 255),
|
||||
|
||||
// reserve extra space in savegame here. (currently 28 bytes)
|
||||
SLE_CONDARR(NullStruct,null,SLE_FILE_U8 | SLE_VAR_NULL, 32, 2, 255),
|
||||
|
||||
SLE_END()
|
||||
|
@ -2887,8 +2967,9 @@ static const byte _goods_desc[] = {
|
|||
static void SaveLoad_STNS(Station *st)
|
||||
{
|
||||
int i;
|
||||
|
||||
SlObject(st, _station_desc);
|
||||
for(i=0; i!=NUM_CARGO; i++)
|
||||
for (i = 0; i != NUM_CARGO; i++)
|
||||
SlObject(&st->goods[i], _goods_desc);
|
||||
}
|
||||
|
||||
|
@ -2920,6 +3001,32 @@ static void Load_STNS(void)
|
|||
st->trainst_w = w;
|
||||
st->trainst_h = h;
|
||||
}
|
||||
|
||||
if (_sl.full_version < 0x600) {
|
||||
/* Convert old bus and truck tile to new-ones */
|
||||
RoadStop **currstop;
|
||||
RoadStop *prev = NULL;
|
||||
RoadStop *road_stop;
|
||||
|
||||
if (st->bus_tile_obsolete != 0) {
|
||||
road_stop = GetFirstFreeRoadStop();
|
||||
if (road_stop == NULL)
|
||||
error("Station: too many busstations in savegame");
|
||||
|
||||
FindRoadStationSpot(RS_BUS, st, &currstop, &prev);
|
||||
*currstop = road_stop;
|
||||
InitializeRoadStop(road_stop, prev, st->bus_tile_obsolete, st->index);
|
||||
}
|
||||
if (st->lorry_tile_obsolete != 0) {
|
||||
road_stop = GetFirstFreeRoadStop();
|
||||
if (road_stop == NULL)
|
||||
error("Station: too many truckstations in savegame");
|
||||
|
||||
FindRoadStationSpot(RS_TRUCK, st, &currstop, &prev);
|
||||
*currstop = road_stop;
|
||||
InitializeRoadStop(road_stop, prev, st->lorry_tile_obsolete, st->index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This is to ensure all pointers are within the limits of
|
||||
|
@ -2928,7 +3035,28 @@ static void Load_STNS(void)
|
|||
_station_tick_ctr = 0;
|
||||
}
|
||||
|
||||
static void Save_ROADSTOP( void )
|
||||
{
|
||||
uint i;
|
||||
|
||||
for (i = 0; i < lengthof(_roadstops); i++) {
|
||||
if (_roadstops[i].used) {
|
||||
SlSetArrayIndex(i);
|
||||
SlObject(&_roadstops[i], _roadstop_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_ROADSTOP( void )
|
||||
{
|
||||
int index;
|
||||
|
||||
while ((index = SlIterateArray()) != -1)
|
||||
SlObject(&_roadstops[index], _roadstop_desc);
|
||||
}
|
||||
|
||||
const ChunkHandler _station_chunk_handlers[] = {
|
||||
{ 'STNS', Save_STNS, Load_STNS, CH_ARRAY | CH_LAST},
|
||||
{ 'STNS', Save_STNS, Load_STNS, CH_ARRAY },
|
||||
{ 'ROAD', Save_ROADSTOP, Load_ROADSTOP, CH_ARRAY | CH_LAST},
|
||||
};
|
||||
|
||||
|
|
2
ttd.c
2
ttd.c
|
@ -496,6 +496,8 @@ static void InitializeDynamicVariables(void)
|
|||
_stations_size = lengthof(_stations);
|
||||
_station_sort = NULL;
|
||||
|
||||
_roadstops_size = lengthof(_roadstops);
|
||||
|
||||
_vehicles_size = lengthof(_vehicles);
|
||||
_vehicle_sort = NULL;
|
||||
|
||||
|
|
|
@ -1886,6 +1886,9 @@ static const byte _roadveh_desc[] = {
|
|||
SLE_VARX(offsetof(Vehicle,u)+offsetof(VehicleRoad,crashed_ctr), SLE_UINT16),
|
||||
SLE_VARX(offsetof(Vehicle,u)+offsetof(VehicleRoad,reverse_ctr), SLE_UINT8),
|
||||
|
||||
SLE_CONDREFX(offsetof(Vehicle,u)+offsetof(VehicleRoad,slot), REF_ROADSTOPS, 6, 255),
|
||||
SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRoad,slotindex), SLE_UINT8, 6, 255),
|
||||
SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRoad,slot_age), SLE_UINT8, 6, 255),
|
||||
// reserve extra space in savegame here. (currently 16 bytes)
|
||||
SLE_CONDARR(NullStruct,null,SLE_FILE_U64 | SLE_VAR_NULL, 2, 2, 255),
|
||||
|
||||
|
|
Loading…
Reference in New Issue