diff --git a/src/economy.cpp b/src/economy.cpp index 713af79a7a..25c26fd7e6 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -36,6 +36,7 @@ #include "newgrf_sound.h" #include "newgrf_callbacks.h" #include "newgrf_industries.h" +#include "newgrf_industrytiles.h" #include "unmovable.h" #include "date.h" #include "cargotype.h" @@ -1251,6 +1252,8 @@ static void DeliverGoodsToIndustry(TileIndex xy, CargoID cargo_type, int num_pie best->produced_cargo_waiting[0] = min(best->produced_cargo_waiting[0] + (num_pieces * indspec->input_cargo_multiplier[accepted_cargo_index][0] / 256), 0xFFFF); best->produced_cargo_waiting[1] = min(best->produced_cargo_waiting[1] + (num_pieces * indspec->input_cargo_multiplier[accepted_cargo_index][1] / 256), 0xFFFF); } + + StartStopIndustryTileAnimation(best, IAT_INDUSTRY_RECEIVED_CARGO); } } diff --git a/src/industry.h b/src/industry.h index d971858628..ab528269cc 100644 --- a/src/industry.h +++ b/src/industry.h @@ -186,6 +186,10 @@ struct IndustryTileSpec { ///< state instead of the construction state /* Newgrf data */ uint8 callback_flags; ///< Flags telling which grf callback is set + uint16 animation_info; ///< Information about the animation (is it looping, how many loops etc) + uint8 animation_speed; ///< The speed of the animation + uint8 animation_triggers; ///< When to start the animation + uint8 animation_special_flags; ///< Extra flags to influence the animation bool enabled; ///< entity still avaible (by default true).newgrf can disable it, though struct GRFFileProps grf_prop; }; diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index 388621cabe..da81964868 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -413,7 +413,7 @@ static void TransportIndustryGoods(TileIndex tile) am = MoveGoodsToStation(i->xy, i->width, i->height, indspec->produced_cargo[0], cw); i->this_month_transported[0] += am; - if (am != 0) { + if (am != 0 && !StartStopIndustryTileAnimation(i, IAT_INDUSTRY_DISTRIBUTES_CARGO)) { uint newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_production; if (newgfx != INDUSTRYTILE_NOANIM) { @@ -442,8 +442,14 @@ static void TransportIndustryGoods(TileIndex tile) static void AnimateTile_Industry(TileIndex tile) { byte m; + IndustryGfx gfx = GetIndustryGfx(tile); + + if (GetIndustryTileSpec(gfx)->animation_info != 0xFFFF) { + AnimateNewIndustryTile(tile); + return; + } - switch (GetIndustryGfx(tile)) { + switch (gfx) { case GFX_SUGAR_MINE_SIEVE: if ((_tick_counter & 1) == 0) { m = GetIndustryAnimationState(tile) + 1; @@ -629,6 +635,7 @@ static void MakeIndustryTileBigger(TileIndex tile) stage = GetIndustryConstructionStage(tile) + 1; SetIndustryConstructionCounter(tile, 0); SetIndustryConstructionStage(tile, stage); + StartStopIndustryTileAnimation(tile, IAT_CONSTRUCTION_STATE_CHANGE); if (stage == 3) { SetIndustryCompleted(tile, true); } @@ -637,7 +644,15 @@ static void MakeIndustryTileBigger(TileIndex tile) if (!IsIndustryCompleted(tile)) return; - switch (GetIndustryGfx(tile)) { + IndustryGfx gfx = GetIndustryGfx(tile); + if (gfx >= NEW_INDUSTRYTILEOFFSET) { + /* New industry */ + const IndustryTileSpec *its = GetIndustryTileSpec(gfx); + if (its->animation_info != 0xFFFF) AddAnimatedTile(tile); + return; + } + + switch (gfx) { case GFX_POWERPLANT_CHIMNEY: CreateIndustryEffectSmoke(tile); break; @@ -701,6 +716,8 @@ static void TileLoop_Industry(TileIndex tile) TransportIndustryGoods(tile); + if (StartStopIndustryTileAnimation(tile, IAT_TILELOOP)) return; + newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_next; if (newgfx != INDUSTRYTILE_NOANIM) { ResetIndustryConstructionStage(tile); @@ -1032,6 +1049,7 @@ void OnTick_Industry() if (_game_mode == GM_EDITOR) return; FOR_ALL_INDUSTRIES(i) { + StartStopIndustryTileAnimation(i, IAT_INDUSTRY_TICK); ProduceIndustryGoods(i); } } diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 8de6063645..f7bce1cb92 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -1765,19 +1765,19 @@ static bool IndustrytilesChangeInfo(uint indtid, int numinfo, int prop, byte **b break; case 0x0F: // Animation information - grf_load_word(&buf); // TODO + tsp->animation_info = grf_load_word(&buf); break; case 0x10: // Animation speed - grf_load_byte(&buf); // TODO + tsp->animation_speed = grf_load_byte(&buf); break; case 0x11: // Triggers for callback 25 - grf_load_byte(&buf); // TODO + tsp->animation_triggers = grf_load_byte(&buf); break; case 0x12: // Special flags - grf_load_byte(&buf); // TODO + tsp->animation_special_flags = grf_load_byte(&buf); break; default: diff --git a/src/newgrf_callbacks.h b/src/newgrf_callbacks.h index 71475e8a60..d255c9a51d 100644 --- a/src/newgrf_callbacks.h +++ b/src/newgrf_callbacks.h @@ -85,13 +85,13 @@ enum CallbackID { CBID_STATION_TILE_LAYOUT = 0x24, /** Called for periodically starting or stopping the animation. */ - CBID_INDTILE_ANIM_START_STOP = 0x25, // not implemented + CBID_INDTILE_ANIM_START_STOP = 0x25, /** Called to determine industry tile next animation frame. */ - CBID_INDTILE_ANIM_NEXT_FRAME = 0x26, // not implemented + CBID_INDTILE_ANIM_NEXT_FRAME = 0x26, /** Called to indicate how long the current animation frame should last. */ - CBID_INDTILE_ANIMATION_SPEED = 0x27, // not implemented + CBID_INDTILE_ANIMATION_SPEED = 0x27, /** Called to determine if the given industry can be built on specific area. */ CBID_INDUSTRY_LOCATION = 0x28, diff --git a/src/newgrf_industrytiles.cpp b/src/newgrf_industrytiles.cpp index 77993eafa5..f87e4a6d7a 100644 --- a/src/newgrf_industrytiles.cpp +++ b/src/newgrf_industrytiles.cpp @@ -15,6 +15,7 @@ #include "newgrf_spritegroup.h" #include "newgrf_callbacks.h" #include "newgrf_industries.h" +#include "newgrf_industrytiles.h" #include "newgrf_text.h" #include "industry_map.h" #include "clear_map.h" @@ -249,3 +250,104 @@ bool PerformIndustryTileSlopeCheck(TileIndex tile, const IndustryTileSpec *its, default: _error_message = GetGRFStringID(its->grf_prop.grffile->grfid, 0xD000 + callback_res); return false; } } + +void AnimateNewIndustryTile(TileIndex tile) +{ + Industry *ind = GetIndustryByTile(tile); + IndustryGfx gfx = GetIndustryGfx(tile); + const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx); + byte animation_speed = itspec->animation_speed; + + if (HASBIT(itspec->callback_flags, CBM_INDT_ANIM_SPEED)) { + uint16 callback_res = GetIndustryTileCallback(CBID_INDTILE_ANIMATION_SPEED, 0, 0, gfx, ind, tile); + if (callback_res != CALLBACK_FAILED) animation_speed = clamp(callback_res & 0xFF, 0, 16); + } + + /* An animation speed of 2 means the animation frame changes 4 ticks, and + * increasing this value by one doubles the wait. 0 is the minimum value + * allowed for animation_speed, which corresponds to 30ms, and 16 is the + * maximum, corresponding to around 33 minutes. */ + if ((_tick_counter % (1 << animation_speed)) != 0) return; + + bool frame_set_by_callback = false; + byte frame = GetIndustryAnimationState(tile); + uint16 num_frames = GB(itspec->animation_info, 0, 8) + 1; + + if (HASBIT(itspec->callback_flags, CBM_INDT_ANIM_NEXT_FRAME)) { + uint16 callback_res = GetIndustryTileCallback(CBID_INDTILE_ANIM_NEXT_FRAME, HASBIT(itspec->animation_special_flags, 0) ? Random() : 0, 0, gfx, ind, 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 (!frame_set_by_callback) { + if (frame < num_frames) { + frame++; + } else if (frame == num_frames && GB(itspec->animation_info, 8, 8) == 1) { + /* This animation loops, so start again from the beginning */ + frame = 0; + } else { + /* This animation doesn't loop, so stay here */ + DeleteAnimatedTile(tile); + } + } + + SetIndustryAnimationState(tile, frame); + MarkTileDirtyByTile(tile); +} + +static void ChangeIndustryTileAnimationFrame(TileIndex tile, IndustryAnimationTrigger iat, uint32 random_bits, IndustryGfx gfx, Industry *ind) +{ + uint16 callback_res = GetIndustryTileCallback(CBID_INDTILE_ANIM_START_STOP, random_bits, iat, gfx, ind, tile); + if (callback_res == CALLBACK_FAILED) return; + + switch (callback_res & 0xFF) { + case 0xFD: /* Do nothing. */ break; + case 0xFE: AddAnimatedTile(tile); break; + case 0xFF: DeleteAnimatedTile(tile); break; + default: + SetIndustryAnimationState(tile, callback_res & 0xFF); + AddAnimatedTile(tile); + break; + } +} + +bool StartStopIndustryTileAnimation(TileIndex tile, IndustryAnimationTrigger iat, uint32 random) +{ + IndustryGfx gfx = GetIndustryGfx(tile); + const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx); + + if (!HASBIT(itspec->animation_triggers, iat)) return false; + + Industry *ind = GetIndustryByTile(tile); + ChangeIndustryTileAnimationFrame(tile, iat, random, gfx, ind); + return true; +} + +bool StartStopIndustryTileAnimation(const Industry *ind, IndustryAnimationTrigger iat) +{ + bool ret = true; + uint32 random = Random(); + BEGIN_TILE_LOOP(tile, ind->width, ind->height, ind->xy) + if (IsTileType(tile, MP_INDUSTRY) && GetIndustryIndex(tile) == ind->index) { + ret &= StartStopIndustryTileAnimation(tile, iat, random); + SB(random, 0, 16, Random()); + } + END_TILE_LOOP(tile, ind->width, ind->height, ind->xy) + + return ret; +} diff --git a/src/newgrf_industrytiles.h b/src/newgrf_industrytiles.h index 16321217b5..91bfa97fa9 100644 --- a/src/newgrf_industrytiles.h +++ b/src/newgrf_industrytiles.h @@ -5,8 +5,20 @@ #ifndef NEWGRF_INDUSTRYTILES_H #define NEWGRF_INDUSTRYTILES_H +enum IndustryAnimationTrigger { + IAT_CONSTRUCTION_STATE_CHANGE, + IAT_TILELOOP, + IAT_INDUSTRY_TICK, + IAT_INDUSTRY_RECEIVED_CARGO, + IAT_INDUSTRY_DISTRIBUTES_CARGO, +}; + bool DrawNewIndustryTile(TileInfo *ti, Industry *i, IndustryGfx gfx, const IndustryTileSpec *inds); uint16 GetIndustryTileCallback(uint16 callback, uint32 param1, uint32 param2, IndustryGfx gfx_id, Industry *industry, TileIndex tile); bool PerformIndustryTileSlopeCheck(TileIndex tile, const IndustryTileSpec *its, IndustryType type, IndustryGfx gfx); +void AnimateNewIndustryTile(TileIndex tile); +bool StartStopIndustryTileAnimation(TileIndex tile, IndustryAnimationTrigger iat, uint32 random = Random()); +bool StartStopIndustryTileAnimation(const Industry *ind, IndustryAnimationTrigger iat); + #endif /* NEWGRF_INDUSTRYTILES_H */ diff --git a/src/table/build_industry.h b/src/table/build_industry.h index 14ca228e2f..7915754dbf 100644 --- a/src/table/build_industry.h +++ b/src/table/build_industry.h @@ -1532,7 +1532,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { * @param a2 next frame of animation * @param a3 chooses between animation or construction state */ -#define MT(ca1, c1, ca2, c2, ca3, c3, sl, a1, a2, a3) {{c1, c2, c3}, {ca1, ca2, ca3}, sl, a1, a2, a3, 0, true, {0, 0, NULL, NULL, 0}} +#define MT(ca1, c1, ca2, c2, ca3, c3, sl, a1, a2, a3) {{c1, c2, c3}, {ca1, ca2, ca3}, sl, a1, a2, a3, 0, 0xFFFF, 2, 0, 0, true, {0, 0, NULL, NULL, 0}} static const IndustryTileSpec _origin_industry_tile_specs[NEW_INDUSTRYTILEOFFSET] = { /* Coal Mine */ MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false),