diff options
Diffstat (limited to 'src/uqm/planets/pstarmap.c')
-rw-r--r-- | src/uqm/planets/pstarmap.c | 1631 |
1 files changed, 1631 insertions, 0 deletions
diff --git a/src/uqm/planets/pstarmap.c b/src/uqm/planets/pstarmap.c new file mode 100644 index 0000000..cd33858 --- /dev/null +++ b/src/uqm/planets/pstarmap.c @@ -0,0 +1,1631 @@ +//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 "scan.h" +#include "../colors.h" +#include "../controls.h" +#include "../menustat.h" +#include "../starmap.h" +#include "../races.h" +#include "../gameopt.h" +#include "../gamestr.h" +#include "../globdata.h" +#include "../shipcont.h" +#include "../units.h" +#include "../hyper.h" +#include "../sis.h" + // for DrawHyperCoords(), DrawStatusMessage() +#include "../settings.h" +#include "../setup.h" +#include "../sounds.h" +#include "../state.h" +#include "../uqmdebug.h" +#include "options.h" +#include "libs/inplib.h" +#include "libs/strlib.h" +#include "libs/graphics/gfx_common.h" +#include "libs/mathlib.h" +#include "libs/memlib.h" + +#include <stdlib.h> + + +static POINT cursorLoc; +static POINT mapOrigin; +static int zoomLevel; +static FRAME StarMapFrame; + + +static inline long +signedDivWithError (long val, long divisor) +{ + int invert = 0; + if (val < 0) + { + invert = 1; + val = -val; + } + val = (val + ROUNDING_ERROR (divisor)) / divisor; + return invert ? -val : val; +} + +#define MAP_FIT_X ((MAX_X_UNIVERSE + 1) / SIS_SCREEN_WIDTH + 1) + +static inline COORD +universeToDispx (long ux) +{ + return signedDivWithError (((ux - mapOrigin.x) << zoomLevel) + * SIS_SCREEN_WIDTH, MAX_X_UNIVERSE + MAP_FIT_X) + + ((SIS_SCREEN_WIDTH - 1) >> 1); +} +#define UNIVERSE_TO_DISPX(ux) universeToDispx(ux) + +static inline COORD +universeToDispy (long uy) +{ + return signedDivWithError (((mapOrigin.y - uy) << zoomLevel) + * SIS_SCREEN_HEIGHT, MAX_Y_UNIVERSE + 2) + + ((SIS_SCREEN_HEIGHT - 1) >> 1); +} +#define UNIVERSE_TO_DISPY(uy) universeToDispy(uy) + +static inline COORD +dispxToUniverse (COORD dx) +{ + return (((long)(dx - ((SIS_SCREEN_WIDTH - 1) >> 1)) + * (MAX_X_UNIVERSE + MAP_FIT_X)) >> zoomLevel) + / SIS_SCREEN_WIDTH + mapOrigin.x; +} +#define DISP_TO_UNIVERSEX(dx) dispxToUniverse(dx) + +static inline COORD +dispyToUniverse (COORD dy) +{ + return (((long)(((SIS_SCREEN_HEIGHT - 1) >> 1) - dy) + * (MAX_Y_UNIVERSE + 2)) >> zoomLevel) + / SIS_SCREEN_HEIGHT + mapOrigin.y; +} +#define DISP_TO_UNIVERSEY(dy) dispyToUniverse(dy) + +static BOOLEAN transition_pending; + +static void +flashCurrentLocation (POINT *where) +{ + static BYTE c = 0; + static int val = -2; + static POINT universe; + static TimeCount NextTime = 0; + + if (where) + universe = *where; + + if (GetTimeCounter () >= NextTime) + { + Color OldColor; + CONTEXT OldContext; + STAMP s; + + NextTime = GetTimeCounter () + (ONE_SECOND / 16); + + OldContext = SetContext (SpaceContext); + + if (c == 0x00 || c == 0x1A) + val = -val; + c += val; + OldColor = SetContextForeGroundColor ( + BUILD_COLOR (MAKE_RGB15 (c, c, c), c)); + s.origin.x = UNIVERSE_TO_DISPX (universe.x); + s.origin.y = UNIVERSE_TO_DISPY (universe.y); + s.frame = IncFrameIndex (StarMapFrame); + DrawFilledStamp (&s); + SetContextForeGroundColor (OldColor); + + SetContext (OldContext); + } +} + +static void +DrawCursor (COORD curs_x, COORD curs_y) +{ + STAMP s; + + s.origin.x = curs_x; + s.origin.y = curs_y; + s.frame = StarMapFrame; + + DrawStamp (&s); +} + +static void +DrawAutoPilot (POINT *pDstPt) +{ + SIZE dx, dy, + xincr, yincr, + xerror, yerror, + cycle, delta; + POINT pt; + + if (!inHQSpace ()) + pt = CurStarDescPtr->star_pt; + else + { + pt.x = LOGX_TO_UNIVERSE (GLOBAL_SIS (log_x)); + pt.y = LOGY_TO_UNIVERSE (GLOBAL_SIS (log_y)); + } + pt.x = UNIVERSE_TO_DISPX (pt.x); + pt.y = UNIVERSE_TO_DISPY (pt.y); + + dx = UNIVERSE_TO_DISPX (pDstPt->x) - pt.x; + if (dx >= 0) + xincr = 1; + else + { + xincr = -1; + dx = -dx; + } + dx <<= 1; + + dy = UNIVERSE_TO_DISPY (pDstPt->y) - pt.y; + if (dy >= 0) + yincr = 1; + else + { + yincr = -1; + dy = -dy; + } + dy <<= 1; + + if (dx >= dy) + cycle = dx; + else + cycle = dy; + delta = xerror = yerror = cycle >> 1; + + SetContextForeGroundColor ( + BUILD_COLOR (MAKE_RGB15 (0x04, 0x04, 0x1F), 0x01)); + + delta &= ~1; + while (delta--) + { + if (!(delta & 1)) + DrawPoint (&pt); + + if ((xerror -= dx) <= 0) + { + pt.x += xincr; + xerror += cycle; + } + if ((yerror -= dy) <= 0) + { + pt.y += yincr; + yerror += cycle; + } + } +} + +static void +GetSphereRect (FLEET_INFO *FleetPtr, RECT *pRect, RECT *pRepairRect) +{ + long diameter; + + diameter = (long)(FleetPtr->known_strength * SPHERE_RADIUS_INCREMENT); + pRect->extent.width = UNIVERSE_TO_DISPX (diameter) + - UNIVERSE_TO_DISPX (0); + if (pRect->extent.width < 0) + pRect->extent.width = -pRect->extent.width; + else if (pRect->extent.width == 0) + pRect->extent.width = 1; + pRect->extent.height = UNIVERSE_TO_DISPY (diameter) + - UNIVERSE_TO_DISPY (0); + if (pRect->extent.height < 0) + pRect->extent.height = -pRect->extent.height; + else if (pRect->extent.height == 0) + pRect->extent.height = 1; + + pRect->corner.x = UNIVERSE_TO_DISPX (FleetPtr->known_loc.x); + pRect->corner.y = UNIVERSE_TO_DISPY (FleetPtr->known_loc.y); + pRect->corner.x -= pRect->extent.width >> 1; + pRect->corner.y -= pRect->extent.height >> 1; + + { + TEXT t; + STRING locString; + + SetContextFont (TinyFont); + + t.baseline.x = pRect->corner.x + (pRect->extent.width >> 1); + t.baseline.y = pRect->corner.y + (pRect->extent.height >> 1) - 1; + t.align = ALIGN_CENTER; + locString = SetAbsStringTableIndex (FleetPtr->race_strings, 1); + t.CharCount = GetStringLength (locString); + t.pStr = (UNICODE *)GetStringAddress (locString); + TextRect (&t, pRepairRect, NULL); + + if (pRepairRect->corner.x <= 0) + pRepairRect->corner.x = 1; + else if (pRepairRect->corner.x + pRepairRect->extent.width >= + SIS_SCREEN_WIDTH) + pRepairRect->corner.x = + SIS_SCREEN_WIDTH - pRepairRect->extent.width - 1; + if (pRepairRect->corner.y <= 0) + pRepairRect->corner.y = 1; + else if (pRepairRect->corner.y + pRepairRect->extent.height >= + SIS_SCREEN_HEIGHT) + pRepairRect->corner.y = + SIS_SCREEN_HEIGHT - pRepairRect->extent.height - 1; + + BoxUnion (pRepairRect, pRect, pRepairRect); + pRepairRect->extent.width++; + pRepairRect->extent.height++; + } +} + +static void +DrawStarMap (COUNT race_update, RECT *pClipRect) +{ +#define GRID_DELTA 500 + SIZE i; + COUNT which_space; + long diameter; + RECT r, old_r; + POINT oldOrigin = {0, 0}; + STAMP s; + FRAME star_frame; + STAR_DESC *SDPtr; + BOOLEAN draw_cursor; + + if (pClipRect == (RECT*)-1) + { + pClipRect = 0; + draw_cursor = FALSE; + } + else + { + draw_cursor = TRUE; + } + + SetContext (SpaceContext); + if (pClipRect) + { + GetContextClipRect (&old_r); + pClipRect->corner.x += old_r.corner.x; + pClipRect->corner.y += old_r.corner.y; + SetContextClipRect (pClipRect); + pClipRect->corner.x -= old_r.corner.x; + pClipRect->corner.y -= old_r.corner.y; + // Offset the origin so that we draw the correct gfx in the cliprect + oldOrigin = SetContextOrigin (MAKE_POINT (-pClipRect->corner.x, + -pClipRect->corner.y)); + } + + if (transition_pending) + { + SetTransitionSource (NULL); + } + BatchGraphics (); + + which_space = GET_GAME_STATE (ARILOU_SPACE_SIDE); + + if (which_space <= 1) + { + SDPtr = &star_array[0]; + SetContextForeGroundColor ( + BUILD_COLOR (MAKE_RGB15 (0x00, 0x00, 0x07), 0x57)); + SetContextBackGroundColor (BLACK_COLOR); + } + else + { + SDPtr = &star_array[NUM_SOLAR_SYSTEMS + 1]; + SetContextForeGroundColor ( + BUILD_COLOR (MAKE_RGB15 (0x00, 0x0B, 0x00), 0x6D)); + SetContextBackGroundColor ( + BUILD_COLOR (MAKE_RGB15 (0x00, 0x08, 0x00), 0x6E)); + } + ClearDrawable (); + + // Draw the fuel range circle + if (race_update == 0 + && which_space < 2 + && (diameter = (long)GLOBAL_SIS (FuelOnBoard) << 1)) + { + Color OldColor; + + if (!inHQSpace ()) + r.corner = CurStarDescPtr->star_pt; + else + { + r.corner.x = LOGX_TO_UNIVERSE (GLOBAL_SIS (log_x)); + r.corner.y = LOGY_TO_UNIVERSE (GLOBAL_SIS (log_y)); + } + + // Cap the diameter to a sane range + if (diameter > MAX_X_UNIVERSE * 4) + diameter = MAX_X_UNIVERSE * 4; + + r.extent.width = UNIVERSE_TO_DISPX (diameter) + - UNIVERSE_TO_DISPX (0); + if (r.extent.width < 0) + r.extent.width = -r.extent.width; + r.extent.height = UNIVERSE_TO_DISPY (diameter) + - UNIVERSE_TO_DISPY (0); + if (r.extent.height < 0) + r.extent.height = -r.extent.height; + + r.corner.x = UNIVERSE_TO_DISPX (r.corner.x) + - (r.extent.width >> 1); + r.corner.y = UNIVERSE_TO_DISPY (r.corner.y) + - (r.extent.height >> 1); + + OldColor = SetContextForeGroundColor ( + BUILD_COLOR (MAKE_RGB15 (0x03, 0x03, 0x03), 0x22)); + DrawFilledOval (&r); + SetContextForeGroundColor (OldColor); + } + + for (i = MAX_Y_UNIVERSE + 1; i >= 0; i -= GRID_DELTA) + { + SIZE j; + + r.corner.x = UNIVERSE_TO_DISPX (0); + r.corner.y = UNIVERSE_TO_DISPY (i); + r.extent.width = SIS_SCREEN_WIDTH << zoomLevel; + r.extent.height = 1; + DrawFilledRectangle (&r); + + r.corner.y = UNIVERSE_TO_DISPY (MAX_Y_UNIVERSE + 1); + r.extent.width = 1; + r.extent.height = SIS_SCREEN_HEIGHT << zoomLevel; + for (j = MAX_X_UNIVERSE + 1; j >= 0; j -= GRID_DELTA) + { + r.corner.x = UNIVERSE_TO_DISPX (j); + DrawFilledRectangle (&r); + } + } + + star_frame = SetRelFrameIndex (StarMapFrame, 2); + if (which_space <= 1) + { + COUNT index; + HFLEETINFO hStarShip, hNextShip; + static const Color race_colors[] = + { + RACE_COLORS + }; + + for (index = 0, + hStarShip = GetHeadLink (&GLOBAL (avail_race_q)); + hStarShip != 0; ++index, hStarShip = hNextShip) + { + FLEET_INFO *FleetPtr; + + FleetPtr = LockFleetInfo (&GLOBAL (avail_race_q), hStarShip); + hNextShip = _GetSuccLink (FleetPtr); + + if (FleetPtr->known_strength) + { + RECT repair_r; + + GetSphereRect (FleetPtr, &r, &repair_r); + if (r.corner.x < SIS_SCREEN_WIDTH + && r.corner.y < SIS_SCREEN_HEIGHT + && r.corner.x + r.extent.width > 0 + && r.corner.y + r.extent.height > 0 + && (pClipRect == 0 + || (repair_r.corner.x < pClipRect->corner.x + pClipRect->extent.width + && repair_r.corner.y < pClipRect->corner.y + pClipRect->extent.height + && repair_r.corner.x + repair_r.extent.width > pClipRect->corner.x + && repair_r.corner.y + repair_r.extent.height > pClipRect->corner.y))) + { + Color c; + TEXT t; + STRING locString; + + c = race_colors[index]; + if (index + 1 == race_update) + SetContextForeGroundColor (WHITE_COLOR); + else + SetContextForeGroundColor (c); + DrawOval (&r, 0); + + SetContextFont (TinyFont); + + t.baseline.x = r.corner.x + (r.extent.width >> 1); + t.baseline.y = r.corner.y + (r.extent.height >> 1) - 1; + t.align = ALIGN_CENTER; + locString = SetAbsStringTableIndex ( + FleetPtr->race_strings, 1); + t.CharCount = GetStringLength (locString); + t.pStr = (UNICODE *)GetStringAddress (locString); + TextRect (&t, &r, NULL); + + if (r.corner.x <= 0) + t.baseline.x -= r.corner.x - 1; + else if (r.corner.x + r.extent.width >= SIS_SCREEN_WIDTH) + t.baseline.x -= (r.corner.x + r.extent.width) + - SIS_SCREEN_WIDTH + 1; + if (r.corner.y <= 0) + t.baseline.y -= r.corner.y - 1; + else if (r.corner.y + r.extent.height >= SIS_SCREEN_HEIGHT) + t.baseline.y -= (r.corner.y + r.extent.height) + - SIS_SCREEN_HEIGHT + 1; + + // The text color is slightly lighter than the color of + // the SoI. + c.r = (c.r >= 0xff - CC5TO8 (0x03)) ? + 0xff : c.r + CC5TO8 (0x03); + c.g = (c.g >= 0xff - CC5TO8 (0x03)) ? + 0xff : c.g + CC5TO8 (0x03); + c.b = (c.b >= 0xff - CC5TO8 (0x03)) ? + 0xff : c.b + CC5TO8 (0x03); + + SetContextForeGroundColor (c); + font_DrawText (&t); + } + } + + UnlockFleetInfo (&GLOBAL (avail_race_q), hStarShip); + } + } + + do + { + BYTE star_type; + + star_type = SDPtr->Type; + + s.origin.x = UNIVERSE_TO_DISPX (SDPtr->star_pt.x); + s.origin.y = UNIVERSE_TO_DISPY (SDPtr->star_pt.y); + if (which_space <= 1) + s.frame = SetRelFrameIndex (star_frame, + STAR_TYPE (star_type) + * NUM_STAR_COLORS + + STAR_COLOR (star_type)); + else if (SDPtr->star_pt.x == ARILOU_HOME_X + && SDPtr->star_pt.y == ARILOU_HOME_Y) + s.frame = SetRelFrameIndex (star_frame, + SUPER_GIANT_STAR * NUM_STAR_COLORS + GREEN_BODY); + else + s.frame = SetRelFrameIndex (star_frame, + GIANT_STAR * NUM_STAR_COLORS + GREEN_BODY); + DrawStamp (&s); + + ++SDPtr; + } while (SDPtr->star_pt.x <= MAX_X_UNIVERSE + && SDPtr->star_pt.y <= MAX_Y_UNIVERSE); + + if (GET_GAME_STATE (ARILOU_SPACE)) + { + if (which_space <= 1) + { + s.origin.x = UNIVERSE_TO_DISPX (ARILOU_SPACE_X); + s.origin.y = UNIVERSE_TO_DISPY (ARILOU_SPACE_Y); + } + else + { + s.origin.x = UNIVERSE_TO_DISPX (QUASI_SPACE_X); + s.origin.y = UNIVERSE_TO_DISPY (QUASI_SPACE_Y); + } + s.frame = SetRelFrameIndex (star_frame, + GIANT_STAR * NUM_STAR_COLORS + GREEN_BODY); + DrawStamp (&s); + } + + if (race_update == 0 + && GLOBAL (autopilot.x) != ~0 + && GLOBAL (autopilot.y) != ~0) + DrawAutoPilot (&GLOBAL (autopilot)); + + if (transition_pending) + { + GetContextClipRect (&r); + ScreenTransition (3, &r); + transition_pending = FALSE; + } + + UnbatchGraphics (); + + if (pClipRect) + { + SetContextClipRect (&old_r); + SetContextOrigin (oldOrigin); + } + + if (race_update == 0) + { + if (draw_cursor) + { + GetContextClipRect (&r); + LoadIntoExtraScreen (&r); + DrawCursor (UNIVERSE_TO_DISPX (cursorLoc.x), + UNIVERSE_TO_DISPY (cursorLoc.y)); + } + } +} + +static void +EraseCursor (COORD curs_x, COORD curs_y) +{ + RECT r; + + GetFrameRect (StarMapFrame, &r); + + if ((r.corner.x += curs_x) < 0) + { + r.extent.width += r.corner.x; + r.corner.x = 0; + } + else if (r.corner.x + r.extent.width >= SIS_SCREEN_WIDTH) + r.extent.width = SIS_SCREEN_WIDTH - r.corner.x; + if ((r.corner.y += curs_y) < 0) + { + r.extent.height += r.corner.y; + r.corner.y = 0; + } + else if (r.corner.y + r.extent.height >= SIS_SCREEN_HEIGHT) + r.extent.height = SIS_SCREEN_HEIGHT - r.corner.y; + +#ifndef OLD + RepairBackRect (&r); +#else /* NEW */ + r.extent.height += r.corner.y & 1; + r.corner.y &= ~1; + DrawStarMap (0, &r); +#endif /* OLD */ +} + +static void +ZoomStarMap (SIZE dir) +{ +#define MAX_ZOOM_SHIFT 4 + if (dir > 0) + { + if (zoomLevel < MAX_ZOOM_SHIFT) + { + ++zoomLevel; + mapOrigin = cursorLoc; + + DrawStarMap (0, NULL); + SleepThread (ONE_SECOND / 8); + } + } + else if (dir < 0) + { + if (zoomLevel > 0) + { + if (zoomLevel > 1) + mapOrigin = cursorLoc; + else + { + mapOrigin.x = MAX_X_UNIVERSE >> 1; + mapOrigin.y = MAX_Y_UNIVERSE >> 1; + } + --zoomLevel; + + DrawStarMap (0, NULL); + SleepThread (ONE_SECOND / 8); + } + } +} + +static void +UpdateCursorLocation (int sx, int sy, const POINT *newpt) +{ + STAMP s; + POINT pt; + + pt.x = UNIVERSE_TO_DISPX (cursorLoc.x); + pt.y = UNIVERSE_TO_DISPY (cursorLoc.y); + + if (newpt) + { // absolute move + sx = sy = 0; + s.origin.x = UNIVERSE_TO_DISPX (newpt->x); + s.origin.y = UNIVERSE_TO_DISPY (newpt->y); + cursorLoc = *newpt; + } + else + { // incremental move + s.origin.x = pt.x + sx; + s.origin.y = pt.y + sy; + } + + if (sx) + { + cursorLoc.x = DISP_TO_UNIVERSEX (s.origin.x) - sx; + while (UNIVERSE_TO_DISPX (cursorLoc.x) == pt.x) + cursorLoc.x += sx; + + if (cursorLoc.x < 0) + cursorLoc.x = 0; + else if (cursorLoc.x > MAX_X_UNIVERSE) + cursorLoc.x = MAX_X_UNIVERSE; + + s.origin.x = UNIVERSE_TO_DISPX (cursorLoc.x); + } + + if (sy) + { + cursorLoc.y = DISP_TO_UNIVERSEY (s.origin.y) + sy; + while (UNIVERSE_TO_DISPY (cursorLoc.y) == pt.y) + cursorLoc.y -= sy; + + if (cursorLoc.y < 0) + cursorLoc.y = 0; + else if (cursorLoc.y > MAX_Y_UNIVERSE) + cursorLoc.y = MAX_Y_UNIVERSE; + + s.origin.y = UNIVERSE_TO_DISPY (cursorLoc.y); + } + + if (s.origin.x < 0 || s.origin.y < 0 + || s.origin.x >= SIS_SCREEN_WIDTH + || s.origin.y >= SIS_SCREEN_HEIGHT) + { + mapOrigin = cursorLoc; + DrawStarMap (0, NULL); + + s.origin.x = UNIVERSE_TO_DISPX (cursorLoc.x); + s.origin.y = UNIVERSE_TO_DISPY (cursorLoc.y); + } + else + { + EraseCursor (pt.x, pt.y); + // ClearDrawable (); + DrawCursor (s.origin.x, s.origin.y); + } +} + +#define CURSOR_INFO_BUFSIZE 256 + +static void +UpdateCursorInfo (UNICODE *prevbuf) +{ + UNICODE buf[CURSOR_INFO_BUFSIZE] = ""; + POINT pt; + STAR_DESC *SDPtr; + STAR_DESC *BestSDPtr; + + pt.x = UNIVERSE_TO_DISPX (cursorLoc.x); + pt.y = UNIVERSE_TO_DISPY (cursorLoc.y); + + SDPtr = BestSDPtr = 0; + while ((SDPtr = FindStar (SDPtr, &cursorLoc, 75, 75))) + { + if (UNIVERSE_TO_DISPX (SDPtr->star_pt.x) == pt.x + && UNIVERSE_TO_DISPY (SDPtr->star_pt.y) == pt.y + && (BestSDPtr == 0 + || STAR_TYPE (SDPtr->Type) >= STAR_TYPE (BestSDPtr->Type))) + BestSDPtr = SDPtr; + } + + if (BestSDPtr) + { + cursorLoc = BestSDPtr->star_pt; + GetClusterName (BestSDPtr, buf); + } + else + { // No star found. Reset the coordinates to the cursor's location + cursorLoc.x = DISP_TO_UNIVERSEX (pt.x); + if (cursorLoc.x < 0) + cursorLoc.x = 0; + else if (cursorLoc.x > MAX_X_UNIVERSE) + cursorLoc.x = MAX_X_UNIVERSE; + cursorLoc.y = DISP_TO_UNIVERSEY (pt.y); + if (cursorLoc.y < 0) + cursorLoc.y = 0; + else if (cursorLoc.y > MAX_Y_UNIVERSE) + cursorLoc.y = MAX_Y_UNIVERSE; + } + + if (GET_GAME_STATE (ARILOU_SPACE)) + { + POINT ari_pt; + + if (GET_GAME_STATE (ARILOU_SPACE_SIDE) <= 1) + { + ari_pt.x = ARILOU_SPACE_X; + ari_pt.y = ARILOU_SPACE_Y; + } + else + { + ari_pt.x = QUASI_SPACE_X; + ari_pt.y = QUASI_SPACE_Y; + } + + if (UNIVERSE_TO_DISPX (ari_pt.x) == pt.x + && UNIVERSE_TO_DISPY (ari_pt.y) == pt.y) + { + cursorLoc = ari_pt; + utf8StringCopy (buf, sizeof (buf), + GAME_STRING (STAR_STRING_BASE + 132)); + } + } + + DrawHyperCoords (cursorLoc); + if (strcmp (buf, prevbuf) != 0) + { + strcpy (prevbuf, buf); + DrawSISMessage (buf); + } +} + +static void +UpdateFuelRequirement (void) +{ + UNICODE buf[80]; + COUNT fuel_required; + DWORD f; + POINT pt; + + if (!inHQSpace ()) + pt = CurStarDescPtr->star_pt; + else + { + pt.x = LOGX_TO_UNIVERSE (GLOBAL_SIS (log_x)); + pt.y = LOGY_TO_UNIVERSE (GLOBAL_SIS (log_y)); + } + pt.x -= cursorLoc.x; + pt.y -= cursorLoc.y; + + f = (DWORD)((long)pt.x * pt.x + (long)pt.y * pt.y); + if (f == 0 || GET_GAME_STATE (ARILOU_SPACE_SIDE) > 1) + fuel_required = 0; + else + fuel_required = square_root (f) + (FUEL_TANK_SCALE / 20); + + sprintf (buf, "%s %u.%u", + GAME_STRING (NAVIGATION_STRING_BASE + 4), + fuel_required / FUEL_TANK_SCALE, + (fuel_required % FUEL_TANK_SCALE) / 10); + + DrawStatusMessage (buf); +} + +#define STAR_SEARCH_BUFSIZE 256 + +typedef struct starsearch_state +{ + // TODO: pMS field is probably not needed anymore + MENU_STATE *pMS; + UNICODE Text[STAR_SEARCH_BUFSIZE]; + UNICODE LastText[STAR_SEARCH_BUFSIZE]; + DWORD LastChangeTime; + int FirstIndex; + int CurIndex; + int LastIndex; + BOOLEAN SingleClust; + BOOLEAN SingleMatch; + UNICODE Buffer[STAR_SEARCH_BUFSIZE]; + const UNICODE *Prefix; + const UNICODE *Cluster; + int PrefixLen; + int ClusterLen; + int ClusterPos; + int SortedStars[NUM_SOLAR_SYSTEMS]; +} STAR_SEARCH_STATE; + +static int +compStarName (const void *ptr1, const void *ptr2) +{ + int index1; + int index2; + + index1 = *(const int *) ptr1; + index2 = *(const int *) ptr2; + if (star_array[index1].Postfix != star_array[index2].Postfix) + { + return utf8StringCompare (GAME_STRING (star_array[index1].Postfix), + GAME_STRING (star_array[index2].Postfix)); + } + + if (star_array[index1].Prefix < star_array[index2].Prefix) + return -1; + + if (star_array[index1].Prefix > star_array[index2].Prefix) + return 1; + + return 0; +} + +static void +SortStarsOnName (STAR_SEARCH_STATE *pSS) +{ + int i; + int *sorted = pSS->SortedStars; + + for (i = 0; i < NUM_SOLAR_SYSTEMS; i++) + sorted[i] = i; + + qsort (sorted, NUM_SOLAR_SYSTEMS, sizeof (int), compStarName); +} + +static void +SplitStarName (STAR_SEARCH_STATE *pSS) +{ + UNICODE *buf = pSS->Buffer; + UNICODE *next; + UNICODE *sep = NULL; + + pSS->Prefix = 0; + pSS->PrefixLen = 0; + pSS->Cluster = 0; + pSS->ClusterLen = 0; + pSS->ClusterPos = 0; + + // skip leading space + for (next = buf; *next != '\0' && + getCharFromString ((const UNICODE **)&next) == ' '; + buf = next) + ; + if (*buf == '\0') + { // no text + return; + } + + pSS->Prefix = buf; + + // See if player gave a prefix + for (buf = next; *next != '\0' && + getCharFromString ((const UNICODE **)&next) != ' '; + buf = next) + ; + if (*buf != '\0') + { // found possibly separating ' ' + sep = buf; + // skip separating space + for (buf = next; *next != '\0' && + getCharFromString ((const UNICODE **)&next) == ' '; + buf = next) + ; + } + + if (*buf == '\0') + { // reached the end -- cluster only + pSS->Cluster = pSS->Prefix; + pSS->ClusterLen = utf8StringCount (pSS->Cluster); + pSS->ClusterPos = utf8StringCountN (pSS->Buffer, pSS->Cluster); + pSS->Prefix = 0; + return; + } + + // consider the rest cluster name (whatever there is) + pSS->Cluster = buf; + pSS->ClusterLen = utf8StringCount (pSS->Cluster); + pSS->ClusterPos = utf8StringCountN (pSS->Buffer, pSS->Cluster); + *sep = '\0'; // split + pSS->PrefixLen = utf8StringCount (pSS->Prefix); +} + +static inline int +SkipStarCluster (int *sortedStars, int istar) +{ + int Postfix = star_array[sortedStars[istar]].Postfix; + + for (++istar; istar < NUM_SOLAR_SYSTEMS && + star_array[sortedStars[istar]].Postfix == Postfix; + ++istar) + ; + return istar; +} + +static int +FindNextStarIndex (STAR_SEARCH_STATE *pSS, int from, BOOLEAN WithinClust) +{ + int i; + + if (!pSS->Cluster) + return -1; // nothing to search for + + for (i = from; i < NUM_SOLAR_SYSTEMS; ++i) + { + STAR_DESC *SDPtr = &star_array[pSS->SortedStars[i]]; + UNICODE FullName[STAR_SEARCH_BUFSIZE]; + UNICODE *ClusterName = GAME_STRING (SDPtr->Postfix); + const UNICODE *sptr; + const UNICODE *dptr; + int dlen; + int c; + + dlen = utf8StringCount (ClusterName); + if (pSS->ClusterLen > dlen) + { // no match, skip the rest of cluster + i = SkipStarCluster (pSS->SortedStars, i) - 1; + continue; + } + + for (c = 0, sptr = pSS->Cluster, dptr = ClusterName; + c < pSS->ClusterLen; ++c) + { + UniChar sc = getCharFromString (&sptr); + UniChar dc = getCharFromString (&dptr); + + if (UniChar_toUpper (sc) != UniChar_toUpper (dc)) + break; + } + + if (c < pSS->ClusterLen) + { // no match here, skip the rest of cluster + i = SkipStarCluster (pSS->SortedStars, i) - 1; + continue; + } + + if (pSS->Prefix && !SDPtr->Prefix) + // we were given a prefix but found a singular star; + // that is a no match + continue; + + if (WithinClust) + // searching within clusters; any prefix is a match + break; + + if (!pSS->Prefix) + { // searching for cluster name only + // return only the first stars in a cluster + if (i == 0 || SDPtr->Postfix != + star_array[pSS->SortedStars[i - 1]].Postfix) + { // found one + break; + } + else + { // another star in the same cluster, skip cluster + i = SkipStarCluster (pSS->SortedStars, i) - 1; + continue; + } + } + + // check prefix + GetClusterName (SDPtr, FullName); + dlen = utf8StringCount (FullName); + if (pSS->PrefixLen > dlen) + continue; + + for (c = 0, sptr = pSS->Prefix, dptr = FullName; + c < pSS->PrefixLen; ++c) + { + UniChar sc = getCharFromString (&sptr); + UniChar dc = getCharFromString (&dptr); + + if (UniChar_toUpper (sc) != UniChar_toUpper (dc)) + break; + } + + if (c >= pSS->PrefixLen) + break; // found one + } + + return (i < NUM_SOLAR_SYSTEMS) ? i : -1; +} + +static void +DrawMatchedStarName (TEXTENTRY_STATE *pTES) +{ + STAR_SEARCH_STATE *pSS = (STAR_SEARCH_STATE *) pTES->CbParam; + UNICODE buf[STAR_SEARCH_BUFSIZE] = ""; + SIZE ExPos = 0; + SIZE CurPos = -1; + STAR_DESC *SDPtr = &star_array[pSS->SortedStars[pSS->CurIndex]]; + COUNT flags; + + if (pSS->SingleClust || pSS->SingleMatch) + { // draw full star name + GetClusterName (SDPtr, buf); + ExPos = -1; + flags = DSME_SETFR; + } + else + { // draw substring match + UNICODE *pstr = buf; + + strcpy (pstr, pSS->Text); + ExPos = pSS->ClusterPos; + pstr = skipUTF8Chars (pstr, pSS->ClusterPos); + + strcpy (pstr, GAME_STRING (SDPtr->Postfix)); + ExPos += pSS->ClusterLen; + CurPos = pTES->CursorPos; + + flags = DSME_CLEARFR; + if (pTES->JoystickMode) + flags |= DSME_BLOCKCUR; + } + + DrawSISMessageEx (buf, CurPos, ExPos, flags); + DrawHyperCoords (cursorLoc); +} + +static void +MatchNextStar (STAR_SEARCH_STATE *pSS, BOOLEAN Reset) +{ + if (Reset) + pSS->FirstIndex = -1; // reset cache + + if (pSS->FirstIndex < 0) + { // first time after changes + pSS->CurIndex = -1; + pSS->LastIndex = -1; + pSS->SingleClust = FALSE; + pSS->SingleMatch = FALSE; + strcpy (pSS->Buffer, pSS->Text); + SplitStarName (pSS); + } + + pSS->CurIndex = FindNextStarIndex (pSS, pSS->CurIndex + 1, + pSS->SingleClust); + if (pSS->FirstIndex < 0) // first search + pSS->FirstIndex = pSS->CurIndex; + + if (pSS->CurIndex >= 0) + { // remember as last (searching forward-only) + pSS->LastIndex = pSS->CurIndex; + } + else + { // wrap around + pSS->CurIndex = pSS->FirstIndex; + + if (pSS->FirstIndex == pSS->LastIndex && pSS->FirstIndex != -1) + { + if (!pSS->Prefix) + { // only one cluster matching + pSS->SingleClust = TRUE; + } + else + { // exact match + pSS->SingleMatch = TRUE; + } + } + } +} + +static BOOLEAN +OnStarNameChange (TEXTENTRY_STATE *pTES) +{ + STAR_SEARCH_STATE *pSS = (STAR_SEARCH_STATE *) pTES->CbParam; + COUNT flags; + BOOLEAN ret = TRUE; + + if (strcmp (pSS->Text, pSS->LastText) != 0) + { // string changed + pSS->LastChangeTime = GetTimeCounter (); + strcpy (pSS->LastText, pSS->Text); + + // reset the search + MatchNextStar (pSS, TRUE); + } + + if (pSS->CurIndex < 0) + { // nothing found + if (pSS->Text[0] == '\0') + flags = DSME_SETFR; + else + flags = DSME_CLEARFR; + if (pTES->JoystickMode) + flags |= DSME_BLOCKCUR; + + ret = DrawSISMessageEx (pSS->Text, pTES->CursorPos, -1, flags); + } + else + { + STAR_DESC *SDPtr; + + // move the cursor to the found star + SDPtr = &star_array[pSS->SortedStars[pSS->CurIndex]]; + UpdateCursorLocation (0, 0, &SDPtr->star_pt); + + DrawMatchedStarName (pTES); + UpdateFuelRequirement (); + } + + return ret; +} + +static BOOLEAN +OnStarNameFrame (TEXTENTRY_STATE *pTES) +{ + STAR_SEARCH_STATE *pSS = (STAR_SEARCH_STATE *) pTES->CbParam; + + if (PulsedInputState.menu[KEY_MENU_NEXT]) + { // search for next match + STAR_DESC *SDPtr; + + MatchNextStar (pSS, FALSE); + + if (pSS->CurIndex < 0) + { // nothing found + if (PulsedInputState.menu[KEY_MENU_NEXT]) + PlayMenuSound (MENU_SOUND_FAILURE); + return TRUE; + } + + // move the cursor to the found star + SDPtr = &star_array[pSS->SortedStars[pSS->CurIndex]]; + UpdateCursorLocation (0, 0, &SDPtr->star_pt); + + DrawMatchedStarName (pTES); + UpdateFuelRequirement (); + } + + flashCurrentLocation (NULL); + + SleepThread (ONE_SECOND / 30); + + return TRUE; +} + +static BOOLEAN +DoStarSearch (MENU_STATE *pMS) +{ + TEXTENTRY_STATE tes; + STAR_SEARCH_STATE *pss; + BOOLEAN success; + + pss = HMalloc (sizeof (*pss)); + if (!pss) + return FALSE; + + DrawSISMessageEx ("", 0, 0, DSME_SETFR); + + pss->pMS = pMS; + pss->LastChangeTime = 0; + pss->Text[0] = '\0'; + pss->LastText[0] = '\0'; + pss->FirstIndex = -1; + SortStarsOnName (pss); + + // text entry setup + tes.Initialized = FALSE; + tes.BaseStr = pss->Text; + tes.MaxSize = sizeof (pss->Text); + tes.CursorPos = 0; + tes.CbParam = pss; + tes.ChangeCallback = OnStarNameChange; + tes.FrameCallback = OnStarNameFrame; + + SetMenuSounds (MENU_SOUND_ARROWS, MENU_SOUND_SELECT); + SetDefaultMenuRepeatDelay (); + success = DoTextEntry (&tes); + + DrawSISMessageEx (pss->Text, -1, -1, DSME_CLEARFR); + + HFree (pss); + + return success; +} + +static BOOLEAN +DoMoveCursor (MENU_STATE *pMS) +{ +#define MIN_ACCEL_DELAY (ONE_SECOND / 60) +#define MAX_ACCEL_DELAY (ONE_SECOND / 8) +#define STEP_ACCEL_DELAY (ONE_SECOND / 120) + static UNICODE last_buf[CURSOR_INFO_BUFSIZE]; + DWORD TimeIn = GetTimeCounter (); + + if (!pMS->Initialized) + { + POINT universe; + + pMS->Initialized = TRUE; + pMS->InputFunc = DoMoveCursor; + + if (!inHQSpace ()) + universe = CurStarDescPtr->star_pt; + else + { + universe.x = LOGX_TO_UNIVERSE (GLOBAL_SIS (log_x)); + universe.y = LOGY_TO_UNIVERSE (GLOBAL_SIS (log_y)); + } + flashCurrentLocation (&universe); + + last_buf[0] = '\0'; + UpdateCursorInfo (last_buf); + UpdateFuelRequirement (); + + return TRUE; + } + else if (PulsedInputState.menu[KEY_MENU_CANCEL]) + { + return FALSE; + } + else if (PulsedInputState.menu[KEY_MENU_SELECT]) + { + GLOBAL (autopilot) = cursorLoc; +#ifdef DEBUG + if (instantMove) + { + PlayMenuSound (MENU_SOUND_INVOKED); + + if (inHQSpace ()) + { + // Move to the new location immediately. + doInstantMove (); + } + else if (LOBYTE (GLOBAL (CurrentActivity)) == IN_INTERPLANETARY) + { + // We're in a solar system; exit it. + GLOBAL (CurrentActivity) |= END_INTERPLANETARY; + + // Set a hook to move to the new location: + debugHook = doInstantMove; + } + + return FALSE; + } +#endif + DrawStarMap (0, NULL); + } + else if (PulsedInputState.menu[KEY_MENU_SEARCH]) + { + if (GET_GAME_STATE (ARILOU_SPACE_SIDE) <= 1) + { // HyperSpace search + POINT oldpt = cursorLoc; + + if (!DoStarSearch (pMS)) + { // search failed or canceled - return cursor + UpdateCursorLocation (0, 0, &oldpt); + } + // make sure cmp fails + strcpy (last_buf, " <random garbage> "); + UpdateCursorInfo (last_buf); + UpdateFuelRequirement (); + + SetMenuRepeatDelay (MIN_ACCEL_DELAY, MAX_ACCEL_DELAY, + STEP_ACCEL_DELAY, TRUE); + SetMenuSounds (MENU_SOUND_NONE, MENU_SOUND_NONE); + } + else + { // no search in QuasiSpace + PlayMenuSound (MENU_SOUND_FAILURE); + } + } + else + { + SBYTE sx, sy; + SIZE ZoomIn, ZoomOut; + + ZoomIn = ZoomOut = 0; + if (PulsedInputState.menu[KEY_MENU_ZOOM_IN]) + ZoomIn = 1; + else if (PulsedInputState.menu[KEY_MENU_ZOOM_OUT]) + ZoomOut = 1; + + ZoomStarMap (ZoomIn - ZoomOut); + + sx = sy = 0; + if (PulsedInputState.menu[KEY_MENU_LEFT]) sx = -1; + if (PulsedInputState.menu[KEY_MENU_RIGHT]) sx = 1; + if (PulsedInputState.menu[KEY_MENU_UP]) sy = -1; + if (PulsedInputState.menu[KEY_MENU_DOWN]) sy = 1; + + if (sx != 0 || sy != 0) + { + UpdateCursorLocation (sx, sy, NULL); + UpdateCursorInfo (last_buf); + UpdateFuelRequirement (); + } + + SleepThreadUntil (TimeIn + MIN_ACCEL_DELAY); + } + + flashCurrentLocation (NULL); + + return !(GLOBAL (CurrentActivity) & CHECK_ABORT); +} + +static void +RepairMap (COUNT update_race, RECT *pLastRect, RECT *pNextRect) +{ + RECT r; + + /* make a rect big enough for text */ + r.extent.width = 50; + r.corner.x = (pNextRect->corner.x + (pNextRect->extent.width >> 1)) + - (r.extent.width >> 1); + if (r.corner.x < 0) + r.corner.x = 0; + else if (r.corner.x + r.extent.width >= SIS_SCREEN_WIDTH) + r.corner.x = SIS_SCREEN_WIDTH - r.extent.width; + r.extent.height = 9; + r.corner.y = (pNextRect->corner.y + (pNextRect->extent.height >> 1)) + - r.extent.height; + if (r.corner.y < 0) + r.corner.y = 0; + else if (r.corner.y + r.extent.height >= SIS_SCREEN_HEIGHT) + r.corner.y = SIS_SCREEN_HEIGHT - r.extent.height; + BoxUnion (pLastRect, &r, &r); + BoxUnion (pNextRect, &r, &r); + *pLastRect = *pNextRect; + + if (r.corner.x < 0) + { + r.extent.width += r.corner.x; + r.corner.x = 0; + } + if (r.corner.x + r.extent.width > SIS_SCREEN_WIDTH) + r.extent.width = SIS_SCREEN_WIDTH - r.corner.x; + if (r.corner.y < 0) + { + r.extent.height += r.corner.y; + r.corner.y = 0; + } + if (r.corner.y + r.extent.height > SIS_SCREEN_HEIGHT) + r.extent.height = SIS_SCREEN_HEIGHT - r.corner.y; + + r.extent.height += r.corner.y & 1; + r.corner.y &= ~1; + + DrawStarMap (update_race, &r); +} + +static void +UpdateMap (void) +{ + BYTE ButtonState, VisibleChange; + BOOLEAN MapDrawn, Interrupted; + COUNT index; + HFLEETINFO hStarShip, hNextShip; + + FlushInput (); + ButtonState = 1; /* assume a button down */ + + MapDrawn = Interrupted = FALSE; + for (index = 1, + hStarShip = GetHeadLink (&GLOBAL (avail_race_q)); + hStarShip; ++index, hStarShip = hNextShip) + { + FLEET_INFO *FleetPtr; + + FleetPtr = LockFleetInfo (&GLOBAL (avail_race_q), hStarShip); + hNextShip = _GetSuccLink (FleetPtr); + + if (ButtonState) + { + if (!AnyButtonPress (TRUE)) + ButtonState = 0; + } + else if ((Interrupted = (BOOLEAN)( + Interrupted || AnyButtonPress (TRUE) + ))) + MapDrawn = TRUE; + + if (FleetPtr->known_strength) + { + SIZE dx, dy, delta; + RECT r, last_r, temp_r0, temp_r1; + + dx = FleetPtr->loc.x - FleetPtr->known_loc.x; + dy = FleetPtr->loc.y - FleetPtr->known_loc.y; + if (dx || dy) + { + SIZE xincr, yincr, + xerror, yerror, + cycle; + + if (dx >= 0) + xincr = 1; + else + { + xincr = -1; + dx = -dx; + } + dx <<= 1; + + if (dy >= 0) + yincr = 1; + else + { + yincr = -1; + dy = -dy; + } + dy <<= 1; + + if (dx >= dy) + cycle = dx; + else + cycle = dy; + delta = xerror = yerror = cycle >> 1; + + if (!MapDrawn) + { + DrawStarMap ((COUNT)~0, NULL); + MapDrawn = TRUE; + } + + GetSphereRect (FleetPtr, &temp_r0, &last_r); + ++last_r.extent.width; + ++last_r.extent.height; + VisibleChange = FALSE; + do + { + do + { + if ((xerror -= dx) <= 0) + { + FleetPtr->known_loc.x += xincr; + xerror += cycle; + } + if ((yerror -= dy) <= 0) + { + FleetPtr->known_loc.y += yincr; + yerror += cycle; + } + GetSphereRect (FleetPtr, &temp_r1, &r); + } while (delta-- + && ((delta & 0x1F) + || (temp_r0.corner.x == temp_r1.corner.x + && temp_r0.corner.y == temp_r1.corner.y))); + + if (ButtonState) + { + if (!AnyButtonPress (TRUE)) + ButtonState = 0; + } + else if ((Interrupted = (BOOLEAN)( + Interrupted || AnyButtonPress (TRUE) + ))) + { + MapDrawn = TRUE; + goto DoneSphereMove; + } + + ++r.extent.width; + ++r.extent.height; + if (temp_r0.corner.x != temp_r1.corner.x + || temp_r0.corner.y != temp_r1.corner.y) + { + VisibleChange = TRUE; + RepairMap (index, &last_r, &r); + } + } while (delta >= 0); + if (VisibleChange) + RepairMap ((COUNT)~0, &last_r, &r); + +DoneSphereMove: + FleetPtr->known_loc = FleetPtr->loc; + } + + delta = FleetPtr->actual_strength - FleetPtr->known_strength; + if (delta) + { + if (!MapDrawn) + { + DrawStarMap ((COUNT)~0, NULL); + MapDrawn = TRUE; + } + + if (delta > 0) + dx = 1; + else + { + delta = -delta; + dx = -1; + } + --delta; + + GetSphereRect (FleetPtr, &temp_r0, &last_r); + ++last_r.extent.width; + ++last_r.extent.height; + VisibleChange = FALSE; + do + { + do + { + FleetPtr->known_strength += dx; + GetSphereRect (FleetPtr, &temp_r1, &r); + } while (delta-- + && ((delta & 0xF) + || temp_r0.extent.height == temp_r1.extent.height)); + + if (ButtonState) + { + if (!AnyButtonPress (TRUE)) + ButtonState = 0; + } + else if ((Interrupted = (BOOLEAN)( + Interrupted || AnyButtonPress (TRUE) + ))) + { + MapDrawn = TRUE; + goto DoneSphereGrowth; + } + ++r.extent.width; + ++r.extent.height; + if (temp_r0.extent.height != temp_r1.extent.height) + { + VisibleChange = TRUE; + RepairMap (index, &last_r, &r); + } + } while (delta >= 0); + if (VisibleChange || temp_r0.extent.width != temp_r1.extent.width) + RepairMap ((COUNT)~0, &last_r, &r); + +DoneSphereGrowth: + FleetPtr->known_strength = FleetPtr->actual_strength; + } + } + + UnlockFleetInfo (&GLOBAL (avail_race_q), hStarShip); + } +} + +BOOLEAN +StarMap (void) +{ + MENU_STATE MenuState; + POINT universe; + //FRAME OldFrame; + RECT clip_r; + CONTEXT OldContext; + + memset (&MenuState, 0, sizeof (MenuState)); + + zoomLevel = 0; + mapOrigin.x = MAX_X_UNIVERSE >> 1; + mapOrigin.y = MAX_Y_UNIVERSE >> 1; + StarMapFrame = SetAbsFrameIndex (MiscDataFrame, 48); + + if (!inHQSpace ()) + universe = CurStarDescPtr->star_pt; + else + { + universe.x = LOGX_TO_UNIVERSE (GLOBAL_SIS (log_x)); + universe.y = LOGY_TO_UNIVERSE (GLOBAL_SIS (log_y)); + } + + cursorLoc = GLOBAL (autopilot); + if (cursorLoc.x == ~0 && cursorLoc.y == ~0) + cursorLoc = universe; + + MenuState.InputFunc = DoMoveCursor; + MenuState.Initialized = FALSE; + + transition_pending = TRUE; + if (GET_GAME_STATE (ARILOU_SPACE_SIDE) <= 1) + UpdateMap (); + + DrawStarMap (0, (RECT*)-1); + transition_pending = FALSE; + + BatchGraphics (); + OldContext = SetContext (SpaceContext); + GetContextClipRect (&clip_r); + SetContext (OldContext); + LoadIntoExtraScreen (&clip_r); + DrawCursor (UNIVERSE_TO_DISPX (cursorLoc.x), + UNIVERSE_TO_DISPY (cursorLoc.y)); + UnbatchGraphics (); + + SetMenuSounds (MENU_SOUND_NONE, MENU_SOUND_NONE); + SetMenuRepeatDelay (MIN_ACCEL_DELAY, MAX_ACCEL_DELAY, STEP_ACCEL_DELAY, + TRUE); + DoInput (&MenuState, FALSE); + SetMenuSounds (MENU_SOUND_ARROWS, MENU_SOUND_SELECT); + SetDefaultMenuRepeatDelay (); + + DrawHyperCoords (universe); + DrawSISMessage (NULL); + DrawStatusMessage (NULL); + + if (GLOBAL (autopilot.x) == universe.x + && GLOBAL (autopilot.y) == universe.y) + GLOBAL (autopilot.x) = GLOBAL (autopilot.y) = ~0; + + return (GLOBAL (autopilot.x) != ~0 + && GLOBAL (autopilot.y) != ~0); +} + |