* Change industry production or do closure * @param i Industry for which changes are performed * @param monthly true if it's the monthly call, false if it's the random call */
| 2870 | * @param monthly true if it's the monthly call, false if it's the random call |
| 2871 | */ |
| 2872 | static void ChangeIndustryProduction(Industry *i, bool monthly) |
| 2873 | { |
| 2874 | StringID str = STR_NULL; |
| 2875 | bool closeit = false; |
| 2876 | const IndustrySpec *indspec = GetIndustrySpec(i->type); |
| 2877 | bool standard = false; |
| 2878 | bool suppress_message = false; |
| 2879 | bool recalculate_multipliers = false; ///< reinitialize production_rate to match prod_level |
| 2880 | /* use original economy for industries using production related callbacks */ |
| 2881 | bool original_economy = indspec->UsesOriginalEconomy(); |
| 2882 | uint8_t div = 0; |
| 2883 | uint8_t mul = 0; |
| 2884 | int8_t increment = 0; |
| 2885 | |
| 2886 | bool callback_enabled = indspec->callback_mask.Test(monthly ? IndustryCallbackMask::MonthlyProdChange : IndustryCallbackMask::ProductionChange); |
| 2887 | if (callback_enabled) { |
| 2888 | std::array<int32_t, 1> regs100; |
| 2889 | uint16_t res = GetIndustryCallback(monthly ? CBID_INDUSTRY_MONTHLYPROD_CHANGE : CBID_INDUSTRY_PRODUCTION_CHANGE, 0, Random(), i, i->type, i->location.tile, regs100); |
| 2890 | if (res != CALLBACK_FAILED) { // failed callback means "do nothing" |
| 2891 | suppress_message = HasBit(res, 7); |
| 2892 | /* Get the custom message if any */ |
| 2893 | if (HasBit(res, 8)) str = MapGRFStringID(indspec->grf_prop.grfid, GRFStringID(GB(regs100[0], 0, 16))); |
| 2894 | res = GB(res, 0, 4); |
| 2895 | switch (res) { |
| 2896 | default: NOT_REACHED(); |
| 2897 | case 0x0: break; // Do nothing, but show the custom message if any |
| 2898 | case 0x1: div = 1; break; // Halve industry production. If production reaches the quarter of the default, the industry is closed instead. |
| 2899 | case 0x2: mul = 1; break; // Double industry production if it hasn't reached eight times of the original yet. |
| 2900 | case 0x3: closeit = true; break; // The industry announces imminent closure, and is physically removed from the map next month. |
| 2901 | case 0x4: standard = true; break; // Do the standard random production change as if this industry was a primary one. |
| 2902 | case 0x5: case 0x6: case 0x7: // Divide production by 4, 8, 16 |
| 2903 | case 0x8: div = res - 0x3; break; // Divide production by 32 |
| 2904 | case 0x9: case 0xA: case 0xB: // Multiply production by 4, 8, 16 |
| 2905 | case 0xC: mul = res - 0x7; break; // Multiply production by 32 |
| 2906 | case 0xD: // decrement production |
| 2907 | case 0xE: // increment production |
| 2908 | increment = res == 0x0D ? -1 : 1; |
| 2909 | break; |
| 2910 | case 0xF: // Set production to third byte of register 0x100 |
| 2911 | i->prod_level = Clamp(GB(regs100[0], 16, 8), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM); |
| 2912 | recalculate_multipliers = true; |
| 2913 | break; |
| 2914 | } |
| 2915 | } |
| 2916 | } else { |
| 2917 | if (monthly == original_economy) return; |
| 2918 | if (!original_economy && _settings_game.economy.type == ET_FROZEN) return; |
| 2919 | if (indspec->life_type == INDUSTRYLIFE_BLACK_HOLE) return; |
| 2920 | } |
| 2921 | |
| 2922 | if (standard || (!callback_enabled && indspec->life_type.Any({IndustryLifeType::Organic, IndustryLifeType::Extractive}))) { |
| 2923 | /* decrease or increase */ |
| 2924 | bool only_decrease = indspec->behaviour.Test(IndustryBehaviour::DontIncrProd) && _settings_game.game_creation.landscape == LandscapeType::Temperate; |
| 2925 | |
| 2926 | if (original_economy) { |
| 2927 | if (only_decrease || Chance16(1, 3)) { |
| 2928 | /* If more than 60% transported, 66% chance of increase, else 33% chance of increase */ |
| 2929 | if (!only_decrease && (i->GetProduced(0).history[LAST_MONTH].PctTransported() > PERCENT_TRANSPORTED_60) != Chance16(1, 3)) { |
no test coverage detected