summaryrefslogtreecommitdiff
path: root/src/uqm/build.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/uqm/build.c')
-rw-r--r--src/uqm/build.c547
1 files changed, 547 insertions, 0 deletions
diff --git a/src/uqm/build.c b/src/uqm/build.c
new file mode 100644
index 0000000..070453a
--- /dev/null
+++ b/src/uqm/build.c
@@ -0,0 +1,547 @@
+//Copyright Paul Reiche, Fred Ford. 1992-2002
+
+/*
+ * 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 "build.h"
+
+#include "races.h"
+#include "master.h"
+#include "sis.h"
+#include "setup.h"
+#include "libs/compiler.h"
+#include "libs/mathlib.h"
+
+
+// Allocate a new STARSHIP or SHIP_FRAGMENT and put it in the queue
+HLINK
+Build (QUEUE *pQueue, SPECIES_ID SpeciesID)
+{
+ HLINK hNewShip;
+ SHIP_BASE *ShipPtr;
+
+ assert (GetLinkSize (pQueue) == sizeof (STARSHIP) ||
+ GetLinkSize (pQueue) == sizeof (SHIP_FRAGMENT));
+
+ hNewShip = AllocLink (pQueue);
+ if (!hNewShip)
+ return 0;
+
+ ShipPtr = (SHIP_BASE *) LockLink (pQueue, hNewShip);
+ memset (ShipPtr, 0, GetLinkSize (pQueue));
+ ShipPtr->SpeciesID = SpeciesID;
+
+ UnlockLink (pQueue, hNewShip);
+ PutQueue (pQueue, hNewShip);
+
+ return hNewShip;
+}
+
+HLINK
+GetStarShipFromIndex (QUEUE *pShipQ, COUNT Index)
+{
+ HLINK hStarShip, hNextShip;
+
+ for (hStarShip = GetHeadLink (pShipQ);
+ Index > 0 && hStarShip; hStarShip = hNextShip, --Index)
+ {
+ LINK *StarShipPtr;
+
+ StarShipPtr = LockLink (pShipQ, hStarShip);
+ hNextShip = _GetSuccLink (StarShipPtr);
+ UnlockLink (pShipQ, hStarShip);
+ }
+
+ return (hStarShip);
+}
+
+HSHIPFRAG
+GetEscortByStarShipIndex (COUNT index)
+{
+ HSHIPFRAG hStarShip;
+ HSHIPFRAG hNextShip;
+ SHIP_FRAGMENT *StarShipPtr;
+
+ for (hStarShip = GetHeadLink (&GLOBAL (built_ship_q));
+ hStarShip; hStarShip = hNextShip)
+ {
+ StarShipPtr = LockShipFrag (&GLOBAL (built_ship_q), hStarShip);
+
+ if (StarShipPtr->index == index)
+ {
+ UnlockShipFrag (&GLOBAL (built_ship_q), hStarShip);
+ break;
+ }
+
+ hNextShip = _GetSuccLink (StarShipPtr);
+ UnlockShipFrag (&GLOBAL (built_ship_q), hStarShip);
+ }
+
+ return hStarShip;
+}
+
+/*
+ * Give the player 'count' ships of the specified race,
+ * limited by the number of free slots.
+ * Returns the number of ships added.
+ */
+COUNT
+AddEscortShips (COUNT race, SIZE count)
+{
+ HFLEETINFO hFleet;
+ BYTE which_window;
+ COUNT i;
+
+ hFleet = GetStarShipFromIndex (&GLOBAL (avail_race_q), race);
+ if (!hFleet)
+ return 0;
+
+ assert (count > 0);
+
+ which_window = 0;
+ for (i = 0; i < (COUNT) count; i++)
+ {
+ HSHIPFRAG hStarShip;
+ HSHIPFRAG hOldShip;
+ SHIP_FRAGMENT *StarShipPtr;
+
+ hStarShip = CloneShipFragment (race, &GLOBAL (built_ship_q), 0);
+ if (!hStarShip)
+ break;
+
+ RemoveQueue (&GLOBAL (built_ship_q), hStarShip);
+
+ /* Find first available escort window */
+ while ((hOldShip = GetStarShipFromIndex (
+ &GLOBAL (built_ship_q), which_window++)))
+ {
+ BYTE win_loc;
+
+ StarShipPtr = LockShipFrag (&GLOBAL (built_ship_q), hOldShip);
+ win_loc = StarShipPtr->index;
+ UnlockShipFrag (&GLOBAL (built_ship_q), hOldShip);
+ if (which_window <= win_loc)
+ break;
+ }
+
+ StarShipPtr = LockShipFrag (&GLOBAL (built_ship_q), hStarShip);
+ StarShipPtr->index = which_window - 1;
+ UnlockShipFrag (&GLOBAL (built_ship_q), hStarShip);
+
+ InsertQueue (&GLOBAL (built_ship_q), hStarShip, hOldShip);
+ }
+
+ DeltaSISGauges (UNDEFINED_DELTA, UNDEFINED_DELTA, UNDEFINED_DELTA);
+ return i;
+}
+
+/*
+ * Returns the total value of all the ships escorting the SIS.
+ */
+COUNT
+CalculateEscortsWorth (void)
+{
+ COUNT ShipCost[] =
+ {
+ RACE_SHIP_COST
+ };
+ COUNT total = 0;
+ HSHIPFRAG hStarShip, hNextShip;
+
+ for (hStarShip = GetHeadLink (&GLOBAL (built_ship_q));
+ hStarShip; hStarShip = hNextShip)
+ {
+ SHIP_FRAGMENT *StarShipPtr;
+
+ StarShipPtr = LockShipFrag (&GLOBAL (built_ship_q), hStarShip);
+ hNextShip = _GetSuccLink (StarShipPtr);
+ total += ShipCost[StarShipPtr->race_id];
+ UnlockShipFrag (&GLOBAL (built_ship_q), hStarShip);
+ }
+ return total;
+}
+
+#if 0
+/*
+ * Returns the size of the fleet of the specified race when the starmap was
+ * last checked. If the race has no SoI, 0 is returned.
+ */
+COUNT
+GetRaceKnownSize (COUNT race)
+{
+ HFLEETINFO hFleet;
+ FLEET_INFO *FleetPtr;
+ COUNT result;
+
+ hFleet = GetStarShipFromIndex (&GLOBAL (avail_race_q), race);
+ if (!hFleet)
+ return 0;
+
+ FleetPtr = LockFleetInfo (&GLOBAL (avail_race_q), hFleet);
+
+ result = FleetPtr->known_strength;
+
+ UnlockFleetInfo (&GLOBAL (avail_race_q), hFleet);
+ return result;
+}
+#endif
+
+/*
+ * Start or end an alliance with the specified race.
+ * Being in an alliance with a race makes their ships available for building
+ * in the shipyard.
+ * flag == TRUE: start an alliance
+ * flag == TRUE: end an alliance
+ */
+COUNT
+SetRaceAllied (COUNT race, BOOLEAN flag) {
+ HFLEETINFO hFleet;
+ FLEET_INFO *FleetPtr;
+
+ hFleet = GetStarShipFromIndex (&GLOBAL (avail_race_q), race);
+ if (!hFleet)
+ return 0;
+
+ FleetPtr = LockFleetInfo (&GLOBAL (avail_race_q), hFleet);
+
+ if (FleetPtr->allied_state == DEAD_GUY)
+ {
+ /* Strange request, silently ignore it */
+ }
+ else
+ {
+ FleetPtr->allied_state = (flag ? GOOD_GUY : BAD_GUY);
+ }
+
+ UnlockFleetInfo (&GLOBAL (avail_race_q), hFleet);
+ return 1;
+}
+
+/*
+ * Make the sphere of influence for the specified race shown on the starmap
+ * in the future.
+ * The value returned is 'race', unless the type of ship is only available
+ * in SuperMelee, in which case 0 is returned.
+ */
+COUNT
+StartSphereTracking (COUNT race)
+{
+ HFLEETINFO hFleet;
+ FLEET_INFO *FleetPtr;
+
+ hFleet = GetStarShipFromIndex (&GLOBAL (avail_race_q), race);
+ if (!hFleet)
+ return 0;
+
+ FleetPtr = LockFleetInfo (&GLOBAL (avail_race_q), hFleet);
+
+ if (FleetPtr->actual_strength == 0)
+ {
+ if (FleetPtr->allied_state == DEAD_GUY)
+ {
+ // Race is extinct.
+ UnlockFleetInfo (&GLOBAL (avail_race_q), hFleet);
+ return 0;
+ }
+ }
+ else if (FleetPtr->known_strength == 0
+ && FleetPtr->actual_strength != INFINITE_RADIUS)
+ {
+ FleetPtr->known_strength = 1;
+ FleetPtr->known_loc = FleetPtr->loc;
+ }
+
+ UnlockFleetInfo (&GLOBAL (avail_race_q), hFleet);
+ return race;
+}
+
+/*
+ * Returns the number of ships of the specified race among the
+ * escort ships.
+ */
+COUNT
+CountEscortShips (COUNT race)
+{
+ HFLEETINFO hFleet;
+ HSHIPFRAG hStarShip, hNextShip;
+ COUNT result = 0;
+
+ hFleet = GetStarShipFromIndex (&GLOBAL (avail_race_q), race);
+ if (!hFleet)
+ return 0;
+
+ for (hStarShip = GetHeadLink (&GLOBAL (built_ship_q)); hStarShip;
+ hStarShip = hNextShip)
+ {
+ BYTE ship_type;
+ SHIP_FRAGMENT *StarShipPtr;
+
+ StarShipPtr = LockShipFrag (&GLOBAL (built_ship_q), hStarShip);
+ hNextShip = _GetSuccLink (StarShipPtr);
+ ship_type = StarShipPtr->race_id;
+ UnlockShipFrag (&GLOBAL (built_ship_q), hStarShip);
+
+ if (ship_type == race)
+ result++;
+ }
+ return result;
+}
+
+/*
+ * Returns true if and only if a ship of the specified race is among the
+ * escort ships.
+ */
+BOOLEAN
+HaveEscortShip (COUNT race)
+{
+ return (CountEscortShips (race) > 0);
+}
+
+/*
+ * Test if the SIS can have an escort of the specified race.
+ * Returns 0 if 'race' is not available.
+ * Otherwise, returns the number of ships that can be added.
+ */
+COUNT
+EscortFeasibilityStudy (COUNT race)
+{
+ HFLEETINFO hFleet;
+
+ hFleet = GetStarShipFromIndex (&GLOBAL (avail_race_q), race);
+ if (!hFleet)
+ return 0;
+
+ return (MAX_BUILT_SHIPS - CountLinks (&GLOBAL (built_ship_q)));
+}
+
+/*
+ * Test the alliance status of the specified race.
+ * Either DEAD_GUY (extinct), GOOD_GUY (allied), or BAD_GUY (not allied) is
+ * returned.
+ */
+COUNT
+CheckAlliance (COUNT race)
+{
+ HFLEETINFO hFleet;
+ UWORD flags;
+ FLEET_INFO *FleetPtr;
+
+ hFleet = GetStarShipFromIndex (&GLOBAL (avail_race_q), race);
+ if (!hFleet)
+ return 0;
+
+ FleetPtr = LockFleetInfo (&GLOBAL (avail_race_q), hFleet);
+ flags = FleetPtr->allied_state;
+ UnlockFleetInfo (&GLOBAL (avail_race_q), hFleet);
+
+ return flags;
+}
+
+/*
+ * Remove a number of escort ships of the specified race (if present).
+ * Returns the number of escort ships removed.
+ */
+COUNT
+RemoveSomeEscortShips (COUNT race, COUNT count)
+{
+ HSHIPFRAG hStarShip;
+ HSHIPFRAG hNextShip;
+
+ if (count == 0)
+ return 0;
+
+ for (hStarShip = GetHeadLink (&GLOBAL (built_ship_q)); hStarShip;
+ hStarShip = hNextShip)
+ {
+ BOOLEAN RemoveShip;
+ SHIP_FRAGMENT *StarShipPtr;
+
+ StarShipPtr = LockShipFrag (&GLOBAL (built_ship_q), hStarShip);
+ hNextShip = _GetSuccLink (StarShipPtr);
+ RemoveShip = (StarShipPtr->race_id == race);
+ UnlockShipFrag (&GLOBAL (built_ship_q), hStarShip);
+
+ if (RemoveShip)
+ {
+ RemoveQueue (&GLOBAL (built_ship_q), hStarShip);
+ FreeShipFrag (&GLOBAL (built_ship_q), hStarShip);
+ count--;
+ if (count == 0)
+ break;
+ }
+ }
+
+ if (count > 0)
+ {
+ // Update the display.
+ DeltaSISGauges (UNDEFINED_DELTA, UNDEFINED_DELTA, UNDEFINED_DELTA);
+ }
+
+ return count;
+}
+
+/*
+ * Remove all escort ships of the specified race.
+ */
+void
+RemoveEscortShips (COUNT race)
+{
+ RemoveSomeEscortShips (race, (COUNT) -1);
+}
+
+COUNT
+GetIndexFromStarShip (QUEUE *pShipQ, HLINK hStarShip)
+{
+ COUNT Index;
+
+ Index = 0;
+ while (hStarShip != GetHeadLink (pShipQ))
+ {
+ HLINK hNextShip;
+ LINK *StarShipPtr;
+
+ StarShipPtr = LockLink (pShipQ, hStarShip);
+ hNextShip = _GetPredLink (StarShipPtr);
+ UnlockLink (pShipQ, hStarShip);
+
+ hStarShip = hNextShip;
+ ++Index;
+ }
+
+ return Index;
+}
+
+BYTE
+NameCaptain (QUEUE *pQueue, SPECIES_ID SpeciesID)
+{
+ BYTE name_index;
+ HLINK hStarShip;
+
+ assert (GetLinkSize (pQueue) == sizeof (STARSHIP) ||
+ GetLinkSize (pQueue) == sizeof (SHIP_FRAGMENT));
+
+ do
+ {
+ HLINK hNextShip;
+
+ name_index = PickCaptainName ();
+ for (hStarShip = GetHeadLink (pQueue); hStarShip;
+ hStarShip = hNextShip)
+ {
+ SHIP_BASE *ShipPtr;
+ BYTE test_name_index = -1;
+
+ ShipPtr = (SHIP_BASE *) LockLink (pQueue, hStarShip);
+ hNextShip = _GetSuccLink (ShipPtr);
+ if (ShipPtr->SpeciesID == SpeciesID)
+ test_name_index = ShipPtr->captains_name_index;
+ UnlockLink (pQueue, hStarShip);
+
+ if (name_index == test_name_index)
+ break;
+ }
+ } while (hStarShip /* name matched another ship */);
+
+ return name_index;
+}
+
+// crew_level can be set to INFINITE_FLEET for a ship which is to
+// represent an infinite number of ships.
+HSHIPFRAG
+CloneShipFragment (COUNT shipIndex, QUEUE *pDstQueue, COUNT crew_level)
+{
+ HFLEETINFO hFleet;
+ HSHIPFRAG hBuiltShip;
+ FLEET_INFO *TemplatePtr;
+ BYTE captains_name_index;
+
+ assert (GetLinkSize (pDstQueue) == sizeof (SHIP_FRAGMENT));
+
+ hFleet = GetStarShipFromIndex (&GLOBAL (avail_race_q), shipIndex);
+ if (!hFleet)
+ return 0;
+
+ TemplatePtr = LockFleetInfo (&GLOBAL (avail_race_q), hFleet);
+ if (shipIndex == SAMATRA_SHIP)
+ captains_name_index = 0;
+ else
+ captains_name_index = NameCaptain (pDstQueue,
+ TemplatePtr->SpeciesID);
+ hBuiltShip = Build (pDstQueue, TemplatePtr->SpeciesID);
+ if (hBuiltShip)
+ {
+ SHIP_FRAGMENT *ShipFragPtr;
+
+ ShipFragPtr = LockShipFrag (pDstQueue, hBuiltShip);
+ ShipFragPtr->captains_name_index = captains_name_index;
+ ShipFragPtr->race_strings = TemplatePtr->race_strings;
+ ShipFragPtr->icons = TemplatePtr->icons;
+ ShipFragPtr->melee_icon = TemplatePtr->melee_icon;
+ if (crew_level)
+ ShipFragPtr->crew_level = crew_level;
+ else
+ ShipFragPtr->crew_level = TemplatePtr->crew_level;
+ ShipFragPtr->max_crew = TemplatePtr->max_crew;
+ ShipFragPtr->energy_level = 0;
+ ShipFragPtr->max_energy = TemplatePtr->max_energy;
+ ShipFragPtr->race_id = (BYTE)shipIndex;
+ ShipFragPtr->index = 0;
+ UnlockShipFrag (pDstQueue, hBuiltShip);
+ }
+ UnlockFleetInfo (&GLOBAL (avail_race_q), hFleet);
+
+ return hBuiltShip;
+}
+
+/* Set the crew and captain's name on the first fully-crewed escort
+ * ship of race 'which_ship' */
+int
+SetEscortCrewComplement (COUNT which_ship, COUNT crew_level, BYTE captain)
+{
+ HFLEETINFO hFleet;
+ FLEET_INFO *TemplatePtr;
+ HSHIPFRAG hStarShip, hNextShip;
+ SHIP_FRAGMENT *StarShipPtr = 0;
+ int Index;
+
+ hFleet = GetStarShipFromIndex (&GLOBAL (avail_race_q), which_ship);
+ if (!hFleet)
+ return -1;
+ TemplatePtr = LockFleetInfo (&GLOBAL (avail_race_q), hFleet);
+
+ /* Find first ship of which_ship race */
+ for (hStarShip = GetHeadLink (&GLOBAL (built_ship_q)), Index = 0;
+ hStarShip; hStarShip = hNextShip, ++Index)
+ {
+ StarShipPtr = LockShipFrag (&GLOBAL (built_ship_q), hStarShip);
+ hNextShip = _GetSuccLink (StarShipPtr);
+ if (which_ship == StarShipPtr->race_id &&
+ StarShipPtr->crew_level == TemplatePtr->crew_level)
+ break; /* found one */
+ UnlockShipFrag (&GLOBAL (built_ship_q), hStarShip);
+ }
+ if (hStarShip)
+ {
+ StarShipPtr->crew_level = crew_level;
+ StarShipPtr->captains_name_index = captain;
+ UnlockShipFrag (&GLOBAL (built_ship_q), hStarShip);
+ }
+ else
+ Index = -1;
+
+ UnlockFleetInfo (&GLOBAL (avail_race_q), hFleet);
+ return Index;
+}