mirror of https://github.com/OpenTTD/OpenTTD.git
(svn r10280) [0.5] -Backport from trunk (r10109, r10219, r10222, r10230, r10246, r10258):
- Fix: Do not look in every direction for tunnels when building one, one direction is enough (r10258) - Fix: Take the age of the front vehicle for station rating (r10246) - Fix: Terraforming wipes out canals. Now you always have to remove the canal before terraforming, instead of "just" removing the canal [FS#594] (r10240) - Fix: Only 2 trains could crash at one time as collision checking stopped on the first hit. This could technically cause desyncs in network games as the collision hash order is not guaranteed [FS#892] (r10222) - Fix: Land under foundations was terraform when it shouldn't be terraformed [FS#882, FS#890] (r10219) - Fix: Some NewGRFs use the same (unused in the "current" climate) sprite IDs. Normally this gives some artefacts, but when one NewGRF expects it to be a sprite and another NewGRF overwrites it with a non-sprite nasty things happen (drawing a non-sprite crashes OTTD) [FS#838] (r10109)
This commit is contained in:
parent
79a7bf75a0
commit
7fff0a71f2
10
clear_cmd.c
10
clear_cmd.c
|
@ -17,6 +17,7 @@
|
|||
#include "unmovable_map.h"
|
||||
#include "genworld.h"
|
||||
#include "industry.h"
|
||||
#include "water_map.h"
|
||||
|
||||
typedef struct TerraformerHeightMod {
|
||||
TileIndex tile;
|
||||
|
@ -111,7 +112,7 @@ static int TerraformProc(TerraformerState *ts, TileIndex tile, int mode)
|
|||
// basement and then you raise/lower the other corner.
|
||||
tileh = GetTileSlope(tile, &z);
|
||||
if (tileh == unsafe_slope[mode] ||
|
||||
tileh == ComplementSlope(unsafe_slope[mode])) {
|
||||
tileh == (SLOPE_STEEP | ComplementSlope(unsafe_slope[mode]))) {
|
||||
_terraform_err_tile = tile;
|
||||
_error_message = STR_1008_MUST_REMOVE_RAILROAD_TRACK;
|
||||
return -1;
|
||||
|
@ -136,6 +137,13 @@ static int TerraformProc(TerraformerState *ts, TileIndex tile, int mode)
|
|||
}
|
||||
}
|
||||
|
||||
/* Canals can't be terraformed */
|
||||
if (IsClearWaterTile(tile) && IsCanal(tile)) {
|
||||
_terraform_err_tile = tile;
|
||||
_error_message = STR_MUST_DEMOLISH_CANAL_FIRST;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = DoCommand(tile, 0,0, ts->flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
|
||||
|
||||
if (CmdFailed(ret)) {
|
||||
|
|
|
@ -1468,7 +1468,7 @@ int LoadUnloadVehicle(Vehicle *v, bool just_arrived)
|
|||
|
||||
// if last speed is 0, we treat that as if no vehicle has ever visited the station.
|
||||
ge->last_speed = min(t, 255);
|
||||
ge->last_age = _cur_year - v->build_year;
|
||||
ge->last_age = _cur_year - u->build_year;
|
||||
|
||||
// If there's goods waiting at the station, and the vehicle
|
||||
// has capacity for it, load it on the vehicle.
|
||||
|
|
|
@ -1801,6 +1801,7 @@ STR_3804_WATER :Water
|
|||
STR_3805_COAST_OR_RIVERBANK :Coast or riverbank
|
||||
STR_3806_SHIP_DEPOT :Ship depot
|
||||
STR_3807_CAN_T_BUILD_ON_WATER :{WHITE}...Can't build on water
|
||||
STR_MUST_DEMOLISH_CANAL_FIRST :{WHITE}Must demolish canal first
|
||||
|
||||
##id 0x4000
|
||||
STR_4000_SAVE_GAME :{WHITE}Save Game
|
||||
|
|
|
@ -84,7 +84,7 @@ bool SpriteExists(SpriteID id)
|
|||
|
||||
static void* AllocSprite(size_t);
|
||||
|
||||
static void* ReadSprite(SpriteID id)
|
||||
static void* ReadSprite(SpriteID id, bool real_sprite)
|
||||
{
|
||||
uint num;
|
||||
byte type;
|
||||
|
@ -104,7 +104,17 @@ static void* ReadSprite(SpriteID id)
|
|||
num = FioReadWord();
|
||||
type = FioReadByte();
|
||||
if (type == 0xFF) {
|
||||
byte* dest = AllocSprite(num);
|
||||
byte* dest;
|
||||
|
||||
if (real_sprite) {
|
||||
static byte warning_level = 0;
|
||||
DEBUG(misc, warning_level) ("Tried to load non sprite #%d as a real sprite. Probable cause: NewGRF interference", id);
|
||||
warning_level = 6;
|
||||
if (id == SPR_IMG_QUERY) error("Uhm, would you be so kind not to load a NewGRF that makes the 'query' sprite a non- sprite?");
|
||||
return (void*)GetSprite(SPR_IMG_QUERY);
|
||||
}
|
||||
|
||||
dest = AllocSprite(num);
|
||||
|
||||
_sprite_ptr[id] = dest;
|
||||
FioReadBlock(dest, num);
|
||||
|
@ -116,6 +126,12 @@ static void* ReadSprite(SpriteID id)
|
|||
Sprite* sprite;
|
||||
byte* dest;
|
||||
|
||||
if (!real_sprite) {
|
||||
static byte warning_level = 0;
|
||||
DEBUG(misc, warning_level) ("Tried to load real sprite #%d as a non sprite. Probable cause: NewGRF interference", id);
|
||||
warning_level = 6;
|
||||
}
|
||||
|
||||
num = (type & 0x02) ? width * height : num - 8;
|
||||
sprite = AllocSprite(sizeof(*sprite) + num);
|
||||
_sprite_ptr[id] = sprite;
|
||||
|
@ -424,7 +440,7 @@ static uint RotateSprite(uint s)
|
|||
}
|
||||
#endif
|
||||
|
||||
const void *GetRawSprite(SpriteID sprite)
|
||||
const void *GetRawSprite(SpriteID sprite, bool real_sprite)
|
||||
{
|
||||
void* p;
|
||||
|
||||
|
@ -444,7 +460,7 @@ const void *GetRawSprite(SpriteID sprite)
|
|||
|
||||
p = _sprite_ptr[sprite];
|
||||
// Load the sprite, if it is not loaded, yet
|
||||
if (p == NULL) p = ReadSprite(sprite);
|
||||
if (p == NULL) p = ReadSprite(sprite, real_sprite);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,17 +12,17 @@ typedef struct Sprite {
|
|||
byte data[VARARRAY_SIZE];
|
||||
} Sprite;
|
||||
|
||||
const void *GetRawSprite(SpriteID sprite);
|
||||
const void *GetRawSprite(SpriteID sprite, bool real_sprite);
|
||||
bool SpriteExists(SpriteID sprite);
|
||||
|
||||
static inline const Sprite *GetSprite(SpriteID sprite)
|
||||
{
|
||||
return GetRawSprite(sprite);
|
||||
return GetRawSprite(sprite, true);
|
||||
}
|
||||
|
||||
static inline const byte *GetNonSprite(SpriteID sprite)
|
||||
{
|
||||
return GetRawSprite(sprite);
|
||||
return GetRawSprite(sprite, false);
|
||||
}
|
||||
|
||||
void GfxInitSpriteMem(void);
|
||||
|
|
91
train_cmd.c
91
train_cmd.c
|
@ -2915,28 +2915,6 @@ static void TrainMovedChangeSignals(TileIndex tile, DiagDirection dir)
|
|||
}
|
||||
|
||||
|
||||
typedef struct TrainCollideChecker {
|
||||
const Vehicle *v;
|
||||
const Vehicle *v_skip;
|
||||
} TrainCollideChecker;
|
||||
|
||||
static void *FindTrainCollideEnum(Vehicle *v, void *data)
|
||||
{
|
||||
const TrainCollideChecker* tcc = data;
|
||||
|
||||
if (v != tcc->v &&
|
||||
v != tcc->v_skip &&
|
||||
v->type == VEH_Train &&
|
||||
v->u.rail.track != 0x80 &&
|
||||
myabs(v->z_pos - tcc->v->z_pos) <= 6 &&
|
||||
myabs(v->x_pos - tcc->v->x_pos) < 6 &&
|
||||
myabs(v->y_pos - tcc->v->y_pos) < 6) {
|
||||
return v;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void SetVehicleCrashed(Vehicle *v)
|
||||
{
|
||||
Vehicle *u;
|
||||
|
@ -2962,6 +2940,47 @@ static uint CountPassengersInTrain(const Vehicle* v)
|
|||
return num;
|
||||
}
|
||||
|
||||
typedef struct TrainCollideChecker {
|
||||
Vehicle *v;
|
||||
const Vehicle *v_skip;
|
||||
uint num;
|
||||
} TrainCollideChecker;
|
||||
|
||||
static void *FindTrainCollideEnum(Vehicle *v, void *data)
|
||||
{
|
||||
TrainCollideChecker* tcc = (TrainCollideChecker*)data;
|
||||
|
||||
if (v != tcc->v &&
|
||||
v != tcc->v_skip &&
|
||||
v->type == VEH_Train &&
|
||||
v->u.rail.track != 0x80 &&
|
||||
myabs(v->z_pos - tcc->v->z_pos) < 6 &&
|
||||
myabs(v->x_pos - tcc->v->x_pos) < 6 &&
|
||||
myabs(v->y_pos - tcc->v->y_pos) < 6 ) {
|
||||
|
||||
Vehicle *coll = GetFirstVehicleInChain(v);
|
||||
|
||||
/* it can't collide with its own wagons */
|
||||
if (tcc->v == coll ||
|
||||
(tcc->v->u.rail.track == 0x40 && (tcc->v->direction & 2) != (v->direction & 2)))
|
||||
return NULL;
|
||||
|
||||
/* two drivers + passengers killed in train tcc->v (if it was not crashed already) */
|
||||
if (!(tcc->v->vehstatus & VS_CRASHED)) {
|
||||
tcc->num += 2 + CountPassengersInTrain(tcc->v);
|
||||
SetVehicleCrashed(tcc->v);
|
||||
}
|
||||
|
||||
if (!(coll->vehstatus & VS_CRASHED)) {
|
||||
/* two drivers + passengers killed in train coll (if it was not crashed already) */
|
||||
tcc->num += 2 + CountPassengersInTrain(coll);
|
||||
SetVehicleCrashed(coll);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks whether the specified train has a collision with another vehicle. If
|
||||
* so, destroys this vehicle, and the other vehicle if its subtype has TS_Front.
|
||||
|
@ -2971,9 +2990,6 @@ static uint CountPassengersInTrain(const Vehicle* v)
|
|||
static void CheckTrainCollision(Vehicle *v)
|
||||
{
|
||||
TrainCollideChecker tcc;
|
||||
Vehicle *coll;
|
||||
Vehicle *realcoll;
|
||||
uint num;
|
||||
|
||||
/* can't collide in depot */
|
||||
if (v->u.rail.track == 0x80) return;
|
||||
|
@ -2982,28 +2998,15 @@ static void CheckTrainCollision(Vehicle *v)
|
|||
|
||||
tcc.v = v;
|
||||
tcc.v_skip = v->next;
|
||||
tcc.num = 0;
|
||||
|
||||
/* find colliding vehicle */
|
||||
realcoll = VehicleFromPos(TileVirtXY(v->x_pos, v->y_pos), &tcc, FindTrainCollideEnum);
|
||||
if (realcoll == NULL) return;
|
||||
/* find colliding vehicles */
|
||||
VehicleFromPos(v->tile, &tcc, FindTrainCollideEnum);
|
||||
|
||||
coll = GetFirstVehicleInChain(realcoll);
|
||||
/* any dead -> no crash */
|
||||
if (tcc.num == 0) return;
|
||||
|
||||
/* it can't collide with its own wagons */
|
||||
if (v == coll ||
|
||||
(v->u.rail.track & 0x40 && (v->direction & 2) != (realcoll->direction & 2)))
|
||||
return;
|
||||
|
||||
//two drivers + passangers killed in train v
|
||||
num = 2 + CountPassengersInTrain(v);
|
||||
if (!(coll->vehstatus & VS_CRASHED))
|
||||
//two drivers + passangers killed in train coll (if it was not crashed already)
|
||||
num += 2 + CountPassengersInTrain(coll);
|
||||
|
||||
SetVehicleCrashed(v);
|
||||
if (IsFrontEngine(coll)) SetVehicleCrashed(coll);
|
||||
|
||||
SetDParam(0, num);
|
||||
SetDParam(0, tcc.num);
|
||||
AddNewsItem(STR_8868_TRAIN_CRASH_DIE_IN_FIREBALL,
|
||||
NEWS_FLAGS(NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, 0),
|
||||
v->index,
|
||||
|
|
|
@ -24,7 +24,7 @@ TileIndex GetOtherTunnelEnd(TileIndex tile)
|
|||
}
|
||||
|
||||
|
||||
static bool IsTunnelInWayDir(TileIndex tile, uint z, DiagDirection dir)
|
||||
bool IsTunnelInWayDir(TileIndex tile, uint z, DiagDirection dir)
|
||||
{
|
||||
TileIndexDiff delta = TileOffsByDiagDir(dir);
|
||||
uint height;
|
||||
|
|
|
@ -38,6 +38,7 @@ static inline TransportType GetTunnelTransportType(TileIndex t)
|
|||
|
||||
TileIndex GetOtherTunnelEnd(TileIndex);
|
||||
bool IsTunnelInWay(TileIndex, uint z);
|
||||
bool IsTunnelInWayDir(TileIndex tile, uint z, DiagDirection dir);
|
||||
|
||||
|
||||
static inline void MakeRoadTunnel(TileIndex t, Owner o, DiagDirection d)
|
||||
|
|
|
@ -452,6 +452,7 @@ int32 CmdBuildTunnel(TileIndex start_tile, uint32 flags, uint32 p1, uint32 p2)
|
|||
uint end_z;
|
||||
int32 cost;
|
||||
int32 ret;
|
||||
DiagDirection tunnel_in_way_dir;
|
||||
|
||||
_build_tunnel_endtile = 0;
|
||||
|
||||
|
@ -476,6 +477,12 @@ int32 CmdBuildTunnel(TileIndex start_tile, uint32 flags, uint32 p1, uint32 p2)
|
|||
* position, because of increased-cost-by-length: 'cost += cost >> 3' */
|
||||
cost = 0;
|
||||
delta = TileOffsByDiagDir(direction);
|
||||
if (OtherAxis(DiagDirToAxis(direction)) == AXIS_X) {
|
||||
tunnel_in_way_dir = (TileX(start_tile) < (MapMaxX() / 2)) ? DIAGDIR_SW : DIAGDIR_NE;
|
||||
} else {
|
||||
tunnel_in_way_dir = (TileY(start_tile) < (MapMaxX() / 2)) ? DIAGDIR_SE : DIAGDIR_NW;
|
||||
}
|
||||
|
||||
end_tile = start_tile;
|
||||
for (;;) {
|
||||
end_tile += delta;
|
||||
|
@ -483,7 +490,7 @@ int32 CmdBuildTunnel(TileIndex start_tile, uint32 flags, uint32 p1, uint32 p2)
|
|||
|
||||
if (start_z == end_z) break;
|
||||
|
||||
if (!_cheats.crossing_tunnels.value && IsTunnelInWay(end_tile, start_z)) {
|
||||
if (!_cheats.crossing_tunnels.value && IsTunnelInWayDir(end_tile, start_z, tunnel_in_way_dir)) {
|
||||
return_cmd_error(STR_5003_ANOTHER_TUNNEL_IN_THE_WAY);
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,11 @@ static inline bool IsCoast(TileIndex t)
|
|||
return GetWaterTileType(t) == WATER_COAST;
|
||||
}
|
||||
|
||||
static inline bool IsCanal(TileIndex t)
|
||||
{
|
||||
return GetWaterTileType(t) == WATER_CLEAR && GetTileOwner(t) != OWNER_WATER;
|
||||
}
|
||||
|
||||
static inline bool IsClearWaterTile(TileIndex t)
|
||||
{
|
||||
return IsTileType(t, MP_WATER) && IsWater(t) && GetTileSlope(t, NULL) == SLOPE_FLAT;
|
||||
|
|
Loading…
Reference in New Issue