(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)
This commit is contained in:
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
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"

View File

@ -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

View File

@ -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) {

View File

@ -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);

View File

@ -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[] = {

View File

@ -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;

View File

@ -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();
}

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 */
if (!IsCompatibleRail(GetRailType(tile), totype) &&
!HasVehicleOnTunnelBridge(tile, endtile)) continue;
HasVehicleOnTunnelBridge(tile, endtile)) continue;
if (flags & DC_EXEC) {
SetRailType(tile, totype);

View File

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

View File

@ -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 */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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 {

View File

@ -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);
}

View File

@ -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;