/** * Handles Click event for savegame button. * * @param key The index of the clicked button. * @return True if a game has been saved, False otherwise. */ static bool GUI_Widget_Savegame_Click(uint16 key) { WindowDesc *desc = &g_savegameNameWindowDesc; bool loop; char *saveDesc = g_savegameDesc[key]; uint16 loc08; uint16 loc0A; bool ret; if (*saveDesc == '[') *saveDesc = 0; GUI_Window_BackupScreen(desc); GUI_Window_Create(desc); ret = false; loop = true; loc08 = 1; if (*saveDesc == '[') key = s_savegameCountOnDisk; GFX_Screen_SetActive(0); Widget_SetCurrentWidget(15); GUI_Mouse_Hide_Safe(); GUI_DrawBorder((g_curWidgetXBase << 3) - 1, g_curWidgetYBase - 1, (g_curWidgetWidth << 3) + 2, g_curWidgetHeight + 2, 4, false); GUI_Mouse_Show_Safe(); while (loop) { Widget *w = g_widgetLinkedListTail; GUI_DrawText_Wrapper(NULL, 0, 0, 232, 235, 0x22); loc0A = GUI_EditBox(saveDesc, 50, 15, g_widgetLinkedListTail, NULL, loc08); loc08 = 2; if ((loc0A & 0x8000) == 0) continue; GUI_Widget_MakeNormal(GUI_Widget_Get_ByIndex(w, loc0A & 0x7FFF), false); switch (loc0A & 0x7FFF) { case 0x1E: if (*saveDesc == 0) break; SaveFile(GenerateSavegameFilename(s_savegameIndexBase - key), saveDesc); loop = false; ret = true; break; case 0x1F: loop = false; ret = false; FillSavegameDesc(true); break; default: break; } sleepIdle(); } GUI_Window_RestoreScreen(desc); return ret; }
static void GUI_Window_Create(WindowDesc *desc) { uint8 i; if (desc == NULL) return; g_widgetLinkedListTail = NULL; GFX_Screen_SetActive(2); Widget_SetCurrentWidget(desc->index); GUI_Widget_DrawBorder(g_curWidgetIndex, 2, true); if (GUI_String_Get_ByIndex(desc->stringID) != NULL) { GUI_DrawText_Wrapper(GUI_String_Get_ByIndex(desc->stringID), (g_curWidgetXBase << 3) + (g_curWidgetWidth << 2), g_curWidgetYBase + 6 + ((desc == &g_yesNoWindowDesc) ? 2 : 0), 238, 0, 0x122); } if (GUI_String_Get_ByIndex(desc->widgets[0].stringID) == NULL) { GUI_DrawText_Wrapper(String_Get_ByIndex(STR_THERE_ARE_NO_SAVED_GAMES_TO_LOAD), (g_curWidgetXBase + 2) << 3, g_curWidgetYBase + 42, 232, 0, 0x22); } for (i = 0; i < desc->widgetCount; i++) { Widget *w = &g_table_windowWidgets[i]; if (GUI_String_Get_ByIndex(desc->widgets[i].stringID) == NULL) continue; w->next = NULL; w->offsetX = desc->widgets[i].offsetX; w->offsetY = desc->widgets[i].offsetY; w->width = desc->widgets[i].width; w->height = desc->widgets[i].height; w->shortcut = 0; w->shortcut2 = 0; if (desc != &g_savegameNameWindowDesc) { if (desc->widgets[i].labelStringId != STR_NULL) { w->shortcut = GUI_Widget_GetShortcut(*GUI_String_Get_ByIndex(desc->widgets[i].labelStringId)); } else { w->shortcut = GUI_Widget_GetShortcut(*GUI_String_Get_ByIndex(desc->widgets[i].stringID)); } } w->shortcut2 = desc->widgets[i].shortcut2; if (w->shortcut == 0x1B) { w->shortcut2 = 0x13; } w->stringID = desc->widgets[i].stringID; w->drawModeNormal = DRAW_MODE_CUSTOM_PROC; w->drawModeSelected = DRAW_MODE_CUSTOM_PROC; w->drawModeDown = DRAW_MODE_CUSTOM_PROC; w->drawParameterNormal.proc = &GUI_Widget_TextButton_Draw; w->drawParameterSelected.proc = &GUI_Widget_TextButton_Draw; w->drawParameterDown.proc = &GUI_Widget_TextButton_Draw; w->parentID = desc->index; w->state.all = 0x0; g_widgetLinkedListTail = GUI_Widget_Link(g_widgetLinkedListTail, w); GUI_Widget_MakeVisible(w); GUI_Widget_MakeNormal(w, false); GUI_Widget_Draw(w); if (desc->widgets[i].labelStringId == STR_NULL) continue; if (g_config.language == LANGUAGE_FRENCH) { GUI_DrawText_Wrapper(GUI_String_Get_ByIndex(desc->widgets[i].labelStringId), (g_widgetProperties[w->parentID].xBase << 3) + 40, w->offsetY + g_widgetProperties[w->parentID].yBase + 3, 232, 0, 0x22); } else { GUI_DrawText_Wrapper(GUI_String_Get_ByIndex(desc->widgets[i].labelStringId), w->offsetX + (g_widgetProperties[w->parentID].xBase << 3) - 10, w->offsetY + g_widgetProperties[w->parentID].yBase + 3, 232, 0, 0x222); } } if (s_savegameCountOnDisk >= 5 && desc->addArrows) { Widget *w = &g_table_windowWidgets[7]; w->drawParameterNormal.sprite = g_sprites[59]; w->drawParameterSelected.sprite = g_sprites[60]; w->drawParameterDown.sprite = g_sprites[60]; w->next = NULL; w->parentID = desc->index; GUI_Widget_MakeNormal(w, false); GUI_Widget_MakeInvisible(w); GUI_Widget_Undraw(w, 233); g_widgetLinkedListTail = GUI_Widget_Link(g_widgetLinkedListTail, w); w = &g_table_windowWidgets[8]; w->drawParameterNormal.sprite = g_sprites[61]; w->drawParameterSelected.sprite = g_sprites[62]; w->drawParameterDown.sprite = g_sprites[62]; w->next = NULL; w->parentID = desc->index; GUI_Widget_MakeNormal(w, false); GUI_Widget_MakeInvisible(w); GUI_Widget_Undraw(w, 233); g_widgetLinkedListTail = GUI_Widget_Link(g_widgetLinkedListTail, w); } GUI_Mouse_Hide_Safe(); Widget_SetCurrentWidget(desc->index); GUI_Screen_Copy(g_curWidgetXBase, g_curWidgetYBase, g_curWidgetXBase, g_curWidgetYBase, g_curWidgetWidth, g_curWidgetHeight, 2, 0); GUI_Mouse_Show_Safe(); GFX_Screen_SetActive(0); }
/** * Handles Click event for "Options" button. * * @param w The widget. * @return False, always. */ bool GUI_Widget_Options_Click(Widget *w) { WindowDesc *desc = &g_optionsWindowDesc; uint16 cursor = g_cursorSpriteID; bool loop; g_cursorSpriteID = 0; Sprites_SetMouseSprite(0, 0, g_sprites[0]); Sprites_UnloadTiles(); memmove(g_palette_998A, g_paletteActive, 256 * 3); Driver_Voice_Play(NULL, 0xFF); Timer_SetTimer(TIMER_GAME, false); GUI_DrawText_Wrapper(NULL, 0, 0, 0, 0, 0x22); ShadeScreen(); GUI_Window_BackupScreen(desc); GUI_Window_Create(desc); loop = true; while (loop) { Widget *w2 = g_widgetLinkedListTail; uint16 key = GUI_Widget_HandleEvents(w2); if ((key & 0x8000) != 0) { w = GUI_Widget_Get_ByIndex(w2, key); GUI_Window_RestoreScreen(desc); switch ((key & 0x7FFF) - 0x1E) { case 0: if (GUI_Widget_SaveLoad_Click(false)) loop = false; break; case 1: if (GUI_Widget_SaveLoad_Click(true)) loop = false; break; case 2: GUI_Widget_GameControls_Click(w); break; case 3: /* "Are you sure you wish to restart?" */ if (!GUI_YesNo(0x76)) break; loop = false; g_gameMode = GM_RESTART; break; case 4: /* "Are you sure you wish to pick a new house?" */ if (!GUI_YesNo(0x77)) break; loop = false; Driver_Music_FadeOut(); g_gameMode = GM_PICKHOUSE; break; case 5: loop = false; break; case 6: /* "Are you sure you want to quit playing?" */ loop = !GUI_YesNo(0x65); g_var_38F8 = loop; Sound_Output_Feedback(0xFFFE); while (Driver_Voice_IsPlaying()) sleepIdle(); break; default: break; } if (g_var_38F8 && loop) { GUI_Window_BackupScreen(desc); GUI_Window_Create(desc); } } GUI_PaletteAnimate(); sleepIdle(); } g_textDisplayNeedsUpdate = true; Sprites_LoadTiles(); GUI_DrawInterfaceAndRadar(0); UnshadeScreen(); GUI_Widget_MakeSelected(w, false); Timer_SetTimer(TIMER_GAME, true); GameOptions_Save(); Structure_Recount(); Unit_Recount(); g_cursorSpriteID = cursor; Sprites_SetMouseSprite(0, 0, g_sprites[cursor]); return false; }
/** * Show an EditBox and handles the input. * @param text The text to edit. Uses the pointer to make the modifications. * @param maxLength The maximum length of the text. * @param unknown1 Unknown. * @param w The widget this editbox is attached to. * @param tickProc The function to call every tick, for animation etc. * @param unknown4 Unknown. * @return Unknown. */ uint16 GUI_EditBox(char *text, uint16 maxLength, uint16 unknown1, Widget *w, uint16 (*tickProc)(void), uint16 unknown4) { Screen oldScreenID; uint16 oldValue_07AE_0000; uint16 positionX; uint16 maxWidth; uint16 textWidth; uint16 textLength; uint16 returnValue; char *t; /* Initialize */ { Input_Flags_SetBits(INPUT_FLAG_NO_TRANSLATE); Input_Flags_ClearBits(INPUT_FLAG_UNKNOWN_2000); oldScreenID = GFX_Screen_SetActive(SCREEN_0); oldValue_07AE_0000 = Widget_SetCurrentWidget(unknown1); returnValue = 0x0; } positionX = g_curWidgetXBase << 3; textWidth = 0; textLength = 0; maxWidth = (g_curWidgetWidth << 3) - Font_GetCharWidth('W') - 1; t = text; /* Calculate the length and width of the current string */ for (; *t != '\0'; t++) { textWidth += Font_GetCharWidth(*t); textLength++; if (textWidth >= maxWidth) break; } *t = '\0'; if ((unknown4 & 0x1) != 0) { unknown4 |= 0x4; } GUI_Mouse_Hide_Safe(); if ((unknown4 & 0x4) != 0) Widget_PaintCurrentWidget(); GUI_DrawText_Wrapper(text, positionX, g_curWidgetYBase, g_curWidgetFGColourBlink, g_curWidgetFGColourNormal, 0); GUI_EditBox_BlinkCursor(positionX + textWidth, false); GUI_Mouse_Show_Safe(); for (;; sleepIdle()) { uint16 keyWidth; uint16 key; if (tickProc != NULL) { returnValue = tickProc(); if (returnValue != 0) break; } key = GUI_Widget_HandleEvents(w); GUI_EditBox_BlinkCursor(positionX + textWidth, false); if (key == 0x0) continue; if ((key & 0x8000) != 0) { returnValue = key; break; } if (key == 0x2B) { returnValue = 0x2B; break; } if (key == 0x6E) { *t = '\0'; returnValue = 0x6B; break; } /* Handle backspace */ if (key == 0x0F) { if (textLength == 0) continue; GUI_EditBox_BlinkCursor(positionX + textWidth, true); textWidth -= Font_GetCharWidth(*(t - 1)); textLength--; *(--t) = '\0'; GUI_EditBox_BlinkCursor(positionX + textWidth, false); continue; } key = Input_Keyboard_HandleKeys(key) & 0xFF; /* Names can't start with a space, and should be alpha-numeric */ if ((key == 0x20 && textLength == 0) || key < 0x20 || key > 0x7E) continue; keyWidth = Font_GetCharWidth(key & 0xFF); if (textWidth + keyWidth >= maxWidth || textLength >= maxLength) continue; /* Add char to the text */ *t = key & 0xFF; *(++t) = '\0'; textLength++; GUI_Mouse_Hide_Safe(); GUI_EditBox_BlinkCursor(positionX + textWidth, true); /* Draw new character */ GUI_DrawText_Wrapper(text + textLength - 1, positionX + textWidth, g_curWidgetYBase, g_curWidgetFGColourBlink, g_curWidgetFGColourNormal, 0x020); GUI_Mouse_Show_Safe(); textWidth += keyWidth; GUI_EditBox_BlinkCursor(positionX + textWidth, false); } /* Deinitialize */ { Input_Flags_ClearBits(INPUT_FLAG_NO_TRANSLATE); Input_Flags_SetBits(INPUT_FLAG_UNKNOWN_2000); Widget_SetCurrentWidget(oldValue_07AE_0000); GFX_Screen_SetActive(oldScreenID); } return returnValue; }
static void GUI_Purchase_ShowInvoice() { Widget *w = g_widgetInvoiceTail; uint16 oldScreenID = GFX_Screen_SetActive(2); uint16 y = 48; uint16 total = 0; uint16 x; char textBuffer[12]; GUI_DrawFilledRectangle(128, 48, 311, 159, 20); GUI_DrawText_Wrapper(String_Get_ByIndex(STR_ITEM_NAME_QTY_TOTAL), 128, y, 12, 0, 0x11); y += 7; GUI_DrawLine(129, y, 310, y, 12); y += 2; if (g_factoryWindowOrdered != 0) { uint16 i; for (i = 0; i < g_factoryWindowTotal; i++) { ObjectInfo *oi; uint16 amount; if (g_factoryWindowItems[i].amount == 0) continue; amount = g_factoryWindowItems[i].amount * g_factoryWindowItems[i].credits; total += amount; snprintf(textBuffer, sizeof(textBuffer), "%02d %5d", g_factoryWindowItems[i].amount, amount); oi = g_factoryWindowItems[i].objectInfo; GUI_DrawText_Wrapper(String_Get_ByIndex(oi->stringID_full), 128, y, 8, 0, 0x11); GUI_DrawText_Monospace(textBuffer, 311 - strlen(textBuffer) * 6, y, 15, 0, 6); y += 8; } } else { GUI_DrawText_Wrapper(String_Get_ByIndex(STR_NO_UNITS_ON_ORDER), 220, 99, 6, 0, 0x112); } GUI_DrawLine(129, 148, 310, 148, 12); GUI_DrawLine(129, 150, 310, 150, 12); snprintf(textBuffer, sizeof(textBuffer), "%d", total); x = 311 - strlen(textBuffer) * 6; /* "Total Cost :" */ GUI_DrawText_Wrapper(GUI_String_Get_ByIndex(0xB8), x - 3, 152, 11, 0, 0x211); GUI_DrawText_Monospace(textBuffer, x, 152, 11, 0, 6); GUI_Mouse_Hide_Safe(); GUI_Screen_Copy(16, 48, 16, 48, 23, 112, 2, 0); GUI_Mouse_Show_Safe(); GFX_Screen_SetActive(0); GUI_FactoryWindow_DrawCaption(String_Get_ByIndex(STR_INVOICE_OF_UNITS_ON_ORDER)); Input_History_Clear(); while (GUI_Widget_HandleEvents(w) == 0) { GUI_DrawCredits(g_playerHouseID, 0); GUI_FactoryWindow_UpdateSelection(false); GUI_PaletteAnimate(); sleepIdle(); } GFX_Screen_SetActive(oldScreenID); w = GUI_Widget_Get_ByIndex(w, 10); if (w != NULL && Mouse_InsideRegion(w->offsetX, w->offsetY, w->offsetX + w->width, w->offsetY + w->height) != 0) { while (Input_Test(0x41) != 0 || Input_Test(0x42) != 0) msleep(0); Input_History_Clear(); } if (g_factoryWindowResult == FACTORY_CONTINUE) GUI_FactoryWindow_DrawDetails(); }
static uint16 GameLoop_HandleEvents(const char **strings) { uint8 last; uint16 result; uint16 key; uint16 top; uint16 left; uint16 minX; uint16 maxX; uint16 minY; uint16 maxY; uint16 lineHeight; uint8 fgColourNormal; uint8 fgColourSelected; uint8 old; WidgetProperties *props; uint8 current; props = &g_widgetProperties[21]; last = props->height - 1; old = props->fgColourBlink % (last + 1); current = old; result = 0xFFFF; top = g_curWidgetYBase + props->yBase; left = (g_curWidgetXBase + props->xBase) << 3; lineHeight = g_fontCurrent->height; minX = (g_curWidgetXBase << 3) + (g_fontCurrent->maxWidth * props->xBase); minY = g_curWidgetYBase + props->yBase; maxX = minX + (g_fontCurrent->maxWidth * props->width) - 1; maxY = minY + (props->height * lineHeight) - 1; fgColourNormal = props->fgColourNormal; fgColourSelected = props->fgColourSelected; key = 0; if (Input_IsInputAvailable() != 0) { key = Input_Wait() & 0x8FF; } if (g_mouseDisabled == 0) { uint16 y = g_mouseY; if (GameLoop_IsInRange(g_mouseX, y, minX, minY, maxX, maxY)) { current = (y - minY) / lineHeight; } } switch (key) { case 0x60: /* NUMPAD 8 / ARROW UP */ if (current-- == 0) current = last; break; case 0x62: /* NUMPAD 2 / ARROW DOWN */ if (current++ == last) current = 0; break; case 0x5B: /* NUMPAD 7 / HOME */ case 0x65: /* NUMPAD 9 / PAGE UP */ current = 0; break; case 0x5D: /* NUMPAD 1 / END */ case 0x67: /* NUMPAD 3 / PAGE DOWN */ current = last; break; case 0x41: /* MOUSE LEFT BUTTON */ case 0x42: /* MOUSE RIGHT BUTTON */ if (GameLoop_IsInRange(g_mouseClickX, g_mouseClickY, minX, minY, maxX, maxY)) { current = (g_mouseClickY - minY) / lineHeight; result = current; } break; case 0x2B: /* NUMPAD 5 / RETURN */ case 0x3D: /* SPACE */ case 0x61: result = current; break; default: { uint8 i; for (i = 0; i < props->height; i++) { char c1; char c2; c1 = toupper(*strings[i]); c2 = toupper(Input_Keyboard_HandleKeys(key & 0xFF)); if (c1 == c2) { result = i; current = i; break; } } } break; } if (current != old) { GUI_Mouse_Hide_Safe(); GUI_DrawText_Wrapper(strings[old], left, top + (old * lineHeight), fgColourNormal, 0, 0x22); GUI_DrawText_Wrapper(strings[current], left, top + (current * lineHeight), fgColourSelected, 0, 0x22); GUI_Mouse_Show_Safe(); } props->fgColourBlink = current; if (result == 0xFFFF) return 0xFFFF; GUI_Mouse_Hide_Safe(); GameLoop_DrawText2(strings[result], left, top + (current * lineHeight), fgColourNormal, fgColourSelected, 0); GUI_Mouse_Show_Safe(); return result; }
/** * Intro menu. */ static void GameLoop_GameIntroAnimationMenu(void) { static const uint16 mainMenuStrings[][6] = { {STR_PLAY_A_GAME, STR_REPLAY_INTRODUCTION, STR_EXIT_GAME, STR_NULL, STR_NULL, STR_NULL}, /* Neither HOF nor save. */ {STR_PLAY_A_GAME, STR_REPLAY_INTRODUCTION, STR_LOAD_GAME, STR_EXIT_GAME, STR_NULL, STR_NULL}, /* Has a save game. */ {STR_PLAY_A_GAME, STR_REPLAY_INTRODUCTION, STR_EXIT_GAME, STR_HALL_OF_FAME, STR_NULL, STR_NULL}, /* Has a HOF. */ {STR_PLAY_A_GAME, STR_REPLAY_INTRODUCTION, STR_LOAD_GAME, STR_EXIT_GAME, STR_HALL_OF_FAME, STR_NULL} /* Has a HOF and a save game. */ }; bool loadGame = false; static bool drawMenu = true; static uint16 stringID = STR_REPLAY_INTRODUCTION; uint16 maxWidth; static bool hasSave = false; static bool hasFame = false; static const char *strings[6]; static uint16 index = 0xFFFF; if (index == 0xFFFF) { hasSave = File_Exists_Personal("_save000.dat"); hasFame = File_Exists_Personal("SAVEFAME.DAT"); index = (hasFame ? 2 : 0) + (hasSave ? 1 : 0); } if (hasSave || File_Exists_Personal("ONETIME.DAT")) g_canSkipIntro = true; switch (stringID) { case STR_REPLAY_INTRODUCTION: Music_Play(0); free(g_readBuffer); g_readBufferSize = (g_enableVoices == 0) ? 12000 : 28000; g_readBuffer = calloc(1, g_readBufferSize); GUI_Mouse_Hide_Safe(); Driver_Music_FadeOut(); GameLoop_GameIntroAnimation(); Sound_Output_Feedback(0xFFFE); File_ReadBlockFile("IBM.PAL", g_palette_998A, 256 * 3); memmove(g_palette1, g_palette_998A, 256 * 3); if (!g_canSkipIntro) { File_Create_Personal("ONETIME.DAT"); g_canSkipIntro = true; } Music_Play(0); free(g_readBuffer); g_readBufferSize = (g_enableVoices == 0) ? 12000 : 20000; g_readBuffer = calloc(1, g_readBufferSize); GUI_Mouse_Show_Safe(); Music_Play(28); drawMenu = true; break; case STR_EXIT_GAME: g_running = false; return; case STR_HALL_OF_FAME: GUI_HallOfFame_Show(0xFFFF); GFX_SetPalette(g_palette2); hasFame = File_Exists_Personal("SAVEFAME.DAT"); drawMenu = true; break; case STR_LOAD_GAME: GUI_Mouse_Hide_Safe(); GUI_SetPaletteAnimated(g_palette2, 30); GUI_ClearScreen(SCREEN_0); GUI_Mouse_Show_Safe(); GFX_SetPalette(g_palette1); if (GUI_Widget_SaveLoad_Click(false)) { loadGame = true; if (g_gameMode == GM_RESTART) break; g_gameMode = GM_NORMAL; } else { GFX_SetPalette(g_palette2); drawMenu = true; } break; default: break; } if (drawMenu) { uint16 i; g_widgetProperties[21].height = 0; for (i = 0; i < 6; i++) { strings[i] = NULL; if (mainMenuStrings[index][i] == 0) { if (g_widgetProperties[21].height == 0) g_widgetProperties[21].height = i; continue; } strings[i] = String_Get_ByIndex(mainMenuStrings[index][i]); } GUI_DrawText_Wrapper(NULL, 0, 0, 0, 0, 0x22); maxWidth = 0; for (i = 0; i < g_widgetProperties[21].height; i++) { if (Font_GetStringWidth(strings[i]) <= maxWidth) continue; maxWidth = Font_GetStringWidth(strings[i]); } maxWidth += 7; g_widgetProperties[21].width = maxWidth >> 3; g_widgetProperties[13].width = g_widgetProperties[21].width + 2; g_widgetProperties[13].xBase = 19 - (maxWidth >> 4); g_widgetProperties[13].yBase = 160 - ((g_widgetProperties[21].height * g_fontCurrent->height) >> 1); g_widgetProperties[13].height = (g_widgetProperties[21].height * g_fontCurrent->height) + 11; Sprites_LoadImage(String_GenerateFilename("TITLE"), SCREEN_1, NULL); GUI_Mouse_Hide_Safe(); GUI_ClearScreen(SCREEN_0); GUI_Screen_Copy(0, 0, 0, 0, SCREEN_WIDTH / 8, SCREEN_HEIGHT, SCREEN_1, SCREEN_0); GUI_SetPaletteAnimated(g_palette1, 30); GUI_DrawText_Wrapper("V1.07", 319, 192, 133, 0, 0x231, 0x39); GUI_DrawText_Wrapper(NULL, 0, 0, 0, 0, 0x22); Widget_SetCurrentWidget(13); GUI_Widget_DrawBorder(13, 2, 1); GameLoop_DrawMenu(strings); GUI_Mouse_Show_Safe(); drawMenu = false; } if (loadGame) return; stringID = GameLoop_HandleEvents(strings); if (stringID != 0xFFFF) stringID = mainMenuStrings[index][stringID]; GUI_PaletteAnimate(); if (stringID == STR_PLAY_A_GAME) g_gameMode = GM_PICKHOUSE; }
void async_GUI_Mentat_Loop() { uint16 key; GFX_Screen_SetActive(0); key = GUI_Widget_HandleEvents(asyncMentatLoop.w); GUI_PaletteAnimate(); if (key != 0) { if ((key & 0x800) == 0) { if (asyncMentatLoop.w != NULL) { if ((key & 0x8000) != 0 && asyncMentatLoop.result == 0) asyncMentatLoop.result = key; } else { if (asyncMentatLoop.textDone) asyncMentatLoop.result = key; } } else { key = 0; } } switch (asyncMentatLoop.step) { case 0: if (key == 0) break; asyncMentatLoop.step = 1; /* FALL-THROUGH */ case 1: if (key != 0) { if (asyncMentatLoop.result != 0) { asyncMentatLoop.step = 5; break; } asyncMentatLoop.lines = asyncMentatLoop.descLines; asyncMentatLoop.dirty = true; } else { if (g_timerGUI > asyncMentatLoop.descTick) { asyncMentatLoop.descTick = g_timerGUI + 15; asyncMentatLoop.lines++; asyncMentatLoop.dirty = true; } } if (asyncMentatLoop.lines < asyncMentatLoop.descLines && asyncMentatLoop.lines <= 12) break; asyncMentatLoop.step = (asyncMentatLoop.text != NULL) ? 2 : 4; asyncMentatLoop.lines = asyncMentatLoop.descLines; break; case 2: GUI_Mouse_Hide_InRegion(0, 0, SCREEN_WIDTH, 40); GUI_Screen_Copy(0, 0, 0, 160, SCREEN_WIDTH / 8, 40, 0, 4); GUI_Mouse_Show_InRegion(); asyncMentatLoop.step = 3; key = 1; /* FALL-THROUGH */ case 3: if (asyncMentatLoop.mentatSpeakingMode == 2 && asyncMentatLoop.textTick < g_timerGUI) key = 1; if ((key != 0 && asyncMentatLoop.textDone) || asyncMentatLoop.result != 0) { GUI_Mouse_Hide_InRegion(0, 0, SCREEN_WIDTH, 40); GUI_Screen_Copy(0, 160, 0, 0, SCREEN_WIDTH / 8, 40, 4, 0); GUI_Mouse_Show_InRegion(); asyncMentatLoop.step = 4; asyncMentatLoop.mentatSpeakingMode = 0; break; } if (key != 0) { GUI_Screen_Copy(0, 160, 0, 0, SCREEN_WIDTH / 8, 40, 4, 4); if (asyncMentatLoop.textLines-- != 0) { GFX_Screen_SetActive(4); GUI_DrawText_Wrapper(asyncMentatLoop.text, 4, 1, g_curWidgetFGColourBlink, 0, 0x32); asyncMentatLoop.mentatSpeakingMode = 1; asyncMentatLoop.textDelay = strlen(asyncMentatLoop.text) * 4; asyncMentatLoop.textTick = g_timerGUI + asyncMentatLoop.textDelay; if (asyncMentatLoop.textLines != 0) { while (*asyncMentatLoop.text++ != '\0') {} } else { asyncMentatLoop.textDone = true; } GFX_Screen_SetActive(0); } GUI_Mouse_Hide_InRegion(0, 0, SCREEN_WIDTH, 40); GUI_Screen_Copy(0, 0, 0, 0, SCREEN_WIDTH / 8, 40, 4, 0); GUI_Mouse_Show_InRegion(); break; } if (asyncMentatLoop.mentatSpeakingMode == 0 || asyncMentatLoop.textTick > g_timerGUI) break; asyncMentatLoop.mentatSpeakingMode = 2; asyncMentatLoop.textTick += asyncMentatLoop.textDelay + asyncMentatLoop.textDelay / 2; break; case 4: if (asyncMentatLoop.result != 0 || asyncMentatLoop.w == NULL) asyncMentatLoop.step = 5; break; case 5: asyncMentatLoop.dirty = true; asyncMentatLoop.done = true; break; default: break; } GUI_Mentat_Animation(asyncMentatLoop.mentatSpeakingMode); if (asyncMentatLoop.wsa != NULL && g_timerTimeout == 0) { g_timerTimeout = 7; do { if (asyncMentatLoop.step == 0 && asyncMentatLoop.frame > 4) asyncMentatLoop.step = 1; if (!WSA_DisplayFrame(asyncMentatLoop.wsa, asyncMentatLoop.frame++, g_curWidgetXBase << 3, g_curWidgetYBase, 4)) { if (asyncMentatLoop.step == 0) asyncMentatLoop.step = 1; if (asyncMentatLoop.arg12 != 0) { asyncMentatLoop.frame = 0; } else { WSA_Unload(asyncMentatLoop.wsa); asyncMentatLoop.wsa = NULL; } } } while (asyncMentatLoop.frame == 0); asyncMentatLoop.dirty = true; } if (!asyncMentatLoop.dirty) { sleepIdle(); return; } GUI_Mentat_DrawInfo(asyncMentatLoop.pictureDetails, (g_curWidgetXBase << 3) + 5, g_curWidgetYBase + 3, 8, 0, asyncMentatLoop.lines, 0x31); GUI_DrawSprite(4, g_sprites[397 + g_playerHouseID * 15], g_shoulderLeft, g_shoulderTop, 0, 0); GUI_Mouse_Hide_InWidget(g_curWidgetIndex); GUI_Screen_Copy(g_curWidgetXBase, g_curWidgetYBase, g_curWidgetXBase, g_curWidgetYBase, g_curWidgetWidth, g_curWidgetHeight, 4, 0); GUI_Mouse_Show_InWidget(); asyncMentatLoop.dirty = false; sleepIdle(); }
static void GUI_Mentat_Draw(bool force) { static uint16 displayedHelpSubject = 0; uint16 oldScreenID; Widget *line; Widget *w = g_widgetMentatTail; uint8 *helpSubjects = s_helpSubjects; uint16 i; if (!force && s_topHelpList == displayedHelpSubject) return; displayedHelpSubject = s_topHelpList; oldScreenID = GFX_Screen_SetActive(2); Widget_SetAndPaintCurrentWidget(8); GUI_DrawSprite(2, g_sprites[397 + g_playerHouseID * 15], g_shoulderLeft, g_shoulderTop, 0, 0); GUI_DrawText_Wrapper(String_Get_ByIndex(STR_SELECT_SUBJECT), (g_curWidgetXBase << 3) + 16, g_curWidgetYBase + 2, 12, 0, 0x12); GUI_DrawText_Wrapper(NULL, 0, 0, 0, 0, 0x11); line = GUI_Widget_Get_ByIndex(w, 3); for (i = 0; i < 11; i++) { line->drawParameterDown.text = (char *)helpSubjects + 7; line->drawParameterSelected.text = (char *)helpSubjects + 7; line->drawParameterNormal.text = (char *)helpSubjects + 7; if (helpSubjects[6] == '0') { line->offsetX = 16; line->fgColourSelected = 11; line->fgColourDown = 11; line->fgColourNormal = 11; line->stringID = 0x30; } else { uint8 colour = (i == s_selectedHelpSubject) ? 8 : 15; line->offsetX = 24; line->fgColourSelected = colour; line->fgColourDown = colour; line->fgColourNormal = colour; line->stringID = 0x31; } GUI_Widget_MakeNormal(line, false); GUI_Widget_Draw(line); line = GUI_Widget_GetNext(line); helpSubjects = String_NextString(helpSubjects); } GUI_Widget_Scrollbar_Init(GUI_Widget_Get_ByIndex(w, 15), s_numberHelpSubjects, 11, s_topHelpList); GUI_Widget_Draw(GUI_Widget_Get_ByIndex(w, 16)); GUI_Widget_Draw(GUI_Widget_Get_ByIndex(w, 17)); GUI_Mouse_Hide_Safe(); GUI_Screen_Copy(g_curWidgetXBase, g_curWidgetYBase, g_curWidgetXBase, g_curWidgetYBase, g_curWidgetWidth, g_curWidgetHeight, 2, 0); GUI_Mouse_Show_Safe(); GFX_Screen_SetActive(oldScreenID); }
/** * Ask the security question to the user. Give him 3 times. If he fails, * return false, otherwise true. * @return True if and only if the user answered one of the three questions * correct. */ bool GUI_Security_Show(void) { const char *wsaHouseFilename; uint16 questionsCount; uint16 oldCurrentWidget; Screen oldScreenID; uint16 i; bool valid; g_disableOtherMovement = true; g_interrogation = true; wsaHouseFilename = House_GetWSAHouseFilename(g_playerHouseID); if (wsaHouseFilename == NULL) return true; GUI_SetPaletteAnimated(g_palette2, 15); GUI_Mentat_Display(wsaHouseFilename, g_playerHouseID); GUI_Mouse_Hide_Safe(); GUI_Screen_Copy(0, 0, 0, 0, SCREEN_WIDTH / 8, SCREEN_HEIGHT, SCREEN_1, SCREEN_0); GUI_Mouse_Show_Safe(); GUI_SetPaletteAnimated(g_palette1, 15); strncpy(g_readBuffer, String_Get_ByIndex(STR_SECURITY_TEXT_HARKONNEN + g_playerHouseID * 3), g_readBufferSize); GUI_Mentat_Loop(wsaHouseFilename, NULL, g_readBuffer, true, NULL); questionsCount = atoi(String_Get_ByIndex(STR_SECURITY_COUNT)); oldCurrentWidget = Widget_SetCurrentWidget(8); oldScreenID = GFX_Screen_SetActive(SCREEN_2); for (i = 0, valid = false; i < 3 && !valid; i++) { void *wsa; uint16 questionIndex; uint32 tickWaitTill; char buffer[81]; questionIndex = Tools_RandomLCG_Range(0, questionsCount - 1) * 3 + STR_SECURITY_QUESTIONS; Widget_SetCurrentWidget(8); wsa = WSA_LoadFile(String_Get_ByIndex(questionIndex + 1), GFX_Screen_Get_ByIndex(SCREEN_1), GFX_Screen_GetSize_ByIndex(SCREEN_1), false); WSA_DisplayFrame(wsa, 0, g_curWidgetXBase << 3, g_curWidgetYBase, SCREEN_2); WSA_Unload(wsa); GUI_DrawSprite(SCREEN_2, g_sprites[397 + g_playerHouseID * 15], g_shoulderLeft, g_shoulderTop, 0, 0); GUI_Mouse_Hide_InWidget(g_curWidgetIndex); GUI_Screen_Copy(g_curWidgetXBase, g_curWidgetYBase, g_curWidgetXBase, g_curWidgetYBase, g_curWidgetWidth, g_curWidgetHeight, SCREEN_2, SCREEN_0); GUI_Mouse_Show_InWidget(); strncpy(g_readBuffer, String_Get_ByIndex(questionIndex), g_readBufferSize); GUI_Security_DrawText(g_readBuffer); g_interrogationTimer = g_timerGUI + (uint32)strlen(g_readBuffer) * 4; Widget_SetCurrentWidget(9); GUI_Mouse_Hide_Safe(); GUI_Screen_Copy(g_curWidgetXBase - 1, g_curWidgetYBase - 8, 0, 0, g_curWidgetWidth + 2, g_curWidgetHeight + 16, SCREEN_0, SCREEN_2); GUI_Mouse_Show_Safe(); GFX_Screen_SetActive(SCREEN_0); GUI_Mouse_Hide_Safe(); GUI_DrawBorder((g_curWidgetXBase << 3) - 6, g_curWidgetYBase - 6, (g_curWidgetWidth << 3) + 12, g_curWidgetHeight + 12, 1, true); GUI_DrawBorder((g_curWidgetXBase << 3) - 2, g_curWidgetYBase - 2, (g_curWidgetWidth << 3) + 4, g_curWidgetHeight + 4, 2, false); GUI_Mouse_Show_Safe(); Input_History_Clear(); buffer[0] = 0; GUI_DrawText_Wrapper(NULL, 0, 0, 0, 0, 0x22); GUI_EditBox(buffer, sizeof(buffer) - 1, 9, NULL, &GUI_Mentat_Tick, 0); GUI_Security_UndrawText(); GUI_Mouse_Hide_Safe(); GUI_Screen_Copy(0, 0, g_curWidgetXBase - 1, g_curWidgetYBase - 8, g_curWidgetWidth + 2, g_curWidgetHeight + 16, SCREEN_2, SCREEN_0); GUI_Mouse_Show_Safe(); GUI_Security_NormaliseText(buffer); strncpy(g_readBuffer, String_Get_ByIndex(questionIndex + 2), g_readBufferSize); GUI_Security_NormaliseText(g_readBuffer); if (strcasecmp(g_readBuffer, buffer) != 0) { strncpy(g_readBuffer, String_Get_ByIndex(STR_SECURITY_WRONG_HARKONNEN + g_playerHouseID * 3), g_readBufferSize); } else { strncpy(g_readBuffer, String_Get_ByIndex(STR_SECURITY_CORRECT_HARKONNEN + g_playerHouseID * 3), g_readBufferSize); valid = true; } GUI_Security_DrawText(g_readBuffer); tickWaitTill = g_timerGUI + (uint32)strlen(g_readBuffer) * 4; Input_History_Clear(); /* ENHANCEMENT -- In Dune2, the + 120 is on the other side, causing the 'You are wrong! / Well done.' screen to appear very short (close to invisible, so to say) */ while (g_timerGUI + (g_dune2_enhanced ? 0 : 120) < tickWaitTill + (g_dune2_enhanced ? 120 : 0)) { if (Input_Keyboard_NextKey() != 0) break; if (g_timerGUI < tickWaitTill) { GUI_Mentat_Animation(1); } else { GUI_Mentat_Animation(0); } } GUI_Security_UndrawText(); } Widget_SetCurrentWidget(oldCurrentWidget); GFX_Screen_SetActive(oldScreenID); Input_History_Clear(); Load_Palette_Mercenaries(); g_disableOtherMovement = false; g_interrogation = false; return valid; }
/** * Handles Click event for savegame button. * * @param index The index of the clicked button. * @return True if a game has been saved, False otherwise. */ static bool GUI_Widget_Savegame_Click(uint16 index) { WindowDesc *desc = &g_savegameNameWindowDesc; bool loop; char *saveDesc = g_savegameDesc[index]; bool widgetPaint; bool ret; if (*saveDesc == '[') *saveDesc = 0; GUI_Window_BackupScreen(desc); GUI_Window_Create(desc); ret = false; widgetPaint = true; if (*saveDesc == '[') index = s_savegameCountOnDisk; GFX_Screen_SetActive(SCREEN_0); Widget_SetCurrentWidget(15); GUI_Mouse_Hide_Safe(); GUI_DrawBorder((g_curWidgetXBase << 3) - 1, g_curWidgetYBase - 1, (g_curWidgetWidth << 3) + 2, g_curWidgetHeight + 2, 4, false); GUI_Mouse_Show_Safe(); for (loop = true; loop; sleepIdle()) { uint16 eventKey; Widget *w = g_widgetLinkedListTail; GUI_DrawText_Wrapper(NULL, 0, 0, 232, 235, 0x22); eventKey = GUI_EditBox(saveDesc, 50, 15, g_widgetLinkedListTail, NULL, widgetPaint); widgetPaint = false; if ((eventKey & 0x8000) == 0) continue; GUI_Widget_MakeNormal(GUI_Widget_Get_ByIndex(w, eventKey & 0x7FFF), false); switch (eventKey & 0x7FFF) { case 0x1E: /* RETURN / Save Button */ if (*saveDesc == 0) break; SaveGame_SaveFile(GenerateSavegameFilename(s_savegameIndexBase - index), saveDesc); loop = false; ret = true; break; case 0x1F: /* ESCAPE / Cancel Button */ loop = false; ret = false; FillSavegameDesc(true); break; default: break; } } GUI_Window_RestoreScreen(desc); return ret; }
/** * Redraw parts of the viewport that require redrawing. * * @param forceRedraw If true, dirty flags are ignored, and everything is drawn. * @param arg08 ?? * @param drawToMainScreen True if and only if we are drawing to the main screen and not some buffer screen. */ void GUI_Widget_Viewport_Draw(bool forceRedraw, bool arg08, bool drawToMainScreen) { static const uint16 values_32A4[8][2] = { {0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {3, 1}, {2, 1}, {1, 1} }; uint16 x; uint16 y; uint16 i; uint16 curPos; bool updateDisplay; Screen oldScreenID; uint16 oldValue_07AE_0000; int16 minX[10]; int16 maxX[10]; PoolFindStruct find; updateDisplay = forceRedraw; memset(minX, 0xF, sizeof(minX)); memset(maxX, 0, sizeof(minX)); oldScreenID = GFX_Screen_SetActive(SCREEN_1); oldValue_07AE_0000 = Widget_SetCurrentWidget(2); if (g_dirtyViewportCount != 0 || forceRedraw) { for (y = 0; y < 10; y++) { uint16 top = (y << 4) + 0x28; for (x = 0; x < (drawToMainScreen ? 15 : 16); x++) { Tile *t; uint16 left; curPos = g_viewportPosition + Tile_PackXY(x, y); if (x < 15 && !forceRedraw && BitArray_Test(g_dirtyViewport, curPos)) { if (maxX[y] < x) maxX[y] = x; if (minX[y] > x) minX[y] = x; updateDisplay = true; } if (!BitArray_Test(g_dirtyMinimap, curPos) && !forceRedraw) continue; BitArray_Set(g_dirtyViewport, curPos); if (x < 15) { updateDisplay = true; if (maxX[y] < x) maxX[y] = x; if (minX[y] > x) minX[y] = x; } t = &g_map[curPos]; left = x << 4; if (!g_debugScenario && g_veiledSpriteID == t->overlaySpriteID) { GUI_DrawFilledRectangle(left, top, left + 15, top + 15, 12); continue; } GFX_DrawSprite(t->groundSpriteID, left, top, t->houseID); if (t->overlaySpriteID == 0 || g_debugScenario) continue; GFX_DrawSprite(t->overlaySpriteID, left, top, t->houseID); } } g_dirtyViewportCount = 0; } find.type = UNIT_SANDWORM; find.index = 0xFFFF; find.houseID = HOUSE_INVALID; while (true) { Unit *u; uint8 *sprite; u = Unit_Find(&find); if (u == NULL) break; if (!u->o.flags.s.isDirty && !forceRedraw) continue; u->o.flags.s.isDirty = false; if (!g_map[Tile_PackTile(u->o.position)].isUnveiled && !g_debugScenario) continue; sprite = GUI_Widget_Viewport_Draw_GetSprite(g_table_unitInfo[u->o.type].groundSpriteID, Unit_GetHouseID(u)); s_spriteFlags = 0x200; if (Map_IsPositionInViewport(u->o.position, &x, &y)) GUI_DrawSprite(g_screenActiveID, sprite, x, y, 2, s_spriteFlags | 0xC000); if (Map_IsPositionInViewport(u->targetLast, &x, &y)) GUI_DrawSprite(g_screenActiveID, sprite, x, y, 2, s_spriteFlags | 0xC000); if (Map_IsPositionInViewport(u->targetPreLast, &x, &y)) GUI_DrawSprite(g_screenActiveID, sprite, x, y, 2, s_spriteFlags | 0xC000); if (u != g_unitSelected) continue; if (!Map_IsPositionInViewport(u->o.position, &x, &y)) continue; GUI_DrawSprite(g_screenActiveID, g_sprites[6], x, y, 2, 0xC000); } if (g_unitSelected == NULL && (g_var_3A08 != 0 || arg08) && (Structure_Get_ByPackedTile(g_selectionRectanglePosition) != NULL || g_selectionType == SELECTIONTYPE_PLACE || g_debugScenario)) { uint16 x1 = (Tile_GetPackedX(g_selectionRectanglePosition) - Tile_GetPackedX(g_minimapPosition)) << 4; uint16 y1 = ((Tile_GetPackedY(g_selectionRectanglePosition) - Tile_GetPackedY(g_minimapPosition)) << 4) + 0x28; uint16 x2 = x1 + (g_selectionWidth << 4) - 1; uint16 y2 = y1 + (g_selectionHeight << 4) - 1; GUI_SetClippingArea(0, 40, 239, SCREEN_HEIGHT - 1); GUI_DrawWiredRectangle(x1, y1, x2, y2, 0xFF); if (g_selectionState == 0 && g_selectionType == SELECTIONTYPE_PLACE) { GUI_DrawLine(x1, y1, x2, y2, 0xFF); GUI_DrawLine(x2, y1, x1, y2, 0xFF); } GUI_SetClippingArea(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1); g_var_3A08 = 0; } if (g_dirtyUnitCount != 0 || forceRedraw || updateDisplay) { find.type = 0xFFFF; find.index = 0xFFFF; find.houseID = HOUSE_INVALID; while (true) { Unit *u; UnitInfo *ui; uint16 packed; uint8 orientation; uint16 index; u = Unit_Find(&find); if (u == NULL) break; if (u->o.index < 20 || u->o.index > 101) continue; packed = Tile_PackTile(u->o.position); if ((!u->o.flags.s.isDirty || u->o.flags.s.isNotOnMap) && !forceRedraw && !BitArray_Test(g_dirtyViewport, packed)) continue; u->o.flags.s.isDirty = false; if (!g_map[packed].isUnveiled && !g_debugScenario) continue; ui = &g_table_unitInfo[u->o.type]; if (!Map_IsPositionInViewport(u->o.position, &x, &y)) continue; x += g_table_tilediff[0][u->wobbleIndex].x; y += g_table_tilediff[0][u->wobbleIndex].y; orientation = Orientation_Orientation256ToOrientation8(u->orientation[0].current); if (u->spriteOffset >= 0 || ui->destroyedSpriteID == 0) { static const uint16 values_32C4[8][2] = { {0, 0}, {1, 0}, {1, 0}, {1, 0}, {2, 0}, {1, 1}, {1, 1}, {1, 1} }; index = ui->groundSpriteID; switch (ui->displayMode) { case DISPLAYMODE_UNIT: case DISPLAYMODE_ROCKET: if (ui->movementType == MOVEMENT_SLITHER) break; index += values_32A4[orientation][0]; s_spriteFlags = values_32A4[orientation][1]; break; case DISPLAYMODE_INFANTRY_3_FRAMES: { static const uint16 values_334A[4] = {0, 1, 0, 2}; index += values_32C4[orientation][0] * 3; index += values_334A[u->spriteOffset & 3]; s_spriteFlags = values_32C4[orientation][1]; } break; case DISPLAYMODE_INFANTRY_4_FRAMES: index += values_32C4[orientation][0] * 4; index += u->spriteOffset & 3; s_spriteFlags = values_32C4[orientation][1]; break; default: s_spriteFlags = 0; break; } } else { index = ui->destroyedSpriteID - u->spriteOffset - 1; s_spriteFlags = 0; } if (u->o.type != UNIT_SANDWORM && u->o.flags.s.isHighlighted) s_spriteFlags |= 0x100; if (ui->o.flags.blurTile) s_spriteFlags |= 0x200; GUI_DrawSprite(g_screenActiveID, GUI_Widget_Viewport_Draw_GetSprite(index, (u->deviated != 0) ? u->deviatedHouse : Unit_GetHouseID(u)), x, y, 2, s_spriteFlags | 0xE000, s_paletteHouse, g_paletteMapping2, 1); if (u->o.type == UNIT_HARVESTER && u->actionID == ACTION_HARVEST && u->spriteOffset >= 0 && (u->actionID == ACTION_HARVEST || u->actionID == ACTION_MOVE)) { uint16 type = Map_GetLandscapeType(packed); if (type == LST_SPICE || type == LST_THICK_SPICE) { static const int16 values_334E[8][2] = { {0, 7}, {-7, 6}, {-14, 1}, {-9, -6}, {0, -9}, { 9, -6}, { 14, 1}, { 7, 6} }; GUI_DrawSprite(g_screenActiveID, GUI_Widget_Viewport_Draw_GetSprite((u->spriteOffset % 3) + 0xDF + (values_32A4[orientation][0] * 3), Unit_GetHouseID(u)), x + values_334E[orientation][0], y + values_334E[orientation][1], 2, values_32A4[orientation][1] | 0xC000); } } if (u->spriteOffset >= 0 && ui->turretSpriteID != 0xFFFF) { int16 offsetX = 0; int16 offsetY = 0; uint16 spriteID = ui->turretSpriteID; orientation = Orientation_Orientation256ToOrientation8(u->orientation[ui->o.flags.hasTurret ? 1 : 0].current); switch (ui->turretSpriteID) { case 0x8D: /* sonic tank */ offsetY = -2; break; case 0x92: /* rocket launcher */ offsetY = -3; break; case 0x7E: { /* siege tank */ static const int16 values_336E[8][2] = { { 0, -5}, { 0, -5}, { 2, -3}, { 2, -1}, {-1, -3}, {-2, -1}, {-2, -3}, {-1, -5} }; offsetX = values_336E[orientation][0]; offsetY = values_336E[orientation][1]; } break; case 0x88: { /* devastator */ static const int16 values_338E[8][2] = { { 0, -4}, {-1, -3}, { 2, -4}, {0, -3}, {-1, -3}, { 0, -3}, {-2, -4}, {1, -3} }; offsetX = values_338E[orientation][0]; offsetY = values_338E[orientation][1]; } break; default: break; } s_spriteFlags = values_32A4[orientation][1]; spriteID += values_32A4[orientation][0]; GUI_DrawSprite(g_screenActiveID, GUI_Widget_Viewport_Draw_GetSprite(spriteID, Unit_GetHouseID(u)), x + offsetX, y + offsetY, 2, s_spriteFlags | 0xE000, s_paletteHouse); } if (u->o.flags.s.isSmoking) { uint16 spriteID = 180 + (u->spriteOffset & 3); if (spriteID == 183) spriteID = 181; GUI_DrawSprite(g_screenActiveID, g_sprites[spriteID], x, y - 14, 2, 0xC000); } if (u != g_unitSelected) continue; GUI_DrawSprite(g_screenActiveID, g_sprites[6], x, y, 2, 0xC000); } g_dirtyUnitCount = 0; } for (i = 0; i < EXPLOSION_MAX; i++) { Explosion *e = Explosion_Get_ByIndex(i); curPos = Tile_PackTile(e->position); if (BitArray_Test(g_dirtyViewport, curPos)) e->isDirty = true; if (e->commands == NULL) continue; if (!e->isDirty && !forceRedraw) continue; if (e->spriteID == 0) continue; e->isDirty = false; if (!g_map[curPos].isUnveiled && !g_debugScenario) continue; if (!Map_IsPositionInViewport(e->position, &x, &y)) continue; s_spriteFlags = 0xC000; GUI_DrawSprite(g_screenActiveID, GUI_Widget_Viewport_Draw_GetSprite(e->spriteID, e->houseID), x, y, 2, s_spriteFlags, s_paletteHouse); } if (g_dirtyAirUnitCount != 0 || forceRedraw || updateDisplay) { find.type = 0xFFFF; find.index = 0xFFFF; find.houseID = HOUSE_INVALID; while (true) { static const uint16 values_32E4[8][2] = { {0, 0}, {1, 0}, {2, 0}, {1, 2}, {0, 2}, {1, 3}, {2, 1}, {1, 1} }; Unit *u; UnitInfo *ui; uint8 orientation; uint8 *sprite; uint16 index; u = Unit_Find(&find); if (u == NULL) break; if (u->o.index > 15) continue; curPos = Tile_PackTile(u->o.position); if ((!u->o.flags.s.isDirty || u->o.flags.s.isNotOnMap) && !forceRedraw && !BitArray_Test(g_dirtyViewport, curPos)) continue; u->o.flags.s.isDirty = false; if (!g_map[curPos].isUnveiled && !g_debugScenario) continue; ui = &g_table_unitInfo[u->o.type]; if (!Map_IsPositionInViewport(u->o.position, &x, &y)) continue; index = ui->groundSpriteID; orientation = u->orientation[0].current; s_spriteFlags = 0xC000; switch (ui->displayMode) { case DISPLAYMODE_SINGLE_FRAME: if (u->o.flags.s.bulletIsBig) index++; break; case DISPLAYMODE_UNIT: orientation = Orientation_Orientation256ToOrientation8(orientation); index += values_32E4[orientation][0]; s_spriteFlags |= values_32E4[orientation][1]; break; case DISPLAYMODE_ROCKET: { static const uint16 values_3304[16][2] = { {0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {3, 2}, {2, 2}, {1, 2}, {0, 2}, {3, 3}, {2, 3}, {3, 3}, {4, 1}, {3, 1}, {2, 1}, {1, 1} }; orientation = Orientation_Orientation256ToOrientation16(orientation); index += values_3304[orientation][0]; s_spriteFlags |= values_3304[orientation][1]; } break; case DISPLAYMODE_ORNITHOPTER: { static const uint16 values_33AE[4] = {2, 1, 0, 1}; orientation = Orientation_Orientation256ToOrientation8(orientation); index += (values_32E4[orientation][0] * 3) + values_33AE[u->spriteOffset & 3]; s_spriteFlags |= values_32E4[orientation][1]; } break; default: s_spriteFlags = 0x0; break; } if (ui->flags.hasAnimationSet && u->o.flags.s.animationFlip) index += 5; if (u->o.type == UNIT_CARRYALL && u->o.flags.s.inTransport) index += 3; sprite = GUI_Widget_Viewport_Draw_GetSprite(index, Unit_GetHouseID(u)); if (ui->o.flags.hasShadow) GUI_DrawSprite(g_screenActiveID, sprite, x + 1, y + 3, 2, (s_spriteFlags & 0xDFFF) | 0x300, g_paletteMapping1, 1); if (ui->o.flags.blurTile) s_spriteFlags |= 0x200; GUI_DrawSprite(g_screenActiveID, sprite, x, y, 2, s_spriteFlags | 0x2000, s_paletteHouse); } g_dirtyAirUnitCount = 0; } if (updateDisplay) { memset(g_dirtyMinimap, 0, sizeof(g_dirtyMinimap)); memset(g_dirtyViewport, 0, sizeof(g_dirtyViewport)); } if (g_changedTilesCount != 0) { bool init = false; bool update = false; Screen oldScreenID2 = SCREEN_1; for (i = 0; i < g_changedTilesCount; i++) { curPos = g_changedTiles[i]; BitArray_Clear(g_changedTilesMap, curPos); if (!init) { init = true; oldScreenID2 = GFX_Screen_SetActive(SCREEN_1); GUI_Mouse_Hide_InWidget(3); } GUI_Widget_Viewport_DrawTile(curPos); if (!update && BitArray_Test(g_displayedMinimap, curPos)) update = true; } if (update) Map_UpdateMinimapPosition(g_minimapPosition, true); if (init) { GUI_Screen_Copy(32, 136, 32, 136, 8, 64, g_screenActiveID, SCREEN_0); GFX_Screen_SetActive(oldScreenID2); GUI_Mouse_Show_InWidget(); } if (g_changedTilesCount == lengthof(g_changedTiles)) { g_changedTilesCount = 0; for (i = 0; i < 4096; i++) { if (!BitArray_Test(g_changedTilesMap, i)) continue; g_changedTiles[g_changedTilesCount++] = i; if (g_changedTilesCount == lengthof(g_changedTiles)) break; } } else { g_changedTilesCount = 0; } } if ((g_viewportMessageCounter & 1) != 0 && g_viewportMessageText != NULL && (minX[6] <= 14 || maxX[6] >= 0 || arg08 || forceRedraw)) { GUI_DrawText_Wrapper(g_viewportMessageText, 112, 139, 15, 0, 0x132); minX[6] = -1; maxX[6] = 14; } if (updateDisplay && !drawToMainScreen) { if (g_viewport_fadein) { GUI_Mouse_Hide_InWidget(g_curWidgetIndex); /* ENHANCEMENT -- When fading in the game on start, you don't see the fade as it is against the already drawn screen. */ if (g_dune2_enhanced) { Screen oldScreenID2 = g_screenActiveID; GFX_Screen_SetActive(SCREEN_0); GUI_DrawFilledRectangle(g_curWidgetXBase << 3, g_curWidgetYBase, (g_curWidgetXBase + g_curWidgetWidth) << 3, g_curWidgetYBase + g_curWidgetHeight, 0); GFX_Screen_SetActive(oldScreenID2); } GUI_Screen_FadeIn(g_curWidgetXBase, g_curWidgetYBase, g_curWidgetXBase, g_curWidgetYBase, g_curWidgetWidth, g_curWidgetHeight, g_screenActiveID, SCREEN_0); GUI_Mouse_Show_InWidget(); g_viewport_fadein = false; } else { bool init = false; for (i = 0; i < 10; i++) { uint16 width; uint16 height; if (arg08) { minX[i] = 0; maxX[i] = 14; } if (maxX[i] < minX[i]) continue; x = minX[i] * 2; y = (i << 4) + 0x28; width = (maxX[i] - minX[i] + 1) * 2; height = 16; if (!init) { GUI_Mouse_Hide_InWidget(g_curWidgetIndex); init = true; } GUI_Screen_Copy(x, y, x, y, width, height, g_screenActiveID, SCREEN_0); } if (init) GUI_Mouse_Show_InWidget(); } } GFX_Screen_SetActive(oldScreenID); Widget_SetCurrentWidget(oldValue_07AE_0000); }
static void GameLoop_PlaySubtitle(uint8 animation) { const HouseAnimation_Subtitle *subtitle; uint8 i; uint8 colors[16]; s_var_8068++; GameLoop_PlaySoundEffect(animation); subtitle = &s_houseAnimation_subtitle[s_houseAnimation_currentSubtitle]; if (subtitle->stringID == 0xFFFF || subtitle->animationID > animation) return; if (s_subtitleActive) { if (s_subtitleWait == 0xFFFF) s_subtitleWait = subtitle->waitFadeout; if (s_subtitleWait-- != 0) return; s_subtitleActive = false; s_houseAnimation_currentSubtitle++; s_palettePartDirection = PPD_TO_BLACK; if (subtitle->paletteFadeout != 0) { s_palettePartCount = subtitle->paletteFadeout; for (i = 0; i < 18; i++) { s_palettePartChange[i] = s_palettePartTarget[i] / s_palettePartCount; if (s_palettePartChange[i] == 0) s_palettePartChange[i] = 1; } return; } memcpy(s_palettePartChange, s_palettePartTarget, 18); s_palettePartCount = 1; return; } if (s_subtitleWait == 0xFFFF) s_subtitleWait = subtitle->waitFadein; if (s_subtitleWait-- != 0) return; memcpy(s_palettePartTarget, &g_palette1[(144 + (subtitle->colour * 16)) * 3], 18); s_subtitleActive = true; GUI_DrawFilledRectangle(0, subtitle->top == 85 ? 0 : subtitle->top, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, 0); if (g_enableVoices != 0 && s_feedback_base_index != 0xFFFF && s_houseAnimation_currentSubtitle != 0 && g_config.language == LANGUAGE_ENGLISH) { /* specific code for Intro * @see GameLoop_GameIntroAnimation() */ uint16 feedback_index = s_feedback_base_index + s_houseAnimation_currentSubtitle; Sound_Output_Feedback(feedback_index); if (g_feedback[feedback_index].messageId != 0) { /* force drawing of subtitle */ GameLoop_DrawText(String_Get_ByIndex(subtitle->stringID), subtitle->top); } } else { if (subtitle->stringID != STR_NULL) { GameLoop_DrawText(String_Get_ByIndex(subtitle->stringID), subtitle->top); } } s_palettePartDirection = PPD_TO_NEW_PALETTE; if (subtitle->paletteFadein != 0) { s_palettePartCount = subtitle->paletteFadein; for (i = 0; i < 18; i++) { s_palettePartChange[i] = s_palettePartTarget[i] / s_palettePartCount; if (s_palettePartChange[i] == 0) s_palettePartChange[i] = 1; } } else { memcpy(s_palettePartChange, s_palettePartTarget, 18); s_palettePartCount = 1; } if (g_playerHouseID != HOUSE_INVALID || s_houseAnimation_currentSubtitle != 2) return; GUI_DrawText_Wrapper(NULL, 0, 0, 0, 0, 0x21); GUI_DrawText_Wrapper("Copyright (c) 1992 Westwood Studios, Inc.", 160, 189, 215, 0, 0x112); g_fontCharOffset = 0; colors[0] = 0; for (i = 0; i < 6; i++) colors[i + 1] = 215 + i; GUI_InitColors(colors, 0, 15); Font_Select(g_fontIntro); }
uint16 GUI_Mentat_Loop(const char *wsaFilename, char *pictureDetails, char *text, bool arg12, Widget *w) { uint16 oldScreenID; uint16 old07AE; void *wsa; uint16 descLines; bool dirty; bool done; bool textDone; uint16 frame; uint32 descTick; uint16 mentatSpeakingMode; uint16 result; uint32 textTick; uint32 textDelay; uint16 lines; uint16 textLines; uint16 step; dirty = false; textTick = 0; textDelay = 0; old07AE = Widget_SetCurrentWidget(8); oldScreenID = GFX_Screen_SetActive(4); wsa = NULL; if (wsaFilename != NULL) { wsa = WSA_LoadFile(wsaFilename, GFX_Screen_Get_ByIndex(3), GFX_Screen_GetSize_ByIndex(3), false); } step = 0; if (wsa == NULL) { Widget_PaintCurrentWidget(); step = 1; } GUI_DrawText_Wrapper(NULL, 0, 0, 0, 0, 0x31); descLines = GUI_SplitText(pictureDetails, (g_curWidgetWidth << 3) + 10, '\0'); GUI_DrawText_Wrapper(NULL, 0, 0, 0, 0, 0x32); textLines = GUI_Mentat_SplitText(text, 304); mentatSpeakingMode = 2; lines = 0; frame = 0; g_timerTimeout = 0; descTick = g_timerGUI + 30; Input_History_Clear(); textDone = false; done = false; result = 0; while (!done) { uint16 key; GFX_Screen_SetActive(0); key = GUI_Widget_HandleEvents(w); GUI_PaletteAnimate(); if (key != 0) { if ((key & 0x800) == 0) { if (w != NULL) { if ((key & 0x8000) != 0 && result == 0) result = key; } else { if (textDone) result = key; } } else { key = 0; } } switch (step) { case 0: if (key == 0) break; step = 1; /* FALL-THROUGH */ case 1: if (key != 0) { if (result != 0) { step = 5; break; } lines = descLines; dirty = true; } else { if (g_timerGUI > descTick) { descTick = g_timerGUI + 15; lines++; dirty = true; } } if (lines < descLines && lines <= 12) break; step = (text != NULL) ? 2 : 4; lines = descLines; break; case 2: GUI_Mouse_Hide_InRegion(0, 0, SCREEN_WIDTH, 40); GUI_Screen_Copy(0, 0, 0, 160, SCREEN_WIDTH / 8, 40, 0, 4); GUI_Mouse_Show_InRegion(); step = 3; key = 1; /* FALL-THROUGH */ case 3: if (mentatSpeakingMode == 2 && textTick < g_timerGUI) key = 1; if ((key != 0 && textDone) || result != 0) { GUI_Mouse_Hide_InRegion(0, 0, SCREEN_WIDTH, 40); GUI_Screen_Copy(0, 160, 0, 0, SCREEN_WIDTH / 8, 40, 4, 0); GUI_Mouse_Show_InRegion(); step = 4; mentatSpeakingMode = 0; break; } if (key != 0) { GUI_Screen_Copy(0, 160, 0, 0, SCREEN_WIDTH / 8, 40, 4, 4); if (textLines-- != 0) { GFX_Screen_SetActive(4); GUI_DrawText_Wrapper(text, 4, 1, g_curWidgetFGColourBlink, 0, 0x32); mentatSpeakingMode = 1; textDelay = strlen(text) * 4; textTick = g_timerGUI + textDelay; if (textLines != 0) { while (*text++ != '\0') {} } else { textDone = true; } GFX_Screen_SetActive(0); } GUI_Mouse_Hide_InRegion(0, 0, SCREEN_WIDTH, 40); GUI_Screen_Copy(0, 0, 0, 0, SCREEN_WIDTH / 8, 40, 4, 0); GUI_Mouse_Show_InRegion(); break; } if (mentatSpeakingMode == 0 || textTick > g_timerGUI) break; mentatSpeakingMode = 2; textTick += textDelay + textDelay / 2; break; case 4: if (result != 0 || w == NULL) step = 5; break; case 5: dirty = true; done = true; break; default: break; } GUI_Mentat_Animation(mentatSpeakingMode); if (wsa != NULL && g_timerTimeout == 0) { g_timerTimeout = 7; do { if (step == 0 && frame > 4) step = 1; if (!WSA_DisplayFrame(wsa, frame++, g_curWidgetXBase << 3, g_curWidgetYBase, 4)) { if (step == 0) step = 1; if (arg12 != 0) { frame = 0; } else { WSA_Unload(wsa); wsa = NULL; } } } while (frame == 0); dirty = true; } if (!dirty) { sleepIdle(); continue; } GUI_Mentat_DrawInfo(pictureDetails, (g_curWidgetXBase << 3) + 5, g_curWidgetYBase + 3, 8, 0, lines, 0x31); GUI_DrawSprite(4, g_sprites[397 + g_playerHouseID * 15], g_shoulderLeft, g_shoulderTop, 0, 0); GUI_Mouse_Hide_InWidget(g_curWidgetIndex); GUI_Screen_Copy(g_curWidgetXBase, g_curWidgetYBase, g_curWidgetXBase, g_curWidgetYBase, g_curWidgetWidth, g_curWidgetHeight, 4, 0); GUI_Mouse_Show_InWidget(); dirty = false; sleepIdle(); } if (wsa != NULL) WSA_Unload(wsa); GFX_Screen_SetActive(4); GUI_DrawSprite(4, g_sprites[397 + g_playerHouseID * 15], g_shoulderLeft, g_shoulderTop, 0, 0); GUI_Mouse_Hide_InWidget(g_curWidgetIndex); GUI_Screen_Copy(g_curWidgetXBase, g_curWidgetYBase, g_curWidgetXBase, g_curWidgetYBase, g_curWidgetWidth, g_curWidgetHeight, 4, 0); GUI_Mouse_Show_InWidget(); Widget_SetCurrentWidget(old07AE); GFX_Screen_SetActive(oldScreenID); Input_History_Clear(); return result; }