ULONG SlAddMenuItem( PSL_MENU Menu, PCHAR Text, PVOID Data, ULONG Attributes ) /*++ Routine Description: Adds an item to the menu Arguments: Menu - Supplies a pointer to the menu the item will be added to Text - Supplies the text to be displayed in the menu Data - Supplies a pointer to the data to be returned when the item is selected. Attributes - Supplies any attributes for the item. Return Value: The Selection index if successful -1 on failure --*/ { PSL_MENUITEM NewItem; ULONG Length; NewItem = BlAllocateHeap(sizeof(SL_MENUITEM)); if (NewItem==NULL) { SlError(0); return((ULONG)-1); } InsertTailList(&Menu->ItemListHead, &NewItem->ListEntry); Menu->ItemCount += 1; NewItem->Text = Text; NewItem->Data = Data; NewItem->Attributes = Attributes; Length = strlen(Text); if (Length > Menu->Width) { Menu->Width = Length; } return(Menu->ItemCount - 1); }
PVOID SlGetMenuItem( IN PSL_MENU Menu, IN ULONG Item ) /*++ Routine Description: Given an item index, returns the data associated with that item. Arguments: Menu - Supplies the menu structure. Item - Supplies the item index. Return Value: The data associated with the given item. --*/ { ULONG i; PSL_MENUITEM MenuItem; // // Find item to return // MenuItem = CONTAINING_RECORD(Menu->ItemListHead.Flink, SL_MENUITEM, ListEntry); for (i=0;i<Item;i++) { MenuItem = CONTAINING_RECORD(MenuItem->ListEntry.Flink, SL_MENUITEM, ListEntry); #if DBG if (&MenuItem->ListEntry == &Menu->ItemListHead) { SlError(Item); return(NULL); } #endif } return(MenuItem->Data); }
/** * Perform all steps to upgrade from the old waypoints to the new version * that uses station. This includes some old saveload mechanics. */ void MoveWaypointsToBaseStations() { /* In version 17, ground type is moved from m2 to m4 for depots and * waypoints to make way for storing the index in m2. The custom graphics * id which was stored in m4 is now saved as a grf/id reference in the * waypoint struct. */ if (IsSavegameVersionBefore(17)) { for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) { if (wp->delete_ctr != 0) continue; // The waypoint was deleted /* Waypoint indices were not added to the map prior to this. */ _m[wp->xy].m2 = (StationID)wp->index; if (HasBit(_m[wp->xy].m3, 4)) { wp->spec = StationClass::Get(STAT_CLASS_WAYP, _m[wp->xy].m4 + 1); } } } else { /* As of version 17, we recalculate the custom graphic ID of waypoints * from the GRF ID / station index. */ for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) { for (uint i = 0; i < StationClass::GetCount(STAT_CLASS_WAYP); i++) { const StationSpec *statspec = StationClass::Get(STAT_CLASS_WAYP, i); if (statspec != NULL && statspec->grf_prop.grffile->grfid == wp->grfid && statspec->grf_prop.local_id == wp->localidx) { wp->spec = statspec; break; } } } } if (!Waypoint::CanAllocateItem(_old_waypoints.Length())) SlError(STR_ERROR_TOO_MANY_STATIONS_LOADING); /* All saveload conversions have been done. Create the new waypoints! */ for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) { Waypoint *new_wp = new Waypoint(wp->xy); new_wp->town = wp->town; new_wp->town_cn = wp->town_cn; new_wp->name = wp->name; new_wp->delete_ctr = 0; // Just reset delete counter for once. new_wp->build_date = wp->build_date; new_wp->owner = wp->owner; new_wp->string_id = STR_SV_STNAME_WAYPOINT; TileIndex t = wp->xy; if (IsTileType(t, MP_RAILWAY) && GetRailTileType(t) == 2 /* RAIL_TILE_WAYPOINT */ && _m[t].m2 == wp->index) { /* The tile might've been reserved! */ bool reserved = !IsSavegameVersionBefore(100) && HasBit(_m[t].m5, 4); /* The tile really has our waypoint, so reassign the map array */ MakeRailWaypoint(t, GetTileOwner(t), new_wp->index, (Axis)GB(_m[t].m5, 0, 1), 0, GetRailType(t)); new_wp->facilities |= FACIL_TRAIN; new_wp->owner = GetTileOwner(t); SetRailStationReservation(t, reserved); if (wp->spec != NULL) { SetCustomStationSpecIndex(t, AllocateSpecToStation(wp->spec, new_wp, true)); } new_wp->rect.BeforeAddTile(t, StationRect::ADD_FORCE); } wp->new_index = new_wp->index; } /* Update the orders of vehicles */ OrderList *ol; FOR_ALL_ORDER_LISTS(ol) { if (ol->GetFirstSharedVehicle()->type != VEH_TRAIN) continue; for (Order *o = ol->GetFirstOrder(); o != NULL; o = o->next) UpdateWaypointOrder(o); } Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->type != VEH_TRAIN) continue; UpdateWaypointOrder(&v->current_order); } _old_waypoints.Reset(); }
VOID SlpDrawMenuItem( IN ULONG X, IN ULONG Y, IN ULONG TopItem, IN ULONG Height, IN ULONG Item, IN PSL_MENU Menu ) /*++ Routine Description: Redraws the given item Arguments: X - Supplies X coordinate of upper-left corner of menu Y - Supplies Y coordinate of upper-left corner of menu TopItem - Supplies index of item at the top of the menu Height - Supplies the height of the menu Item - Supplies the index of the item to be redrawn Menu - Supplies the menu to be displayed Return Value: None. --*/ { ULONG i; PSL_MENUITEM MenuItem; ULONG Count; CHAR Width[80]; // // Find item to display // MenuItem = CONTAINING_RECORD(Menu->ItemListHead.Flink, SL_MENUITEM, ListEntry); for (i=0;i<Item;i++) { MenuItem = CONTAINING_RECORD(MenuItem->ListEntry.Flink, SL_MENUITEM, ListEntry); #if DBG if (&MenuItem->ListEntry == &Menu->ItemListHead) { SlError(Item); } #endif } RtlFillMemory(Width,Menu->Width,' '); RtlCopyMemory(Width,MenuItem->Text,strlen(MenuItem->Text)); SlPositionCursor(X+2, Y+(Item-TopItem)+1); ArcWrite(ARC_CONSOLE_OUTPUT,Width,Menu->Width,&Count); }
VOID SlGenericMessageBox( IN ULONG MessageId, OPTIONAL IN va_list *args, OPTIONAL IN PCHAR Message, OPTIONAL IN OUT PULONG xLeft, OPTIONAL IN OUT PULONG yTop, OPTIONAL OUT PULONG yBottom, OPTIONAL IN BOOLEAN bCenterMsg ) /*++ Routine Description: Formats and displays a message box. The longest line in the string of characters will be centered on the screen if bCenterMsg is TRUE. The status text line will be erased. Arguments: NOTE: Either the MessageId/args pair or the Message string must be specified. Message string will be used if non-NULL. MessageId - Supplies the MessageId that will be looked up to provide a NULL-terminated string of characters. Each \r\n delimited string will be displayed on its own line. args - Supplies the argument list that will be passed to vsprintf. Message - Supplies the actual text of the message to be displayed xLeft - If bCenterMsg is FALSE, then xLeft is used for the starting x coordinate of the message (if specified, otherwise, x = 1). Also, if specified, it receives the x coordinate of the left edge of all lines that were displayed. yTop - If bCenterMsg is FALSE, then yTop is used for the starting y coordinate of the message (if specified, otherwise, y = 3). Also, if specified, receives the y coordinate of the top line where the message box was displayed. yBottom - if specified, receives the y coordinate of the bottom line of the message box. bCenterMsg - if TRUE, center message on the screen. Return Value: None. --*/ { PCHAR p; ULONG NumLines; ULONG MaxLength; ULONG x; ULONG y; ULONG i; PCHAR Line[20]; ULONG LineLength[20]; ULONG Count; if(!Message) { // then look up the message p=BlFindMessage(MessageId); if (p==NULL) { SlError(MessageId); x=3; y=ScreenHeight/2; NumLines=0; } else { _vsnprintf(MessageBuffer,sizeof(MessageBuffer),p,*args); Message = MessageBuffer; } } else { // // Just make p non-NULL, so we'll know it's OK to continue. // p = Message; } if(p) { SlWriteStatusText(""); // Clear status bar SlpSizeMessage(Message, &NumLines, &MaxLength, LineLength, Line); if (MaxLength > ScreenWidth) { MaxLength = ScreenWidth; } if(bCenterMsg) { x = (ScreenWidth-MaxLength)/2; y = (ScreenHeight-NumLines)/2; } else { if(xLeft) { x = *xLeft; } else { x = 1; } if(yTop) { y = *yTop; } else { y = 3; } } } for (i=0; i<NumLines; i++) { SlPositionCursor(x, y+i); ArcWrite(ARC_CONSOLE_OUTPUT,Line[i],LineLength[i],&Count); } if(xLeft) { *xLeft = x; } if(yTop) { *yTop = y; } if(yBottom) { *yBottom = NumLines ? y+NumLines-1 : 0; } }
VOID SlFatalError( IN ULONG MessageId, ... ) /*++ Routine Description: This is called when a fatal error occurs. It clears the client area, puts up a message box, displays the fatal error message, and allows the user to press a key to reboot. The status text line will be erased. Arguments: MessageId - Supplies ID of message box to be presented. any sprintf-compatible arguments to be inserted in the message box. Return Value: Does not return. --*/ { va_list args; ULONG x,y; PUCHAR Text; SlClearClientArea(); Text = BlFindMessage(MessageId); if(Text) { va_start(args, MessageId); _vsnprintf(MessageBuffer, sizeof(MessageBuffer), Text, args); // // Add a blank line, then concatenate the 'Can't continue' text. // strcat(MessageBuffer, "\r\n"); Text = BlFindMessage(SL_CANT_CONTINUE); if(Text) { strcat(MessageBuffer, Text); } Text = BlAllocateHeap((strlen(MessageBuffer)+1) * sizeof(CHAR)); strcpy(Text, MessageBuffer); // // Note that MessageId and args won't be used, since we're // passing in our Text pointer. // SlGenericMessageBox(MessageId, &args, Text, &x, NULL, &y, TRUE); va_end(args); } else { SlError(MessageId); } SlFlushConsoleBuffer(); SlGetChar(); ArcRestart(); }
BOOLEAN SlPromptForDisk( IN PCHAR DiskName, IN BOOLEAN IsCancellable ) /*++ Routine Description: This routine prompts a user to insert a given diskette #, or to abort the Setup process. The status line will be erased. Arguments: DiskName - Supplies the name of the disk to be inserted. IsCancellable - Supplies flag indicating whether prompt may be cancelled. Return Value: TRUE - The user has pressed OK FALSE - The user has pressed CANCEL --*/ { ULONG msg; ULONG y; ULONG Key; PCHAR StatusText; PCHAR PleaseWait; ULONG i; CHAR DiskNameDisplayed[81]; BOOLEAN Repaint=TRUE; SlWriteStatusText(""); if(IsCancellable) { msg = SL_NEXT_DISK_PROMPT_CANCELLABLE; } else { msg = SL_NEXT_DISK_PROMPT; } StatusText = BlFindMessage(msg); if(StatusText == NULL) { SlError(msg); return(FALSE); } PleaseWait = BlFindMessage(SL_PLEASE_WAIT); if(PleaseWait == NULL) { SlError(SL_PLEASE_WAIT); return(FALSE); } // // Get first line of DiskName and save it in DiskNameDisplayed (limit to 80 chars) // for(i = 0; ((i < 80) && DiskName[i] && (DiskName[i] != '\r') && (DiskName[i] != '\n')); i++) { DiskNameDisplayed[i] = DiskName[i]; } DiskNameDisplayed[i] = '\0'; do { if (Repaint) { SlClearClientArea(); y = SlDisplayMessageBox(SL_MSG_INSERT_DISK); SlPositionCursor((ScreenWidth-i)/2,y+2); SlWriteString(DiskNameDisplayed); SlWriteStatusText(StatusText); } Repaint = FALSE; SlFlushConsoleBuffer(); Key = SlGetChar(); if (Key == ASCI_CR) { SlClearClientArea(); SlWriteStatusText(PleaseWait); return(TRUE); } else if (Key == SL_KEY_F3) { SlConfirmExit(); Repaint=TRUE; } else if((Key == ASCI_ESC) && IsCancellable) { SlWriteStatusText(""); SlClearClientArea(); return FALSE; } } while ( TRUE ); }