# newgrf_generic.cpp

Go to the documentation of this file.

    00001 /* $Id: newgrf_generic.cpp 24846 2012-12-23 21:09:09Z frosch $ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * 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.
    00006  * 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.
    00007  * 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/>.
    00008  */
    00009
    00012 #include "stdafx.h"
    00013 #include "debug.h"
    00014 #include "newgrf_spritegroup.h"
    00015 #include "industrytype.h"
    00016 #include "core/random_func.hpp"
    00017 #include "newgrf_sound.h"
    00018 #include "water_map.h"
    00019 #include <list>
    00020
    00022 struct GenericScopeResolver : public ScopeResolver {
    00023   CargoID cargo_type;
    00024   uint8 default_selection;
    00025   uint8 src_industry;
    00026   uint8 dst_industry;
    00027   uint8 distance;
    00028   AIConstructionEvent event;
    00029   uint8 count;
    00030   uint8 station_size;
    00031
    00032   GenericScopeResolver(ResolverObject *ro, bool ai_callback);
    00033
    00034   /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
    00035
    00036 private:
    00037   bool ai_callback;
    00038 };
    00039
    00040
    00042 struct GenericResolverObject : public ResolverObject {
    00043   GenericScopeResolver generic_scope;
    00044
    00045   GenericResolverObject(bool ai_callback, CallbackID callback = CBID_NO_CALLBACK);
    00046
    00047   /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0)
    00048   {
    00049     switch (scope) {
    00050       case VSG_SCOPE_SELF: return &this->generic_scope;
    00051       default: return ResolverObject::GetScope(scope, relative);
    00052     }
    00053   }
    00054
    00055   /* virtual */ const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const;
    00056 };
    00057
    00058 struct GenericCallback {
    00059   const GRFFile *file;
    00060   const SpriteGroup *group;
    00061
    00062   GenericCallback(const GRFFile *file, const SpriteGroup *group) :
    00063     file(file),
    00064     group(group)
    00065   { }
    00066 };
    00067
    00068 typedef std::list<GenericCallback> GenericCallbackList;
    00069
    00070 static GenericCallbackList _gcl[GSF_END];
    00071
    00072
    00076 void ResetGenericCallbacks()
    00077 {
    00078   for (uint8 feature = 0; feature < lengthof(_gcl); feature++) {
    00079     _gcl[feature].clear();
    00080   }
    00081 }
    00082
    00083
    00090 void AddGenericCallback(uint8 feature, const GRFFile *file, const SpriteGroup *group)
    00091 {
    00092   if (feature >= lengthof(_gcl)) {
    00093     grfmsg(5, "AddGenericCallback: Unsupported feature 0x%02X", feature);
    00094     return;
    00095   }
    00096
    00097   /* Generic feature callbacks are evaluated in reverse (i.e. the last group
    00098    * to be added is evaluated first, etc) thus we push the group to the
    00099    * beginning of the list so a standard iterator will do the right thing. */
    00100   _gcl[feature].push_front(GenericCallback(file, group));
    00101 }
    00102
    00103 /* virtual */ uint32 GenericScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
    00104 {
    00105   if (this->ai_callback) {
    00106     switch (variable) {
    00107       case 0x40: return this->ro->grffile->cargo_map[this->cargo_type];
    00108
    00109       case 0x80: return this->cargo_type;
    00110       case 0x81: return CargoSpec::Get(this->cargo_type)->bitnum;
    00111       case 0x82: return this->default_selection;
    00112       case 0x83: return this->src_industry;
    00113       case 0x84: return this->dst_industry;
    00114       case 0x85: return this->distance;
    00115       case 0x86: return this->event;
    00116       case 0x87: return this->count;
    00117       case 0x88: return this->station_size;
    00118
    00119       default: break;
    00120     }
    00121   }
    00122
    00123   DEBUG(grf, 1, "Unhandled generic feature variable 0x%02X", variable);
    00124
    00125   *available = false;
    00126   return UINT_MAX;
    00127 }
    00128
    00129
    00130 /* virtual */ const SpriteGroup *GenericResolverObject::ResolveReal(const RealSpriteGroup *group) const
    00131 {
    00132   if (group->num_loaded == 0) return NULL;
    00133
    00134   return group->loaded[0];
    00135 }
    00136
    00142 GenericResolverObject::GenericResolverObject(bool ai_callback, CallbackID callback) : ResolverObject(NULL, callback), generic_scope(this, ai_callback)
    00143 {
    00144 }
    00145
    00151 GenericScopeResolver::GenericScopeResolver(ResolverObject *ro, bool ai_callback) : ScopeResolver(ro)
    00152 {
    00153   this->cargo_type = 0;
    00154   this->default_selection = 0;
    00155   this->src_industry = 0;
    00156   this->dst_industry = 0;
    00157   this->distance = 0;
    00158   this->event = (AIConstructionEvent)0;
    00159   this->count = 0;
    00160   this->station_size = 0;
    00161   this->ai_callback = ai_callback;
    00162 }
    00163
    00164
    00176 static uint16 GetGenericCallbackResult(uint8 feature, ResolverObject *object, uint32 param1_grfv7, uint32 param1_grfv8, const GRFFile **file)
    00177 {
    00178   assert(feature < lengthof(_gcl));
    00179
    00180   /* Test each feature callback sprite group. */
    00181   for (GenericCallbackList::const_iterator it = _gcl[feature].begin(); it != _gcl[feature].end(); ++it) {
    00182     const SpriteGroup *group = it->group;
    00183     object->grffile = it->file;
    00184     /* Set callback param based on GRF version. */
    00185     object->callback_param1 = it->file->grf_version >= 8 ? param1_grfv8 : param1_grfv7;
    00186     group = SpriteGroup::Resolve(group, object);
    00187     if (group == NULL || group->GetCallbackResult() == CALLBACK_FAILED) continue;
    00188
    00189     /* Return NewGRF file if necessary */
    00190     if (file != NULL) *file = it->file;
    00191
    00192     return group->GetCallbackResult();
    00193   }
    00194
    00195   /* No callback returned a valid result, so we've failed. */
    00196   return CALLBACK_FAILED;
    00197 }
    00198
    00199
    00216 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)
    00217 {
    00218   GenericResolverObject object(true, CBID_GENERIC_AI_PURCHASE_SELECTION);
    00219
    00220   if (src_industry != IT_AI_UNKNOWN && src_industry != IT_AI_TOWN) {
    00221     const IndustrySpec *is = GetIndustrySpec(src_industry);
    00222     /* If this is no original industry, use the substitute type */
    00223     if (is->grf_prop.subst_id != INVALID_INDUSTRYTYPE) src_industry = is->grf_prop.subst_id;
    00224   }
    00225
    00226   if (dst_industry != IT_AI_UNKNOWN && dst_industry != IT_AI_TOWN) {
    00227     const IndustrySpec *is = GetIndustrySpec(dst_industry);
    00228     /* If this is no original industry, use the substitute type */
    00229     if (is->grf_prop.subst_id != INVALID_INDUSTRYTYPE) dst_industry = is->grf_prop.subst_id;
    00230   }
    00231
    00232   object.generic_scope.cargo_type        = cargo_type;
    00233   object.generic_scope.default_selection = default_selection;
    00234   object.generic_scope.src_industry      = src_industry;
    00235   object.generic_scope.dst_industry      = dst_industry;
    00236   object.generic_scope.distance          = distance;
    00237   object.generic_scope.event             = event;
    00238   object.generic_scope.count             = count;
    00239   object.generic_scope.station_size      = station_size;
    00240
    00241   uint16 callback = GetGenericCallbackResult(feature, &object, 0, 0, file);
    00242   if (callback != CALLBACK_FAILED) callback = GB(callback, 0, 8);
    00243   return callback;
    00244 }
    00245
    00246
    00251 void AmbientSoundEffectCallback(TileIndex tile)
    00252 {
    00253   assert(IsTileType(tile, MP_CLEAR) || IsTileType(tile, MP_TREES) || IsTileType(tile, MP_WATER));
    00254
    00255   /* Only run every 1/200-th time. */
    00256   uint32 r; // Save for later
    00257   if (!Chance16R(1, 200, r) || !_settings_client.sound.ambient) return;
    00258
    00259   /* Prepare resolver object. */
    00260   GenericResolverObject object(false, CBID_SOUNDS_AMBIENT_EFFECT);
    00261
    00262   uint32 param1_v7 = GetTileType(tile) << 28 | Clamp(TileHeight(tile), 0, 15) << 24 | GB(r, 16, 8) << 16 | GetTerrainType(tile);
    00263   uint32 param1_v8 = GetTileType(tile) << 24 | GetTileZ(tile) << 16 | GB(r, 16, 8) << 8 | (HasTileWaterClass(tile) ? GetWaterClass(tile) : 0) << 3 | GetTerrainType(tile);
    00264
    00265   /* Run callback. */
    00266   const GRFFile *grf_file;
    00267   uint16 callback = GetGenericCallbackResult(GSF_SOUNDFX, &object, param1_v7, param1_v8, &grf_file);
    00268
    00269   if (callback != CALLBACK_FAILED) PlayTileSound(grf_file, callback, tile);
    00270 }