# newgrf_house.cpp

Go to the documentation of this file.

    00001 /* $Id: newgrf_house.cpp 24900 2013-01-08 22:46:42Z planetmaker $ */
    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 "landscape.h"
    00015 #include "newgrf_house.h"
    00016 #include "newgrf_spritegroup.h"
    00017 #include "newgrf_town.h"
    00018 #include "newgrf_sound.h"
    00019 #include "company_func.h"
    00020 #include "company_base.h"
    00021 #include "town.h"
    00022 #include "genworld.h"
    00023 #include "newgrf_animation_base.h"
    00024 #include "newgrf_cargo.h"
    00025 #include "station_base.h"
    00026
    00027 static BuildingCounts<uint32> _building_counts;
    00028 static HouseClassMapping _class_mapping[HOUSE_CLASS_MAX];
    00029
    00030 HouseOverrideManager _house_mngr(NEW_HOUSE_OFFSET, HOUSE_MAX, INVALID_HOUSE_ID);
    00031
    00042 HouseScopeResolver::HouseScopeResolver(ResolverObject *ro, HouseID house_id, TileIndex tile, Town *town,
    00043       bool not_yet_constructed, uint8 initial_random_bits, uint32 watched_cargo_triggers)
    00044     : ScopeResolver(ro)
    00045 {
    00046   this->house_id = house_id;
    00047   this->tile = tile;
    00048   this->town = town;
    00049   this->not_yet_constructed = not_yet_constructed;
    00050   this->initial_random_bits = initial_random_bits;
    00051   this->watched_cargo_triggers = watched_cargo_triggers;
    00052 }
    00053
    00059 static const GRFFile *GetHouseSpecGrf(HouseID house_id)
    00060 {
    00061   const HouseSpec *hs  = HouseSpec::Get(house_id);
    00062   return (hs != NULL) ? hs->grf_prop.grffile : NULL;
    00063 }
    00064
    00077 HouseResolverObject::HouseResolverObject(HouseID house_id, TileIndex tile, Town *town,
    00078     CallbackID callback, uint32 param1, uint32 param2,
    00079     bool not_yet_constructed, uint8 initial_random_bits, uint32 watched_cargo_triggers)
    00080   : ResolverObject(GetHouseSpecGrf(house_id), callback, param1, param2),
    00081   house_scope(this, house_id, tile, town, not_yet_constructed, initial_random_bits, watched_cargo_triggers),
    00082   town_scope(this, town, not_yet_constructed) // Don't access StorePSA if house is not yet constructed.
    00083 {
    00084 }
    00085
    00086 HouseClassID AllocateHouseClassID(byte grf_class_id, uint32 grfid)
    00087 {
    00088   /* Start from 1 because 0 means that no class has been assigned. */
    00089   for (int i = 1; i != lengthof(_class_mapping); i++) {
    00090     HouseClassMapping *map = &_class_mapping[i];
    00091
    00092     if (map->class_id == grf_class_id && map->grfid == grfid) return (HouseClassID)i;
    00093
    00094     if (map->class_id == 0 && map->grfid == 0) {
    00095       map->class_id = grf_class_id;
    00096       map->grfid    = grfid;
    00097       return (HouseClassID)i;
    00098     }
    00099   }
    00100   return HOUSE_NO_CLASS;
    00101 }
    00102
    00103 void InitializeBuildingCounts()
    00104 {
    00105   memset(&_building_counts, 0, sizeof(_building_counts));
    00106
    00107   Town *t;
    00108   FOR_ALL_TOWNS(t) {
    00109     memset(&t->cache.building_counts, 0, sizeof(t->cache.building_counts));
    00110   }
    00111 }
    00112
    00119 void IncreaseBuildingCount(Town *t, HouseID house_id)
    00120 {
    00121   HouseClassID class_id = HouseSpec::Get(house_id)->class_id;
    00122
    00123   if (!_loaded_newgrf_features.has_newhouses) return;
    00124
    00125   t->cache.building_counts.id_count[house_id]++;
    00126   _building_counts.id_count[house_id]++;
    00127
    00128   if (class_id == HOUSE_NO_CLASS) return;
    00129
    00130   t->cache.building_counts.class_count[class_id]++;
    00131   _building_counts.class_count[class_id]++;
    00132 }
    00133
    00140 void DecreaseBuildingCount(Town *t, HouseID house_id)
    00141 {
    00142   HouseClassID class_id = HouseSpec::Get(house_id)->class_id;
    00143
    00144   if (!_loaded_newgrf_features.has_newhouses) return;
    00145
    00146   if (t->cache.building_counts.id_count[house_id] > 0) t->cache.building_counts.id_count[house_id]--;
    00147   if (_building_counts.id_count[house_id] > 0) _building_counts.id_count[house_id]--;
    00148
    00149   if (class_id == HOUSE_NO_CLASS) return;
    00150
    00151   if (t->cache.building_counts.class_count[class_id] > 0) t->cache.building_counts.class_count[class_id]--;
    00152   if (_building_counts.class_count[class_id] > 0) _building_counts.class_count[class_id]--;
    00153 }
    00154
    00155 /* virtual */ uint32 HouseScopeResolver::GetRandomBits() const
    00156 {
    00157   /* Note: Towns build houses over houses. So during construction checks 'tile' may be a valid but unrelated house. */
    00158   assert(IsValidTile(this->tile) && (this->not_yet_constructed || IsTileType(this->tile, MP_HOUSE)));
    00159   return this->not_yet_constructed ? this->initial_random_bits : GetHouseRandomBits(this->tile);
    00160 }
    00161
    00162 /* virtual */ uint32 HouseScopeResolver::GetTriggers() const
    00163 {
    00164   /* Note: Towns build houses over houses. So during construction checks 'tile' may be a valid but unrelated house. */
    00165   assert(IsValidTile(this->tile) && (this->not_yet_constructed || IsTileType(this->tile, MP_HOUSE)));
    00166   return this->not_yet_constructed ? 0 : GetHouseTriggers(this->tile);
    00167 }
    00168
    00169 /* virtual */ void HouseScopeResolver::SetTriggers(int triggers) const
    00170 {
    00171   assert(!this->not_yet_constructed && IsValidTile(this->tile) && IsTileType(this->tile, MP_HOUSE));
    00172   SetHouseTriggers(this->tile, triggers);
    00173 }
    00174
    00175 static uint32 GetNumHouses(HouseID house_id, const Town *town)
    00176 {
    00177   uint8 map_id_count, town_id_count, map_class_count, town_class_count;
    00178   HouseClassID class_id = HouseSpec::Get(house_id)->class_id;
    00179
    00180   map_id_count     = ClampU(_building_counts.id_count[house_id], 0, 255);
    00181   map_class_count  = ClampU(_building_counts.class_count[class_id], 0, 255);
    00182   town_id_count    = ClampU(town->cache.building_counts.id_count[house_id], 0, 255);
    00183   town_class_count = ClampU(town->cache.building_counts.class_count[class_id], 0, 255);
    00184
    00185   return map_class_count << 24 | town_class_count << 16 | map_id_count << 8 | town_id_count;
    00186 }
    00187
    00195 static uint32 GetNearbyTileInformation(byte parameter, TileIndex tile, bool grf_version8)
    00196 {
    00197   tile = GetNearbyTile(parameter, tile);
    00198   return GetNearbyTileInformation(tile, grf_version8);
    00199 }
    00200
    00202 typedef struct {
    00203   const HouseSpec *hs;
    00204   TileIndex north_tile;
    00205 } SearchNearbyHouseData;
    00206
    00213 static bool SearchNearbyHouseID(TileIndex tile, void *user_data)
    00214 {
    00215   if (IsTileType(tile, MP_HOUSE)) {
    00216     HouseID house = GetHouseType(tile); // tile been examined
    00217     const HouseSpec *hs = HouseSpec::Get(house);
    00218     if (hs->grf_prop.grffile != NULL) { // must be one from a grf file
    00219       SearchNearbyHouseData *nbhd = (SearchNearbyHouseData *)user_data;
    00220
    00221       TileIndex north_tile = tile + GetHouseNorthPart(house); // modifies 'house'!
    00222       if (north_tile == nbhd->north_tile) return false; // Always ignore origin house
    00223
    00224       return hs->grf_prop.local_id == nbhd->hs->grf_prop.local_id &&  // same local id as the one requested
    00225         hs->grf_prop.grffile->grfid == nbhd->hs->grf_prop.grffile->grfid;  // from the same grf
    00226     }
    00227   }
    00228   return false;
    00229 }
    00230
    00237 static bool SearchNearbyHouseClass(TileIndex tile, void *user_data)
    00238 {
    00239   if (IsTileType(tile, MP_HOUSE)) {
    00240     HouseID house = GetHouseType(tile); // tile been examined
    00241     const HouseSpec *hs = HouseSpec::Get(house);
    00242     if (hs->grf_prop.grffile != NULL) { // must be one from a grf file
    00243       SearchNearbyHouseData *nbhd = (SearchNearbyHouseData *)user_data;
    00244
    00245       TileIndex north_tile = tile + GetHouseNorthPart(house); // modifies 'house'!
    00246       if (north_tile == nbhd->north_tile) return false; // Always ignore origin house
    00247
    00248       return hs->class_id == nbhd->hs->class_id &&  // same classid as the one requested
    00249         hs->grf_prop.grffile->grfid == nbhd->hs->grf_prop.grffile->grfid;  // from the same grf
    00250     }
    00251   }
    00252   return false;
    00253 }
    00254
    00261 static bool SearchNearbyHouseGRFID(TileIndex tile, void *user_data)
    00262 {
    00263   if (IsTileType(tile, MP_HOUSE)) {
    00264     HouseID house = GetHouseType(tile); // tile been examined
    00265     const HouseSpec *hs = HouseSpec::Get(house);
    00266     if (hs->grf_prop.grffile != NULL) { // must be one from a grf file
    00267       SearchNearbyHouseData *nbhd = (SearchNearbyHouseData *)user_data;
    00268
    00269       TileIndex north_tile = tile + GetHouseNorthPart(house); // modifies 'house'!
    00270       if (north_tile == nbhd->north_tile) return false; // Always ignore origin house
    00271
    00272       return hs->grf_prop.grffile->grfid == nbhd->hs->grf_prop.grffile->grfid;  // from the same grf
    00273     }
    00274   }
    00275   return false;
    00276 }
    00277
    00288 static uint32 GetDistanceFromNearbyHouse(uint8 parameter, TileIndex tile, HouseID house)
    00289 {
    00290   static TestTileOnSearchProc * const search_procs[3] = {
    00291     SearchNearbyHouseID,
    00292     SearchNearbyHouseClass,
    00293     SearchNearbyHouseGRFID,
    00294   };
    00295   TileIndex found_tile = tile;
    00296   uint8 searchtype = GB(parameter, 6, 2);
    00297   uint8 searchradius = GB(parameter, 0, 6);
    00298   if (searchtype >= lengthof(search_procs)) return 0;  // do not run on ill-defined code
    00299   if (searchradius < 1) return 0; // do not use a too low radius
    00300
    00301   SearchNearbyHouseData nbhd;
    00302   nbhd.hs = HouseSpec::Get(house);
    00303   nbhd.north_tile = tile + GetHouseNorthPart(house); // modifies 'house'!
    00304
    00305   /* Use a pointer for the tile to start the search. Will be required for calculating the distance*/
    00306   if (CircularTileSearch(&found_tile, 2 * searchradius + 1, search_procs[searchtype], &nbhd)) {
    00307     return DistanceManhattan(found_tile, tile);
    00308   }
    00309   return 0;
    00310 }
    00311
    00315 /* virtual */ uint32 HouseScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
    00316 {
    00317   switch (variable) {
    00318     /* Construction stage. */
    00319     case 0x40: return (IsTileType(this->tile, MP_HOUSE) ? GetHouseBuildingStage(this->tile) : 0) | TileHash2Bit(TileX(this->tile), TileY(this->tile)) << 2;
    00320
    00321     /* Building age. */
    00322     case 0x41: return IsTileType(this->tile, MP_HOUSE) ? GetHouseAge(this->tile) : 0;
    00323
    00324     /* Town zone */
    00325     case 0x42: return GetTownRadiusGroup(this->town, this->tile);
    00326
    00327     /* Terrain type */
    00328     case 0x43: return GetTerrainType(this->tile);
    00329
    00330     /* Number of this type of building on the map. */
    00331     case 0x44: return GetNumHouses(this->house_id, this->town);
    00332
    00333     /* Whether the town is being created or just expanded. */
    00334     case 0x45: return _generating_world ? 1 : 0;
    00335
    00336     /* Current animation frame. */
    00337     case 0x46: return IsTileType(this->tile, MP_HOUSE) ? GetAnimationFrame(this->tile) : 0;
    00338
    00339     /* Position of the house */
    00340     case 0x47: return TileY(this->tile) << 16 | TileX(this->tile);
    00341
    00342     /* Building counts for old houses with id = parameter. */
    00343     case 0x60: return parameter < NEW_HOUSE_OFFSET ? GetNumHouses(parameter, this->town) : 0;
    00344
    00345     /* Building counts for new houses with id = parameter. */
    00346     case 0x61: {
    00347       const HouseSpec *hs = HouseSpec::Get(this->house_id);
    00348       if (hs->grf_prop.grffile == NULL) return 0;
    00349
    00350       HouseID new_house = _house_mngr.GetID(parameter, hs->grf_prop.grffile->grfid);
    00351       return new_house == INVALID_HOUSE_ID ? 0 : GetNumHouses(new_house, this->town);
    00352     }
    00353
    00354     /* Land info for nearby tiles. */
    00355     case 0x62: return GetNearbyTileInformation(parameter, this->tile, this->ro->grffile->grf_version >= 8);
    00356
    00357     /* Current animation frame of nearby house tiles */
    00358     case 0x63: {
    00359       TileIndex testtile = GetNearbyTile(parameter, this->tile);
    00360       return IsTileType(testtile, MP_HOUSE) ? GetAnimationFrame(testtile) : 0;
    00361     }
    00362
    00363     /* Cargo acceptance history of nearby stations */
    00364     case 0x64: {
    00365       CargoID cid = GetCargoTranslation(parameter, this->ro->grffile);
    00366       if (cid == CT_INVALID) return 0;
    00367
    00368       /* Extract tile offset. */
    00369       int8 x_offs = GB(GetRegister(0x100), 0, 8);
    00370       int8 y_offs = GB(GetRegister(0x100), 8, 8);
    00371       TileIndex testtile = TILE_MASK(this->tile + TileDiffXY(x_offs, y_offs));
    00372
    00373       StationFinder stations(TileArea(testtile, 1, 1));
    00374       const StationList *sl = stations.GetStations();
    00375
    00376       /* Collect acceptance stats. */
    00377       uint32 res = 0;
    00378       for (Station * const * st_iter = sl->Begin(); st_iter != sl->End(); st_iter++) {
    00379         const Station *st = *st_iter;
    00380         if (HasBit(st->goods[cid].acceptance_pickup, GoodsEntry::GES_EVER_ACCEPTED))    SetBit(res, 0);
    00381         if (HasBit(st->goods[cid].acceptance_pickup, GoodsEntry::GES_LAST_MONTH))       SetBit(res, 1);
    00382         if (HasBit(st->goods[cid].acceptance_pickup, GoodsEntry::GES_CURRENT_MONTH))    SetBit(res, 2);
    00383         if (HasBit(st->goods[cid].acceptance_pickup, GoodsEntry::GES_ACCEPTED_BIGTICK)) SetBit(res, 3);
    00384       }
    00385
    00386       /* Cargo triggered CB 148? */
    00387       if (HasBit(this->watched_cargo_triggers, cid)) SetBit(res, 4);
    00388
    00389       return res;
    00390     }
    00391
    00392     /* Distance test for some house types */
    00393     case 0x65: return GetDistanceFromNearbyHouse(parameter, this->tile, this->house_id);
    00394
    00395     /* Class and ID of nearby house tile */
    00396     case 0x66: {
    00397       TileIndex testtile = GetNearbyTile(parameter, this->tile);
    00398       if (!IsTileType(testtile, MP_HOUSE)) return 0xFFFFFFFF;
    00399       HouseSpec *hs = HouseSpec::Get(GetHouseType(testtile));
    00400       /* Information about the grf local classid if the house has a class */
    00401       uint houseclass = 0;
    00402       if (hs->class_id != HOUSE_NO_CLASS) {
    00403         houseclass = (hs->grf_prop.grffile == this->ro->grffile ? 1 : 2) << 8;
    00404         houseclass |= _class_mapping[hs->class_id].class_id;
    00405       }
    00406       /* old house type or grf-local houseid */
    00407       uint local_houseid = 0;
    00408       if (this->house_id < NEW_HOUSE_OFFSET) {
    00409         local_houseid = this->house_id;
    00410       } else {
    00411         local_houseid = (hs->grf_prop.grffile == this->ro->grffile ? 1 : 2) << 8;
    00412         local_houseid |= hs->grf_prop.local_id;
    00413       }
    00414       return houseclass << 16 | local_houseid;
    00415     }
    00416
    00417     /* GRFID of nearby house tile */
    00418     case 0x67: {
    00419       TileIndex testtile = GetNearbyTile(parameter, this->tile);
    00420       if (!IsTileType(testtile, MP_HOUSE)) return 0xFFFFFFFF;
    00421       HouseID house_id = GetHouseType(testtile);
    00422       if (house_id < NEW_HOUSE_OFFSET) return 0;
    00423       /* Checking the grffile information via HouseSpec doesn't work
    00424        * in case the newgrf was removed. */
    00425       return _house_mngr.GetGRFID(house_id);
    00426     }
    00427   }
    00428
    00429   DEBUG(grf, 1, "Unhandled house variable 0x%X", variable);
    00430
    00431   *available = false;
    00432   return UINT_MAX;
    00433 }
    00434
    00435 uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, Town *town, TileIndex tile,
    00436     bool not_yet_constructed, uint8 initial_random_bits, uint32 watched_cargo_triggers)
    00437 {
    00438   assert(IsValidTile(tile) && (not_yet_constructed || IsTileType(tile, MP_HOUSE)));
    00439
    00440   HouseResolverObject object(house_id, tile, town, callback, param1, param2,
    00441       not_yet_constructed, initial_random_bits, watched_cargo_triggers);
    00442
    00443   const SpriteGroup *group = SpriteGroup::Resolve(HouseSpec::Get(house_id)->grf_prop.spritegroup[0], &object);
    00444   if (group == NULL) return CALLBACK_FAILED;
    00445
    00446   return group->GetCallbackResult();
    00447 }
    00448
    00449 static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, byte stage, HouseID house_id)
    00450 {
    00451   const DrawTileSprites *dts = group->ProcessRegisters(&stage);
    00452
    00453   const HouseSpec *hs = HouseSpec::Get(house_id);
    00454   PaletteID palette = hs->random_colour[TileHash2Bit(ti->x, ti->y)] + PALETTE_RECOLOUR_START;
    00455   if (HasBit(hs->callback_mask, CBM_HOUSE_COLOUR)) {
    00456     uint16 callback = GetHouseCallback(CBID_HOUSE_COLOUR, 0, 0, house_id, Town::GetByTile(ti->tile), ti->tile);
    00457     if (callback != CALLBACK_FAILED) {
    00458       /* If bit 14 is set, we should use a 2cc colour map, else use the callback value. */
    00459       palette = HasBit(callback, 14) ? GB(callback, 0, 8) + SPR_2CCMAP_BASE : callback;
    00460     }
    00461   }
    00462
    00463   SpriteID image = dts->ground.sprite;
    00464   PaletteID pal  = dts->ground.pal;
    00465
    00466   if (HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE)) image += stage;
    00467   if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += stage;
    00468
    00469   if (GB(image, 0, SPRITE_WIDTH) != 0) {
    00470     DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, palette));
    00471   }
    00472
    00473   DrawNewGRFTileSeq(ti, dts, TO_HOUSES, stage, palette);
    00474 }
    00475
    00476 void DrawNewHouseTile(TileInfo *ti, HouseID house_id)
    00477 {
    00478   const HouseSpec *hs = HouseSpec::Get(house_id);
    00479
    00480   if (ti->tileh != SLOPE_FLAT) {
    00481     bool draw_old_one = true;
    00482     if (HasBit(hs->callback_mask, CBM_HOUSE_DRAW_FOUNDATIONS)) {
    00483       /* Called to determine the type (if any) of foundation to draw for the house tile */
    00484       uint32 callback_res = GetHouseCallback(CBID_HOUSE_DRAW_FOUNDATIONS, 0, 0, house_id, Town::GetByTile(ti->tile), ti->tile);
    00485       if (callback_res != CALLBACK_FAILED) draw_old_one = ConvertBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DRAW_FOUNDATIONS, callback_res);
    00486     }
    00487
    00488     if (draw_old_one) DrawFoundation(ti, FOUNDATION_LEVELED);
    00489   }
    00490
    00491   HouseResolverObject object(house_id, ti->tile, Town::GetByTile(ti->tile));
    00492
    00493   const SpriteGroup *group = SpriteGroup::Resolve(hs->grf_prop.spritegroup[0], &object);
    00494   if (group != NULL && group->type == SGT_TILELAYOUT) {
    00495     /* Limit the building stage to the number of stages supplied. */
    00496     const TileLayoutSpriteGroup *tlgroup = (const TileLayoutSpriteGroup *)group;
    00497     byte stage = GetHouseBuildingStage(ti->tile);
    00498     DrawTileLayout(ti, tlgroup, stage, house_id);
    00499   }
    00500 }
    00501
    00502 /* Simple wrapper for GetHouseCallback to keep the animation unified. */
    00503 uint16 GetSimpleHouseCallback(CallbackID callback, uint32 param1, uint32 param2, const HouseSpec *spec, Town *town, TileIndex tile, uint32 extra_data)
    00504 {
    00505   return GetHouseCallback(callback, param1, param2, spec - HouseSpec::Get(0), town, tile, false, 0, extra_data);
    00506 }
    00507
    00509 struct HouseAnimationBase : public AnimationBase<HouseAnimationBase, HouseSpec, Town, uint32, GetSimpleHouseCallback> {
    00510   static const CallbackID cb_animation_speed      = CBID_HOUSE_ANIMATION_SPEED;
    00511   static const CallbackID cb_animation_next_frame = CBID_HOUSE_ANIMATION_NEXT_FRAME;
    00512
    00513   static const HouseCallbackMask cbm_animation_speed      = CBM_HOUSE_ANIMATION_SPEED;
    00514   static const HouseCallbackMask cbm_animation_next_frame = CBM_HOUSE_ANIMATION_NEXT_FRAME;
    00515 };
    00516
    00517 void AnimateNewHouseTile(TileIndex tile)
    00518 {
    00519   const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
    00520   if (hs == NULL) return;
    00521
    00522   HouseAnimationBase::AnimateTile(hs, Town::GetByTile(tile), tile, HasBit(hs->extra_flags, CALLBACK_1A_RANDOM_BITS));
    00523 }
    00524
    00525 void AnimateNewHouseConstruction(TileIndex tile)
    00526 {
    00527   const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
    00528
    00529   if (HasBit(hs->callback_mask, CBM_HOUSE_CONSTRUCTION_STATE_CHANGE)) {
    00530     HouseAnimationBase::ChangeAnimationFrame(CBID_HOUSE_CONSTRUCTION_STATE_CHANGE, hs, Town::GetByTile(tile), tile, 0, 0);
    00531   }
    00532 }
    00533
    00534 bool CanDeleteHouse(TileIndex tile)
    00535 {
    00536   const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
    00537
    00538   /* Humans are always allowed to remove buildings, as is water and
    00539    * anyone using the scenario editor. */
    00540   if (Company::IsValidHumanID(_current_company) || _current_company == OWNER_WATER || _current_company == OWNER_NONE) {
    00541     return true;
    00542   }
    00543
    00544   if (HasBit(hs->callback_mask, CBM_HOUSE_DENY_DESTRUCTION)) {
    00545     uint16 callback_res = GetHouseCallback(CBID_HOUSE_DENY_DESTRUCTION, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile);
    00546     return (callback_res == CALLBACK_FAILED || !ConvertBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DENY_DESTRUCTION, callback_res));
    00547   } else {
    00548     return !(hs->extra_flags & BUILDING_IS_PROTECTED);
    00549   }
    00550 }
    00551
    00552 static void AnimationControl(TileIndex tile, uint16 random_bits)
    00553 {
    00554   const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
    00555
    00556   if (HasBit(hs->callback_mask, CBM_HOUSE_ANIMATION_START_STOP)) {
    00557     uint32 param = (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) ? (GB(Random(), 0, 16) | random_bits << 16) : Random();
    00558     HouseAnimationBase::ChangeAnimationFrame(CBID_HOUSE_ANIMATION_START_STOP, hs, Town::GetByTile(tile), tile, param, 0);
    00559   }
    00560 }
    00561
    00562 bool NewHouseTileLoop(TileIndex tile)
    00563 {
    00564   const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
    00565
    00566   if (GetHouseProcessingTime(tile) > 0) {
    00567     DecHouseProcessingTime(tile);
    00568     return true;
    00569   }
    00570
    00571   TriggerHouse(tile, HOUSE_TRIGGER_TILE_LOOP);
    00572   if (hs->building_flags & BUILDING_HAS_1_TILE) TriggerHouse(tile, HOUSE_TRIGGER_TILE_LOOP_TOP);
    00573
    00574   if (HasBit(hs->callback_mask, CBM_HOUSE_ANIMATION_START_STOP)) {
    00575     /* If this house is marked as having a synchronised callback, all the
    00576      * tiles will have the callback called at once, rather than when the
    00577      * tile loop reaches them. This should only be enabled for the northern
    00578      * tile, or strange things will happen (here, and in TTDPatch). */
    00579     if (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) {
    00580       uint16 random = GB(Random(), 0, 16);
    00581
    00582       if (hs->building_flags & BUILDING_HAS_1_TILE)  AnimationControl(tile, random);
    00583       if (hs->building_flags & BUILDING_2_TILES_Y)   AnimationControl(TILE_ADDXY(tile, 0, 1), random);
    00584       if (hs->building_flags & BUILDING_2_TILES_X)   AnimationControl(TILE_ADDXY(tile, 1, 0), random);
    00585       if (hs->building_flags & BUILDING_HAS_4_TILES) AnimationControl(TILE_ADDXY(tile, 1, 1), random);
    00586     } else {
    00587       AnimationControl(tile, 0);
    00588     }
    00589   }
    00590
    00591   /* Check callback 21, which determines if a house should be destroyed. */
    00592   if (HasBit(hs->callback_mask, CBM_HOUSE_DESTRUCTION)) {
    00593     uint16 callback_res = GetHouseCallback(CBID_HOUSE_DESTRUCTION, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile);
    00594     if (callback_res != CALLBACK_FAILED && Convert8bitBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DESTRUCTION, callback_res)) {
    00595       ClearTownHouse(Town::GetByTile(tile), tile);
    00596       return false;
    00597     }
    00598   }
    00599
    00600   SetHouseProcessingTime(tile, hs->processing_time);
    00601   MarkTileDirtyByTile(tile);
    00602   return true;
    00603 }
    00604
    00605 static void DoTriggerHouse(TileIndex tile, HouseTrigger trigger, byte base_random, bool first)
    00606 {
    00607   /* We can't trigger a non-existent building... */
    00608   assert(IsTileType(tile, MP_HOUSE));
    00609
    00610   HouseID hid = GetHouseType(tile);
    00611   HouseSpec *hs = HouseSpec::Get(hid);
    00612
    00613   if (hs->grf_prop.spritegroup == NULL) return;
    00614
    00615   HouseResolverObject object(hid, tile, Town::GetByTile(tile), CBID_RANDOM_TRIGGER);
    00616   object.trigger = trigger;
    00617
    00618   const SpriteGroup *group = SpriteGroup::Resolve(hs->grf_prop.spritegroup[0], &object);
    00619   if (group == NULL) return;
    00620
    00621   byte new_random_bits = Random();
    00622   byte random_bits = GetHouseRandomBits(tile);
    00623   uint32 reseed = object.GetReseedSum(); // The scope only affects triggers, not the reseeding
    00624   random_bits &= ~reseed;
    00625   random_bits |= (first ? new_random_bits : base_random) & reseed;
    00626   SetHouseRandomBits(tile, random_bits);
    00627
    00628   switch (trigger) {
    00629     case HOUSE_TRIGGER_TILE_LOOP:
    00630       /* Random value already set. */
    00631       break;
    00632
    00633     case HOUSE_TRIGGER_TILE_LOOP_TOP:
    00634       if (!first) {
    00635         /* The top tile is marked dirty by the usual TileLoop */
    00636         MarkTileDirtyByTile(tile);
    00637         break;
    00638       }
    00639       /* Random value of first tile already set. */
    00640       if (hs->building_flags & BUILDING_2_TILES_Y)   DoTriggerHouse(TILE_ADDXY(tile, 0, 1), trigger, random_bits, false);
    00641       if (hs->building_flags & BUILDING_2_TILES_X)   DoTriggerHouse(TILE_ADDXY(tile, 1, 0), trigger, random_bits, false);
    00642       if (hs->building_flags & BUILDING_HAS_4_TILES) DoTriggerHouse(TILE_ADDXY(tile, 1, 1), trigger, random_bits, false);
    00643       break;
    00644   }
    00645 }
    00646
    00647 void TriggerHouse(TileIndex t, HouseTrigger trigger)
    00648 {
    00649   DoTriggerHouse(t, trigger, 0, true);
    00650 }
    00651
    00659 void DoWatchedCargoCallback(TileIndex tile, TileIndex origin, uint32 trigger_cargoes, uint16 random)
    00660 {
    00661   TileIndexDiffC diff = TileIndexToTileIndexDiffC(origin, tile);
    00662   uint32 cb_info = random << 16 | (uint8)diff.y << 8 | (uint8)diff.x;
    00663   HouseAnimationBase::ChangeAnimationFrame(CBID_HOUSE_WATCHED_CARGO_ACCEPTED, HouseSpec::Get(GetHouseType(tile)), Town::GetByTile(tile), tile, 0, cb_info, trigger_cargoes);
    00664 }
    00665
    00672 void WatchedCargoCallback(TileIndex tile, uint32 trigger_cargoes)
    00673 {
    00674   assert(IsTileType(tile, MP_HOUSE));
    00675   HouseID id = GetHouseType(tile);
    00676   const HouseSpec *hs = HouseSpec::Get(id);
    00677
    00678   trigger_cargoes &= hs->watched_cargoes;
    00679   /* None of the trigger cargoes is watched? */
    00680   if (trigger_cargoes == 0) return;
    00681
    00682   /* Same random value for all tiles of a multi-tile house. */
    00683   uint16 r = Random();
    00684
    00685   /* Do the callback, start at northern tile. */
    00686   TileIndex north = tile + GetHouseNorthPart(id);
    00687   hs = HouseSpec::Get(id);
    00688
    00689   DoWatchedCargoCallback(north, tile, trigger_cargoes, r);
    00690   if (hs->building_flags & BUILDING_2_TILES_Y)   DoWatchedCargoCallback(TILE_ADDXY(north, 0, 1), tile, trigger_cargoes, r);
    00691   if (hs->building_flags & BUILDING_2_TILES_X)   DoWatchedCargoCallback(TILE_ADDXY(north, 1, 0), tile, trigger_cargoes, r);
    00692   if (hs->building_flags & BUILDING_HAS_4_TILES) DoWatchedCargoCallback(TILE_ADDXY(north, 1, 1), tile, trigger_cargoes, r);
    00693 }
    00694