diff --git a/clear_cmd.c b/clear_cmd.c index c8ba25bbb4..18a06a0d88 100644 --- a/clear_cmd.c +++ b/clear_cmd.c @@ -414,8 +414,6 @@ int32 CmdPurchaseLandArea(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); - if (!EnsureNoVehicle(tile)) return CMD_ERROR; - if (IsOwnedLandTile(tile) && IsTileOwner(tile, _current_player)) { return_cmd_error(STR_5807_YOU_ALREADY_OWN_IT); } diff --git a/command.c b/command.c index 6482eddea5..8f5693c7d7 100644 --- a/command.c +++ b/command.c @@ -537,7 +537,7 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback, SubtractMoneyFromPlayer(res2); if (IsLocalPlayer() && _game_mode != GM_EDITOR) { - if (res2 != 0) ShowCostOrIncomeAnimation(x, y, GetSlopeZ(x, y), res2); + if (res2 != 0 && tile != 0) ShowCostOrIncomeAnimation(x, y, GetSlopeZ(x, y), res2); if (_additional_cash_required) { SetDParam(0, _additional_cash_required); ShowErrorMessage(STR_0003_NOT_ENOUGH_CASH_REQUIRES, error_part1, x,y); diff --git a/depot.h b/depot.h index 7cf25a1b1e..e5d97e006d 100644 --- a/depot.h +++ b/depot.h @@ -10,6 +10,7 @@ #include "oldpool.h" #include "tile.h" #include "variables.h" +#include "station_map.h" struct Depot { TileIndex xy; @@ -82,6 +83,21 @@ static inline bool IsTileDepotType(TileIndex tile, TransportType type) } } +/** + * Is the given tile a tile with a depot on it? + * @param tile the tile to check + * @return true if and only if there is a depot on the tile. + */ +static inline bool IsDepotTile(TileIndex tile) +{ + switch (GetTileType(tile)) { + case MP_STREET: return (_m[tile].m5 & 0xF0) == 0x20; + case MP_WATER: return (_m[tile].m5 & ~3) == 0x80; + case MP_RAILWAY: return (_m[tile].m5 & 0xFC) == 0xC0; + case MP_STATION: return IsHangar(tile); + default: return false; + } +} /** * Find out if the slope of the tile is suitable to build a depot of given direction diff --git a/economy.c b/economy.c index 7b82bc72f7..7c80b8c501 100644 --- a/economy.c +++ b/economy.c @@ -217,10 +217,7 @@ int UpdateCompanyRatingAndValue(Player *p, bool update) // Skip the total if (i == SCORE_TOTAL) continue; // Check the score - s = (_score_part[owner][i] >= _score_info[i].needed) ? - _score_info[i].score : - _score_part[owner][i] * _score_info[i].score / _score_info[i].needed; - if (s < 0) s = 0; + s = clamp(_score_part[owner][i], 0, _score_info[i].needed) * _score_info[i].score / _score_info[i].needed; score += s; total_score += _score_info[i].score; } @@ -649,6 +646,8 @@ static void AddInflation(void) int i; int32 inf = _economy.infl_amount * 54; + if ((_cur_year - _patches.starting_year) >= (ORIGINAL_MAX_YEAR - ORIGINAL_BASE_YEAR)) return; + for (i = 0; i != NUM_PRICES; i++) { AddSingleInflation((int32*)&_price + i, _price_frac + i, inf); } @@ -1633,11 +1632,16 @@ int32 CmdBuyShareInCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) Player *p; int64 cost; - /* Check if buying shares is allowed (protection against modified clients */ - if (!IsValidPlayer((PlayerID)p1) || !_patches.allow_shares) return CMD_ERROR; + /* Check if buying shares is allowed (protection against modified clients) */ + /* Cannot buy own shares */ + if (!IsValidPlayer((PlayerID)p1) || !_patches.allow_shares || _current_player == (PlayerID)p1) return CMD_ERROR; + + p = GetPlayer((PlayerID)p1); + + /* Cannot buy shares of non-existent nor bankrupted company */ + if (!p->is_active) return CMD_ERROR; SET_EXPENSES_TYPE(EXPENSES_OTHER); - p = GetPlayer(p1); /* Protect new companies from hostile takeovers */ if (_cur_year - p->inaugurated_year < 6) return_cmd_error(STR_7080_PROTECTED); @@ -1678,11 +1682,16 @@ int32 CmdSellShareInCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) Player *p; int64 cost; - /* Check if buying shares is allowed (protection against modified clients */ - if (!IsValidPlayer((PlayerID)p1) || !_patches.allow_shares) return CMD_ERROR; + /* Check if selling shares is allowed (protection against modified clients) */ + /* Cannot sell own shares */ + if (!IsValidPlayer((PlayerID)p1) || !_patches.allow_shares || _current_player == (PlayerID)p1) return CMD_ERROR; + + p = GetPlayer((PlayerID)p1); + + /* Cannot sell shares of non-existent nor bankrupted company */ + if (!p->is_active) return CMD_ERROR; SET_EXPENSES_TYPE(EXPENSES_OTHER); - p = GetPlayer(p1); /* Those lines are here for network-protection (clients can be slow) */ if (GetAmountOwnedBy(p, _current_player) == 0) return 0; diff --git a/graph_gui.c b/graph_gui.c index 06a9d29d00..5d0a4534b4 100644 --- a/graph_gui.c +++ b/graph_gui.c @@ -997,13 +997,7 @@ static void PerformanceRatingDetailWndProc(Window *w, WindowEvent *e) DrawStringRightAligned(107, y, SET_PERFORMANCE_DETAIL_INT, 0); // Calculate the %-bar - if (val > needed) { - x = 50; - } else if (val == 0) { - x = 0; - } else { - x = val * 50 / needed; - } + x = clamp(val, 0, needed) * 50 / needed; // SCORE_LOAN is inversed if (val < 0 && i == SCORE_LOAN) x = 0; @@ -1013,7 +1007,7 @@ static void PerformanceRatingDetailWndProc(Window *w, WindowEvent *e) if (x != 50) GfxFillRect(112 + x, y - 2, 112 + 50, y + 10, color_notdone); // Calculate the % - x = (val <= needed) ? val * 100 / needed : 100; + x = clamp(val, 0, needed) * 100 / needed; // SCORE_LOAN is inversed if (val < 0 && i == SCORE_LOAN) x = 0; diff --git a/main_gui.c b/main_gui.c index 87e386dab2..4f4a7f2c56 100644 --- a/main_gui.c +++ b/main_gui.c @@ -88,7 +88,7 @@ void HandleOnEditText(WindowEvent *e) #ifdef ENABLE_NETWORK case 3: { /* Give money, you can only give money in excess of loan */ const Player *p = GetPlayer(_current_player); - int32 money = min(p->money64 - p->current_loan, atoi(e->we.edittext.str) / _currency->rate); + int32 money = min(p->money64 - p->current_loan, (int64)(atoi(e->we.edittext.str) / _currency->rate)); money = clamp(money, 0, 20000000); // Clamp between 20 million and 0 diff --git a/music/win32_m.c b/music/win32_m.c index 36b79b30bb..6a1a717b53 100644 --- a/music/win32_m.c +++ b/music/win32_m.c @@ -12,6 +12,7 @@ static struct { bool playing; int new_vol; HANDLE wait_obj; + HANDLE thread; UINT_PTR devid; char start_song[260]; } _midi; @@ -86,8 +87,6 @@ static bool MidiIntIsSongPlaying(void) static DWORD WINAPI MidiThread(LPVOID arg) { - _midi.wait_obj = CreateEvent(NULL, FALSE, FALSE, NULL); - do { char *s; int vol; @@ -104,9 +103,7 @@ static DWORD WINAPI MidiThread(LPVOID arg) s[0] = '\0'; // Delay somewhat in case we don't manage to play. - if (!_midi.playing) { - Sleep(5000); - } + if (!_midi.playing) WaitForMultipleObjects(1, &_midi.wait_obj, FALSE, 5000); } if (_midi.stop_song && _midi.playing) { @@ -121,14 +118,13 @@ static DWORD WINAPI MidiThread(LPVOID arg) WaitForMultipleObjects(1, &_midi.wait_obj, FALSE, 1000); } while (!_midi.terminate); - DeleteObject(_midi.wait_obj); + MidiIntStopSong(); return 0; } static const char *Win32MidiStart(const char * const *parm) { MIDIOUTCAPS midicaps; - DWORD threadId; UINT nbdev; UINT_PTR dev; char buf[16]; @@ -148,8 +144,8 @@ static const char *Win32MidiStart(const char * const *parm) } } - if (CreateThread(NULL, 8192, MidiThread, 0, 0, &threadId) == NULL) - return "Failed to create thread"; + if (NULL == (_midi.wait_obj = CreateEvent(NULL, FALSE, FALSE, NULL))) return "Failed to create event"; + if (NULL == (_midi.thread = CreateThread(NULL, 8192, MidiThread, 0, 0, NULL))) return "Failed to create thread"; return NULL; } @@ -158,6 +154,9 @@ static void Win32MidiStop(void) { _midi.terminate = true; SetEvent(_midi.wait_obj); + WaitForMultipleObjects(1, &_midi.thread, true, INFINITE); + CloseHandle(_midi.wait_obj); + CloseHandle(_midi.thread); } const HalMusicDriver _win32_music_driver = { diff --git a/tree_cmd.c b/tree_cmd.c index 847b8971da..f4f4149713 100644 --- a/tree_cmd.c +++ b/tree_cmd.c @@ -249,6 +249,11 @@ int32 CmdPlantTree(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) cost += _price.build_trees * 2; break; + case MP_WATER: + msg = STR_3807_CAN_T_BUILD_ON_WATER; + continue; + break; + case MP_CLEAR: if (!IsTileOwner(tile, OWNER_NONE)) { msg = STR_2804_SITE_UNSUITABLE; diff --git a/vehicle.c b/vehicle.c index f1985013a3..6190a610c4 100644 --- a/vehicle.c +++ b/vehicle.c @@ -1740,7 +1740,7 @@ int32 CmdDepotMassAutoReplace(TileIndex tile, uint32 flags, uint32 p1, uint32 p2 byte vehicle_type = GB(p1, 0, 8); - if (!IsTileOwner(tile, _current_player)) return CMD_ERROR; + if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_player)) return CMD_ERROR; /* Get the list of vehicles in the depot */ BuildDepotVehicleList(vehicle_type, tile, &vl, &engine_list_length, &engine_count, NULL, NULL, NULL); diff --git a/water_cmd.c b/water_cmd.c index 31bcc3dc09..622f3569c6 100644 --- a/water_cmd.c +++ b/water_cmd.c @@ -61,10 +61,7 @@ int32 CmdBuildShipDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) if (p1 > 1) return CMD_ERROR; - if (!EnsureNoVehicle(tile)) return CMD_ERROR; - tile2 = tile + (p1 ? TileDiffXY(0, 1) : TileDiffXY(1, 0)); - if (!EnsureNoVehicle(tile2)) return CMD_ERROR; if (!IsClearWaterTile(tile) || !IsClearWaterTile(tile2)) return_cmd_error(STR_3801_MUST_BE_BUILT_ON_WATER); @@ -294,15 +291,15 @@ static int32 ClearTile_Water(TileIndex tile, byte flags) case WATER_CLEAR: if (flags & DC_NO_WATER) return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER); - // Make sure no vehicle is on the tile - if (!EnsureNoVehicle(tile)) return CMD_ERROR; - // Make sure it's not an edge tile. if (!IS_INT_INSIDE(TileX(tile), 1, MapMaxX() - 1) || !IS_INT_INSIDE(TileY(tile), 1, MapMaxY() - 1)) { return_cmd_error(STR_0002_TOO_CLOSE_TO_EDGE_OF_MAP); } + /* Make sure no vehicle is on the tile */ + if (!EnsureNoVehicle(tile)) return CMD_ERROR; + if (GetTileOwner(tile) != OWNER_WATER && GetTileOwner(tile) != OWNER_NONE && !CheckTileOwnership(tile)) return CMD_ERROR; if (flags & DC_EXEC) DoClearSquare(tile); @@ -314,12 +311,6 @@ static int32 ClearTile_Water(TileIndex tile, byte flags) // Make sure no vehicle is on the tile if (!EnsureNoVehicle(tile)) return CMD_ERROR; - // Make sure it's not an edge tile. - if (!IS_INT_INSIDE(TileX(tile), 1, MapMaxX() - 1) || - !IS_INT_INSIDE(TileY(tile), 1, MapMaxY() - 1)) { - return_cmd_error(STR_0002_TOO_CLOSE_TO_EDGE_OF_MAP); - } - if (flags & DC_EXEC) DoClearSquare(tile); if (slope == SLOPE_N || slope == SLOPE_E || slope == SLOPE_S || slope == SLOPE_W) { return _price.clear_water;