(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:
rubidium 2007-09-09 20:36:15 +00:00
parent c7dbb1fca0
commit 70d43a7b37
10 changed files with 56 additions and 44 deletions

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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