OpenTTD
newgrf_generic.cpp
Go to the documentation of this file.
1 /* $Id: newgrf_generic.cpp 27984 2018-03-11 13:19:41Z frosch $ */
2 
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  */
9 
12 #include "stdafx.h"
13 #include "debug.h"
14 #include "newgrf_spritegroup.h"
15 #include "industrytype.h"
16 #include "core/random_func.hpp"
17 #include "newgrf_sound.h"
18 #include "water_map.h"
19 #include <list>
20 
21 #include "safeguards.h"
22 
25  CargoID cargo_type;
26  uint8 default_selection;
27  uint8 src_industry;
28  uint8 dst_industry;
29  uint8 distance;
30  AIConstructionEvent event;
31  uint8 count;
32  uint8 station_size;
33 
40  : ScopeResolver(ro), cargo_type(0), default_selection(0), src_industry(0), dst_industry(0), distance(0),
41  event(), count(0), station_size(0), ai_callback(ai_callback)
42  {
43  }
44 
45  /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
46 
47 private:
48  bool ai_callback;
49 };
50 
51 
54  GenericScopeResolver generic_scope;
55 
57 
58  /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0)
59  {
60  switch (scope) {
61  case VSG_SCOPE_SELF: return &this->generic_scope;
62  default: return ResolverObject::GetScope(scope, relative);
63  }
64  }
65 
66  /* virtual */ const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const;
67 };
68 
70  const GRFFile *file;
71  const SpriteGroup *group;
72 
73  GenericCallback(const GRFFile *file, const SpriteGroup *group) :
74  file(file),
75  group(group)
76  { }
77 };
78 
79 typedef std::list<GenericCallback> GenericCallbackList;
80 
81 static GenericCallbackList _gcl[GSF_END];
82 
83 
88 {
89  for (uint8 feature = 0; feature < lengthof(_gcl); feature++) {
90  _gcl[feature].clear();
91  }
92 }
93 
94 
101 void AddGenericCallback(uint8 feature, const GRFFile *file, const SpriteGroup *group)
102 {
103  if (feature >= lengthof(_gcl)) {
104  grfmsg(5, "AddGenericCallback: Unsupported feature 0x%02X", feature);
105  return;
106  }
107 
108  /* Generic feature callbacks are evaluated in reverse (i.e. the last group
109  * to be added is evaluated first, etc) thus we push the group to the
110  * beginning of the list so a standard iterator will do the right thing. */
111  _gcl[feature].push_front(GenericCallback(file, group));
112 }
113 
114 /* virtual */ uint32 GenericScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
115 {
116  if (this->ai_callback) {
117  switch (variable) {
118  case 0x40: return this->ro.grffile->cargo_map[this->cargo_type];
119 
120  case 0x80: return this->cargo_type;
121  case 0x81: return CargoSpec::Get(this->cargo_type)->bitnum;
122  case 0x82: return this->default_selection;
123  case 0x83: return this->src_industry;
124  case 0x84: return this->dst_industry;
125  case 0x85: return this->distance;
126  case 0x86: return this->event;
127  case 0x87: return this->count;
128  case 0x88: return this->station_size;
129 
130  default: break;
131  }
132  }
133 
134  DEBUG(grf, 1, "Unhandled generic feature variable 0x%02X", variable);
135 
136  *available = false;
137  return UINT_MAX;
138 }
139 
140 
141 /* virtual */ const SpriteGroup *GenericResolverObject::ResolveReal(const RealSpriteGroup *group) const
142 {
143  if (group->num_loaded == 0) return NULL;
144 
145  return group->loaded[0];
146 }
147 
153 GenericResolverObject::GenericResolverObject(bool ai_callback, CallbackID callback) : ResolverObject(NULL, callback), generic_scope(*this, ai_callback)
154 {
155 }
156 
157 
169 static uint16 GetGenericCallbackResult(uint8 feature, ResolverObject &object, uint32 param1_grfv7, uint32 param1_grfv8, const GRFFile **file)
170 {
171  assert(feature < lengthof(_gcl));
172 
173  /* Test each feature callback sprite group. */
174  for (GenericCallbackList::const_iterator it = _gcl[feature].begin(); it != _gcl[feature].end(); ++it) {
175  object.grffile = it->file;
176  object.root_spritegroup = it->group;
177  /* Set callback param based on GRF version. */
178  object.callback_param1 = it->file->grf_version >= 8 ? param1_grfv8 : param1_grfv7;
179  uint16 result = object.ResolveCallback();
180  if (result == CALLBACK_FAILED) continue;
181 
182  /* Return NewGRF file if necessary */
183  if (file != NULL) *file = it->file;
184 
185  return result;
186  }
187 
188  /* No callback returned a valid result, so we've failed. */
189  return CALLBACK_FAILED;
190 }
191 
192 
209 uint16 GetAiPurchaseCallbackResult(uint8 feature, CargoID cargo_type, uint8 default_selection, IndustryType src_industry, IndustryType dst_industry, uint8 distance, AIConstructionEvent event, uint8 count, uint8 station_size, const GRFFile **file)
210 {
212 
213  if (src_industry != IT_AI_UNKNOWN && src_industry != IT_AI_TOWN) {
214  const IndustrySpec *is = GetIndustrySpec(src_industry);
215  /* If this is no original industry, use the substitute type */
216  if (is->grf_prop.subst_id != INVALID_INDUSTRYTYPE) src_industry = is->grf_prop.subst_id;
217  }
218 
219  if (dst_industry != IT_AI_UNKNOWN && dst_industry != IT_AI_TOWN) {
220  const IndustrySpec *is = GetIndustrySpec(dst_industry);
221  /* If this is no original industry, use the substitute type */
222  if (is->grf_prop.subst_id != INVALID_INDUSTRYTYPE) dst_industry = is->grf_prop.subst_id;
223  }
224 
225  object.generic_scope.cargo_type = cargo_type;
226  object.generic_scope.default_selection = default_selection;
227  object.generic_scope.src_industry = src_industry;
228  object.generic_scope.dst_industry = dst_industry;
229  object.generic_scope.distance = distance;
230  object.generic_scope.event = event;
231  object.generic_scope.count = count;
232  object.generic_scope.station_size = station_size;
233 
234  uint16 callback = GetGenericCallbackResult(feature, object, 0, 0, file);
235  if (callback != CALLBACK_FAILED) callback = GB(callback, 0, 8);
236  return callback;
237 }
238 
239 
245 {
246  assert(IsTileType(tile, MP_CLEAR) || IsTileType(tile, MP_TREES) || IsTileType(tile, MP_WATER));
247 
248  /* Only run every 1/200-th time. */
249  uint32 r; // Save for later
250  if (!Chance16R(1, 200, r) || !_settings_client.sound.ambient) return;
251 
252  /* Prepare resolver object. */
254 
255  uint32 param1_v7 = GetTileType(tile) << 28 | Clamp(TileHeight(tile), 0, 15) << 24 | GB(r, 16, 8) << 16 | GetTerrainType(tile);
256  uint32 param1_v8 = GetTileType(tile) << 24 | GetTileZ(tile) << 16 | GB(r, 16, 8) << 8 | (HasTileWaterClass(tile) ? GetWaterClass(tile) : 0) << 3 | GetTerrainType(tile);
257 
258  /* Run callback. */
259  const GRFFile *grf_file;
260  uint16 callback = GetGenericCallbackResult(GSF_SOUNDFX, object, param1_v7, param1_v8, &grf_file);
261 
262  if (callback != CALLBACK_FAILED) PlayTileSound(grf_file, callback, tile);
263 }
static TileType GetTileType(TileIndex tile)
Get the tiletype of a given tile.
Definition: tile_map.h:89
Interface to query and set values specific to a single VarSpriteGroupScope (action 2 scope)...
Scope resolver for generic objects and properties.
Resolver object for generic objects/properties.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
uint8 dst_industry
Destination industry substitute type. 0xFF for "town", 0xFE for "unknown".
ResolverObject & ro
Surrounding resolver object.
VarSpriteGroupScope
static WaterClass GetWaterClass(TileIndex t)
Get the water class at a tile.
Definition: water_map.h:106
Functions related to debugging.
Interface for SpriteGroup-s to access the gamestate.
uint32 GetTerrainType(TileIndex tile, TileContext context)
Function used by houses (and soon industries) to get information on type of "terrain" the tile it is ...
uint32 GetVariable(byte variable, uint32 parameter, bool *available) const
Get a variable value.
GenericResolverObject(bool ai_callback, CallbackID callback=CBID_NO_CALLBACK)
Generic resolver.
Set when using the callback resolve system, but not to resolve a callback.
bool ambient
Play ambient, industry and town sounds.
Industry type specs.
virtual ScopeResolver * GetScope(VarSpriteGroupScope scope=VSG_SCOPE_SELF, byte relative=0)
Get a resolver for the scope.
AI construction/purchase selection.
byte num_loaded
Number of loaded groups.
void AddGenericCallback(uint8 feature, const GRFFile *file, const SpriteGroup *group)
Add a generic feature callback sprite group to the appropriate feature list.
int GetTileZ(TileIndex tile)
Get bottom height of the tile.
Definition: tile_map.cpp:182
Pseudo random number generator.
AIConstructionEvent
AI events for asking the NewGRF for information.
Action 2 handling.
static const IndustryType IT_AI_UNKNOWN
The AI has no specific industry in mind.
static bool IsTileType(TileIndex tile, TileType type)
Checks if a tile is a give tiletype.
Definition: tile_map.h:143
const SpriteGroup ** loaded
List of loaded groups (can be SpriteIDs or Callback results)
static const IndustryType IT_AI_TOWN
The AI actually wants to transport to/from a town, not an industry.
SoundSettings sound
sound effect settings
bool ai_callback
Callback comes from the AI.
void PlayTileSound(const GRFFile *file, SoundID sound_id, TileIndex tile)
Play a NewGRF sound effect at the location of a specific tile.
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:76
Map accessors for water tiles.
const IndustrySpec * GetIndustrySpec(IndustryType thistype)
Accessor for array _industry_specs.
Definition of base types and functions in a cross-platform compatible way.
uint16 GetAiPurchaseCallbackResult(uint8 feature, CargoID cargo_type, uint8 default_selection, IndustryType src_industry, IndustryType dst_industry, uint8 distance, AIConstructionEvent event, uint8 count, uint8 station_size, const GRFFile **file)
&#39;Execute&#39; an AI purchase selection callback
A number of safeguards to prevent using unsafe methods.
Water tile.
Definition: tile_type.h:49
Defines the data structure for constructing industry.
Definition: industrytype.h:101
uint8 cargo_map[NUM_CARGO]
Inverse cargo translation table (CargoID -> local ID)
Definition: newgrf.h:126
#define lengthof(x)
Return the length of an fixed size array.
Definition: depend.cpp:42
GRFFileProps grf_prop
properties related to the grf file
Definition: industrytype.h:136
Resolved object itself.
static bool Chance16R(const uint a, const uint b, uint32 &r)
Flips a coin with a given probability and saves the randomize-number in a variable.
static T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition: math_func.hpp:139
#define DEBUG(name, level,...)
Output a line of debugging information.
Definition: debug.h:39
const GRFFile * grffile
GRFFile the resolved SpriteGroup belongs to.
Tile got trees.
Definition: tile_type.h:47
void AmbientSoundEffectCallback(TileIndex tile)
&#39;Execute&#39; the ambient sound effect callback.
static const IndustryType INVALID_INDUSTRYTYPE
one above amount is considered invalid
Definition: industry_type.h:29
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo ID.
Definition: cargotype.h:118
uint32 TileIndex
The index/ID of a Tile.
Definition: tile_type.h:80
void CDECL grfmsg(int severity, const char *str,...)
DEBUG() function dedicated to newGRF debugging messages Function is essentially the same as DEBUG(grf...
Definition: newgrf.cpp:375
CallbackID callback
Callback being resolved.
static uint GB(const T x, const uint8 s, const uint8 n)
Fetch n bits from x, started at bit s.
uint8 src_industry
Source industry substitute type. 0xFF for "town", 0xFE for "unknown".
void ResetGenericCallbacks()
Reset all generic feature callback sprite groups.
static uint16 GetGenericCallbackResult(uint8 feature, ResolverObject &object, uint32 param1_grfv7, uint32 param1_grfv8, const GRFFile **file)
Follow a generic feature callback list and return the first successful answer.
static uint TileHeight(TileIndex tile)
Returns the height of a tile.
Definition: tile_map.h:31
ScopeResolver * GetScope(VarSpriteGroupScope scope=VSG_SCOPE_SELF, byte relative=0)
Get a resolver for the scope.
uint8 bitnum
Cargo bit number, is INVALID_CARGO for a non-used spec.
Definition: cargotype.h:57
CallbackID
List of implemented NewGRF callbacks.
Select an ambient sound to play for a given type of tile.
static bool HasTileWaterClass(TileIndex t)
Checks whether the tile has an waterclass associated.
Definition: water_map.h:95
Functions related to NewGRF provided sounds.
A tile without any structures, i.e. grass, rocks, farm fields etc.
Definition: tile_type.h:43
byte CargoID
Cargo slots to indicate a cargo type within a game.
Definition: cargo_type.h:22
const SpriteGroup * ResolveReal(const RealSpriteGroup *group) const
Get the real sprites of the grf.
GenericScopeResolver(ResolverObject &ro, bool ai_callback)
Generic scope resolver.
Dynamic data of a loaded NewGRF.
Definition: newgrf.h:104