diff --git a/src/newgrf.cpp b/src/newgrf.cpp index ad973c8649..68f5b7888e 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -6711,7 +6711,50 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp /* Procedure call or complex adjustment */ if (adjust.operation == DSGA_OP_STO) handle_unpredictable_temp_store(); if (adjust.variable == 0x7E) { - reset_store_values(); + std::bitset<256> seen_stores; + bool seen_unpredictable_store = false; + bool seen_special_store = false; + bool seen_perm_store = false; + auto handle_proc_stores = y_combinator([&](auto handle_proc_stores, const SpriteGroup *sg) -> void { + if (sg == nullptr) return; + if (sg->type == SGT_RANDOMIZED) { + const RandomizedSpriteGroup *rsg = (const RandomizedSpriteGroup*)sg; + for (const auto &group : rsg->groups) { + handle_proc_stores(group); + } + } else if (sg->type == SGT_DETERMINISTIC) { + const DeterministicSpriteGroup *dsg = (const DeterministicSpriteGroup*)sg; + for (const DeterministicSpriteGroupAdjust &adjust : dsg->adjusts) { + if (adjust.variable == 0x7E) { + handle_proc_stores(adjust.subroutine); + } + if (adjust.operation == DSGA_OP_STO) { + if (adjust.type == DSGA_TYPE_NONE && adjust.variable == 0x1A && adjust.shift_num == 0) { + /* Temp store */ + if (adjust.and_mask < 0x100) { + seen_stores.set(adjust.and_mask, true); + } else { + seen_special_store = true; + } + } else { + /* Unpredictable store */ + seen_unpredictable_store = true; + } + } + if (adjust.operation == DSGA_OP_STO_NC) { + if (adjust.divmod_val < 0x100) { + seen_stores.set(adjust.divmod_val, true); + } else { + seen_special_store = true; + } + } + if (adjust.operation == DSGA_OP_STOP) { + seen_perm_store = true; + } + } + } + }); + auto handle_group = y_combinator([&](auto handle_group, const SpriteGroup *sg) -> void { if (sg == nullptr) return; if (sg->type == SGT_RANDOMIZED) { @@ -6731,9 +6774,35 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp if (!state.seen_procedure_call && ((const DeterministicSpriteGroup*)sg)->dsg_flags & DSGF_REQUIRES_VAR1C) { group->dsg_flags |= DSGF_REQUIRES_VAR1C; } + handle_proc_stores(sg); } }); handle_group(adjust.subroutine); + + if (seen_unpredictable_store) { + reset_store_values(); + } else { + for (auto &it : state.temp_stores) { + if (seen_stores[it.first]) { + it.second.inference = VA2AIF_NONE; + it.second.version++; + } else { + /* See DSGA_OP_STO handler */ + if ((it.second.inference & VA2AIF_SINGLE_LOAD) && it.second.var_source.variable == 0x7D && seen_stores[it.second.var_source.parameter & 0xFF]) { + it.second.inference &= ~VA2AIF_SINGLE_LOAD; + } + if (seen_special_store && (it.second.inference & VA2AIF_SINGLE_LOAD) && it.second.var_source.variable != 0x7D) { + it.second.inference &= ~VA2AIF_SINGLE_LOAD; + } + + /* See DSGA_OP_STOP handler */ + if (seen_perm_store && (it.second.inference & VA2AIF_SINGLE_LOAD) && it.second.var_source.variable == 0x7C) { + it.second.inference &= ~VA2AIF_SINGLE_LOAD; + } + } + } + } + state.seen_procedure_call = true; } else if (adjust.operation == DSGA_OP_RST) { state.inference = VA2AIF_SINGLE_LOAD;