Add ScriptStoryPageElementList to get the contents of a page
[openttd/fttd.git] / src / gamelog.cpp
blob0be3ed67001652cb1f7b7d4e2aa86b8de90a753e
1 /* $Id$ */
3 /*
4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8 */
10 /** @file gamelog.cpp Definition of functions used for logging of important changes in the game */
12 #include "stdafx.h"
13 #include "saveload/saveload.h"
14 #include "string_func.h"
15 #include "settings_type.h"
16 #include "gamelog_entries.h"
17 #include "console_func.h"
18 #include "debug.h"
19 #include "date_func.h"
20 #include "rev.h"
22 #include <stdarg.h>
25 Gamelog _gamelog; ///< gamelog
27 /**
28 * Resets and frees all memory allocated - used before loading or starting a new game
30 void GamelogReset()
32 _gamelog.clear();
36 /**
37 * Get some basic information from the given gamelog.
38 * @param gamelog Pointer to the gamelog to extract information from.
39 * @param [out] last_rev NewGRF version from the binary that last saved the savegame.
40 * @param [out] ever_modified Max value of 'modified' from all binaries that ever saved this savegame.
41 * @param [out] removed_newgrfs Set to true if any NewGRFs have been removed.
43 void GamelogInfo(const Gamelog *gamelog, uint32 *last_rev, byte *ever_modified, bool *removed_newgrfs)
45 for (Gamelog::const_iterator entry = gamelog->cbegin(); entry != gamelog->cend(); entry++) {
46 switch ((*entry)->type) {
47 default: break;
49 case GLOG_REVISION: {
50 const GamelogEntryRevision *rev = (GamelogEntryRevision*)entry->get();
51 *last_rev = rev->newgrf;
52 *ever_modified = max(*ever_modified, rev->modified);
53 break;
56 case GLOG_GRFREM:
57 *removed_newgrfs = true;
58 break;
64 GamelogEntry *GamelogEntryByType(uint type)
66 switch (type) {
67 case GLOG_START: return new GamelogEntryStart();
68 case GLOG_STARTED: return new GamelogEntryStarted();
69 case GLOG_LOAD: return new GamelogEntryLoad();
70 case GLOG_LOADED: return new GamelogEntryLoaded();
71 case GLOG_MODE: return new GamelogEntryMode();
72 case GLOG_REVISION: return new GamelogEntryRevision();
73 case GLOG_LEGACYREV: return new GamelogEntryLegacyRev();
74 case GLOG_OLDVER: return new GamelogEntryOldVer();
75 case GLOG_EMERGENCY: return new GamelogEntryEmergency();
76 case GLOG_SETTING: return new GamelogEntrySetting();
77 case GLOG_CHEAT: return new GamelogEntryCheat();
78 case GLOG_GRFBEGIN: return new GamelogEntryGRFBegin();
79 case GLOG_GRFEND: return new GamelogEntryGRFEnd();
80 case GLOG_GRFADD: return new GamelogEntryGRFAdd();
81 case GLOG_GRFREM: return new GamelogEntryGRFRemove();
82 case GLOG_GRFCOMPAT: return new GamelogEntryGRFCompat();
83 case GLOG_GRFPARAM: return new GamelogEntryGRFParam();
84 case GLOG_GRFMOVE: return new GamelogEntryGRFMove();
85 case GLOG_GRFBUG: return new GamelogEntryGRFBug();
86 default: NOT_REACHED();
91 /**
92 * Information about the presence of a Grf at a certain point during gamelog history
93 * Note about missing Grfs:
94 * Changes to missing Grfs are not logged including manual removal of the Grf.
95 * So if the gamelog tells a Grf is missing we do not know whether it was readded or completely removed
96 * at some later point.
98 struct GRFPresence{
99 const GRFConfig *gc; ///< GRFConfig, if known
100 bool was_missing; ///< Grf was missing during some gameload in the past
102 GRFPresence(const GRFConfig *gc) : gc(gc), was_missing(false) {}
104 typedef SmallMap<uint32, GRFPresence> GrfIDMapping;
107 /** Gamelog print buffer */
108 class GamelogPrintBuffer {
109 static const uint LENGTH = 1024; ///< length of buffer for one line of text
111 char buffer[LENGTH]; ///< output buffer
112 uint offset; ///< offset in buffer
114 public:
115 GrfIDMapping grf_names; ///< keep track of this so that inconsistencies can be detected
116 bool in_load; ///< currently printing between GLOG_LOAD and GLOG_LOADED
118 void reset() {
119 this->offset = 0;
122 void append(const char *s, ...) WARN_FORMAT(2, 3) {
123 if (this->offset >= this->LENGTH) return;
125 va_list va;
127 va_start(va, s);
128 this->offset += vsnprintf(this->buffer + this->offset, this->LENGTH - this->offset, s, va);
129 va_end(va);
132 void dump(GamelogPrintProc *proc) {
133 proc(this->buffer);
138 * Prints GRF ID, checksum and filename if found
139 * @param buf The buffer to write to
140 * @param grfid GRF ID
141 * @param md5sum array of md5sum to print, if known
142 * @param gc GrfConfig, if known
144 static void PrintGrfInfo(GamelogPrintBuffer *buf, uint grfid, const uint8 *md5sum, const GRFConfig *gc)
146 char txt[40];
148 if (md5sum != NULL) {
149 md5sumToString(txt, lastof(txt), md5sum);
150 buf->append("GRF ID %08X, checksum %s", BSWAP32(grfid), txt);
151 } else {
152 buf->append("GRF ID %08X", BSWAP32(grfid));
155 if (gc != NULL) {
156 buf->append(", filename: %s (md5sum matches)", gc->filename);
157 } else {
158 gc = FindGRFConfig(grfid, FGCM_ANY);
159 if (gc != NULL) {
160 buf->append(", filename: %s (matches GRFID only)", gc->filename);
161 } else {
162 buf->append(", unknown GRF");
168 * Prints active gamelog
169 * @param proc the procedure to draw with
171 void GamelogPrint(GamelogPrintProc *proc)
173 GamelogPrintBuffer buf;
175 proc("---- gamelog start ----");
177 for (Gamelog::const_iterator entry = _gamelog.cbegin(); entry != _gamelog.cend(); entry++) {
178 buf.reset();
179 (*entry)->Print(&buf);
180 buf.dump(proc);
183 proc("---- gamelog end ----");
187 static void GamelogPrintConsoleProc(const char *s)
189 IConsolePrint(CC_WARNING, s);
192 /** Print the gamelog data to the console. */
193 void GamelogPrintConsole()
195 GamelogPrint(&GamelogPrintConsoleProc);
198 static int _gamelog_print_level = 0; ///< gamelog debug level we need to print stuff
200 static void GamelogPrintDebugProc(const char *s)
202 DEBUG(gamelog, _gamelog_print_level, "%s", s);
206 * Prints gamelog to debug output. Code is executed even when
207 * there will be no output. It is called very seldom, so it
208 * doesn't matter that much. At least it gives more uniform code...
209 * @param level debug level we need to print stuff
211 void GamelogPrintDebug(int level)
213 _gamelog_print_level = level;
214 GamelogPrint(&GamelogPrintDebugProc);
218 /* Gamelog entry types */
221 /* Gamelog entry base class for entries with tick information. */
223 void GamelogEntryTimed::PrependTick(GamelogPrintBuffer *buf) {
224 buf->append("Tick %u: ", (uint)this->tick);
228 /* Gamelog entry for game start */
230 void GamelogEntryStart::Print(GamelogPrintBuffer *buf) {
231 this->PrependTick(buf);
232 buf->append("New game");
235 void GamelogAddStart()
237 _gamelog.append(new GamelogEntryStart());
241 /* Gamelog entry after game start */
243 void GamelogEntryStarted::Print(GamelogPrintBuffer *buf) {
244 buf->append(" Game started");
247 void GamelogAddStarted()
249 _gamelog.append(new GamelogEntryStarted());
253 /** Gamelog entry for game load */
254 void GamelogEntryLoad::Print(GamelogPrintBuffer *buf) {
255 this->PrependTick(buf);
256 buf->append("Load game");
257 buf->in_load = true;
260 void GamelogAddLoad()
262 _gamelog.append(new GamelogEntryLoad());
266 /* Gamelog entry after game load */
268 void GamelogEntryLoaded::Print(GamelogPrintBuffer *buf) {
269 buf->append(" Game loaded");
270 buf->in_load = false;
273 void GamelogAddLoaded()
275 _gamelog.append(new GamelogEntryLoaded());
279 /* Gamelog entry for mode switch between scenario editor and game */
281 void GamelogEntryMode::Print(GamelogPrintBuffer *buf) {
282 buf->append(" New game mode %u, landscape %u",
283 (uint)this->mode, (uint)this->landscape);
287 * Logs a change in game mode (scenario editor or game)
289 void GamelogAddMode()
291 _gamelog.append(new GamelogEntryMode());
295 * Finds last stored game mode or landscape.
296 * Any change is logged
298 void GamelogTestMode()
300 const GamelogEntryMode *mode = NULL;
302 for (Gamelog::const_iterator entry = _gamelog.cbegin(); entry != _gamelog.cend(); entry++) {
303 if ((*entry)->type == GLOG_MODE) {
304 mode = (GamelogEntryMode*)entry->get();
308 if (mode == NULL || mode->mode != _game_mode || mode->landscape != _settings_game.game_creation.landscape) GamelogAddMode();
312 /* Gamelog entry for game revision string */
314 void GamelogEntryRevision::Print(GamelogPrintBuffer *buf) {
315 buf->append(" Revision text changed to %s, savegame version %u, %smodified, newgrf version 0x%08x",
316 this->text, this->slver,
317 (this->modified == 0) ? "not " : (this->modified == 1) ? "maybe " : "",
318 this->newgrf);
322 * Logs a change in game revision
324 void GamelogAddRevision()
326 _gamelog.append(new GamelogEntryRevision());
330 * Finds out if current revision is different than last revision stored in the savegame.
331 * Appends a revision entry when the revision string changed
333 void GamelogTestRevision()
335 const GamelogEntryRevision *rev = NULL;
337 for (Gamelog::const_iterator entry = _gamelog.cbegin(); entry != _gamelog.cend(); entry++) {
338 if ((*entry)->type == GLOG_REVISION) {
339 rev = (GamelogEntryRevision*)entry->get();
343 if (rev == NULL || strcmp(rev->text, _openttd_revision) != 0 ||
344 rev->modified != _openttd_revision_modified ||
345 rev->newgrf != _openttd_newgrf_version) {
346 GamelogAddRevision();
351 /* Gamelog entry for game revision string (legacy) */
353 void GamelogEntryLegacyRev::Print(GamelogPrintBuffer *buf) {
354 buf->append(" Revision text changed to %s (legacy), savegame version %u, %smodified, newgrf version 0x%08x",
355 this->text, this->slver,
356 (this->modified == 0) ? "not " : (this->modified == 1) ? "maybe " : "",
357 this->newgrf);
361 /* Gamelog entry for savegames without log */
363 void GamelogEntryOldVer::Print(GamelogPrintBuffer *buf) {
364 switch (this->type) {
365 case SGT_TTO:
366 buf->append(" Conversion from TTO savegame");
367 break;
369 case SGT_TTD:
370 buf->append(" Conversion from TTD savegame");
371 break;
373 case SGT_TTDP1:
374 case SGT_TTDP2:
375 buf->append(" Conversion from %s TTDP savegame version %u.%u.%u.%u",
376 (this->type == SGT_TTDP1) ? "old" : "new",
377 GB(this->version, 24, 8),
378 GB(this->version, 20, 4),
379 GB(this->version, 16, 4),
380 GB(this->version, 0, 16));
381 break;
383 default: NOT_REACHED();
384 case SGT_OTTD:
385 buf->append(" Conversion from OTTD savegame without gamelog, version %u, %u",
386 GB(this->version, 8, 16), GB(this->version, 0, 8));
387 break;
392 * Logs loading from savegame without gamelog
394 void GamelogOldver(const SavegameTypeVersion *stv)
396 _gamelog.append(new GamelogEntryOldVer(stv));
400 /* Gamelog entry for emergency savegames. */
402 void GamelogEntryEmergency::Print(GamelogPrintBuffer *buf) {
403 this->PrependTick(buf);
404 buf->append("Emergency savegame");
408 * Logs an emergency savegame
410 void GamelogEmergency()
412 _gamelog.append(new GamelogEntryEmergency());
416 * Finds out if current game is a loaded emergency savegame.
418 bool GamelogTestEmergency()
420 for (Gamelog::const_iterator entry = _gamelog.cbegin(); entry != _gamelog.cend(); entry++) {
421 if ((*entry)->type == GLOG_EMERGENCY) return true;
424 return false;
428 /* Gamelog entry for settings change */
430 void GamelogEntrySetting::Print(GamelogPrintBuffer *buf) {
431 this->PrependTick(buf);
432 buf->append("Setting '%s' changed from %d to %d",
433 this->name, this->oldval, this->newval);
437 * Logs change in game settings. Only non-networksafe settings are logged
438 * @param name setting name
439 * @param oldval old setting value
440 * @param newval new setting value
442 void GamelogSetting(const char *name, int32 oldval, int32 newval)
444 _gamelog.append(new GamelogEntrySetting(name, oldval, newval));
448 /* Gamelog entry for cheating */
450 void GamelogEntryCheat::Print(GamelogPrintBuffer *buf) {
451 this->PrependTick(buf);
452 buf->append("Cheat used");
456 /* Gamelog entry for GRF config change begin */
458 void GamelogEntryGRFBegin::Print(GamelogPrintBuffer *buf) {
459 this->PrependTick(buf);
460 buf->append("GRF config change");
464 * Log GRF config change begin
466 void GamelogGRFBegin()
468 _gamelog.append(new GamelogEntryGRFBegin());
472 /* Gamelog entry for GRF config change end */
474 void GamelogEntryGRFEnd::Print(GamelogPrintBuffer *buf) {
475 buf->append(" GRF config change end");
479 * Log GRF config change end
481 void GamelogGRFEnd()
483 _gamelog.append(new GamelogEntryGRFEnd());
488 * Decides if GRF should be logged
489 * @param g grf to determine
490 * @return true iff GRF is not static and is loaded
492 static inline bool IsLoggableGrfConfig(const GRFConfig *g)
494 return !HasBit(g->flags, GCF_STATIC) && g->status != GCS_NOT_FOUND;
498 /* Gamelog entry for GRF addition */
500 void GamelogEntryGRFAdd::Print(GamelogPrintBuffer *buf) {
501 const GRFConfig *gc = FindGRFConfig(this->grf.grfid, FGCM_EXACT, this->grf.md5sum);
502 buf->append(" Added NewGRF: ");
503 PrintGrfInfo(buf, this->grf.grfid, this->grf.md5sum, gc);
504 GrfIDMapping::Pair *gm = buf->grf_names.Find(this->grf.grfid);
505 if (gm != buf->grf_names.End() && !gm->second.was_missing) buf->append(" (inconsistency: already added)");
506 buf->grf_names[this->grf.grfid] = gc;
510 * Logs adding of a GRF
511 * @param newg added GRF
513 void GamelogGRFAdd(const GRFConfig *newg)
515 if (!IsLoggableGrfConfig(newg)) return;
517 _gamelog.append(new GamelogEntryGRFAdd(&newg->ident));
521 * Logs adding of list of GRFs.
522 * Useful when old savegame is loaded or when new game is started
523 * @param newg head of GRF linked list
525 void GamelogGRFAddList(const GRFConfig *newg)
527 for (; newg != NULL; newg = newg->next) {
528 GamelogGRFAdd(newg);
533 /* Gamelog entry for GRF removal */
535 void GamelogEntryGRFRemove::Print(GamelogPrintBuffer *buf) {
536 GrfIDMapping::Pair *gm = buf->grf_names.Find(this->grfid);
537 buf->append(buf->in_load ? " Missing NewGRF: " : " Removed NewGRF: ");
538 PrintGrfInfo(buf, this->grfid, NULL, gm != buf->grf_names.End() ? gm->second.gc : NULL);
539 if (gm == buf->grf_names.End()) {
540 buf->append(" (inconsistency: never added)");
541 } else if (buf->in_load) {
542 /* Missing grfs on load are not removed from the configuration */
543 gm->second.was_missing = true;
544 } else {
545 buf->grf_names.Erase(gm);
550 * Logs removal of a GRF
551 * @param grfid ID of removed GRF
553 void GamelogGRFRemove(uint32 grfid)
555 _gamelog.append(new GamelogEntryGRFRemove(grfid));
559 /* Gamelog entry for compatible GRF load */
561 void GamelogEntryGRFCompat::Print(GamelogPrintBuffer *buf) {
562 const GRFConfig *gc = FindGRFConfig(this->grf.grfid, FGCM_EXACT, this->grf.md5sum);
563 buf->append(" Compatible NewGRF loaded: ");
564 PrintGrfInfo(buf, this->grf.grfid, this->grf.md5sum, gc);
565 if (!buf->grf_names.Contains(this->grf.grfid)) buf->append(" (inconsistency: never added)");
566 buf->grf_names[this->grf.grfid] = gc;
570 * Logs loading compatible GRF
571 * (the same ID, but different MD5 hash)
572 * @param newg new (updated) GRF
574 void GamelogGRFCompatible(const GRFIdentifier *newg)
576 _gamelog.append(new GamelogEntryGRFCompat(newg));
580 /* Gamelog entry for GRF parameter changes */
582 void GamelogEntryGRFParam::Print(GamelogPrintBuffer *buf) {
583 GrfIDMapping::Pair *gm = buf->grf_names.Find(this->grfid);
584 buf->append(" GRF parameter changed: ");
585 PrintGrfInfo(buf, this->grfid, NULL, gm != buf->grf_names.End() ? gm->second.gc : NULL);
586 if (gm == buf->grf_names.End()) buf->append(" (inconsistency: never added)");
590 * Logs change in GRF parameters.
591 * Details about parameters changed are not stored
592 * @param grfid ID of GRF to store
594 static void GamelogGRFParameters(uint32 grfid)
596 _gamelog.append(new GamelogEntryGRFParam(grfid));
600 /* Gamelog entry for GRF order change */
602 void GamelogEntryGRFMove::Print(GamelogPrintBuffer *buf) {
603 GrfIDMapping::Pair *gm = buf->grf_names.Find(this->grfid);
604 buf->append("GRF order changed: %08X moved %d places %s, ",
605 BSWAP32(this->grfid), abs(this->offset), this->offset >= 0 ? "down" : "up");
606 PrintGrfInfo(buf, this->grfid, NULL, gm != buf->grf_names.End() ? gm->second.gc : NULL);
607 if (gm == buf->grf_names.End()) buf->append(" (inconsistency: never added)");
611 * Logs changing GRF order
612 * @param grfid GRF that is moved
613 * @param offset how far it is moved, positive = moved down
615 static void GamelogGRFMove(uint32 grfid, int32 offset)
617 _gamelog.append(new GamelogEntryGRFMove(grfid, offset));
621 /** List of GRFs using array of pointers instead of linked list */
622 struct GRFList {
623 uint n;
624 const GRFConfig *grf[];
628 * Generates GRFList
629 * @param grfc head of GRF linked list
631 static GRFList *GenerateGRFList(const GRFConfig *grfc)
633 uint n = 0;
634 for (const GRFConfig *g = grfc; g != NULL; g = g->next) {
635 if (IsLoggableGrfConfig(g)) n++;
638 GRFList *list = (GRFList*)MallocT<byte>(sizeof(GRFList) + n * sizeof(GRFConfig*));
640 list->n = 0;
641 for (const GRFConfig *g = grfc; g != NULL; g = g->next) {
642 if (IsLoggableGrfConfig(g)) list->grf[list->n++] = g;
645 return list;
649 * Compares two NewGRF lists and logs any change
650 * @param oldc original GRF list
651 * @param newc new GRF list
653 void GamelogGRFUpdate(const GRFConfig *oldc, const GRFConfig *newc)
655 GRFList *ol = GenerateGRFList(oldc);
656 GRFList *nl = GenerateGRFList(newc);
658 uint o = 0, n = 0;
660 while (o < ol->n && n < nl->n) {
661 const GRFConfig *og = ol->grf[o];
662 const GRFConfig *ng = nl->grf[n];
664 if (og->ident.grfid != ng->ident.grfid) {
665 uint oi, ni;
666 for (oi = 0; oi < ol->n; oi++) {
667 if (ol->grf[oi]->ident.grfid == nl->grf[n]->ident.grfid) break;
669 if (oi < o) {
670 /* GRF was moved, this change has been logged already */
671 n++;
672 continue;
674 if (oi == ol->n) {
675 /* GRF couldn't be found in the OLD list, GRF was ADDED */
676 GamelogGRFAdd(nl->grf[n++]);
677 continue;
679 for (ni = 0; ni < nl->n; ni++) {
680 if (nl->grf[ni]->ident.grfid == ol->grf[o]->ident.grfid) break;
682 if (ni < n) {
683 /* GRF was moved, this change has been logged already */
684 o++;
685 continue;
687 if (ni == nl->n) {
688 /* GRF couldn't be found in the NEW list, GRF was REMOVED */
689 GamelogGRFRemove(ol->grf[o++]->ident.grfid);
690 continue;
693 /* o < oi < ol->n
694 * n < ni < nl->n */
695 assert(ni > n && ni < nl->n);
696 assert(oi > o && oi < ol->n);
698 ni -= n; // number of GRFs it was moved downwards
699 oi -= o; // number of GRFs it was moved upwards
701 if (ni >= oi) { // prefer the one that is moved further
702 /* GRF was moved down */
703 GamelogGRFMove(ol->grf[o++]->ident.grfid, ni);
704 } else {
705 GamelogGRFMove(nl->grf[n++]->ident.grfid, -(int)oi);
707 } else {
708 if (memcmp(og->ident.md5sum, ng->ident.md5sum, sizeof(og->ident.md5sum)) != 0) {
709 /* md5sum changed, probably loading 'compatible' GRF */
710 GamelogGRFCompatible(&nl->grf[n]->ident);
713 if (og->num_params != ng->num_params || memcmp(og->param, ng->param, og->num_params * sizeof(og->param[0])) != 0) {
714 GamelogGRFParameters(ol->grf[o]->ident.grfid);
717 o++;
718 n++;
722 while (o < ol->n) GamelogGRFRemove(ol->grf[o++]->ident.grfid); // remaining GRFs were removed ...
723 while (n < nl->n) GamelogGRFAdd (nl->grf[n++]); // ... or added
725 free(ol);
726 free(nl);
730 /* Gamelog entry for GRF bugs */
732 void GamelogEntryGRFBug::Print(GamelogPrintBuffer *buf) {
733 this->PrependTick(buf);
734 GrfIDMapping::Pair *gm = buf->grf_names.Find(this->grfid);
735 switch (this->bug) {
736 default: NOT_REACHED();
737 case GBUG_VEH_LENGTH:
738 buf->append("Rail vehicle changes length outside a depot: GRF ID %08X, internal ID 0x%X", BSWAP32(this->grfid), (uint)this->data);
739 break;
741 PrintGrfInfo(buf, this->grfid, NULL, gm != buf->grf_names.End() ? gm->second.gc : NULL);
742 if (gm == buf->grf_names.End()) buf->append(" (inconsistency: never added)");
746 * Logs triggered GRF bug.
747 * @param grfid ID of problematic GRF
748 * @param bug type of bug, @see enum GRFBugs
749 * @param data additional data
751 static inline void GamelogGRFBug(uint32 grfid, byte bug, uint64 data)
753 _gamelog.append(new GamelogEntryGRFBug(grfid, bug, data));
757 * Logs GRF bug - rail vehicle has different length after reversing.
758 * Ensures this is logged only once for each GRF and engine type
759 * This check takes some time, but it is called pretty seldom, so it
760 * doesn't matter that much (ideally it shouldn't be called at all).
761 * @param grfid the broken NewGRF
762 * @param internal_id the internal ID of whatever's broken in the NewGRF
763 * @return true iff a unique record was done
765 bool GamelogGRFBugReverse(uint32 grfid, uint16 internal_id)
767 for (Gamelog::const_iterator entry = _gamelog.cbegin(); entry != _gamelog.end(); entry++) {
768 if ((*entry)->type == GLOG_GRFBUG) {
769 const GamelogEntryGRFBug *bug = (GamelogEntryGRFBug*)entry->get();
770 if (bug->bug == GBUG_VEH_LENGTH && bug->grfid == grfid && bug->data == internal_id) {
771 return false;
776 GamelogGRFBug(grfid, GBUG_VEH_LENGTH, internal_id);
778 return true;