mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-05 22:04:57 +00:00
(svn r19708) -Add: NewGRF "debugging" window and data tables; should be a useful tool for NewGRF developers to get some insights into the value of some variables
This commit is contained in:
parent
1da0086a45
commit
21883a84d7
@ -1183,6 +1183,10 @@
|
||||
RelativePath=".\..\src\newgrf_config.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\newgrf_debug.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\newgrf_engine.h"
|
||||
>
|
||||
@ -1851,6 +1855,10 @@
|
||||
RelativePath=".\..\src\network\network_gui.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\newgrf_debug_gui.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\newgrf_gui.cpp"
|
||||
>
|
||||
|
@ -1180,6 +1180,10 @@
|
||||
RelativePath=".\..\src\newgrf_config.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\newgrf_debug.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\newgrf_engine.h"
|
||||
>
|
||||
@ -1848,6 +1852,10 @@
|
||||
RelativePath=".\..\src\network\network_gui.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\newgrf_debug_gui.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\newgrf_gui.cpp"
|
||||
>
|
||||
|
@ -205,6 +205,7 @@ newgrf_canal.h
|
||||
newgrf_cargo.h
|
||||
newgrf_commons.h
|
||||
newgrf_config.h
|
||||
newgrf_debug.h
|
||||
newgrf_engine.h
|
||||
newgrf_generic.h
|
||||
newgrf_house.h
|
||||
@ -389,6 +390,7 @@ music_gui.cpp
|
||||
network/network_chat_gui.cpp
|
||||
network/network_content_gui.cpp
|
||||
network/network_gui.cpp
|
||||
newgrf_debug_gui.cpp
|
||||
newgrf_gui.cpp
|
||||
news_gui.cpp
|
||||
order_gui.cpp
|
||||
|
@ -2365,6 +2365,16 @@ STR_NEWGRF_ADD_FILE_TOOLTIP :{BLACK}Add the
|
||||
STR_NEWGRF_ADD_RESCAN_FILES :{BLACK}Rescan files
|
||||
STR_NEWGRF_ADD_RESCAN_FILES_TOOLTIP :{BLACK}Update the list of available NewGRF files
|
||||
|
||||
# NewGRF inspect window
|
||||
STR_NEWGRF_INSPECT_CAPTION :{WHITE}Inspect - {STRING5}
|
||||
STR_NEWGRF_INSPECT_PARENT_BUTTON :{BLACK}Parent
|
||||
STR_NEWGRF_INSPECT_PARENT_TOOLTIP :{BLACK}Inspect the object of the parent scope
|
||||
|
||||
STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT :{STRING1} at {HEX}
|
||||
STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE :Rail type
|
||||
|
||||
STR_NEWGRF_INSPECT_QUERY_CAPTION :{WHITE}NewGRF variable 60+x parameter (hexadecimal)
|
||||
|
||||
# NewGRF (self) generated warnings/errors
|
||||
STR_NEWGRF_ERROR_MSG_INFO :{SILVER}{RAW_STRING}
|
||||
STR_NEWGRF_ERROR_MSG_WARNING :{RED}Warning: {SILVER}{RAW_STRING}
|
||||
|
@ -60,6 +60,11 @@ enum GrfSpecFeature {
|
||||
GSF_RAILTYPES,
|
||||
GSF_AIRPORTTILES,
|
||||
GSF_END,
|
||||
|
||||
GSF_FAKE_TOWNS = GSF_END, ///< Fake town GrfSpecFeature for NewGRF debugging (parent scope)
|
||||
GSF_FAKE_END, ///< End of the fake features
|
||||
|
||||
GSF_INVALID = 0xFF ///< An invalid spec feature
|
||||
};
|
||||
|
||||
static const uint32 INVALID_GRFID = 0xFFFFFFFF;
|
||||
|
60
src/newgrf_debug.h
Normal file
60
src/newgrf_debug.h
Normal file
@ -0,0 +1,60 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* 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.
|
||||
* 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.
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/** @file newgrf_debug.h Functions/types related to NewGRF debugging. */
|
||||
|
||||
#ifndef NEWGRF_DEBUG_H
|
||||
#define NEWGRF_DEBUG_H
|
||||
|
||||
#include "newgrf.h"
|
||||
|
||||
/**
|
||||
* Can we inspect the data given a certain feature and index.
|
||||
* The index is normally an in-game location/identifier, such
|
||||
* as a TileIndex or an IndustryID depending on the feature
|
||||
* we want to inspect.
|
||||
* @param feature The feature we want to inspect.
|
||||
* @param index The index/identifier of the feature to inspect.
|
||||
* @return true if there is something to show.
|
||||
*/
|
||||
bool IsNewGRFInspectable(GrfSpecFeature feature, uint index);
|
||||
|
||||
/**
|
||||
* Show the inspect window for a given feature and index.
|
||||
* The index is normally an in-game location/identifier, such
|
||||
* as a TileIndex or an IndustryID depending on the feature
|
||||
* we want to inspect.
|
||||
* @param feature The feature we want to inspect.
|
||||
* @param index The index/identifier of the feature to inspect.
|
||||
*/
|
||||
void ShowNewGRFInspectWindow(GrfSpecFeature feature, uint index);
|
||||
|
||||
/**
|
||||
* Delete inspect window for a given feature and index.
|
||||
* The index is normally an in-game location/identifier, such
|
||||
* as a TileIndex or an IndustryID depending on the feature
|
||||
* we want to inspect.
|
||||
* @param feature The feature we want to delete the window for.
|
||||
* @param index The index/identifier of the feature to delete.
|
||||
*/
|
||||
void DeleteNewGRFInspectWindow(GrfSpecFeature feature, uint index);
|
||||
|
||||
/**
|
||||
* Get the GrfSpecFeature associated with the tile.
|
||||
* @return the GrfSpecFeature.
|
||||
*/
|
||||
GrfSpecFeature GetGrfSpecFeature(TileIndex tile);
|
||||
|
||||
/**
|
||||
* Get the GrfSpecFeature associated with the vehicle.
|
||||
* @return the GrfSpecFeature.
|
||||
*/
|
||||
GrfSpecFeature GetGrfSpecFeature(VehicleType type);
|
||||
|
||||
#endif /* NEWGRF_DEBUG_H */
|
530
src/newgrf_debug_gui.cpp
Normal file
530
src/newgrf_debug_gui.cpp
Normal file
@ -0,0 +1,530 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* 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.
|
||||
* 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.
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/** @file newgrf_debug_gui.cpp GUIs for debugging NewGRFs. */
|
||||
|
||||
#include "stdafx.h"
|
||||
#include <stdarg.h>
|
||||
#include "window_gui.h"
|
||||
#include "window_func.h"
|
||||
#include "gfx_func.h"
|
||||
#include "string_func.h"
|
||||
#include "strings_func.h"
|
||||
#include "textbuf_gui.h"
|
||||
#include "tunnelbridge_map.h"
|
||||
|
||||
#include "engine_base.h"
|
||||
#include "house.h"
|
||||
#include "industry.h"
|
||||
#include "rail.h"
|
||||
#include "station_base.h"
|
||||
#include "town.h"
|
||||
#include "vehicle_base.h"
|
||||
|
||||
#include "newgrf_airporttiles.h"
|
||||
#include "newgrf_debug.h"
|
||||
#include "newgrf_spritegroup.h"
|
||||
#include "newgrf_station.h"
|
||||
#include "newgrf_town.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
/**
|
||||
* Get the feature index related to the window number.
|
||||
* @param window_number The window to get the feature index from.
|
||||
* @return the feature index
|
||||
*/
|
||||
static inline uint GetFeatureIndex(uint window_number)
|
||||
{
|
||||
return GB(window_number, 0, 24);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the window number for the inspect window given a
|
||||
* feature and index.
|
||||
* @param feature The feature we want to inspect.
|
||||
* @param index The index/identifier of the feature to inspect.
|
||||
* @return the InspectWindow (Window)Number
|
||||
*/
|
||||
static inline uint GetInspectWindowNumber(GrfSpecFeature feature, uint index)
|
||||
{
|
||||
assert((index >> 24) == 0);
|
||||
return (feature << 24) | index;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of a property to show. This is used to
|
||||
* provide an appropriate represenation in the GUI.
|
||||
*/
|
||||
enum NIType {
|
||||
NIT_INT, ///< The property is a simple integer
|
||||
NIT_CARGO, ///< The property is a cargo
|
||||
};
|
||||
|
||||
/** Representation of the data from a NewGRF property. */
|
||||
struct NIProperty {
|
||||
const char *name; ///< A (human readable) name for the property
|
||||
ptrdiff_t offset; ///< Offset of the variable in the class
|
||||
byte read_size; ///< Number of bytes (i.e. byte, word, dword etc)
|
||||
byte prop; ///< The number of the property
|
||||
byte type;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Representation of the available callbacks with
|
||||
* information on when they actually apply.
|
||||
*/
|
||||
struct NICallback {
|
||||
const char *name; ///< The human readable name of the callback
|
||||
ptrdiff_t offset; ///< Offset of the variable in the class
|
||||
byte read_size; ///< The number of bytes (i.e. byte, word, dword etc) to read
|
||||
byte cb_bit; ///< The bit that needs to be set for this callback to be enabled
|
||||
uint16 cb_id; ///< The number of the callback
|
||||
};
|
||||
/** Mask to show no bit needs to be enabled for the callback. */
|
||||
static const int CBM_NO_BIT = UINT8_MAX;
|
||||
|
||||
/** Representation on the NewGRF variables. */
|
||||
struct NIVariable {
|
||||
const char *name;
|
||||
byte var;
|
||||
};
|
||||
|
||||
/** Helper class to wrap some functionality/queries in. */
|
||||
class NIHelper {
|
||||
public:
|
||||
/**
|
||||
* Is the item with the given index inspectable?
|
||||
* @param index the index to check.
|
||||
* @return true iff the index is inspectable.
|
||||
*/
|
||||
virtual bool IsInspectable(uint index) const = 0;
|
||||
|
||||
/**
|
||||
* Get the parent "window_number" of a given instance.
|
||||
* @param index the instance to get the parent for.
|
||||
* @return the parent's window_number or UINT32_MAX if there is none.
|
||||
*/
|
||||
virtual uint GetParent(uint index) const = 0;
|
||||
|
||||
/**
|
||||
* Get the instance given an index.
|
||||
* @param index the index to get the instance for.
|
||||
* @return the instance.
|
||||
*/
|
||||
virtual const void *GetInstance(uint index) const = 0;
|
||||
|
||||
/**
|
||||
* Get (NewGRF) specs given an index.
|
||||
* @param index the index to get the specs for for.
|
||||
* @return the specs.
|
||||
*/
|
||||
virtual const void *GetSpec(uint index) const = 0;
|
||||
|
||||
/**
|
||||
* Set the string parameters to write the right data for a STRINGn.
|
||||
* @param index the index to get the string parameters for.
|
||||
*/
|
||||
virtual void SetStringParameters(uint index) const = 0;
|
||||
|
||||
/**
|
||||
* Resolve (action2) variable for a given index.
|
||||
* @param index The (instance) index to resolve the variable for.
|
||||
* @param var The variable to actually resolve.
|
||||
* @param param The varaction2 0x60+x parameter to pass.
|
||||
* @param avail Return whether the variable is available.
|
||||
* @return The resolved variable's value.
|
||||
*/
|
||||
virtual uint Resolve(uint index, uint var, uint param, bool *avail) const
|
||||
{
|
||||
ResolverObject ro;
|
||||
memset(&ro, 0, sizeof(ro));
|
||||
this->Resolve(&ro, index);
|
||||
return ro.GetVariable(&ro, var, param, avail);
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Actually execute the real resolving for a given (instance) index.
|
||||
* @param ro The resolver object to fill with everything
|
||||
* needed to be able to resolve a variable.
|
||||
* @param index The (instance) index of the to-be-resolved variable.
|
||||
*/
|
||||
virtual void Resolve(ResolverObject *ro, uint index) const {}
|
||||
|
||||
/**
|
||||
* Helper to make setting the strings easier.
|
||||
* @param string the string to actually draw.
|
||||
* @param index the (instance) index for the string.
|
||||
*/
|
||||
void SetSimpleStringParameters(StringID string, uint32 index) const
|
||||
{
|
||||
SetDParam(0, string);
|
||||
SetDParam(1, index);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper to make setting the strings easier for objects at a specific tile.
|
||||
* @param string the string to draw the object's name
|
||||
* @param index the (instance) index for the string.
|
||||
* @param tile the tile the object is at
|
||||
*/
|
||||
void SetObjectAtStringParameters(StringID string, uint32 index, TileIndex tile) const
|
||||
{
|
||||
SetDParam(0, STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT);
|
||||
SetDParam(1, string);
|
||||
SetDParam(2, index);
|
||||
SetDParam(3, tile);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Container for all information for a given feature. */
|
||||
struct NIFeature {
|
||||
const NIProperty *properties; ///< The properties associated with this feature.
|
||||
const NICallback *callbacks; ///< The callbacks associated with this feature.
|
||||
const NIVariable *variables; ///< The variables associated with this feature.
|
||||
const NIHelper *helper; ///< The class container all helper functions.
|
||||
uint psa_size; ///< The size of the persistent storage in indices.
|
||||
size_t psa_offset; ///< Offset to the array in the PSA.
|
||||
};
|
||||
|
||||
/* Load all the NewGRF debug data; externalised as it is just a huge bunch of tables. */
|
||||
#include "table/newgrf_debug_data.h"
|
||||
|
||||
/**
|
||||
* Get the NIFeature related to the window number.
|
||||
* @param window_number The window to get the NIFeature for.
|
||||
* @return the NIFeature, or NULL is there isn't one.
|
||||
*/
|
||||
static inline const NIFeature *GetFeature(uint window_number)
|
||||
{
|
||||
byte idx = GB(window_number, 24, 8);
|
||||
return idx < GSF_FAKE_END ? _nifeatures[idx] : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the NIHelper related to the window number.
|
||||
* @param window_number The window to get the NIHelper for.
|
||||
* @pre GetFeature(window_number) != NULL
|
||||
* @return the NIHelper
|
||||
*/
|
||||
static inline const NIHelper *GetFeatureHelper(uint window_number)
|
||||
{
|
||||
return GetFeature(window_number)->helper;
|
||||
}
|
||||
|
||||
|
||||
/** Widget numbers of settings window */
|
||||
enum NewGRFInspectWidgets {
|
||||
NIW_CAPTION, ///< The caption bar ofcourse
|
||||
NIW_PARENT, ///< Inspect the parent
|
||||
NIW_MAINPANEL, ///< Panel widget containing the actual data
|
||||
NIW_SCROLLBAR, ///< Scrollbar
|
||||
};
|
||||
|
||||
/** Window used for inspecting NewGRFs. */
|
||||
struct NewGRFInspectWindow : Window {
|
||||
static const int LEFT_OFFSET = 5; ///< Position of left edge
|
||||
static const int RIGHT_OFFSET = 5; ///< Position of right edge
|
||||
static const int TOP_OFFSET = 5; ///< Position of top edge
|
||||
static const int BOTTOM_OFFSET = 5; ///< Position of bottom edge
|
||||
|
||||
/** The value for the variable 60 parameters. */
|
||||
static byte var60params[0x20];
|
||||
|
||||
/** The currently editted parameter, to update the right one. */
|
||||
byte current_edit_param;
|
||||
|
||||
/**
|
||||
* Check whether the given variable has a parameter.
|
||||
* @param variable the variable to check.
|
||||
* @return true iff the variable has a parameter.
|
||||
*/
|
||||
static bool HasVariableParameter(uint variable)
|
||||
{
|
||||
return IsInsideBS(variable, 0x60, 0x20);
|
||||
}
|
||||
|
||||
NewGRFInspectWindow(const WindowDesc *desc, WindowNumber wno) : Window()
|
||||
{
|
||||
this->InitNested(desc, wno);
|
||||
|
||||
this->vscroll.SetCount(0);
|
||||
this->SetWidgetDisabledState(NIW_PARENT, GetFeatureHelper(this->window_number)->GetParent(GetFeatureIndex(this->window_number)) == UINT32_MAX);
|
||||
}
|
||||
|
||||
virtual void SetStringParameters(int widget) const
|
||||
{
|
||||
if (widget != NIW_CAPTION) return;
|
||||
|
||||
GetFeatureHelper(this->window_number)->SetStringParameters(GetFeatureIndex(this->window_number));
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
{
|
||||
if (widget != NIW_MAINPANEL) return;
|
||||
|
||||
resize->height = max(11, FONT_HEIGHT_NORMAL + 1);
|
||||
resize->width = 1;
|
||||
|
||||
size->height = 5 * resize->height + TOP_OFFSET + BOTTOM_OFFSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to draw a string (line) in the window.
|
||||
* @param r The (screen) rectangle we must draw within
|
||||
* @param offset The offset (in lines) we want to draw for
|
||||
* @param format The format string
|
||||
*/
|
||||
void WARN_FORMAT(4, 5) DrawString(const Rect &r, int offset, const char *format, ...) const
|
||||
{
|
||||
char buf[1024];
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
vsnprintf(buf, lengthof(buf), format, va);
|
||||
va_end(va);
|
||||
|
||||
offset -= this->vscroll.GetPosition();
|
||||
if (offset < 0 || offset >= this->vscroll.GetCapacity()) return;
|
||||
|
||||
::DrawString(r.left + LEFT_OFFSET, r.right + RIGHT_OFFSET, r.top + TOP_OFFSET + (offset * this->resize.step_height), buf, TC_BLACK);
|
||||
}
|
||||
|
||||
virtual void DrawWidget(const Rect &r, int widget) const
|
||||
{
|
||||
if (widget != NIW_MAINPANEL) return;
|
||||
|
||||
uint index = GetFeatureIndex(this->window_number);
|
||||
const NIFeature *nif = GetFeature(this->window_number);
|
||||
const NIHelper *nih = nif->helper;
|
||||
const void *base = nih->GetInstance(index);
|
||||
const void *base_spec = nih->GetSpec(index);
|
||||
|
||||
uint i = 0;
|
||||
if (nif->variables != NULL) {
|
||||
this->DrawString(r, i++, "Variables:");
|
||||
for (const NIVariable *niv = nif->variables; niv->name != NULL; niv++) {
|
||||
bool avail = true;
|
||||
uint param = HasVariableParameter(niv->var) ? NewGRFInspectWindow::var60params[niv->var - 0x60] : 0;
|
||||
uint value = nih->Resolve(index, niv->var, param, &avail);
|
||||
|
||||
if (!avail) continue;
|
||||
|
||||
if (HasVariableParameter(niv->var)) {
|
||||
this->DrawString(r, i++, " %02x[%02x]: %08x (%s)", niv->var, param, value, niv->name);
|
||||
} else {
|
||||
this->DrawString(r, i++, " %02x: %08x (%s)", niv->var, value, niv->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nif->psa_size != 0) {
|
||||
this->DrawString(r, i++, "Persistent storage:");
|
||||
assert(nif->psa_size % 4 == 0);
|
||||
int32 *psa = (int32*)((byte*)base + nif->psa_offset);
|
||||
for (uint j = 0; j < nif->psa_size; j += 4, psa += 4) {
|
||||
this->DrawString(r, i++, " %i: %i %i %i %i", j, psa[0], psa[1], psa[2], psa[3]);
|
||||
}
|
||||
}
|
||||
|
||||
if (nif->properties != NULL) {
|
||||
this->DrawString(r, i++, "Properties:");
|
||||
for (const NIProperty *nip = nif->properties; nip->name != NULL; nip++) {
|
||||
void *ptr = (byte*)base + nip->offset;
|
||||
uint value;
|
||||
switch (nip->read_size) {
|
||||
case 1: value = *(uint8 *)ptr; break;
|
||||
case 2: value = *(uint16 *)ptr; break;
|
||||
case 4: value = *(uint32 *)ptr; break;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
|
||||
StringID string;
|
||||
SetDParam(0, value);
|
||||
switch (nip->type) {
|
||||
case NIT_INT:
|
||||
string = STR_JUST_INT;
|
||||
break;
|
||||
|
||||
case NIT_CARGO:
|
||||
string = value != INVALID_CARGO ? CargoSpec::Get(value)->name : STR_QUANTITY_N_A;
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
|
||||
char buffer[64];
|
||||
GetString(buffer, string, lastof(buffer));
|
||||
this->DrawString(r, i++, " %02x: %s (%s)", nip->prop, buffer, nip->name);
|
||||
}
|
||||
}
|
||||
|
||||
if (nif->callbacks != NULL) {
|
||||
this->DrawString(r, i++, "Callbacks:");
|
||||
for (const NICallback *nic = nif->callbacks; nic->name != NULL; nic++) {
|
||||
if (nic->cb_bit != CBM_NO_BIT) {
|
||||
void *ptr = (byte*)base_spec + nic->offset;
|
||||
uint value;
|
||||
switch (nic->read_size) {
|
||||
case 1: value = *(uint8 *)ptr; break;
|
||||
case 2: value = *(uint16 *)ptr; break;
|
||||
case 4: value = *(uint32 *)ptr; break;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
|
||||
if (!HasBit(value, nic->cb_bit)) continue;
|
||||
this->DrawString(r, i++, " %03x: %s", nic->cb_id, nic->name);
|
||||
} else {
|
||||
this->DrawString(r, i++, " %03x: %s (unmasked)", nic->cb_id, nic->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Not nice and certainly a hack, but it beats duplicating
|
||||
* this whole function just to count the actual number of
|
||||
* elements. Especially because they need to be redrawn. */
|
||||
const_cast<NewGRFInspectWindow*>(this)->vscroll.SetCount(i);
|
||||
}
|
||||
|
||||
virtual void OnPaint()
|
||||
{
|
||||
this->DrawWidgets();
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
{
|
||||
switch (widget) {
|
||||
case NIW_PARENT: {
|
||||
uint index = GetFeatureHelper(this->window_number)->GetParent(GetFeatureIndex(this->window_number));
|
||||
::ShowNewGRFInspectWindow((GrfSpecFeature)GB(index, 24, 8), GetFeatureIndex(index));
|
||||
} break;
|
||||
|
||||
case NIW_MAINPANEL: {
|
||||
/* Does this feature have variables? */
|
||||
const NIFeature *nif = GetFeature(this->window_number);
|
||||
if (nif->variables == NULL) return;
|
||||
|
||||
/* Get the line, make sure it's within the boundaries. */
|
||||
int line = (pt.y - this->GetWidget<NWidgetBase>(NIW_MAINPANEL)->pos_y - TOP_OFFSET) / this->resize.step_height;
|
||||
if (line >= this->vscroll.GetCapacity()) return;
|
||||
line += this->vscroll.GetPosition();
|
||||
|
||||
/* Find the variable related to the line */
|
||||
for (const NIVariable *niv = nif->variables; niv->name != NULL; niv++, line--) {
|
||||
if (line != 1) continue; // 1 because of the "Variables:" line
|
||||
|
||||
if (!HasVariableParameter(niv->var)) break;
|
||||
|
||||
this->current_edit_param = niv->var;
|
||||
ShowQueryString(STR_EMPTY, STR_NEWGRF_INSPECT_QUERY_CAPTION, 3, 100, this, CS_HEXADECIMAL, QSF_NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnQueryTextFinished(char *str)
|
||||
{
|
||||
if (StrEmpty(str)) return;
|
||||
|
||||
NewGRFInspectWindow::var60params[this->current_edit_param - 0x60] = strtol(str, NULL, 16);
|
||||
this->SetDirty();
|
||||
}
|
||||
|
||||
virtual void OnResize()
|
||||
{
|
||||
this->vscroll.SetCapacityFromWidget(this, NIW_MAINPANEL, TOP_OFFSET + BOTTOM_OFFSET);
|
||||
}
|
||||
};
|
||||
|
||||
/* static */ byte NewGRFInspectWindow::var60params[0x20] = { 0 }; // Use spec to have 0s in whole array
|
||||
|
||||
static const NWidgetPart _nested_newgrf_inspect_widgets[] = {
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
|
||||
NWidget(WWT_CAPTION, COLOUR_GREY, NIW_CAPTION), SetDataTip(STR_NEWGRF_INSPECT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, NIW_PARENT), SetDataTip(STR_NEWGRF_INSPECT_PARENT_BUTTON, STR_NEWGRF_INSPECT_PARENT_TOOLTIP),
|
||||
NWidget(WWT_SHADEBOX, COLOUR_GREY),
|
||||
NWidget(WWT_STICKYBOX, COLOUR_GREY),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_PANEL, COLOUR_GREY, NIW_MAINPANEL), SetMinimalSize(300, 0), EndContainer(),
|
||||
NWidget(NWID_VERTICAL),
|
||||
NWidget(WWT_SCROLLBAR, COLOUR_GREY, NIW_SCROLLBAR),
|
||||
NWidget(WWT_RESIZEBOX, COLOUR_GREY),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
};
|
||||
|
||||
static const WindowDesc _newgrf_inspect_desc(
|
||||
WDP_AUTO, 400, 300,
|
||||
WC_NEWGRF_INSPECT, WC_NONE,
|
||||
WDF_UNCLICK_BUTTONS,
|
||||
_nested_newgrf_inspect_widgets, lengthof(_nested_newgrf_inspect_widgets)
|
||||
);
|
||||
|
||||
void ShowNewGRFInspectWindow(GrfSpecFeature feature, uint index)
|
||||
{
|
||||
if (!IsNewGRFInspectable(feature, index)) return;
|
||||
|
||||
WindowNumber wno = GetInspectWindowNumber(feature, index);
|
||||
AllocateWindowDescFront<NewGRFInspectWindow>(&_newgrf_inspect_desc, wno);
|
||||
}
|
||||
|
||||
void DeleteNewGRFInspectWindow(GrfSpecFeature feature, uint index)
|
||||
{
|
||||
if (feature == GSF_INVALID) return;
|
||||
|
||||
WindowNumber wno = GetInspectWindowNumber(feature, index);
|
||||
DeleteWindowById(WC_NEWGRF_INSPECT, wno);
|
||||
|
||||
/* Reinitialise the land information window to remove the "debug" sprite if needed. */
|
||||
Window *w = FindWindowById(WC_LAND_INFO, 0);
|
||||
if (w != NULL) w->ReInit();
|
||||
}
|
||||
|
||||
bool IsNewGRFInspectable(GrfSpecFeature feature, uint index)
|
||||
{
|
||||
const NIFeature *nif = GetFeature(GetInspectWindowNumber(feature, index));
|
||||
if (nif == NULL) return false;
|
||||
return nif->helper->IsInspectable(index);
|
||||
}
|
||||
|
||||
GrfSpecFeature GetGrfSpecFeature(TileIndex tile)
|
||||
{
|
||||
switch (GetTileType(tile)) {
|
||||
default: return GSF_INVALID;
|
||||
case MP_RAILWAY: return GSF_RAILTYPES;
|
||||
case MP_ROAD: return IsLevelCrossing(tile) ? GSF_RAILTYPES : GSF_INVALID;
|
||||
case MP_HOUSE: return GSF_HOUSES;
|
||||
case MP_INDUSTRY: return GSF_INDUSTRYTILES;
|
||||
|
||||
case MP_STATION:
|
||||
switch (GetStationType(tile)) {
|
||||
case STATION_RAIL: return GSF_STATIONS;
|
||||
case STATION_AIRPORT: return GSF_AIRPORTTILES;
|
||||
default: return GSF_INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GrfSpecFeature GetGrfSpecFeature(VehicleType type)
|
||||
{
|
||||
switch (type) {
|
||||
case VEH_TRAIN: return GSF_TRAINS;
|
||||
case VEH_ROAD: return GSF_ROADVEHICLES;
|
||||
case VEH_SHIP: return GSF_SHIPS;
|
||||
case VEH_AIRCRAFT: return GSF_AIRCRAFT;
|
||||
default: return GSF_INVALID;
|
||||
}
|
||||
}
|
426
src/table/newgrf_debug_data.h
Normal file
426
src/table/newgrf_debug_data.h
Normal file
@ -0,0 +1,426 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* 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.
|
||||
* 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.
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/** @file newgrf_debug_data.cpp Data 'tables' for NewGRF debugging. */
|
||||
|
||||
/* Helper for filling property tables */
|
||||
#define NIP(prop, base, variable, type, name) { name, cpp_offsetof(base, variable), cpp_sizeof(base, variable), prop, type }
|
||||
#define NIP_END() { NULL, 0, 0, 0, 0 }
|
||||
|
||||
/* Helper for filling callback tables */
|
||||
#define NIC(cb_id, base, variable, bit) { #cb_id, cpp_offsetof(base, variable), cpp_sizeof(base, variable), bit, cb_id }
|
||||
#define NIC_END() { NULL, 0, 0, 0, 0 }
|
||||
|
||||
/* Helper for filling variable tables */
|
||||
#define NIV(var, name) { name, var }
|
||||
#define NIV_END() { NULL, 0 }
|
||||
|
||||
|
||||
/*** NewGRF Vehicles ***/
|
||||
|
||||
#define NICV(cb_id, bit) NIC(cb_id, Engine, info.callback_mask, bit)
|
||||
static const NICallback _nic_vehicles[] = {
|
||||
NICV(CBID_TRAIN_WAGON_POWER, CBM_TRAIN_WAGON_POWER),
|
||||
NICV(CBID_VEHICLE_LENGTH, CBM_VEHICLE_LENGTH),
|
||||
NICV(CBID_VEHICLE_LOAD_AMOUNT, CBM_VEHICLE_LOAD_AMOUNT),
|
||||
NICV(CBID_VEHICLE_REFIT_CAPACITY, CBM_VEHICLE_REFIT_CAPACITY),
|
||||
NICV(CBID_VEHICLE_ARTIC_ENGINE, CBM_VEHICLE_ARTIC_ENGINE),
|
||||
NICV(CBID_VEHICLE_CARGO_SUFFIX, CBM_VEHICLE_CARGO_SUFFIX),
|
||||
NICV(CBID_TRAIN_ALLOW_WAGON_ATTACH, CBM_NO_BIT),
|
||||
NICV(CBID_VEHICLE_ADDITIONAL_TEXT, CBM_NO_BIT),
|
||||
NICV(CBID_VEHICLE_COLOUR_MAPPING, CBM_VEHICLE_COLOUR_REMAP),
|
||||
NICV(CBID_VEHICLE_START_STOP_CHECK, CBM_NO_BIT),
|
||||
NICV(CBID_VEHICLE_32DAY_CALLBACK, CBM_NO_BIT),
|
||||
NICV(CBID_VEHICLE_SOUND_EFFECT, CBM_VEHICLE_SOUND_EFFECT),
|
||||
NICV(CBID_VEHICLE_AUTOREPLACE_SELECTION, CBM_NO_BIT),
|
||||
NICV(CBID_VEHICLE_MODIFY_PROPERTY, CBM_NO_BIT),
|
||||
NIC_END()
|
||||
};
|
||||
|
||||
|
||||
static const NIVariable _niv_vehicles[] = {
|
||||
NIV(0x40, "position in consist and length"),
|
||||
NIV(0x41, "position and length of chain of same vehicles"),
|
||||
NIV(0x42, "transported cargo types"),
|
||||
NIV(0x43, "player info"),
|
||||
NIV(0x44, "aircraft info"),
|
||||
NIV(0x45, "curvature info"),
|
||||
NIV(0x46, "motion counter"),
|
||||
NIV(0x47, "vehicle cargo info"),
|
||||
NIV(0x48, "vehicle type info"),
|
||||
NIV(0x49, "year of construction"),
|
||||
NIV(0x60, "count vehicle id occurrences"),
|
||||
NIV_END()
|
||||
};
|
||||
|
||||
class NIHVehicle : public NIHelper {
|
||||
bool IsInspectable(uint index) const { return Engine::Get(Vehicle::Get(index)->engine_type)->grffile != NULL; }
|
||||
uint GetParent(uint index) const { const Vehicle *first = Vehicle::Get(index)->First(); return GetInspectWindowNumber(GetGrfSpecFeature(first->type), first->index); }
|
||||
const void *GetInstance(uint index)const { return Vehicle::Get(index); }
|
||||
const void *GetSpec(uint index) const { return Engine::Get(Vehicle::Get(index)->engine_type); }
|
||||
void SetStringParameters(uint index) const { this->SetSimpleStringParameters(STR_VEHICLE_NAME, index); }
|
||||
void Resolve(ResolverObject *ro, uint32 index) const { extern void GetVehicleResolver(ResolverObject *ro, uint index); GetVehicleResolver(ro, index); }
|
||||
};
|
||||
|
||||
static const NIFeature _nif_vehicle = {
|
||||
NULL,
|
||||
_nic_vehicles,
|
||||
_niv_vehicles,
|
||||
new NIHVehicle(),
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
/*** NewGRF station (tiles) ***/
|
||||
|
||||
#define NICS(cb_id, bit) NIC(cb_id, StationSpec, callback_mask, bit)
|
||||
static const NICallback _nic_stations[] = {
|
||||
NICS(CBID_STATION_AVAILABILITY, CBM_STATION_AVAIL),
|
||||
NICS(CBID_STATION_SPRITE_LAYOUT, CBM_NO_BIT),
|
||||
NICS(CBID_STATION_TILE_LAYOUT, CBM_STATION_SPRITE_LAYOUT),
|
||||
NICS(CBID_STATION_ANIM_START_STOP, CBM_NO_BIT),
|
||||
NICS(CBID_STATION_ANIM_NEXT_FRAME, CBM_STATION_ANIMATION_NEXT_FRAME),
|
||||
NICS(CBID_STATION_ANIMATION_SPEED, CBM_STATION_ANIMATION_SPEED),
|
||||
NICS(CBID_STATION_LAND_SLOPE_CHECK, CBM_STATION_SLOPE_CHECK),
|
||||
NIC_END()
|
||||
};
|
||||
|
||||
static const NIVariable _niv_stations[] = {
|
||||
NIV(0x40, "platform info and relative position"),
|
||||
NIV(0x41, "platform info and relative position for individually built sections"),
|
||||
NIV(0x42, "terrain and track type"),
|
||||
NIV(0x43, "player info"),
|
||||
NIV(0x44, "path signalling info"),
|
||||
NIV(0x45, "rail continuation info"),
|
||||
NIV(0x46, "platform info and relative position from middle"),
|
||||
NIV(0x47, "platform info and relative position from middle for individually built sections"),
|
||||
NIV(0x48, "bitmask of accepted cargoes"),
|
||||
NIV(0x49, "platform info and relative position of same-direction section"),
|
||||
NIV(0x4A, "current animation frame"),
|
||||
NIV(0x60, "amount of cargo waiting"),
|
||||
NIV(0x61, "time since last cargo pickup"),
|
||||
NIV(0x62, "rating of cargo"),
|
||||
NIV(0x63, "time spent on route"),
|
||||
NIV(0x64, "information about last vehicle picking cargo up"),
|
||||
NIV(0x65, "amount of cargo acceptance"),
|
||||
NIV(0x66, "animation frame of nearby tile"),
|
||||
NIV(0x67, "land info of nearby tiles"),
|
||||
NIV(0x68, "station info of nearby tiles"),
|
||||
NIV(0x69, "information about cargo accepted in the past"),
|
||||
NIV_END()
|
||||
};
|
||||
|
||||
class NIHStation : public NIHelper {
|
||||
bool IsInspectable(uint index) const { return GetStationSpec(index) != NULL; }
|
||||
uint GetParent(uint index) const { return GetInspectWindowNumber(GSF_FAKE_TOWNS, Station::GetByTile(index)->town->index); }
|
||||
const void *GetInstance(uint index)const { return NULL; }
|
||||
const void *GetSpec(uint index) const { return GetStationSpec(index); }
|
||||
void SetStringParameters(uint index) const { this->SetObjectAtStringParameters(STR_STATION_NAME, GetStationIndex(index), index); }
|
||||
void Resolve(ResolverObject *ro, uint32 index) const { extern void GetStationResolver(ResolverObject *ro, uint index); GetStationResolver(ro, index); }
|
||||
};
|
||||
|
||||
static const NIFeature _nif_station = {
|
||||
NULL,
|
||||
_nic_stations,
|
||||
_niv_stations,
|
||||
new NIHStation(),
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
/*** NewGRF house tiles ***/
|
||||
|
||||
#define NICH(cb_id, bit) NIC(cb_id, HouseSpec, callback_mask, bit)
|
||||
static const NICallback _nic_house[] = {
|
||||
NICH(CBID_HOUSE_ALLOW_CONSTRUCTION, CBM_HOUSE_ALLOW_CONSTRUCTION),
|
||||
NICH(CBID_HOUSE_ANIMATION_NEXT_FRAME, CBM_HOUSE_ANIMATION_NEXT_FRAME),
|
||||
NICH(CBID_HOUSE_ANIMATION_START_STOP, CBM_HOUSE_ANIMATION_START_STOP),
|
||||
NICH(CBID_HOUSE_CONSTRUCTION_STATE_CHANGE, CBM_HOUSE_CONSTRUCTION_STATE_CHANGE),
|
||||
NICH(CBID_HOUSE_COLOUR, CBM_HOUSE_COLOUR),
|
||||
NICH(CBID_HOUSE_CARGO_ACCEPTANCE, CBM_HOUSE_CARGO_ACCEPTANCE),
|
||||
NICH(CBID_HOUSE_ANIMATION_SPEED, CBM_HOUSE_ANIMATION_SPEED),
|
||||
NICH(CBID_HOUSE_DESTRUCTION, CBM_HOUSE_DESTRUCTION),
|
||||
NICH(CBID_HOUSE_ACCEPT_CARGO, CBM_HOUSE_ACCEPT_CARGO),
|
||||
NICH(CBID_HOUSE_PRODUCE_CARGO, CBM_HOUSE_PRODUCE_CARGO),
|
||||
NICH(CBID_HOUSE_DENY_DESTRUCTION, CBM_HOUSE_DENY_DESTRUCTION),
|
||||
NICH(CBID_HOUSE_WATCHED_CARGO_ACCEPTED, CBM_NO_BIT),
|
||||
NICH(CBID_HOUSE_CUSTOM_NAME, CBM_NO_BIT),
|
||||
NICH(CBID_HOUSE_DRAW_FOUNDATIONS, CBM_HOUSE_DRAW_FOUNDATIONS),
|
||||
NICH(CBID_HOUSE_AUTOSLOPE, CBM_HOUSE_AUTOSLOPE),
|
||||
NIC_END()
|
||||
};
|
||||
|
||||
static const NIVariable _niv_house[] = {
|
||||
NIV(0x40, "construction state of tile and pseudo-random value"),
|
||||
NIV(0x41, "age of building in years"),
|
||||
NIV(0x42, "town zone"),
|
||||
NIV(0x43, "terrain type"),
|
||||
NIV(0x44, "building counts"),
|
||||
NIV(0x45, "town expansion bits"),
|
||||
NIV(0x46, "current animation frame"),
|
||||
NIV(0x47, "xy coordinate of the building"),
|
||||
NIV(0x60, "other building counts (old house type)"),
|
||||
NIV(0x61, "other building counts (new house type)"),
|
||||
NIV(0x62, "land info of nearby tiles"),
|
||||
NIV(0x63, "current animation frame of nearby house tile"),
|
||||
NIV(0x64, "cargo acceptance history of nearby stations"),
|
||||
NIV(0x65, "distance of nearest house matching a given criterion"),
|
||||
NIV(0x66, "class and ID of nearby house tile"),
|
||||
NIV(0x67, "GRFID of nearby house tile"),
|
||||
NIV_END()
|
||||
};
|
||||
|
||||
class NIHHouse : public NIHelper {
|
||||
bool IsInspectable(uint index) const { return HouseSpec::Get(GetHouseType(index))->grffile != NULL; }
|
||||
uint GetParent(uint index) const { return GetInspectWindowNumber(GSF_FAKE_TOWNS, GetTownIndex(index)); }
|
||||
const void *GetInstance(uint index)const { return NULL; }
|
||||
const void *GetSpec(uint index) const { return HouseSpec::Get(GetHouseType(index)); }
|
||||
void SetStringParameters(uint index) const { this->SetObjectAtStringParameters(STR_TOWN_NAME, GetTownIndex(index), index); }
|
||||
void Resolve(ResolverObject *ro, uint32 index) const { extern void GetHouseResolver(ResolverObject *ro, uint index); GetHouseResolver(ro, index); }
|
||||
};
|
||||
|
||||
static const NIFeature _nif_house = {
|
||||
NULL,
|
||||
_nic_house,
|
||||
_niv_house,
|
||||
new NIHHouse(),
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
/*** NewGRF industry tiles ***/
|
||||
|
||||
#define NICIT(cb_id, bit) NIC(cb_id, IndustryTileSpec, callback_mask, bit)
|
||||
static const NICallback _nic_industrytiles[] = {
|
||||
NICIT(CBID_INDTILE_ANIM_START_STOP, CBM_NO_BIT),
|
||||
NICIT(CBID_INDTILE_ANIM_NEXT_FRAME, CBM_INDT_ANIM_NEXT_FRAME),
|
||||
NICIT(CBID_INDTILE_ANIMATION_SPEED, CBM_INDT_ANIM_SPEED),
|
||||
NICIT(CBID_INDTILE_CARGO_ACCEPTANCE, CBM_INDT_CARGO_ACCEPTANCE),
|
||||
NICIT(CBID_INDTILE_ACCEPT_CARGO, CBM_INDT_ACCEPT_CARGO),
|
||||
NICIT(CBID_INDTILE_SHAPE_CHECK, CBM_INDT_SHAPE_CHECK),
|
||||
NICIT(CBID_INDTILE_DRAW_FOUNDATIONS, CBM_INDT_DRAW_FOUNDATIONS),
|
||||
NICIT(CBID_INDTILE_AUTOSLOPE, CBM_INDT_AUTOSLOPE),
|
||||
NIC_END()
|
||||
};
|
||||
|
||||
static const NIVariable _niv_industrytiles[] = {
|
||||
NIV(0x40, "construction state of tile"),
|
||||
NIV(0x41, "ground type"),
|
||||
NIV(0x42, "current town zone in nearest town"),
|
||||
NIV(0x43, "relative position"),
|
||||
NIV(0x44, "animation frame"),
|
||||
NIV(0x60, "land info of nearby tiles"),
|
||||
NIV(0x61, "animation stage of nearby tiles"),
|
||||
NIV(0x62, "get industry or airport tile ID at offset"),
|
||||
NIV_END()
|
||||
};
|
||||
|
||||
class NIHIndustryTile : public NIHelper {
|
||||
bool IsInspectable(uint index) const { return GetIndustryTileSpec(GetIndustryGfx(index))->grf_prop.grffile != NULL; }
|
||||
uint GetParent(uint index) const { return GetInspectWindowNumber(GSF_INDUSTRIES, GetIndustryIndex(index)); }
|
||||
const void *GetInstance(uint index)const { return NULL; }
|
||||
const void *GetSpec(uint index) const { return GetIndustryTileSpec(GetIndustryGfx(index)); }
|
||||
void SetStringParameters(uint index) const { this->SetObjectAtStringParameters(STR_INDUSTRY_NAME, GetIndustryIndex(index), index); }
|
||||
void Resolve(ResolverObject *ro, uint32 index) const { extern void GetIndustryTileResolver(ResolverObject *ro, uint index); GetIndustryTileResolver(ro, index); }
|
||||
};
|
||||
|
||||
static const NIFeature _nif_industrytile = {
|
||||
NULL,
|
||||
_nic_industrytiles,
|
||||
_niv_industrytiles,
|
||||
new NIHIndustryTile(),
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
/*** NewGRF industries ***/
|
||||
|
||||
static const NIProperty _nip_industries[] = {
|
||||
NIP(0x10, Industry, produced_cargo[0], NIT_CARGO, "produced cargo 0"),
|
||||
NIP(0x10, Industry, produced_cargo[1], NIT_CARGO, "produced cargo 1"),
|
||||
NIP(0x11, Industry, accepts_cargo[0], NIT_CARGO, "accepted cargo 0"),
|
||||
NIP(0x11, Industry, accepts_cargo[1], NIT_CARGO, "accepted cargo 1"),
|
||||
NIP(0x11, Industry, accepts_cargo[2], NIT_CARGO, "accepted cargo 2"),
|
||||
NIP_END()
|
||||
};
|
||||
|
||||
#define NICI(cb_id, bit) NIC(cb_id, IndustrySpec, callback_mask, bit)
|
||||
static const NICallback _nic_industries[] = {
|
||||
NICI(CBID_INDUSTRY_AVAILABLE, CBM_IND_AVAILABLE),
|
||||
NICI(CBID_INDUSTRY_LOCATION, CBM_IND_LOCATION),
|
||||
NICI(CBID_INDUSTRY_PRODUCTION_CHANGE, CBM_IND_PRODUCTION_CHANGE),
|
||||
NICI(CBID_INDUSTRY_MONTHLYPROD_CHANGE, CBM_IND_MONTHLYPROD_CHANGE),
|
||||
NICI(CBID_INDUSTRY_CARGO_SUFFIX, CBM_IND_CARGO_SUFFIX),
|
||||
NICI(CBID_INDUSTRY_FUND_MORE_TEXT, CBM_IND_FUND_MORE_TEXT),
|
||||
NICI(CBID_INDUSTRY_WINDOW_MORE_TEXT, CBM_IND_WINDOW_MORE_TEXT),
|
||||
NICI(CBID_INDUSTRY_SPECIAL_EFFECT, CBM_IND_SPECIAL_EFFECT),
|
||||
NICI(CBID_INDUSTRY_REFUSE_CARGO, CBM_IND_REFUSE_CARGO),
|
||||
NICI(CBID_INDUSTRY_DECIDE_COLOUR, CBM_IND_DECIDE_COLOUR),
|
||||
NICI(CBID_INDUSTRY_INPUT_CARGO_TYPES, CBM_IND_INPUT_CARGO_TYPES),
|
||||
NICI(CBID_INDUSTRY_OUTPUT_CARGO_TYPES, CBM_IND_OUTPUT_CARGO_TYPES),
|
||||
NIC_END()
|
||||
};
|
||||
|
||||
static const NIVariable _niv_industries[] = {
|
||||
NIV(0x40, "waiting cargo 0"),
|
||||
NIV(0x41, "waiting cargo 1"),
|
||||
NIV(0x42, "waiting cargo 2"),
|
||||
NIV(0x43, "distance to closest dry/land tile"),
|
||||
NIV(0x44, "layout number"),
|
||||
NIV(0x45, "player info"),
|
||||
NIV(0x46, "industry construction date"),
|
||||
NIV(0x60, "get industry tile ID at offset"),
|
||||
NIV(0x61, "get random tile bits at offset"),
|
||||
NIV(0x62, "land info of nearby tiles"),
|
||||
NIV(0x63, "animation stage of nearby tiles"),
|
||||
NIV(0x64, "distance on nearest industry with given type"),
|
||||
NIV(0x65, "get town zone and Manhattan distance of closest town"),
|
||||
NIV(0x66, "get square of Euclidean distance of closes town"),
|
||||
NIV(0x67, "count of industry and distance of closest instance"),
|
||||
NIV(0x68, "count of industry and distance of closest instance with layout filter"),
|
||||
NIV_END()
|
||||
};
|
||||
|
||||
class NIHIndustry : public NIHelper {
|
||||
bool IsInspectable(uint index) const { return GetIndustrySpec(Industry::Get(index)->type)->grf_prop.grffile != NULL; }
|
||||
uint GetParent(uint index) const { return GetInspectWindowNumber(GSF_FAKE_TOWNS, Industry::Get(index)->town->index); }
|
||||
const void *GetInstance(uint index)const { return Industry::Get(index); }
|
||||
const void *GetSpec(uint index) const { return GetIndustrySpec(Industry::Get(index)->type); }
|
||||
void SetStringParameters(uint index) const { this->SetSimpleStringParameters(STR_INDUSTRY_NAME, index); }
|
||||
void Resolve(ResolverObject *ro, uint32 index) const { extern void GetIndustryResolver(ResolverObject *ro, uint index); GetIndustryResolver(ro, index); }
|
||||
};
|
||||
|
||||
static const NIFeature _nif_industry = {
|
||||
_nip_industries,
|
||||
_nic_industries,
|
||||
_niv_industries,
|
||||
new NIHIndustry(),
|
||||
cpp_lengthof(Industry, psa.storage),
|
||||
cpp_offsetof(Industry, psa.storage)
|
||||
};
|
||||
|
||||
|
||||
/*** NewGRF rail types ***/
|
||||
|
||||
static const NIVariable _niv_railtypes[] = {
|
||||
NIV(0x40, "terrain type"),
|
||||
NIV(0x41, "enhanced tunnels"),
|
||||
NIV(0x42, "level crossing status"),
|
||||
NIV_END()
|
||||
};
|
||||
|
||||
class NIHRailType : public NIHelper {
|
||||
bool IsInspectable(uint index) const { return true; }
|
||||
uint GetParent(uint index) const { return UINT32_MAX; }
|
||||
const void *GetInstance(uint index)const { return NULL; }
|
||||
const void *GetSpec(uint index) const { return NULL; }
|
||||
void SetStringParameters(uint index) const { this->SetObjectAtStringParameters(STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE, INVALID_STRING_ID, index); }
|
||||
void Resolve(ResolverObject *ro, uint32 index) const { extern void GetRailTypeResolver(ResolverObject *ro, uint index); GetRailTypeResolver(ro, index); }
|
||||
};
|
||||
|
||||
static const NIFeature _nif_railtype = {
|
||||
NULL,
|
||||
NULL,
|
||||
_niv_railtypes,
|
||||
new NIHRailType(),
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
/*** NewGRF airport tiles ***/
|
||||
|
||||
#define NICAT(cb_id, bit) NIC(cb_id, AirportTileSpec, callback_flags, bit)
|
||||
static const NICallback _nic_airporttiles[] = {
|
||||
NICAT(CBID_AIRPTILE_DRAW_FOUNDATIONS, CBM_AIRT_DRAW_FOUNDATIONS),
|
||||
NICAT(CBID_AIRPTILE_ANIM_START_STOP, CBM_NO_BIT),
|
||||
NICAT(CBID_AIRPTILE_ANIM_NEXT_FRAME, CBM_AIRT_ANIM_NEXT_FRAME),
|
||||
NICAT(CBID_AIRPTILE_ANIMATION_SPEED, CBM_AIRT_ANIM_SPEED),
|
||||
NIC_END()
|
||||
};
|
||||
|
||||
class NIHAirportTile : public NIHelper {
|
||||
bool IsInspectable(uint index) const { return AirportTileSpec::Get(GetAirportGfx(index))->grf_prop.grffile != NULL; }
|
||||
uint GetParent(uint index) const { return GetInspectWindowNumber(GSF_FAKE_TOWNS, Station::GetByTile(index)->town->index); }
|
||||
const void *GetInstance(uint index)const { return NULL; }
|
||||
const void *GetSpec(uint index) const { return AirportTileSpec::Get(GetAirportGfx(index)); }
|
||||
void SetStringParameters(uint index) const { this->SetObjectAtStringParameters(STR_STATION_NAME, GetStationIndex(index), index); }
|
||||
void Resolve(ResolverObject *ro, uint32 index) const { extern void GetAirportTileTypeResolver(ResolverObject *ro, uint index); GetAirportTileTypeResolver(ro, index); }
|
||||
};
|
||||
|
||||
static const NIFeature _nif_airporttile = {
|
||||
NULL,
|
||||
_nic_airporttiles,
|
||||
_niv_industrytiles, // Yes, they share this (at least now)
|
||||
new NIHAirportTile(),
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
/*** NewGRF towns ***/
|
||||
|
||||
static const NIVariable _niv_towns[] = {
|
||||
NIV(0x40, "larger town effect on this town"),
|
||||
NIV(0x41, "town index"),
|
||||
NIV(0x82, "population"),
|
||||
NIV(0x94, "zone radius 0"),
|
||||
NIV(0x96, "zone radius 1"),
|
||||
NIV(0x98, "zone radius 2"),
|
||||
NIV(0x9A, "zone radius 3"),
|
||||
NIV(0x9C, "zone radius 4"),
|
||||
NIV(0xB6, "number of buildings"),
|
||||
NIV_END()
|
||||
};
|
||||
|
||||
class NIHTown : public NIHelper {
|
||||
bool IsInspectable(uint index) const { return false; }
|
||||
uint GetParent(uint index) const { return UINT32_MAX; }
|
||||
const void *GetInstance(uint index)const { return Town::Get(index); }
|
||||
const void *GetSpec(uint index) const { return NULL; }
|
||||
void SetStringParameters(uint index) const { this->SetSimpleStringParameters(STR_TOWN_NAME, index); }
|
||||
uint Resolve(uint index, uint var, uint param, bool *avail) const { return TownGetVariable(var, param, avail, Town::Get(index)); }
|
||||
};
|
||||
|
||||
static const NIFeature _nif_town = {
|
||||
NULL,
|
||||
NULL,
|
||||
_niv_towns,
|
||||
new NIHTown(),
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
/** Table with all NIFeatures. */
|
||||
static const NIFeature * const _nifeatures[] = {
|
||||
&_nif_vehicle, // GSF_TRAINS
|
||||
&_nif_vehicle, // GSF_ROADVEHICLES
|
||||
&_nif_vehicle, // GSF_SHIPS
|
||||
&_nif_vehicle, // GSF_AIRCRAFT
|
||||
&_nif_station, // GSF_STATIONS
|
||||
NULL, // GSF_CANALS (no callbacks/action2 implemented)
|
||||
NULL, // GSF_BRIDGES (no callbacks/action2)
|
||||
&_nif_house, // GSF_HOUSES
|
||||
NULL, // GSF_GLOBALVAR (has no "physical" objects)
|
||||
&_nif_industrytile, // GSF_INDUSTRYTILES
|
||||
&_nif_industry, // GSF_INDUSTRIES
|
||||
NULL, // GSF_CARGOS (has no "physical" objects)
|
||||
NULL, // GSF_SOUNDFX (has no "physical" objects)
|
||||
NULL, // GSF_AIRPORTS (feature not implemented)
|
||||
NULL, // GSF_SIGNALS (feature not implemented)
|
||||
NULL, // GSF_OBJECTS (feature not implemented)
|
||||
&_nif_railtype, // GSF_RAILTYPES
|
||||
&_nif_airporttile, // GSF_AIRPORTTILES
|
||||
&_nif_town, // GSF_FAKE_TOWNS
|
||||
};
|
||||
assert_compile(lengthof(_nifeatures) == GSF_FAKE_END);
|
@ -106,6 +106,7 @@ enum WindowClass {
|
||||
WC_AI_DEBUG,
|
||||
WC_AI_LIST,
|
||||
WC_AI_SETTINGS,
|
||||
WC_NEWGRF_INSPECT,
|
||||
|
||||
WC_INVALID = 0xFFFF
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user