© |
Detailed Operation
|
This file contains details regarding the inner workings of PHOST. If you believe that some aspect of PHOST operation should be documented in this file but it is not, then please send e-mail to the PHOST support team and bring this to our attention.
PHOST performs the following events in sequence. The phase numbers (1, 2, and 3) refer to broad stages of host processing. Phase 1 represents the processing of TRN files, phase 2 represents the bulk of host processing, phase 3 represents the generation of RST files. AUXHOST 1 programs run between phase 1 and phase 2, while AUXHOST 2 programs run betweeen phase 2 and phase 3.
COL | Colonists on a planet |
CLANS | Clans on a planet or ship (COL / 100) |
NAT | Natives on a planet |
NATCLANS | Native clans on a planet (NAT / 100) |
F | Factories |
M | Mines |
DP | Planetary defense posts |
BDP | Base defense posts |
PDAMAGE | Planetary damage during combat |
SUP | Supplies |
MC | Megacredits |
FC | Friendly code |
CTAX | Colonist tax rate (%) |
NTAX | Native tax rate (%) |
NATGOV | Native government (1=Anarchy, 9=Unity) |
CHAPPY | Colonist happiness (-300 to 100) |
NHAPPY | Native happiness (-300 to 100) |
TEMP | Planet temperature |
ABS(X) | Absolute value of X |
ARCTAN(Y,X) | Four-quadrant arctangent of Y/X |
COS(X) | Cosine of argument (argument is in radians) |
DIST(X,Y) | Distance in LY from X to Y |
ERND(X) | Round floating point to nearest integer. Values that have a fractional part of exactly 0.5 are rounded to the nearest even integer (e.g., 8.5 becomes 8, 9.5 becomes 10) |
EXP(X) | Exponential function of X (i.e., 2.71828^X) |
MAX(A,B) | Maximum of A and B |
MIN(A,B) | Minimum of A and B |
RAND(N) | Random integer in the range 0 to N-1 inclusive |
RND(X) | Round floating point number to nearest integer |
SGN(X) | Sign of X (+1 if positive, -1 if negative, else 0) |
SIN(X) | Sine of argument (argument is in radians) |
SQRT(X) | Square root of X |
TRUNC(X) | Truncate floating point by discarding fractional part |
X^N | X to the Nth power |
cfg_XXXX | This notation represent the configuration option XXXX |
Colonist/native populations are generally expressed as number of persons, not clans. When a formula yields a number of colonists/natives which is not evenly divisible by 100, the result is rounded down. Unless specified otherwise, PHOST truncates results.
COL survived after meteor strike = COL * (RAND(91) + 10) / 100 NAT survived after meteor strike = NAT * (RAND(100) + 1) / 100 CHAPPY after meteor strike = CHAPPY - (RAND(31) + 50) NHAPPY after meteor strike = NHAPPY - (RAND(31) + 50) NHAPPY after combat in which planet was lost = NHAPPY - 20 COL after Klingon pillage = TRUNC(0.8*COL - 2000) CHAPPY after Klingon pillage = CHAPPY - 10 NAT after Klingon pillage = TRUNC(0.8*NAT - 12000) NHAPPY after Klingon pillage = NHAPPY - 10 SUP generated by Klingon pillage = TRUNC((COL+NAT) / 10000) MC generated by Klingon pillage = TRUNC((COL+NAT) / 10000) (COL and NAT are populations present *before* reduction) CHAPPY after Rebel RGA = CHAPPY - 60 NHAPPY after Rebel RGA = NHAPPY + 40 MC after Rebel RGA = TRUNC(MC*7/10) SUP after Rebel RGA = TRUNC(SUP*6/10) DP after Rebel RGA = TRUNC(DP*8/10) M after Rebel RGA = TRUNC(M*4/10) F after Rebel RGA = TRUNC(F*7/10) COL after Rebel RGA = TRUNC(COL*8/10) Minerals mined = ROUND(MINING_RATE * M / 100) MINING_RATE = ROUND((cfg_RaceMiningRate * MINERAL_DENSITY) / 100) If at least 100 Reptilian natives are present, MINING_RATE = MINING_RATE * 2 PHost before version 3.5 used TRUNC instead of ROUND in this formula. Colonist supply contribution = F Bovinoid supply contribution = MIN(NATCLANS / 100, CLANS), if planet has Bovinoids = 0, otherwise Total supplies collected = = TRUNC((COLONIST_SUPPLIES+BOVINOID_SUPPLIES) * cfg_ProductionRate / 100) Minerals from TUDR = TRUNC((cfg_TransuraniumDecayRate * MINERAL_DENSITY + 50) / 100) Natives assimilated = MIN(COL * cfg_BorgAssimilationRate / 100, NAT) TargetTemp = 100 if planet is Crystal and cfg_CrystalsPreferDeserts is ON = 50 TempDivisor = 66 if planet is Crystal and cfg_CrystalsPreferDeserts is ON = 33 CHAPPY change = TRUNC(10 - SQRT(CLANS/10000.0) - ABS(TEMP-TargetTemp)/TempDivisor - (M+F)/300 - CTAX*0.8) NHAPPY change = TRUNC(5 + NATGOV/2 - SQRT(NATCLANS/10000.0) - (M+F)/200 - NTAX*0.85) If natives are Avian, NHAPPY change = NHAPPY change + 10 CHAPPY/NHAPPY change from Hissing = (Number of Hissing ships)*cfg_HissEffectRate (Note that hissing happens before taxation; after the hiss effect increases happiness, taxation will it bring down again) MC from colonist tax = 0, if CHAPPY < 30 = TRUNC((CLANS * CTAX * 5 + 2500) / 5000) if CHAPPY >= 30 ...then MC = TRUNC((MC * cfg_ColonistTaxRate + 50) / 100) MC from native tax = = 0, if NHAPPY < 30 or natives are Amorphous = MIN(TRUNC((NATCLANS * NATGOV * NTAX + 2500) / 5000), CLANS) ...then MC = MC * 2 if natives are Insectoid ...then MC = TRUNC((MC * cfg_NativeTaxRate + 50) / 100) Max COL Supply Bonus = 0, if cfg_AllowEatingSupplies is OFF = TRUNC(100*SUP/40), if cfg_AllowEatingSupplies is ON Base Max COL on planet = MAX(10 000 000*sin(TEMP * 3.14159 / 200), 100) if planet is Crystalline and cfg_CrystalsPreferDeserts is ON and cfg_CrystalSinTempBehavior is ON and TEMP >= 15 = 300 + cfg_MaxColTempSlope*TEMP if planet is Crystalline and cfg_CrystalsPreferDeserts is ON and cfg_CrystalSinTempBehavior is ON and TEMP < 15 = MAX(100 000*TEMP, 100) if planet is Crystalline and cfg_CrystalsPreferDeserts is ON and cfg_CrystalSinTempBehavior is OFF = 9000000 if TEMP < 20 and planet is Rebel = 300 + cfg_MaxColTempSlope*TEMP if TEMP < 15 = at least 6000 if TEMP > 84 and planet is Klingon, Robotic, Rebel, or Colonial = 100 + (100 - TEMP)*cfg_MaxColTempSlope if TEMP > 84 = SIN(TEMP * 3.14159 / 100) * 10 000 000 if TEMP >= 15 and TEMP <= 84 Max COL on planet = 25 000 000 if cfg_ClimateLimitsPopulation is OFF = TRUNC(BASE_MAX_COL) + TRUNC(MAX_COL_SUPPLY_BONUS) Max NAT on planet = 15 600 000 if cfg_ClimateLimitsPopulation is OFF = (100 000 * TEMP) if natives are Siliconoid and CrystalsPreferDeserts is ON and PHost 3.3c or later = sin(TEMP * 3.14159 / 100) * 15 600 000 COL_GROWTH_RATE = 0 if CHAPPY < 70 or COL >= Max COL on Planet = 0 if planet is Crystalline and cfg_CrystalsPreferDeserts is ON and cfg_CrystalSinTempBehavior is ON and TEMP < 15 = 5*SIN(TEMP * 3.14159 / 200) / (1 + CTAX/5) if planet is Crystalline and cfg_CrystalsPreferDeserts is ON and cfg_CrystalSinTempBehavior is ON and TEMP >= 15 = 5 * (TEMP / 100) / (1 + CTAX/5) if planet is Crystalline and cfg_CrystalsPreferDeserts is ON and cfg_CrystalSinTempBehavior is OFF = 0, if TEMP < 15 or or TEMP > 84 = 5*SIN(TEMP * 3.14159 / 100) / (1 + CTAX/5) COL growth = = RND(COL_GROWTH_RATE * COL / 10000) * cfg_RaceGrowthRate IF (COL growth + COL > Max COL on Planet) THEN COL growth = Max COL on Planet - COL COL climate deaths = (COL - 25 000 000) if COL > 25 000 000 = 0, if cfg_ClimateLimitsPopulation is OFF = 0, if COL <= Max COL on planet = TRUNC(COL * cfg_ClimateDeathRate / 100) If (COL - COL climate deaths < Max COL on planet): COL climate deaths = COL - Max COL on planet If (COL_climate_deaths < 100): COL climate deaths = 0 Overpopulation supply loss = 0, if cfg_ClimateLimitsPopulation is OFF = 0, if COL <= BASE_MAX_COL_ON_PLANET = MIN(TRUNC((COL-BASE_MAX_COL_ON_PLANET)/4000)+1,SUP) NAT_GROWTH_RATE = 0 if NHAPPY < 70 = 4*(TEMP/100) / (1 + NTAX/5) if natives are Siliconoids and cfg_CrystalsPreferDeserts is ON and PHost 3.3c or later = 4*SIN(TEMP * 3.14159 / 100) / (1 + NTAX/5) NAT growth = 0, if planet is unowned = (NAT_GROWTH_RATE * NAT + 50) / 100 if (NAT growth + NAT > Max NAT on Planet) THEN NAT growth = Max NAT on Planet - NAT NAT climate deaths = (25 000 000 - NAT) if NAT > 25 000 000 = 0, if cfg_ClimateLimitsPopulation is OFF = 0, if planet is unowned = 0, if NAT < Max NAT on planet = TRUNC((NAT * cfg_NativeClimateDeathRate) / 100) If (NAT - NAT_climate_deaths < Max NAT on planet): NAT climate deaths = NAT - Max NAT on planet Max M on planet = CLANS, if CLANS < 200 = RND(200 + SQRT(CLANS - 200)) Max F on planet = CLANS, if CLANS < 100 = RND(100 + SQRT(CLANS - 100)) Max DP on planet = CLANS, if CLANS < 50 = RND(50 + SQRT(CLANS - 50)) COL deaths from Amorphous natives = 500, if NHAPPY >= 70 = 2000, if NHAPPY >= 50 = 4000, if NHAPPY < 50 deaths = MIN(deaths, COL) COL deaths from fighting = COL * (40 - CHAPPY) / 500, if CHAPPY < 20 = COL * (40 - NHAPPY) / 2500, if NHAPPY < 20 NAT deaths from fighting = NAT * (40 - NHAPPY) / 500, if NHAPPY < 20 = NAT * (40 - CHAPPY) / 2500, if CHAPPY < 20 % chance that planet is detected on sensor sweep = = 0, if DP >= cfg_DefenseForUndetectable = 0, if (M < cfg_MinesForDetectable) AND (F < cfg_FactoriesForDetectable) = 100% * (cfg_DefenseForUndetectable - DP) / cfg_DefenseForUndetectable Planet industrial activity = "minimal", if (M+F) < 30 = "light", if (M+F) < 60 = "moderate", if (M+F) < 90 = "substantial", if (M+F) < 120 = "heavy", if (M+F) >= 120
Fuel needed to remain cloaked = 1 KT after movement phase = CLOAK_FUEL_BURN+1 KT before movement phase CLOAK_FUEL_BURN = 0 if ship has advanced cloaking device = TRUNC(MAX(ShipHullMass, 100) * cfg_CloakFuelBurn / 100) UnitsPerTorp = TRUNC(TorpType^2 * MIN(cfg_UnitsPerTorpRate[ShipOwner], cfg_UnitsPerTorpRate[MinefieldOwner]) / 100) MAX_TORPS_TO_LAY = 0, if UnitsPerTorp is 0 = TRUNC((cfg_MaximumMinefieldRadius^2 - MinefieldRadius^2) / UnitsPerTorp) Units laid in minefield = UnitsPerTorp*MIN(Torps, MAX_TORPS_TO_LAY) Torps to scoop = MinefieldRadius^2, if UnitsPerTorp is 0 = TRUNC(MinefieldRadius^2 / UnitsPerTorp) NOTE: If the number of torps created by scooping (as limited by cargo room) actually equals TorpsToScoop, then the minefield vanishes (i.e., minefield units leading to fractional torps are lost if the minefield is completely swept). Mine units swept = TRUNC(BeamType^2 * BeamNumber * cfg_MineSweepRate) = above + (NumFighters * cfg_FighterSweepRate) if ship is in range and (minefield is not a web mine field or (ship is Colonial and cfg_AllowColoniesSweepWebs is ON)) Minerals reclaimed from colonizing ship = = TRUNC((HullMineral + NumEngines*EngineMineral + NumBeams*BeamMineral + NumTubes*TubeMineral) * cfg_RecycleRate / 100) Colonists on planet after colonize mission = = 100*(TRUNC(ShipCrew/100) + 1) Max ship speed (warp) = 15 - TRUNC(ShipDamage / 10) if Lizards = 10 - TRUNC(ShipDamage / 10) Fuel consumption rate = EngineFuelConsumption / 200 000 if ship hull is gravitonic = EngineFuelConsumption / 100 000 Fuel consumption = TRUNC(ERND((FuellessShipMass+ShipFuel)/10) * 10*FUEL_CONSUMPTION_RATE * TRUNC(DistanceToTravel)) if cfg_UseAccurateFuelModel is OFF = RND((FuellessShipMass+ShipFuel) * (1 - EXP(-FUEL_CONSUMPTION_RATE * DistanceToTravel))) if cfg_UseAccurateFuelModel is ON EngineFuelConsumption is derived from value from ENGSPEC.DAT and is tabulated in Eden Tan's Infolist. It is reproduced here for convenience (note that this only applies to the original ship list):
Fuel Usage | Warp 1 | Warp 2 | Warp 3 | Warp 4 | Warp 5 | Warp 6 | Warp 7 | Warp 8 | Warp 9 |
---|---|---|---|---|---|---|---|---|---|
StarDrive 1 | 100.00 | 200.00 | 300.00 | 400.00 | 500.00 | 600.00 | 700.00 | 800.00 | 900.00 |
StarDrive 2 | 100.00 | 107.50 | 300.00 | 400.00 | 500.00 | 600.00 | 700.00 | 800.00 | 900.00 |
StarDrive 3 | 100.00 | 106.25 | 107.78 | 337.50 | 500.00 | 600.00 | 700.00 | 800.00 | 900.00 |
SuperStarDrv 4 | 100.00 | 103.75 | 104.44 | 106.25 | 300.00 | 322.22 | 495.92 | 487.50 | 900.00 |
Nova Drive 5 | 100.00 | 103.75 | 104.44 | 106.25 | 104.00 | 291.67 | 291.84 | 366.41 | 900.00 |
HeavyNova Drv 6 | 100.00 | 103.75 | 104.44 | 106.25 | 104.00 | 103.69 | 251.02 | 335.16 | 900.00 |
Quantam Drive 7 | 100.00 | 103.75 | 104.44 | 106.25 | 104.00 | 103.69 | 108.16 | 303.91 | 529.63 |
Hyper Drive 8 | 100.00 | 100.00 | 100.00 | 100.00 | 100.00 | 100.00 | 102.04 | 109.38 | 529.63 |
Transwarp Drive | 100.00 | 100.00 | 100.00 | 100.00 | 100.00 | 100.00 | 100.00 | 100.00 | 100.00 |
Mine hit damage = TRUNC(100 * cfg_MineHitDamageFor100KT / ShipHullMass) Web hit damage = TRUNC(100 * cfg_WebHitDamageFor100KT / ShipHullMass) Ground attack attack factor = cfg_GroundKillFactor Ground attack defense factor = cfg_GroundDefenseFactor + PlanetDefense/20 Ground attack discriminant = AttackColonists*GROUND_ATTACK_FACTOR - DefenseColonists*GROUND_DEFENSE_FACTOR Planet colonists remaining after ground attack = = GROUND_ATTACK_DISCRIMINANT / GROUND_ATTACK_FACTOR if GROUND_ATTACK_DISCRIMINANT >= 0 (attackers win) = -GROUND_ATTACK_DISCRIMINANT / GROUND_DEFENSE_FACTOR if GROUND_ATTACK_DISCRIMINANT < 0 (defenders win)
Minefield units after decay = = TRUNC(CurrentUnits * (100 - cfg_MineDecayRate) / 100) for mines = TRUNC(CurrentUnits * (100 - cfg_WebMineDecayRate) / 100) for webs Web drain fuel loss = MIN(cfg_WebDrainFuelLoss, ShipFuel) Web hit fuel loss = MIN(MAX(50, ShipFuel/6), ShipFuel) Minefields exploding: D = DIST( Mine1, Mine2 ), the distance between 2 minefield centers R1 = SQRT( MineUnits1 ), the radii of the minefields R2 = SQRT( MineUnits2 ) IF (D > (R1+R2)) THEN Mines exploding = 0 ELSE IF (D is 0) THEN Mines exploding = MineUnits1 if R1 < R2 = MineUnits2 if R2 <= R1 ELSE A = (R1*R1 - R2*R2 + D*D) / (2*D) IF (A < 0) THEN Mines exploding = MineUnits1 ELSE IF (A > D) THEN Mines exploding = MineUnits2 ELSE Mines exploding = R1*R1 - A*A ENDIF ENDIF When you use AlternativeMinesDestroyMines (i.e. the only possible method in PHost up to 3.4e), PHost will try this formula for all minefields which overlap the new one, in Id order. The new method uses essentially the same formulas, but in a differential fashion to correctly handle multiple overlaps at once.
Base tech maximum after damage (a.k.a. BaseDamageTech(TECH) ) = = MAX(MIN( (100-BaseDamage)/10, BaseTech(TECH) ), 1) PLANET_COMBAT_DEFENSE = TRUNC(DP * (100-PDAMAGE) / 100) BASE_COMBAT_DEFENSE = TRUNC(BDP * (100-PDAMAGE) / 100) TOTAL_COMBAT_DEFENSE = TRUNC((DP + BDP) * (100-PDAMAGE) / 100) (damage-scaled planetary/starbase defense post count) Planet combat mass = 100 + PLANET_COMBAT_DEFENSE = above + BASE_COMBAT_DEFENSE if starbase present Planet beam type = RND(PLANET_COMBAT_DEFENSE / 2) if no base = MAX(above, BaseDamageTech(BEAMS)) if base present Planet beam number = MIN(RND(SQRT(TOTAL_COMBAT_DEFENSE / 3)), 20) if cfg_AllowAlternativeCombat is ON = MIN(RND(SQRT(TOTAL_COMBAT_DEFENSE / 3)), 10) if cfg_AllowAlternativeCombat is OFF Planet torp type = RND(PLANET_COMBAT_DEFENSE / 2) if no base = MAX(above, BaseDamageTech(TORPS)) if base present Planet tube number = MIN(RND(SQRT(TOTAL_COMBAT_DEFENSE / 4)), 20) Planet torp number = PLANET_TUBE_NUMBER * cfg_PlanetaryTorpsPerTube = above + BASE_TORPS if base is present and UseBaseTorpsInCombat is enabled. BASE_TORPS is calculated according to the following algorithm: EQUIVCOST = 0 FOR Type=1 TO 10 EQUIVCOST = EQUIVCOST + TorpsInStorage(Type)*TorpMoneyCost(Type) ENDFOR BASE_TORPS = EQUIVCOST / TorpMoneyCost(PLANET_TORP_TYPE) A planet can have at most 255 torpedoes. Torps removed from base storage after combat are calculated as follows: COST_OF_TORPS = TorpsFiredInBattle * TorpMoneyCost(PLANET_TORP_TYPE) WHILE (COST_OF_TORPS > 0) DONE=1 FOR TYPE=1 to 10 IF ( BaseTorps(TYPE) > 0 AND TorpMoneyCost(TYPE) <= COST_OF_TORPS ) COST_OF_TORPS = COST_OF_TORPS - TorpMoneyCost(TYPE) BaseTorps(TYPE) = BaseTorps(TYPE) - 1 DONE=0 ENDIF ENDFOR IF (DONE) STOP ENDWHILE Planet bay number = MIN(RND(SQRT(PLANET_COMBAT_DEFENSE)), 50) if no base = MIN(above+5, 50) if base present Planet fighters = RND(SQRT(PLANET_COMBAT_DEFENSE)) if no base = above + BaseFighters if base present NAT after combat in which planet is conquered = = TRUNC(NAT*cfg_NativeCombatSurvivalRate/100)
Ship shields = TRUNC((300 - 2*ShipDamage)/3) if ship is Lizard = TRUNC(100 - ShipDamage) Ship mass = ShipHullMass + TRUNC(ENGINE_TECH_BONUS*cfg_EngineShieldBonusRate/100) if cfg_AllowEngineShieldBonus is ON and (ship is fighting a ship, or cfg_AllowESBonusAgainstPlanets is ON) = ShipHullMass otherwise = above + 50 if ship is Federation and cfg_AllowFedCombatBonus is ON If cfg_PALIncludesESB is ON (hardwired on PHost 3.3d or earlier), the ship mass computed here is used for PAL computations. Otherwise, only the ShipHullMass is used for PALs. ENGINE_TECH_BONUS = cost (in megacredits) of building 1 engine of the same type as the ship's engines DamageScale = 150 if ship is Lizard = 100 otherwise Ship beam number = = ShipBeams if ship is Federation and cfg_AllowFedCombatBonus is ON = MIN(ShipBeams, MaxHullBeams-TRUNC(MaxHullBeams*ShipDamage/DamageScale)) Ship bay number = = ShipBays if ship is Federation and cfg_AllowFedCombatBonus is ON = MIN(ShipBays, MaxShipBays-TRUNC(MaxShipBays*ShipDamage/DamageScale)) Ship tube number = ShipTubes if ship is Federation and cfg_AllowFedCombatBonus is ON = MIN(ShipTubes, MaxHullTubes-TRUNC(MaxHullTubes*ShipDamage/DamageScale)) Beam hit odds = cfg_BeamHitOdds + TRUNC((BeamKillPower+BeamSmashPower)*cfg_BeamHitBonus/100) Torp hit odds = cfg_TorpHitOdds + TRUNC((TorpKillPower+TorpSmashPower)*cfg_TorpHitBonus/100) Beam recharge rate = cfg_BeamRechargeRate + TRUNC((BeamKillPower + BeamSmashPower) * cfg_BeamRechargeBonus / 100) Bay recharge rate = cfg_BayRechargeRate + cfg_BayRechargeBonus*NumBays Tube recharge rate = cfg_TubeRechargeRate + TRUNC((TorpKillPower + TorpSmashPower) * cfg_TubeRechargeBonus / 100) Damage to shields = (SmashPower * cfg_ShieldDamageScaling) / (Mass + 1) if cfg_AllowAlternativeCombat is ON = TRUNC(above + 1.5) if cfg_AllowAlternativeCombat is OFF Damage to hull = (SmashPower * cfg_HullDamageScaling) / (Mass + 1) if cfg_AllowAlternativeCombat is ON = TRUNC((DAMAGE_TO_SHIELDS * cfg_HullDamageScaling) / (Mass + 1) + 1.5) if cfg_AllowAlternativeCombat is OFF Crew killed = (KillPower * cfg_CrewKillScaling) / (Mass + 1) if cfg_AllowAlternativeCombat is ON = TRUNC(above + 0.5) if cfg_AllowAlternativeCombat is OFF
A torpedo or beam with a SmashPower of 0 emits "death rays". Those do no damage to shields or to the hull, but immediately kill crew. The formula remains the same as above, EXCEPT that it kills at least one crew member for each hit in Tim combat.
; "Special Missions 1" CHAPPY = MIN(CHAPPY + HISS_EFFECT, 100) NHAPPY = MIN(NHAPPY + HISS_EFFECT, 100) ; ... much later, after movement: IF (Planet is captured in combat) THEN ;can occur multiple times if planet is captured more than once NHAPPY = NHAPPY - 20 ENDIF ; after terraforming, RGA and Pillage ... IF CHAPPY < 30 AND CTAX > 0 THEN CTAX = 0 ;Colonists refuse to pay taxes ENDIF CHAPPY = CHAPPY + COLONIST_HAPPY_CHANGE IF CHAPPY < 20 THEN ;Civil war ELSE IF CHAPPY < 40 THEN ;Riots ENDIF IF CLANS == 0 THEN CTAX = 0 NTAX = 0 ENDIF IF NHAPPY < 30 AND NTAX > 0 THEN NTAX = 0 ;Natives refuse to pay taxes ENDIF NHAPPY = NHAPPY + NATIVE_HAPPY_CHANGE IF NHAPPY < 20 THEN ;Native civil war ELSE IF NHAPPY < 40 THEN ;Native riots ENDIF
COL = COL - COL_CLIMATE_DEATHS NAT = NAT - NAT_CLIMATE_DEATHS SUP = SUP - OVERPOPULATION_SUPPLY_LOSS M = M - STRUCTURE_DECAY_LOSS F = F - STRUCTURE_DECAY_LOSS DP = DP - STRUCTURE_DECAY_LOSS IF CHAPPY < 40 OR NHAPPY < 40 THEN M = M - 10 F = F - 10 ENDIF COL = COL - COL_FIGHTING_DEATHS NAT = NAT - NAT_FIGHTING_DEATHS COL = COL - AMORPHOUS_LOSSES
Ship starting co-ordinates = (Xs, Ys) Ship waypoint co-ordinates = (Xw, Yw) Start-to-waypoint distance = D = DIST(startpoint,waypoint) Actual travel distance = T = MIN(D, ShipSpeed*ShipSpeed*GravFactor) (where GravFactor = 2 for gravitonic ships, GravFactor = 1 for all other ships) Ship heading = ARCTAN(Yw-Ys, Xw-Xs) (HEADING) IF T == D THEN New ship location = (Xw, Yw) ELSE Ship displacement (floating point) = (T*COS(HEADING), T*SIN(HEADING)) = (Xdf, Ydf) IF Xw == Xs THEN Xdf = 0 ENDIF IF Yw == Ys THEN Ydf = 0 ENDIF Ship displacement (integer) = (ROUNDUP(Xdf), ROUNDUP(Ydf)) = (Xsi, Ysi) New ship location = (Xs+Xsi, Ys+Ysi) ENDIF ROUNDUP(Q) rounds number Q towards the next larger integer, preserving the sign: ROUNDUP(0) = 0 ROUNDUP(10.3) = 11 ROUNDUP(-10.3) = -11 ROUNDUP(11) = 11 ROUNDUP(-11) = -11 ROUNDUP(11.01) = 12 ROUNDUP(-11.01) = -12 ***NOTE: Ship locations are limited to the square (0,0)-(10000,10000). If an X or Y position of a ship exceeds the value 10000, it is reduced to 10000. If a position becomes negative, it is mapped to the value 10000.
Ship starting co-ordinates = (Xs, Ys) Ship waypoint co-ordinates = (Xw, Yw) DX = Xw-Xs DY = Yw-Ys DIST_TO_WAYPOINT = SQRT(DX*DX+DY*DY) IF (DIST_TO_WAYPOINT >= 340 AND DIST_TO_WAYPOINT <= 360) THEN New Location X = Xw New Location Y = Yw ELSE New Location X = Xs + SGN(DX)*TRUNC(350*ABS(DX)/SQRT(DX^2 + DY^2) + 0.4999999) New Location Y = Ys + SGN(DY)*TRUNC(350*ABS(DY)/SQRT(DX^2 + DY^2) + 0.4999999) ENDIF
Definitions: ShipX -- X co-ordinate of ship position before wraparound ShipY -- Y co-ordinate of ship position before wraparound NewShipX -- X co-ordinate of ship position after wraparound NewShipY -- Y co-ordinate of ship position after wraparound LowerLeftX -- X co-ordinate of lower-left corner of wrap region LowerLeftY -- Y co-ordinate of lower-left corner of wrap region UpperRightX -- X co-ordinate of upper-right corner of wrap region UpperRightY -- Y co-ordinate of upper-right corner of wrap region (these are the four numbers specified in cfg_WraparoundRectangle) DimX -- Length of wrap region along the X-axis (UpperRightX-LowerLeftX) DimY -- Length of wrap region along the Y-axis (UpperRightY-LowerLeftY) Movement Formulas: IF (ShipX < LowerLeftX) THEN NewShipX = ShipX + DimX ELSE IF (ShipX >= UpperRightX) THEN NewShipX = ShipX - DimX ENDIF IF (ShipY < LowerLeftY) THEN NewShipY = ShipY + DimY ELSE IF (ShipY >= UpperRightY) THEN NewShipY = ShipY - DimY ENDIF Note that PHost 3.3b and earlier had ">" in the UpperRightX and UpperRightY comparisons which caused ugly ambiguities.
Wormhole detection radius = D = 10 * WormholeMass^(1/3) Wormhole detection chance = 100% if DIST(ship,wormhole) <= D = (4 - (DIST(ship,wormhole)/D)^2) * 33.3% if D < DIST(ship,wormhole) <= 2D = 0% if DIST(ship,wormhole) > 2D Wormhole stress factor = (TotalShipMass/WormholeMass - 1)^2 (WRM_STRESS) if TotalShipMass >= WormholeMass = 0 if TotalShipMass < WormholeMass Wormhole passage failure chance = WRM_STRESS + WormholeInstability (WRM_FAILURE) + WRM_STRESS*WormholeInstability/10 (percent) Wormhole passage failure figure = RAND(100) (WRM_FAILFIG) Ship damage from wormhole passage failure = (WRM_FAILFIG - WRM_FAILURE)^2 if WRM_FAILFIG < WRM_FAILURE = 0 if WRM_FAILFIG >= WRM_FAILURE Wormhole entry radius = 0.5 * WormholeMass^(cfg_WrmEntryPowerX100/100) LY Ship exit point X (normal travel) = WRM_EXIT_X + RAND(21) - 10 Ship exit point Y (normal travel) = WRM_EXIT_Y + RAND(21) - 10 Ship exit point X (insufficient fuel) = RAND(2001) + 1000 Ship exit point Y (insufficient fuel) = RAND(2001) + 1000