mirror of https://github.com/OpenTTD/OpenTTD.git
(svn r11073) [0.5] -Backport from trunk (r11039, r11029, r11027, r11024, r11021, r11020, r11018):
- Fix: Underflow that caused overflows in the performance rating [FS#1179] (r11039) - Fix [Windows]: MIDI does not stop when closing openttd [FS#1164] (r11029) - Fix: Do not unconditionally assume that a tile has a depot (r11027) - Fix: Give a more correct error when building some things on tile 0 [FS#1173] (r11024) - Fix: Do not display income/expenses when they do not belong to a "valid" tile, like the money cheat and giving money [FS#1175] (r11021) - Fix: One could not give money when (s)he had too much money [FS#1174] (r11020) - Fix: Disallow buying/selling shares in your own company or a bankrupt company [FS#1169] (r11018)
This commit is contained in:
parent
c7dbb1fca0
commit
70d43a7b37
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
16
depot.h
16
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
|
||||
|
|
29
economy.c
29
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;
|
||||
|
|
10
graph_gui.c
10
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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
15
water_cmd.c
15
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;
|
||||
|
|
Loading…
Reference in New Issue