diff --git a/src/3rdparty/squirrel/squirrel/sqvm.cpp b/src/3rdparty/squirrel/squirrel/sqvm.cpp index 0cb66e9c11..5087248017 100644 --- a/src/3rdparty/squirrel/squirrel/sqvm.cpp +++ b/src/3rdparty/squirrel/squirrel/sqvm.cpp @@ -749,7 +749,16 @@ common_call: case OT_NATIVECLOSURE: { bool suspend; _suspended_target = ct_target; - _GUARD(CallNative(_nativeclosure(clo), arg3, ct_stackbase, clo,suspend)); + try { + _GUARD(CallNative(_nativeclosure(clo), arg3, ct_stackbase, clo,suspend)); + } catch (...) { + _suspended = SQTrue; + _suspended_target = ct_target; + _suspended_root = ci->_root; + _suspended_traps = traps; + _suspend_varargs = ci->_vargs; + throw; + } if(suspend){ _suspended = SQTrue; _suspended_target = ct_target; diff --git a/src/ai/ai_instance.cpp b/src/ai/ai_instance.cpp index 68be5fdd6d..6498a0bdbd 100644 --- a/src/ai/ai_instance.cpp +++ b/src/ai/ai_instance.cpp @@ -304,9 +304,17 @@ void AIInstance::GameLoop() AIObject::SetAllowDoCommand(false); /* Run the constructor if it exists. Don't allow any DoCommands in it. */ if (this->engine->MethodExists(*this->instance, "constructor")) { - if (!this->engine->CallMethod(*this->instance, "constructor")) { this->Died(); return; } + if (!this->engine->CallMethod(*this->instance, "constructor", 100000) || this->engine->IsSuspended()) { + if (this->engine->IsSuspended()) AILog::Error("This AI took too long to initialize. AI is not started."); + this->Died(); + return; + } + } + if (!this->CallLoad() || this->engine->IsSuspended()) { + if (this->engine->IsSuspended()) AILog::Error("This AI took too long in the Load function. AI is not started."); + this->Died(); + return; } - if (!this->CallLoad()) { this->Died(); return; } AIObject::SetAllowDoCommand(true); /* Start the AI by calling Start() */ if (!this->engine->CallMethod(*this->instance, "Start", _settings_game.ai.ai_max_opcode_till_suspend) || !this->engine->IsSuspended()) this->Died(); @@ -702,7 +710,7 @@ bool AIInstance::CallLoad() /* Call the AI load function. sq_call removes the arguments (but not the * function pointer) from the stack. */ - if (SQ_FAILED(sq_call(vm, 3, SQFalse, SQFalse))) return false; + if (SQ_FAILED(sq_call(vm, 3, SQFalse, SQFalse, 100000))) return false; /* Pop 1) The version, 2) the savegame data, 3) the object instance, 4) the function pointer. */ sq_pop(vm, 4); diff --git a/src/ai/api/ai_rail.cpp b/src/ai/api/ai_rail.cpp index b067b09040..519d23162a 100644 --- a/src/ai/api/ai_rail.cpp +++ b/src/ai/api/ai_rail.cpp @@ -110,7 +110,7 @@ { if (!IsRailStationTile(tile)) return RAILTRACK_INVALID; - return (RailTrack)::GetRailStationTrack(tile); + return (RailTrack)::GetRailStationTrackBits(tile); } /* static */ bool AIRail::BuildRailDepot(TileIndex tile, TileIndex front) diff --git a/src/script/squirrel.cpp b/src/script/squirrel.cpp index f31b813da3..6737fd3ef3 100644 --- a/src/script/squirrel.cpp +++ b/src/script/squirrel.cpp @@ -209,7 +209,7 @@ bool Squirrel::CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT if (ret != NULL) sq_getstackobj(vm, -1, ret); /* Reset the top, but don't do so for the AI main function, as we need * a correct stack when resuming. */ - if (suspend == -1) sq_settop(this->vm, top); + if (!this->IsSuspended()) sq_settop(this->vm, top); /* Restore the return-value location. */ this->vm->_suspended_target = last_target; diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index ee47504565..954525617c 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -1493,7 +1493,7 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin static Vehicle *ClearRoadStopStatusEnum(Vehicle *v, void *) { - if (v->type == VEH_ROAD) ClrBit(v->u.road.state, RVS_IN_DT_ROAD_STOP); + if (v->type == VEH_ROAD) v->u.road.state &= RVSB_ROAD_STOP_TRACKDIR_MASK; return NULL; } diff --git a/src/station_map.h b/src/station_map.h index e706dd2a65..b49fb40f4a 100644 --- a/src/station_map.h +++ b/src/station_map.h @@ -202,6 +202,11 @@ static inline Track GetRailStationTrack(TileIndex t) return AxisToTrack(GetRailStationAxis(t)); } +static inline TrackBits GetRailStationTrackBits(TileIndex t) +{ + return AxisToTrackBits(GetRailStationAxis(t)); +} + static inline bool IsCompatibleTrainStationTile(TileIndex t1, TileIndex t2) { assert(IsRailwayStationTile(t2)); @@ -245,7 +250,7 @@ static inline void SetRailwayStationReservation(TileIndex t, bool b) */ static inline TrackBits GetRailStationReservation(TileIndex t) { - return GetRailwayStationReservation(t) ? AxisToTrackBits(GetRailStationAxis(t)) : TRACK_BIT_NONE; + return GetRailwayStationReservation(t) ? GetRailStationTrackBits(t) : TRACK_BIT_NONE; } diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index af3f9d5ac5..ea04b24ae3 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -167,6 +167,10 @@ public: void Draw(int x, int y, uint width, uint height, bool sel, int bg_colour) const { CompanyID company = (CompanyID)result; + + /* It's possible the company is deleted while the dropdown is open */ + if (!IsValidCompanyID(company)) return; + DrawCompanyIcon(company, x + 2, y + 1); SetDParam(0, company);