|
@@ -221,218 +221,216 @@ static uint32 HouseGetVariable(const Res
|
|
|
|
|
|
/* Whether the town is being created or just expanded. */
|
|
|
case 0x45: return _generating_world ? 1 : 0;
|
|
|
|
|
|
/* Current animation frame. */
|
|
|
case 0x46: return IsTileType(tile, MP_HOUSE) ? GetHouseAnimationFrame(tile) : 0;
|
|
|
|
|
|
|
|
|
/* Building counts for old houses with id = parameter. */
|
|
|
case 0x60: return GetNumHouses(parameter, town);
|
|
|
|
|
|
/* Building counts for new houses with id = parameter. */
|
|
|
case 0x61: {
|
|
|
const HouseSpec *hs = GetHouseSpecs(house_id);
|
|
|
if (hs->grffile == NULL) return 0;
|
|
|
|
|
|
HouseID new_house = _house_mngr.GetID(parameter, hs->grffile->grfid);
|
|
|
return new_house == INVALID_HOUSE_ID ? 0 : GetNumHouses(new_house, town);
|
|
|
}
|
|
|
|
|
|
/* Land info for nearby tiles. */
|
|
|
case 0x62: return GetNearbyTileInformation(parameter, tile);
|
|
|
|
|
|
/* Read GRF parameter */
|
|
|
case 0x7F: return GetGRFParameter(object->u.house.house_id, parameter);
|
|
|
}
|
|
|
|
|
|
DEBUG(grf, 1, "Unhandled house property 0x%X", variable);
|
|
|
|
|
|
*available = false;
|
|
|
return UINT_MAX;
|
|
|
}
|
|
|
|
|
|
static const SpriteGroup *HouseResolveReal(const ResolverObject *object, const SpriteGroup *group)
|
|
|
{
|
|
|
/* Houses do not have 'real' groups */
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* NewHouseResolver():
|
|
|
*
|
|
|
* Returns a resolver object to be used with feature 07 spritegroups.
|
|
|
*/
|
|
|
static void NewHouseResolver(ResolverObject *res, HouseID house_id, TileIndex tile, Town *town)
|
|
|
{
|
|
|
res->GetRandomBits = HouseGetRandomBits;
|
|
|
res->GetTriggers = HouseGetTriggers;
|
|
|
res->SetTriggers = HouseSetTriggers;
|
|
|
res->GetVariable = HouseGetVariable;
|
|
|
res->ResolveReal = HouseResolveReal;
|
|
|
|
|
|
res->u.house.tile = tile;
|
|
|
res->u.house.town = town;
|
|
|
res->u.house.house_id = house_id;
|
|
|
|
|
|
res->callback = CBID_NO_CALLBACK;
|
|
|
res->callback_param1 = 0;
|
|
|
res->callback_param2 = 0;
|
|
|
res->last_value = 0;
|
|
|
res->trigger = 0;
|
|
|
res->reseed = 0;
|
|
|
}
|
|
|
|
|
|
uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, Town *town, TileIndex tile)
|
|
|
{
|
|
|
ResolverObject object;
|
|
|
const SpriteGroup *group;
|
|
|
|
|
|
NewHouseResolver(&object, house_id, tile, town);
|
|
|
object.callback = callback;
|
|
|
object.callback_param1 = param1;
|
|
|
object.callback_param2 = param2;
|
|
|
|
|
|
group = Resolve(GetHouseSpecs(house_id)->spritegroup, &object);
|
|
|
if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED;
|
|
|
|
|
|
return group->g.callback.result;
|
|
|
}
|
|
|
|
|
|
void DrawTileLayout(const TileInfo *ti, const SpriteGroup *group, byte stage, HouseID house_id)
|
|
|
{
|
|
|
const DrawTileSprites *dts = group->g.layout.dts;
|
|
|
const DrawTileSeqStruct *dtss;
|
|
|
|
|
|
SpriteID image = dts->ground_sprite;
|
|
|
SpriteID pal = dts->ground_pal;
|
|
|
|
|
|
if (GB(image, 0, SPRITE_WIDTH) != 0) DrawGroundSprite(image, pal);
|
|
|
|
|
|
foreach_draw_tile_seq(dtss, dts->seq) {
|
|
|
if (GB(dtss->image, 0, SPRITE_WIDTH) == 0) continue;
|
|
|
|
|
|
image = dtss->image + stage;
|
|
|
pal = dtss->pal;
|
|
|
|
|
|
if (!HASBIT(image, SPRITE_MODIFIER_OPAQUE) && HASBIT(_transparent_opt, TO_HOUSES)) {
|
|
|
SETBIT(image, PALETTE_MODIFIER_TRANSPARENT);
|
|
|
pal = PALETTE_TO_TRANSPARENT;
|
|
|
} else if (HASBIT(image, PALETTE_MODIFIER_COLOR)) {
|
|
|
if ((HASBIT(image, SPRITE_MODIFIER_OPAQUE) || !HASBIT(_transparent_opt, TO_HOUSES)) && HASBIT(image, PALETTE_MODIFIER_COLOR)) {
|
|
|
if (pal == 0) {
|
|
|
const HouseSpec *hs = GetHouseSpecs(house_id);
|
|
|
if (HASBIT(hs->callback_mask, CBM_BUILDING_COLOUR)) {
|
|
|
uint16 callback = GetHouseCallback(CBID_BUILDING_COLOUR, 0, 0, house_id, GetTownByTile(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. */
|
|
|
pal = HASBIT(callback, 14) ? GB(callback, 0, 8) + SPR_2CCMAP_BASE : callback;
|
|
|
}
|
|
|
} else {
|
|
|
pal = hs->random_colour[OriginalTileRandomiser(ti->x, ti->y)] + PALETTE_RECOLOR_START;
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
pal = PAL_NONE;
|
|
|
}
|
|
|
|
|
|
if ((byte)dtss->delta_z != 0x80) {
|
|
|
AddSortableSpriteToDraw(
|
|
|
image, pal,
|
|
|
ti->x + dtss->delta_x, ti->y + dtss->delta_y,
|
|
|
dtss->size_x, dtss->size_y,
|
|
|
dtss->size_z, ti->z + dtss->delta_z
|
|
|
dtss->size_z, ti->z + dtss->delta_z,
|
|
|
HASBIT(_transparent_opt, TO_HOUSES)
|
|
|
);
|
|
|
} else {
|
|
|
AddChildSpriteScreen(image, pal, dtss->delta_x, dtss->delta_y);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void DrawNewHouseTile(TileInfo *ti, HouseID house_id)
|
|
|
{
|
|
|
const HouseSpec *hs = GetHouseSpecs(house_id);
|
|
|
const SpriteGroup *group;
|
|
|
ResolverObject object;
|
|
|
|
|
|
if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, ti->tileh);
|
|
|
|
|
|
NewHouseResolver(&object, house_id, ti->tile, GetTownByTile(ti->tile));
|
|
|
|
|
|
group = Resolve(hs->spritegroup, &object);
|
|
|
if (group == NULL || group->type != SGT_TILELAYOUT) {
|
|
|
/* XXX: This is for debugging purposes really, and shouldn't stay. */
|
|
|
DrawGroundSprite(SPR_SHADOW_CELL, PAL_NONE);
|
|
|
} else {
|
|
|
/* Limit the building stage to the number of stages supplied. */
|
|
|
byte stage = GetHouseBuildingStage(ti->tile);
|
|
|
stage = clamp(stage - 4 + group->g.layout.num_sprites, 0, group->g.layout.num_sprites - 1);
|
|
|
DrawTileLayout(ti, group, stage, house_id);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void AnimateNewHouseTile(TileIndex tile)
|
|
|
{
|
|
|
const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile));
|
|
|
byte animation_speed = hs->animation_speed;
|
|
|
bool frame_set_by_callback = false;
|
|
|
|
|
|
if (HASBIT(hs->callback_mask, CBM_ANIMATION_SPEED)) {
|
|
|
uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_SPEED, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile);
|
|
|
if (callback_res != CALLBACK_FAILED) animation_speed = clamp(callback_res & 0xFF, 2, 16);
|
|
|
}
|
|
|
|
|
|
/* An animation speed of 2 means the animation frame changes 4 ticks, and
|
|
|
* increasing this value by one doubles the wait. 2 is the minimum value
|
|
|
* allowed for animation_speed, which corresponds to 120ms, and 16 is the
|
|
|
* maximum, corresponding to around 33 minutes. */
|
|
|
if (_tick_counter % (1 << animation_speed) != 0) return;
|
|
|
|
|
|
byte frame = GetHouseAnimationFrame(tile);
|
|
|
byte num_frames = GB(hs->animation_frames, 0, 7);
|
|
|
|
|
|
if (HASBIT(hs->callback_mask, CBM_ANIMATION_NEXT_FRAME)) {
|
|
|
uint32 param = (hs->extra_flags & CALLBACK_1A_RANDOM_BITS) ? Random() : 0;
|
|
|
uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_NEXT_FRAME, param, 0, GetHouseType(tile), GetTownByTile(tile), tile);
|
|
|
|
|
|
if (callback_res != CALLBACK_FAILED) {
|
|
|
frame_set_by_callback = true;
|
|
|
|
|
|
switch (callback_res & 0xFF) {
|
|
|
case 0xFF:
|
|
|
DeleteAnimatedTile(tile);
|
|
|
break;
|
|
|
case 0xFE:
|
|
|
/* Carry on as normal. */
|
|
|
frame_set_by_callback = false;
|
|
|
break;
|
|
|
default:
|
|
|
frame = callback_res & 0xFF;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
/* If the lower 7 bits of the upper byte of the callback
|
|
|
* result are not empty, it is a sound effect. */
|
|
|
if (GB(callback_res, 8, 7) != 0) PlayHouseSound(GB(callback_res, 8, 7), tile);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (!frame_set_by_callback) {
|
|
|
if (frame < num_frames) {
|
|
|
frame++;
|
|
|
} else if (frame == num_frames && HASBIT(hs->animation_frames, 7)) {
|
|
|
/* This animation loops, so start again from the beginning */
|
|
|
frame = 0;
|
|
|
} else {
|
|
|
/* This animation doesn't loop, so stay here */
|
|
|
DeleteAnimatedTile(tile);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
SetHouseAnimationFrame(tile, frame);
|
|
|
MarkTileDirtyByTile(tile);
|
|
|
}
|
|
|
|
|
|
void ChangeHouseAnimationFrame(TileIndex tile, uint16 callback_result)
|
|
|
{
|
|
|
switch (callback_result & 0xFF) {
|
|
|
case 0xFD: /* Do nothing. */ break;
|
|
|
case 0xFE: AddAnimatedTile(tile); break;
|