summaryrefslogtreecommitdiff
path: root/src/uqm/planets/roster.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/uqm/planets/roster.c')
-rw-r--r--src/uqm/planets/roster.c428
1 files changed, 428 insertions, 0 deletions
diff --git a/src/uqm/planets/roster.c b/src/uqm/planets/roster.c
new file mode 100644
index 0000000..663ac28
--- /dev/null
+++ b/src/uqm/planets/roster.c
@@ -0,0 +1,428 @@
+//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 "../colors.h"
+#include "../controls.h"
+#include "../races.h"
+#include "../units.h"
+#include "../sis.h"
+#include "../shipcont.h"
+#include "../setup.h"
+#include "../sounds.h"
+#include "port.h"
+#include "libs/gfxlib.h"
+#include "libs/tasklib.h"
+
+#include <stdlib.h>
+
+// Ship icon positions in status display around the flagship
+static const POINT ship_pos[MAX_BUILT_SHIPS] =
+{
+ SUPPORT_SHIP_PTS
+};
+
+typedef struct
+{
+ // Ship icon positions split into (lower half) left and right (upper)
+ // and sorted in the Y coord. These are used for navigation around the
+ // escort positions.
+ POINT shipPos[MAX_BUILT_SHIPS];
+ COUNT count;
+ // Number of ships
+
+ POINT curShipPt;
+ // Location of the currently selected escort
+ FRAME curShipFrame;
+ // Icon of the currently selected escort
+ bool modifyingCrew;
+ // true when in crew modification "sub-menu". This is simple
+ // enough that it does not require a real sub-menu.
+} ROSTER_STATE;
+
+static SHIP_FRAGMENT* LockSupportShip (ROSTER_STATE *, HSHIPFRAG *phFrag);
+
+static void
+drawSupportShip (ROSTER_STATE *rosterState, bool filled)
+{
+ STAMP s;
+
+ if (!rosterState->curShipFrame)
+ return;
+
+ s.origin = rosterState->curShipPt;
+ s.frame = rosterState->curShipFrame;
+
+ if (filled)
+ DrawFilledStamp (&s);
+ else
+ DrawStamp (&s);
+}
+
+static void
+getSupportShipIcon (ROSTER_STATE *rosterState)
+{
+ HSHIPFRAG hShipFrag;
+ SHIP_FRAGMENT *ShipFragPtr;
+
+ rosterState->curShipFrame = NULL;
+ ShipFragPtr = LockSupportShip (rosterState, &hShipFrag);
+ if (!ShipFragPtr)
+ return;
+
+ rosterState->curShipFrame = ShipFragPtr->icons;
+ UnlockShipFrag (&GLOBAL (built_ship_q), hShipFrag);
+}
+
+static void
+flashSupportShip (ROSTER_STATE *rosterState)
+{
+ static Color c = BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x00, 0x00), 0x24);
+ static TimeCount NextTime = 0;
+
+ if (GetTimeCounter () >= NextTime)
+ {
+ NextTime = GetTimeCounter () + (ONE_SECOND / 15);
+
+ /* The commented code out code is the old code before the switch
+ * to 24-bits colors. The current code produces very slightly
+ * different colors due to rounding errors, but the old code wasn't
+ * original anyhow, and you can't tell the difference visually.
+ * - SvdB
+ if (c >= BUILD_COLOR (MAKE_RGB15 (0x1F, 0x19, 0x19), 0x24))
+ c = BUILD_COLOR (MAKE_RGB15 (0x1F, 0x00, 0x00), 0x24);
+ else
+ c += BUILD_COLOR (MAKE_RGB15 (0x00, 0x02, 0x02), 0x00);
+ */
+
+ if (c.g >= CC5TO8 (0x19))
+ {
+ c = BUILD_COLOR (MAKE_RGB15 (0x1F, 0x00, 0x00), 0x24);
+ }
+ else
+ {
+ c.g += CC5TO8 (0x02);
+ c.b += CC5TO8 (0x02);
+ }
+ SetContextForeGroundColor (c);
+
+ drawSupportShip (rosterState, TRUE);
+ }
+}
+
+static SHIP_FRAGMENT *
+LockSupportShip (ROSTER_STATE *rosterState, HSHIPFRAG *phFrag)
+{
+ const POINT *pship_pos;
+ HSHIPFRAG hStarShip, hNextShip;
+
+ // Lookup the current escort's location in the unsorted points list
+ // to find the original escort index
+ for (hStarShip = GetHeadLink (&GLOBAL (built_ship_q)),
+ pship_pos = ship_pos;
+ hStarShip; hStarShip = hNextShip, ++pship_pos)
+ {
+ SHIP_FRAGMENT *StarShipPtr;
+
+ StarShipPtr = LockShipFrag (&GLOBAL (built_ship_q), hStarShip);
+
+ if (pointsEqual (*pship_pos, rosterState->curShipPt))
+ {
+ *phFrag = hStarShip;
+ return StarShipPtr;
+ }
+
+ hNextShip = _GetSuccLink (StarShipPtr);
+ UnlockShipFrag (&GLOBAL (built_ship_q), hStarShip);
+ }
+
+ return NULL;
+}
+
+static void
+flashSupportShipCrew (void)
+{
+ RECT r;
+
+ SetContext (StatusContext);
+ GetStatusMessageRect (&r);
+ SetFlashRect (&r);
+}
+
+static BOOLEAN
+DeltaSupportCrew (ROSTER_STATE *rosterState, SIZE crew_delta)
+{
+ BOOLEAN ret = FALSE;
+ UNICODE buf[40];
+ HFLEETINFO hTemplate;
+ HSHIPFRAG hShipFrag;
+ SHIP_FRAGMENT *StarShipPtr;
+ FLEET_INFO *TemplatePtr;
+
+ StarShipPtr = LockSupportShip (rosterState, &hShipFrag);
+ if (!StarShipPtr)
+ return FALSE;
+
+ hTemplate = GetStarShipFromIndex (&GLOBAL (avail_race_q),
+ StarShipPtr->race_id);
+ TemplatePtr = LockFleetInfo (&GLOBAL (avail_race_q), hTemplate);
+
+ StarShipPtr->crew_level += crew_delta;
+
+ if (StarShipPtr->crew_level == 0)
+ StarShipPtr->crew_level = 1;
+ else if (StarShipPtr->crew_level > TemplatePtr->crew_level &&
+ crew_delta > 0)
+ StarShipPtr->crew_level -= crew_delta;
+ else
+ {
+ if (StarShipPtr->crew_level >= TemplatePtr->crew_level)
+ sprintf (buf, "%u", StarShipPtr->crew_level);
+ else
+ sprintf (buf, "%u/%u",
+ StarShipPtr->crew_level,
+ TemplatePtr->crew_level);
+
+ PreUpdateFlashRect ();
+ DrawStatusMessage (buf);
+ PostUpdateFlashRect ();
+ DeltaSISGauges (-crew_delta, 0, 0);
+ if (crew_delta)
+ {
+ flashSupportShipCrew ();
+ }
+ ret = TRUE;
+ }
+
+ UnlockFleetInfo (&GLOBAL (avail_race_q), hTemplate);
+ UnlockShipFrag (&GLOBAL (built_ship_q), hShipFrag);
+
+ return ret;
+}
+
+static void
+drawModifiedSupportShip (ROSTER_STATE *rosterState)
+{
+ SetContext (StatusContext);
+ SetContextForeGroundColor (ROSTER_MODIFY_SHIP_COLOR);
+ drawSupportShip (rosterState, TRUE);
+}
+
+static void
+selectSupportShip (ROSTER_STATE *rosterState, COUNT shipIndex)
+{
+ rosterState->curShipPt = rosterState->shipPos[shipIndex];
+ getSupportShipIcon (rosterState);
+ DeltaSupportCrew (rosterState, 0);
+}
+
+static BOOLEAN
+DoModifyRoster (MENU_STATE *pMS)
+{
+ ROSTER_STATE *rosterState = pMS->privData;
+ BOOLEAN select, cancel, up, down, horiz;
+
+ if (GLOBAL (CurrentActivity) & CHECK_ABORT)
+ return FALSE;
+
+ select = PulsedInputState.menu[KEY_MENU_SELECT];
+ cancel = PulsedInputState.menu[KEY_MENU_CANCEL];
+ up = PulsedInputState.menu[KEY_MENU_UP];
+ down = PulsedInputState.menu[KEY_MENU_DOWN];
+ // Left or right produces the same effect because there are 2 columns
+ horiz = PulsedInputState.menu[KEY_MENU_LEFT] ||
+ PulsedInputState.menu[KEY_MENU_RIGHT];
+
+ if (cancel && !rosterState->modifyingCrew)
+ {
+ return FALSE;
+ }
+ else if (select || cancel)
+ {
+ rosterState->modifyingCrew ^= true;
+ if (!rosterState->modifyingCrew)
+ {
+ SetFlashRect (NULL);
+ SetMenuSounds (MENU_SOUND_ARROWS, MENU_SOUND_SELECT);
+ }
+ else
+ {
+ drawModifiedSupportShip (rosterState);
+ flashSupportShipCrew ();
+ SetMenuSounds (MENU_SOUND_UP | MENU_SOUND_DOWN,
+ MENU_SOUND_SELECT | MENU_SOUND_CANCEL);
+ }
+ }
+ else if (rosterState->modifyingCrew)
+ {
+ SIZE delta = 0;
+ BOOLEAN failed = FALSE;
+
+ if (up)
+ {
+ if (GLOBAL_SIS (CrewEnlisted))
+ delta = 1;
+ else
+ failed = TRUE;
+ }
+ else if (down)
+ {
+ if (GLOBAL_SIS (CrewEnlisted) < GetCrewPodCapacity ())
+ delta = -1;
+ else
+ failed = TRUE;
+ }
+
+ if (delta != 0)
+ {
+ failed = !DeltaSupportCrew (rosterState, delta);
+ }
+
+ if (failed)
+ { // not enough room or crew
+ PlayMenuSound (MENU_SOUND_FAILURE);
+ }
+ }
+ else
+ {
+ COUNT NewState;
+ POINT *pship_pos = rosterState->shipPos;
+ COUNT top_right = (rosterState->count + 1) >> 1;
+
+ NewState = pMS->CurState;
+
+ if (rosterState->count < 2)
+ {
+ // no navigation allowed
+ }
+ else if (horiz)
+ {
+ if (NewState == top_right - 1)
+ NewState = rosterState->count - 1;
+ else if (NewState >= top_right)
+ {
+ NewState -= top_right;
+ if (pship_pos[NewState].y < pship_pos[pMS->CurState].y)
+ ++NewState;
+ }
+ else
+ {
+ NewState += top_right;
+ if (NewState != top_right
+ && pship_pos[NewState].y > pship_pos[pMS->CurState].y)
+ --NewState;
+ }
+ }
+ else if (down)
+ {
+ ++NewState;
+ if (NewState == rosterState->count)
+ NewState = top_right;
+ else if (NewState == top_right)
+ NewState = 0;
+ }
+ else if (up)
+ {
+ if (NewState == 0)
+ NewState = top_right - 1;
+ else if (NewState == top_right)
+ NewState = rosterState->count - 1;
+ else
+ --NewState;
+ }
+
+ BatchGraphics ();
+ SetContext (StatusContext);
+
+ if (NewState != pMS->CurState)
+ {
+ // Draw the previous escort in unselected state
+ drawSupportShip (rosterState, FALSE);
+ // Select the new one
+ selectSupportShip (rosterState, NewState);
+ pMS->CurState = NewState;
+ }
+
+ flashSupportShip (rosterState);
+
+ UnbatchGraphics ();
+ }
+
+ SleepThread (ONE_SECOND / 30);
+
+ return TRUE;
+}
+
+static int
+compShipPos (const void *ptr1, const void *ptr2)
+{
+ const POINT *pt1 = (const POINT *) ptr1;
+ const POINT *pt2 = (const POINT *) ptr2;
+
+ // Ships on the left in the lower half
+ if (pt1->x < pt2->x)
+ return -1;
+ else if (pt1->x > pt2->x)
+ return 1;
+
+ // and ordered on Y
+ if (pt1->y < pt2->y)
+ return -1;
+ else if (pt1->y > pt2->y)
+ return 1;
+ else
+ return 0;
+}
+
+BOOLEAN
+RosterMenu (void)
+{
+ MENU_STATE MenuState;
+ ROSTER_STATE RosterState;
+
+ memset (&MenuState, 0, sizeof MenuState);
+ MenuState.privData = &RosterState;
+
+ memset (&RosterState, 0, sizeof RosterState);
+
+ RosterState.count = CountLinks (&GLOBAL (built_ship_q));
+ if (!RosterState.count)
+ return FALSE;
+
+ // Get the escort positions we will use and sort on X then Y
+ assert (sizeof (RosterState.shipPos) == sizeof (ship_pos));
+ memcpy (RosterState.shipPos, ship_pos, sizeof (ship_pos));
+ qsort (RosterState.shipPos, RosterState.count,
+ sizeof (RosterState.shipPos[0]), compShipPos);
+
+ SetContext (StatusContext);
+ selectSupportShip (&RosterState, MenuState.CurState);
+
+ SetMenuSounds (MENU_SOUND_ARROWS, MENU_SOUND_SELECT);
+
+ MenuState.InputFunc = DoModifyRoster;
+ DoInput (&MenuState, TRUE);
+
+ SetContext (StatusContext);
+ // unselect the last ship
+ drawSupportShip (&RosterState, FALSE);
+ DrawStatusMessage (NULL);
+
+ return TRUE;
+}
+