/* * 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; }
static HSHIPFRAG MatchSupportShip (MENU_STATE *pMS) { POINT *pship_pos; HSHIPFRAG hStarShip, hNextShip; for (hStarShip = GetHeadLink (&GLOBAL (built_ship_q)), pship_pos = (POINT*)pMS->flash_frame0; hStarShip; hStarShip = hNextShip, ++pship_pos) { SHIP_FRAGMENT *StarShipPtr; StarShipPtr = LockShipFrag (&GLOBAL (built_ship_q), hStarShip); if (pship_pos->x == pMS->first_item.x && pship_pos->y == pMS->first_item.y) { UnlockShipFrag (&GLOBAL (built_ship_q), hStarShip); return hStarShip; } hNextShip = _GetSuccLink (StarShipPtr); UnlockShipFrag (&GLOBAL (built_ship_q), hStarShip); } return 0; }
static void RosterCleanup (MENU_STATE *pMS) { if (pMS->flash_task) { UnlockMutex (GraphicsLock); ConcludeTask (pMS->flash_task); LockMutex (GraphicsLock); pMS->flash_task = 0; } if (pMS->CurFrame) { STAMP s; SHIP_FRAGMENT *StarShipPtr; SetContext (StatusContext); s.origin = pMS->first_item; StarShipPtr = LockShipFrag (&GLOBAL (built_ship_q), (HSHIPFRAG)pMS->CurFrame); s.frame = StarShipPtr->icons; UnlockShipFrag (&GLOBAL (built_ship_q), (HSHIPFRAG)pMS->CurFrame); if (!(pMS->CurState & SHIP_TOGGLE)) DrawStamp (&s); else { SetContextForeGroundColor (WHITE_COLOR); DrawFilledStamp (&s); } } }
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; }
/* * 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; }
// 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; }
void clearEscorts (void) { 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); UnlockShipFrag (&GLOBAL (built_ship_q), hStarShip); RemoveQueue (&GLOBAL (built_ship_q), hStarShip); FreeShipFrag (&GLOBAL (built_ship_q), hStarShip); } DeltaSISGauges (UNDEFINED_DELTA, UNDEFINED_DELTA, UNDEFINED_DELTA); }
static int flash_ship_task (void *data) { DWORD TimeIn; COLOR c; Task task = (Task) data; c = BUILD_COLOR (MAKE_RGB15 (0x1F, 0x00, 0x00), 0x24); TimeIn = GetTimeCounter (); while (!Task_ReadState (task, TASK_EXIT)) { STAMP s; SHIP_FRAGMENT *StarShipPtr; COLOR OldColor; CONTEXT OldContext; LockMutex (GraphicsLock); s.origin = pMenuState->first_item; StarShipPtr = LockShipFrag (&GLOBAL (built_ship_q), (HSHIPFRAG)pMenuState->CurFrame); s.frame = StarShipPtr->icons; UnlockShipFrag (&GLOBAL (built_ship_q), (HSHIPFRAG)pMenuState->CurFrame); OldContext = SetContext (StatusContext); 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); OldColor = SetContextForeGroundColor (c); DrawFilledStamp (&s); SetContextForeGroundColor (OldColor); SetContext (OldContext); UnlockMutex (GraphicsLock); SleepThreadUntil (TimeIn + ONE_SECOND / 15); TimeIn = GetTimeCounter (); } FinishTask (task); return 0; }
/* * 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; }
static void LoadShipQueue (DECODE_REF fh, QUEUE *pQueue) { COUNT num_links; cread_16 (fh, &num_links); while (num_links--) { HSHIPFRAG hStarShip; SHIP_FRAGMENT *FragPtr; COUNT Index; BYTE tmpb; cread_16 (fh, &Index); hStarShip = CloneShipFragment (Index, pQueue, 0); FragPtr = LockShipFrag (pQueue, hStarShip); // Read SHIP_FRAGMENT elements cread_16 (fh, NULL); /* unused: was which_side */ cread_8 (fh, &FragPtr->captains_name_index); cread_8 (fh, NULL); /* padding */ cread_16 (fh, NULL); /* unused: was ship_flags */ cread_8 (fh, &FragPtr->race_id); cread_8 (fh, &FragPtr->index); // XXX: reading crew as BYTE to maintain savegame compatibility cread_8 (fh, &tmpb); FragPtr->crew_level = tmpb; cread_8 (fh, &tmpb); FragPtr->max_crew = tmpb; cread_8 (fh, &FragPtr->energy_level); cread_8 (fh, &FragPtr->max_energy); cread_16 (fh, NULL); /* unused; was loc.x */ cread_16 (fh, NULL); /* unused; was loc.y */ UnlockShipFrag (pQueue, hStarShip); } }
/* * 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; }
/* 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; }
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; }
static BOOLEAN DeltaSupportCrew (SIZE crew_delta) { BOOLEAN ret = FALSE; UNICODE buf[40]; HFLEETINFO hTemplate; SHIP_FRAGMENT *StarShipPtr; FLEET_INFO *TemplatePtr; StarShipPtr = LockShipFrag (&GLOBAL (built_ship_q), (HSHIPFRAG)pMenuState->CurFrame); hTemplate = GetStarShipFromIndex (&GLOBAL (avail_race_q), StarShipPtr->race_id); TemplatePtr = LockFleetInfo (&GLOBAL (avail_race_q), hTemplate); if (crew_delta > 0) { while (crew_delta && (StarShipPtr->crew_level + crew_delta) > StarShipPtr->max_crew) crew_delta--; } else if (crew_delta < 0) { while (crew_delta && (StarShipPtr->crew_level + crew_delta) < 1) crew_delta++; } 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); DrawStatusMessage (buf); DeltaSISGauges (-crew_delta, 0, 0); if (crew_delta) { RECT r; r.corner.x = 2; r.corner.y = 130; r.extent.width = STATUS_MESSAGE_WIDTH; r.extent.height = STATUS_MESSAGE_HEIGHT; SetContext (StatusContext); SetFlashRect (&r, (FRAME)0); } ret = TRUE; } UnlockFleetInfo (&GLOBAL (avail_race_q), hTemplate); UnlockShipFrag (&GLOBAL (built_ship_q), (HSHIPFRAG)pMenuState->CurFrame); return ret; }
static BOOLEAN DoModifyRoster (MENU_STATE *pMS) { BYTE NewState; SBYTE sx, sy; RECT r; STAMP s; SHIP_FRAGMENT *StarShipPtr; BOOLEAN select, cancel, up, down, pgup, pgdn, horiz; if (GLOBAL (CurrentActivity) & CHECK_ABORT) { LockMutex (GraphicsLock); RosterCleanup (pMS); UnlockMutex (GraphicsLock); pMS->CurFrame = 0; 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]; horiz = PulsedInputState.menu[KEY_MENU_LEFT] || PulsedInputState.menu[KEY_MENU_RIGHT]; pgup = PulsedInputState.menu[KEY_MENU_PAGE_UP]; pgdn = PulsedInputState.menu[KEY_MENU_PAGE_DOWN]; if (pMS->Initialized && (pMS->CurState & SHIP_TOGGLE)) { SetMenuSounds (MENU_SOUND_UP | MENU_SOUND_DOWN | MENU_SOUND_PAGEUP | MENU_SOUND_PAGEDOWN, MENU_SOUND_SELECT | MENU_SOUND_CANCEL); } else { SetMenuSounds (MENU_SOUND_ARROWS | MENU_SOUND_PAGEUP | MENU_SOUND_PAGEDOWN, MENU_SOUND_SELECT); } if (!pMS->Initialized) { pMS->InputFunc = DoModifyRoster; pMS->Initialized = TRUE; pMS->CurState = NewState = 0; LockMutex (GraphicsLock); SetContext (StatusContext); goto SelectSupport; } else if (cancel && !(pMS->CurState & SHIP_TOGGLE)) { LockMutex (GraphicsLock); SetFlashRect (NULL, (FRAME)0); RosterCleanup (pMS); pMS->CurFrame = 0; DrawStatusMessage (NULL); UnlockMutex (GraphicsLock); return FALSE; } else if (select || cancel) { LockMutex (GraphicsLock); pMS->CurState ^= SHIP_TOGGLE; if (!(pMS->CurState & SHIP_TOGGLE)) SetFlashRect (NULL, (FRAME)0); else { RosterCleanup (pMS); r.corner.x = 2; r.corner.y = 130; r.extent.width = STATUS_MESSAGE_WIDTH; r.extent.height = STATUS_MESSAGE_HEIGHT; SetContext (StatusContext); SetFlashRect (&r, (FRAME)0); } UnlockMutex (GraphicsLock); } else if (pMS->CurState & SHIP_TOGGLE) { SIZE delta = 0; BOOLEAN failed = FALSE; if (up || pgup) { if (GLOBAL_SIS (CrewEnlisted)) delta = pgup ? 10 : 1; else failed = TRUE; } else if (down || pgdn) { if (GLOBAL_SIS (CrewEnlisted) < GetCPodCapacity (NULL)) delta = pgdn ? -10 : -1; else failed = TRUE; } if (delta != 0) { LockMutex (GraphicsLock); failed = !DeltaSupportCrew (delta); UnlockMutex (GraphicsLock); } if (failed) { // not enough room or crew PlayMenuSound (MENU_SOUND_FAILURE); } } else { POINT *pship_pos; NewState = pMS->CurState; sx = (SBYTE)((pMS->delta_item + 1) >> 1); if (horiz) { pship_pos = (POINT*)pMS->flash_frame1; if (NewState == (BYTE)(sx - 1)) NewState = (BYTE)(pMS->delta_item - 1); else if (NewState >= (BYTE)sx) { NewState -= sx; if (pship_pos[NewState].y < pship_pos[pMS->CurState].y) ++NewState; } else { NewState += sx; if (NewState != (BYTE)sx && pship_pos[NewState].y > pship_pos[pMS->CurState].y) --NewState; } } else if (down) { sy = 1; if (++NewState == (BYTE)pMS->delta_item) NewState = (BYTE)(sx - 1); else if (NewState == (BYTE)sx) NewState = 0; } else if (up) { sy = -1; if (NewState == 0) NewState += sx - 1; else if (NewState == (BYTE)sx) NewState = (BYTE)(pMS->delta_item - 1); else --NewState; } if (NewState != pMS->CurState) { LockMutex (GraphicsLock); SetContext (StatusContext); s.origin = pMS->first_item; StarShipPtr = LockShipFrag (&GLOBAL (built_ship_q), (HSHIPFRAG)pMS->CurFrame); s.frame = StarShipPtr->icons; UnlockShipFrag (&GLOBAL (built_ship_q), (HSHIPFRAG)pMS->CurFrame); DrawStamp (&s); SelectSupport: pship_pos = (POINT*)pMS->flash_frame1; pMS->first_item = pship_pos[NewState]; pMS->CurFrame = (FRAME)MatchSupportShip (pMS); DeltaSupportCrew (0); UnlockMutex (GraphicsLock); pMS->CurState = NewState; } if (pMS->flash_task == 0) pMS->flash_task = AssignTask (flash_ship_task, 2048, "flash roster menu"); } return TRUE; }