diff --git a/src/command.cpp b/src/command.cpp index 959610cd28..d72b55931d 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -26,6 +26,8 @@ #include "signal_func.h" #include "core/backup_type.hpp" #include "object_base.h" +#include "newgrf_text.h" +#include "string_func.h" #include "table/strings.h" @@ -735,7 +737,9 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, * test and execution have yielded the same result, * i.e. cost and error state are the same. */ if (!test_and_exec_can_differ) { - assert(res.GetCost() == res2.GetCost() && res.Failed() == res2.Failed()); // sanity check + assert_msg(res.GetCost() == res2.GetCost() && res.Failed() == res2.Failed(), + "Command: cmd: 0x%X (%s), Test: %s, Exec: %s", cmd, GetCommandName(cmd), + res.AllocSummaryMessage(GB(cmd, 16, 16)), res2.AllocSummaryMessage(GB(cmd, 16, 16))); // sanity check } else if (res2.Failed()) { return_dcpi(res2); } @@ -803,3 +807,34 @@ void CommandCost::UseTextRefStack(const GRFFile *grffile, uint num_registers) textref_stack[i] = _temp_store.GetValue(0x100 + i); } } + +char *CommandCost::AllocSummaryMessage(StringID cmd_msg) const +{ + char buf[DRAW_STRING_BUFFER]; + this->WriteSummaryMessage(buf, lastof(buf), cmd_msg); + return stredup(buf, lastof(buf)); +} + +int CommandCost::WriteSummaryMessage(char *buf, char *last, StringID cmd_msg) const +{ + if (this->Succeeded()) { + return seprintf(buf, last, "Success: cost: " OTTD_PRINTF64, (int64) this->GetCost()); + } else { + if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_grffile, this->textref_stack_size, textref_stack); + + char *b = buf; + b += seprintf(b, last, "Failed: cost: " OTTD_PRINTF64, (int64) this->GetCost()); + if (cmd_msg != 0) { + b += seprintf(b, last, " "); + b = GetString(b, cmd_msg, last); + } + if (this->message != INVALID_STRING_ID) { + b += seprintf(b, last, " "); + b = GetString(b, this->message, last); + } + + if (this->textref_stack_size > 0) StopTextRefStackUsage(); + + return b - buf; + } +} diff --git a/src/command_type.h b/src/command_type.h index f318216acc..1d39ee00a9 100644 --- a/src/command_type.h +++ b/src/command_type.h @@ -162,6 +162,21 @@ public: { return !this->success; } + + /** + * @param cmd_msg optional failure string as passed to DoCommand + * @return an allocated string summarising the command result + */ + char *AllocSummaryMessage(StringID cmd_msg = 0) const; + + /** + * Write a string summarising the command result + * @param buf buffer to write to + * @param last last byte in buffer + * @param cmd_msg optional failure string as passed to DoCommand + * @return the number of bytes written + */ + int WriteSummaryMessage(char *buf, char *last, StringID cmd_msg = 0) const; }; /** diff --git a/src/openttd.cpp b/src/openttd.cpp index c149ebbd4d..5e3d2a6c4c 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -123,6 +123,25 @@ void CDECL error(const char *s, ...) abort(); } +void CDECL assert_msg_error(int line, const char *file, const char *expr, const char *str, ...) +{ + va_list va; + char buf[2048]; + + char *b = buf; + b += seprintf(b, lastof(buf), "Assertion failed at line %i of %s: %s\n\t", line, file, expr); + + va_start(va, str); + vseprintf(b, lastof(buf), str, va); + va_end(va); + + ShowOSErrorBox(buf, true); + + /* Set the error message for the crash log and then invoke it. */ + CrashLog::SetErrorMessage(buf); + abort(); +} + /** * Shows some information on the console/a popup box depending on the OS. * @param str the text to show. diff --git a/src/stdafx.h b/src/stdafx.h index 4616212f18..78401402e5 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -446,6 +446,7 @@ assert_compile(SIZE_MAX >= UINT32_MAX); void NORETURN CDECL usererror(const char *str, ...) WARN_FORMAT(1, 2); void NORETURN CDECL error(const char *str, ...) WARN_FORMAT(1, 2); +void NORETURN CDECL assert_msg_error(int line, const char *file, const char *expr, const char *str, ...) WARN_FORMAT(4, 5); #define NOT_REACHED() error("NOT_REACHED triggered at line %i of %s", __LINE__, __FILE__) /* For non-debug builds with assertions enabled use the special assertion handler: @@ -460,6 +461,9 @@ void NORETURN CDECL error(const char *str, ...) WARN_FORMAT(1, 2); /* Asserts are enabled if NDEBUG isn't defined, or if we are using MSVC and WITH_ASSERT is defined. */ #if !defined(NDEBUG) || (defined(_MSC_VER) && defined(WITH_ASSERT)) #define OTTD_ASSERT + #define assert_msg(expression, ...) if (!(expression)) assert_msg_error(__LINE__, __FILE__, #expression, __VA_ARGS__); +#else + #define assert_msg(expression, ...) #endif #if defined(MORPHOS) || defined(__NDS__) || defined(__DJGPP__)