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 #include "newgrf_commons.h" |
|
28 #include "transparency.h" |
28 |
29 |
29 static BuildingCounts _building_counts; |
30 static BuildingCounts _building_counts; |
30 static HouseClassMapping _class_mapping[HOUSE_CLASS_MAX]; |
31 static HouseClassMapping _class_mapping[HOUSE_CLASS_MAX]; |
31 |
32 |
32 HouseOverrideManager _house_mngr(NEW_HOUSE_OFFSET, HOUSE_MAX, INVALID_HOUSE_ID); |
33 HouseOverrideManager _house_mngr(NEW_HOUSE_OFFSET, HOUSE_MAX, INVALID_HOUSE_ID); |
208 switch (variable) { |
209 switch (variable) { |
209 /* Construction stage. */ |
210 /* Construction stage. */ |
210 case 0x40: return (IsTileType(tile, MP_HOUSE) ? GetHouseBuildingStage(tile) : 0) | OriginalTileRandomiser(TileX(tile), TileY(tile)) << 2; |
211 case 0x40: return (IsTileType(tile, MP_HOUSE) ? GetHouseBuildingStage(tile) : 0) | OriginalTileRandomiser(TileX(tile), TileY(tile)) << 2; |
211 |
212 |
212 /* Building age. */ |
213 /* Building age. */ |
213 case 0x41: return clamp(_cur_year - GetHouseConstructionYear(tile), 0, 0xFF); |
214 case 0x41: return Clamp(_cur_year - GetHouseConstructionYear(tile), 0, 0xFF); |
214 |
215 |
215 /* Town zone */ |
216 /* Town zone */ |
216 case 0x42: return GetTownRadiusGroup(town, tile); |
217 case 0x42: return GetTownRadiusGroup(town, tile); |
217 |
218 |
218 /* Terrain type */ |
219 /* Terrain type */ |
318 image = dtss->image; |
319 image = dtss->image; |
319 pal = dtss->pal; |
320 pal = dtss->pal; |
320 |
321 |
321 if (IS_CUSTOM_SPRITE(image)) image += stage; |
322 if (IS_CUSTOM_SPRITE(image)) image += stage; |
322 |
323 |
323 if ((HASBIT(image, SPRITE_MODIFIER_OPAQUE) || !HASBIT(_transparent_opt, TO_HOUSES)) && HASBIT(image, PALETTE_MODIFIER_COLOR)) { |
324 if ((HasBit(image, SPRITE_MODIFIER_OPAQUE) || !IsTransparencySet(TO_HOUSES)) && HasBit(image, PALETTE_MODIFIER_COLOR)) { |
324 if (pal == 0) { |
325 if (pal == 0) { |
325 const HouseSpec *hs = GetHouseSpecs(house_id); |
326 const HouseSpec *hs = GetHouseSpecs(house_id); |
326 if (HASBIT(hs->callback_mask, CBM_HOUSE_COLOUR)) { |
327 if (HasBit(hs->callback_mask, CBM_HOUSE_COLOUR)) { |
327 uint16 callback = GetHouseCallback(CBID_HOUSE_COLOUR, 0, 0, house_id, GetTownByTile(ti->tile), ti->tile); |
328 uint16 callback = GetHouseCallback(CBID_HOUSE_COLOUR, 0, 0, house_id, GetTownByTile(ti->tile), ti->tile); |
328 if (callback != CALLBACK_FAILED) { |
329 if (callback != CALLBACK_FAILED) { |
329 /* If bit 14 is set, we should use a 2cc colour map, else use the callback value. */ |
330 /* If bit 14 is set, we should use a 2cc colour map, else use the callback value. */ |
330 pal = HASBIT(callback, 14) ? GB(callback, 0, 8) + SPR_2CCMAP_BASE : callback; |
331 pal = HasBit(callback, 14) ? GB(callback, 0, 8) + SPR_2CCMAP_BASE : callback; |
331 } |
332 } |
332 } else { |
333 } else { |
333 pal = hs->random_colour[OriginalTileRandomiser(ti->x, ti->y)] + PALETTE_RECOLOR_START; |
334 pal = hs->random_colour[OriginalTileRandomiser(ti->x, ti->y)] + PALETTE_RECOLOR_START; |
334 } |
335 } |
335 } |
336 } |
341 AddSortableSpriteToDraw( |
342 AddSortableSpriteToDraw( |
342 image, pal, |
343 image, pal, |
343 ti->x + dtss->delta_x, ti->y + dtss->delta_y, |
344 ti->x + dtss->delta_x, ti->y + dtss->delta_y, |
344 dtss->size_x, dtss->size_y, |
345 dtss->size_x, dtss->size_y, |
345 dtss->size_z, ti->z + dtss->delta_z, |
346 dtss->size_z, ti->z + dtss->delta_z, |
346 HASBIT(_transparent_opt, TO_HOUSES) |
347 IsTransparencySet(TO_HOUSES) |
347 ); |
348 ); |
348 } else { |
349 } else { |
349 AddChildSpriteScreen(image, pal, dtss->delta_x, dtss->delta_y, HASBIT(_transparent_opt, TO_HOUSES)); |
350 AddChildSpriteScreen(image, pal, (byte)dtss->delta_x, (byte)dtss->delta_y, IsTransparencySet(TO_HOUSES)); |
350 } |
351 } |
351 } |
352 } |
352 } |
353 } |
353 |
354 |
354 void DrawNewHouseTile(TileInfo *ti, HouseID house_id) |
355 void DrawNewHouseTile(TileInfo *ti, HouseID house_id) |
366 /* XXX: This is for debugging purposes really, and shouldn't stay. */ |
367 /* XXX: This is for debugging purposes really, and shouldn't stay. */ |
367 DrawGroundSprite(SPR_SHADOW_CELL, PAL_NONE); |
368 DrawGroundSprite(SPR_SHADOW_CELL, PAL_NONE); |
368 } else { |
369 } else { |
369 /* Limit the building stage to the number of stages supplied. */ |
370 /* Limit the building stage to the number of stages supplied. */ |
370 byte stage = GetHouseBuildingStage(ti->tile); |
371 byte stage = GetHouseBuildingStage(ti->tile); |
371 stage = clamp(stage - 4 + group->g.layout.num_sprites, 0, group->g.layout.num_sprites - 1); |
372 stage = Clamp(stage - 4 + group->g.layout.num_sprites, 0, group->g.layout.num_sprites - 1); |
372 DrawTileLayout(ti, group, stage, house_id); |
373 DrawTileLayout(ti, group, stage, house_id); |
373 } |
374 } |
374 } |
375 } |
375 |
376 |
376 void AnimateNewHouseTile(TileIndex tile) |
377 void AnimateNewHouseTile(TileIndex tile) |
377 { |
378 { |
378 const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile)); |
379 const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile)); |
379 byte animation_speed = hs->animation_speed; |
380 byte animation_speed = hs->animation_speed; |
380 bool frame_set_by_callback = false; |
381 bool frame_set_by_callback = false; |
381 |
382 |
382 if (HASBIT(hs->callback_mask, CBM_HOUSE_ANIMATION_SPEED)) { |
383 if (HasBit(hs->callback_mask, CBM_HOUSE_ANIMATION_SPEED)) { |
383 uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_SPEED, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile); |
384 uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_SPEED, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile); |
384 if (callback_res != CALLBACK_FAILED) animation_speed = clamp(callback_res & 0xFF, 2, 16); |
385 if (callback_res != CALLBACK_FAILED) animation_speed = Clamp(callback_res & 0xFF, 2, 16); |
385 } |
386 } |
386 |
387 |
387 /* An animation speed of 2 means the animation frame changes 4 ticks, and |
388 /* An animation speed of 2 means the animation frame changes 4 ticks, and |
388 * increasing this value by one doubles the wait. 2 is the minimum value |
389 * increasing this value by one doubles the wait. 2 is the minimum value |
389 * allowed for animation_speed, which corresponds to 120ms, and 16 is the |
390 * allowed for animation_speed, which corresponds to 120ms, and 16 is the |
391 if (_tick_counter % (1 << animation_speed) != 0) return; |
392 if (_tick_counter % (1 << animation_speed) != 0) return; |
392 |
393 |
393 byte frame = GetHouseAnimationFrame(tile); |
394 byte frame = GetHouseAnimationFrame(tile); |
394 byte num_frames = GB(hs->animation_frames, 0, 7); |
395 byte num_frames = GB(hs->animation_frames, 0, 7); |
395 |
396 |
396 if (HASBIT(hs->callback_mask, CBM_HOUSE_ANIMATION_NEXT_FRAME)) { |
397 if (HasBit(hs->callback_mask, CBM_HOUSE_ANIMATION_NEXT_FRAME)) { |
397 uint32 param = (hs->extra_flags & CALLBACK_1A_RANDOM_BITS) ? Random() : 0; |
398 uint32 param = (hs->extra_flags & CALLBACK_1A_RANDOM_BITS) ? Random() : 0; |
398 uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_NEXT_FRAME, param, 0, GetHouseType(tile), GetTownByTile(tile), tile); |
399 uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_NEXT_FRAME, param, 0, GetHouseType(tile), GetTownByTile(tile), tile); |
399 |
400 |
400 if (callback_res != CALLBACK_FAILED) { |
401 if (callback_res != CALLBACK_FAILED) { |
401 frame_set_by_callback = true; |
402 frame_set_by_callback = true; |
420 } |
421 } |
421 |
422 |
422 if (!frame_set_by_callback) { |
423 if (!frame_set_by_callback) { |
423 if (frame < num_frames) { |
424 if (frame < num_frames) { |
424 frame++; |
425 frame++; |
425 } else if (frame == num_frames && HASBIT(hs->animation_frames, 7)) { |
426 } else if (frame == num_frames && HasBit(hs->animation_frames, 7)) { |
426 /* This animation loops, so start again from the beginning */ |
427 /* This animation loops, so start again from the beginning */ |
427 frame = 0; |
428 frame = 0; |
428 } else { |
429 } else { |
429 /* This animation doesn't loop, so stay here */ |
430 /* This animation doesn't loop, so stay here */ |
430 DeleteAnimatedTile(tile); |
431 DeleteAnimatedTile(tile); |
458 /* Human players are always allowed to remove buildings, as is water and |
459 /* Human players are always allowed to remove buildings, as is water and |
459 * anyone using the scenario editor. */ |
460 * anyone using the scenario editor. */ |
460 if ((IsValidPlayer(_current_player) && IsHumanPlayer(_current_player)) |
461 if ((IsValidPlayer(_current_player) && IsHumanPlayer(_current_player)) |
461 || _current_player == OWNER_WATER || _current_player == OWNER_NONE) return true; |
462 || _current_player == OWNER_WATER || _current_player == OWNER_NONE) return true; |
462 |
463 |
463 if (HASBIT(hs->callback_mask, CBM_HOUSE_DENY_DESTRUCTION)) { |
464 if (HasBit(hs->callback_mask, CBM_HOUSE_DENY_DESTRUCTION)) { |
464 uint16 callback_res = GetHouseCallback(CBID_HOUSE_DENY_DESTRUCTION, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile); |
465 uint16 callback_res = GetHouseCallback(CBID_HOUSE_DENY_DESTRUCTION, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile); |
465 return (callback_res == CALLBACK_FAILED || callback_res == 0); |
466 return (callback_res == CALLBACK_FAILED || callback_res == 0); |
466 } else { |
467 } else { |
467 return !(hs->extra_flags & BUILDING_IS_PROTECTED); |
468 return !(hs->extra_flags & BUILDING_IS_PROTECTED); |
468 } |
469 } |
470 |
471 |
471 static void AnimationControl(TileIndex tile, uint16 random_bits) |
472 static void AnimationControl(TileIndex tile, uint16 random_bits) |
472 { |
473 { |
473 const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile)); |
474 const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile)); |
474 |
475 |
475 if (HASBIT(hs->callback_mask, CBM_HOUSE_ANIMATION_START_STOP)) { |
476 if (HasBit(hs->callback_mask, CBM_HOUSE_ANIMATION_START_STOP)) { |
476 uint32 param = (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) ? (GB(Random(), 0, 16) | random_bits << 16) : Random(); |
477 uint32 param = (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) ? (GB(Random(), 0, 16) | random_bits << 16) : Random(); |
477 uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_START_STOP, param, 0, GetHouseType(tile), GetTownByTile(tile), tile); |
478 uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_START_STOP, param, 0, GetHouseType(tile), GetTownByTile(tile), tile); |
478 |
479 |
479 if (callback_res != CALLBACK_FAILED) ChangeHouseAnimationFrame(tile, callback_res); |
480 if (callback_res != CALLBACK_FAILED) ChangeHouseAnimationFrame(tile, callback_res); |
480 } |
481 } |
487 if (GetHouseProcessingTime(tile) > 0) { |
488 if (GetHouseProcessingTime(tile) > 0) { |
488 DecHouseProcessingTime(tile); |
489 DecHouseProcessingTime(tile); |
489 return true; |
490 return true; |
490 } |
491 } |
491 |
492 |
492 /* @todo: Magic with triggers goes here. Got to implement that, one day. .. |
493 TriggerHouse(tile, HOUSE_TRIGGER_TILE_LOOP); |
493 * Process randomizing of tiles following specs. |
494 TriggerHouse(tile, HOUSE_TRIGGER_TILE_LOOP_TOP); |
494 * Once done, redraw the house |
495 |
495 * MarkTileDirtyByTile(tile); |
496 if (HasBit(hs->callback_mask, CBM_HOUSE_ANIMATION_START_STOP)) { |
496 */ |
|
497 |
|
498 if (HASBIT(hs->callback_mask, CBM_HOUSE_ANIMATION_START_STOP)) { |
|
499 /* If this house is marked as having a synchronised callback, all the |
497 /* If this house is marked as having a synchronised callback, all the |
500 * tiles will have the callback called at once, rather than when the |
498 * tiles will have the callback called at once, rather than when the |
501 * tile loop reaches them. This should only be enabled for the northern |
499 * tile loop reaches them. This should only be enabled for the northern |
502 * tile, or strange things will happen (here, and in TTDPatch). */ |
500 * tile, or strange things will happen (here, and in TTDPatch). */ |
503 if (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) { |
501 if (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) { |
511 AnimationControl(tile, 0); |
509 AnimationControl(tile, 0); |
512 } |
510 } |
513 } |
511 } |
514 |
512 |
515 /* Check callback 21, which determines if a house should be destroyed. */ |
513 /* Check callback 21, which determines if a house should be destroyed. */ |
516 if (HASBIT(hs->callback_mask, CBM_HOUSE_DESTRUCTION)) { |
514 if (HasBit(hs->callback_mask, CBM_HOUSE_DESTRUCTION)) { |
517 uint16 callback_res = GetHouseCallback(CBID_HOUSE_DESTRUCTION, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile); |
515 uint16 callback_res = GetHouseCallback(CBID_HOUSE_DESTRUCTION, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile); |
518 if (callback_res != CALLBACK_FAILED && callback_res > 0) { |
516 if (callback_res != CALLBACK_FAILED && callback_res > 0) { |
519 ClearTownHouse(GetTownByTile(tile), tile); |
517 ClearTownHouse(GetTownByTile(tile), tile); |
520 return false; |
518 return false; |
521 } |
519 } |
522 } |
520 } |
523 |
521 |
524 SetHouseProcessingTime(tile, hs->processing_time); |
522 SetHouseProcessingTime(tile, hs->processing_time); |
525 return true; |
523 return true; |
526 } |
524 } |
|
525 |
|
526 static void DoTriggerHouse(TileIndex tile, HouseTrigger trigger, byte base_random, bool first) |
|
527 { |
|
528 ResolverObject object; |
|
529 |
|
530 /* We can't trigger a non-existent building... */ |
|
531 assert(IsTileType(tile, MP_HOUSE)); |
|
532 |
|
533 HouseID hid = GetHouseType(tile); |
|
534 HouseSpec *hs = GetHouseSpecs(hid); |
|
535 |
|
536 NewHouseResolver(&object, hid, tile, GetTownByTile(tile)); |
|
537 |
|
538 object.callback = CBID_RANDOM_TRIGGER; |
|
539 object.trigger = trigger; |
|
540 |
|
541 const SpriteGroup *group = Resolve(hs->spritegroup, &object); |
|
542 if (group == NULL) return; |
|
543 |
|
544 byte new_random_bits = Random(); |
|
545 byte random_bits = GetHouseRandomBits(tile); |
|
546 random_bits &= ~object.reseed; |
|
547 random_bits |= (first ? new_random_bits : base_random) & object.reseed; |
|
548 SetHouseRandomBits(tile, random_bits); |
|
549 |
|
550 switch (trigger) { |
|
551 case HOUSE_TRIGGER_TILE_LOOP: |
|
552 /* Random value already set. */ |
|
553 break; |
|
554 |
|
555 case HOUSE_TRIGGER_TILE_LOOP_TOP: |
|
556 if (!first) break; |
|
557 /* Random value of first tile already set. */ |
|
558 if (hs->building_flags & BUILDING_2_TILES_Y) DoTriggerHouse(TILE_ADDXY(tile, 0, 1), trigger, random_bits, false); |
|
559 if (hs->building_flags & BUILDING_2_TILES_X) DoTriggerHouse(TILE_ADDXY(tile, 1, 0), trigger, random_bits, false); |
|
560 if (hs->building_flags & BUILDING_HAS_4_TILES) DoTriggerHouse(TILE_ADDXY(tile, 1, 1), trigger, random_bits, false); |
|
561 break; |
|
562 } |
|
563 } |
|
564 |
|
565 void TriggerHouse(TileIndex t, HouseTrigger trigger) |
|
566 { |
|
567 DoTriggerHouse(t, trigger, 0, true); |
|
568 } |