import buildings; from buildings import IBuildingHook; import resources; import util.formatting; import systems; import saving; from statuses import IStatusHook, Status, StatusInstance; from resources import integerSum, decimalSum; import planet_types; import planet_levels; import generic_effects; import hook_globals; //AddPressureCap() // Give extra pressure cap on the planet. class AddPressureCap : GenericEffect, TriggerableGeneric { Document doc("Increase the planet's total pressure capacity."); Argument amount(AT_Integer, doc="Amount of pressure capacity to add."); bool get_hasEffect() const override { return true; } string formatEffect(Object& obj, array& hooks) const override { return formatPosEffect(locale::EFFECT_ADDPRESSURECAP, "+"+integerSum(hooks, 0)); } #section server void enable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modPressureCapMod(+arguments[0].integer); } void disable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modPressureCapMod(-arguments[0].integer); } #section all }; //ModPressureCapMult() // Give extra base pressure cap on the planet. class ModPressureCapMult : GenericEffect, TriggerableGeneric { Document doc("Add to the planet's pressure cap multiplier."); Argument amount(AT_Decimal, doc="Percentage increase to pressure cap. eg. 0.3 for +30% pressure cap."); #section server void enable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modPressureCapFactor(+arguments[0].decimal); } void disable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modPressureCapFactor(-arguments[0].decimal); } #section all }; //ModCivResourceMult(, ) // Add to the civilian multiplier. class ModCivResourceMult : GenericEffect, TriggerableGeneric { Document doc("Increase the civilian resource production multiplier for a particular type of income."); Argument type(AT_TileResource, doc="Which income to modify the multiplier for."); Argument amount(AT_Decimal, doc="Percentage increase to the income multiplier. eg. 0.15 for +15% income."); bool get_hasEffect() const override { return true; } bool mergesEffect(const GenericEffect@ eff) const { return eff.arguments[0].integer == arguments[0].integer; } string formatEffect(Object& obj, array& hooks) const override { return formatPctEffect(format(locale::EFFECT_MODCIVRESOURCE, getTileResourceName(arguments[0].integer)), decimalSum(hooks, 1)); } #section server void enable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modCivResourceMod(arguments[0].integer, +arguments[1].decimal); } void disable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modCivResourceMod(arguments[0].integer, -arguments[1].decimal); } #section all }; //ModTerraformCost() // Modify the cost to terraform things *with* this planet by . class ModTerraformCost : GenericEffect, TriggerableGeneric { Document doc("Increase the terraform cost multiplier for terraforming other planets with this object."); Argument amount(AT_Decimal, doc="Percentage increase to the terraform cost multiplier. eg. -0.5 for -50% terraform cost."); #section server void enable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modTerraformCostMod(+arguments[0].decimal); } void disable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modTerraformCostMod(-arguments[0].decimal); } #section all }; //ModPopulationGrowth() // Modify the population growth rate by an amount. class ModPopulationGrowth : GenericEffect, TriggerableGeneric { Document doc("Increase the population growth multiplier on this planet."); Argument amount(AT_Decimal, doc="Percentage increase to the population growth multiplier. eg. 0.1 for +10% population growth."); #section server void enable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modGrowthRate(+arguments[0].decimal); } void disable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modGrowthRate(-arguments[0].decimal); } #section all }; //ModTileDevelopRate() // Modify the tile development rate by an amount. class ModTileDevelopRate : GenericEffect, TriggerableGeneric { Document doc("Increase the tile development rate multiplier on this planet."); Argument amount(AT_Decimal, doc="Percentage increase to the tile development rate multiplier. eg. 0.25 for +25% tile development speed."); #section server void enable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modTileDevelopRate(+arguments[0].decimal); } void disable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modTileDevelopRate(-arguments[0].decimal); } #section all }; //ModBuildingConstructRate() // Modify the building construction rate by an amount. class ModBuildingConstructRate : GenericEffect, TriggerableGeneric { Document doc("Increase the building construction speed multiplier on this planet."); Argument amount(AT_Decimal, doc="Percentage increase to the builing construction speed multiplier. eg. 0.25 for +25% building construction speed."); #section server void enable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modBuildingConstructRate(+arguments[0].decimal); } void disable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modBuildingConstructRate(-arguments[0].decimal); } #section all }; //AddBuildingMaintenanceRefund() // Reduces the total maintenance of buildings by a flat . class AddBuildingMaintenanceRefund : GenericEffect, TriggerableGeneric { Document doc("Decrease the total maintenance cost of buildings on this planet by a static amount."); Argument amount(AT_Integer, doc="Amount of money to decrease the total maintenance cost by."); bool get_hasEffect() const override { return true; } string formatEffect(Object& obj, array& hooks) const override { int totalReduction = integerSum(hooks, 0); int remaining = 0; if(obj.isPlanet && obj.owner is playerEmpire) remaining = obj.buildingMaintenance; string eff; if(totalReduction > 10000000) { if(remaining == 0) eff = "-"+formatMoney(0); else eff = "-"+formatMoney(totalReduction + remaining); } else { if(remaining < 0) { int used = totalReduction + remaining; if(used != 0) { eff = format("-$1 [color=#fe4]($2)[/color]", formatMoney(used), formatMoney(-remaining)); } else { eff = format("[color=#fe4]($1)[/color]", formatMoney(-remaining)); } } else eff = "-"+formatMoney(totalReduction); } return formatPosEffect(locale::EFFECT_BLDMAINTREFUND, eff); } #section server void enable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modBuildingMaintenanceRefund(+arguments[0].integer); } void disable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modBuildingMaintenanceRefund(-arguments[0].integer); } #section all }; //AddResourceVanishBonus() // Increases the amount of time temporary resources have on this planet by . class AddResourceVanishBonus : GenericEffect, TriggerableGeneric { Document doc("Increases the amount of time temporary resources consumed by this planet stay active."); Argument amount(AT_Decimal, doc="Percentage increase to the temporary resource time. eg. 0.4 for +40% resource time."); bool get_hasEffect() const override { return true; } string formatEffect(Object& obj, array& hooks) const override { return formatPctEffect(locale::EFFECT_VANISHBONUS, decimalSum(hooks, 0), locale::MOD_TIME); } #section server void enable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modResourceVanishBonus(+arguments[0].decimal); } void disable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modResourceVanishBonus(-arguments[0].decimal); } #section all }; //GiveNativePressure() // Give the consuming planet extra pressure in its native resource's type class GiveNativePressure : GenericEffect { Document doc("Give the consuming planet extra pressure of the primary type of pressure its native resource gives."); Argument amount(AT_Integer, doc="Amount of extra pressure to give."); Argument allow_money(AT_Boolean, "True", doc="Whether to allow giving extra money pressure."); #section server void enable(Object& obj, any@ data) const override { if(obj.nativeResourceCount > 0) { const ResourceType@ res = getResource(obj.nativeResourceType[0]); if(res !is null) { int64 resource = -1; int best = 0; for(uint i = allow_money.boolean ? 0 : 1; i < TR_COUNT; ++i) { if(res.tilePressure[i] > best) { best = res.tilePressure[i]; resource = int(i); } } if(resource != -1) obj.modPressure(uint(resource), +arguments[0].integer); data.store(resource); } } } void disable(Object& obj, any@ data) const override { int64 reso = -1; data.retrieve(reso); if(reso != -1) obj.modPressure(uint(reso), -arguments[0].integer); } void save(any@ data, SaveFile& file) const override { int64 reso = -1; data.retrieve(reso); file << reso; } void load(any@ data, SaveFile& file) const override { int64 reso = -1; file >> reso; data.store(reso); } #section all }; class GiveNativeProduction : GenericEffect { Document doc("Give the consuming planet extra production of the primary type of pressure its native resource gives."); Argument amount(AT_Integer, doc="Amount of extra production to give."); Argument allow_money(AT_Boolean, "True", doc="Whether to allow giving extra money pressure."); #section server void enable(Object& obj, any@ data) const override { if(obj.nativeResourceCount > 0) { const ResourceType@ res = getResource(obj.nativeResourceType[0]); if(res !is null) { int64 resource = -1; int best = 0; for(uint i = allow_money.boolean ? 0 : 1; i < TR_COUNT; ++i) { if(res.tilePressure[i] > best) { best = res.tilePressure[i]; resource = int(i); } } if(resource != -1) obj.modResource(uint(resource), +arguments[0].integer); data.store(resource); } } } void disable(Object& obj, any@ data) const override { int64 reso = -1; data.retrieve(reso); if(reso != -1) obj.modResource(uint(reso), -arguments[0].integer); } void save(any@ data, SaveFile& file) const override { int64 reso = -1; data.retrieve(reso); file << reso; } void load(any@ data, SaveFile& file) const override { int64 reso = -1; file >> reso; data.store(reso); } #section all }; //GiveResourcePressure(, , = -1) // Give the consuming planet extra pressure on all its resources. class GiveExtraResourcePressure : GenericEffect { Document doc("Multiply the pressure each of resources consumed by the planet gives of a particular type."); Argument type(AT_TileResource, doc="Type of pressure to multiply."); Argument factor(AT_Decimal, doc="Percentage increase to the pressure given. eg. 0.2 for a +20% increase in pressure."); Argument level_filter(AT_Integer, "-1", doc="If not -1, only resources of the indicated level receive bonus pressure."); Argument allow_uniques(AT_Boolean, "True", doc="If set to false, unique resources will not be boosted by this."); #section server void enable(Object& obj, any@ data) const override { int reso = 0; data.store(reso); } void tick(Object& obj, any@ data, double time) const override { int current = 0; data.retrieve(current); double newValue = 0; int resType = arguments[0].integer; double factor = arguments[1].decimal; int level = arguments[2].integer; for(uint i = 0, cnt = obj.availableResourceCount; i < cnt; ++i) { if(!obj.availableResourceUsable[i]) continue; auto@ type = getResource(obj.availableResourceType[i]); if(type is null) continue; if(level != -1 && level != int(type.level)) continue; if(!allow_uniques.boolean && (type.unique || type.rarity == RR_Unique)) continue; newValue += double(type.tilePressure[resType]) * factor; } int nextValue = int(newValue); if(current != nextValue) { obj.modPressure(resType, nextValue - current); data.store(nextValue); } } void disable(Object& obj, any@ data) const override { int reso = -1; data.retrieve(reso); if(reso > 0) obj.modPressure(arguments[0].integer, -reso); } void save(any@ data, SaveFile& file) const override { int reso = -1; data.retrieve(reso); file << reso; } void load(any@ data, SaveFile& file) const override { int reso = -1; file >> reso; data.store(reso); } #section all }; class AddPressurePerAffinity : GenericEffect { Document doc("For every affinity of a particular type, add an amount of pressure."); Argument affinity_type(AT_TileResource, doc="Affinity type to check for."); Argument pressure_type(AT_TileResource, doc="Type of pressure to generate."); Argument amount(AT_Decimal, "1", doc="Amount of pressure to add per affinity."); #section server void enable(Object& obj, any@ data) const override { int amt = 0; data.store(amt); } void disable(Object& obj, any@ data) const override { if(obj.hasSurfaceComponent) { int amt = 0; data.retrieve(amt); if(amt != 0) obj.modPressure(pressure_type.integer, -amt); } } void tick(Object& obj, any@ data, double tick) const override { if(obj.hasSurfaceComponent) { int amt = 0; data.retrieve(amt); int newAmt = double(obj.getAffinitiesMatching(affinity_type.integer)) * amount.decimal; if(amt != newAmt) { obj.modPressure(pressure_type.integer, newAmt - amt); data.store(newAmt); } } } void save(any@ data, SaveFile& file) const override { int amt = 0; data.retrieve(amt); file << amt; } void load(any@ data, SaveFile& file) const override { int amt = 0; file >> amt; data.store(amt); } #section all }; //ModColonyShipAccel() // Colony ships leaving the consuming planet accelerate faster. class ModColonyShipAccel : GenericEffect, TriggerableGeneric { Document doc("Multiply the acceleration of outgoing colony ships from this planet by a factor."); Argument multiplier(AT_Decimal, "1.0", doc="Multiplier to the acceleration."); bool get_hasEffect() const override { return true; } string formatEffect(Object& obj, array& hooks) const override { return formatPctEffect(locale::PEKELM_EFFECT, decimalSum(hooks, 0)); } #section server void enable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modColonyShipAccel(arguments[0].decimal); } void disable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modColonyShipAccel(1.0/arguments[0].decimal); } #section all }; //ModLoyalty() // Add extra loyalty to the consuming planet. class ModLoyalty : GenericEffect, TriggerableGeneric { Document doc("Increase the loyalty of this planet."); Argument amount(AT_Integer, doc="Amount of extra loyalty to give."); bool get_hasEffect() const override { return true; } string formatEffect(Object& obj, array& hooks) const override { return formatPosEffect(locale::SPICE_EFFECT, "+"+integerSum(hooks, 0)); } #section server void enable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modBaseLoyalty(+arguments[0].integer); } void disable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modBaseLoyalty(-arguments[0].integer); } #section all }; //AddPressure(, ) // Adds pressure. class AddPressure : GenericEffect, TriggerableGeneric { Document doc("Add extra pressure to this planet."); Argument type(AT_TileResource, doc="Type of pressure to give."); Argument amount(AT_Integer, doc="Amount of pressure."); bool get_hasEffect() const override { return true; } bool mergesEffect(const GenericEffect@ eff) const override { return eff.arguments[0].integer == arguments[0].integer; } string formatEffect(Object& obj, array& hooks) const override { return formatPosEffect(format(locale::EFFECT_ADDPRESSURE, getTileResourceName(arguments[0].integer)), "+"+integerSum(hooks, 1)); } #section server void enable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modPressure(arguments[0].integer, +arguments[1].integer); } void disable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modPressure(arguments[0].integer, -arguments[1].integer); } #section all }; //AddResource(, ) // Add the equivalent of pressure in production. class AddResource : GenericEffect, TriggerableGeneric { Document doc("Add free resource production equivalent to an amount of pressure to this planet."); Argument type(AT_TileResource, doc="Type of resource income."); Argument amount(AT_Decimal, doc="Amount of pressure to give the equivalent resource production for."); bool get_hasEffect() const override { return true; } bool mergesEffect(const GenericEffect@ eff) const override { return eff.arguments[0].integer == arguments[0].integer; } string formatEffect(Object& obj, array& hooks) const override { return formatPosEffect(format(locale::EFFECT_ADDRESOURCE, getTileResourceName(arguments[0].integer)), "+"+integerSum(hooks, 1)); } #section server void enable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modResource(arguments[0].integer, +arguments[1].decimal); } void disable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modResource(arguments[0].integer, -arguments[1].decimal); } #section all }; class AddIncome : GenericEffect, TriggerableGeneric { Document doc("Change the planet's income by an amount."); Argument amount(AT_Integer, doc="Amount of income to change the planet's income by."); #section server void enable(Object& obj, any@ data) const override { if(obj.hasSurfaceComponent) obj.modIncome(+amount.integer); } void disable(Object& obj, any@ data) const override { if(obj.hasSurfaceComponent) obj.modIncome(-amount.integer); } #section all }; //AddResourceEmpireAttribute(, ) // Add resource production from an empire attribute. class AddResourceEmpireAttribute : GenericEffect { Document doc("Add free resource production based on an equivalent amount of pressure stored in an empire attribute."); Argument type(AT_TileResource, doc="Type of resource income."); Argument attribute(AT_EmpAttribute, doc="Empire attribute to take the amount of income from, can be set to any arbitrary name to be created as a new attribute with starting value 0."); Argument multiplier(AT_Decimal, "1.0", doc="Multiplier to amount of resource to generate."); #section server void enable(Object& obj, any@ data) const override { double value = 0; data.store(value); } void tick(Object& obj, any@ data, double time) const override { double value = 0; data.retrieve(value); Empire@ owner = obj.owner; double newValue = 0; if(owner !is null) newValue = owner.getAttribute(arguments[1].integer) * multiplier.decimal; if(newValue != value) { obj.modResource(arguments[0].integer, newValue - value); data.store(newValue); } } void disable(Object& obj, any@ data) const override { double value = 0; data.retrieve(value); if(obj.isPlanet) obj.modResource(arguments[0].integer, -value); } void save(any@ data, SaveFile& file) const override { double amt = 0; data.retrieve(amt); file << amt; } void load(any@ data, SaveFile& file) const override { double amt = 0; file >> amt; data.store(amt); } #section all }; class AddPressureEmpireAttribute : GenericEffect { Document doc("Add pressure based on an empire attribute."); Argument type(AT_TileResource, doc="Type of resource to add pressure for."); Argument attribute(AT_EmpAttribute, doc="Empire attribute to take the amount of income from, can be set to any arbitrary name to be created as a new attribute with starting value 0."); Argument multiplier(AT_Decimal, "1.0", doc="Multiplier to amount of resource to generate."); #section server void enable(Object& obj, any@ data) const override { int value = 0; data.store(value); } void tick(Object& obj, any@ data, double time) const override { double value = 0; data.retrieve(value); Empire@ owner = obj.owner; int newValue = 0; if(owner !is null) newValue = int(floor(owner.getAttribute(attribute.integer) * multiplier.decimal)); if(newValue != value) { obj.modPressure(type.integer, newValue - value); data.store(newValue); } } void disable(Object& obj, any@ data) const override { int value = 0; data.retrieve(value); if(obj.isPlanet) obj.modPressure(type.integer, -value); } void save(any@ data, SaveFile& file) const override { int amt = 0; data.retrieve(amt); file << amt; } void load(any@ data, SaveFile& file) const override { int amt = 0; file >> amt; data.store(amt); } #section all }; //AddResourceFromGlobal(, , = 1.0) // Add resource production from an empire attribute. class AddResourceFromGlobal : GenericEffect { Document doc("Add free resource production based on an equivalent amount of pressure stored in a global value."); Argument type(AT_TileResource, doc="Type of resource income."); Argument global(AT_Global, doc="Global variable to take value from."); Argument factor(AT_Decimal, "1.0", doc="Multiplication factor to the global's value to give in pressure-equivalent income."); #section server void enable(Object& obj, any@ data) const override { double value = 0; data.store(value); } void tick(Object& obj, any@ data, double time) const override { double value = 0; data.retrieve(value); double newValue = getGlobal(arguments[1].integer).value * arguments[2].decimal; if(newValue != value) { obj.modResource(arguments[0].integer, newValue - value); data.store(newValue); } } void disable(Object& obj, any@ data) const override { double value = 0; data.retrieve(value); if(obj.isPlanet) obj.modResource(arguments[0].integer, -value); } void save(any@ data, SaveFile& file) const override { double amt = 0; data.retrieve(amt); file << amt; } void load(any@ data, SaveFile& file) const override { double amt = 0; file >> amt; data.store(amt); } #section all }; //AddResourceFromLevel(, = 0.0, = 1.0) // Add resource production related to the planet level. class AddResourceFromLevel : GenericEffect { Document doc("Add free resource production based on the planet's level."); Argument type(AT_TileResource, doc="Type of resource income."); Argument base(AT_Decimal, "0.0", doc="Base amount of pressure-equilavent income to give."); Argument factor(AT_Decimal, "1.0", doc="Multiplication factor to the planet's level to give in pressure-equivalent income."); #section server void enable(Object& obj, any@ data) const override { double value = 0; data.store(value); } void tick(Object& obj, any@ data, double time) const override { double value = 0; data.retrieve(value); double newValue = arguments[1].decimal + arguments[2].decimal * obj.level; if(newValue != value) { obj.modResource(arguments[0].integer, newValue - value); data.store(newValue); } } void disable(Object& obj, any@ data) const override { double value = 0; data.retrieve(value); if(obj.isPlanet) obj.modResource(arguments[0].integer, -value); } void save(any@ data, SaveFile& file) const override { double amt = 0; data.retrieve(amt); file << amt; } void load(any@ data, SaveFile& file) const override { double amt = 0; file >> amt; data.store(amt); } #section all }; //AddMaxPopulation() // Add maximum population to the planet. class AddMaxPopulation : GenericEffect, TriggerableGeneric { Document doc("Increase the planet's maximum population."); Argument amount(AT_Integer, doc="Amount of extra maximum population."); #section server void enable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modMaxPopulation(arguments[0].integer); } void disable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modMaxPopulation(-arguments[0].integer); } #section all }; //AddOverpopulation() // Add overpopulation to the planet. class AddOverpopulation : GenericEffect, TriggerableGeneric { Document doc("Increase the planet's overpopulation."); Argument amount(AT_Integer, doc="Amount of extra overpopulation."); bool get_hasEffect() const override { return true; } string formatEffect(Object& obj, array& hooks) const override { return formatPosEffect(locale::EFFECT_OVERPOPULATION, toString(integerSum(hooks, 0))); } #section server void enable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modOverpopulation(+arguments[0].integer); } void disable(Object& obj, any@ data) const override { if(obj.isPlanet) obj.modOverpopulation(-arguments[0].integer); } #section all }; //PerResourceAddResource(, , ) // Adds generation equivalent to pressure for every // available on the planet. class PerResourceAddResource : GenericEffect { Document doc("Add free resource income for every planetary resource of a particular type being consumed on the planet."); Argument resource(AT_PlanetResource, doc="Type of planetary resource to count."); Argument factor(AT_Decimal, doc="Multiplier to the amount of planetary resources to give in pressure-equivalent income."); Argument income(AT_TileResource, doc="Type of income to generate."); bool get_hasEffect() const override { return true; } bool mergesEffect(const GenericEffect@ eff) const override { return eff.arguments[0].integer == arguments[0].integer && arguments[2].integer == arguments[2].integer; } string formatEffect(Object& obj, array& hooks) const override { return formatPosEffect(format(locale::EFFECT_ADDRESOURCE, getTileResourceName(arguments[2].integer)), "+"+(decimalSum(hooks, 1) * obj.getAvailableResourceAmount(arguments[0].integer))); } #section server void tick(Object& obj, any@ data, double time) const override { if(obj.isPlanet) { int64 prev = 0; data.retrieve(prev); int64 resCnt = obj.getAvailableResourceAmount(arguments[0].integer); if(resCnt != prev) { data.store(resCnt); obj.modResource(arguments[2].integer, double(resCnt - prev) * arguments[1].decimal); } } } void enable(Object& obj, any@ data) const override { int64 amt = 0; data.store(amt); } void disable(Object& obj, any@ data) const override { int64 amt = 0; data.retrieve(amt); obj.modResource(arguments[2].integer, -double(amt) * arguments[1].decimal); amt = 0; data.store(amt); } void save(any@ data, SaveFile& file) const { int64 amt = 0; data.retrieve(amt); file << int(amt); } void load(any@ data, SaveFile& file) const { int amt = 0; file >> amt; data.store(int64(amt)); } #section all }; //ModExistingResource(, ) // Adds generation equivalent to pressure // if the resource is being produced at all. Resources cannot drop below 0. class ModExistingResource : GenericEffect { Document doc("Modify a particular type of income on this planet, but only if that income is non-zero to begin with."); Argument income(AT_TileResource, doc="Type of income to modify."); Argument amount(AT_Decimal, doc="Amount of pressure-equivalent income to add or subtract."); #section server void tick(Object& obj, any@ data, double time) const override { if(obj.isPlanet) { double cur = 0; data.retrieve(cur); double production = obj.getResourceProduction(arguments[0].integer); double next = 0; double mod = arguments[1].decimal; double net = production - cur; if(mod > 0) { if(net > 0) next = mod; else next = 0; } else { if(net >= 0) next = max(-net, mod); else next = 0; } if(next != cur) { obj.modResource(arguments[0].integer, next - cur); data.store(next); } } } void enable(Object& obj, any@ data) const override { double amt = 0; data.store(amt); } void disable(Object& obj, any@ data) const override { double amt = 0; data.retrieve(amt); if(obj.isPlanet) obj.modResource(arguments[0].integer, -amt); amt = 0; data.store(amt); } void save(any@ data, SaveFile& file) const { double amt = 0; data.retrieve(amt); file << amt; } void load(any@ data, SaveFile& file) const { double amt = 0; file >> amt; data.store(amt); } #section all }; class ModExistingPressure : GenericEffect { Document doc("Modify a particular type of pressure on this planet, but only if that pressure is non-zero to begin with."); Argument income(AT_TileResource, doc="Type of pressure to modify."); Argument amount(AT_Decimal, doc="Amount of pressure to add or subtract."); #section server void tick(Object& obj, any@ data, double time) const override { if(obj.isPlanet) { double cur = 0; data.retrieve(cur); double production = obj.getResourcePressure(arguments[0].integer); double next = 0; double mod = arguments[1].decimal; double net = production - cur; if(mod > 0) { if(net > 0) next = mod; else next = 0; } else { if(net >= 0) next = max(-net, mod); else next = 0; } if(next != cur) { obj.modPressure(arguments[0].integer, next - cur); data.store(next); } } } void enable(Object& obj, any@ data) const override { double amt = 0; data.store(amt); } void disable(Object& obj, any@ data) const override { double amt = 0; data.retrieve(amt); if(obj.isPlanet) obj.modPressure(arguments[0].integer, -amt); amt = 0; data.store(amt); } void save(any@ data, SaveFile& file) const { double amt = 0; data.retrieve(amt); file << amt; } void load(any@ data, SaveFile& file) const { double amt = 0; file >> amt; data.store(amt); } #section all }; class ModPressurePct : GenericEffect { Document doc("Modify the amount of pressure on the planet of a type by a percentage."); Argument income(AT_TileResource, doc="Type of pressure to modify."); Argument amount(AT_Decimal, doc="Percentage of pressure to add or subtract."); Argument min_amount(AT_Integer, "0", doc="Minimum change to pressure."); #section server void tick(Object& obj, any@ data, double time) const override { if(obj.isPlanet) { double cur = 0; data.retrieve(cur); double production = obj.getResourcePressure(income.integer); double net = production - cur; double next = 0; double mod = round((production - cur) * amount.decimal); if(min_amount.integer < 0 && net != 0) mod = min(double(min_amount.integer), mod); else if(min_amount.integer > 0 && net != 0) mod = max(double(min_amount.integer), mod); if(mod > 0) { if(net > 0) next = mod; else next = 0; } else { if(net >= 0) next = max(-net, mod); else next = 0; } if(next != cur) { obj.modPressure(income.integer, next - cur); data.store(next); } } } void enable(Object& obj, any@ data) const override { double amt = 0; data.store(amt); } void disable(Object& obj, any@ data) const override { double amt = 0; data.retrieve(amt); if(obj.isPlanet) obj.modPressure(income.integer, -amt); amt = 0; data.store(amt); } void save(any@ data, SaveFile& file) const { double amt = 0; data.retrieve(amt); file << amt; } void load(any@ data, SaveFile& file) const { double amt = 0; file >> amt; data.store(amt); } #section all }; //PerIncomeAddResource(, , ) // Adds generation equivalent to pressure for every // being generated on the planet. class PerIncomeAddResource : GenericEffect { Document doc("Add free resource income for every resource income of a particular type being generated on this planet."); Argument resource(AT_TileResource, doc="Type of income resource to count."); Argument factor(AT_Decimal, doc="Multiplier to the amount of income resource already generated to give in pressure-equivalent income."); Argument income(AT_TileResource, doc="Type of income to generate."); #section server void enable(Object& obj, any@ data) const override { double amt = 0.0; data.store(amt); } void disable(Object& obj, any@ data) const override { if(obj.isPlanet) { double amt = 0.0; data.retrieve(amt); if(amt != 0.0) obj.modResource(arguments[2].integer, -amt); } } void tick(Object& obj, any@ data, double tick) const override { if(obj.isPlanet) { double amt = 0.0; data.retrieve(amt); double newAmt = obj.getResourceProduction(arguments[0].integer) * arguments[1].decimal; if(amt != newAmt) { obj.modResource(arguments[2].integer, newAmt - amt); data.store(newAmt); } } } void save(any@ data, SaveFile& file) const override { double amt = 0.0; data.retrieve(amt); file << amt; } void load(any@ data, SaveFile& file) const override { double amt = 0.0; file >> amt; data.store(amt); } #section all }; //PerPopulationAddResource(, ) // Adds generation equivalent to pressure for every // population on the planet. class PerPopulationAddResource : GenericEffect { Document doc("Add free resource income based on the planet's current population."); Argument factor(AT_Decimal, doc="Multiplier to the planet's current population to give in pressure-equivalent income."); Argument income(AT_TileResource, doc="Type of income to generate."); Argument overpop_factor(AT_Boolean, "True", doc="Whether to account for the race's OverpopulationBenefitFactor for overpopulation."); Argument ignore_first(AT_Decimal, "0", doc="Ignore this amount of population before adding for the remaining population."); bool get_hasEffect() const override { return true; } bool mergesEffect(const GenericEffect@ eff) const override { return eff.arguments[1].integer == arguments[1].integer; } string formatEffect(Object& obj, array& hooks) const override { if(arguments[0].integer == TR_Money) return formatPosEffect(format(locale::EFFECT_ADDRESOURCE, getTileResourceName(arguments[0].integer)), "+"+formatMoney(decimalSum(hooks, 1) * obj.population * 100.0)); else return formatMagEffect(format(locale::EFFECT_ADDRESOURCE, getTileResourceName(arguments[0].integer)), (decimalSum(hooks, 1) * obj.population)); } #section server void enable(Object& obj, any@ data) const override { double amt = 0.0; data.store(amt); } void disable(Object& obj, any@ data) const override { if(obj.isPlanet) { double amt = 0.0; data.retrieve(amt); if(amt != 0.0) obj.modResource(arguments[1].integer, -amt); } } void tick(Object& obj, any@ data, double tick) const override { if(obj.isPlanet) { double amt = 0.0; data.retrieve(amt); double pop = max(obj.population - ignore_first.decimal, 0.0); double newAmt = pop * arguments[0].decimal; if(overpop_factor.boolean) { double maxPop = obj.maxPopulation; if(pop > maxPop) newAmt = (maxPop + (pop - maxPop) * obj.owner.OverpopulationBenefitFactor) * arguments[0].decimal; } if(amt != newAmt) { obj.modResource(arguments[1].integer, newAmt - amt); data.store(newAmt); } } } void save(any@ data, SaveFile& file) const override { double amt = 0.0; data.retrieve(amt); file << amt; } void load(any@ data, SaveFile& file) const override { double amt = 0.0; file >> amt; data.store(amt); } #section all }; //AddDummyResource(, ) // Add s solely for the purpose of requirement resolution. class AddDummyResource : GenericEffect, TriggerableGeneric { Document doc("Add a dummy resource of a particular type. Dummy resources are not listed and have no effects except for being usable for planet levelup."); Argument resource(AT_PlanetResource, doc="Type of planetary resource to add a dummy of."); Argument amount(AT_Integer, "1", doc="Amount of dummy resources of that type to add."); Argument base_chain_only(AT_Boolean, "False", doc="Only add this dummy resource if the planet is using the base levelup chain."); #section server void enable(Object& obj, any@ data) const override { if(!base_chain_only.boolean || obj.levelChain == baseLevelChain.id) obj.modDummyResource(arguments[0].integer, +arguments[1].integer, true); } void disable(Object& obj, any@ data) const override { if(!base_chain_only.boolean || obj.levelChain == baseLevelChain.id) obj.modDummyResource(arguments[0].integer, -arguments[1].integer, true); } #section all }; //ConvertToFTL(, ) // Convert all income into FTL income at . class ConvertToFTL : GenericEffect { Document doc("Convert all income of a particular type to FTL generation."); Argument type(AT_TileResource, doc="Type of income to convert."); Argument factor(AT_Decimal, doc="Every pressure-equivalent income of the given type is converted to this much FTL per second."); #section server void enable(Object& obj, any@ data) const override { double current = 0.0; data.store(current); obj.modCivResourceMod(arguments[0].integer, -1.f); } void disable(Object& obj, any@ data) const override { double current = 0.0; data.retrieve(current); if(current > 0) { if(obj.owner !is null && obj.owner.valid) obj.owner.modFTLIncome(-current); } obj.modCivResourceMod(arguments[0].integer, +1.f); } void ownerChange(Object& obj, any@ data, Empire@ prevOwner, Empire@ newOwner) const override { double current = 0.0; data.retrieve(current); if(current > 0) { if(prevOwner !is null && prevOwner.valid) prevOwner.modFTLIncome(-current); if(newOwner !is null && newOwner.valid) newOwner.modFTLIncome(+current); } } void tick(Object& obj, any@ data, double time) const override { double newIncome = obj.getCivilianProduction(arguments[0].integer) * arguments[1].decimal; double current = 0.0; data.retrieve(current); if(current != newIncome) { obj.owner.modFTLIncome(newIncome - current); current = newIncome; data.store(current); } } void save(any@ data, SaveFile& file) const override { double current = 0.0; data.retrieve(current); file << current; } void load(any@ data, SaveFile& file) const override { double current = 0.0; file >> current; data.store(current); } #section all }; //ConvertResource(, , ) // Convert all civilian income into income at . tidy final class ConvertData { double taken = 0.0; double given = 0.0; }; class ConvertResource : GenericEffect { Document doc("Convert all civilian income of a particular type to income of a different type."); Argument resource(AT_TileResource, doc="Type of income resource to convert."); Argument factor(AT_Decimal, doc="Multiplier to the amount of income taken away."); Argument income(AT_TileResource, doc="Type of income to generate, after multiplication."); Argument maximum_converted(AT_Decimal, "-1", doc="Maximum amount of resource of the first type that is converted."); Argument convert_percent(AT_Decimal, "1", doc="Percentage of the original resource to be converted. The rest is left alone."); #section server void enable(Object& obj, any@ data) const override { ConvertData info; data.store(@info); } void disable(Object& obj, any@ data) const override { ConvertData@ info; data.retrieve(@info); if(info.given > 0) obj.modResource(income.integer, -info.given); if(info.taken > 0) obj.modResource(resource.integer, +info.taken); } void tick(Object& obj, any@ data, double time) const override { ConvertData@ info; data.retrieve(@info); //Check rate double curProd = obj.getResourceProduction(resource.integer); double total = info.taken + curProd; double target = total - (total * (1.0 - convert_percent.decimal)); target = clamp(target, 0.0, total); double newTaken = total - target; if(maximum_converted.decimal >= 0) newTaken = min(newTaken, maximum_converted.decimal); if(newTaken != info.taken) { obj.modResource(resource.integer, -(newTaken - info.taken)); info.taken = newTaken; } double newGiven = newTaken * factor.decimal; if(newGiven != info.given) { obj.modResource(income.integer, newGiven - info.given); info.given = newGiven; } } void save(any@ data, SaveFile& file) const override { ConvertData@ info; data.retrieve(@info); file << info.given; file << info.taken; } void load(any@ data, SaveFile& file) const override { ConvertData info; if(file >= SV_0079) { file >> info.given; file >> info.taken; } else { double current = 0; double rate = 0; file >> current; if(file >= SV_0049) file >> rate; } data.store(@info); } #section all }; //AddToNativeResource((..)) // Adds the inner effect hook to where the native resource is going. tidy final class AddToNativeData { Object@ current; any data; }; tidy final class AddToNativeResource : GenericEffect { GenericEffect@ hook; Document doc("The inner hook is executed from the context of the native resource's destination, rather than on the planet this effect is active on."); Argument hookID("Hook", AT_Hook, "planet_effects::GenericEffect"); bool instantiate() { @hook = cast(parseHook(arguments[0].str, "planet_effects::")); if(hook is null) { error("AddToNativeResource: could not find inner hook: "+escape(arguments[0].str)); return false; } return GenericEffect::instantiate(); } const IResourceHook@ get_displayHook() const override { return null; } const IResourceHook@ get_carriedHook() const override { return hook.displayHook; } #section server void enable(Object& obj, any@ data) const override { AddToNativeData info; data.store(@info); } void disable(Object& obj, any@ data) const override { AddToNativeData@ info; data.retrieve(@info); if(info !is null && info.current !is null) hook.disable(info.current, info.data); @info = null; data.store(@info); } void tick(Object& obj, any@ data, double time) const { AddToNativeData@ info; data.retrieve(@info); //Make sure the hook is applied to the right object Object@ target; if(obj.hasResources) @target = obj.nativeResourceDestination[0]; if(target is null) @target = obj; if(target !is info.current) { if(info.current !is null) hook.disable(info.current, info.data); if(target !is null) hook.enable(target, info.data); @info.current = target; } if(info.current !is null) hook.tick(info.current, info.data, time); } void ownerChange(Object& obj, any@ data, Empire@ prevOwner, Empire@ newOwner) const { AddToNativeData@ info; data.retrieve(@info); if(info.current !is null) hook.ownerChange(info.current, info.data, prevOwner, newOwner); } void regionChange(Object& obj, any@ data, Region@ fromRegion, Region@ toRegion) const { AddToNativeData@ info; data.retrieve(@info); if(info.current !is null) hook.regionChange(info.current, info.data, fromRegion, toRegion); } void save(any@ data, SaveFile& file) const { AddToNativeData@ info; data.retrieve(@info); if(info is null){ Object@ tmp; file << tmp; } else { file << info.current; if(info.current !is null) hook.save(info.data, file); } } void load(any@ data, SaveFile& file) const { AddToNativeData info; data.store(@info); file >> info.current; if(info.current !is null) hook.load(info.data, file); } #section all }; //AddRandomPressure(, , ) // Adds random pressure that changes every . tidy final class PressureData { int type; int amount; double timer; }; class AddRandomPressure : GenericEffect { Document doc("Add randomized pressure to the planet that changes to a different type periodically."); Argument amount(AT_Integer, doc="Amount of randomized pressure to give."); Argument change_timer(AT_Decimal, doc="Time interval between when the pressure changes types."); Argument buildup_time(AT_Decimal, doc="Time period over which the pressure builds up from 0 to its maximum value."); #section server void enable(Object& obj, any@ data) const override { PressureData info; info.type = randomi(0, TR_COUNT-1); info.amount = 0; info.timer = 0.0; data.store(@info); } void disable(Object& obj, any@ data) const override { PressureData@ info; data.retrieve(@info); if(info.type != -1) obj.modPressure(info.type, -info.amount); @info = null; data.store(null); } void tick(Object& obj, any@ data, double time) const { PressureData@ info; data.retrieve(@info); int maxAmount = arguments[0].integer; if(info.amount < maxAmount) { //Pressure buildup int prevAmt = info.amount; info.timer += time; info.amount = clamp(round(info.timer / arguments[2].decimal * double(maxAmount)), 0, maxAmount); if(info.amount != prevAmt) obj.modPressure(info.type, info.amount - prevAmt); if(info.amount == maxAmount) info.timer = 0.0; } else { //Pressure change info.timer += time; if(info.timer >= arguments[1].decimal) { obj.modPressure(info.type, -info.amount); info.type = randomi(0, TR_COUNT-1); obj.modPressure(info.type, +info.amount); info.timer = 0.0; } } } void save(any@ data, SaveFile& file) const { PressureData@ info; data.retrieve(@info); if(info !is null) { file << info.type; file << info.amount; file << info.timer; } else { int tmp = -1; file << tmp; tmp = 0; file << tmp; double tmpd = 0.0; file << tmpd; } } void load(any@ data, SaveFile& file) const { PressureData info; file >> info.type; file >> info.amount; file >> info.timer; data.store(@info); } #section all }; class ReplacesCities : GenericEffect, TriggerableGeneric { Document doc("The planet this effect is active on needs to construct fewer civilian cities than normal, this effect replaces some."); Argument amount(AT_Integer, "1", doc="How many cities this replaces."); #section server void enable(Object& obj, any@ data) const override { if(obj.hasSurfaceComponent) obj.modCityCount(+amount.integer); } void disable(Object& obj, any@ data) const override { if(obj.hasSurfaceComponent) obj.modCityCount(-amount.integer); } //This hook, when used on a building, takes effect immediately, to prevent 'temporary' cities from being built void startConstruction(Object& obj, SurfaceBuilding@ bld) const { enable(obj, bld.data[hookIndex]); } void cancelConstruction(Object& obj, SurfaceBuilding@ bld) const { disable(obj, bld.data[hookIndex]); } void complete(Object& obj, SurfaceBuilding@ bld) const { //Already enabled in startConstruction } #section all }; class MakeQuarantined : GenericEffect, TriggerableGeneric { Document doc("The planet this is active on is marked 'quarantined', which prevents it from importing, exporting or being colonized."); #section server void enable(Object& obj, any@ data) const override { if(obj.hasSurfaceComponent) obj.setQuarantined(true); } void disable(Object& obj, any@ data) const override { if(obj.hasSurfaceComponent) obj.setQuarantined(false); } #section all }; class NoNeedPopulationForLevel : GenericEffect { Document doc("The planet this is on does not require extra population to level."); #section server void enable(Object& obj, any@ data) const override { if(obj.hasSurfaceComponent) obj.setNeedsPopulationForLevel(false); } void disable(Object& obj, any@ data) const override { if(obj.hasSurfaceComponent) obj.setNeedsPopulationForLevel(true); } #section all }; class PopulationCannotDie : GenericEffect { Document doc("The population on this planet cannot die."); #section server void tick(Object& obj, any@ data, double time) const override { if(obj.hasSurfaceComponent) { double curPop = obj.population; double intPop = ceil(curPop); if(curPop != intPop) obj.addPopulation(intPop - curPop); } } #section all }; class AlwaysAtMaxPopulation : GenericEffect { Document doc("The population of the planet is always at the maximum value."); #section server void tick(Object& obj, any@ data, double time) const override { if(obj.hasSurfaceComponent) { double diff = obj.maxPopulation - obj.population; if(diff != 0) obj.addPopulation(diff); } } #section all }; class ForceIntegerPopulation : GenericEffect { Document doc("The population on this planet dies in integer increments."); #section server void enable(Object& obj, any@ data) const override { double popDmg = 0; if(obj.hasSurfaceComponent) { double curPop = obj.population; double targPop = floor(curPop); if(curPop != targPop) { popDmg = curPop - targPop; obj.addPopulation(targPop - curPop); } } data.store(popDmg); } void tick(Object& obj, any@ data, double time) const override { if(obj.hasSurfaceComponent) { double popDmg = 0; data.retrieve(popDmg); double curPop = obj.population; double targPop = max(ceil(curPop - popDmg), 1.0); if(curPop != targPop) { popDmg += targPop - curPop; obj.addPopulation(targPop - curPop); data.store(popDmg); } } } void save(any@ data, SaveFile& file) const override { double amt = 0; data.retrieve(amt); file << amt; } void load(any@ data, SaveFile& file) const override { double amt = 0; file >> amt; data.store(amt); } #section all }; class ProduceAllPressure : GenericEffect { Document doc("Produce all pressure of a particular type directly as resource production."); Argument type(AT_TileResource, doc="Type of pressure to produce."); Argument factor(AT_Decimal, "1", doc="Factor of pressure to produce."); #section server void enable(Object& obj, any@ data) const override { double prod = 0; data.store(prod); } void tick(Object& obj, any@ data, double time) const override { if(!obj.hasSurfaceComponent) return; double prod = 0; data.retrieve(prod); double newProd = obj.getResourcePressure(type.integer) * factor.decimal; if(newProd != prod && obj.hasSurfaceComponent) { obj.modResource(type.integer, newProd - prod); data.store(newProd); } } void disable(Object& obj, any@ data) const override { double prod = 0; data.retrieve(prod); if(prod != 0 && obj.hasSurfaceComponent) obj.modResource(type.integer, -prod); } void save(any@ data, SaveFile& file) const override { double amt = 0; data.retrieve(amt); file << amt; } void load(any@ data, SaveFile& file) const override { double amt = 0; file >> amt; data.store(amt); } #section all }; class SetMaxLevel : GenericEffect { Document doc("Set the planet's maximum level, it cannot level up beyond this."); Argument level(AT_Integer, doc="Maximum level to set"); #section server void enable(Object& obj, any@ data) const override { if(obj.hasSurfaceComponent) obj.maxLevel = level.integer; } void tick(Object& obj, any@ data, double time) const override { if(obj.hasSurfaceComponent) obj.maxLevel = level.integer; } void disable(Object& obj, any@ data) const override { if(obj.hasSurfaceComponent) obj.maxLevel = -1; } #section all }; class SetMaxLevelStatusCount : GenericEffect { Document doc("Set the planet's maximum level based on how many statuses it has."); Argument base(AT_Integer, doc="Base level."); Argument status(AT_Status, doc="Status to count."); #section server void tick(Object& obj, any@ data, double time) const override { if(obj.hasSurfaceComponent) obj.maxLevel = base.integer + obj.getStatusStackCountAny(status.integer); } void disable(Object& obj, any@ data) const override { if(obj.hasSurfaceComponent) obj.maxLevel = -1; } #section all }; class ForceUsefulSurface : GenericEffect { Document doc("Force the planet to have a percentage of useful region on its surface."); Argument percent(AT_Decimal, doc="Percent of the surface that needs to be useful."); Argument biome(AT_PlanetBiome, doc="Biome to fill the planet with to ensure surface."); #section server void enable(Object& cur, any@ data) const override { if(cur is null || !cur.hasSurfaceComponent) return; auto@ type = getBiome(biome.str); if(type !is null) cur.forceUsefulSurface(percent.decimal, type.id); else print("No such biome: "+biome.str); } #section all }; class SetOrbitSpin : GenericEffect { Document doc("Force the planet to have a particular spin."); Argument spin(AT_Range, doc="Time for the planet to complete one spin."); #section server void enable(Object& cur, any@ data) const override { if(cur.hasOrbit) cur.orbitSpin(spin.fromRange(), true); } #section all }; class ChangeNativeResourceTo : GenericEffect { Document doc("Change the type of native resource for the duration of this effect."); Argument resource(AT_PlanetResource, doc="Type of planetary resource to convert to."); #section server void enable(Object& cur, any@ data) const override { uint prevType = cur.primaryResourceType; data.store(prevType); cur.terraformTo(resource.integer); } void disable(Object& cur, any@ data) const override { uint prevType = uint(-1); data.retrieve(prevType); cur.terraformTo(prevType); } void save(any@ data, SaveFile& file) const override { uint reso = uint(-1); data.retrieve(reso); file << reso; } void load(any@ data, SaveFile& file) const override { uint reso = uint(-1); file >> reso; data.store(reso); } #section all }; class ChangeLevelChain : GenericEffect { Document doc("Change the planet's level chain and requirements."); Argument chain(AT_Custom, doc="Chain to change to."); Argument base_only(AT_Boolean, "True", doc="Only apply this chain if the chain was base before."); uint chainId = 0; bool instantiate() override { chainId = getLevelChainID(chain.str); if(chainId == uint(-1)) { chainId = 0; error("Cannot find planet level chain: "+chain.str); return false; } return GenericEffect::instantiate(); } #section server void enable(Object& cur, any@ data) const override { if(cur.hasSurfaceComponent) { if(base_only.boolean) { if(cur.levelChain == 0) cur.setLevelChain(chainId); } else { if(cur.levelChain != chainId) cur.setLevelChain(chainId); } } } void tick(Object& cur, any@ data, double time) const override { enable(cur, data); } void disable(Object& cur, any@ data) const override { if(cur.hasSurfaceComponent) { if(cur.levelChain == chainId) cur.setLevelChain(0); } } #section all }; class PlanetLevelIncomeMod : GenericEffect { Document doc("Modify the planet's income based on its level."); Argument level0(AT_Integer, doc="Income modification at level 0."); Argument level1(AT_Integer, doc="Income modification at level 1."); Argument step(AT_Integer, doc="Step that is added at every level afterwards."); #section server void enable(Object& obj, any@ data) const override { int mod = 0; data.store(mod); } void tick(Object& obj, any@ data, double time) const override { if(!obj.hasSurfaceComponent) return; int prevMod = 0; data.retrieve(prevMod); int newMod = 0; uint curLevel = obj.level; uint chain = obj.levelChain; if(curLevel == 0) { newMod = level0.integer; } else { double curPop = obj.population; auto@ lv0 = getPlanetLevel(chain, 0); auto@ lv1 = getPlanetLevel(chain, 1); if(lv0 !is null && lv1 !is null) { double startPop = lv0.population; double endPop = lv1.population; newMod = level0.integer + double(level1.integer - level0.integer) * clamp(curPop - startPop, 0.0, (endPop - startPop)) / (endPop - startPop); for(uint i = 2; i <= curLevel; ++i) { auto@ lv = getPlanetLevel(chain, i); if(lv is null) break; startPop = endPop; endPop = lv.population; if(startPop != endPop) newMod += double(step.integer) * clamp(curPop - startPop, 0.0, (endPop - startPop)) / (endPop - startPop); } } } if(newMod != prevMod) { obj.modIncome(newMod - prevMod); data.store(newMod); } } void disable(Object& obj, any@ data) const override { int mod = 0; data.retrieve(mod); if(mod != 0 && obj.hasSurfaceComponent) obj.modIncome(-mod); } void save(any@ data, SaveFile& file) const override { int amt = 0; data.retrieve(amt); file << amt; } void load(any@ data, SaveFile& file) const override { int amt = 0; file >> amt; data.store(amt); } #section all }; class ProduceAsteroidPressure : GenericEffect { Document doc("Produce the pressure given by asteroids on this plaent."); Argument factor(AT_Decimal, "1.0", doc="Multiplication to the pressure in production."); #section server void enable(Object& obj, any@ data) const override { array production(TR_COUNT, 0.0); data.store(@production); } void tick(Object& obj, any@ data, double time) const override { array@ production; data.retrieve(@production); for(uint i = 0; i < TR_COUNT; ++i) { double prevProd = production[i]; double newProd = obj.pressureFromAsteroids(i) * factor.decimal; if(prevProd != newProd) { obj.modResource(i, newProd - prevProd); production[i] = newProd; } } } void disable(Object& obj, any@ data) const override { array@ production; data.retrieve(@production); for(uint i = 0; i < TR_COUNT; ++i) { obj.modResource(i, -production[i]); production[i] = 0.0; } } void save(any@ data, SaveFile& file) const override { array@ production; data.retrieve(@production); for(uint i = 0; i < TR_COUNT; ++i) file << production[i]; } void load(any@ data, SaveFile& file) const override { array production(TR_COUNT, 0.0); data.store(@production); for(uint i = 0; i < TR_COUNT; ++i) file >> production[i]; } #section all };