# newgrf_commons.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    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
    00015 #include "stdafx.h"
    00016 #include "debug.h"
    00017 #include "landscape.h"
    00018 #include "house.h"
    00019 #include "industrytype.h"
    00020 #include "newgrf_config.h"
    00021 #include "clear_map.h"
    00022 #include "station_map.h"
    00023 #include "tree_map.h"
    00024 #include "tunnelbridge_map.h"
    00025 #include "newgrf_object.h"
    00026 #include "genworld.h"
    00027 #include "newgrf_spritegroup.h"
    00028 #include "newgrf_text.h"
    00029 #include "company_base.h"
    00030 #include "error.h"
    00031 #include "strings_func.h"
    00032
    00033 #include "table/strings.h"
    00034
    00041 OverrideManagerBase::OverrideManagerBase(uint16 offset, uint16 maximum, uint16 invalid)
    00042 {
    00043   max_offset = offset;
    00044   max_new_entities = maximum;
    00045   invalid_ID = invalid;
    00046
    00047   mapping_ID = CallocT<EntityIDMapping>(max_new_entities);
    00048   entity_overrides = MallocT<uint16>(max_offset);
    00049   for (size_t i = 0; i < max_offset; i++) entity_overrides[i] = invalid;
    00050   grfid_overrides = CallocT<uint32>(max_offset);
    00051 }
    00052
    00057 OverrideManagerBase::~OverrideManagerBase()
    00058 {
    00059   free(mapping_ID);
    00060   free(entity_overrides);
    00061   free(grfid_overrides);
    00062 }
    00063
    00072 void OverrideManagerBase::Add(uint8 local_id, uint32 grfid, uint entity_type)
    00073 {
    00074   assert(entity_type < max_offset);
    00075   /* An override can be set only once */
    00076   if (entity_overrides[entity_type] != invalid_ID) return;
    00077   entity_overrides[entity_type] = local_id;
    00078   grfid_overrides[entity_type] = grfid;
    00079 }
    00080
    00082 void OverrideManagerBase::ResetMapping()
    00083 {
    00084   memset(mapping_ID, 0, (max_new_entities - 1) * sizeof(EntityIDMapping));
    00085 }
    00086
    00088 void OverrideManagerBase::ResetOverride()
    00089 {
    00090   for (uint16 i = 0; i < max_offset; i++) {
    00091     entity_overrides[i] = invalid_ID;
    00092     grfid_overrides[i] = 0;
    00093   }
    00094 }
    00095
    00102 uint16 OverrideManagerBase::GetID(uint8 grf_local_id, uint32 grfid) const
    00103 {
    00104   const EntityIDMapping *map;
    00105
    00106   for (uint16 id = 0; id < max_new_entities; id++) {
    00107     map = &mapping_ID[id];
    00108     if (map->entity_id == grf_local_id && map->grfid == grfid) {
    00109       return id;
    00110     }
    00111   }
    00112
    00113   return invalid_ID;
    00114 }
    00115
    00123 uint16 OverrideManagerBase::AddEntityID(byte grf_local_id, uint32 grfid, byte substitute_id)
    00124 {
    00125   uint16 id = this->GetID(grf_local_id, grfid);
    00126   EntityIDMapping *map;
    00127
    00128   /* Look to see if this entity has already been added. This is done
    00129    * separately from the loop below in case a GRF has been deleted, and there
    00130    * are any gaps in the array.
    00131    */
    00132   if (id != invalid_ID) {
    00133     return id;
    00134   }
    00135
    00136   /* This entity hasn't been defined before, so give it an ID now. */
    00137   for (id = max_offset; id < max_new_entities; id++) {
    00138     map = &mapping_ID[id];
    00139
    00140     if (CheckValidNewID(id) && map->entity_id == 0 && map->grfid == 0) {
    00141       map->entity_id     = grf_local_id;
    00142       map->grfid         = grfid;
    00143       map->substitute_id = substitute_id;
    00144       return id;
    00145     }
    00146   }
    00147
    00148   return invalid_ID;
    00149 }
    00150
    00156 uint32 OverrideManagerBase::GetGRFID(uint16 entity_id) const
    00157 {
    00158   return mapping_ID[entity_id].grfid;
    00159 }
    00160
    00166 uint16 OverrideManagerBase::GetSubstituteID(uint16 entity_id) const
    00167 {
    00168   return mapping_ID[entity_id].substitute_id;
    00169 }
    00170
    00176 void HouseOverrideManager::SetEntitySpec(const HouseSpec *hs)
    00177 {
    00178   HouseID house_id = this->AddEntityID(hs->grf_prop.local_id, hs->grf_prop.grffile->grfid, hs->grf_prop.subst_id);
    00179
    00180   if (house_id == invalid_ID) {
    00181     grfmsg(1, "House.SetEntitySpec: Too many houses allocated. Ignoring.");
    00182     return;
    00183   }
    00184
    00185   MemCpyT(HouseSpec::Get(house_id), hs);
    00186
    00187   /* Now add the overrides. */
    00188   for (int i = 0; i != max_offset; i++) {
    00189     HouseSpec *overridden_hs = HouseSpec::Get(i);
    00190
    00191     if (entity_overrides[i] != hs->grf_prop.local_id || grfid_overrides[i] != hs->grf_prop.grffile->grfid) continue;
    00192
    00193     overridden_hs->grf_prop.override = house_id;
    00194     entity_overrides[i] = invalid_ID;
    00195     grfid_overrides[i] = 0;
    00196   }
    00197 }
    00198
    00205 uint16 IndustryOverrideManager::GetID(uint8 grf_local_id, uint32 grfid) const
    00206 {
    00207   uint16 id = OverrideManagerBase::GetID(grf_local_id, grfid);
    00208   if (id != invalid_ID) return id;
    00209
    00210   /* No mapping found, try the overrides */
    00211   for (id = 0; id < max_offset; id++) {
    00212     if (entity_overrides[id] == grf_local_id && grfid_overrides[id] == grfid) return id;
    00213   }
    00214
    00215   return invalid_ID;
    00216 }
    00217
    00225 uint16 IndustryOverrideManager::AddEntityID(byte grf_local_id, uint32 grfid, byte substitute_id)
    00226 {
    00227   /* This entity hasn't been defined before, so give it an ID now. */
    00228   for (uint16 id = 0; id < max_new_entities; id++) {
    00229     /* Skip overriden industries */
    00230     if (id < max_offset && entity_overrides[id] != invalid_ID) continue;
    00231
    00232     /* Get the real live industry */
    00233     const IndustrySpec *inds = GetIndustrySpec(id);
    00234
    00235     /* This industry must be one that is not available(enabled), mostly because of climate.
    00236      * And it must not already be used by a grf (grffile == NULL).
    00237      * So reseve this slot here, as it is the chosen one */
    00238     if (!inds->enabled && inds->grf_prop.grffile == NULL) {
    00239       EntityIDMapping *map = &mapping_ID[id];
    00240
    00241       if (map->entity_id == 0 && map->grfid == 0) {
    00242         /* winning slot, mark it as been used */
    00243         map->entity_id     = grf_local_id;
    00244         map->grfid         = grfid;
    00245         map->substitute_id = substitute_id;
    00246         return id;
    00247       }
    00248     }
    00249   }
    00250
    00251   return invalid_ID;
    00252 }
    00253
    00260 void IndustryOverrideManager::SetEntitySpec(IndustrySpec *inds)
    00261 {
    00262   /* First step : We need to find if this industry is already specified in the savegame data. */
    00263   IndustryType ind_id = this->GetID(inds->grf_prop.local_id, inds->grf_prop.grffile->grfid);
    00264
    00265   if (ind_id == invalid_ID) {
    00266     /* Not found.
    00267      * Or it has already been overriden, so you've lost your place old boy.
    00268      * Or it is a simple substitute.
    00269      * We need to find a free available slot */
    00270     ind_id = this->AddEntityID(inds->grf_prop.local_id, inds->grf_prop.grffile->grfid, inds->grf_prop.subst_id);
    00271     inds->grf_prop.override = invalid_ID;  // make sure it will not be detected as overriden
    00272   }
    00273
    00274   if (ind_id == invalid_ID) {
    00275     grfmsg(1, "Industry.SetEntitySpec: Too many industries allocated. Ignoring.");
    00276     return;
    00277   }
    00278
    00279   /* Now that we know we can use the given id, copy the spec to its final destination... */
    00280   memcpy(&_industry_specs[ind_id], inds, sizeof(*inds));
    00281   /* ... and mark it as usable*/
    00282   _industry_specs[ind_id].enabled = true;
    00283 }
    00284
    00285 void IndustryTileOverrideManager::SetEntitySpec(const IndustryTileSpec *its)
    00286 {
    00287   IndustryGfx indt_id = this->AddEntityID(its->grf_prop.local_id, its->grf_prop.grffile->grfid, its->grf_prop.subst_id);
    00288
    00289   if (indt_id == invalid_ID) {
    00290     grfmsg(1, "IndustryTile.SetEntitySpec: Too many industry tiles allocated. Ignoring.");
    00291     return;
    00292   }
    00293
    00294   memcpy(&_industry_tile_specs[indt_id], its, sizeof(*its));
    00295
    00296   /* Now add the overrides. */
    00297   for (int i = 0; i < max_offset; i++) {
    00298     IndustryTileSpec *overridden_its = &_industry_tile_specs[i];
    00299
    00300     if (entity_overrides[i] != its->grf_prop.local_id || grfid_overrides[i] != its->grf_prop.grffile->grfid) continue;
    00301
    00302     overridden_its->grf_prop.override = indt_id;
    00303     overridden_its->enabled = false;
    00304     entity_overrides[i] = invalid_ID;
    00305     grfid_overrides[i] = 0;
    00306   }
    00307 }
    00308
    00315 void ObjectOverrideManager::SetEntitySpec(ObjectSpec *spec)
    00316 {
    00317   /* First step : We need to find if this object is already specified in the savegame data. */
    00318   ObjectType type = this->GetID(spec->grf_prop.local_id, spec->grf_prop.grffile->grfid);
    00319
    00320   if (type == invalid_ID) {
    00321     /* Not found.
    00322      * Or it has already been overriden, so you've lost your place old boy.
    00323      * Or it is a simple substitute.
    00324      * We need to find a free available slot */
    00325     type = this->AddEntityID(spec->grf_prop.local_id, spec->grf_prop.grffile->grfid, OBJECT_TRANSMITTER);
    00326   }
    00327
    00328   if (type == invalid_ID) {
    00329     grfmsg(1, "Object.SetEntitySpec: Too many objects allocated. Ignoring.");
    00330     return;
    00331   }
    00332
    00333   extern ObjectSpec _object_specs[NUM_OBJECTS];
    00334
    00335   /* Now that we know we can use the given id, copy the spec to its final destination. */
    00336   memcpy(&_object_specs[type], spec, sizeof(*spec));
    00337   ObjectClass::Assign(&_object_specs[type]);
    00338 }
    00339
    00348 uint32 GetTerrainType(TileIndex tile, TileContext context)
    00349 {
    00350   switch (_settings_game.game_creation.landscape) {
    00351     case LT_TROPIC: return GetTropicZone(tile);
    00352     case LT_ARCTIC: {
    00353       bool has_snow;
    00354       switch (GetTileType(tile)) {
    00355         case MP_CLEAR:
    00356           /* During map generation the snowstate may not be valid yet, as the tileloop may not have run yet. */
    00357           if (_generating_world) goto genworld;
    00358           has_snow = IsSnowTile(tile) && GetClearDensity(tile) >= 2;
    00359           break;
    00360
    00361         case MP_RAILWAY: {
    00362           /* During map generation the snowstate may not be valid yet, as the tileloop may not have run yet. */
    00363           if (_generating_world) goto genworld; // we do not care about foundations here
    00364           RailGroundType ground = GetRailGroundType(tile);
    00365           has_snow = (ground == RAIL_GROUND_ICE_DESERT || (context == TCX_UPPER_HALFTILE && ground == RAIL_GROUND_HALF_SNOW));
    00366           break;
    00367         }
    00368
    00369         case MP_ROAD:
    00370           /* During map generation the snowstate may not be valid yet, as the tileloop may not have run yet. */
    00371           if (_generating_world) goto genworld; // we do not care about foundations here
    00372           has_snow = IsOnSnow(tile);
    00373           break;
    00374
    00375         case MP_TREES: {
    00376           /* During map generation the snowstate may not be valid yet, as the tileloop may not have run yet. */
    00377           if (_generating_world) goto genworld;
    00378           TreeGround ground = GetTreeGround(tile);
    00379           has_snow = (ground == TREE_GROUND_SNOW_DESERT || ground == TREE_GROUND_ROUGH_SNOW) && GetTreeDensity(tile) >= 2;
    00380           break;
    00381         }
    00382
    00383         case MP_TUNNELBRIDGE:
    00384           if (context == TCX_ON_BRIDGE) {
    00385             has_snow = (GetBridgeHeight(tile) > GetSnowLine());
    00386           } else {
    00387             /* During map generation the snowstate may not be valid yet, as the tileloop may not have run yet. */
    00388             if (_generating_world) goto genworld; // we do not care about foundations here
    00389             has_snow = HasTunnelBridgeSnowOrDesert(tile);
    00390           }
    00391           break;
    00392
    00393         case MP_STATION:
    00394         case MP_HOUSE:
    00395         case MP_INDUSTRY:
    00396         case MP_OBJECT:
    00397           /* These tiles usually have a levelling foundation. So use max Z */
    00398           has_snow = (GetTileMaxZ(tile) > GetSnowLine());
    00399           break;
    00400
    00401         case MP_VOID:
    00402         case MP_WATER:
    00403         genworld:
    00404           has_snow = (GetTileZ(tile) > GetSnowLine());
    00405           break;
    00406
    00407         default: NOT_REACHED();
    00408       }
    00409       return has_snow ? 4 : 0;
    00410     }
    00411     default:        return 0;
    00412   }
    00413 }
    00414
    00423 TileIndex GetNearbyTile(byte parameter, TileIndex tile, bool signed_offsets, Axis axis)
    00424 {
    00425   int8 x = GB(parameter, 0, 4);
    00426   int8 y = GB(parameter, 4, 4);
    00427
    00428   if (signed_offsets && x >= 8) x -= 16;
    00429   if (signed_offsets && y >= 8) y -= 16;
    00430
    00431   /* Swap width and height depending on axis for railway stations */
    00432   if (axis == INVALID_AXIS && HasStationTileRail(tile)) axis = GetRailStationAxis(tile);
    00433   if (axis == AXIS_Y) Swap(x, y);
    00434
    00435   /* Make sure we never roam outside of the map, better wrap in that case */
    00436   return TILE_MASK(tile + TileDiffXY(x, y));
    00437 }
    00438
    00446 uint32 GetNearbyTileInformation(TileIndex tile, bool grf_version8)
    00447 {
    00448   TileType tile_type = GetTileType(tile);
    00449
    00450   /* Fake tile type for trees on shore */
    00451   if (IsTileType(tile, MP_TREES) && GetTreeGround(tile) == TREE_GROUND_SHORE) tile_type = MP_WATER;
    00452
    00453   int z;
    00454   Slope tileh = GetTilePixelSlope(tile, &z);
    00455   /* Return 0 if the tile is a land tile */
    00456   byte terrain_type = (HasTileWaterClass(tile) ? (GetWaterClass(tile) + 1) & 3 : 0) << 5 | GetTerrainType(tile) << 2 | (tile_type == MP_WATER ? 1 : 0) << 1;
    00457   if (grf_version8) z /= TILE_HEIGHT;
    00458   return tile_type << 24 | Clamp(z, 0, 0xFF) << 16 | terrain_type << 8 | tileh;
    00459 }
    00460
    00467 uint32 GetCompanyInfo(CompanyID owner, const Livery *l)
    00468 {
    00469   if (l == NULL && Company::IsValidID(owner)) l = &Company::Get(owner)->livery[LS_DEFAULT];
    00470   return owner | (Company::IsValidAiID(owner) ? 0x10000 : 0) | (l != NULL ? (l->colour1 << 24) | (l->colour2 << 28) : 0);
    00471 }
    00472
    00480 CommandCost GetErrorMessageFromLocationCallbackResult(uint16 cb_res, uint32 grfid, StringID default_error)
    00481 {
    00482   CommandCost res;
    00483
    00484   if (cb_res < 0x400) {
    00485     res = CommandCost(GetGRFStringID(grfid, 0xD000 + cb_res));
    00486   } else {
    00487     switch (cb_res) {
    00488       case 0x400: return res; // No error.
    00489
    00490       default:    // unknown reason -> default error
    00491       case 0x401: res = CommandCost(default_error); break;
    00492
    00493       case 0x402: res = CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST); break;
    00494       case 0x403: res = CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT); break;
    00495       case 0x404: res = CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE); break;
    00496       case 0x405: res = CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE); break;
    00497       case 0x406: res = CommandCost(STR_ERROR_CAN_T_BUILD_ON_SEA); break;
    00498       case 0x407: res = CommandCost(STR_ERROR_CAN_T_BUILD_ON_CANAL); break;
    00499       case 0x408: res = CommandCost(STR_ERROR_CAN_T_BUILD_ON_RIVER); break;
    00500     }
    00501   }
    00502
    00503   /* Copy some parameters from the registers to the error message text ref. stack */
    00504   res.UseTextRefStack(4);
    00505
    00506   return res;
    00507 }
    00508
    00516 void ErrorUnknownCallbackResult(uint32 grfid, uint16 cbid, uint16 cb_res)
    00517 {
    00518   GRFConfig *grfconfig = GetGRFConfig(grfid);
    00519
    00520   if (!HasBit(grfconfig->grf_bugs, GBUG_UNKNOWN_CB_RESULT)) {
    00521     SetBit(grfconfig->grf_bugs, GBUG_UNKNOWN_CB_RESULT);
    00522     SetDParamStr(0, grfconfig->GetName());
    00523     SetDParam(1, cbid);
    00524     SetDParam(2, cb_res);
    00525     ShowErrorMessage(STR_NEWGRF_BUGGY, STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT, WL_CRITICAL);
    00526   }
    00527
    00528   /* debug output */
    00529   char buffer[512];
    00530
    00531   SetDParamStr(0, grfconfig->GetName());
    00532   GetString(buffer, STR_NEWGRF_BUGGY, lastof(buffer));
    00533   DEBUG(grf, 0, "%s", buffer + 3);
    00534
    00535   SetDParam(1, cbid);
    00536   SetDParam(2, cb_res);
    00537   GetString(buffer, STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT, lastof(buffer));
    00538   DEBUG(grf, 0, "%s", buffer + 3);
    00539 }
    00540
    00550 bool ConvertBooleanCallback(const GRFFile *grffile, uint16 cbid, uint16 cb_res)
    00551 {
    00552   assert(cb_res != CALLBACK_FAILED); // We do not know what to return
    00553
    00554   if (grffile->grf_version < 8) return cb_res != 0;
    00555
    00556   if (cb_res > 1) ErrorUnknownCallbackResult(grffile->grfid, cbid, cb_res);
    00557   return cb_res != 0;
    00558 }
    00559
    00569 bool Convert8bitBooleanCallback(const GRFFile *grffile, uint16 cbid, uint16 cb_res)
    00570 {
    00571   assert(cb_res != CALLBACK_FAILED); // We do not know what to return
    00572
    00573   if (grffile->grf_version < 8) return GB(cb_res, 0, 8) != 0;
    00574
    00575   if (cb_res > 1) ErrorUnknownCallbackResult(grffile->grfid, cbid, cb_res);
    00576   return cb_res != 0;
    00577 }
    00578
    00579
    00580 /* static */ SmallVector<DrawTileSeqStruct, 8> NewGRFSpriteLayout::result_seq;
    00581
    00586 void NewGRFSpriteLayout::Clone(const DrawTileSeqStruct *source)
    00587 {
    00588   assert(this->seq == NULL);
    00589   assert(source != NULL);
    00590
    00591   size_t count = 1; // 1 for the terminator
    00592   const DrawTileSeqStruct *element;
    00593   foreach_draw_tile_seq(element, source) count++;
    00594
    00595   DrawTileSeqStruct *sprites = MallocT<DrawTileSeqStruct>(count);
    00596   MemCpyT(sprites, source, count);
    00597   this->seq = sprites;
    00598 }
    00599
    00604 void NewGRFSpriteLayout::Clone(const NewGRFSpriteLayout *source)
    00605 {
    00606   this->Clone((const DrawTileSprites*)source);
    00607
    00608   if (source->registers != NULL) {
    00609     size_t count = 1; // 1 for the ground sprite
    00610     const DrawTileSeqStruct *element;
    00611     foreach_draw_tile_seq(element, source->seq) count++;
    00612
    00613     TileLayoutRegisters *regs = MallocT<TileLayoutRegisters>(count);
    00614     MemCpyT(regs, source->registers, count);
    00615     this->registers = regs;
    00616   }
    00617 }
    00618
    00619
    00624 void NewGRFSpriteLayout::Allocate(uint num_sprites)
    00625 {
    00626   assert(this->seq == NULL);
    00627
    00628   DrawTileSeqStruct *sprites = CallocT<DrawTileSeqStruct>(num_sprites + 1);
    00629   sprites[num_sprites].MakeTerminator();
    00630   this->seq = sprites;
    00631 }
    00632
    00636 void NewGRFSpriteLayout::AllocateRegisters()
    00637 {
    00638   assert(this->seq != NULL);
    00639   assert(this->registers == NULL);
    00640
    00641   size_t count = 1; // 1 for the ground sprite
    00642   const DrawTileSeqStruct *element;
    00643   foreach_draw_tile_seq(element, this->seq) count++;
    00644
    00645   this->registers = CallocT<TileLayoutRegisters>(count);
    00646 }
    00647
    00660 uint32 NewGRFSpriteLayout::PrepareLayout(uint32 orig_offset, uint32 newgrf_ground_offset, uint32 newgrf_offset, uint constr_stage, bool separate_ground) const
    00661 {
    00662   result_seq.Clear();
    00663   uint32 var10_values = 0;
    00664
    00665   /* Create a copy of the spritelayout, so we can modify some values.
    00666    * Also include the groundsprite into the sequence for easier processing. */
    00667   DrawTileSeqStruct *result = result_seq.Append();
    00668   result->image = ground;
    00669   result->delta_x = 0;
    00670   result->delta_y = 0;
    00671   result->delta_z = (int8)0x80;
    00672
    00673   const DrawTileSeqStruct *dtss;
    00674   foreach_draw_tile_seq(dtss, this->seq) {
    00675     *result_seq.Append() = *dtss;
    00676   }
    00677   result_seq.Append()->MakeTerminator();
    00678
    00679   /* Determine the var10 values the action-1-2-3 chains needs to be resolved for,
    00680    * and apply the default sprite offsets (unless disabled). */
    00681   const TileLayoutRegisters *regs = this->registers;
    00682   bool ground = true;
    00683   foreach_draw_tile_seq(result, result_seq.Begin()) {
    00684     TileLayoutFlags flags = TLF_NOTHING;
    00685     if (regs != NULL) flags = regs->flags;
    00686
    00687     /* Record var10 value for the sprite */
    00688     if (HasBit(result->image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE) || (flags & TLF_SPRITE_REG_FLAGS)) {
    00689       uint8 var10 = (flags & TLF_SPRITE_VAR10) ? regs->sprite_var10 : (ground && separate_ground ? 1 : 0);
    00690       SetBit(var10_values, var10);
    00691     }
    00692
    00693     /* Add default sprite offset, unless there is a custom one */
    00694     if (!(flags & TLF_SPRITE)) {
    00695       if (HasBit(result->image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE)) {
    00696         result->image.sprite += ground ? newgrf_ground_offset : newgrf_offset;
    00697         if (constr_stage > 0 && regs != NULL) result->image.sprite += GetConstructionStageOffset(constr_stage, regs->max_sprite_offset);
    00698       } else {
    00699         result->image.sprite += orig_offset;
    00700       }
    00701     }
    00702
    00703     /* Record var10 value for the palette */
    00704     if (HasBit(result->image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE) || (flags & TLF_PALETTE_REG_FLAGS)) {
    00705       uint8 var10 = (flags & TLF_PALETTE_VAR10) ? regs->palette_var10 : (ground && separate_ground ? 1 : 0);
    00706       SetBit(var10_values, var10);
    00707     }
    00708
    00709     /* Add default palette offset, unless there is a custom one */
    00710     if (!(flags & TLF_PALETTE)) {
    00711       if (HasBit(result->image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) {
    00712         result->image.sprite += ground ? newgrf_ground_offset : newgrf_offset;
    00713         if (constr_stage > 0 && regs != NULL) result->image.sprite += GetConstructionStageOffset(constr_stage, regs->max_palette_offset);
    00714       }
    00715     }
    00716
    00717     ground = false;
    00718     if (regs != NULL) regs++;
    00719   }
    00720
    00721   return var10_values;
    00722 }
    00723
    00732 void NewGRFSpriteLayout::ProcessRegisters(uint8 resolved_var10, uint32 resolved_sprite, bool separate_ground) const
    00733 {
    00734   DrawTileSeqStruct *result;
    00735   const TileLayoutRegisters *regs = this->registers;
    00736   bool ground = true;
    00737   foreach_draw_tile_seq(result, result_seq.Begin()) {
    00738     TileLayoutFlags flags = TLF_NOTHING;
    00739     if (regs != NULL) flags = regs->flags;
    00740
    00741     /* Is the sprite or bounding box affected by an action-1-2-3 chain? */
    00742     if (HasBit(result->image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE) || (flags & TLF_SPRITE_REG_FLAGS)) {
    00743       /* Does the var10 value apply to this sprite? */
    00744       uint8 var10 = (flags & TLF_SPRITE_VAR10) ? regs->sprite_var10 : (ground && separate_ground ? 1 : 0);
    00745       if (var10 == resolved_var10) {
    00746         /* Apply registers */
    00747         if ((flags & TLF_DODRAW) && GetRegister(regs->dodraw) == 0) {
    00748           result->image.sprite = 0;
    00749         } else {
    00750           if (HasBit(result->image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE)) result->image.sprite += resolved_sprite;
    00751           if (flags & TLF_SPRITE) {
    00752             int16 offset = (int16)GetRegister(regs->sprite); // mask to 16 bits to avoid trouble
    00753             if (!HasBit(result->image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE) || (offset >= 0 && offset < regs->max_sprite_offset)) {
    00754               result->image.sprite += offset;
    00755             } else {
    00756               result->image.sprite = SPR_IMG_QUERY;
    00757             }
    00758           }
    00759
    00760           if (result->IsParentSprite()) {
    00761             if (flags & TLF_BB_XY_OFFSET) {
    00762               result->delta_x += (int32)GetRegister(regs->delta.parent[0]);
    00763               result->delta_y += (int32)GetRegister(regs->delta.parent[1]);
    00764             }
    00765             if (flags & TLF_BB_Z_OFFSET)    result->delta_z += (int32)GetRegister(regs->delta.parent[2]);
    00766           } else {
    00767             if (flags & TLF_CHILD_X_OFFSET) result->delta_x += (int32)GetRegister(regs->delta.child[0]);
    00768             if (flags & TLF_CHILD_Y_OFFSET) result->delta_y += (int32)GetRegister(regs->delta.child[1]);
    00769           }
    00770         }
    00771       }
    00772     }
    00773
    00774     /* Is the palette affected by an action-1-2-3 chain? */
    00775     if (result->image.sprite != 0 && (HasBit(result->image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE) || (flags & TLF_PALETTE_REG_FLAGS))) {
    00776       /* Does the var10 value apply to this sprite? */
    00777       uint8 var10 = (flags & TLF_PALETTE_VAR10) ? regs->palette_var10 : (ground && separate_ground ? 1 : 0);
    00778       if (var10 == resolved_var10) {
    00779         /* Apply registers */
    00780         if (HasBit(result->image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) result->image.pal += resolved_sprite;
    00781         if (flags & TLF_PALETTE) {
    00782           int16 offset = (int16)GetRegister(regs->palette); // mask to 16 bits to avoid trouble
    00783           if (!HasBit(result->image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE) || (offset >= 0 && offset < regs->max_palette_offset)) {
    00784             result->image.pal += offset;
    00785           } else {
    00786             result->image.sprite = SPR_IMG_QUERY;
    00787             result->image.pal = PAL_NONE;
    00788           }
    00789         }
    00790       }
    00791     }
    00792
    00793     ground = false;
    00794     if (regs != NULL) regs++;
    00795   }
    00796 }