1
0
Fork 0

(svn r14385) [0.6] -Backport from trunk:

- Fix: Invalid v->u.air.targetairport could cause crashes at several places [FS#2300] (r14383, r14344, r14343)
- Fix: Moving the first vehicle of a train elsewhere might require a new unitnumber for the remaining chain which might not be available (r14384)
- Fix: Trams jumping when reversing on a single trambit (like caused during road construction reworks) or when (manually) reversing in a corner [FS#1852] (r14371)
- Fix: Multiheaded parts in free wagon chains weren't connected (could cause desyncs) (r14366, r14362)
- Fix: [Win32] Some keypress combinations could be handled twice [FS#2206] (r14363)
- Fix: The ownership of roadtiles was not properly set for very old savegames (including TTD's) making it impossible to remove some pieces of road [FS#2311] (r14359)
- Fix: Desync due to randomly ordered vehicle hash by flooding and road vehicle overtake/following (r14356, r14258)
- Fix: Signs were not updated on company bankrupcy/sell, and thus could have the colour of invalid player (r14348)
- Fix: Delete the RenameSignWindow when 'its' sign is deleted (r14345)
release/0.6
rubidium 2008-09-22 19:57:31 +00:00
parent 456b479a21
commit 68fe4d71e1
15 changed files with 126 additions and 55 deletions

View File

@ -91,10 +91,10 @@ elif [ -d "$ROOT_DIR/.hg" ]; then
if [ -n "`hg status \"$SRC_DIR\" | grep -v '^?'`" ]; then if [ -n "`hg status \"$SRC_DIR\" | grep -v '^?'`" ]; then
MODIFIED="2" MODIFIED="2"
fi fi
HASH=`LC_ALL=C hg tip 2>/dev/null | head -n 1 | cut -d: -f3 | cut -c1-8` HASH=`LC_ALL=C hg parents 2>/dev/null | head -n 1 | cut -d: -f3 | cut -c1-8`
REV="h$HASH" REV="h$HASH"
BRANCH=`hg branch | sed 's/^default$//'` BRANCH=`hg branch | sed 's/^default$//'`
REV_NR=`LC_ALL=C hg log -k "svn" -l 1 --template "{desc}\n" "$SRC_DIR" | grep "^(svn r[0-9]*)" | head -n 1 | sed "s/.*(svn r\([0-9]*\)).*/\1/"` REV_NR=`LC_ALL=C hg log -r $HASH:0 -k "svn" -l 1 --template "{desc}\n" "$SRC_DIR" | grep "^(svn r[0-9]*)" | head -n 1 | sed "s/.*(svn r\([0-9]*\)).*/\1/"`
else else
# We don't know # We don't know
MODIFIED="1" MODIFIED="1"

View File

@ -41,7 +41,7 @@ Sub UpdateFiles(version)
revision = Mid(revision, 1, InStr(revision, "-") - 1) revision = Mid(revision, 1, InStr(revision, "-") - 1)
End If End If
Case "h" ' mercurial (hg) Case "h" ' mercurial (hg)
Set oExec = WshShell.Exec("hg log -k " & Chr(34) & "svn" & Chr(34) & " -l 1 --template " & Chr(34) & "{desc}\n" & Chr(34) & " ../src") Set oExec = WshShell.Exec("hg log -r " & Mid(version, 2, 8) & ":0 -k " & Chr(34) & "svn" & Chr(34) & " -l 1 --template " & Chr(34) & "{desc}\n" & Chr(34) & " ../src")
If Err.Number = 0 Then If Err.Number = 0 Then
revision = Mid(OExec.StdOut.ReadLine(), 7) revision = Mid(OExec.StdOut.ReadLine(), 7)
revision = Mid(revision, 1, InStr(revision, ")") - 1) revision = Mid(revision, 1, InStr(revision, ")") - 1)
@ -207,7 +207,7 @@ Function DetermineSVNVersion()
Else Else
' try mercurial (hg) ' try mercurial (hg)
Err.Clear Err.Clear
Set oExec = WshShell.Exec("hg tip") Set oExec = WshShell.Exec("hg parents")
If Err.Number = 0 Then If Err.Number = 0 Then
' Wait till the application is finished ... ' Wait till the application is finished ...
Do While oExec.Status = 0 Do While oExec.Status = 0

View File

@ -1059,10 +1059,8 @@ static bool AircraftController(Vehicle *v)
{ {
int count; int count;
StationID target = v->u.air.targetairport;
/* NULL if station is invalid */ /* NULL if station is invalid */
const Station *st = IsValidStationID(target) ? GetStation(target) : NULL; const Station *st = IsValidStationID(v->u.air.targetairport) ? GetStation(v->u.air.targetairport) : NULL;
/* 0 if there is no station */ /* 0 if there is no station */
TileIndex tile = 0; TileIndex tile = 0;
if (st != NULL) { if (st != NULL) {

View File

@ -46,6 +46,7 @@
#include "signal_func.h" #include "signal_func.h"
#include "gfx_func.h" #include "gfx_func.h"
#include "autoreplace_func.h" #include "autoreplace_func.h"
#include "signs.h"
#include "table/strings.h" #include "table/strings.h"
#include "table/sprites.h" #include "table/sprites.h"
@ -469,6 +470,11 @@ void ChangeOwnershipOfPlayerItems(PlayerID old_player, PlayerID new_player)
} }
} }
Sign *si;
FOR_ALL_SIGNS(si) {
if (si->owner == old_player) si->owner = new_player == PLAYER_SPECTATOR ? OWNER_NONE : new_player;
}
/* Change color of existing windows */ /* Change color of existing windows */
if (new_player != PLAYER_SPECTATOR) ChangeWindowOwner(old_player, new_player); if (new_player != PLAYER_SPECTATOR) ChangeWindowOwner(old_player, new_player);

View File

@ -685,9 +685,12 @@ void UpdateFillingPercent(TextEffectID te_id, uint8 percent, StringID string)
UpdateTextEffect(te_id, string); UpdateTextEffect(te_id, string);
} }
void HideFillingPercent(TextEffectID te_id) void HideFillingPercent(TextEffectID *te_id)
{ {
if (te_id != INVALID_TE_ID) RemoveTextEffect(te_id); if (*te_id == INVALID_TE_ID) return;
RemoveTextEffect(*te_id);
*te_id = INVALID_TE_ID;
} }
static const Widget _tooltips_widgets[] = { static const Widget _tooltips_widgets[] = {

View File

@ -25,6 +25,7 @@
#include "direction_func.h" #include "direction_func.h"
#include "rail_map.h" #include "rail_map.h"
#include "rail.h" #include "rail.h"
#include "aircraft.h"
int _traininfo_vehicle_pitch = 0; int _traininfo_vehicle_pitch = 0;
@ -215,8 +216,8 @@ enum {
*/ */
static byte MapAircraftMovementState(const Vehicle *v) static byte MapAircraftMovementState(const Vehicle *v)
{ {
const Station *st = GetStation(v->u.air.targetairport); const Station *st = GetTargetAirportIfValid(v);
if (st->airport_tile == 0) return AMS_TTDP_FLIGHT_TO_TOWER; if (st == NULL) return AMS_TTDP_FLIGHT_TO_TOWER;
const AirportFTAClass *afc = st->Airport(); const AirportFTAClass *afc = st->Airport();
uint16 amdflag = afc->MovingData(v->u.air.pos)->flag; uint16 amdflag = afc->MovingData(v->u.air.pos)->flag;
@ -552,22 +553,26 @@ static uint32 VehicleGetVariable(const ResolverObject *object, byte variable, by
{ {
const Vehicle *w = v->Next(); const Vehicle *w = v->Next();
uint16 altitude = v->z_pos - w->z_pos; // Aircraft height - shadow height uint16 altitude = v->z_pos - w->z_pos; // Aircraft height - shadow height
byte airporttype; byte airporttype = ATP_TTDP_LARGE;
switch (GetStation(v->u.air.targetairport)->airport_type) { const Station *st = GetTargetAirportIfValid(v);
/* Note, Helidepot and Helistation are treated as small airports
* as they are at ground level. */ if (st != NULL) {
case AT_HELIDEPOT: switch (st->airport_type) {
case AT_HELISTATION: /* Note, Helidepot and Helistation are treated as small airports
case AT_COMMUTER: * as they are at ground level. */
case AT_SMALL: airporttype = ATP_TTDP_SMALL; break; case AT_HELIDEPOT:
case AT_METROPOLITAN: case AT_HELISTATION:
case AT_INTERNATIONAL: case AT_COMMUTER:
case AT_INTERCON: case AT_SMALL: airporttype = ATP_TTDP_SMALL; break;
case AT_LARGE: airporttype = ATP_TTDP_LARGE; break; case AT_METROPOLITAN:
case AT_HELIPORT: airporttype = ATP_TTDP_HELIPORT; break; case AT_INTERNATIONAL:
case AT_OILRIG: airporttype = ATP_TTDP_OILRIG; break; case AT_INTERCON:
default: airporttype = ATP_TTDP_LARGE; break; case AT_LARGE: airporttype = ATP_TTDP_LARGE; break;
case AT_HELIPORT: airporttype = ATP_TTDP_HELIPORT; break;
case AT_OILRIG: airporttype = ATP_TTDP_OILRIG; break;
default: airporttype = ATP_TTDP_LARGE; break;
}
} }
return (altitude << 8) | airporttype; return (altitude << 8) | airporttype;

View File

@ -1188,8 +1188,8 @@ static void ConvertTownOwner()
for (tile = 0; tile != MapSize(); tile++) { for (tile = 0; tile != MapSize(); tile++) {
switch (GetTileType(tile)) { switch (GetTileType(tile)) {
case MP_ROAD: case MP_ROAD:
if (GB(_m[tile].m5, 4, 2) == ROAD_TILE_CROSSING && HasBit(_m[tile].m4, 7)) { if (GB(_m[tile].m5, 4, 2) == ROAD_TILE_CROSSING && HasBit(_m[tile].m3, 7)) {
_m[tile].m4 = OWNER_TOWN; _m[tile].m3 = OWNER_TOWN;
} }
/* FALLTHROUGH */ /* FALLTHROUGH */
@ -1596,7 +1596,7 @@ bool AfterLoadGame()
case MP_ROAD: case MP_ROAD:
_m[t].m4 |= (_m[t].m2 << 4); _m[t].m4 |= (_m[t].m2 << 4);
if (IsTileOwner(t, OWNER_TOWN)) { if ((GB(_m[t].m5, 4, 2) == ROAD_TILE_CROSSING ? (Owner)_m[t].m3 : GetTileOwner(t)) == OWNER_TOWN) {
SetTownIndex(t, CalcClosestTownFromTile(t, (uint)-1)->index); SetTownIndex(t, CalcClosestTownFromTile(t, (uint)-1)->index);
} else { } else {
SetTownIndex(t, 0); SetTownIndex(t, 0);
@ -2477,6 +2477,15 @@ bool AfterLoadGame()
} }
} }
/* Just always run this for 0.6. Doesn't hurt to fix the owners a second time. */
if (CheckSavegameVersion(103)) {
/* signs with invalid owner left from older savegames */
Sign *si;
FOR_ALL_SIGNS(si) {
if (si->owner != OWNER_NONE && !IsValidPlayer(si->owner) && GetPlayer(si->owner)->is_active) si->owner = OWNER_NONE;
}
}
return InitializeWindowsAndCaches(); return InitializeWindowsAndCaches();
} }

View File

@ -1282,7 +1282,7 @@ CommandCost CmdConvertRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
/* When not coverting rail <-> el. rail, any vehicle cannot be in tunnel/bridge */ /* When not coverting rail <-> el. rail, any vehicle cannot be in tunnel/bridge */
if (!IsCompatibleRail(GetRailType(tile), totype) && if (!IsCompatibleRail(GetRailType(tile), totype) &&
!HasVehicleOnTunnelBridge(tile, endtile)) continue; HasVehicleOnTunnelBridge(tile, endtile)) continue;
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
SetRailType(tile, totype); SetRailType(tile, totype);

View File

@ -35,6 +35,10 @@ Sign::Sign(PlayerID owner)
Sign::~Sign() Sign::~Sign()
{ {
free(this->name); free(this->name);
if (CleaningPool()) return;
DeleteRenameSignWindow(this->index);
this->owner = INVALID_PLAYER; this->owner = INVALID_PLAYER;
} }

View File

@ -67,7 +67,7 @@ void PlaceProc_Sign(TileIndex tile);
/* signs_gui.cpp */ /* signs_gui.cpp */
void ShowRenameSignWindow(const Sign *si); void ShowRenameSignWindow(const Sign *si);
void DeleteRenameSignWindow(SignID sign);
void ShowSignList(); void ShowSignList();
#endif /* SIGNS_H */ #endif /* SIGNS_H */

View File

@ -251,8 +251,9 @@ static void QuerySignEditWndProc(Window *w, WindowEvent *e)
case QUERY_EDIT_SIGN_WIDGET_DELETE: case QUERY_EDIT_SIGN_WIDGET_DELETE:
/* Only need to set the buffer to null, the rest is handled as the OK button */ /* Only need to set the buffer to null, the rest is handled as the OK button */
DeleteTextBufferAll(&qs->text); RenameSign(qs->cur_sign, "");
/* FALL THROUGH */ /* don't delete this, we are deleted in Sign::~Sign() -> DeleteRenameSignWindow() */
break;
case QUERY_EDIT_SIGN_WIDGET_OK: case QUERY_EDIT_SIGN_WIDGET_OK:
RenameSign(qs->cur_sign, qs->text.buf); RenameSign(qs->cur_sign, qs->text.buf);
@ -325,5 +326,9 @@ void ShowRenameSignWindow(const Sign *si)
UpdateSignEditWindow(w, si); UpdateSignEditWindow(w, si);
} }
void DeleteRenameSignWindow(SignID sign)
{
const Window *w = FindWindowById(WC_QUERY_STRING, 0);
if (w != NULL && WP(w, editsign_d).cur_sign == sign) delete w;
}

View File

@ -30,6 +30,6 @@ void UndrawChatMessage();
/* misc_gui.cpp */ /* misc_gui.cpp */
TextEffectID ShowFillingPercent(int x, int y, int z, uint8 percent, StringID color); TextEffectID ShowFillingPercent(int x, int y, int z, uint8 percent, StringID color);
void UpdateFillingPercent(TextEffectID te_id, uint8 percent, StringID color); void UpdateFillingPercent(TextEffectID te_id, uint8 percent, StringID color);
void HideFillingPercent(TextEffectID te_id); void HideFillingPercent(TextEffectID *te_id);
#endif /* TEXTEFF_HPP */ #endif /* TEXTEFF_HPP */

View File

@ -1123,6 +1123,14 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p
if (flags & DC_EXEC) src->unitnumber = unit_num; if (flags & DC_EXEC) src->unitnumber = unit_num;
} }
/* When we move the front vehicle, the second vehicle might need a unitnumber */
if (!HasBit(p2, 0) && (IsFreeWagon(src) || IsFrontEngine(src)) && (flags & DC_AUTOREPLACE) == 0) {
Vehicle *second = GetNextUnit(src);
if (second != NULL && IsTrainEngine(second) && GetFreeUnitNumber(VEH_TRAIN) > _patches.max_trains) {
return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
}
}
/* /*
* Check whether the vehicles in the source chain are in the destination * Check whether the vehicles in the source chain are in the destination
* chain. This can easily be done by checking whether the first vehicle * chain. This can easily be done by checking whether the first vehicle
@ -1962,6 +1970,7 @@ CommandCost CmdReverseTrainDirection(TileIndex tile, uint32 flags, uint32 p1, ui
} else { } else {
v->cur_speed = 0; v->cur_speed = 0;
SetLastSpeed(v, 0); SetLastSpeed(v, 0);
HideFillingPercent(&v->fill_percent_te_id);
ReverseTrainDirection(v); ReverseTrainDirection(v);
} }
} }
@ -3850,9 +3859,23 @@ void ConnectMultiheadedTrains()
} }
FOR_ALL_VEHICLES(v) { FOR_ALL_VEHICLES(v) {
if (v->type == VEH_TRAIN && IsFrontEngine(v)) { if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) {
Vehicle *u = v; /* Two ways to associate multiheaded parts to each other:
* sequential-matching: Trains shall be arranged to look like <..>..<..>..<..>..
* bracket-matching: Free vehicle chains shall be arranged to look like ..<..<..>..<..>..>..
*
* Note: Old savegames might contain chains which do not comply with these rules, e.g.
* - the front and read parts have invalid orders
* - different engine types might be combined
* - there might be different amounts of front and rear parts.
*
* Note: The multiheaded parts need to be matched exactly like they are matched on the server, else desyncs will occur.
* This is why two matching strategies are needed.
*/
bool sequential_matching = IsFrontEngine(v);
Vehicle *u = v;
BEGIN_ENUM_WAGONS(u) { BEGIN_ENUM_WAGONS(u) {
if (u->u.rail.other_multiheaded_part != NULL) continue; // we already linked this one if (u->u.rail.other_multiheaded_part != NULL) continue; // we already linked this one
@ -3863,14 +3886,35 @@ void ConnectMultiheadedTrains()
u->spritenum--; u->spritenum--;
} }
/* Find a matching back part */
EngineID eid = u->engine_type;
Vehicle *w; Vehicle *w;
for (w = u->Next(); w != NULL && (w->engine_type != u->engine_type || w->u.rail.other_multiheaded_part != NULL); w = GetNextVehicle(w)) {} if (sequential_matching) {
if (w != NULL) { for (w = GetNextVehicle(u); w != NULL; w = GetNextVehicle(w)) {
/* we found a car to partner with this engine. Now we will make sure it face the right way */ if (w->engine_type != eid || w->u.rail.other_multiheaded_part != NULL || !IsMultiheaded(w)) continue;
if (IsTrainEngine(w)) {
ClearTrainEngine(w); /* we found a car to partner with this engine. Now we will make sure it face the right way */
w->spritenum++; if (IsTrainEngine(w)) {
ClearTrainEngine(w);
w->spritenum++;
}
break;
} }
} else {
uint stack_pos = 0;
for (w = GetNextVehicle(u); w != NULL; w = GetNextVehicle(w)) {
if (w->engine_type != eid || w->u.rail.other_multiheaded_part != NULL || !IsMultiheaded(w)) continue;
if (IsTrainEngine(w)) {
stack_pos++;
} else {
if (stack_pos == 0) break;
stack_pos--;
}
}
}
if (w != NULL) {
w->u.rail.other_multiheaded_part = u; w->u.rail.other_multiheaded_part = u;
u->u.rail.other_multiheaded_part = w; u->u.rail.other_multiheaded_part = w;
} else { } else {

View File

@ -616,8 +616,7 @@ void Vehicle::PreDestructor()
if (IsValidStationID(this->last_station_visited)) { if (IsValidStationID(this->last_station_visited)) {
GetStation(this->last_station_visited)->loading_vehicles.remove(this); GetStation(this->last_station_visited)->loading_vehicles.remove(this);
HideFillingPercent(this->fill_percent_te_id); HideFillingPercent(&this->fill_percent_te_id);
this->fill_percent_te_id = INVALID_TE_ID;
} }
if (IsEngineCountable(this)) { if (IsEngineCountable(this)) {
@ -3240,8 +3239,7 @@ void Vehicle::LeaveStation()
current_order.flags = 0; current_order.flags = 0;
GetStation(this->last_station_visited)->loading_vehicles.remove(this); GetStation(this->last_station_visited)->loading_vehicles.remove(this);
HideFillingPercent(this->fill_percent_te_id); HideFillingPercent(&this->fill_percent_te_id);
this->fill_percent_te_id = INVALID_TE_ID;
} }

View File

@ -463,8 +463,6 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP
return 0; return 0;
case WM_CHAR: { case WM_CHAR: {
/* Silently drop all non-text messages as those were handled by WM_KEYDOWN */
if (wParam < VK_SPACE) return 0;
uint scancode = GB(lParam, 16, 8); uint scancode = GB(lParam, 16, 8);
uint charcode = wParam; uint charcode = wParam;
@ -490,12 +488,13 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP
case WM_KEYDOWN: { case WM_KEYDOWN: {
keycode = MapWindowsKey(wParam); keycode = MapWindowsKey(wParam);
/* Silently drop all text messages as those will be handled by WM_CHAR /* Silently drop all messages handled by WM_CHAR. */
* WM_KEYDOWN only handles CTRL+ commands and special keys like VK_LEFT, etc. */ MSG msg;
if (keycode == 0 || (keycode > WKC_PAUSE && GB(keycode, 13, 4) == 0)) return 0; if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
if (msg.message == WM_CHAR && GB(lParam, 16, 8) == GB(msg.lParam, 16, 8)) {
/* Keys handled in WM_CHAR */ return 0;
if ((uint)(GB(keycode, 0, 12) - WKC_NUM_DIV) <= WKC_MINUS - WKC_NUM_DIV) return 0; }
}
HandleKeypress(0 | (keycode << 16)); HandleKeypress(0 | (keycode << 16));
return 0; return 0;