[PHost Logo]

Formulas
The Portable Host
Version 4.0k

Index

Introduction

This document describes all formulas and processes used in PHost. It is intended for players who do not leave anything to chance. If you believe that some aspect of PHost operation should be documented in this file but is not, send mail to the PHost group and bring this to our attention.

The sequence of events is documented on the Host Sequence page.

This document is organized by initiator of an action. For example, Pillage is a ship mission, so it is documented in the ships section. Combat is an exception because it applies to ships as well as planets.

Notation

Variable names (Hull_mass, Native_race, ...) should be self-explanatory. We use common arithmetic notation. In particular, / is a fractional division.

Configuration options are specified verbatim, with links to their description. Eff_ConfigOption denotes the value of the ConfigOption modified by experience modifiers EModConfigOption.

Internally, PHost often uses people counts for populations, which were also used in the older documentation. For this document, numbers have been converted to the the more familiar clans. Since VGA Planets does not support fractional clans, PHost truncated after each step anyway.

When a series of "if..." sentences is given, take the first applicable one.

Trunc(X) Truncate X to integer (remove fractional part)
Round(X) Round X to integer (round towards nearest integer; round up if ends in .5 exactly)
ERnd(X) Round X to integer (round towards nearest integer; round towards nearest even number if ends in .5 exactly)
Ceil(X) Next-largest integer (round up if there is any fractional part)
Sqrt(X) Square-root of X
Exp(X) Exponential of X (2.7182^X)
Ln(X) Natural logarithm of X
Random(X) Random number, between 0 (inclusive) up to X (not inclusive). For example, Random(3) yields one of 0, 1, 2.
PI The number PI = 3.14159265358979323846

Back to top


Ships

General

Ships burn fuel after movement. If the ship has less fuel, nothing bad will happen, but the ship will end up without fuel afterwards.

Fuel_burned_per_turn =
   Ceil(Ship_hull_mass * FuelUsagePerTurnFor100KT / 100)

Ships burn fuel after each fight. If the ship has less fuel, nothing bad will happen, but the ship will end up without fuel afterwards.

Fuel_burned_per_fight =
   Ceil(Ship_hull_mass * FuelUsagePerFightFor100KT / 100)

Movement

Speed Limit:

Max_speed =
   9                 ...if ship has Hardened Engines
   15 - Trunc(Damage/10)
                     ...if ship owner is Lizards
   10 - Trunc(Damage/10)
                     ...otherwise

Fuel usage:

Fuel_usage =
   Trunc((ERnd(Total_ship_mass/10) * Distance * Engine_fuel_usage)
           / (10000 * Max_dist))
                     ...if UseAccurateFuelModel is off
   Total_ship_mass
    *  (1.0 - Exp(-(Engine_fuel_usage * Distance) / (Max_dist * 100000)))
                     ...if UseAccurateFuelModel is on
   ...where
      Max_dist =
         Warp^2      ...for normal engines
         Warp^2 * 2  ...for gravitonic engines

Note that the UseAccurateFuelModel formula can yield fractional values. In case ship movement occurs in multiple phases (because the ship hits a mine), these fractional values are added up, and arithmetically rounded at the end. In contrast, non-accurate movement rounds after every step.

Damage from mine hit:

Damage_taken =
   100 * MineHitDamageFor100KT / Hull_mass
                     ...for normal mines
   100 * WebHitDamageFor100KT / Hull_mass
                     ...for web mines

Ground Combat

Ground combat happens when a hostile ship drops colonists on a foreign planet, using the ship-to-planet cargo transporters.

During ground combat, attacking colonists and defenders annihilate each other, subject to their attack and defense ratios, until one party remains.

Ground_attack_result =
   "attacker wins with Trunc(Result/Attacker_rate) clans remaining"
                     ...if Result >= 0
   "defender wins with Trunc(-Result/Defender_rate) clans remaining"
                     ...if Result < 0
   ...with
      Attacker_rate =
         GroundKillFactor[Ship_owner]
      Defender_rate =
         GroundDefenseFactor[Planet_owner] + Planet_defense / 20
      Result =
         (Attacking_clans * Attacker_rate) - (Defending_clans * Defender_rate)

Note that if the result yields 0 clans remaining (maybe due to rounding), the planet gets unowned.

Mission Effects

Mine Sweeping

Mine sweeping comes in two flavours: normal sweeping and scooping. Scooping is selected using the msc friendly code or the Scoop Torpedoes extended mission. Mine sweeping scans all minefields in range, and destroys hostile minefields if possible. Mine scooping, in addition, gathers up torpedoes from a minefield owned by the same player as the ship, and turns it back into torpedoes.

Units_swept =
   Beam_contribution + Fighter_contribution

Beam_contribution =
   Beam_count * Beam_type^2 * Sweep_rate
   ...with Sweep_rate is WebMineSweepRate or MineSweepRate
                     ...if ship has beams, is within range, and field not
                        hidden by ion storm
   0                 ...otherwise

Fighter_contribution =
   Fighter_count * FighterSweepRate
                     ...if ship has bays, and is within FighterSweepRange,
                        and minefield is a normal minefield
                            or ship is owned by colonies and AllowColoniesSweepWebs is enabled
   0                 ...otherwise

Torps_scooped =
   Max(Trunc(Mine_units / Conversion_rate), Free_cargo_room)
   ...where
      Conversion_rate =
         Trunc(Torp_type^2 * UnitsPerTorpRate[Ship_owner] / 100)
Units_scooped =
   Torps_scooped * Conversion_rate

If the Scoop Torpedoes mission is used, the parameter specifies the maximum number of torpedoes to scoop from each applicable minefield, not the total amount.

Mine Laying

Torpedo ships can lay mines. The same formulas apply to web laying.

Torps_laid =
   Min(Torps_available, Trunc((Max_units - Existing_units) / Conversion_rate))
   ...0 if Conversion_rate is zero or Existing_units >= Max_units
   ...where
      Conversion_rate =
         Trunc(Torp_type^2 * Min(UnitsPerTorpRate[Ship_owner],
                                 UnitsPerTorpRate[Minefield_owner]) / 100)
      Max_units =
         MaximumMinefieldRadius[Minefield_owner]
         ...if it is a normal mine field
         MaximumWebMinefieldRadius[Minefield_owner]
         ...if it is a web field
Units_laid =
   Torps_laid * Conversion_rate

Existing_units is the number of mine units in the field we're adding to, 0 if it is a new field. Torps_available is the number of Torps allowed for laying using mdX or an extended mission like Lay Minefield. Note that Ship_owner and Minefield_owner can differ if miX or an extended mission is used.

Towing

For more details about towing, see Tow Conflict Resolution.

Tow_strength = Engine_contribution + Movement_contribution

Engine_contribution = Engine_tech^2 * Eff_engines
   * Warp_factor * TowStrengthEngineScale
Movement_contribution = Movement_distance
   * TowStrengthDistanceScale

Intercept

For intercept, PHost attempts to sort ships into an order such that all intercept targets move before their respective interceptors. In case of circular intercept, this cannot be done, so it is treated specially:

Waypoint_X =
   (Sum(Position_X) + Adjust_X) / Num_ships_in_loop

Waypoint_Y =
   (Sum(Position_Y) + Adjust_Y) / Num_ships_in_loop

Adjust_X =
   0                 ...if AllowWraparoundMap is off
   i * Map_dimension_X
       ...where 0 <= i < Num_ships_in_loop
          such that Sum((Position_X - Waypoint_X)^2) is minimal

Adjust_Y =
   0                 ...if AllowWraparoundMap is off
   j * Map_dimension_Y
       ...where 0 <= j < Num_ships_in_loop
          such that Sum((Position_Y - Waypoint_Y)^2) is minimal

The Adjust_X and Adjust_Y parameters are used only in wraparound-map games, and attempt to make sure that ships move the minimum possible distance. They are found by iterating all possible i and j values and picking the best fit. In PHost below 4.0k/3.4m, they are always zero.

Klingon Pillage

Ships that do Pillage will plunder planetary households to get cash and supplies. They will then kill people which makes the population unhappy.

Supplies_made =
   Trunc((Colonist_clans + Native_clans) / 100)

Money_made =
   Trunc((Colonist_clans + Native_clans) / 100)

Colonist_clans_survived =
   Trunc(Colonist_clans * 0.8 - 20)

Native_clans_survived =
   Trunc(Native_clans * 0.8 - 120)

Colonist_happy_change =
   -10

Native_happy_change =
   -10

Rebel Ground Attack

Ships that do Rebel Ground Attack will destroy planetary resources. They will then kill colonists, which makes them unhappy. Sarcastic natives will laugh at unhappy colonists.

Money_remaining =
   Trunc(Money * 0.7)

Supplies_remaining =
   Trunc(Supplies * 0.6)

Defense_remaining =
   Trunc(Defense_posts * 0.8)

Mines_remaining =
   Trunc(Mines * 0.4)

Factories_remaining =
   Trunc(Factories * 0.7)

Colonist_clans_survived =
   Trunc(Colonist_clans * 0.8)

Colonist_happy_change =
   -60

Native_happy_change =
   +40

Cloaking

Ships that cloak need to burn fuel.

Fuel_burned_by_cloak =
   0                 ...if ship has Advanced Cloaking
   Trunc(CloakFuelBurn * Min(Hull_mass, 100) / 100)
                     ...otherwise

Fuel_needed_before_movement =
   1 + Fuel_burned_by_cloak

Fuel_needed_after_movement =
   1

Ships need to decloak if their fuel drops below the Fuel_needed value. After the normal cloak fuel was burnt, one kt must remain; fuelless ships cannot cloak.

Back to top


Planets

Meteor Strikes

Large meteors kill people and make them unhappy. Meteor showers have no effect on the population.

Colonists_survived =
   Colonists * (Random(91)+10) / 100
Colonist_happiness_change =
   -(Random(31) + 50)
Natives_survived =
   Natives * (Random(100)+1) / 100
Native_happiness_change =
   -(Random(31) + 50)

In simple words, up to 90% of the colonists and up to 99% of the natives die, and they lose 50 to 80 happiness points. The mineral amounts added to the planet's core (not surface!) are configurable (LargeMeteorOreRanges, MeteorShowerOreRanges).

Buildings

Maximum: The maximum number of structures you can build on a planet depends on the population of the planet.

Maximum_mines =
   Colonist_clans    ...if Colonist_clans < 200
   Round(200 + Sqrt(Colonist_clans - 200))
                     ...if Colonist_clans >= 200

Maximum_factories =
   Colonist_clans    ...if Colonist_clans < 100
   Round(100 + Sqrt(Colonist_clans - 100))
                     ...if Colonist_clans >= 100

Maximum_defense_posts =
   Colonist_clans    ...if Colonist_clans < 50
   Round(50 + Sqrt(Colonist_clans - 50))
                     ...if Colonist_clans >= 50

Note that you need not permanently fulfill these conditions. You can build factories and beam off clans to a ship. Excess buildings will decay at a rate of StructureDecayPerTurn.

Buildings affect your visibility to Sensor Sweep.

Industry_detection_chance =
   0%            ...if Mines < MinesForDetectable
                    and Factories < FactoriesForDetectable
   0%            ...if Defense >= DefenseForUndetectable
   100% - (Defense / DefenseForUndetectable * 100%)
                 ...in all other cases

Industry_level_reported =
   "minimal"     ...if (Mines + Factories) < 30
   "light"       ...if (Mines + Factories) < 60
   "moderate"    ...if (Mines + Factories) < 90
   "substantial" ...if (Mines + Factories) < 120
   "heavy"       ...if (Mines + Factories) >= 120

Bioscan_detection_chance =
   0%            ...if Defense >= 20
   0%            ...if ship does not have bioscanner (of course :-)
   100%          ...if ship has full bioscanner
   20%           ...otherwise

Production

Supplies: Supplies are produced by factories, or by Bovinoid natives.

Supplies_made =
   Trunc((Factory_contribution + Bovinoid_contribution) * ProductionRate) / 100)
   ...where
      Factory_contribution =
         Factories
      Bovinoid_contribution =
         Min(Trunc(Native_clans / 100), Colonist_clans)
            ...if natives are Bovinoid
         0  ...otherwise

Taxation: Taxes are collected from colonists and natives.

Taxes_collected =
   Taxes_from_colonists + Taxes_from_natives
   ...at most MaxPlanetaryIncome

Taxes_from_colonists =
   Round(Round(Colonist_clans * Colonist_tax / 1000) * ColonistTaxRate / 100)
                    ...if Colonist_happiness >= 30
   0                ...if Colonist_happiness < 30

Taxes_from_natives =
   0                ...if Native_happiness < 30
   0                ...if natives are Amorphous
   Round(Max(Colonist_clans, Natives_due) * IF * NativeTaxRate / 100)
   ...where Natives_due = Round(Native_clans * Native_gov_number * Native_tax / 5000)
   ...where IF = 2 if natives are insectoid, IF = 1 otherwise

The Native_gov_number is tabulated in the Planet Rules section (e.g. 6 for Monarchy).

Happiness: Taxation changes happiness. Note that happiness changes occur before taxation. If the happiness before this stage is below 30, taxes are set to zero (and new happiness is computed according to this rate).

Colonist_happiness_change =
   Trunc(10 - Sqrt(Colonist_clans / 10000)
            - Abs(Temperature - Target_temperature) / Temp_divisor
            - (Mines + Factories) / 300
            - Colonist_tax * 0.8)
   ...where Target_temperature = 100 and Temp_divisor = 66
      if owner is Crystal and CrystalsPreferDeserts is on
   ...where Target_temperature = 50 and Temp_divisor = 33
      otherwise

Native_happiness_change =
   Trunc(5 + Native_gov_factor / 2
         - Sqrt(Native_clans / 10000)
         - (Mines + Factories) / 200
         - Native_tax * 0.85)
   ...plus 10 if natives are Avian

Again, the Native_gov_number is tabulated in the Planet Rules section (e.g. 6 for Monarchy, yielding a value of 6/2 = 3 for the first term).

Happiness is summarized as follows:

Happiness_level =
   "happy"           ...if Happiness >= 90
   "calm"            ...if Happiness >= 70
   "unhappy"         ...if Happiness >= 50
   "very angry"      ...if Happiness >= 40
   "rioting"         ...if Happiness >= 20
   "fighting"        ...if Happiness < 20

Happiness_change_level =
   "hate you"        ...if Happiness_change < -5
   "angry about you" ...if Happiness_change < 0
   "undecided"       ...if Happiness_change = 0
   "like your leadership"
                     ...if Happiness_change <= 4
   "love you"        ...if Happiness_change >= 5

Mining: The maximum amount of minerals extracted from a planet's core depends on the mineral density.

Max_minerals_mined =
   Trunc(Mining_rate * Mine_count / 100)
   ...where Mining_rate = Trunc(RaceMiningRate * Mineral_density / 100) * RF
   ...with RF = 2 for Reptilian natives, 1 otherwise

Minerals_mined =
   Min(Max_minerals_mined, Minerals_in_core)
   

Trans-Uranium Decay: New minerals appear in the planet's core. Note that this happens after mining, so you cannot extract the new minerals the same turn.

New_minerals_in_core =
   Trunc((TransuraniumDecayRate * Mineral_density + 50) / 100)

Population

Cyborg Assimilation: Cyborgs assimilate natives, and turn them into colonists. One assimilated native clan yields one new cyborg colonist clan.

Native_clans_assimilated =
   Trunc(Colonist_clans * BorgAssimilationRate / 100)
   ...at most Native_clans

Maximum Population: The maximum population for a planet is a fixed number which depends on the planet's climate. With ClimateLimitsPopulation enabled, the maximum population on an ideally-tempered world is 100000 clans (10 million colonists). If configured, supplies help you support more colonists on a planet.

Eff_max_colonist_clans =
   Max_colonist_clans + Supply_bonus
      ...if ClimateLimitsPopulation is enabled
   250000
      ...otherwise (25 million colonists)

Max_colonist_clans =
   Max(Trunc(100000 * Sin(Temperature * PI / 200)), 1)
                    ...if colonists are Crystalline
                       and CrystalsPreferDeserts is enabled
                       and CrystalSinTempBehavior is enabled
                       and Temperature >= 15
   3 + Trunc(MaxColTempSlope * Temperature / 100)
                    ...if colonists are Crystalline
                       and CrystalsPreferDeserts is enabled
                       and CrystalSinTempBehavior is enabled
                       and Temperature < 15
   Max(1000 * Temperature, 1)
                    ...if colonists are Crystalline
                       and CrystalsPreferDeserts is enabled
                       and CrystalSinTempBehavior is disabled
   90000
                    ...if colonists are Rebel and Temperature < 20 (9 million colonists)
   3 + Trunc(MaxColTempSlope * Temperature / 100)
                    ...if Temperature < 15
   1 + Trunc((100-Temperature) * MaxColTempSlope / 100)
                    ...if Temperature > 84
                    ...at least 60 if colonists are Klingon, Robot, Rebel or Colony
   Trunc(100000 * Sin(Temperature * PI / 100))
                    ...in all remaining cases

Supply_bonus =
   Trunc(Supplies / 40)
                    ...if AllowEatingSupplies is enabled
   0                ...otherwise

Native populations have simpler formulas. The absolute maximum is 15.6 million natives (156000 clans). Supplies do not help you to increase the limit.

Max_native_clans =
   156000
                    ...if ClimateLimitsPopulation is disabled
   100000 * Temperature
                    ...if natives are Siliconoid
                       and CrystalsPreferDeserts is enabled
                       and PHost is version 3.3c or newer
   Trunc(Sin(Temperature * PI / 100) * 156000)
                    ...in all remaining cases

It might be considered a bug that Siliconoids cannot reach the 15.6 million mark with CrystalsPreferDeserts enabled, but changing the formula would again complicate matters even more.

Growth: Growth depends on taxation and climate. Populations will never grow over the limit. The maximum growth rate is 5% per turn.

Colonist_growth_in_clans =
   Trunc(Round(Colonist_growth_rate * Colonist_clans / 10000) *
           RaceGrowthRate / 100)
   ...at most Eff_max_colonist_clans - Colonist_clans

Colonist_growth_rate =
   0                ...if Colonist_clans >= Eff_max_colonist_clans
   0                ...if Colonist_happiness < 70
   0                ...if colonists are Crystalline
                       and CrystalsPreferDeserts is enabled
                       and CrystalSinTempBehavior is enabled
                       and Temperature < 15
   5 * Sin(Temperature * PI / 200) / (1 + Colonist_tax / 5)
                    ...if colonists are Crystalline
                       and CrystalsPreferDeserts is enabled
                       and CrystalSinTempBehavior is enabled
                       and Temperature >= 15
   5 * (Temperature / 100 ) / (1 + Colonist_tax / 5)
                    ...if colonists are Crystalline
                       and CrystalsPreferDeserts is enabled
                       and CrystalSinTempBehavior is disabled
   0                ...if Temperature < 15
   0                ...if Temperature > 84
   5 * Sin(Temperature * PI / 100) / (1 + Colonist_tax / 5)
                    ...in all other cases

Native growth is similar, but here the maximum growth rate is 4%. Natives do not grow on unowned planets(!).

Native_growth_in_clans =
   Trunc(Round(Native_growth_rate * Native_clans) / 100)
   ...at most Max_native_clans - Native_clans

Native_growth_rate =
   0                ...if Native_clans >= Max_native_clans
   0                ...if Native_happiness < 70
   4 * (Temperature / 100) / (1 + Native_tax / 5)
                    ...if natives are Siliconoids
                       and CrystalsPreferDeserts is enabled
                       and PHost is version 3.3c or newer
   4 * Sin(Temperature * PI / 100) / (1 + Native_tax / 5)
                    ...in all other cases

Overpopulation eats supplies: If enabled, colonist overpopulation will eat supplies to survive.

Supply_loss =
   0                ...if AllowEatingSupplies is off
   0                ...if ClimateLimitsPopulation is off
   0                ...if Colonist_clans <= Max_colonist_clans
   Trunc((Colonist_clans - Max_colonist_clans) / 40 + 1)
                    ...otherwise

If there are fewer supplies than needed, they'll all be used up with no negative consequences.

Climate Deaths: If enabled, colonists and natives over the population limit will die.

Colonist_clans_dying =
   0                ...if ClimateLimitsPopulation is off
   0                ...if Colonist_clans <= Eff_max_colonist_clans
   Min(Trunc(Colonist_clans * ClimateDeathRate / 100),
       Eff_max_colonist_clans - Colonist_clans)
                    ...otherwise

Native_clans_dying =
   0                ...if ClimateLimitsPopulation is off
   0                ...if planet is unowned
   0                ...if Native_clans <= Max_native_clans
   Min(Trunc(Native_clans * NativeClimateDeathRate / 100),
       Max_native_clans - Native_clans)
                    ...otherwise

==> If the population exceeds the absolute maximum of 250000 clans (25 million people), the excess clans will die and be reported as climate deaths, even if ClimateLimitsPopulation is off.

==> Eff_max_colonist_clans is computed after overpopulation-eats-supplies, so it uses the new (lower) supply amount.

Planetary Actions Flowchart

This table shows all actions involving planets. The left column shows the PControl stages, in chronological order. The middle column contains all actions affecting happiness or population (like "taxation happens before growth"), the right-most column contains all actions affecting minerals and buildings (like "beam-up-multiple happens before lfm" (hint, hint)).

Stage Happiness/Population Minerals/Industry
LargeMeteors, MeteorShowers Meteors might bring down happiness. Meteors and meteor showers add minerals to planet core.
CargoDump Ground combat
Training Ships gather supplies for training
GatherMission Ships gather stuff
SpecialMissions_1 Lizards Hiss
BuildFighters, BuildTorpedoes Ships gather stuff
ShipBuilding_1 Cloning might consume minerals.
DumpOldBaseParts Starbases recycle old starship parts
BaseMissions_1 Starbases first recycle ships, then maximize defense or load torps onto ships
FreeFighters Starbases build "free" fighters
GloryDevices Glory devices kill people and toast Amorphous natives Glory devices damage planet
ColonizeMission Colonize ships bring clans Colonize ships bring minerals
BaseMissions_2 Starbases refuel ships or unload them
Combat Population might be killed in combat. Defense might be destroyed.
TerraForming Terraforming makes environment more pleasant for inhabitants.
SensorSweep Sensor Sweep might discover planets according to their industry.
SpecialMissions_2 Pillage / RGA might make people unhappy Pillage / RGA will destroy stuff, Dark Sense reports amounts afterwards
PlanetaryProduction Mining, supply production, then trans-uranium decay
PlanetaryHappiness if happiness is 29 or lower, taxes are set to 0. Then, happiness changes.
PlanetaryTaxation Tax collection
PlanetaryGrowth Growth
PlanetaryLosses Climate deaths, then losses through riots Overpopulation eat supplies, then structure decay, then losses through riots, then Amorphs eating colonists
ShipBuilding_2 Cloning might consume minerals.
Assimilation Cyborgs assimilate natives

Back to top


Wormholes

General Specs

The size of the wormhole entry point depends on its mass.

Wormhole_radius =
   (Wormhole_mass ^ (WrmEntryPowerX100 / 100)) / 2

Note that PHost uses the exact fractional value internally. Ufos will report Trunc(Wormhole_radius) (versions up to 3.3d always report 5).

Endpoint Movement: Wormhole endpoints move each turn. They move towards their waypoint up to WrmDisplacement lightyears in X/Y direction, and add some random jitter of WrmRandDisplacement.

Endpoint_displacement =
   Waypoint_displacement + Random_displacement
   ...where
      Random_displacement =
         Random(1 + 2*WrmRandDisplacement) - WrmRandDisplacement
      Waypoint_displacement =
         Waypoint_position - Endpoint_position
         ...at most WrmDisplacement
         ...at least -WrmDisplacement

Size changes: Wormholes change their mass and instability each turn.

Mass_change =
   WrmMassAdd + Random(1 + 2*WrmRandMass) - WrmRandMass

Instability_change =
   -WrmStabilityAddX10 / 10 + Random(1 + 2*WrmRandStability) - WrmRandStability

The mass is an integer in the range 1..32767, the instability is a possibly fractional value in range 0..100. Note that if the mass drops to zero by this process, the wormhole dies, and PHost will set the start and end coordinates to (0,0).

Scanning for Wormholes

Let Ship_dist be the distance between the scanning ship and the center of the wormhole entry point (the X,Y from wormhole.txt).

Deterministic Scanning: A ship sees all wormholes for which Ship_dist <= WrmScanRange. A ship with the ScansAllWormholes function sees all wormholes for which Ship_dist <= 2 * WrmScanRange. These rules are only applied if WrmScanRange is not 0.

Probabilistic Scanning: The chance to see a wormhole depends on its mass.

Detection_radius =
   10 * Wormhole_mass ^ (1/3)
Detection_chance =
   100%              ...if Ship_dist <= Detection_radius
   (4 - (Ship_dist/Detection_radius)^2) * 33.3%
                     ...if Detection_radius < Ship_dist <= 2*Detection_radius
   0%                ...if Ship_dist > 2*Detection_radius

For every wormhole, a dice is rolled.

Wormhole Travel

Ships must be within Wormhole_radius lightyears from the endpoint's center to enter a wormhole.

Wormhole travel imposes some stress on the wormhole. The higher the stress, the higher the chance of a travel failure.

Wormhole_stress =
   0                 ...if Ship_mass < Wormhole_mass
   ((Ship_mass / Wormhole_mass) - 1)^2
                     ...otherwise

Travel_failure_odds =
   Wormhole_stress + Wormhole_instability
     + (Wormhole_stress*Wormhole_instability / 10)

Travel_failure_figure =
   Random(100)

Travel_fuel_usage =
   Fuel_usage(Equiv_distance, WrmTravelWarpSpeed)
   ...where Equiv_distance = Wormhole_distance / WrmTravelDistDivisor

==> Note that PHost up to version 4.0j/3.4l truncates the Travel_failure_odds value to an integral number. Later versions use the exact value.

Possible outcomes of wormhole travel:

Travel_fuel_usage > Fuel
   Travel fails:
      New_ship_X   = 1000 + Random(2001)
      New_ship_Y   = 1000 + Random(2001)
      Damage_taken = 25 + Random(75)
Travel_fuel_usage <= Fuel and Travel_failure_figure >= Travel_failure_odds
   Safe travel:
      New_ship_X   = Endpoint_X - 10 + Random(21)
      New_ship_Y   = Endpoint_Y - 10 + Random(21)
      Damage_taken = 0
Travel_fuel_usage <= Fuel and Travel_failure_figure < Travel_failure_odds
   Successful travel with damage taken:
      New_ship_X   = Endpoint_X - 10 + Random(21)
      New_ship_Y   = Endpoint_Y - 10 + Random(21)
      Damage_taken = (Travel_failure_odds - Travel_failure_figure) ^ 2

The wormhole instability provides a rating for the safety of this wormhole. It is summarized and reported to players using the following levels:

Wormhole_stability_rating =
   "very stable"     ...if Wormhole_instability <= 5
   "stable"          ...if Wormhole_instability <= 15
   "mostly stable"   ...if Wormhole_instability <= 30
   "unstable"        ...if Wormhole_instability <= 50
   "very unstable"   ...if Wormhole_instability <= 80
   "completely unstable"
                     ...otherwise

Back to top


Combat

Starting Parameters for Ships

Starting Parameters for Planets

A planet's defense is reduced if the planet gets damaged.

Eff_Planet_Defense =
   Trunc(Planet_Defense * (100 - Damage) / 100)
Eff_Base_Defense =
   Trunc(Base_Defense * (100 - Damage) / 100)
Eff_Total_Defense =
   Trunc((Base_Defense + Planet_Defense) * (100 - Damage) / 100)

A base's tech level is reduced if the base gets damaged. Here's the formula for beam tech, it applies to the other areas as well.

Eff_Beam_Tech =
   Beam_Tech
   ...at most Trunc((100 - Base_damage) / 10)
   ...at least 1

Planet's equipment in combat:

Combat_mass =
   100 + Eff_Planet_Defense
   ...plus Eff_Base_Defense if base exists

Beam_type =
   Round(Sqrt(Eff_Planet_Defense / 2))
                     ...if no base
   Max(above, Eff_Beam_Tech)
                     ...if base present

Beam_count =
   Round(Sqrt(Eff_Total_Defense / 3))
   ...at most 10 if AllowAlternativeCombat is off
   ...at most 20 if AllowAlternativeCombat is on

Torp_type =
   Round(Sqrt(Eff_Planet_Defense / 2))
                     ...if no base
   Max(above, Eff_Torp_Tech)
                     ...if base present

Tube_count =
   Round(Sqrt(Eff_Total_Defense / 4))
   ...at most 20

Torp_count =
   Tube_count * PlanetaryTorpsPerTube
   ...plus Trunc(Base_torp_cost / Torp_money_cost(Torp_type))
      if base present
   ...at most 255

   Base_torp_cost =
      Torp_money_cost(1) * Torps_in_storage(1)
      + Torp_money_cost(2) * Torps_in_storage(2)
      ...
      + Torp_money_cost(10) * Torps_in_storage(10)

Combat Formulas

Weapon Specs

Beam_hit_odds = Eff_BeamHitOdds
    + Trunc((Beam_Kill_Power + Beam_Expl_Power) * Eff_BeamHitBonus / 100)
Beam_recharge_rate = BeamRechargeRate
    + Trunc((Beam_Kill_Power + Beam_Expl_Power) * Eff_BeamRechargeBonus / 100)
Beam_recharge_per_tick = Random(Beam_recharge_rate)

Torp_hit_odds = Eff_TorpHitOdds
    + Trunc((Torp_Kill_Power + Torp_Expl_Power) * Eff_TorpHitBonus / 100)
Torp_recharge_rate = Eff_TubeRechargeRate
    + Trunc((Torp_Kill_Power + Torp_Expl_Power) * Eff_TubeRechargeBonus / 100)
Torp_recharge_per_tick = Random(Torp_recharge_rate)

Bay_recharge_rate = Eff_BayRechargeRate + Eff_BayRechargeBonus * Num_Bays
Bay_recharge_per_tick = Random(Bay_recharge_rate)

Eff_XXX means the effective value of a configuration option, which consists of the actual configuration value plus the experience modifier of the unit using the weapon.

Weapon Effects

Every weapon hit is defined by three values:

Beams: The Expl_Power and Kill_Power are taken from the weapon definition. A beam emits death rays if its Expl_Power is zero. If the owner of the weapon is Privateer, the Kill_Power is tripled. The beam's charge affects its power; a beam fired at charge 600 has only 60% of its normal power.

Torpedoes: The Expl_Power and Kill_Power are taken from the weapon definition. If AllowAlternativeCombat is off, the values are doubled (note that some clients already display the doubled values). A torpedo emits death rays if its Expl_Power is zero.

Fighters: The Expl_Power and Kill_Power are defined by FighterBeamExplosive and FighterBeamKill, respectively. Fighters never fire death rays.

Shield_damage = (Expl_Power * Eff_ShieldDamageScaling
                 + Kill_Power * Eff_ShieldKillScaling) / (Mass + 1)
         if AllowAlternativeCombat is on
              = Trunc(above + 1.5)
         if AllowAlternativeCombat is off

Hull_damage = (Expl_Power * Eff_HullDamageScaling) / (Mass + 1)
         if AllowAlternativeCombat is on
            = Trunc(1.5 + (Shield_damage * Eff_HullDamageScaling
                             / (Mass + 1))
         if AllowAlternativeCombat is off

Crew_killed = (Kill_Power * Eff_CrewKillScaling) / (Mass + 1)
         if AllowAlternativeCombat is on
            = Trunc(above + 0.5)
         if AllowAlternativeCombat is off
         ...at least 1 if AllowAlternativeCombat is off and
            the weapon emits Death Rays.

Eff_XXX means the effective value of a configuration option, which consists of the actual configuration value plus any experience modifier of the unit being hit (these are the defensive bonuses).

Back to top


Ion Storms

Ion storm classes are described in the Rules section.

Movement

Speed   = 8              ...if Voltage > 250
          6              ...if Radius < 200
          2 + Random(3)  ...otherwise, i.e. random between 2 and 4
Heading = Old_heading - 10 + Random(21)
                         ...i.e. change by +/- 10 degrees

Growing Storms

Voltage_change =
   2 * Random(6)
   ...i.e. 0 to 10 in steps of two
Radius_change =
   Random(4)
   ...i.e. 0 to 3
New_voltage =
   Old_voltage + Voltage_change + Additional_gain

New_radius =
   Old_radius - Radius_change
   ...if Old_radius > Radius_change
   1 - (Old_radius - Radius_change)
   ...otherwise

The Additional_gain consists of four bonuses that are given to each storm. Note that, because growing storms always have odd voltages, adding one will turn the storm into a weakening one. All four conditions are checked, so the bonus may be anything between zero and four.

Additional_gain =
   +1   ...if second rule was used for New_radius
   +1   ...with a 1% chance
   +1   ...with a 2.5% chance if New_voltage > 320
   +1   ...with a 10% chance if New_voltage > 500

Weakening Storms

Voltage_change =
   4 + 2 * Random(6)
   ...i.e. 4 to 14 in steps of two
Radius_change =
   Random(11)
   ...i.e. 0 to 10
New_voltage =
   Old_voltage - Voltage_change
   ...Storm disappears if this is zero or less
New_radius =
   Old_radius + Radius_change

Pancaking Effect: The pancaking effect has a probability of 1:33 to occur, and happens after normal radius and voltage changes. This may change the storm into a growing one.

Voltage_after_pancaking =
   Round(Sqrt(New_voltage))
Radius_after_pancaking =
   2 * New_radius

Merging storms

Storms Id_1 and Id_2 merge if they partially overlap: Distance_of_centers^2 <= Radius_1^2 + Radius_2^2.

New_X =
    Trunc((X_1 * Voltage_1 + X_2 * Voltage_2) / (Voltage_1 + Voltage_2))
New_Y =
    Trunc((Y_1 * Voltage_1 + Y_2 * Voltage_2) / (Voltage_1 + Voltage_2))
    ...i.e. weighed average; closer to center of stronger storm
New_Radius =
    Trunc(Sqrt(Radius_1^2 + Radius_2^2))
    ...i.e. the storm is larger than each of the original ones
New_voltage =
    Trunc((Voltage_1 * Radius_1^2 + Voltage_2 * Radius_2^2) / (Radius_1^2 + Radius_2^2))
    ...i.e. weighed average

The Id of the new storm is the same as the Id of the stronger storm; if they are equally strong, it is the higher of the two. The new heading and speed are taken from that storm.

Whether the new storm is growing or weakening depends upon whether the computed New_voltage is odd or even.

Effects

Ships: All storms de-cloak ships that don't have advanced cloaking. Storms stronger than 150 MeV affect all ships that do not cloak or were thus uncloaked, and which do not have an Ion Shield.

Ship_dragged_distance =
   0.75 * Storm_warp^2
Ship_dragged_heading =
   Storm_heading
Ship_damage_taken =
   (Random(200) + Storm_voltage - Ship_mass - 20 * Ship_engine) * Exp_modificator
   ...with Exp_modificator =
         1        ...if NumExperienceLevels = 0
         1 - (Ship_experience_level / NumExperienceLevels)
                  ...otherwise
   ...plus 50 if ship does not have fuel
   ...at least zero, of course
Ship_damage =
   Ship_damage + Ship_damage_taken
Ship_crew =
   Trunc(Ship_crew * (100 - Ship_damage_taken) / 100)
Ship_experience_gain =
   Trunc(EPShipIonStorm100MEV * (Storm_voltage - 100) / 100)

Back to top


This document is maintained by The Portable Host Project[Remote] (support@phost.de).

Last updated 03 September 2006.