(svn r17302) [0.7] -Backport from trunk:

- Fix: [NoAI] Reloading an AI started a new AI in the first available company slot causing other AIs to be started [FS#3153] (r17298)
- Fix: Crash after upgrading base graphics set when opening the game options menu and you were using the upgraded set [FS#3147] (r17291)
- Fix: [Squirrel] Stack was not always cleared properly with tail recursion (r17284)
- Fix: [Squirrel] Calling a function that has default parameters with not enough parameters can cause a crash (r17273)
- Change: Mention the MD5 checksum of the original NewGRF in the "saveload failed horribly"-error message and make it more clear that the filename is of the current NewGRF [FS#3139] (r17267)
This commit is contained in:
rubidium 2009-08-28 17:17:08 +00:00
parent ca66a61cc9
commit 47ae295ee1
8 changed files with 53 additions and 15 deletions

View File

@ -323,6 +323,10 @@ bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger args,SQIntege
SQInteger ndef = func->_ndefaultparams; SQInteger ndef = func->_ndefaultparams;
if(ndef && nargs < paramssize) { if(ndef && nargs < paramssize) {
SQInteger diff = paramssize - nargs; SQInteger diff = paramssize - nargs;
if (diff > ndef) {
Raise_Error(_SC("wrong number of parameters"));
return false;
}
for(SQInteger n = ndef - diff; n < ndef; n++) { for(SQInteger n = ndef - diff; n < ndef; n++) {
_stack._vals[stackbase + (nargs++)] = closure->_defaultparams[n]; _stack._vals[stackbase + (nargs++)] = closure->_defaultparams[n];
} }
@ -745,9 +749,8 @@ common_call:
_GUARD(gen->Yield(this)); _GUARD(gen->Yield(this));
Return(1, ct_target, clo); Return(1, ct_target, clo);
STK(ct_target) = gen; STK(ct_target) = gen;
while (last_top >= _top) _stack._vals[last_top--].Null();
continue;
} }
while (last_top >= _top) _stack._vals[last_top--].Null();
} }
continue; continue;
case OT_NATIVECLOSURE: { case OT_NATIVECLOSURE: {

View File

@ -742,7 +742,7 @@ struct AIDebugWindow : public Window {
if (widget == AID_WIDGET_RELOAD_TOGGLE && !this->IsWidgetDisabled(widget)) { if (widget == AID_WIDGET_RELOAD_TOGGLE && !this->IsWidgetDisabled(widget)) {
/* First kill the company of the AI, then start a new one. This should start the current AI again */ /* First kill the company of the AI, then start a new one. This should start the current AI again */
DoCommandP(0, 2, ai_debug_company, CMD_COMPANY_CTRL); DoCommandP(0, 2, ai_debug_company, CMD_COMPANY_CTRL);
DoCommandP(0, 1, 0, CMD_COMPANY_CTRL); DoCommandP(0, 1, ai_debug_company, CMD_COMPANY_CTRL);
} }
} }

View File

@ -420,16 +420,23 @@ void ResetCompanyLivery(Company *c)
* Create a new company and sets all company variables default values * Create a new company and sets all company variables default values
* *
* @param is_ai is a ai company? * @param is_ai is a ai company?
* @param company CompanyID to use for the new company
* @return the company struct * @return the company struct
*/ */
Company *DoStartupNewCompany(bool is_ai) Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY)
{ {
if (ActiveCompanyCount() == MAX_COMPANIES || !Company::CanAllocateItem()) return NULL; if (ActiveCompanyCount() == MAX_COMPANIES || !Company::CanAllocateItem()) return NULL;
/* we have to generate colour before this company is valid */ /* we have to generate colour before this company is valid */
Colours colour = GenerateCompanyColour(); Colours colour = GenerateCompanyColour();
Company *c = new Company(STR_SV_UNNAMED, is_ai); Company *c;
if (company == INVALID_COMPANY) {
c = new Company(STR_SV_UNNAMED, is_ai);
} else {
if (IsValidCompanyID(company)) return NULL;
c = new (company) Company(STR_SV_UNNAMED, is_ai);
}
c->colour = colour; c->colour = colour;
@ -486,7 +493,7 @@ static void MaybeStartNewCompany()
if (n < (uint)_settings_game.difficulty.max_no_competitors) { if (n < (uint)_settings_game.difficulty.max_no_competitors) {
/* Send a command to all clients to start up a new AI. /* Send a command to all clients to start up a new AI.
* Works fine for Multiplayer and Singleplayer */ * Works fine for Multiplayer and Singleplayer */
DoCommandP(0, 1, 0, CMD_COMPANY_CTRL); DoCommandP(0, 1, INVALID_COMPANY, CMD_COMPANY_CTRL);
} }
} }
@ -700,6 +707,7 @@ void CompanyNewsInformation::FillData(const Company *c, const Company *other)
* - p1 = 3 - merge two companies together. merge #1 with #2. Identified by p2 * - p1 = 3 - merge two companies together. merge #1 with #2. Identified by p2
* @param p2 various functionality, dictated by p1 * @param p2 various functionality, dictated by p1
* - p1 = 0 - ClientID of the newly created client * - p1 = 0 - ClientID of the newly created client
* - p1 = 1 - CompanyID to start AI (INVALID_COMPANY for first available)
* - p1 = 2 - CompanyID of the that is getting deleted * - p1 = 2 - CompanyID of the that is getting deleted
* - p1 = 3 - #1 p2 = (bit 0-15) - company to merge (p2 & 0xFFFF) * - p1 = 3 - #1 p2 = (bit 0-15) - company to merge (p2 & 0xFFFF)
* - #2 p2 = (bit 16-31) - company to be merged into ((p2>>16)&0xFFFF) * - #2 p2 = (bit 16-31) - company to be merged into ((p2>>16)&0xFFFF)
@ -815,7 +823,8 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
case 1: // Make a new AI company case 1: // Make a new AI company
if (!(flags & DC_EXEC)) return CommandCost(); if (!(flags & DC_EXEC)) return CommandCost();
DoStartupNewCompany(true); if (p2 != INVALID_COMPANY && (p2 >= MAX_COMPANIES || IsValidCompanyID((CompanyID)p2))) return CMD_ERROR;
DoStartupNewCompany(true, (CompanyID)p2);
break; break;
case 2: { // Delete a company case 2: { // Delete a company

View File

@ -1018,7 +1018,7 @@ DEF_CONSOLE_CMD(ConStartAI)
} }
/* Start a new AI company */ /* Start a new AI company */
DoCommandP(0, 1, 0, CMD_COMPANY_CTRL); DoCommandP(0, 1, INVALID_COMPANY, CMD_COMPANY_CTRL);
return true; return true;
} }
@ -1054,7 +1054,7 @@ DEF_CONSOLE_CMD(ConReloadAI)
/* First kill the company of the AI, then start a new one. This should start the current AI again */ /* First kill the company of the AI, then start a new one. This should start the current AI again */
DoCommandP(0, 2, company_id, CMD_COMPANY_CTRL); DoCommandP(0, 2, company_id, CMD_COMPANY_CTRL);
DoCommandP(0, 1, 0, CMD_COMPANY_CTRL); DoCommandP(0, 1, company_id, CMD_COMPANY_CTRL);
IConsolePrint(CC_DEFAULT, "AI reloaded."); IConsolePrint(CC_DEFAULT, "AI reloaded.");
return true; return true;

View File

@ -493,6 +493,11 @@ bool OBGFileScanner::AddFile(const char *filename, size_t basepath_length)
/* don't allow recursive delete of all remaining items */ /* don't allow recursive delete of all remaining items */
duplicate->next = NULL; duplicate->next = NULL;
/* If the duplicate set is currently used (due to rescanning this can happen)
* update the currently used set to the new one. This will 'lie' about the
* version number until a new game is started which isn't a big problem */
if (_used_graphics_set == duplicate) _used_graphics_set = graphics;
DEBUG(grf, 1, "Removing %s (%i) as base graphics set (duplicate)", duplicate->name, duplicate->version); DEBUG(grf, 1, "Removing %s (%i) as base graphics set (duplicate)", duplicate->name, duplicate->version);
delete duplicate; delete duplicate;
ret = true; ret = true;

View File

@ -88,6 +88,7 @@ public:
case CONTENT_TYPE_BASE_GRAPHICS: case CONTENT_TYPE_BASE_GRAPHICS:
FindGraphicsSets(); FindGraphicsSets();
InvalidateWindow(WC_GAME_OPTIONS, 0);
break; break;
case CONTENT_TYPE_NEWGRF: case CONTENT_TYPE_NEWGRF:

View File

@ -71,7 +71,7 @@ void ProcessAsyncSaveFinish();
void CallWindowTickEvent(); void CallWindowTickEvent();
extern void SetDifficultyLevel(int mode, DifficultySettings *gm_opt); extern void SetDifficultyLevel(int mode, DifficultySettings *gm_opt);
extern Company *DoStartupNewCompany(bool is_ai); extern Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY);
extern void ShowOSErrorBox(const char *buf, bool system); extern void ShowOSErrorBox(const char *buf, bool system);
extern void InitializeRailGUI(); extern void InitializeRailGUI();

View File

@ -11,6 +11,7 @@
#include "../roadveh.h" #include "../roadveh.h"
#include "../string_func.h" #include "../string_func.h"
#include "../gamelog.h" #include "../gamelog.h"
#include "../gamelog_internal.h"
#include "../network/network.h" #include "../network/network.h"
#include "../gfxinit.h" #include "../gfxinit.h"
#include "../functions.h" #include "../functions.h"
@ -38,7 +39,7 @@
#include <signal.h> #include <signal.h>
extern StringID _switch_mode_errorstr; extern StringID _switch_mode_errorstr;
extern Company *DoStartupNewCompany(bool is_ai); extern Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY);
extern void InitializeRailGUI(); extern void InitializeRailGUI();
/** /**
@ -266,6 +267,24 @@ static void ResetSignalHandlers()
signal(SIGFPE, _prev_fpe); signal(SIGFPE, _prev_fpe);
} }
/**
* Try to find the overridden GRF identifier of the given GRF.
* @param c the GRF to get the 'previous' version of.
* @return the GRF identifier or \a c if none could be found.
*/
static const GRFIdentifier *GetOverriddenIdentifier(const GRFConfig *c)
{
const LoggedAction *la = &_gamelog_action[_gamelog_actions - 1];
if (la->at != GLAT_LOAD) return c;
const LoggedChange *lcend = &la->change[la->changes];
for (const LoggedChange *lc = la->change; lc != lcend; lc++) {
if (lc->ct == GLCT_GRFCOMPAT && lc->grfcompat.grfid == c->grfid) return &lc->grfcompat;
}
return c;
}
/** /**
* Signal handler used to give a user a more useful report for crashes during * Signal handler used to give a user a more useful report for crashes during
* the savegame loading process; especially when there's problems with the * the savegame loading process; especially when there's problems with the
@ -291,16 +310,17 @@ static void CDECL HandleSavegameLoadCrash(int signum)
"savegame still crashes when all NewGRFs are found you should file a\n" "savegame still crashes when all NewGRFs are found you should file a\n"
"bug report. The missing NewGRFs are:\n"); "bug report. The missing NewGRFs are:\n");
for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) { for (const GRFConfig *c = _grfconfig; c != NULL; c = c->next) {
if (HasBit(c->flags, GCF_COMPATIBLE)) { if (HasBit(c->flags, GCF_COMPATIBLE)) {
const GRFIdentifier *replaced = GetOverriddenIdentifier(c);
char buf[40]; char buf[40];
md5sumToString(buf, lastof(buf), c->md5sum); md5sumToString(buf, lastof(buf), replaced->md5sum);
p += seprintf(p, lastof(buffer), "NewGRF %08X (%s) not found; checksum %s. Tried another NewGRF with same GRF ID\n", BSWAP32(c->grfid), c->filename, buf); p += seprintf(p, lastof(buffer), "NewGRF %08X (checksum %s) not found.\n Loaded NewGRF \"%s\" with same GRF ID instead.\n", BSWAP32(c->grfid), buf, c->filename);
} }
if (c->status == GCS_NOT_FOUND) { if (c->status == GCS_NOT_FOUND) {
char buf[40]; char buf[40];
md5sumToString(buf, lastof(buf), c->md5sum); md5sumToString(buf, lastof(buf), c->md5sum);
p += seprintf(p, lastof(buffer), "NewGRF %08X (%s) not found; checksum %s\n", BSWAP32(c->grfid), c->filename, buf); p += seprintf(p, lastof(buffer), "NewGRF %08X (%s) not found; checksum %s.\n", BSWAP32(c->grfid), c->filename, buf);
} }
} }