22 #include "newgrf_house.h" |
22 #include "newgrf_house.h" |
23 #include "newgrf_spritegroup.h" |
23 #include "newgrf_spritegroup.h" |
24 #include "newgrf_callbacks.h" |
24 #include "newgrf_callbacks.h" |
25 #include "newgrf_town.h" |
25 #include "newgrf_town.h" |
26 #include "newgrf_sound.h" |
26 #include "newgrf_sound.h" |
|
27 #include "newgrf_commons.h" |
27 |
28 |
28 static BuildingCounts _building_counts; |
29 static BuildingCounts _building_counts; |
29 static HouseClassMapping _class_mapping[HOUSE_CLASS_MAX]; |
30 static HouseClassMapping _class_mapping[HOUSE_CLASS_MAX]; |
30 HouseIDMapping _house_id_mapping[HOUSE_MAX]; |
31 |
31 |
32 HouseOverrideManager _house_mngr(NEW_HOUSE_OFFSET, HOUSE_MAX, INVALID_HOUSE_ID); |
32 /* Since the house IDs defined by the GRF file don't necessarily correlate |
|
33 * to those used by the game, the IDs used for overriding old houses must be |
|
34 * translated when the house spec is set. */ |
|
35 static uint16 _house_overrides[NEW_HOUSE_OFFSET]; |
|
36 |
|
37 void AddHouseOverride(uint8 local_id, uint house_type) |
|
38 { |
|
39 assert(house_type < NEW_HOUSE_OFFSET); |
|
40 _house_overrides[house_type] = local_id; |
|
41 } |
|
42 |
|
43 void ResetHouseOverrides() |
|
44 { |
|
45 for (int i = 0; i != lengthof(_house_overrides); i++) { |
|
46 _house_overrides[i] = INVALID_HOUSE_ID; |
|
47 } |
|
48 } |
|
49 |
|
50 static HouseID GetHouseID(byte grf_local_id, uint32 grfid) |
|
51 { |
|
52 const HouseIDMapping *map; |
|
53 |
|
54 for (HouseID house_id = NEW_HOUSE_OFFSET; house_id != lengthof(_house_id_mapping); house_id++) { |
|
55 map = &_house_id_mapping[house_id]; |
|
56 if (map->house_id == grf_local_id && map->grfid == grfid) return house_id; |
|
57 } |
|
58 return INVALID_HOUSE_ID; |
|
59 } |
|
60 |
|
61 static HouseID AddHouseID(byte grf_local_id, uint32 grfid, byte substitute_id) |
|
62 { |
|
63 HouseID house_id; |
|
64 HouseIDMapping *map; |
|
65 |
|
66 /* Look to see if this house has already been added. This is done |
|
67 * separately from the loop below in case a GRF has been deleted, and there |
|
68 * are any gaps in the array. */ |
|
69 house_id = GetHouseID(grf_local_id, grfid); |
|
70 if (house_id != INVALID_HOUSE_ID) return house_id; |
|
71 |
|
72 /* This house hasn't been defined before, so give it an ID now. */ |
|
73 for (house_id = NEW_HOUSE_OFFSET; house_id != lengthof(_house_id_mapping); house_id++) { |
|
74 map = &_house_id_mapping[house_id]; |
|
75 |
|
76 if (map->house_id == 0 && map->grfid == 0) { |
|
77 map->house_id = grf_local_id; |
|
78 map->grfid = grfid; |
|
79 map->substitute_id = substitute_id; |
|
80 return house_id; |
|
81 } |
|
82 } |
|
83 |
|
84 return INVALID_HOUSE_ID; |
|
85 } |
|
86 |
|
87 void SetHouseSpec(const HouseSpec *hs) |
|
88 { |
|
89 HouseID house_id = AddHouseID(hs->local_id, hs->grffile->grfid, hs->substitute_id); |
|
90 |
|
91 if (house_id == INVALID_HOUSE_ID) { |
|
92 grfmsg(1, "SetHouseSpec: Too many houses allocated. Ignoring."); |
|
93 return; |
|
94 } |
|
95 |
|
96 memcpy(&_house_specs[house_id], hs, sizeof(*hs)); |
|
97 |
|
98 /* Now add the overrides. */ |
|
99 for (int i = 0; i != lengthof(_house_overrides); i++) { |
|
100 HouseSpec *overridden_hs = GetHouseSpecs(i); |
|
101 |
|
102 if (_house_overrides[i] != hs->local_id) continue; |
|
103 |
|
104 overridden_hs->override = house_id; |
|
105 _house_overrides[i] = INVALID_HOUSE_ID; |
|
106 } |
|
107 } |
|
108 |
|
109 void ResetHouseIDMapping() |
|
110 { |
|
111 memset(&_house_id_mapping, 0, sizeof(_house_id_mapping)); |
|
112 } |
|
113 |
33 |
114 void CheckHouseIDs() |
34 void CheckHouseIDs() |
115 { |
35 { |
116 for (TileIndex t = 0; t < MapSize(); t++) { |
36 for (TileIndex t = 0; t < MapSize(); t++) { |
117 HouseID house_id; |
37 HouseID house_id; |
120 |
40 |
121 house_id = GetHouseType(t); |
41 house_id = GetHouseType(t); |
122 if (!GetHouseSpecs(house_id)->enabled && house_id >= NEW_HOUSE_OFFSET) { |
42 if (!GetHouseSpecs(house_id)->enabled && house_id >= NEW_HOUSE_OFFSET) { |
123 /* The specs for this type of house are not available any more, so |
43 /* The specs for this type of house are not available any more, so |
124 * replace it with the substitute original house type. */ |
44 * replace it with the substitute original house type. */ |
125 SetHouseType(t, _house_id_mapping[house_id].substitute_id); |
45 SetHouseType(t, _house_mngr.GetSubstituteID(house_id)); |
126 } |
46 } |
127 } |
47 } |
128 |
48 |
129 InitializeBuildingCounts(); |
49 InitializeBuildingCounts(); |
130 AfterLoadCountBuildings(); |
50 AfterLoadCountBuildings(); |
311 /* Building counts for new houses with id = parameter. */ |
231 /* Building counts for new houses with id = parameter. */ |
312 case 0x61: { |
232 case 0x61: { |
313 const HouseSpec *hs = GetHouseSpecs(house_id); |
233 const HouseSpec *hs = GetHouseSpecs(house_id); |
314 if (hs->grffile == NULL) return 0; |
234 if (hs->grffile == NULL) return 0; |
315 |
235 |
316 HouseID new_house = GetHouseID(parameter, hs->grffile->grfid); |
236 HouseID new_house = _house_mngr.GetID(parameter, hs->grffile->grfid); |
317 return new_house == INVALID_HOUSE_ID ? 0 : GetNumHouses(new_house, town); |
237 return new_house == INVALID_HOUSE_ID ? 0 : GetNumHouses(new_house, town); |
318 } |
238 } |
319 |
239 |
320 /* Land info for nearby tiles. */ |
240 /* Land info for nearby tiles. */ |
321 case 0x62: { |
241 case 0x62: { |
372 res->last_value = 0; |
292 res->last_value = 0; |
373 res->trigger = 0; |
293 res->trigger = 0; |
374 res->reseed = 0; |
294 res->reseed = 0; |
375 } |
295 } |
376 |
296 |
377 uint16 GetHouseCallback(uint16 callback, uint32 param1, HouseID house_id, Town *town, TileIndex tile) |
297 uint16 GetHouseCallback(uint16 callback, uint32 param1, uint32 param2, HouseID house_id, Town *town, TileIndex tile) |
378 { |
298 { |
379 ResolverObject object; |
299 ResolverObject object; |
380 const SpriteGroup *group; |
300 const SpriteGroup *group; |
381 |
301 |
382 NewHouseResolver(&object, house_id, tile, town); |
302 NewHouseResolver(&object, house_id, tile, town); |
383 object.callback = callback; |
303 object.callback = callback; |
384 object.callback_param1 = param1; |
304 object.callback_param1 = param1; |
385 object.callback_param2 = 0; |
305 object.callback_param2 = param2; |
386 |
306 |
387 group = Resolve(GetHouseSpecs(house_id)->spritegroup, &object); |
307 group = Resolve(GetHouseSpecs(house_id)->spritegroup, &object); |
388 if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED; |
308 if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED; |
389 |
309 |
390 return group->g.callback.result; |
310 return group->g.callback.result; |
411 pal = PALETTE_TO_TRANSPARENT; |
331 pal = PALETTE_TO_TRANSPARENT; |
412 } else if (HASBIT(image, PALETTE_MODIFIER_COLOR)) { |
332 } else if (HASBIT(image, PALETTE_MODIFIER_COLOR)) { |
413 if (pal == 0) { |
333 if (pal == 0) { |
414 const HouseSpec *hs = GetHouseSpecs(house_id); |
334 const HouseSpec *hs = GetHouseSpecs(house_id); |
415 if (HASBIT(hs->callback_mask, CBM_BUILDING_COLOUR)) { |
335 if (HASBIT(hs->callback_mask, CBM_BUILDING_COLOUR)) { |
416 uint16 callback = GetHouseCallback(CBID_BUILDING_COLOUR, 0, house_id, GetTownByTile(ti->tile), ti->tile); |
336 uint16 callback = GetHouseCallback(CBID_BUILDING_COLOUR, 0, 0, house_id, GetTownByTile(ti->tile), ti->tile); |
417 if (callback != CALLBACK_FAILED) { |
337 if (callback != CALLBACK_FAILED) { |
418 /* If bit 14 is set, we should use a 2cc colour map, else use the callback value. */ |
338 /* If bit 14 is set, we should use a 2cc colour map, else use the callback value. */ |
419 pal = HASBIT(callback, 14) ? GB(callback, 0, 8) + SPR_2CCMAP_BASE : callback; |
339 pal = HASBIT(callback, 14) ? GB(callback, 0, 8) + SPR_2CCMAP_BASE : callback; |
420 } |
340 } |
421 } else { |
341 } else { |
466 const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile)); |
386 const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile)); |
467 byte animation_speed = hs->animation_speed; |
387 byte animation_speed = hs->animation_speed; |
468 bool frame_set_by_callback = false; |
388 bool frame_set_by_callback = false; |
469 |
389 |
470 if (HASBIT(hs->callback_mask, CBM_ANIMATION_SPEED)) { |
390 if (HASBIT(hs->callback_mask, CBM_ANIMATION_SPEED)) { |
471 uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_SPEED, 0, GetHouseType(tile), GetTownByTile(tile), tile); |
391 uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_SPEED, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile); |
472 if (callback_res != CALLBACK_FAILED) animation_speed = clamp(callback_res & 0xFF, 2, 16); |
392 if (callback_res != CALLBACK_FAILED) animation_speed = clamp(callback_res & 0xFF, 2, 16); |
473 } |
393 } |
474 |
394 |
475 /* An animation speed of 2 means the animation frame changes 4 ticks, and |
395 /* An animation speed of 2 means the animation frame changes 4 ticks, and |
476 * increasing this value by one doubles the wait. 2 is the minimum value |
396 * increasing this value by one doubles the wait. 2 is the minimum value |
481 byte frame = GetHouseAnimationFrame(tile); |
401 byte frame = GetHouseAnimationFrame(tile); |
482 byte num_frames = GB(hs->animation_frames, 0, 7); |
402 byte num_frames = GB(hs->animation_frames, 0, 7); |
483 |
403 |
484 if (HASBIT(hs->callback_mask, CBM_ANIMATION_NEXT_FRAME)) { |
404 if (HASBIT(hs->callback_mask, CBM_ANIMATION_NEXT_FRAME)) { |
485 uint32 param = (hs->extra_flags & CALLBACK_1A_RANDOM_BITS) ? Random() : 0; |
405 uint32 param = (hs->extra_flags & CALLBACK_1A_RANDOM_BITS) ? Random() : 0; |
486 uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_NEXT_FRAME, param, GetHouseType(tile), GetTownByTile(tile), tile); |
406 uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_NEXT_FRAME, param, 0, GetHouseType(tile), GetTownByTile(tile), tile); |
487 |
407 |
488 if (callback_res != CALLBACK_FAILED) { |
408 if (callback_res != CALLBACK_FAILED) { |
489 frame_set_by_callback = true; |
409 frame_set_by_callback = true; |
490 |
410 |
491 switch (callback_res & 0xFF) { |
411 switch (callback_res & 0xFF) { |
547 * anyone using the scenario editor. */ |
467 * anyone using the scenario editor. */ |
548 if ((IsValidPlayer(_current_player) && IsHumanPlayer(_current_player)) |
468 if ((IsValidPlayer(_current_player) && IsHumanPlayer(_current_player)) |
549 || _current_player == OWNER_WATER || _current_player == OWNER_NONE) return true; |
469 || _current_player == OWNER_WATER || _current_player == OWNER_NONE) return true; |
550 |
470 |
551 if (HASBIT(hs->callback_mask, CBM_HOUSE_DENY_DESTRUCTION)) { |
471 if (HASBIT(hs->callback_mask, CBM_HOUSE_DENY_DESTRUCTION)) { |
552 uint16 callback_res = GetHouseCallback(CBID_HOUSE_DENY_DESTRUCTION, 0, GetHouseType(tile), GetTownByTile(tile), tile); |
472 uint16 callback_res = GetHouseCallback(CBID_HOUSE_DENY_DESTRUCTION, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile); |
553 return (callback_res == CALLBACK_FAILED || callback_res == 0); |
473 return (callback_res == CALLBACK_FAILED || callback_res == 0); |
554 } else { |
474 } else { |
555 return !(hs->extra_flags & BUILDING_IS_PROTECTED); |
475 return !(hs->extra_flags & BUILDING_IS_PROTECTED); |
556 } |
476 } |
557 } |
477 } |
560 { |
480 { |
561 const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile)); |
481 const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile)); |
562 |
482 |
563 if (HASBIT(hs->callback_mask, CBM_ANIMATION_START_STOP)) { |
483 if (HASBIT(hs->callback_mask, CBM_ANIMATION_START_STOP)) { |
564 uint32 param = (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) ? (GB(Random(), 0, 16) | random_bits << 16) : Random(); |
484 uint32 param = (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) ? (GB(Random(), 0, 16) | random_bits << 16) : Random(); |
565 uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_START_STOP, param, GetHouseType(tile), GetTownByTile(tile), tile); |
485 uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_START_STOP, param, 0, GetHouseType(tile), GetTownByTile(tile), tile); |
566 |
486 |
567 if (callback_res != CALLBACK_FAILED) ChangeHouseAnimationFrame(tile, callback_res); |
487 if (callback_res != CALLBACK_FAILED) ChangeHouseAnimationFrame(tile, callback_res); |
568 } |
488 } |
569 } |
489 } |
570 |
490 |
575 if (GetHouseProcessingTime(tile) > 0) { |
495 if (GetHouseProcessingTime(tile) > 0) { |
576 DecHouseProcessingTime(tile); |
496 DecHouseProcessingTime(tile); |
577 return true; |
497 return true; |
578 } |
498 } |
579 |
499 |
580 /* @todo: Magic with triggers goes here. Got to implement that, one day. .. */ |
500 /* @todo: Magic with triggers goes here. Got to implement that, one day. .. |
|
501 * Process randomizing of tiles following specs. |
|
502 * Once done, redraw the house |
|
503 * MarkTileDirtyByTile(tile); |
|
504 */ |
581 |
505 |
582 if (HASBIT(hs->callback_mask, CBM_ANIMATION_START_STOP)) { |
506 if (HASBIT(hs->callback_mask, CBM_ANIMATION_START_STOP)) { |
583 /* If this house is marked as having a synchronised callback, all the |
507 /* If this house is marked as having a synchronised callback, all the |
584 * tiles will have the callback called at once, rather than when the |
508 * tiles will have the callback called at once, rather than when the |
585 * tile loop reaches them. This should only be enabled for the northern |
509 * tile loop reaches them. This should only be enabled for the northern |
596 } |
520 } |
597 } |
521 } |
598 |
522 |
599 /* Check callback 21, which determines if a house should be destroyed. */ |
523 /* Check callback 21, which determines if a house should be destroyed. */ |
600 if (HASBIT(hs->callback_mask, CBM_HOUSE_DESTRUCTION)) { |
524 if (HASBIT(hs->callback_mask, CBM_HOUSE_DESTRUCTION)) { |
601 uint16 callback_res = GetHouseCallback(CBID_HOUSE_DESTRUCTION, 0, GetHouseType(tile), GetTownByTile(tile), tile); |
525 uint16 callback_res = GetHouseCallback(CBID_HOUSE_DESTRUCTION, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile); |
602 if (callback_res != CALLBACK_FAILED && callback_res > 0) { |
526 if (callback_res != CALLBACK_FAILED && callback_res > 0) { |
603 ClearTownHouse(GetTownByTile(tile), tile); |
527 ClearTownHouse(GetTownByTile(tile), tile); |
604 return false; |
528 return false; |
605 } |
529 } |
606 } |
530 } |