OpenTTD Source 20241224-master-gf74b0cf984
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"
22#include "newgrf_cargo.h"
23#include "station_base.h"
24
25#include "safeguards.h"
26
27static BuildingCounts<uint32_t> _building_counts{};
28static std::vector<HouseClassMapping> _class_mapping{};
29
30HouseOverrideManager _house_mngr(NEW_HOUSE_OFFSET, NUM_HOUSES, INVALID_HOUSE_ID);
31
37static 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
43extern const HouseSpec _original_house_specs[NEW_HOUSE_OFFSET];
44std::vector<HouseSpec> _house_specs;
45
50std::vector<HouseSpec> &HouseSpec::Specs()
51{
52 return _house_specs;
53}
54
60{
61 return static_cast<HouseID>(this - _house_specs.data());
62}
63
69HouseSpec *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. */
80void 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
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
129void ResetHouseClassIDs()
130{
131 _class_mapping.clear();
132
133 /* Add initial entry for HOUSE_NO_CLASS. */
134 _class_mapping.emplace_back();
135}
136
137HouseClassID 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
179std::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. */
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
234static 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
253static 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
264
271static 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.HasGrfFile()) { // 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.grfid == nbhd->hs->grf_prop.grfid; // from the same grf
284 }
285 }
286 return false;
287}
288
295static 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.HasGrfFile()) { // 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.grfid == nbhd->hs->grf_prop.grfid; // from the same grf
308 }
309 }
310 return false;
311}
312
319static 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.HasGrfFile()) { // 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.grfid == nbhd->hs->grf_prop.grfid; // from the same grf
331 }
332 }
333 return false;
334}
335
346static 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.HasGrfFile()) return 0;
433
434 HouseID new_house = _house_mngr.GetID(parameter, hs->grf_prop.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 |= ClampTo<uint8_t>(hs->grf_prop.local_id); // Spec only allows 8 bits, so all local-ids above 254 are clamped.
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
518uint16_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
526static 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
553void 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. */
580uint16_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
586struct 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
594void 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
602void AnimateNewHouseConstruction(TileIndex tile)
603{
604 const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
605
608 }
609}
610
611bool 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
629static 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
639bool 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
679 return true;
680}
681
682static 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 */
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
729void TriggerHouse(TileIndex t, HouseTrigger trigger)
730{
731 DoTriggerHouse(t, trigger, 0, true);
732}
733
741void 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
754void 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
debug_inline constexpr 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.
debug_inline static constexpr 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.
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.
Functions related to companies.
@ OWNER_NONE
The tile has no ownership.
@ OWNER_WATER
The tile/execution is done by "water".
Functions related to debugging.
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition debug.h:37
debug_inline constexpr 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.
static const HouseID NUM_HOUSES
Total number of houses.
Definition house.h:27
static const HouseID NEW_HOUSE_OFFSET
Offset for new houses.
Definition house.h:26
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.
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.
uint32_t GetNearbyTileInformation(TileIndex tile, bool grf_version8)
Common part of station var 0x67, house var 0x62, indtile var 0x60, industry var 0x62.
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()
Initialise global building counts and all town building counts.
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.
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?
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
bool HasGrfFile() const
Test if this entity was introduced by NewGRF.
uint16_t local_id
id defined by the grf file for this entity
uint32_t grfid
grfid that introduced 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.
@ GES_CURRENT_MONTH
Set when cargo was delivered for final delivery this month.
@ GES_EVER_ACCEPTED
Set when a vehicle ever delivered cargo to the station for final delivery.
@ GES_ACCEPTED_BIGTICK
Set when cargo was delivered for final delivery during the current STATION_ACCEPTANCE_TICKS interval.
Helper class for animation control.
Makes class IDs unique to each GRF file.
uint8_t class_id
The class id within the grf file.
uint32_t grfid
The GRF ID of the file this class belongs to.
Resolver object to be used for houses (feature 07 spritegroups).
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.
Town * town
Town of this house.
TileIndex tile
Tile of this house.
CargoTypes watched_cargo_triggers
Cargo types that triggered the watched cargo callback.
uint32_t GetVariable(uint8_t variable, uint32_t parameter, bool &available) const override
uint16_t initial_random_bits
Random bits during construction checks.
uint32_t GetRandomBits() const override
Get a few random bits.
HouseID house_id
Type of house being queried.
uint32_t GetTriggers() const override
Get the triggers.
bool not_yet_constructed
True for construction check.
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.
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(ResolverObject &object) const
Base sprite group resolver.
Station data structure.
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.
TileIndexDiff GetHouseNorthPart(HouseID &house)
Determines if a given HouseID is part of a multitile house.
void ClearTownHouse(Town *t, TileIndex tile)
Clear a town house.
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:262
uint8_t GetHouseRandomBits(Tile t)
Get the random bits for this house.
Definition town_map.h:275
void SetHouseTriggers(Tile t, uint8_t triggers)
Set the activated triggers bits for this house.
Definition town_map.h:288
TimerGameCalendar::Year GetHouseAge(Tile t)
Get the age of the house.
Definition town_map.h:249
void DecHouseProcessingTime(Tile t)
Decrease the amount of time remaining before the tile loop processes this tile.
Definition town_map.h:336
uint8_t GetHouseBuildingStage(Tile t)
House Construction Scheme.
Definition town_map.h:183
uint8_t GetHouseTriggers(Tile t)
Get the already activated triggers bits for this house.
Definition town_map.h:301
void SetHouseProcessingTime(Tile t, uint8_t time)
Set the amount of time remaining before the tile loop processes this tile.
Definition town_map.h:325
uint8_t GetHouseProcessingTime(Tile t)
Get the amount of time remaining before the tile loop processes this tile.
Definition town_map.h:313
@ TO_HOUSES
town buildings
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