newgrf_commons.cpp

Go to the documentation of this file.
00001 /* $Id: newgrf_commons.cpp 23740 2012-01-03 21:32:51Z rubidium $ */
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 }