Files @ r28486:aff297ed5a05
Branch filter:

Location: cpp/openttd-patchpack/source/src/newgrf_house.cpp - annotation

Peter Nelson
Codechange: Allow constexpr NWidgetPart construction.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r9111:983de9c5a848
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6343:4d2d12eee7b9
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r10208:ef8fcc3dc4ca
r10208:ef8fcc3dc4ca
r12239:4ede50b8e95b
r15521:545d58d62089
r15929:5d5037945a0e
r18224:d4deaea79cbe
r18224:d4deaea79cbe
r6332:7393965b5322
r21383:942c32fb8b0e
r21383:942c32fb8b0e
r27737:728d55b97775
r27889:87ac6e837ad9
r6332:7393965b5322
r20794:ace4f2fce9a6
r6332:7393965b5322
r19738:837a139219f0
r19727:37cdfa4a6a38
r19727:37cdfa4a6a38
r23607:36c15679007d
r19727:37cdfa4a6a38
r19727:37cdfa4a6a38
r19727:37cdfa4a6a38
r19727:37cdfa4a6a38
r23607:36c15679007d
r19727:37cdfa4a6a38
r19727:37cdfa4a6a38
r19738:837a139219f0
r19738:837a139219f0
r19738:837a139219f0
r19738:837a139219f0
r19738:837a139219f0
r19738:837a139219f0
r19738:837a139219f0
r19738:837a139219f0
r19738:837a139219f0
r19738:837a139219f0
r19738:837a139219f0
r19738:837a139219f0
r19727:37cdfa4a6a38
r27737:728d55b97775
r27737:728d55b97775
r19727:37cdfa4a6a38
r21008:be2e3d3c935b
r21008:be2e3d3c935b
r19727:37cdfa4a6a38
r21299:8973364c4b52
r19727:37cdfa4a6a38
r19727:37cdfa4a6a38
r24069:49625df81342
r24069:49625df81342
r24069:49625df81342
r24069:49625df81342
r24069:49625df81342
r27737:728d55b97775
r24069:49625df81342
r24069:49625df81342
r24069:49625df81342
r24069:49625df81342
r27889:87ac6e837ad9
r27889:87ac6e837ad9
r27889:87ac6e837ad9
r27889:87ac6e837ad9
r27889:87ac6e837ad9
r27737:728d55b97775
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r19276:ad854f3053cd
r23973:490b8210dd15
r19276:ad854f3053cd
r19276:ad854f3053cd
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r12241:f31db06a63d4
r6332:7393965b5322
r19276:ad854f3053cd
r11396:4adf79ba94c4
r6332:7393965b5322
r11396:4adf79ba94c4
r6332:7393965b5322
r19276:ad854f3053cd
r11396:4adf79ba94c4
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r12241:f31db06a63d4
r6332:7393965b5322
r19276:ad854f3053cd
r19276:ad854f3053cd
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r19276:ad854f3053cd
r19276:ad854f3053cd
r6332:7393965b5322
r6332:7393965b5322
r27737:728d55b97775
r6332:7393965b5322
r15104:1752997daf93
r19727:37cdfa4a6a38
r19727:37cdfa4a6a38
r6332:7393965b5322
r6332:7393965b5322
r27737:728d55b97775
r6332:7393965b5322
r19727:37cdfa4a6a38
r19727:37cdfa4a6a38
r19727:37cdfa4a6a38
r19727:37cdfa4a6a38
r19727:37cdfa4a6a38
r27737:728d55b97775
r6332:7393965b5322
r12241:f31db06a63d4
r6332:7393965b5322
r27272:bb139906001a
r27272:bb139906001a
r27272:bb139906001a
r27272:bb139906001a
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r18308:05de10e00a85
r18308:05de10e00a85
r18308:05de10e00a85
r18308:05de10e00a85
r18308:05de10e00a85
r18308:05de10e00a85
r18308:05de10e00a85
r27737:728d55b97775
r6827:5f08bab6696e
r6827:5f08bab6696e
r18308:05de10e00a85
r6827:5f08bab6696e
r6827:5f08bab6696e
r9594:e12e48163543
r21001:187181592ea9
r16339:e90c1dadabf0
r9594:e12e48163543
r21001:187181592ea9
r9594:e12e48163543
r15610:623a23fb6560
r15610:623a23fb6560
r9574:3d0d723ee642
r9594:e12e48163543
r9574:3d0d723ee642
r9574:3d0d723ee642
r9592:cdeca10f617d
r9574:3d0d723ee642
r9574:3d0d723ee642
r9594:e12e48163543
r12241:f31db06a63d4
r23607:36c15679007d
r9594:e12e48163543
r9594:e12e48163543
r9594:e12e48163543
r9594:e12e48163543
r9594:e12e48163543
r15724:6a590b922d6c
r15724:6a590b922d6c
r9574:3d0d723ee642
r9574:3d0d723ee642
r9574:3d0d723ee642
r9574:3d0d723ee642
r9574:3d0d723ee642
r15610:623a23fb6560
r15610:623a23fb6560
r9574:3d0d723ee642
r9594:e12e48163543
r9574:3d0d723ee642
r9574:3d0d723ee642
r9592:cdeca10f617d
r9574:3d0d723ee642
r9574:3d0d723ee642
r9594:e12e48163543
r12241:f31db06a63d4
r23607:36c15679007d
r9594:e12e48163543
r9594:e12e48163543
r9594:e12e48163543
r9594:e12e48163543
r9594:e12e48163543
r9594:e12e48163543
r15724:6a590b922d6c
r9574:3d0d723ee642
r9574:3d0d723ee642
r9574:3d0d723ee642
r9574:3d0d723ee642
r9574:3d0d723ee642
r15610:623a23fb6560
r15610:623a23fb6560
r9574:3d0d723ee642
r9594:e12e48163543
r9574:3d0d723ee642
r9574:3d0d723ee642
r9592:cdeca10f617d
r9574:3d0d723ee642
r9574:3d0d723ee642
r9594:e12e48163543
r12241:f31db06a63d4
r23607:36c15679007d
r9594:e12e48163543
r9594:e12e48163543
r9594:e12e48163543
r9594:e12e48163543
r9594:e12e48163543
r15724:6a590b922d6c
r9574:3d0d723ee642
r9574:3d0d723ee642
r9574:3d0d723ee642
r9574:3d0d723ee642
r9574:3d0d723ee642
r15610:623a23fb6560
r15610:623a23fb6560
r9574:3d0d723ee642
r9574:3d0d723ee642
r9574:3d0d723ee642
r9574:3d0d723ee642
r9574:3d0d723ee642
r9592:cdeca10f617d
r9592:cdeca10f617d
r9592:cdeca10f617d
r27737:728d55b97775
r9574:3d0d723ee642
r9574:3d0d723ee642
r9574:3d0d723ee642
r9574:3d0d723ee642
r9574:3d0d723ee642
r9574:3d0d723ee642
r9574:3d0d723ee642
r27737:728d55b97775
r27737:728d55b97775
r9574:3d0d723ee642
r9589:1c55e3c8265a
r9574:3d0d723ee642
r9594:e12e48163543
r12241:f31db06a63d4
r9594:e12e48163543
r9594:e12e48163543
r9574:3d0d723ee642
r9594:e12e48163543
r9574:3d0d723ee642
r9574:3d0d723ee642
r9574:3d0d723ee642
r9574:3d0d723ee642
r9574:3d0d723ee642
r6332:7393965b5322
r19727:37cdfa4a6a38
r6332:7393965b5322
r27942:f7389062d120
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r19727:37cdfa4a6a38
r6332:7393965b5322
r6332:7393965b5322
r28112:bca7556a6bb6
r6332:7393965b5322
r6332:7393965b5322
r19727:37cdfa4a6a38
r6332:7393965b5322
r6332:7393965b5322
r19727:37cdfa4a6a38
r6332:7393965b5322
r6332:7393965b5322
r19727:37cdfa4a6a38
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r19727:37cdfa4a6a38
r6332:7393965b5322
r10110:c3a31d3b2182
r19727:37cdfa4a6a38
r6332:7393965b5322
r6332:7393965b5322
r19727:37cdfa4a6a38
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r19727:37cdfa4a6a38
r23607:36c15679007d
r6332:7393965b5322
r15724:6a590b922d6c
r19727:37cdfa4a6a38
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r21008:be2e3d3c935b
r6332:7393965b5322
r9523:119809ed46fc
r9523:119809ed46fc
r19727:37cdfa4a6a38
r15924:f5bba173626e
r9523:119809ed46fc
r9523:119809ed46fc
r9574:3d0d723ee642
r18224:d4deaea79cbe
r21008:be2e3d3c935b
r27421:e8c2cdc1e8e6
r18224:d4deaea79cbe
r18224:d4deaea79cbe
r27737:728d55b97775
r27737:728d55b97775
r26788:0785302ccc5b
r18224:d4deaea79cbe
r18862:80d0a0322356
r18862:80d0a0322356
r18224:d4deaea79cbe
r18224:d4deaea79cbe
r27737:728d55b97775
r23428:4a18cf6bbfe5
r21471:ce169ca93e3c
r21471:ce169ca93e3c
r21471:ce169ca93e3c
r21471:ce169ca93e3c
r18224:d4deaea79cbe
r18224:d4deaea79cbe
r18226:c04963816211
r19727:37cdfa4a6a38
r18226:c04963816211
r18224:d4deaea79cbe
r18224:d4deaea79cbe
r9574:3d0d723ee642
r9574:3d0d723ee642
r19727:37cdfa4a6a38
r14177:eb894a949258
r14177:eb894a949258
r14177:eb894a949258
r19727:37cdfa4a6a38
r14177:eb894a949258
r22379:3604f2df7905
r22379:3604f2df7905
r14177:eb894a949258
r14177:eb894a949258
r14177:eb894a949258
r21008:be2e3d3c935b
r14177:eb894a949258
r14177:eb894a949258
r14177:eb894a949258
r14177:eb894a949258
r22379:3604f2df7905
r22379:3604f2df7905
r14177:eb894a949258
r21008:be2e3d3c935b
r15724:6a590b922d6c
r14177:eb894a949258
r14177:eb894a949258
r14177:eb894a949258
r14177:eb894a949258
r14177:eb894a949258
r14177:eb894a949258
r19727:37cdfa4a6a38
r14177:eb894a949258
r14177:eb894a949258
r14177:eb894a949258
r14177:eb894a949258
r14177:eb894a949258
r17771:ad36e3e3a831
r14177:eb894a949258
r6332:7393965b5322
r6332:7393965b5322
r25655:1030dcb7eb52
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r27737:728d55b97775
r27737:728d55b97775
r6332:7393965b5322
r15104:1752997daf93
r15104:1752997daf93
r19727:37cdfa4a6a38
r19727:37cdfa4a6a38
r21299:8973364c4b52
r6332:7393965b5322
r6332:7393965b5322
r11985:d8202dea2203
r6332:7393965b5322
r17728:6a6e98f25cac
r6332:7393965b5322
r12241:f31db06a63d4
r14309:f445232b17f6
r10355:1d372454f71c
r27737:728d55b97775
r10355:1d372454f71c
r10355:1d372454f71c
r10355:1d372454f71c
r10355:1d372454f71c
r10355:1d372454f71c
r10355:1d372454f71c
r8571:ede148e241b1
r14309:f445232b17f6
r6332:7393965b5322
r14280:9e2593121da6
r17728:6a6e98f25cac
r7619:d663893bc2b3
r10355:1d372454f71c
r10355:1d372454f71c
r10355:1d372454f71c
r6332:7393965b5322
r14284:8fe3cab84763
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r12241:f31db06a63d4
r6332:7393965b5322
r13050:69cb7cb85163
r13050:69cb7cb85163
r13050:69cb7cb85163
r13050:69cb7cb85163
r27737:728d55b97775
r18301:0c1dfbaba57a
r13050:69cb7cb85163
r13050:69cb7cb85163
r13050:69cb7cb85163
r13050:69cb7cb85163
r6332:7393965b5322
r19727:37cdfa4a6a38
r6332:7393965b5322
r21299:8973364c4b52
r23607:36c15679007d
r6332:7393965b5322
r14200:1807a9ce785f
r6332:7393965b5322
r11985:d8202dea2203
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r15929:5d5037945a0e
r27737:728d55b97775
r15929:5d5037945a0e
r18226:c04963816211
r15929:5d5037945a0e
r15929:5d5037945a0e
r15929:5d5037945a0e
r26914:6e889cbdcba1
r15929:5d5037945a0e
r15929:5d5037945a0e
r15929:5d5037945a0e
r15929:5d5037945a0e
r15929:5d5037945a0e
r15929:5d5037945a0e
r15929:5d5037945a0e
r6332:7393965b5322
r6332:7393965b5322
r12241:f31db06a63d4
r23607:36c15679007d
r6332:7393965b5322
r15929:5d5037945a0e
r6332:7393965b5322
r6332:7393965b5322
r15929:5d5037945a0e
r6332:7393965b5322
r15929:5d5037945a0e
r15929:5d5037945a0e
r15929:5d5037945a0e
r15929:5d5037945a0e
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r12241:f31db06a63d4
r6332:7393965b5322
r20414:612b5fb00359
r6332:7393965b5322
r20414:612b5fb00359
r12138:e93d2e409e78
r12138:e93d2e409e78
r6332:7393965b5322
r7928:a80e7e05d6c5
r27737:728d55b97775
r18301:0c1dfbaba57a
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r27737:728d55b97775
r6332:7393965b5322
r12241:f31db06a63d4
r6332:7393965b5322
r7928:a80e7e05d6c5
r27737:728d55b97775
r15929:5d5037945a0e
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r12241:f31db06a63d4
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r7861:9082dbb3187c
r12593:e0b0ea0326ae
r6332:7393965b5322
r7928:a80e7e05d6c5
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r27737:728d55b97775
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r7928:a80e7e05d6c5
r27737:728d55b97775
r18301:0c1dfbaba57a
r12240:9443a1e602a7
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r6332:7393965b5322
r12594:2e8b743b3b20
r6332:7393965b5322
r6332:7393965b5322
r7861:9082dbb3187c
r7861:9082dbb3187c
r7861:9082dbb3187c
r7861:9082dbb3187c
r7861:9082dbb3187c
r7861:9082dbb3187c
r7861:9082dbb3187c
r12241:f31db06a63d4
r7861:9082dbb3187c
r23607:36c15679007d
r9028:43b29ac0a74d
r19727:37cdfa4a6a38
r22707:80b972b362a5
r22707:80b972b362a5
r7861:9082dbb3187c
r21299:8973364c4b52
r23607:36c15679007d
r7861:9082dbb3187c
r22707:80b972b362a5
r22707:80b972b362a5
r22707:80b972b362a5
r22707:80b972b362a5
r7861:9082dbb3187c
r7861:9082dbb3187c
r27737:728d55b97775
r17834:447b5cb3ee1a
r17834:447b5cb3ee1a
r7861:9082dbb3187c
r7861:9082dbb3187c
r7861:9082dbb3187c
r7861:9082dbb3187c
r7861:9082dbb3187c
r7861:9082dbb3187c
r7861:9082dbb3187c
r7861:9082dbb3187c
r12594:2e8b743b3b20
r12594:2e8b743b3b20
r12594:2e8b743b3b20
r12594:2e8b743b3b20
r12594:2e8b743b3b20
r7861:9082dbb3187c
r7866:4f9cd06a358f
r7866:4f9cd06a358f
r7866:4f9cd06a358f
r7861:9082dbb3187c
r7861:9082dbb3187c
r7861:9082dbb3187c
r7861:9082dbb3187c
r7861:9082dbb3187c
r7861:9082dbb3187c
r7868:576cbce4f5dc
r7861:9082dbb3187c
r15071:e236d80508bb
r15071:e236d80508bb
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r27737:728d55b97775
r18226:c04963816211
r18226:c04963816211
r27737:728d55b97775
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r22867:9bff1c966805
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r27737:728d55b97775
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
r18226:c04963816211
/*
 * This file is part of OpenTTD.
 * 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.
 * 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.
 * 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/>.
 */

/** @file newgrf_house.cpp Implementation of NewGRF houses. */

#include "stdafx.h"
#include "debug.h"
#include "landscape.h"
#include "newgrf_house.h"
#include "newgrf_spritegroup.h"
#include "newgrf_town.h"
#include "newgrf_sound.h"
#include "company_func.h"
#include "company_base.h"
#include "town.h"
#include "genworld.h"
#include "newgrf_animation_base.h"
#include "newgrf_cargo.h"
#include "station_base.h"

#include "safeguards.h"

static BuildingCounts<uint32_t> _building_counts;
static std::array<HouseClassMapping, HOUSE_CLASS_MAX> _class_mapping;

HouseOverrideManager _house_mngr(NEW_HOUSE_OFFSET, NUM_HOUSES, INVALID_HOUSE_ID);

/**
 * Retrieve the grf file associated with a house.
 * @param house_id House to query.
 * @return The associated GRF file (may be \c nullptr).
 */
static const GRFFile *GetHouseSpecGrf(HouseID house_id)
{
	const HouseSpec *hs  = HouseSpec::Get(house_id);
	return (hs != nullptr) ? hs->grf_prop.grffile : nullptr;
}

/**
 * Construct a resolver for a house.
 * @param house_id House to query.
 * @param tile %Tile containing the house.
 * @param town %Town containing the house.
 * @param callback Callback ID.
 * @param param1 First parameter (var 10) of the callback.
 * @param param2 Second parameter (var 18) of the callback.
 * @param not_yet_constructed House is still under construction.
 * @param initial_random_bits Random bits during construction checks.
 * @param watched_cargo_triggers Cargo types that triggered the watched cargo callback.
 */
HouseResolverObject::HouseResolverObject(HouseID house_id, TileIndex tile, Town *town,
		CallbackID callback, uint32_t param1, uint32_t param2,
		bool not_yet_constructed, uint8_t initial_random_bits, CargoTypes watched_cargo_triggers)
	: ResolverObject(GetHouseSpecGrf(house_id), callback, param1, param2),
	house_scope(*this, house_id, tile, town, not_yet_constructed, initial_random_bits, watched_cargo_triggers),
	town_scope(*this, town, not_yet_constructed) // Don't access StorePSA if house is not yet constructed.
{
	this->root_spritegroup = HouseSpec::Get(house_id)->grf_prop.spritegroup[0];
}

GrfSpecFeature HouseResolverObject::GetFeature() const
{
	return GSF_HOUSES;
}

uint32_t HouseResolverObject::GetDebugID() const
{
	return HouseSpec::Get(this->house_scope.house_id)->grf_prop.local_id;
}

void ResetHouseClassIDs()
{
	_class_mapping = {};
}

HouseClassID AllocateHouseClassID(byte grf_class_id, uint32_t grfid)
{
	/* Start from 1 because 0 means that no class has been assigned. */
	for (int i = 1; i != lengthof(_class_mapping); i++) {
		HouseClassMapping *map = &_class_mapping[i];

		if (map->class_id == grf_class_id && map->grfid == grfid) return (HouseClassID)i;

		if (map->class_id == 0 && map->grfid == 0) {
			map->class_id = grf_class_id;
			map->grfid    = grfid;
			return (HouseClassID)i;
		}
	}
	return HOUSE_NO_CLASS;
}

void InitializeBuildingCounts()
{
	memset(&_building_counts, 0, sizeof(_building_counts));

	for (Town *t : Town::Iterate()) {
		memset(&t->cache.building_counts, 0, sizeof(t->cache.building_counts));
	}
}

/**
 * IncreaseBuildingCount()
 * Increase the count of a building when it has been added by a town.
 * @param t The town that the building is being built in
 * @param house_id The id of the house being added
 */
void IncreaseBuildingCount(Town *t, HouseID house_id)
{
	HouseClassID class_id = HouseSpec::Get(house_id)->class_id;

	t->cache.building_counts.id_count[house_id]++;
	_building_counts.id_count[house_id]++;

	if (class_id == HOUSE_NO_CLASS) return;

	t->cache.building_counts.class_count[class_id]++;
	_building_counts.class_count[class_id]++;
}

/**
 * DecreaseBuildingCount()
 * Decrease the number of a building when it is deleted.
 * @param t The town that the building was built in
 * @param house_id The id of the house being removed
 */
void DecreaseBuildingCount(Town *t, HouseID house_id)
{
	HouseClassID class_id = HouseSpec::Get(house_id)->class_id;

	if (t->cache.building_counts.id_count[house_id] > 0) t->cache.building_counts.id_count[house_id]--;
	if (_building_counts.id_count[house_id] > 0) _building_counts.id_count[house_id]--;

	if (class_id == HOUSE_NO_CLASS) return;

	if (t->cache.building_counts.class_count[class_id] > 0) t->cache.building_counts.class_count[class_id]--;
	if (_building_counts.class_count[class_id] > 0) _building_counts.class_count[class_id]--;
}

/* virtual */ uint32_t HouseScopeResolver::GetRandomBits() const
{
	/* Note: Towns build houses over houses. So during construction checks 'tile' may be a valid but unrelated house. */
	assert(IsValidTile(this->tile) && (this->not_yet_constructed || IsTileType(this->tile, MP_HOUSE)));
	return this->not_yet_constructed ? this->initial_random_bits : GetHouseRandomBits(this->tile);
}

/* virtual */ uint32_t HouseScopeResolver::GetTriggers() const
{
	/* Note: Towns build houses over houses. So during construction checks 'tile' may be a valid but unrelated house. */
	assert(IsValidTile(this->tile) && (this->not_yet_constructed || IsTileType(this->tile, MP_HOUSE)));
	return this->not_yet_constructed ? 0 : GetHouseTriggers(this->tile);
}

static uint32_t GetNumHouses(HouseID house_id, const Town *town)
{
	HouseClassID class_id = HouseSpec::Get(house_id)->class_id;

	uint8_t map_id_count     = ClampTo<uint8_t>(_building_counts.id_count[house_id]);
	uint8_t map_class_count  = ClampTo<uint8_t>(_building_counts.class_count[class_id]);
	uint8_t town_id_count    = ClampTo<uint8_t>(town->cache.building_counts.id_count[house_id]);
	uint8_t town_class_count = ClampTo<uint8_t>(town->cache.building_counts.class_count[class_id]);

	return map_class_count << 24 | town_class_count << 16 | map_id_count << 8 | town_id_count;
}

/**
 * Get information about a nearby tile.
 * @param parameter from callback. It's in fact a pair of coordinates
 * @param tile TileIndex from which the callback was initiated
 * @param grf_version8 True, if we are dealing with a new NewGRF which uses GRF version >= 8.
 * @return a construction of bits obeying the newgrf format
 */
static uint32_t GetNearbyTileInformation(byte parameter, TileIndex tile, bool grf_version8)
{
	tile = GetNearbyTile(parameter, tile);
	return GetNearbyTileInformation(tile, grf_version8);
}

/** Structure with user-data for SearchNearbyHouseXXX - functions */
struct SearchNearbyHouseData {
	const HouseSpec *hs;  ///< Specs of the house that started the search.
	TileIndex north_tile; ///< Northern tile of the house.
};

/**
 * Callback function to search a house by its HouseID
 * @param tile TileIndex to be examined
 * @param user_data SearchNearbyHouseData
 * @return true or false, if found or not
 */
static bool SearchNearbyHouseID(TileIndex tile, void *user_data)
{
	if (IsTileType(tile, MP_HOUSE)) {
		HouseID house = GetHouseType(tile); // tile been examined
		const HouseSpec *hs = HouseSpec::Get(house);
		if (hs->grf_prop.grffile != nullptr) { // must be one from a grf file
			SearchNearbyHouseData *nbhd = (SearchNearbyHouseData *)user_data;

			TileIndex north_tile = tile + GetHouseNorthPart(house); // modifies 'house'!
			if (north_tile == nbhd->north_tile) return false; // Always ignore origin house

			return hs->grf_prop.local_id == nbhd->hs->grf_prop.local_id &&  // same local id as the one requested
				hs->grf_prop.grffile->grfid == nbhd->hs->grf_prop.grffile->grfid;  // from the same grf
		}
	}
	return false;
}

/**
 * Callback function to search a house by its classID
 * @param tile TileIndex to be examined
 * @param user_data SearchNearbyHouseData
 * @return true or false, if found or not
 */
static bool SearchNearbyHouseClass(TileIndex tile, void *user_data)
{
	if (IsTileType(tile, MP_HOUSE)) {
		HouseID house = GetHouseType(tile); // tile been examined
		const HouseSpec *hs = HouseSpec::Get(house);
		if (hs->grf_prop.grffile != nullptr) { // must be one from a grf file
			SearchNearbyHouseData *nbhd = (SearchNearbyHouseData *)user_data;

			TileIndex north_tile = tile + GetHouseNorthPart(house); // modifies 'house'!
			if (north_tile == nbhd->north_tile) return false; // Always ignore origin house

			return hs->class_id == nbhd->hs->class_id &&  // same classid as the one requested
				hs->grf_prop.grffile->grfid == nbhd->hs->grf_prop.grffile->grfid;  // from the same grf
		}
	}
	return false;
}

/**
 * Callback function to search a house by its grfID
 * @param tile TileIndex to be examined
 * @param user_data SearchNearbyHouseData
 * @return true or false, if found or not
 */
static bool SearchNearbyHouseGRFID(TileIndex tile, void *user_data)
{
	if (IsTileType(tile, MP_HOUSE)) {
		HouseID house = GetHouseType(tile); // tile been examined
		const HouseSpec *hs = HouseSpec::Get(house);
		if (hs->grf_prop.grffile != nullptr) { // must be one from a grf file
			SearchNearbyHouseData *nbhd = (SearchNearbyHouseData *)user_data;

			TileIndex north_tile = tile + GetHouseNorthPart(house); // modifies 'house'!
			if (north_tile == nbhd->north_tile) return false; // Always ignore origin house

			return hs->grf_prop.grffile->grfid == nbhd->hs->grf_prop.grffile->grfid;  // from the same grf
		}
	}
	return false;
}

/**
 * This function will activate a search around a central tile, looking for some houses
 * that fit the requested characteristics
 * @param parameter that is given by the callback.
 *                  bits 0..6 radius of the search
 *                  bits 7..8 search type i.e.: 0 = houseID/ 1 = classID/ 2 = grfID
 * @param tile TileIndex from which to start the search
 * @param house the HouseID that is associated to the house, the callback is called for
 * @return the Manhattan distance from the center tile, if any, and 0 if failure
 */
static uint32_t GetDistanceFromNearbyHouse(uint8_t parameter, TileIndex tile, HouseID house)
{
	static TestTileOnSearchProc * const search_procs[3] = {
		SearchNearbyHouseID,
		SearchNearbyHouseClass,
		SearchNearbyHouseGRFID,
	};
	TileIndex found_tile = tile;
	uint8_t searchtype = GB(parameter, 6, 2);
	uint8_t searchradius = GB(parameter, 0, 6);
	if (searchtype >= lengthof(search_procs)) return 0;  // do not run on ill-defined code
	if (searchradius < 1) return 0; // do not use a too low radius

	SearchNearbyHouseData nbhd;
	nbhd.hs = HouseSpec::Get(house);
	nbhd.north_tile = tile + GetHouseNorthPart(house); // modifies 'house'!

	/* Use a pointer for the tile to start the search. Will be required for calculating the distance*/
	if (CircularTileSearch(&found_tile, 2 * searchradius + 1, search_procs[searchtype], &nbhd)) {
		return DistanceManhattan(found_tile, tile);
	}
	return 0;
}

/**
 * @note Used by the resolver to get values for feature 07 deterministic spritegroups.
 */
/* virtual */ uint32_t HouseScopeResolver::GetVariable(byte variable, [[maybe_unused]] uint32_t parameter, bool *available) const
{
	switch (variable) {
		/* Construction stage. */
		case 0x40: return (IsTileType(this->tile, MP_HOUSE) ? GetHouseBuildingStage(this->tile) : 0) | TileHash2Bit(TileX(this->tile), TileY(this->tile)) << 2;

		/* Building age. */
		case 0x41: return IsTileType(this->tile, MP_HOUSE) ? GetHouseAge(this->tile).base() : 0;

		/* Town zone */
		case 0x42: return GetTownRadiusGroup(this->town, this->tile);

		/* Terrain type */
		case 0x43: return GetTerrainType(this->tile);

		/* Number of this type of building on the map. */
		case 0x44: return GetNumHouses(this->house_id, this->town);

		/* Whether the town is being created or just expanded. */
		case 0x45: return _generating_world ? 1 : 0;

		/* Current animation frame. */
		case 0x46: return IsTileType(this->tile, MP_HOUSE) ? GetAnimationFrame(this->tile) : 0;

		/* Position of the house */
		case 0x47: return TileY(this->tile) << 16 | TileX(this->tile);

		/* Building counts for old houses with id = parameter. */
		case 0x60: return parameter < NEW_HOUSE_OFFSET ? GetNumHouses(parameter, this->town) : 0;

		/* Building counts for new houses with id = parameter. */
		case 0x61: {
			const HouseSpec *hs = HouseSpec::Get(this->house_id);
			if (hs->grf_prop.grffile == nullptr) return 0;

			HouseID new_house = _house_mngr.GetID(parameter, hs->grf_prop.grffile->grfid);
			return new_house == INVALID_HOUSE_ID ? 0 : GetNumHouses(new_house, this->town);
		}

		/* Land info for nearby tiles. */
		case 0x62: return GetNearbyTileInformation(parameter, this->tile, this->ro.grffile->grf_version >= 8);

		/* Current animation frame of nearby house tiles */
		case 0x63: {
			TileIndex testtile = GetNearbyTile(parameter, this->tile);
			return IsTileType(testtile, MP_HOUSE) ? GetAnimationFrame(testtile) : 0;
		}

		/* Cargo acceptance history of nearby stations */
		case 0x64: {
			CargoID cid = GetCargoTranslation(parameter, this->ro.grffile);
			if (!IsValidCargoID(cid)) return 0;

			/* Extract tile offset. */
			int8_t x_offs = GB(GetRegister(0x100), 0, 8);
			int8_t y_offs = GB(GetRegister(0x100), 8, 8);
			TileIndex testtile = Map::WrapToMap(this->tile + TileDiffXY(x_offs, y_offs));

			StationFinder stations(TileArea(testtile, 1, 1));
			const StationList *sl = stations.GetStations();

			/* Collect acceptance stats. */
			uint32_t res = 0;
			for (Station *st : *sl) {
				if (HasBit(st->goods[cid].status, GoodsEntry::GES_EVER_ACCEPTED))    SetBit(res, 0);
				if (HasBit(st->goods[cid].status, GoodsEntry::GES_LAST_MONTH))       SetBit(res, 1);
				if (HasBit(st->goods[cid].status, GoodsEntry::GES_CURRENT_MONTH))    SetBit(res, 2);
				if (HasBit(st->goods[cid].status, GoodsEntry::GES_ACCEPTED_BIGTICK)) SetBit(res, 3);
			}

			/* Cargo triggered CB 148? */
			if (HasBit(this->watched_cargo_triggers, cid)) SetBit(res, 4);

			return res;
		}

		/* Distance test for some house types */
		case 0x65: return GetDistanceFromNearbyHouse(parameter, this->tile, this->house_id);

		/* Class and ID of nearby house tile */
		case 0x66: {
			TileIndex testtile = GetNearbyTile(parameter, this->tile);
			if (!IsTileType(testtile, MP_HOUSE)) return 0xFFFFFFFF;
			HouseID nearby_house_id = GetHouseType(testtile);
			HouseSpec *hs = HouseSpec::Get(nearby_house_id);
			/* Information about the grf local classid if the house has a class */
			uint houseclass = 0;
			if (hs->class_id != HOUSE_NO_CLASS) {
				houseclass = (hs->grf_prop.grffile == this->ro.grffile ? 1 : 2) << 8;
				houseclass |= _class_mapping[hs->class_id].class_id;
			}
			/* old house type or grf-local houseid */
			uint local_houseid = 0;
			if (nearby_house_id < NEW_HOUSE_OFFSET) {
				local_houseid = nearby_house_id;
			} else {
				local_houseid = (hs->grf_prop.grffile == this->ro.grffile ? 1 : 2) << 8;
				local_houseid |= hs->grf_prop.local_id;
			}
			return houseclass << 16 | local_houseid;
		}

		/* GRFID of nearby house tile */
		case 0x67: {
			TileIndex testtile = GetNearbyTile(parameter, this->tile);
			if (!IsTileType(testtile, MP_HOUSE)) return 0xFFFFFFFF;
			HouseID house_id = GetHouseType(testtile);
			if (house_id < NEW_HOUSE_OFFSET) return 0;
			/* Checking the grffile information via HouseSpec doesn't work
			 * in case the newgrf was removed. */
			return _house_mngr.GetGRFID(house_id);
		}
	}

	Debug(grf, 1, "Unhandled house variable 0x{:X}", variable);

	*available = false;
	return UINT_MAX;
}

uint16_t GetHouseCallback(CallbackID callback, uint32_t param1, uint32_t param2, HouseID house_id, Town *town, TileIndex tile,
		bool not_yet_constructed, uint8_t initial_random_bits, CargoTypes watched_cargo_triggers)
{
	assert(IsValidTile(tile) && (not_yet_constructed || IsTileType(tile, MP_HOUSE)));

	HouseResolverObject object(house_id, tile, town, callback, param1, param2,
			not_yet_constructed, initial_random_bits, watched_cargo_triggers);
	return object.ResolveCallback();
}

static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, byte stage, HouseID house_id)
{
	const DrawTileSprites *dts = group->ProcessRegisters(&stage);

	const HouseSpec *hs = HouseSpec::Get(house_id);
	PaletteID palette = hs->random_colour[TileHash2Bit(ti->x, ti->y)] + PALETTE_RECOLOUR_START;
	if (HasBit(hs->callback_mask, CBM_HOUSE_COLOUR)) {
		uint16_t callback = GetHouseCallback(CBID_HOUSE_COLOUR, 0, 0, house_id, Town::GetByTile(ti->tile), ti->tile);
		if (callback != CALLBACK_FAILED) {
			/* If bit 14 is set, we should use a 2cc colour map, else use the callback value. */
			palette = HasBit(callback, 14) ? GB(callback, 0, 8) + SPR_2CCMAP_BASE : callback;
		}
	}

	SpriteID image = dts->ground.sprite;
	PaletteID pal  = dts->ground.pal;

	if (HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE)) image += stage;
	if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += stage;

	if (GB(image, 0, SPRITE_WIDTH) != 0) {
		DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, palette));
	}

	DrawNewGRFTileSeq(ti, dts, TO_HOUSES, stage, palette);
}

void DrawNewHouseTile(TileInfo *ti, HouseID house_id)
{
	const HouseSpec *hs = HouseSpec::Get(house_id);

	if (ti->tileh != SLOPE_FLAT) {
		bool draw_old_one = true;
		if (HasBit(hs->callback_mask, CBM_HOUSE_DRAW_FOUNDATIONS)) {
			/* Called to determine the type (if any) of foundation to draw for the house tile */
			uint32_t callback_res = GetHouseCallback(CBID_HOUSE_DRAW_FOUNDATIONS, 0, 0, house_id, Town::GetByTile(ti->tile), ti->tile);
			if (callback_res != CALLBACK_FAILED) draw_old_one = ConvertBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DRAW_FOUNDATIONS, callback_res);
		}

		if (draw_old_one) DrawFoundation(ti, FOUNDATION_LEVELED);
	}

	HouseResolverObject object(house_id, ti->tile, Town::GetByTile(ti->tile));

	const SpriteGroup *group = object.Resolve();
	if (group != nullptr && group->type == SGT_TILELAYOUT) {
		/* Limit the building stage to the number of stages supplied. */
		const TileLayoutSpriteGroup *tlgroup = (const TileLayoutSpriteGroup *)group;
		byte stage = GetHouseBuildingStage(ti->tile);
		DrawTileLayout(ti, tlgroup, stage, house_id);
	}
}

/* Simple wrapper for GetHouseCallback to keep the animation unified. */
uint16_t GetSimpleHouseCallback(CallbackID callback, uint32_t param1, uint32_t param2, const HouseSpec *spec, Town *town, TileIndex tile, CargoTypes extra_data)
{
	return GetHouseCallback(callback, param1, param2, spec - HouseSpec::Get(0), town, tile, false, 0, extra_data);
}

/** Helper class for animation control. */
struct HouseAnimationBase : public AnimationBase<HouseAnimationBase, HouseSpec, Town, CargoTypes, GetSimpleHouseCallback, TileAnimationFrameAnimationHelper<Town> > {
	static const CallbackID cb_animation_speed      = CBID_HOUSE_ANIMATION_SPEED;
	static const CallbackID cb_animation_next_frame = CBID_HOUSE_ANIMATION_NEXT_FRAME;

	static const HouseCallbackMask cbm_animation_speed      = CBM_HOUSE_ANIMATION_SPEED;
	static const HouseCallbackMask cbm_animation_next_frame = CBM_HOUSE_ANIMATION_NEXT_FRAME;
};

void AnimateNewHouseTile(TileIndex tile)
{
	const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
	if (hs == nullptr) return;

	HouseAnimationBase::AnimateTile(hs, Town::GetByTile(tile), tile, HasBit(hs->extra_flags, CALLBACK_1A_RANDOM_BITS));
}

void AnimateNewHouseConstruction(TileIndex tile)
{
	const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));

	if (HasBit(hs->callback_mask, CBM_HOUSE_CONSTRUCTION_STATE_CHANGE)) {
		HouseAnimationBase::ChangeAnimationFrame(CBID_HOUSE_CONSTRUCTION_STATE_CHANGE, hs, Town::GetByTile(tile), tile, 0, 0);
	}
}

bool CanDeleteHouse(TileIndex tile)
{
	const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));

	/* Humans are always allowed to remove buildings, as is water and disasters and
	 * anyone using the scenario editor. */
	if (Company::IsValidHumanID(_current_company) || _current_company == OWNER_WATER || _current_company == OWNER_NONE || _game_mode == GM_EDITOR || _generating_world) {
		return true;
	}

	if (HasBit(hs->callback_mask, CBM_HOUSE_DENY_DESTRUCTION)) {
		uint16_t callback_res = GetHouseCallback(CBID_HOUSE_DENY_DESTRUCTION, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile);
		return (callback_res == CALLBACK_FAILED || !ConvertBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DENY_DESTRUCTION, callback_res));
	} else {
		return !(hs->extra_flags & BUILDING_IS_PROTECTED);
	}
}

static void AnimationControl(TileIndex tile, uint16_t random_bits)
{
	const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));

	if (HasBit(hs->callback_mask, CBM_HOUSE_ANIMATION_START_STOP)) {
		uint32_t param = (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) ? (GB(Random(), 0, 16) | random_bits << 16) : Random();
		HouseAnimationBase::ChangeAnimationFrame(CBID_HOUSE_ANIMATION_START_STOP, hs, Town::GetByTile(tile), tile, param, 0);
	}
}

bool NewHouseTileLoop(TileIndex tile)
{
	const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));

	if (GetHouseProcessingTime(tile) > 0) {
		DecHouseProcessingTime(tile);
		return true;
	}

	TriggerHouse(tile, HOUSE_TRIGGER_TILE_LOOP);
	if (hs->building_flags & BUILDING_HAS_1_TILE) TriggerHouse(tile, HOUSE_TRIGGER_TILE_LOOP_TOP);

	if (HasBit(hs->callback_mask, CBM_HOUSE_ANIMATION_START_STOP)) {
		/* If this house is marked as having a synchronised callback, all the
		 * tiles will have the callback called at once, rather than when the
		 * tile loop reaches them. This should only be enabled for the northern
		 * tile, or strange things will happen (here, and in TTDPatch). */
		if (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) {
			uint16_t random = GB(Random(), 0, 16);

			if (hs->building_flags & BUILDING_HAS_1_TILE)  AnimationControl(tile, random);
			if (hs->building_flags & BUILDING_2_TILES_Y)   AnimationControl(TILE_ADDXY(tile, 0, 1), random);
			if (hs->building_flags & BUILDING_2_TILES_X)   AnimationControl(TILE_ADDXY(tile, 1, 0), random);
			if (hs->building_flags & BUILDING_HAS_4_TILES) AnimationControl(TILE_ADDXY(tile, 1, 1), random);
		} else {
			AnimationControl(tile, 0);
		}
	}

	/* Check callback 21, which determines if a house should be destroyed. */
	if (HasBit(hs->callback_mask, CBM_HOUSE_DESTRUCTION)) {
		uint16_t callback_res = GetHouseCallback(CBID_HOUSE_DESTRUCTION, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile);
		if (callback_res != CALLBACK_FAILED && Convert8bitBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DESTRUCTION, callback_res)) {
			ClearTownHouse(Town::GetByTile(tile), tile);
			return false;
		}
	}

	SetHouseProcessingTime(tile, hs->processing_time);
	MarkTileDirtyByTile(tile);
	return true;
}

static void DoTriggerHouse(TileIndex tile, HouseTrigger trigger, byte base_random, bool first)
{
	/* We can't trigger a non-existent building... */
	assert(IsTileType(tile, MP_HOUSE));

	HouseID hid = GetHouseType(tile);
	HouseSpec *hs = HouseSpec::Get(hid);

	if (hs->grf_prop.spritegroup[0] == nullptr) return;

	HouseResolverObject object(hid, tile, Town::GetByTile(tile), CBID_RANDOM_TRIGGER);
	object.waiting_triggers = GetHouseTriggers(tile) | trigger;
	SetHouseTriggers(tile, object.waiting_triggers); // store now for var 5F

	const SpriteGroup *group = object.Resolve();
	if (group == nullptr) return;

	/* Store remaining triggers. */
	SetHouseTriggers(tile, object.GetRemainingTriggers());

	/* Rerandomise bits. Scopes other than SELF are invalid for houses. For bug-to-bug-compatibility with TTDP we ignore the scope. */
	byte new_random_bits = Random();
	byte random_bits = GetHouseRandomBits(tile);
	uint32_t reseed = object.GetReseedSum();
	random_bits &= ~reseed;
	random_bits |= (first ? new_random_bits : base_random) & reseed;
	SetHouseRandomBits(tile, random_bits);

	switch (trigger) {
		case HOUSE_TRIGGER_TILE_LOOP:
			/* Random value already set. */
			break;

		case HOUSE_TRIGGER_TILE_LOOP_TOP:
			if (!first) {
				/* The top tile is marked dirty by the usual TileLoop */
				MarkTileDirtyByTile(tile);
				break;
			}
			/* Random value of first tile already set. */
			if (hs->building_flags & BUILDING_2_TILES_Y)   DoTriggerHouse(TILE_ADDXY(tile, 0, 1), trigger, random_bits, false);
			if (hs->building_flags & BUILDING_2_TILES_X)   DoTriggerHouse(TILE_ADDXY(tile, 1, 0), trigger, random_bits, false);
			if (hs->building_flags & BUILDING_HAS_4_TILES) DoTriggerHouse(TILE_ADDXY(tile, 1, 1), trigger, random_bits, false);
			break;
	}
}

void TriggerHouse(TileIndex t, HouseTrigger trigger)
{
	DoTriggerHouse(t, trigger, 0, true);
}

/**
 * Run the watched cargo accepted callback for a single house tile.
 * @param tile The house tile.
 * @param origin The triggering tile.
 * @param trigger_cargoes Cargo types that triggered the callback.
 * @param random Random bits.
 */
void DoWatchedCargoCallback(TileIndex tile, TileIndex origin, CargoTypes trigger_cargoes, uint16_t random)
{
	TileIndexDiffC diff = TileIndexToTileIndexDiffC(origin, tile);
	uint32_t cb_info = random << 16 | (uint8_t)diff.y << 8 | (uint8_t)diff.x;
	HouseAnimationBase::ChangeAnimationFrame(CBID_HOUSE_WATCHED_CARGO_ACCEPTED, HouseSpec::Get(GetHouseType(tile)), Town::GetByTile(tile), tile, 0, cb_info, trigger_cargoes);
}

/**
 * Run watched cargo accepted callback for a house.
 * @param tile House tile.
 * @param trigger_cargoes Triggering cargo types.
 * @pre IsTileType(t, MP_HOUSE)
 */
void WatchedCargoCallback(TileIndex tile, CargoTypes trigger_cargoes)
{
	assert(IsTileType(tile, MP_HOUSE));
	HouseID id = GetHouseType(tile);
	const HouseSpec *hs = HouseSpec::Get(id);

	trigger_cargoes &= hs->watched_cargoes;
	/* None of the trigger cargoes is watched? */
	if (trigger_cargoes == 0) return;

	/* Same random value for all tiles of a multi-tile house. */
	uint16_t r = Random();

	/* Do the callback, start at northern tile. */
	TileIndex north = tile + GetHouseNorthPart(id);
	hs = HouseSpec::Get(id);

	DoWatchedCargoCallback(north, tile, trigger_cargoes, r);
	if (hs->building_flags & BUILDING_2_TILES_Y)   DoWatchedCargoCallback(TILE_ADDXY(north, 0, 1), tile, trigger_cargoes, r);
	if (hs->building_flags & BUILDING_2_TILES_X)   DoWatchedCargoCallback(TILE_ADDXY(north, 1, 0), tile, trigger_cargoes, r);
	if (hs->building_flags & BUILDING_HAS_4_TILES) DoWatchedCargoCallback(TILE_ADDXY(north, 1, 1), tile, trigger_cargoes, r);
}