From 68fe4d71e12aeb8b681bcdbd8c5c7e4d14932b88 Mon Sep 17 00:00:00 2001 From: rubidium Date: Mon, 22 Sep 2008 19:57:31 +0000 Subject: [PATCH] (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) --- findversion.sh | 4 +-- projects/determineversion.vbs | 4 +-- src/aircraft_cmd.cpp | 4 +-- src/economy.cpp | 6 ++++ src/misc_gui.cpp | 7 ++-- src/newgrf_engine.cpp | 39 +++++++++++++---------- src/openttd.cpp | 15 +++++++-- src/rail_cmd.cpp | 2 +- src/signs.cpp | 4 +++ src/signs.h | 2 +- src/signs_gui.cpp | 11 +++++-- src/texteff.hpp | 2 +- src/train_cmd.cpp | 60 ++++++++++++++++++++++++++++++----- src/vehicle.cpp | 6 ++-- src/video/win32_v.cpp | 15 ++++----- 15 files changed, 126 insertions(+), 55 deletions(-) diff --git a/findversion.sh b/findversion.sh index f91186d033..184d5121d2 100755 --- a/findversion.sh +++ b/findversion.sh @@ -91,10 +91,10 @@ elif [ -d "$ROOT_DIR/.hg" ]; then if [ -n "`hg status \"$SRC_DIR\" | grep -v '^?'`" ]; then MODIFIED="2" 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" 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 # We don't know MODIFIED="1" diff --git a/projects/determineversion.vbs b/projects/determineversion.vbs index 2920e958db..c21642b944 100755 --- a/projects/determineversion.vbs +++ b/projects/determineversion.vbs @@ -41,7 +41,7 @@ Sub UpdateFiles(version) revision = Mid(revision, 1, InStr(revision, "-") - 1) End If 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 revision = Mid(OExec.StdOut.ReadLine(), 7) revision = Mid(revision, 1, InStr(revision, ")") - 1) @@ -207,7 +207,7 @@ Function DetermineSVNVersion() Else ' try mercurial (hg) Err.Clear - Set oExec = WshShell.Exec("hg tip") + Set oExec = WshShell.Exec("hg parents") If Err.Number = 0 Then ' Wait till the application is finished ... Do While oExec.Status = 0 diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp index 8b3bdec89d..2dde6bf480 100644 --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -1059,10 +1059,8 @@ static bool AircraftController(Vehicle *v) { int count; - StationID target = v->u.air.targetairport; - /* 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 */ TileIndex tile = 0; if (st != NULL) { diff --git a/src/economy.cpp b/src/economy.cpp index 48a9148951..1f324f79e1 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -46,6 +46,7 @@ #include "signal_func.h" #include "gfx_func.h" #include "autoreplace_func.h" +#include "signs.h" #include "table/strings.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 */ if (new_player != PLAYER_SPECTATOR) ChangeWindowOwner(old_player, new_player); diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index 6ff5071ed3..a637fcc7c2 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -685,9 +685,12 @@ void UpdateFillingPercent(TextEffectID te_id, uint8 percent, StringID 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[] = { diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index b9893eeb9e..f451fad883 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -25,6 +25,7 @@ #include "direction_func.h" #include "rail_map.h" #include "rail.h" +#include "aircraft.h" int _traininfo_vehicle_pitch = 0; @@ -215,8 +216,8 @@ enum { */ static byte MapAircraftMovementState(const Vehicle *v) { - const Station *st = GetStation(v->u.air.targetairport); - if (st->airport_tile == 0) return AMS_TTDP_FLIGHT_TO_TOWER; + const Station *st = GetTargetAirportIfValid(v); + if (st == NULL) return AMS_TTDP_FLIGHT_TO_TOWER; const AirportFTAClass *afc = st->Airport(); 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(); 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) { - /* Note, Helidepot and Helistation are treated as small airports - * as they are at ground level. */ - case AT_HELIDEPOT: - case AT_HELISTATION: - case AT_COMMUTER: - case AT_SMALL: airporttype = ATP_TTDP_SMALL; break; - case AT_METROPOLITAN: - case AT_INTERNATIONAL: - case AT_INTERCON: - 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; + const Station *st = GetTargetAirportIfValid(v); + + if (st != NULL) { + switch (st->airport_type) { + /* Note, Helidepot and Helistation are treated as small airports + * as they are at ground level. */ + case AT_HELIDEPOT: + case AT_HELISTATION: + case AT_COMMUTER: + case AT_SMALL: airporttype = ATP_TTDP_SMALL; break; + case AT_METROPOLITAN: + case AT_INTERNATIONAL: + case AT_INTERCON: + 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; diff --git a/src/openttd.cpp b/src/openttd.cpp index 2afe86801c..47fad621dc 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -1188,8 +1188,8 @@ static void ConvertTownOwner() for (tile = 0; tile != MapSize(); tile++) { switch (GetTileType(tile)) { case MP_ROAD: - if (GB(_m[tile].m5, 4, 2) == ROAD_TILE_CROSSING && HasBit(_m[tile].m4, 7)) { - _m[tile].m4 = OWNER_TOWN; + if (GB(_m[tile].m5, 4, 2) == ROAD_TILE_CROSSING && HasBit(_m[tile].m3, 7)) { + _m[tile].m3 = OWNER_TOWN; } /* FALLTHROUGH */ @@ -1596,7 +1596,7 @@ bool AfterLoadGame() case MP_ROAD: _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); } else { 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(); } diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index e683e803e2..3426f27229 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -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 */ if (!IsCompatibleRail(GetRailType(tile), totype) && - !HasVehicleOnTunnelBridge(tile, endtile)) continue; + HasVehicleOnTunnelBridge(tile, endtile)) continue; if (flags & DC_EXEC) { SetRailType(tile, totype); diff --git a/src/signs.cpp b/src/signs.cpp index c753daf81c..16aeb13bdb 100644 --- a/src/signs.cpp +++ b/src/signs.cpp @@ -35,6 +35,10 @@ Sign::Sign(PlayerID owner) Sign::~Sign() { free(this->name); + + if (CleaningPool()) return; + + DeleteRenameSignWindow(this->index); this->owner = INVALID_PLAYER; } diff --git a/src/signs.h b/src/signs.h index 3f014c0cc1..51b89afc10 100644 --- a/src/signs.h +++ b/src/signs.h @@ -67,7 +67,7 @@ void PlaceProc_Sign(TileIndex tile); /* signs_gui.cpp */ void ShowRenameSignWindow(const Sign *si); - +void DeleteRenameSignWindow(SignID sign); void ShowSignList(); #endif /* SIGNS_H */ diff --git a/src/signs_gui.cpp b/src/signs_gui.cpp index abbcda7605..94fa21efe9 100644 --- a/src/signs_gui.cpp +++ b/src/signs_gui.cpp @@ -251,8 +251,9 @@ static void QuerySignEditWndProc(Window *w, WindowEvent *e) case QUERY_EDIT_SIGN_WIDGET_DELETE: /* Only need to set the buffer to null, the rest is handled as the OK button */ - DeleteTextBufferAll(&qs->text); - /* FALL THROUGH */ + RenameSign(qs->cur_sign, ""); + /* don't delete this, we are deleted in Sign::~Sign() -> DeleteRenameSignWindow() */ + break; case QUERY_EDIT_SIGN_WIDGET_OK: RenameSign(qs->cur_sign, qs->text.buf); @@ -325,5 +326,9 @@ void ShowRenameSignWindow(const Sign *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; +} diff --git a/src/texteff.hpp b/src/texteff.hpp index e05af98d21..6246f3792b 100644 --- a/src/texteff.hpp +++ b/src/texteff.hpp @@ -30,6 +30,6 @@ void UndrawChatMessage(); /* misc_gui.cpp */ TextEffectID ShowFillingPercent(int x, int y, int z, 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 */ diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 08c8705627..34ec74460d 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -1123,6 +1123,14 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p 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 * 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 { v->cur_speed = 0; SetLastSpeed(v, 0); + HideFillingPercent(&v->fill_percent_te_id); ReverseTrainDirection(v); } } @@ -3850,9 +3859,23 @@ void ConnectMultiheadedTrains() } FOR_ALL_VEHICLES(v) { - if (v->type == VEH_TRAIN && IsFrontEngine(v)) { - Vehicle *u = v; + if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(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) { if (u->u.rail.other_multiheaded_part != NULL) continue; // we already linked this one @@ -3863,14 +3886,35 @@ void ConnectMultiheadedTrains() u->spritenum--; } + /* Find a matching back part */ + EngineID eid = u->engine_type; 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 (w != NULL) { - /* we found a car to partner with this engine. Now we will make sure it face the right way */ - if (IsTrainEngine(w)) { - ClearTrainEngine(w); - w->spritenum++; + if (sequential_matching) { + for (w = GetNextVehicle(u); w != NULL; w = GetNextVehicle(w)) { + if (w->engine_type != eid || w->u.rail.other_multiheaded_part != NULL || !IsMultiheaded(w)) continue; + + /* we found a car to partner with this engine. Now we will make sure it face the right way */ + 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; u->u.rail.other_multiheaded_part = w; } else { diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 89744e2b33..a707a0bd3d 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -616,8 +616,7 @@ void Vehicle::PreDestructor() if (IsValidStationID(this->last_station_visited)) { GetStation(this->last_station_visited)->loading_vehicles.remove(this); - HideFillingPercent(this->fill_percent_te_id); - this->fill_percent_te_id = INVALID_TE_ID; + HideFillingPercent(&this->fill_percent_te_id); } if (IsEngineCountable(this)) { @@ -3240,8 +3239,7 @@ void Vehicle::LeaveStation() current_order.flags = 0; GetStation(this->last_station_visited)->loading_vehicles.remove(this); - HideFillingPercent(this->fill_percent_te_id); - this->fill_percent_te_id = INVALID_TE_ID; + HideFillingPercent(&this->fill_percent_te_id); } diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp index 3b7a6d564c..42ebf98811 100644 --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -463,8 +463,6 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP return 0; 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 charcode = wParam; @@ -490,12 +488,13 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP case WM_KEYDOWN: { keycode = MapWindowsKey(wParam); - /* Silently drop all text messages as those will be handled by WM_CHAR - * WM_KEYDOWN only handles CTRL+ commands and special keys like VK_LEFT, etc. */ - if (keycode == 0 || (keycode > WKC_PAUSE && GB(keycode, 13, 4) == 0)) return 0; - - /* Keys handled in WM_CHAR */ - if ((uint)(GB(keycode, 0, 12) - WKC_NUM_DIV) <= WKC_MINUS - WKC_NUM_DIV) return 0; + /* Silently drop all messages handled by WM_CHAR. */ + MSG msg; + if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { + if (msg.message == WM_CHAR && GB(lParam, 16, 8) == GB(msg.lParam, 16, 8)) { + return 0; + } + } HandleKeypress(0 | (keycode << 16)); return 0;