OpenTTD Source  20241108-master-g80f628063a
newgrf_house.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * 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.
4  * 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.
5  * 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/>.
6  */
7 
10 #include "stdafx.h"
11 #include "debug.h"
12 #include "landscape.h"
13 #include "newgrf_house.h"
14 #include "newgrf_spritegroup.h"
15 #include "newgrf_town.h"
16 #include "newgrf_sound.h"
17 #include "company_func.h"
18 #include "company_base.h"
19 #include "town.h"
20 #include "genworld.h"
21 #include "newgrf_animation_base.h"
22 #include "newgrf_cargo.h"
23 #include "station_base.h"
24 
25 #include "safeguards.h"
26 
27 static BuildingCounts<uint32_t> _building_counts{};
28 static std::vector<HouseClassMapping> _class_mapping{};
29 
30 HouseOverrideManager _house_mngr(NEW_HOUSE_OFFSET, NUM_HOUSES, INVALID_HOUSE_ID);
31 
37 static const GRFFile *GetHouseSpecGrf(HouseID house_id)
38 {
39  const HouseSpec *hs = HouseSpec::Get(house_id);
40  return (hs != nullptr) ? hs->grf_prop.grffile : nullptr;
41 }
42 
44 std::vector<HouseSpec> _house_specs;
45 
50 std::vector<HouseSpec> &HouseSpec::Specs()
51 {
52  return _house_specs;
53 }
54 
60 {
61  return static_cast<HouseID>(this - _house_specs.data());
62 }
63 
69 HouseSpec *HouseSpec::Get(size_t house_id)
70 {
71  /* Empty house if index is out of range -- this might happen if NewGRFs are changed. */
72  static HouseSpec empty = {};
73 
74  assert(house_id < NUM_HOUSES);
75  if (house_id >= _house_specs.size()) return &empty;
76  return &_house_specs[house_id];
77 }
78 
79 /* Reset and initialise house specs. */
80 void ResetHouses()
81 {
82  _house_specs.clear();
83  _house_specs.reserve(std::size(_original_house_specs));
84 
85  ResetHouseClassIDs();
86 
87  /* Copy default houses. */
88  _house_specs.insert(std::end(_house_specs), std::begin(_original_house_specs), std::end(_original_house_specs));
89 
90  /* Reset any overrides that have been set. */
91  _house_mngr.ResetOverride();
92 }
93 
107  CallbackID callback, uint32_t param1, uint32_t param2,
108  bool not_yet_constructed, uint8_t initial_random_bits, CargoTypes watched_cargo_triggers, int view)
109  : ResolverObject(GetHouseSpecGrf(house_id), callback, param1, param2),
110  house_scope(*this, house_id, tile, town, not_yet_constructed, initial_random_bits, watched_cargo_triggers, view),
111  town_scope(*this, town, not_yet_constructed) // Don't access StorePSA if house is not yet constructed.
112 {
113  /* Tile must be valid and a house tile, unless not yet constructed in which case it may also be INVALID_TILE. */
114  assert((IsValidTile(tile) && (not_yet_constructed || IsTileType(tile, MP_HOUSE))) || (not_yet_constructed && tile == INVALID_TILE));
115 
116  this->root_spritegroup = HouseSpec::Get(house_id)->grf_prop.spritegroup[0];
117 }
118 
120 {
121  return GSF_HOUSES;
122 }
123 
125 {
126  return HouseSpec::Get(this->house_scope.house_id)->grf_prop.local_id;
127 }
128 
129 void ResetHouseClassIDs()
130 {
131  _class_mapping.clear();
132 
133  /* Add initial entry for HOUSE_NO_CLASS. */
134  _class_mapping.emplace_back();
135 }
136 
137 HouseClassID AllocateHouseClassID(uint8_t grf_class_id, uint32_t grfid)
138 {
139  /* Start from 1 because 0 means that no class has been assigned. */
140  auto it = std::find_if(std::next(std::begin(_class_mapping)), std::end(_class_mapping), [grf_class_id, grfid](const HouseClassMapping &map) { return map.class_id == grf_class_id && map.grfid == grfid; });
141 
142  /* HouseClass not found, allocate a new one. */
143  if (it == std::end(_class_mapping)) it = _class_mapping.insert(it, {.grfid = grfid, .class_id = grf_class_id});
144 
145  return static_cast<HouseClassID>(std::distance(std::begin(_class_mapping), it));
146 }
147 
153 {
154  t->cache.building_counts.id_count.clear();
155  t->cache.building_counts.class_count.clear();
156  t->cache.building_counts.id_count.resize(HouseSpec::Specs().size());
157  t->cache.building_counts.class_count.resize(_class_mapping.size());
158 }
159 
164 {
165  _building_counts.id_count.clear();
166  _building_counts.class_count.clear();
167  _building_counts.id_count.resize(HouseSpec::Specs().size());
168  _building_counts.class_count.resize(_class_mapping.size());
169 
170  for (Town *t : Town::Iterate()) {
172  }
173 }
174 
179 std::span<const uint> GetBuildingHouseIDCounts()
180 {
181  return _building_counts.id_count;
182 }
183 
191 {
192  HouseClassID class_id = HouseSpec::Get(house_id)->class_id;
193 
194  t->cache.building_counts.id_count[house_id]++;
195  _building_counts.id_count[house_id]++;
196 
197  if (class_id == HOUSE_NO_CLASS) return;
198 
199  t->cache.building_counts.class_count[class_id]++;
200  _building_counts.class_count[class_id]++;
201 }
202 
210 {
211  HouseClassID class_id = HouseSpec::Get(house_id)->class_id;
212 
213  if (t->cache.building_counts.id_count[house_id] > 0) t->cache.building_counts.id_count[house_id]--;
214  if (_building_counts.id_count[house_id] > 0) _building_counts.id_count[house_id]--;
215 
216  if (class_id == HOUSE_NO_CLASS) return;
217 
218  if (t->cache.building_counts.class_count[class_id] > 0) t->cache.building_counts.class_count[class_id]--;
219  if (_building_counts.class_count[class_id] > 0) _building_counts.class_count[class_id]--;
220 }
221 
222 /* virtual */ uint32_t HouseScopeResolver::GetRandomBits() const
223 {
224  /* Note: Towns build houses over houses. So during construction checks 'tile' may be a valid but unrelated house. */
225  return this->not_yet_constructed ? this->initial_random_bits : GetHouseRandomBits(this->tile);
226 }
227 
228 /* virtual */ uint32_t HouseScopeResolver::GetTriggers() const
229 {
230  /* Note: Towns build houses over houses. So during construction checks 'tile' may be a valid but unrelated house. */
231  return this->not_yet_constructed ? 0 : GetHouseTriggers(this->tile);
232 }
233 
234 static uint32_t GetNumHouses(HouseID house_id, const Town *town)
235 {
236  HouseClassID class_id = HouseSpec::Get(house_id)->class_id;
237 
238  uint8_t map_id_count = ClampTo<uint8_t>(_building_counts.id_count[house_id]);
239  uint8_t map_class_count = ClampTo<uint8_t>(_building_counts.class_count[class_id]);
240  uint8_t town_id_count = ClampTo<uint8_t>(town->cache.building_counts.id_count[house_id]);
241  uint8_t town_class_count = ClampTo<uint8_t>(town->cache.building_counts.class_count[class_id]);
242 
243  return map_class_count << 24 | town_class_count << 16 | map_id_count << 8 | town_id_count;
244 }
245 
253 static uint32_t GetNearbyTileInformation(uint8_t parameter, TileIndex tile, bool grf_version8)
254 {
255  tile = GetNearbyTile(parameter, tile);
256  return GetNearbyTileInformation(tile, grf_version8);
257 }
258 
261  const HouseSpec *hs;
263 };
264 
271 static bool SearchNearbyHouseID(TileIndex tile, void *user_data)
272 {
273  if (IsTileType(tile, MP_HOUSE)) {
274  HouseID house = GetHouseType(tile); // tile been examined
275  const HouseSpec *hs = HouseSpec::Get(house);
276  if (hs->grf_prop.grffile != nullptr) { // must be one from a grf file
277  SearchNearbyHouseData *nbhd = (SearchNearbyHouseData *)user_data;
278 
279  TileIndex north_tile = tile + GetHouseNorthPart(house); // modifies 'house'!
280  if (north_tile == nbhd->north_tile) return false; // Always ignore origin house
281 
282  return hs->grf_prop.local_id == nbhd->hs->grf_prop.local_id && // same local id as the one requested
283  hs->grf_prop.grffile->grfid == nbhd->hs->grf_prop.grffile->grfid; // from the same grf
284  }
285  }
286  return false;
287 }
288 
295 static bool SearchNearbyHouseClass(TileIndex tile, void *user_data)
296 {
297  if (IsTileType(tile, MP_HOUSE)) {
298  HouseID house = GetHouseType(tile); // tile been examined
299  const HouseSpec *hs = HouseSpec::Get(house);
300  if (hs->grf_prop.grffile != nullptr) { // must be one from a grf file
301  SearchNearbyHouseData *nbhd = (SearchNearbyHouseData *)user_data;
302 
303  TileIndex north_tile = tile + GetHouseNorthPart(house); // modifies 'house'!
304  if (north_tile == nbhd->north_tile) return false; // Always ignore origin house
305 
306  return hs->class_id == nbhd->hs->class_id && // same classid as the one requested
307  hs->grf_prop.grffile->grfid == nbhd->hs->grf_prop.grffile->grfid; // from the same grf
308  }
309  }
310  return false;
311 }
312 
319 static bool SearchNearbyHouseGRFID(TileIndex tile, void *user_data)
320 {
321  if (IsTileType(tile, MP_HOUSE)) {
322  HouseID house = GetHouseType(tile); // tile been examined
323  const HouseSpec *hs = HouseSpec::Get(house);
324  if (hs->grf_prop.grffile != nullptr) { // must be one from a grf file
325  SearchNearbyHouseData *nbhd = (SearchNearbyHouseData *)user_data;
326 
327  TileIndex north_tile = tile + GetHouseNorthPart(house); // modifies 'house'!
328  if (north_tile == nbhd->north_tile) return false; // Always ignore origin house
329 
330  return hs->grf_prop.grffile->grfid == nbhd->hs->grf_prop.grffile->grfid; // from the same grf
331  }
332  }
333  return false;
334 }
335 
346 static uint32_t GetDistanceFromNearbyHouse(uint8_t parameter, TileIndex tile, HouseID house)
347 {
348  static TestTileOnSearchProc * const search_procs[3] = {
352  };
353  TileIndex found_tile = tile;
354  uint8_t searchtype = GB(parameter, 6, 2);
355  uint8_t searchradius = GB(parameter, 0, 6);
356  if (searchtype >= lengthof(search_procs)) return 0; // do not run on ill-defined code
357  if (searchradius < 1) return 0; // do not use a too low radius
358 
360  nbhd.hs = HouseSpec::Get(house);
361  nbhd.north_tile = tile + GetHouseNorthPart(house); // modifies 'house'!
362 
363  /* Use a pointer for the tile to start the search. Will be required for calculating the distance*/
364  if (CircularTileSearch(&found_tile, 2 * searchradius + 1, search_procs[searchtype], &nbhd)) {
365  return DistanceManhattan(found_tile, tile);
366  }
367  return 0;
368 }
369 
373 /* virtual */ uint32_t HouseScopeResolver::GetVariable(uint8_t variable, [[maybe_unused]] uint32_t parameter, bool &available) const
374 {
375  if (this->tile == INVALID_TILE) {
376  /* House does not yet exist, nor is it being planned to exist. Provide some default values intead. */
377  switch (variable) {
378  case 0x40: return TOWN_HOUSE_COMPLETED | this->view << 2; /* Construction stage. */
379  case 0x41: return 0;
380  case 0x42: return 0;
381  case 0x43: return 0;
382  case 0x44: return 0;
383  case 0x45: return _generating_world ? 1 : 0;
384  case 0x46: return 0;
385  case 0x47: return 0;
386  case 0x60: return 0;
387  case 0x61: return 0;
388  case 0x62: return 0;
389  case 0x63: return 0;
390  case 0x64: return 0;
391  case 0x65: return 0;
392  case 0x66: return 0xFFFFFFFF; /* Class and ID of nearby house. */
393  case 0x67: return 0;
394  }
395 
396  Debug(grf, 1, "Unhandled house variable 0x{:X}", variable);
397  available = false;
398  return UINT_MAX;
399  }
400 
401  switch (variable) {
402  /* Construction stage. */
403  case 0x40: return (IsTileType(this->tile, MP_HOUSE) ? GetHouseBuildingStage(this->tile) : 0) | TileHash2Bit(TileX(this->tile), TileY(this->tile)) << 2;
404 
405  /* Building age. */
406  case 0x41: return IsTileType(this->tile, MP_HOUSE) ? GetHouseAge(this->tile).base() : 0;
407 
408  /* Town zone */
409  case 0x42: return GetTownRadiusGroup(this->town, this->tile);
410 
411  /* Terrain type */
412  case 0x43: return GetTerrainType(this->tile);
413 
414  /* Number of this type of building on the map. */
415  case 0x44: return GetNumHouses(this->house_id, this->town);
416 
417  /* Whether the town is being created or just expanded. */
418  case 0x45: return _generating_world ? 1 : 0;
419 
420  /* Current animation frame. */
421  case 0x46: return IsTileType(this->tile, MP_HOUSE) ? GetAnimationFrame(this->tile) : 0;
422 
423  /* Position of the house */
424  case 0x47: return TileY(this->tile) << 16 | TileX(this->tile);
425 
426  /* Building counts for old houses with id = parameter. */
427  case 0x60: return parameter < NEW_HOUSE_OFFSET ? GetNumHouses(parameter, this->town) : 0;
428 
429  /* Building counts for new houses with id = parameter. */
430  case 0x61: {
431  const HouseSpec *hs = HouseSpec::Get(this->house_id);
432  if (hs->grf_prop.grffile == nullptr) return 0;
433 
434  HouseID new_house = _house_mngr.GetID(parameter, hs->grf_prop.grffile->grfid);
435  return new_house == INVALID_HOUSE_ID ? 0 : GetNumHouses(new_house, this->town);
436  }
437 
438  /* Land info for nearby tiles. */
439  case 0x62: return GetNearbyTileInformation(parameter, this->tile, this->ro.grffile->grf_version >= 8);
440 
441  /* Current animation frame of nearby house tiles */
442  case 0x63: {
443  TileIndex testtile = GetNearbyTile(parameter, this->tile);
444  return IsTileType(testtile, MP_HOUSE) ? GetAnimationFrame(testtile) : 0;
445  }
446 
447  /* Cargo acceptance history of nearby stations */
448  case 0x64: {
449  CargoID cid = GetCargoTranslation(parameter, this->ro.grffile);
450  if (!IsValidCargoID(cid)) return 0;
451 
452  /* Extract tile offset. */
453  int8_t x_offs = GB(GetRegister(0x100), 0, 8);
454  int8_t y_offs = GB(GetRegister(0x100), 8, 8);
455  TileIndex testtile = Map::WrapToMap(this->tile + TileDiffXY(x_offs, y_offs));
456 
457  StationFinder stations(TileArea(testtile, 1, 1));
458  const StationList *sl = stations.GetStations();
459 
460  /* Collect acceptance stats. */
461  uint32_t res = 0;
462  for (Station *st : *sl) {
463  if (HasBit(st->goods[cid].status, GoodsEntry::GES_EVER_ACCEPTED)) SetBit(res, 0);
464  if (HasBit(st->goods[cid].status, GoodsEntry::GES_LAST_MONTH)) SetBit(res, 1);
465  if (HasBit(st->goods[cid].status, GoodsEntry::GES_CURRENT_MONTH)) SetBit(res, 2);
466  if (HasBit(st->goods[cid].status, GoodsEntry::GES_ACCEPTED_BIGTICK)) SetBit(res, 3);
467  }
468 
469  /* Cargo triggered CB 148? */
470  if (HasBit(this->watched_cargo_triggers, cid)) SetBit(res, 4);
471 
472  return res;
473  }
474 
475  /* Distance test for some house types */
476  case 0x65: return GetDistanceFromNearbyHouse(parameter, this->tile, this->house_id);
477 
478  /* Class and ID of nearby house tile */
479  case 0x66: {
480  TileIndex testtile = GetNearbyTile(parameter, this->tile);
481  if (!IsTileType(testtile, MP_HOUSE)) return 0xFFFFFFFF;
482  HouseID nearby_house_id = GetHouseType(testtile);
483  HouseSpec *hs = HouseSpec::Get(nearby_house_id);
484  /* Information about the grf local classid if the house has a class */
485  uint houseclass = 0;
486  if (hs->class_id != HOUSE_NO_CLASS) {
487  houseclass = (hs->grf_prop.grffile == this->ro.grffile ? 1 : 2) << 8;
488  houseclass |= _class_mapping[hs->class_id].class_id;
489  }
490  /* old house type or grf-local houseid */
491  uint local_houseid = 0;
492  if (nearby_house_id < NEW_HOUSE_OFFSET) {
493  local_houseid = nearby_house_id;
494  } else {
495  local_houseid = (hs->grf_prop.grffile == this->ro.grffile ? 1 : 2) << 8;
496  local_houseid |= hs->grf_prop.local_id;
497  }
498  return houseclass << 16 | local_houseid;
499  }
500 
501  /* GRFID of nearby house tile */
502  case 0x67: {
503  TileIndex testtile = GetNearbyTile(parameter, this->tile);
504  if (!IsTileType(testtile, MP_HOUSE)) return 0xFFFFFFFF;
505  HouseID house_id = GetHouseType(testtile);
506  if (house_id < NEW_HOUSE_OFFSET) return 0;
507  /* Checking the grffile information via HouseSpec doesn't work
508  * in case the newgrf was removed. */
509  return _house_mngr.GetGRFID(house_id);
510  }
511  }
512 
513  Debug(grf, 1, "Unhandled house variable 0x{:X}", variable);
514 
515  available = false;
516  return UINT_MAX;
517 }
518 
519 uint16_t GetHouseCallback(CallbackID callback, uint32_t param1, uint32_t param2, HouseID house_id, Town *town, TileIndex tile,
520  bool not_yet_constructed, uint8_t initial_random_bits, CargoTypes watched_cargo_triggers, int view)
521 {
522  HouseResolverObject object(house_id, tile, town, callback, param1, param2,
523  not_yet_constructed, initial_random_bits, watched_cargo_triggers, view);
524  return object.ResolveCallback();
525 }
526 
527 static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, uint8_t stage, HouseID house_id)
528 {
529  const DrawTileSprites *dts = group->ProcessRegisters(&stage);
530 
531  const HouseSpec *hs = HouseSpec::Get(house_id);
532  PaletteID palette = GENERAL_SPRITE_COLOUR(hs->random_colour[TileHash2Bit(ti->x, ti->y)]);
534  uint16_t callback = GetHouseCallback(CBID_HOUSE_COLOUR, 0, 0, house_id, Town::GetByTile(ti->tile), ti->tile);
535  if (callback != CALLBACK_FAILED) {
536  /* If bit 14 is set, we should use a 2cc colour map, else use the callback value. */
537  palette = HasBit(callback, 14) ? GB(callback, 0, 8) + SPR_2CCMAP_BASE : callback;
538  }
539  }
540 
541  SpriteID image = dts->ground.sprite;
542  PaletteID pal = dts->ground.pal;
543 
544  if (HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE)) image += stage;
545  if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += stage;
546 
547  if (GB(image, 0, SPRITE_WIDTH) != 0) {
548  DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, palette));
549  }
550 
551  DrawNewGRFTileSeq(ti, dts, TO_HOUSES, stage, palette);
552 }
553 
554 void DrawNewHouseTile(TileInfo *ti, HouseID house_id)
555 {
556  const HouseSpec *hs = HouseSpec::Get(house_id);
557 
558  if (ti->tileh != SLOPE_FLAT) {
559  bool draw_old_one = true;
561  /* Called to determine the type (if any) of foundation to draw for the house tile */
562  uint32_t callback_res = GetHouseCallback(CBID_HOUSE_DRAW_FOUNDATIONS, 0, 0, house_id, Town::GetByTile(ti->tile), ti->tile);
563  if (callback_res != CALLBACK_FAILED) draw_old_one = ConvertBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DRAW_FOUNDATIONS, callback_res);
564  }
565 
566  if (draw_old_one) DrawFoundation(ti, FOUNDATION_LEVELED);
567  }
568 
569  HouseResolverObject object(house_id, ti->tile, Town::GetByTile(ti->tile));
570 
571  const SpriteGroup *group = object.Resolve();
572  if (group != nullptr && group->type == SGT_TILELAYOUT) {
573  /* Limit the building stage to the number of stages supplied. */
574  const TileLayoutSpriteGroup *tlgroup = (const TileLayoutSpriteGroup *)group;
575  uint8_t stage = GetHouseBuildingStage(ti->tile);
576  DrawTileLayout(ti, tlgroup, stage, house_id);
577  }
578 }
579 
580 /* Simple wrapper for GetHouseCallback to keep the animation unified. */
581 uint16_t GetSimpleHouseCallback(CallbackID callback, uint32_t param1, uint32_t param2, const HouseSpec *spec, Town *town, TileIndex tile, CargoTypes extra_data)
582 {
583  return GetHouseCallback(callback, param1, param2, spec - HouseSpec::Get(0), town, tile, false, 0, extra_data);
584 }
585 
587 struct HouseAnimationBase : public AnimationBase<HouseAnimationBase, HouseSpec, Town, CargoTypes, GetSimpleHouseCallback, TileAnimationFrameAnimationHelper<Town> > {
588  static const CallbackID cb_animation_speed = CBID_HOUSE_ANIMATION_SPEED;
589  static const CallbackID cb_animation_next_frame = CBID_HOUSE_ANIMATION_NEXT_FRAME;
590 
591  static const HouseCallbackMask cbm_animation_speed = CBM_HOUSE_ANIMATION_SPEED;
592  static const HouseCallbackMask cbm_animation_next_frame = CBM_HOUSE_ANIMATION_NEXT_FRAME;
593 };
594 
595 void AnimateNewHouseTile(TileIndex tile)
596 {
597  const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
598  if (hs == nullptr) return;
599 
600  HouseAnimationBase::AnimateTile(hs, Town::GetByTile(tile), tile, HasFlag(hs->extra_flags, CALLBACK_1A_RANDOM_BITS));
601 }
602 
603 void AnimateNewHouseConstruction(TileIndex tile)
604 {
605  const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
606 
609  }
610 }
611 
612 bool CanDeleteHouse(TileIndex tile)
613 {
614  const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
615 
616  /* Humans are always allowed to remove buildings, as is water and disasters and
617  * anyone using the scenario editor. */
619  return true;
620  }
621 
623  uint16_t callback_res = GetHouseCallback(CBID_HOUSE_DENY_DESTRUCTION, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile);
624  return (callback_res == CALLBACK_FAILED || !ConvertBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DENY_DESTRUCTION, callback_res));
625  } else {
626  return !(hs->extra_flags & BUILDING_IS_PROTECTED);
627  }
628 }
629 
630 static void AnimationControl(TileIndex tile, uint16_t random_bits)
631 {
632  const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
633 
635  uint32_t param = (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) ? (GB(Random(), 0, 16) | random_bits << 16) : Random();
636  HouseAnimationBase::ChangeAnimationFrame(CBID_HOUSE_ANIMATION_START_STOP, hs, Town::GetByTile(tile), tile, param, 0);
637  }
638 }
639 
640 bool NewHouseTileLoop(TileIndex tile)
641 {
642  const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
643 
644  if (GetHouseProcessingTime(tile) > 0) {
646  return true;
647  }
648 
649  TriggerHouse(tile, HOUSE_TRIGGER_TILE_LOOP);
650  if (hs->building_flags & BUILDING_HAS_1_TILE) TriggerHouse(tile, HOUSE_TRIGGER_TILE_LOOP_TOP);
651 
653  /* If this house is marked as having a synchronised callback, all the
654  * tiles will have the callback called at once, rather than when the
655  * tile loop reaches them. This should only be enabled for the northern
656  * tile, or strange things will happen (here, and in TTDPatch). */
658  uint16_t random = GB(Random(), 0, 16);
659 
660  if (hs->building_flags & BUILDING_HAS_1_TILE) AnimationControl(tile, random);
661  if (hs->building_flags & BUILDING_2_TILES_Y) AnimationControl(TileAddXY(tile, 0, 1), random);
662  if (hs->building_flags & BUILDING_2_TILES_X) AnimationControl(TileAddXY(tile, 1, 0), random);
663  if (hs->building_flags & BUILDING_HAS_4_TILES) AnimationControl(TileAddXY(tile, 1, 1), random);
664  } else {
665  AnimationControl(tile, 0);
666  }
667  }
668 
669  /* Check callback 21, which determines if a house should be destroyed. */
671  uint16_t callback_res = GetHouseCallback(CBID_HOUSE_DESTRUCTION, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile);
672  if (callback_res != CALLBACK_FAILED && Convert8bitBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DESTRUCTION, callback_res)) {
673  ClearTownHouse(Town::GetByTile(tile), tile);
674  return false;
675  }
676  }
677 
679  MarkTileDirtyByTile(tile);
680  return true;
681 }
682 
683 static void DoTriggerHouse(TileIndex tile, HouseTrigger trigger, uint8_t base_random, bool first)
684 {
685  /* We can't trigger a non-existent building... */
686  assert(IsTileType(tile, MP_HOUSE));
687 
688  HouseID hid = GetHouseType(tile);
689  HouseSpec *hs = HouseSpec::Get(hid);
690 
691  if (hs->grf_prop.spritegroup[0] == nullptr) return;
692 
693  HouseResolverObject object(hid, tile, Town::GetByTile(tile), CBID_RANDOM_TRIGGER);
694  object.waiting_triggers = GetHouseTriggers(tile) | trigger;
695  SetHouseTriggers(tile, object.waiting_triggers); // store now for var 5F
696 
697  const SpriteGroup *group = object.Resolve();
698  if (group == nullptr) return;
699 
700  /* Store remaining triggers. */
701  SetHouseTriggers(tile, object.GetRemainingTriggers());
702 
703  /* Rerandomise bits. Scopes other than SELF are invalid for houses. For bug-to-bug-compatibility with TTDP we ignore the scope. */
704  uint8_t new_random_bits = Random();
705  uint8_t random_bits = GetHouseRandomBits(tile);
706  uint32_t reseed = object.GetReseedSum();
707  random_bits &= ~reseed;
708  random_bits |= (first ? new_random_bits : base_random) & reseed;
709  SetHouseRandomBits(tile, random_bits);
710 
711  switch (trigger) {
712  case HOUSE_TRIGGER_TILE_LOOP:
713  /* Random value already set. */
714  break;
715 
716  case HOUSE_TRIGGER_TILE_LOOP_TOP:
717  if (!first) {
718  /* The top tile is marked dirty by the usual TileLoop */
719  MarkTileDirtyByTile(tile);
720  break;
721  }
722  /* Random value of first tile already set. */
723  if (hs->building_flags & BUILDING_2_TILES_Y) DoTriggerHouse(TileAddXY(tile, 0, 1), trigger, random_bits, false);
724  if (hs->building_flags & BUILDING_2_TILES_X) DoTriggerHouse(TileAddXY(tile, 1, 0), trigger, random_bits, false);
725  if (hs->building_flags & BUILDING_HAS_4_TILES) DoTriggerHouse(TileAddXY(tile, 1, 1), trigger, random_bits, false);
726  break;
727  }
728 }
729 
730 void TriggerHouse(TileIndex t, HouseTrigger trigger)
731 {
732  DoTriggerHouse(t, trigger, 0, true);
733 }
734 
742 void DoWatchedCargoCallback(TileIndex tile, TileIndex origin, CargoTypes trigger_cargoes, uint16_t random)
743 {
744  TileIndexDiffC diff = TileIndexToTileIndexDiffC(origin, tile);
745  uint32_t cb_info = random << 16 | (uint8_t)diff.y << 8 | (uint8_t)diff.x;
746  HouseAnimationBase::ChangeAnimationFrame(CBID_HOUSE_WATCHED_CARGO_ACCEPTED, HouseSpec::Get(GetHouseType(tile)), Town::GetByTile(tile), tile, 0, cb_info, trigger_cargoes);
747 }
748 
755 void WatchedCargoCallback(TileIndex tile, CargoTypes trigger_cargoes)
756 {
757  assert(IsTileType(tile, MP_HOUSE));
758  HouseID id = GetHouseType(tile);
759  const HouseSpec *hs = HouseSpec::Get(id);
760 
761  trigger_cargoes &= hs->watched_cargoes;
762  /* None of the trigger cargoes is watched? */
763  if (trigger_cargoes == 0) return;
764 
765  /* Same random value for all tiles of a multi-tile house. */
766  uint16_t r = Random();
767 
768  /* Do the callback, start at northern tile. */
769  TileIndex north = tile + GetHouseNorthPart(id);
770  hs = HouseSpec::Get(id);
771 
772  DoWatchedCargoCallback(north, tile, trigger_cargoes, r);
773  if (hs->building_flags & BUILDING_2_TILES_Y) DoWatchedCargoCallback(TileAddXY(north, 0, 1), tile, trigger_cargoes, r);
774  if (hs->building_flags & BUILDING_2_TILES_X) DoWatchedCargoCallback(TileAddXY(north, 1, 0), tile, trigger_cargoes, r);
775  if (hs->building_flags & BUILDING_HAS_4_TILES) DoWatchedCargoCallback(TileAddXY(north, 1, 1), tile, trigger_cargoes, r);
776 }
777 
constexpr debug_inline bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr static debug_inline uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
uint8_t CargoID
Cargo slots to indicate a cargo type within a game.
Definition: cargo_type.h:22
bool IsValidCargoID(CargoID t)
Test whether cargo type is not INVALID_CARGO.
Definition: cargo_type.h:107
uint32_t GetGRFID(uint16_t entity_id) const
Gives the GRFID of the file the entity belongs to.
virtual uint16_t GetID(uint16_t grf_local_id, uint32_t grfid) const
Return the ID (if ever available) of a previously inserted entity.
void ResetOverride()
Resets the override, which is used while initializing game.
Structure contains cached list of stations nearby.
Definition: station_type.h:100
const StationList * GetStations()
Run a tile loop to find stations around a tile, on demand.
Definition of stuff that is very close to a company, like the company struct itself.
CompanyID _current_company
Company currently doing an action.
Definition: company_cmd.cpp:53
Functions related to companies.
@ OWNER_NONE
The tile has no ownership.
Definition: company_type.h:25
@ OWNER_WATER
The tile/execution is done by "water".
Definition: company_type.h:26
Functions related to debugging.
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition: debug.h:37
constexpr debug_inline bool HasFlag(const T x, const T y)
Checks if a value in a bitset enum is set.
Definition: enum_type.hpp:58
bool _generating_world
Whether we are generating the map or not.
Definition: genworld.cpp:67
Functions related to world/map generation.
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition: gfx_type.h:18
uint32_t PaletteID
The number of the palette.
Definition: gfx_type.h:19
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
Definition: viewport.cpp:2057
static const HouseID NUM_HOUSES
Total number of houses.
Definition: house.h:29
static const HouseID NEW_HOUSE_OFFSET
Offset for new houses.
Definition: house.h:28
static const uint8_t TOWN_HOUSE_COMPLETED
Simple value that indicates the house has reached the final stage of construction.
Definition: house.h:23
@ BUILDING_IS_PROTECTED
towns and AI will not remove this house, while human players will be able to
Definition: house.h:86
@ SYNCHRONISED_CALLBACK_1B
synchronized callback 1B will be performed, on multi tile houses
Definition: house.h:87
@ CALLBACK_1A_RANDOM_BITS
callback 1A needs random bits
Definition: house.h:88
uint16_t HouseClassID
Classes of houses.
Definition: house_type.h:14
uint16_t HouseID
OpenTTD ID of house types.
Definition: house_type.h:13
void DrawFoundation(TileInfo *ti, Foundation f)
Draw foundation f at tile ti.
Definition: landscape.cpp:425
Functions related to OTTD's landscape.
bool CircularTileSearch(TileIndex *tile, uint size, TestTileOnSearchProc proc, void *user_data)
Function performing a search around a center tile and going outward, thus in circle.
Definition: map.cpp:247
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition: map.cpp:146
TileIndex TileAddXY(TileIndex tile, int x, int y)
Adds a given offset to a tile.
Definition: map_func.h:467
TileIndexDiff TileDiffXY(int x, int y)
Calculates an offset for the given coordinate(-offset).
Definition: map_func.h:389
bool TestTileOnSearchProc(TileIndex tile, void *user_data)
A callback function type for searching tiles.
Definition: map_func.h:640
static debug_inline uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition: map_func.h:425
static debug_inline uint TileX(TileIndex tile)
Get the X component of a tile.
Definition: map_func.h:415
TileIndexDiffC TileIndexToTileIndexDiffC(TileIndex tile_a, TileIndex tile_b)
Returns the diff between two tiles.
Definition: map_func.h:528
GrfSpecFeature
Definition: newgrf.h:67
Function implementations related to NewGRF animation.
CallbackID
List of implemented NewGRF callbacks.
@ CBID_HOUSE_ANIMATION_START_STOP
Called for periodically starting or stopping the animation.
@ CBID_HOUSE_CONSTRUCTION_STATE_CHANGE
Called whenever the construction state of a house changes.
@ CBID_HOUSE_COLOUR
Called to determine the colour of a town building.
@ CBID_HOUSE_DRAW_FOUNDATIONS
Called to determine the type (if any) of foundation to draw for house tile.
@ CBID_HOUSE_ANIMATION_SPEED
Called to indicate how long the current animation frame should last.
@ CBID_HOUSE_ANIMATION_NEXT_FRAME
Determine the next animation frame for a house.
@ CBID_HOUSE_DENY_DESTRUCTION
Called to determine whether a town building can be destroyed.
@ CBID_HOUSE_WATCHED_CARGO_ACCEPTED
Called when a cargo type specified in property 20 is accepted.
@ CBID_RANDOM_TRIGGER
Set when calling a randomizing trigger (almost undocumented).
@ CBID_HOUSE_DESTRUCTION
Called periodically to determine if a house should be destroyed.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
HouseCallbackMask
Callback masks for houses.
@ CBM_HOUSE_COLOUR
decide the colour of the building
@ CBM_HOUSE_ANIMATION_SPEED
decides animation speed
@ CBM_HOUSE_ANIMATION_NEXT_FRAME
decides next animation frame
@ CBM_HOUSE_ANIMATION_START_STOP
periodically start/stop the animation
@ CBM_HOUSE_CONSTRUCTION_STATE_CHANGE
change animation when construction state changes
@ CBM_HOUSE_DESTRUCTION
trigger destruction of building
@ CBM_HOUSE_DRAW_FOUNDATIONS
decides if default foundations need to be drawn
@ CBM_HOUSE_DENY_DESTRUCTION
conditional protection
CargoID GetCargoTranslation(uint8_t cargo, const GRFFile *grffile, bool usebit)
Translate a GRF-local cargo slot/bitnum into a CargoID.
Cargo support for NewGRFs.
bool Convert8bitBooleanCallback(const GRFFile *grffile, uint16_t cbid, uint16_t cb_res)
Converts a callback result into a boolean.
bool ConvertBooleanCallback(const GRFFile *grffile, uint16_t cbid, uint16_t cb_res)
Converts a callback result into a boolean.
uint32_t GetTerrainType(TileIndex tile, TileContext context)
Function used by houses (and soon industries) to get information on type of "terrain" the tile it is ...
TileIndex GetNearbyTile(uint8_t parameter, TileIndex tile, bool signed_offsets, Axis axis)
Get the tile at the given offset.
void DecreaseBuildingCount(Town *t, HouseID house_id)
DecreaseBuildingCount() Decrease the number of a building when it is deleted.
static bool SearchNearbyHouseClass(TileIndex tile, void *user_data)
Callback function to search a house by its classID.
void IncreaseBuildingCount(Town *t, HouseID house_id)
IncreaseBuildingCount() Increase the count of a building when it has been added by a town.
static uint32_t GetDistanceFromNearbyHouse(uint8_t parameter, TileIndex tile, HouseID house)
This function will activate a search around a central tile, looking for some houses that fit the requ...
void WatchedCargoCallback(TileIndex tile, CargoTypes trigger_cargoes)
Run watched cargo accepted callback for a house.
std::span< const uint > GetBuildingHouseIDCounts()
Get read-only span of total HouseID building counts.
void DoWatchedCargoCallback(TileIndex tile, TileIndex origin, CargoTypes trigger_cargoes, uint16_t random)
Run the watched cargo accepted callback for a single house tile.
void InitializeBuildingCounts(Town *t)
Initialise building counts for a town.
static const GRFFile * GetHouseSpecGrf(HouseID house_id)
Retrieve the grf file associated with a house.
static bool SearchNearbyHouseID(TileIndex tile, void *user_data)
Callback function to search a house by its HouseID.
static bool SearchNearbyHouseGRFID(TileIndex tile, void *user_data)
Callback function to search a house by its grfID.
static uint32_t GetNearbyTileInformation(uint8_t parameter, TileIndex tile, bool grf_version8)
Get information about a nearby tile.
Functions related to NewGRF houses.
static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, const ObjectSpec *spec)
Draw an group of sprites on the map.
Functions related to NewGRF provided sounds.
Action 2 handling.
uint32_t GetRegister(uint i)
Gets the value of a so-called newgrf "register".
Functions to handle the town part of NewGRF towns.
A number of safeguards to prevent using unsafe methods.
@ SLOPE_FLAT
a flat tile
Definition: slope_type.h:49
@ FOUNDATION_LEVELED
The tile is leveled up to a flat slope.
Definition: slope_type.h:95
void DrawNewGRFTileSeq(const struct TileInfo *ti, const DrawTileSprites *dts, TransparencyOption to, uint32_t stage, PaletteID default_palette)
Draw NewGRF industrytile or house sprite layout.
Definition: sprite.h:124
PaletteID GroundSpritePaletteTransform(SpriteID image, PaletteID pal, PaletteID default_pal)
Applies PALETTE_MODIFIER_COLOUR to a palette entry of a ground sprite.
Definition: sprite.h:168
static constexpr uint8_t SPRITE_MODIFIER_CUSTOM_SPRITE
these masks change the colours of the palette for a sprite.
Definition: sprites.h:1545
static constexpr uint8_t SPRITE_WIDTH
number of bits for the sprite number
Definition: sprites.h:1535
Base classes/functions for stations.
std::set< Station *, StationCompare > StationList
List of stations.
Definition: station_type.h:94
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
Definition: stdafx.h:280
Helper class for a unified approach to NewGRF animation.
static void AnimateTile(const HouseSpec *spec, Town *obj, TileIndex tile, bool random_animation, CargoTypes extra_data=0)
Animate a single tile.
static void ChangeAnimationFrame(CallbackID cb, const HouseSpec *spec, Town *obj, TileIndex tile, uint32_t random_bits, uint32_t trigger, CargoTypes extra_data=0)
Check a callback to determine what the next animation step is and execute that step.
static bool IsValidHumanID(size_t index)
Is this company a valid company, not controlled by a NoAI program?
Definition: company_base.h:171
Ground palette sprite of a tile, together with its sprite layout.
Definition: sprite.h:58
PalSpriteID ground
Palette and sprite for the ground.
Definition: sprite.h:59
uint16_t local_id
id defined by the grf file for this entity
const struct GRFFile * grffile
grf file that introduced this entity
std::array< const struct SpriteGroup *, Tcnt > spritegroup
pointers to the different sprites of the entity
Dynamic data of a loaded NewGRF.
Definition: newgrf.h:108
@ GES_LAST_MONTH
Set when cargo was delivered for final delivery last month.
Definition: station_base.h:195
@ GES_CURRENT_MONTH
Set when cargo was delivered for final delivery this month.
Definition: station_base.h:201
@ GES_EVER_ACCEPTED
Set when a vehicle ever delivered cargo to the station for final delivery.
Definition: station_base.h:189
@ GES_ACCEPTED_BIGTICK
Set when cargo was delivered for final delivery during the current STATION_ACCEPTANCE_TICKS interval.
Definition: station_base.h:207
Helper class for animation control.
Makes class IDs unique to each GRF file.
Definition: newgrf_house.h:86
uint8_t class_id
The class id within the grf file.
Definition: newgrf_house.h:88
uint32_t grfid
The GRF ID of the file this class belongs to.
Definition: newgrf_house.h:87
Resolver object to be used for houses (feature 07 spritegroups).
Definition: newgrf_house.h:52
HouseResolverObject(HouseID house_id, TileIndex tile, Town *town, CallbackID callback=CBID_NO_CALLBACK, uint32_t param1=0, uint32_t param2=0, bool not_yet_constructed=false, uint8_t initial_random_bits=0, CargoTypes watched_cargo_triggers=0, int view=0)
Construct a resolver for a house.
uint32_t GetDebugID() const override
Get an identifier for the item being resolved.
GrfSpecFeature GetFeature() const override
Get the feature number being resolved for.
int view
View when house does yet exist.
Definition: newgrf_house.h:27
Town * town
Town of this house.
Definition: newgrf_house.h:23
TileIndex tile
Tile of this house.
Definition: newgrf_house.h:22
CargoTypes watched_cargo_triggers
Cargo types that triggered the watched cargo callback.
Definition: newgrf_house.h:26
uint16_t initial_random_bits
Random bits during construction checks.
Definition: newgrf_house.h:25
uint32_t GetRandomBits() const override
Get a few random bits.
HouseID house_id
Type of house being queried.
Definition: newgrf_house.h:21
uint32_t GetTriggers() const override
Get the triggers.
bool not_yet_constructed
True for construction check.
Definition: newgrf_house.h:24
uint32_t GetVariable(uint8_t variable, [[maybe_unused]] uint32_t parameter, bool &available) const override
CargoTypes watched_cargoes
Cargo types watched for acceptance.
Definition: house.h:119
static HouseSpec * Get(size_t house_id)
Get the spec for a house ID.
BuildingFlags building_flags
some flags that describe the house (size, stadium etc...)
Definition: house.h:105
uint8_t processing_time
Periodic refresh multiplier.
Definition: house.h:117
HouseExtraFlags extra_flags
some more flags
Definition: house.h:114
HouseID Index() const
Gets the index of this spec.
HouseClassID class_id
defines the class this house has (not grf file based)
Definition: house.h:115
GRFFileProps grf_prop
Properties related the the grf file.
Definition: house.h:110
Colours random_colour[4]
4 "random" colours
Definition: house.h:112
uint16_t callback_mask
Bitmask of house callbacks that have to be called.
Definition: house.h:111
static std::vector< HouseSpec > & Specs()
Get a reference to all HouseSpecs.
static TileIndex WrapToMap(TileIndex tile)
'Wraps' the given "tile" so it is within the map.
Definition: map_func.h:317
SpriteID sprite
The 'real' sprite.
Definition: gfx_type.h:24
PaletteID pal
The palette (use PAL_NONE) if not needed)
Definition: gfx_type.h:25
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
Definition: pool_type.hpp:388
Interface for SpriteGroup-s to access the gamestate.
const GRFFile * grffile
GRFFile the resolved SpriteGroup belongs to.
const SpriteGroup * root_spritegroup
Root SpriteGroup to use for resolving.
ResolverObject & ro
Surrounding resolver object.
Structure with user-data for SearchNearbyHouseXXX - functions.
TileIndex north_tile
Northern tile of the house.
const HouseSpec * hs
Specs of the house that started the search.
virtual const SpriteGroup * Resolve([[maybe_unused]] ResolverObject &object) const
Base sprite group resolver.
Station data structure.
Definition: station_base.h:439
A pair-construct of a TileIndexDiff.
Definition: map_type.h:31
int16_t x
The x value of the coordinate.
Definition: map_type.h:32
int16_t y
The y value of the coordinate.
Definition: map_type.h:33
Tile information, used while rendering the tile.
Definition: tile_cmd.h:43
int x
X position of the tile in unit coordinates.
Definition: tile_cmd.h:44
Slope tileh
Slope of the tile.
Definition: tile_cmd.h:46
TileIndex tile
Tile index.
Definition: tile_cmd.h:47
int y
Y position of the tile in unit coordinates.
Definition: tile_cmd.h:45
Action 2 sprite layout for houses, industry tiles, objects and airport tiles.
const DrawTileSprites * ProcessRegisters(uint8_t *stage) const
Process registers and the construction stage into the sprite layout.
BuildingCounts< uint16_t > building_counts
The number of each type of building in the town.
Definition: town.h:48
Town data structure.
Definition: town.h:54
TownCache cache
Container for all cacheable data.
Definition: town.h:57
uint8_t GetAnimationFrame(Tile t)
Get the current animation frame.
Definition: tile_map.h:250
bool IsValidTile(Tile tile)
Checks if a tile is valid.
Definition: tile_map.h:161
uint TileHash2Bit(uint x, uint y)
Get the last two bits of the TileHash from a tile position.
Definition: tile_map.h:342
static debug_inline bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition: tile_map.h:150
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition: tile_type.h:95
@ MP_HOUSE
A house by a town.
Definition: tile_type.h:51
OrthogonalTileArea TileArea
Shorthand for the much more common orthogonal tile area.
Base of the town class.
HouseZonesBits GetTownRadiusGroup(const Town *t, TileIndex tile)
Returns the bit corresponding to the town zone of the specified tile.
Definition: town_cmd.cpp:2447
TileIndexDiff GetHouseNorthPart(HouseID &house)
Determines if a given HouseID is part of a multitile house.
Definition: town_cmd.cpp:2924
void ClearTownHouse(Town *t, TileIndex tile)
Clear a town house.
Definition: town_cmd.cpp:2949
const HouseSpec _original_house_specs[]
House specifications from original data.
HouseID GetHouseType(Tile t)
Get the type of this house, which is an index into the house spec array.
Definition: town_map.h:60
void SetHouseRandomBits(Tile t, uint8_t random)
Set the random bits for this house.
Definition: town_map.h:263
uint8_t GetHouseRandomBits(Tile t)
Get the random bits for this house.
Definition: town_map.h:276
void SetHouseTriggers(Tile t, uint8_t triggers)
Set the activated triggers bits for this house.
Definition: town_map.h:289
TimerGameCalendar::Year GetHouseAge(Tile t)
Get the age of the house.
Definition: town_map.h:250
void DecHouseProcessingTime(Tile t)
Decrease the amount of time remaining before the tile loop processes this tile.
Definition: town_map.h:337
uint8_t GetHouseBuildingStage(Tile t)
House Construction Scheme.
Definition: town_map.h:184
uint8_t GetHouseTriggers(Tile t)
Get the already activated triggers bits for this house.
Definition: town_map.h:302
void SetHouseProcessingTime(Tile t, uint8_t time)
Set the amount of time remaining before the tile loop processes this tile.
Definition: town_map.h:326
uint8_t GetHouseProcessingTime(Tile t)
Get the amount of time remaining before the tile loop processes this tile.
Definition: town_map.h:314
@ TO_HOUSES
town buildings
Definition: transparency.h:25
void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub, int extra_offs_x, int extra_offs_y)
Draws a ground sprite for the current tile.
Definition: viewport.cpp:587