OpenTTD Source  20241120-master-g6d3adc6169
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 
459  /* Collect acceptance stats. */
460  uint32_t res = 0;
461  for (Station *st : stations.GetStations()) {
462  if (HasBit(st->goods[cid].status, GoodsEntry::GES_EVER_ACCEPTED)) SetBit(res, 0);
463  if (HasBit(st->goods[cid].status, GoodsEntry::GES_LAST_MONTH)) SetBit(res, 1);
464  if (HasBit(st->goods[cid].status, GoodsEntry::GES_CURRENT_MONTH)) SetBit(res, 2);
465  if (HasBit(st->goods[cid].status, GoodsEntry::GES_ACCEPTED_BIGTICK)) SetBit(res, 3);
466  }
467 
468  /* Cargo triggered CB 148? */
469  if (HasBit(this->watched_cargo_triggers, cid)) SetBit(res, 4);
470 
471  return res;
472  }
473 
474  /* Distance test for some house types */
475  case 0x65: return GetDistanceFromNearbyHouse(parameter, this->tile, this->house_id);
476 
477  /* Class and ID of nearby house tile */
478  case 0x66: {
479  TileIndex testtile = GetNearbyTile(parameter, this->tile);
480  if (!IsTileType(testtile, MP_HOUSE)) return 0xFFFFFFFF;
481  HouseID nearby_house_id = GetHouseType(testtile);
482  HouseSpec *hs = HouseSpec::Get(nearby_house_id);
483  /* Information about the grf local classid if the house has a class */
484  uint houseclass = 0;
485  if (hs->class_id != HOUSE_NO_CLASS) {
486  houseclass = (hs->grf_prop.grffile == this->ro.grffile ? 1 : 2) << 8;
487  houseclass |= _class_mapping[hs->class_id].class_id;
488  }
489  /* old house type or grf-local houseid */
490  uint local_houseid = 0;
491  if (nearby_house_id < NEW_HOUSE_OFFSET) {
492  local_houseid = nearby_house_id;
493  } else {
494  local_houseid = (hs->grf_prop.grffile == this->ro.grffile ? 1 : 2) << 8;
495  local_houseid |= hs->grf_prop.local_id;
496  }
497  return houseclass << 16 | local_houseid;
498  }
499 
500  /* GRFID of nearby house tile */
501  case 0x67: {
502  TileIndex testtile = GetNearbyTile(parameter, this->tile);
503  if (!IsTileType(testtile, MP_HOUSE)) return 0xFFFFFFFF;
504  HouseID house_id = GetHouseType(testtile);
505  if (house_id < NEW_HOUSE_OFFSET) return 0;
506  /* Checking the grffile information via HouseSpec doesn't work
507  * in case the newgrf was removed. */
508  return _house_mngr.GetGRFID(house_id);
509  }
510  }
511 
512  Debug(grf, 1, "Unhandled house variable 0x{:X}", variable);
513 
514  available = false;
515  return UINT_MAX;
516 }
517 
518 uint16_t GetHouseCallback(CallbackID callback, uint32_t param1, uint32_t param2, HouseID house_id, Town *town, TileIndex tile,
519  bool not_yet_constructed, uint8_t initial_random_bits, CargoTypes watched_cargo_triggers, int view)
520 {
521  HouseResolverObject object(house_id, tile, town, callback, param1, param2,
522  not_yet_constructed, initial_random_bits, watched_cargo_triggers, view);
523  return object.ResolveCallback();
524 }
525 
526 static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, uint8_t stage, HouseID house_id)
527 {
528  const DrawTileSprites *dts = group->ProcessRegisters(&stage);
529 
530  const HouseSpec *hs = HouseSpec::Get(house_id);
531  PaletteID palette = GENERAL_SPRITE_COLOUR(hs->random_colour[TileHash2Bit(ti->x, ti->y)]);
533  uint16_t callback = GetHouseCallback(CBID_HOUSE_COLOUR, 0, 0, house_id, Town::GetByTile(ti->tile), ti->tile);
534  if (callback != CALLBACK_FAILED) {
535  /* If bit 14 is set, we should use a 2cc colour map, else use the callback value. */
536  palette = HasBit(callback, 14) ? GB(callback, 0, 8) + SPR_2CCMAP_BASE : callback;
537  }
538  }
539 
540  SpriteID image = dts->ground.sprite;
541  PaletteID pal = dts->ground.pal;
542 
543  if (HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE)) image += stage;
544  if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += stage;
545 
546  if (GB(image, 0, SPRITE_WIDTH) != 0) {
547  DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, palette));
548  }
549 
550  DrawNewGRFTileSeq(ti, dts, TO_HOUSES, stage, palette);
551 }
552 
553 void DrawNewHouseTile(TileInfo *ti, HouseID house_id)
554 {
555  const HouseSpec *hs = HouseSpec::Get(house_id);
556 
557  if (ti->tileh != SLOPE_FLAT) {
558  bool draw_old_one = true;
560  /* Called to determine the type (if any) of foundation to draw for the house tile */
561  uint32_t callback_res = GetHouseCallback(CBID_HOUSE_DRAW_FOUNDATIONS, 0, 0, house_id, Town::GetByTile(ti->tile), ti->tile);
562  if (callback_res != CALLBACK_FAILED) draw_old_one = ConvertBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DRAW_FOUNDATIONS, callback_res);
563  }
564 
565  if (draw_old_one) DrawFoundation(ti, FOUNDATION_LEVELED);
566  }
567 
568  HouseResolverObject object(house_id, ti->tile, Town::GetByTile(ti->tile));
569 
570  const SpriteGroup *group = object.Resolve();
571  if (group != nullptr && group->type == SGT_TILELAYOUT) {
572  /* Limit the building stage to the number of stages supplied. */
573  const TileLayoutSpriteGroup *tlgroup = (const TileLayoutSpriteGroup *)group;
574  uint8_t stage = GetHouseBuildingStage(ti->tile);
575  DrawTileLayout(ti, tlgroup, stage, house_id);
576  }
577 }
578 
579 /* Simple wrapper for GetHouseCallback to keep the animation unified. */
580 uint16_t GetSimpleHouseCallback(CallbackID callback, uint32_t param1, uint32_t param2, const HouseSpec *spec, Town *town, TileIndex tile, CargoTypes extra_data)
581 {
582  return GetHouseCallback(callback, param1, param2, spec - HouseSpec::Get(0), town, tile, false, 0, extra_data);
583 }
584 
586 struct HouseAnimationBase : public AnimationBase<HouseAnimationBase, HouseSpec, Town, CargoTypes, GetSimpleHouseCallback, TileAnimationFrameAnimationHelper<Town> > {
587  static const CallbackID cb_animation_speed = CBID_HOUSE_ANIMATION_SPEED;
588  static const CallbackID cb_animation_next_frame = CBID_HOUSE_ANIMATION_NEXT_FRAME;
589 
590  static const HouseCallbackMask cbm_animation_speed = CBM_HOUSE_ANIMATION_SPEED;
591  static const HouseCallbackMask cbm_animation_next_frame = CBM_HOUSE_ANIMATION_NEXT_FRAME;
592 };
593 
594 void AnimateNewHouseTile(TileIndex tile)
595 {
596  const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
597  if (hs == nullptr) return;
598 
599  HouseAnimationBase::AnimateTile(hs, Town::GetByTile(tile), tile, HasFlag(hs->extra_flags, CALLBACK_1A_RANDOM_BITS));
600 }
601 
602 void AnimateNewHouseConstruction(TileIndex tile)
603 {
604  const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
605 
608  }
609 }
610 
611 bool CanDeleteHouse(TileIndex tile)
612 {
613  const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
614 
615  /* Humans are always allowed to remove buildings, as is water and disasters and
616  * anyone using the scenario editor. */
618  return true;
619  }
620 
622  uint16_t callback_res = GetHouseCallback(CBID_HOUSE_DENY_DESTRUCTION, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile);
623  return (callback_res == CALLBACK_FAILED || !ConvertBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DENY_DESTRUCTION, callback_res));
624  } else {
625  return !(hs->extra_flags & BUILDING_IS_PROTECTED);
626  }
627 }
628 
629 static void AnimationControl(TileIndex tile, uint16_t random_bits)
630 {
631  const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
632 
634  uint32_t param = (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) ? (GB(Random(), 0, 16) | random_bits << 16) : Random();
635  HouseAnimationBase::ChangeAnimationFrame(CBID_HOUSE_ANIMATION_START_STOP, hs, Town::GetByTile(tile), tile, param, 0);
636  }
637 }
638 
639 bool NewHouseTileLoop(TileIndex tile)
640 {
641  const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
642 
643  if (GetHouseProcessingTime(tile) > 0) {
645  return true;
646  }
647 
648  TriggerHouse(tile, HOUSE_TRIGGER_TILE_LOOP);
649  if (hs->building_flags & BUILDING_HAS_1_TILE) TriggerHouse(tile, HOUSE_TRIGGER_TILE_LOOP_TOP);
650 
652  /* If this house is marked as having a synchronised callback, all the
653  * tiles will have the callback called at once, rather than when the
654  * tile loop reaches them. This should only be enabled for the northern
655  * tile, or strange things will happen (here, and in TTDPatch). */
657  uint16_t random = GB(Random(), 0, 16);
658 
659  if (hs->building_flags & BUILDING_HAS_1_TILE) AnimationControl(tile, random);
660  if (hs->building_flags & BUILDING_2_TILES_Y) AnimationControl(TileAddXY(tile, 0, 1), random);
661  if (hs->building_flags & BUILDING_2_TILES_X) AnimationControl(TileAddXY(tile, 1, 0), random);
662  if (hs->building_flags & BUILDING_HAS_4_TILES) AnimationControl(TileAddXY(tile, 1, 1), random);
663  } else {
664  AnimationControl(tile, 0);
665  }
666  }
667 
668  /* Check callback 21, which determines if a house should be destroyed. */
670  uint16_t callback_res = GetHouseCallback(CBID_HOUSE_DESTRUCTION, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile);
671  if (callback_res != CALLBACK_FAILED && Convert8bitBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DESTRUCTION, callback_res)) {
672  ClearTownHouse(Town::GetByTile(tile), tile);
673  return false;
674  }
675  }
676 
678  MarkTileDirtyByTile(tile);
679  return true;
680 }
681 
682 static void DoTriggerHouse(TileIndex tile, HouseTrigger trigger, uint8_t base_random, bool first)
683 {
684  /* We can't trigger a non-existent building... */
685  assert(IsTileType(tile, MP_HOUSE));
686 
687  HouseID hid = GetHouseType(tile);
688  HouseSpec *hs = HouseSpec::Get(hid);
689 
690  if (hs->grf_prop.spritegroup[0] == nullptr) return;
691 
692  HouseResolverObject object(hid, tile, Town::GetByTile(tile), CBID_RANDOM_TRIGGER);
693  object.waiting_triggers = GetHouseTriggers(tile) | trigger;
694  SetHouseTriggers(tile, object.waiting_triggers); // store now for var 5F
695 
696  const SpriteGroup *group = object.Resolve();
697  if (group == nullptr) return;
698 
699  /* Store remaining triggers. */
700  SetHouseTriggers(tile, object.GetRemainingTriggers());
701 
702  /* Rerandomise bits. Scopes other than SELF are invalid for houses. For bug-to-bug-compatibility with TTDP we ignore the scope. */
703  uint8_t new_random_bits = Random();
704  uint8_t random_bits = GetHouseRandomBits(tile);
705  uint32_t reseed = object.GetReseedSum();
706  random_bits &= ~reseed;
707  random_bits |= (first ? new_random_bits : base_random) & reseed;
708  SetHouseRandomBits(tile, random_bits);
709 
710  switch (trigger) {
711  case HOUSE_TRIGGER_TILE_LOOP:
712  /* Random value already set. */
713  break;
714 
715  case HOUSE_TRIGGER_TILE_LOOP_TOP:
716  if (!first) {
717  /* The top tile is marked dirty by the usual TileLoop */
718  MarkTileDirtyByTile(tile);
719  break;
720  }
721  /* Random value of first tile already set. */
722  if (hs->building_flags & BUILDING_2_TILES_Y) DoTriggerHouse(TileAddXY(tile, 0, 1), trigger, random_bits, false);
723  if (hs->building_flags & BUILDING_2_TILES_X) DoTriggerHouse(TileAddXY(tile, 1, 0), trigger, random_bits, false);
724  if (hs->building_flags & BUILDING_HAS_4_TILES) DoTriggerHouse(TileAddXY(tile, 1, 1), trigger, random_bits, false);
725  break;
726  }
727 }
728 
729 void TriggerHouse(TileIndex t, HouseTrigger trigger)
730 {
731  DoTriggerHouse(t, trigger, 0, true);
732 }
733 
741 void DoWatchedCargoCallback(TileIndex tile, TileIndex origin, CargoTypes trigger_cargoes, uint16_t random)
742 {
743  TileIndexDiffC diff = TileIndexToTileIndexDiffC(origin, tile);
744  uint32_t cb_info = random << 16 | (uint8_t)diff.y << 8 | (uint8_t)diff.x;
745  HouseAnimationBase::ChangeAnimationFrame(CBID_HOUSE_WATCHED_CARGO_ACCEPTED, HouseSpec::Get(GetHouseType(tile)), Town::GetByTile(tile), tile, 0, cb_info, trigger_cargoes);
746 }
747 
754 void WatchedCargoCallback(TileIndex tile, CargoTypes trigger_cargoes)
755 {
756  assert(IsTileType(tile, MP_HOUSE));
757  HouseID id = GetHouseType(tile);
758  const HouseSpec *hs = HouseSpec::Get(id);
759 
760  trigger_cargoes &= hs->watched_cargoes;
761  /* None of the trigger cargoes is watched? */
762  if (trigger_cargoes == 0) return;
763 
764  /* Same random value for all tiles of a multi-tile house. */
765  uint16_t r = Random();
766 
767  /* Do the callback, start at northern tile. */
768  TileIndex north = tile + GetHouseNorthPart(id);
769  hs = HouseSpec::Get(id);
770 
771  DoWatchedCargoCallback(north, tile, trigger_cargoes, r);
772  if (hs->building_flags & BUILDING_2_TILES_Y) DoWatchedCargoCallback(TileAddXY(north, 0, 1), tile, trigger_cargoes, r);
773  if (hs->building_flags & BUILDING_2_TILES_X) DoWatchedCargoCallback(TileAddXY(north, 1, 0), tile, trigger_cargoes, r);
774  if (hs->building_flags & BUILDING_HAS_4_TILES) DoWatchedCargoCallback(TileAddXY(north, 1, 1), tile, trigger_cargoes, r);
775 }
776 
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.
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:118
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:104
uint8_t processing_time
Periodic refresh multiplier.
Definition: house.h:116
HouseExtraFlags extra_flags
some more flags
Definition: house.h:113
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:114
GRFFileProps grf_prop
Properties related the the grf file.
Definition: house.h:109
Colours random_colour[4]
4 "random" colours
Definition: house.h:111
uint16_t callback_mask
Bitmask of house callbacks that have to be called.
Definition: house.h:110
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