diff options
Diffstat (limited to 'src/uqm/starbase.c')
-rw-r--r-- | src/uqm/starbase.c | 602 |
1 files changed, 602 insertions, 0 deletions
diff --git a/src/uqm/starbase.c b/src/uqm/starbase.c new file mode 100644 index 0000000..f119208 --- /dev/null +++ b/src/uqm/starbase.c @@ -0,0 +1,602 @@ +//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 "starmap.h" +#include "comm.h" +#include "gamestr.h" +#include "save.h" +#include "starbase.h" +#include "sis.h" +#include "resinst.h" +#include "nameref.h" +#include "settings.h" +#include "setup.h" +#include "sounds.h" +#include "libs/graphics/gfx_common.h" +#include "libs/tasklib.h" + + +static void CleanupAfterStarBase (void); + +static void +DrawBaseStateStrings (STARBASE_STATE OldState, STARBASE_STATE NewState) +{ + TEXT t; + //STRING locString; + + SetContext (ScreenContext); + SetContextFont (StarConFont); + SetContextForeGroundColor (BLACK_COLOR); + + t.baseline.x = 73 - 4 + SAFE_X; + t.align = ALIGN_CENTER; + + if (OldState == (STARBASE_STATE)~0) + { + t.baseline.y = 106 + 28 + (SAFE_Y + 4); + for (OldState = TALK_COMMANDER; OldState < DEPART_BASE; ++OldState) + { + if (OldState != NewState) + { + t.pStr = GAME_STRING (STARBASE_STRING_BASE + 1 + OldState); + t.CharCount = (COUNT)~0; + font_DrawText (&t); + } + t.baseline.y += (23 - 4); + } + } + + t.baseline.y = 106 + 28 + (SAFE_Y + 4) + ((23 - 4) * OldState); + t.pStr = GAME_STRING (STARBASE_STRING_BASE + 1 + OldState); + t.CharCount = (COUNT)~0; + font_DrawText (&t); + + SetContextForeGroundColor ( + BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x0A), 0x0E)); + t.baseline.y = 106 + 28 + (SAFE_Y + 4) + ((23 - 4) * NewState); + t.pStr = GAME_STRING (STARBASE_STRING_BASE + 1 + NewState); + t.CharCount = (COUNT)~0; + font_DrawText (&t); +} + +void +DrawShipPiece (FRAME ModuleFrame, COUNT which_piece, COUNT which_slot, + BOOLEAN DrawBluePrint) +{ + Color OldColor = UNDEFINED_COLOR; + // Initialisation is just to keep the compiler silent. + RECT r; + STAMP Side, Top; + SBYTE RepairSlot; + + RepairSlot = 0; + switch (which_piece) + { + case FUSION_THRUSTER: + case EMPTY_SLOT + 0: + Side.origin.x = DRIVE_SIDE_X; + Side.origin.y = DRIVE_SIDE_Y; + Top.origin.x = DRIVE_TOP_X; + Top.origin.y = DRIVE_TOP_Y; + break; + case TURNING_JETS: + case EMPTY_SLOT + 1: + Side.origin.x = JET_SIDE_X; + Side.origin.y = JET_SIDE_Y; + Top.origin.x = JET_TOP_X; + Top.origin.y = JET_TOP_Y; + break; + default: + if (which_piece < EMPTY_SLOT + 2) + { + RepairSlot = 1; + if (which_piece < EMPTY_SLOT + && (which_slot == 0 + || GLOBAL_SIS (ModuleSlots[ + which_slot - 1 + ]) < EMPTY_SLOT)) + ++RepairSlot; + } + else if (!DrawBluePrint) + { + if (which_slot == 0 || which_slot >= NUM_MODULE_SLOTS - 3) + ++which_piece; + + if (which_slot < NUM_MODULE_SLOTS - 1 + && GLOBAL_SIS (ModuleSlots[ + which_slot + 1 + ]) < EMPTY_SLOT) + { + RepairSlot = -1; + if (which_piece == EMPTY_SLOT + 3 + || which_slot + 1 == NUM_MODULE_SLOTS - 3) + --RepairSlot; + } + } + Side.origin.x = MODULE_SIDE_X; + Side.origin.y = MODULE_SIDE_Y; + Top.origin.x = MODULE_TOP_X; + Top.origin.y = MODULE_TOP_Y; + break; + } + + Side.origin.x += which_slot * SHIP_PIECE_OFFSET; + Side.frame = NULL; + if (RepairSlot < 0) + { + Side.frame = SetAbsFrameIndex (ModuleFrame, + ((NUM_MODULES - 1) + (6 - 2)) + (NUM_MODULES + 6) + - (RepairSlot + 1)); + DrawStamp (&Side); + } + else if (RepairSlot) + { + r.corner = Side.origin; + r.extent.width = SHIP_PIECE_OFFSET; + r.extent.height = 1; + OldColor = SetContextForeGroundColor (BLACK_COLOR); + DrawFilledRectangle (&r); + r.corner.y += 23 - 1; + DrawFilledRectangle (&r); + + r.extent.width = 1; + r.extent.height = 8; + if (RepairSlot == 2) + { + r.corner = Side.origin; + DrawFilledRectangle (&r); + r.corner.y += 15; + DrawFilledRectangle (&r); + } + if (which_slot < (NUM_MODULE_SLOTS - 1)) + { + r.corner = Side.origin; + r.corner.x += SHIP_PIECE_OFFSET; + DrawFilledRectangle (&r); + r.corner.y += 15; + DrawFilledRectangle (&r); + } + } + + if (DrawBluePrint) + { + if (RepairSlot) + SetContextForeGroundColor (OldColor); + Side.frame = SetAbsFrameIndex (ModuleFrame, which_piece - 1); + DrawFilledStamp (&Side); + } + else + { + Top.origin.x += which_slot * SHIP_PIECE_OFFSET; + if (RepairSlot < 0) + { + Top.frame = SetRelFrameIndex (Side.frame, -((NUM_MODULES - 1) + 6)); + DrawStamp (&Top); + } + else if (RepairSlot) + { + r.corner = Top.origin; + r.extent.width = SHIP_PIECE_OFFSET; + r.extent.height = 1; + DrawFilledRectangle (&r); + r.corner.y += 32 - 1; + DrawFilledRectangle (&r); + + r.extent.width = 1; + r.extent.height = 12; + if (RepairSlot == 2) + { + r.corner = Top.origin; + DrawFilledRectangle (&r); + r.corner.y += 20; + DrawFilledRectangle (&r); + } + RepairSlot = (which_slot < NUM_MODULE_SLOTS - 1); + if (RepairSlot) + { + r.corner = Top.origin; + r.corner.x += SHIP_PIECE_OFFSET; + DrawFilledRectangle (&r); + r.corner.y += 20; + DrawFilledRectangle (&r); + } + } + + Top.frame = SetAbsFrameIndex (ModuleFrame, which_piece); + DrawStamp (&Top); + + Side.frame = SetRelFrameIndex (Top.frame, (NUM_MODULES - 1) + 6); + DrawStamp (&Side); + + if (which_slot == 1 && which_piece == EMPTY_SLOT + 2) + { + STAMP s; + + s.origin = Top.origin; + s.origin.x -= SHIP_PIECE_OFFSET; + s.frame = SetAbsFrameIndex (ModuleFrame, NUM_MODULES + 5); + DrawStamp (&s); + s.origin = Side.origin; + s.origin.x -= SHIP_PIECE_OFFSET; + s.frame = SetRelFrameIndex (s.frame, (NUM_MODULES - 1) + 6); + DrawStamp (&s); + } + + if (RepairSlot) + { + Top.origin.x += SHIP_PIECE_OFFSET; + Side.origin.x += SHIP_PIECE_OFFSET; + which_piece = GLOBAL_SIS (ModuleSlots[++which_slot]); + if (which_piece == EMPTY_SLOT + 2 + && which_slot >= NUM_MODULE_SLOTS - 3) + ++which_piece; + + Top.frame = SetAbsFrameIndex (ModuleFrame, which_piece); + DrawStamp (&Top); + + Side.frame = SetRelFrameIndex (Top.frame, (NUM_MODULES - 1) + 6); + DrawStamp (&Side); + } + } +} + +static void +rotateStarbase (MENU_STATE *pMS, FRAME AniFrame) +{ + static TimeCount NextTime = 0; + TimeCount Now = GetTimeCounter (); + + if (AniFrame) + { // Setup the animation + pMS->flash_frame0 = AniFrame; + pMS->flash_rect0.corner.x = SAFE_X; + pMS->flash_rect0.corner.y = SAFE_Y + 4; + } + + if (Now >= NextTime || AniFrame) + { + STAMP s; + + NextTime = Now + (ONE_SECOND / 20); + + s.origin = pMS->flash_rect0.corner; + s.frame = pMS->flash_frame0; + DrawStamp (&s); + + s.frame = IncFrameIndex (s.frame); + if (GetFrameIndex (s.frame) == 0) + { // Do not redraw the base frame, animation loops to frame 1 + s.frame = IncFrameIndex (s.frame); + } + pMS->flash_frame0 = s.frame; + } +} + +BOOLEAN +DoStarBase (MENU_STATE *pMS) +{ + // XXX: This function is full of hacks and otherwise strange code + + if (GLOBAL (CurrentActivity) & (CHECK_ABORT | CHECK_LOAD)) + { + pMS->CurState = DEPART_BASE; + goto ExitStarBase; + } + SetMenuSounds (MENU_SOUND_ARROWS, MENU_SOUND_SELECT); + + if (!pMS->Initialized) + { + LastActivity &= ~CHECK_LOAD; + pMS->InputFunc = DoStarBase; + + SetFlashRect (NULL); + + if (pMS->hMusic) + { + StopMusic (); + DestroyMusic (pMS->hMusic); + pMS->hMusic = 0; + } + + pMS->Initialized = TRUE; + + pMS->CurFrame = CaptureDrawable (LoadGraphic (STARBASE_ANIM)); + pMS->hMusic = LoadMusic (STARBASE_MUSIC); + + SetContext (ScreenContext); + SetTransitionSource (NULL); + BatchGraphics (); + SetContextBackGroundColor (BLACK_COLOR); + ClearDrawable (); + rotateStarbase (pMS, pMS->CurFrame); + DrawBaseStateStrings ((STARBASE_STATE)~0, pMS->CurState); + ScreenTransition (3, NULL); + PlayMusic (pMS->hMusic, TRUE, 1); + UnbatchGraphics (); + } + else if (PulsedInputState.menu[KEY_MENU_SELECT]) + { +ExitStarBase: + DestroyDrawable (ReleaseDrawable (pMS->CurFrame)); + pMS->CurFrame = 0; + StopMusic (); + if (pMS->hMusic) + { + DestroyMusic (pMS->hMusic); + pMS->hMusic = 0; + } + + if (pMS->CurState == DEPART_BASE) + { + if (!(GLOBAL (CurrentActivity) & (CHECK_ABORT | CHECK_LOAD))) + { + SET_GAME_STATE (STARBASE_VISITED, 0); + } + return (FALSE); + } + + pMS->Initialized = FALSE; + if (pMS->CurState == TALK_COMMANDER) + { + FlushInput (); + InitCommunication (COMMANDER_CONVERSATION); + // XXX: InitCommunication() clears these flags, and we need them + // This marks that we are in Starbase. + SET_GAME_STATE (GLOBAL_FLAGS_AND_DATA, (BYTE)~0); + } + else + { + BYTE OldState; + + switch (OldState = pMS->CurState) + { + case OUTFIT_STARSHIP: + pMS->InputFunc = DoOutfit; + break; + case SHIPYARD: + pMS->InputFunc = DoShipyard; + break; + } + + SetMenuSounds (MENU_SOUND_ARROWS, MENU_SOUND_SELECT); + DoInput (pMS, TRUE); + + pMS->Initialized = FALSE; + pMS->CurState = OldState; + pMS->InputFunc = DoStarBase; + } + } + else + { + STARBASE_STATE NewState; + + NewState = pMS->CurState; + if (PulsedInputState.menu[KEY_MENU_LEFT] || PulsedInputState.menu[KEY_MENU_UP]) + { + if (NewState-- == TALK_COMMANDER) + NewState = DEPART_BASE; + } + else if (PulsedInputState.menu[KEY_MENU_RIGHT] || PulsedInputState.menu[KEY_MENU_DOWN]) + { + if (NewState++ == DEPART_BASE) + NewState = TALK_COMMANDER; + } + + BatchGraphics (); + SetContext (ScreenContext); + + if (NewState != pMS->CurState) + { + DrawBaseStateStrings (pMS->CurState, NewState); + pMS->CurState = NewState; + } + + rotateStarbase (pMS, NULL); + + UnbatchGraphics (); + + SleepThread (ONE_SECOND / 30); + } + + return (TRUE); +} + +static void +DoTimePassage (void) +{ +#define LOST_DAYS 14 + SleepThreadUntil (FadeScreen (FadeAllToBlack, ONE_SECOND * 2)); + MoveGameClockDays (LOST_DAYS); +} + +void +VisitStarBase (void) +{ + MENU_STATE MenuState; + CONTEXT OldContext; + StatMsgMode prevMsgMode = SMM_UNDEFINED; + + // XXX: This should probably be moved out to Starcon2Main() + if (GET_GAME_STATE (CHMMR_BOMB_STATE) == 2) + { // We were just transported by Chmmr to the Starbase + // Force a reload of the SolarSys + CurStarDescPtr = NULL; + // This marks that we are in Starbase. + SET_GAME_STATE (GLOBAL_FLAGS_AND_DATA, (BYTE)~0); + } + + if (!GET_GAME_STATE (STARBASE_AVAILABLE)) + { + HSHIPFRAG hStarShip; + SHIP_FRAGMENT *FragPtr; + + // Unallied Starbase conversation + SetCommIntroMode (CIM_CROSSFADE_SCREEN, 0); + InitCommunication (COMMANDER_CONVERSATION); + if (!GET_GAME_STATE (PROBE_ILWRATH_ENCOUNTER) + || (GLOBAL (CurrentActivity) & CHECK_ABORT)) + { + CleanupAfterStarBase (); + return; + } + + /* Create an Ilwrath ship responding to the Ur-Quan + * probe's broadcast */ + hStarShip = CloneShipFragment (ILWRATH_SHIP, + &GLOBAL (npc_built_ship_q), 7); + FragPtr = LockShipFrag (&GLOBAL (npc_built_ship_q), hStarShip); + /* Hack (sort of): Suppress the tally and salvage info + * after the battle */ + FragPtr->race_id = (BYTE)~0; + UnlockShipFrag (&GLOBAL (npc_built_ship_q), hStarShip); + + InitCommunication (ILWRATH_CONVERSATION); + if (GLOBAL_SIS (CrewEnlisted) == (COUNT)~0 + || (GLOBAL (CurrentActivity) & CHECK_ABORT)) + return; // Killed by Ilwrath + + // After Ilwrath battle, about-to-ally Starbase conversation + SetCommIntroMode (CIM_CROSSFADE_SCREEN, 0); + InitCommunication (COMMANDER_CONVERSATION); + if (GLOBAL (CurrentActivity) & CHECK_ABORT) + return; + // XXX: InitCommunication() clears these flags, and we need them + // This marks that we are in Starbase. + SET_GAME_STATE (GLOBAL_FLAGS_AND_DATA, (BYTE)~0); + } + + prevMsgMode = SetStatusMessageMode (SMM_RES_UNITS); + + if (GET_GAME_STATE (MOONBASE_ON_SHIP) + || GET_GAME_STATE (CHMMR_BOMB_STATE) == 2) + { // Go immediately into a conversation with the Commander when the + // Starbase becomes available for the first time, or after Chmmr + // install the bomb. + DoTimePassage (); + if (GLOBAL_SIS (CrewEnlisted) == (COUNT)~0) + return; // You are now dead! Thank you! (killed by Kohr-Ah) + + SetCommIntroMode (CIM_FADE_IN_SCREEN, ONE_SECOND * 2); + InitCommunication (COMMANDER_CONVERSATION); + if (GLOBAL (CurrentActivity) & CHECK_ABORT) + return; + // XXX: InitCommunication() clears these flags, and we need them + // This marks that we are in Starbase. + SET_GAME_STATE (GLOBAL_FLAGS_AND_DATA, (BYTE)~0); + } + + memset (&MenuState, 0, sizeof (MenuState)); + MenuState.InputFunc = DoStarBase; + + OldContext = SetContext (ScreenContext); + DoInput (&MenuState, TRUE); + SetContext (OldContext); + + SetStatusMessageMode (prevMsgMode); + CleanupAfterStarBase (); +} + +static void +CleanupAfterStarBase (void) +{ + if (!(GLOBAL (CurrentActivity) & (CHECK_LOAD | CHECK_ABORT))) + { + // Mark as not in Starbase anymore + SET_GAME_STATE (GLOBAL_FLAGS_AND_DATA, 0); + // Fake a load so Starcon2Main takes us to IP + GLOBAL (CurrentActivity) = CHECK_LOAD; + NextActivity = MAKE_WORD (IN_INTERPLANETARY, 0) + | START_INTERPLANETARY; + } +} + +void +InstallBombAtEarth (void) +{ + DoTimePassage (); + + SetContext (ScreenContext); + SetTransitionSource (NULL); + SetContextBackGroundColor (BLACK_COLOR); + ClearDrawable (); + + SleepThreadUntil (FadeScreen (FadeAllToColor, 0)); + + SET_GAME_STATE (CHMMR_BOMB_STATE, 3); /* bomb processed */ + GLOBAL (CurrentActivity) = CHECK_LOAD; /* fake a load game */ + NextActivity = MAKE_WORD (IN_INTERPLANETARY, 0) | START_INTERPLANETARY; + CurStarDescPtr = 0; /* force SolarSys reload */ +} + +// XXX: Doesn't really belong in this file. +COUNT +WrapText (const UNICODE *pStr, COUNT len, TEXT *tarray, SIZE field_width) +{ + COUNT num_lines; + + num_lines = 0; + do + { + RECT r; + COUNT OldCount; + + tarray->align = ALIGN_LEFT; /* set alignment to something */ + tarray->pStr = pStr; + tarray->CharCount = 1; + ++num_lines; + + do + { + OldCount = tarray->CharCount; + while (*++pStr != ' ' && (COUNT)(pStr - tarray->pStr) < len) + ; + tarray->CharCount = pStr - tarray->pStr; + TextRect (tarray, &r, NULL); + } while (tarray->CharCount < len && r.extent.width < field_width); + + if (r.extent.width >= field_width) + { + if ((tarray->CharCount = OldCount) == 1) + { + do + { + ++tarray->CharCount; + TextRect (tarray, &r, NULL); + } while (r.extent.width < field_width); + --tarray->CharCount; + } + } + + pStr = tarray->pStr + tarray->CharCount; + len -= tarray->CharCount; + ++tarray; + + if (len && (r.extent.width < field_width || OldCount > 1)) + { + ++pStr; /* skip white space */ + --len; + } + + } while (len); + + return (num_lines); +} + |