summaryrefslogtreecommitdiff
path: root/src/uqm/planets/generate/gendefault.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/uqm/planets/generate/gendefault.c')
-rw-r--r--src/uqm/planets/generate/gendefault.c373
1 files changed, 373 insertions, 0 deletions
diff --git a/src/uqm/planets/generate/gendefault.c b/src/uqm/planets/generate/gendefault.c
new file mode 100644
index 0000000..a88b89c
--- /dev/null
+++ b/src/uqm/planets/generate/gendefault.c
@@ -0,0 +1,373 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "genall.h"
+#include "../planets.h"
+#include "../lander.h"
+#include "../../encount.h"
+#include "../../gamestr.h"
+#include "../../globdata.h"
+#include "../../grpinfo.h"
+#include "../../races.h"
+#include "../../state.h"
+#include "../../sounds.h"
+#include "libs/mathlib.h"
+
+
+static void GeneratePlanets (SOLARSYS_STATE *system);
+static void check_yehat_rebellion (void);
+
+
+const GenerateFunctions generateDefaultFunctions = {
+ /* .initNpcs = */ GenerateDefault_initNpcs,
+ /* .reinitNpcs = */ GenerateDefault_reinitNpcs,
+ /* .uninitNpcs = */ GenerateDefault_uninitNpcs,
+ /* .generatePlanets = */ GenerateDefault_generatePlanets,
+ /* .generateMoons = */ GenerateDefault_generateMoons,
+ /* .generateName = */ GenerateDefault_generateName,
+ /* .generateOrbital = */ GenerateDefault_generateOrbital,
+ /* .generateMinerals = */ GenerateDefault_generateMinerals,
+ /* .generateEnergy = */ GenerateDefault_generateEnergy,
+ /* .generateLife = */ GenerateDefault_generateLife,
+ /* .pickupMinerals = */ GenerateDefault_pickupMinerals,
+ /* .pickupEnergy = */ GenerateDefault_pickupEnergy,
+ /* .pickupLife = */ GenerateDefault_pickupLife,
+};
+
+
+bool
+GenerateDefault_initNpcs (SOLARSYS_STATE *solarSys)
+{
+ if (!GetGroupInfo (GLOBAL (BattleGroupRef), GROUP_INIT_IP))
+ {
+ GLOBAL (BattleGroupRef) = 0;
+ BuildGroups ();
+ }
+
+ (void) solarSys;
+ return true;
+}
+
+bool
+GenerateDefault_reinitNpcs (SOLARSYS_STATE *solarSys)
+{
+ GetGroupInfo (GROUPS_RANDOM, GROUP_LOAD_IP);
+ // This is not a great place to do the Yehat rebellion check, but
+ // since you can start the rebellion in any star system (not just
+ // the Homeworld), I could not find a better place for it.
+ // At least it is better than where it was originally.
+ check_yehat_rebellion ();
+
+ (void) solarSys;
+ return true;
+}
+
+bool
+GenerateDefault_uninitNpcs (SOLARSYS_STATE *solarSys)
+{
+ PutGroupInfo (GROUPS_RANDOM, GROUP_SAVE_IP);
+ ReinitQueue (&GLOBAL (npc_built_ship_q));
+ ReinitQueue (&GLOBAL (ip_group_q));
+
+ (void) solarSys;
+ return true;
+}
+
+bool
+GenerateDefault_generatePlanets (SOLARSYS_STATE *solarSys)
+{
+ FillOrbits (solarSys, (BYTE)~0, solarSys->PlanetDesc, FALSE);
+ GeneratePlanets (solarSys);
+ return true;
+}
+
+bool
+GenerateDefault_generateMoons (SOLARSYS_STATE *solarSys, PLANET_DESC *planet)
+{
+ FillOrbits (solarSys, planet->NumPlanets, solarSys->MoonDesc, FALSE);
+ return true;
+}
+
+bool
+GenerateDefault_generateName (const SOLARSYS_STATE *solarSys,
+ const PLANET_DESC *world)
+{
+ COUNT i = planetIndex (solarSys, world);
+ utf8StringCopy (GLOBAL_SIS (PlanetName), sizeof (GLOBAL_SIS (PlanetName)),
+ GAME_STRING (PLANET_NUMBER_BASE + (9 + 7) + i));
+ SET_GAME_STATE (BATTLE_PLANET, world->data_index);
+
+ return true;
+}
+
+bool
+GenerateDefault_generateOrbital (SOLARSYS_STATE *solarSys, PLANET_DESC *world)
+{
+ DWORD rand_val;
+ SYSTEM_INFO *sysInfo;
+
+#ifdef DEBUG_SOLARSYS
+ if (worldIsPlanet (solarSys, world))
+ {
+ log_add (log_Debug, "Planet index = %d",
+ planetIndex (solarSys, world));
+ }
+ else
+ {
+ log_add (log_Debug, "Planet index = %d, Moon index = %d",
+ planetIndex (solarSys, world),
+ moonIndex (solarSys, world));
+ }
+#endif /* DEBUG_SOLARSYS */
+
+ sysInfo = &solarSys->SysInfo;
+
+ DoPlanetaryAnalysis (sysInfo, world);
+ rand_val = RandomContext_GetSeed (SysGenRNG);
+
+ sysInfo->PlanetInfo.ScanSeed[BIOLOGICAL_SCAN] = rand_val;
+ GenerateLifeForms (sysInfo, GENERATE_ALL, NULL);
+ rand_val = RandomContext_GetSeed (SysGenRNG);
+
+ sysInfo->PlanetInfo.ScanSeed[MINERAL_SCAN] = rand_val;
+ GenerateMineralDeposits (sysInfo, GENERATE_ALL, NULL);
+
+ sysInfo->PlanetInfo.ScanSeed[ENERGY_SCAN] = rand_val;
+ LoadPlanet (NULL);
+
+ return true;
+}
+
+COUNT
+GenerateDefault_generateMinerals (const SOLARSYS_STATE *solarSys,
+ const PLANET_DESC *world, COUNT whichNode, NODE_INFO *info)
+{
+ return GenerateMineralDeposits (&solarSys->SysInfo, whichNode, info);
+ (void) world;
+}
+
+bool
+GenerateDefault_pickupMinerals (SOLARSYS_STATE *solarSys, PLANET_DESC *world,
+ COUNT whichNode)
+{
+ // Minerals do not need any extra handling as of now
+ (void) solarSys;
+ (void) world;
+ (void) whichNode;
+ return true;
+}
+
+COUNT
+GenerateDefault_generateEnergy (const SOLARSYS_STATE *solarSys,
+ const PLANET_DESC *world, COUNT whichNode, NODE_INFO *info)
+{
+ (void) whichNode;
+ (void) solarSys;
+ (void) world;
+ (void) info;
+ return 0;
+}
+
+bool
+GenerateDefault_pickupEnergy (SOLARSYS_STATE *solarSys, PLANET_DESC *world,
+ COUNT whichNode)
+{
+ // This should never be called since every energy node needs
+ // special handling and the function should be overridden
+ assert (false);
+ (void) solarSys;
+ (void) world;
+ (void) whichNode;
+ return false;
+}
+
+COUNT
+GenerateDefault_generateLife (const SOLARSYS_STATE *solarSys,
+ const PLANET_DESC *world, COUNT whichNode, NODE_INFO *info)
+{
+ return GenerateLifeForms (&solarSys->SysInfo, whichNode, info);
+ (void) world;
+}
+
+bool
+GenerateDefault_pickupLife (SOLARSYS_STATE *solarSys, PLANET_DESC *world,
+ COUNT whichNode)
+{
+ // Bio does not need any extra handling as of now
+ (void) solarSys;
+ (void) world;
+ (void) whichNode;
+ return true;
+}
+
+COUNT
+GenerateDefault_generateArtifact (const SOLARSYS_STATE *solarSys,
+ COUNT whichNode, NODE_INFO *info)
+{
+ // Generate an energy node at a random location
+ return GenerateRandomNodes (&solarSys->SysInfo, ENERGY_SCAN, 1, 0,
+ whichNode, info);
+}
+
+COUNT
+GenerateDefault_generateRuins (const SOLARSYS_STATE *solarSys,
+ COUNT whichNode, NODE_INFO *info)
+{
+ // Generate a standard spread of city ruins of a destroyed civilization
+ return GenerateRandomNodes (&solarSys->SysInfo, ENERGY_SCAN, NUM_RACE_RUINS,
+ 0, whichNode, info);
+}
+
+static inline void
+runLanderReport (void)
+{
+ UnbatchGraphics ();
+ DoDiscoveryReport (MenuSounds);
+ BatchGraphics ();
+}
+
+bool
+GenerateDefault_landerReport (SOLARSYS_STATE *solarSys)
+{
+ PLANET_INFO *planetInfo = &solarSys->SysInfo.PlanetInfo;
+
+ if (!planetInfo->DiscoveryString)
+ return false;
+
+ runLanderReport ();
+
+ // XXX: A non-cycling report is given only once and has to be deleted
+ // in some circumstances (like the Syreen Vault). It does not
+ // hurt to simply delete it in all cases. Nothing should rely on
+ // the presence of DiscoveryString, but the Syreen Vault and the
+ // Mycon Egg Cases rely on its absence.
+ DestroyStringTable (ReleaseStringTable (planetInfo->DiscoveryString));
+ planetInfo->DiscoveryString = 0;
+
+ return true;
+}
+
+bool
+GenerateDefault_landerReportCycle (SOLARSYS_STATE *solarSys)
+{
+ PLANET_INFO *planetInfo = &solarSys->SysInfo.PlanetInfo;
+
+ if (!planetInfo->DiscoveryString)
+ return false;
+
+ runLanderReport ();
+ // Advance to the next report
+ planetInfo->DiscoveryString = SetRelStringTableIndex (
+ planetInfo->DiscoveryString, 1);
+
+ // If our discovery strings have cycled, we're done
+ if (GetStringTableIndex (planetInfo->DiscoveryString) == 0)
+ {
+ DestroyStringTable (ReleaseStringTable (planetInfo->DiscoveryString));
+ planetInfo->DiscoveryString = 0;
+ }
+
+ return true;
+}
+
+// NB. This function modifies the RNG state.
+static void
+GeneratePlanets (SOLARSYS_STATE *solarSys)
+{
+ COUNT i;
+ PLANET_DESC *planet;
+
+ for (i = solarSys->SunDesc[0].NumPlanets,
+ planet = &solarSys->PlanetDesc[0]; i; --i, ++planet)
+ {
+ DWORD rand_val;
+ BYTE byte_val;
+ BYTE num_moons;
+ BYTE type;
+
+ rand_val = RandomContext_Random (SysGenRNG);
+ byte_val = LOBYTE (rand_val);
+
+ num_moons = 0;
+ type = PlanData[planet->data_index & ~PLANET_SHIELDED].Type;
+ switch (PLANSIZE (type))
+ {
+ case LARGE_ROCKY_WORLD:
+ if (byte_val < 0x00FF * 25 / 100)
+ {
+ if (byte_val < 0x00FF * 5 / 100)
+ ++num_moons;
+ ++num_moons;
+ }
+ break;
+ case GAS_GIANT:
+ if (byte_val < 0x00FF * 90 / 100)
+ {
+ if (byte_val < 0x00FF * 75 / 100)
+ {
+ if (byte_val < 0x00FF * 50 / 100)
+ {
+ if (byte_val < 0x00FF * 25 / 100)
+ ++num_moons;
+ ++num_moons;
+ }
+ ++num_moons;
+ }
+ ++num_moons;
+ }
+ break;
+ }
+ planet->NumPlanets = num_moons;
+ }
+}
+
+static void
+check_yehat_rebellion (void)
+{
+ HIPGROUP hGroup, hNextGroup;
+
+ // XXX: Is there a better way to do this? I could not find one.
+ // When you talk to a Yehat ship (YEHAT_SHIP) and start the rebellion,
+ // there is no battle following the comm. There is *never* a battle in
+ // an encounter with Rebels, but the group race_id (YEHAT_REBEL_SHIP)
+ // is different from Royalists (YEHAT_SHIP). There is *always* a battle
+ // in an encounter with Royalists.
+ // TRANSLATION: "If the civil war has not started yet, or the player
+ // battled a ship -- bail."
+ if (!GET_GAME_STATE (YEHAT_CIVIL_WAR) || EncounterRace >= 0)
+ return; // not this time
+
+ // Send Yehat groups to flee the system, but only if the player
+ // has actually talked to a ship.
+ for (hGroup = GetHeadLink (&GLOBAL (ip_group_q)); hGroup;
+ hGroup = hNextGroup)
+ {
+ IP_GROUP *GroupPtr = LockIpGroup (&GLOBAL (ip_group_q), hGroup);
+ hNextGroup = _GetSuccLink (GroupPtr);
+ // IGNORE_FLAGSHIP was set in ipdisp.c:ip_group_collision()
+ // during a collision with the flagship.
+ if (GroupPtr->race_id == YEHAT_SHIP
+ && (GroupPtr->task & IGNORE_FLAGSHIP))
+ {
+ GroupPtr->task &= REFORM_GROUP;
+ GroupPtr->task |= FLEE | IGNORE_FLAGSHIP;
+ GroupPtr->dest_loc = 0;
+ }
+ UnlockIpGroup (&GLOBAL (ip_group_q), hGroup);
+ }
+}
+
+