warzone2100/src/frontend.cpp

1982 lines
54 KiB
C++

/*
This file is part of Warzone 2100.
Copyright (C) 1999-2004 Eidos Interactive
Copyright (C) 2005-2013 Warzone 2100 Project
Warzone 2100 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.
Warzone 2100 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 Warzone 2100; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* FrontEnd.c
*
* front end title and options screens.
* Alex Lee. Pumpkin Studios. Eidos PLC 98,
*/
#include "lib/framework/wzapp.h"
#if defined(WZ_OS_WIN)
# include <shellapi.h> /* For ShellExecute */
#endif
#include "lib/framework/input.h"
#include "lib/framework/wzconfig.h"
#include "lib/framework/physfs_ext.h"
#include "lib/ivis_opengl/bitimage.h"
#include "lib/ivis_opengl/pieblitfunc.h"
#include "lib/ivis_opengl/piestate.h"
#include "lib/sound/mixer.h"
#include "lib/widget/button.h"
#include "lib/widget/label.h"
#include "lib/widget/slider.h"
#include "advvis.h"
#include "challenge.h"
#include "component.h"
#include "configuration.h"
#include "difficulty.h"
#include "display.h"
#include "frend.h"
#include "frontend.h"
#include "hci.h"
#include "init.h"
#include "intdisplay.h"
#include "keyedit.h"
#include "loadsave.h"
#include "main.h"
#include "modding.h"
#include "multiint.h"
#include "multilimit.h"
#include "multiplay.h"
#include "radar.h"
#include "seqdisp.h"
#include "texture.h"
#include "version.h"
#include "warzoneconfig.h"
#include "wrappers.h"
struct CAMPAIGN_FILE
{
QString name;
QString level;
QString video;
QString captions;
QString package;
QString loading;
};
// ////////////////////////////////////////////////////////////////////////////
// Global variables
tMode titleMode; // the global case
tMode lastTitleMode; // Since skirmish and multiplayer setup use the same functions, we use this to go back to the corresponding menu.
char aLevelName[MAX_LEVEL_NAME_SIZE+1]; //256]; // vital! the wrf file to use.
bool bLimiterLoaded = false;
#define TUTORIAL_LEVEL "TUTORIAL3"
// Returns true if escape key pressed.
//
bool CancelPressed(void)
{
const bool cancel = keyPressed(KEY_ESC);
if (cancel)
{
inputLoseFocus(); // clear the input buffer.
}
return cancel;
}
// ////////////////////////////////////////////////////////////////////////////
// Title Screen
static bool startTitleMenu(void)
{
intRemoveReticule();
addBackdrop();
addTopForm();
addBottomForm();
addTextButton(FRONTEND_SINGLEPLAYER, FRONTEND_POS2X, FRONTEND_POS2Y, _("Single Player"), WBUT_TXTCENTRE);
addTextButton(FRONTEND_MULTIPLAYER, FRONTEND_POS3X, FRONTEND_POS3Y, _("Multi Player"), WBUT_TXTCENTRE);
addTextButton(FRONTEND_TUTORIAL, FRONTEND_POS4X, FRONTEND_POS4Y, _("Tutorial"), WBUT_TXTCENTRE);
addTextButton(FRONTEND_OPTIONS, FRONTEND_POS5X, FRONTEND_POS5Y, _("Options"), WBUT_TXTCENTRE);
if (PHYSFS_exists("sequences/devastation.ogg"))
{
addTextButton(FRONTEND_PLAYINTRO, FRONTEND_POS6X, FRONTEND_POS6Y, _("View Intro"), WBUT_TXTCENTRE);
}
else
{
addTextButton(FRONTEND_PLAYINTRO, FRONTEND_POS6X, FRONTEND_POS6Y, _("View Intro"), WBUT_TXTCENTRE|WBUT_DISABLE);
widgSetTip(psWScreen, FRONTEND_PLAYINTRO, _("Videos are missing, download them from http://wz2100.net"));
}
addTextButton(FRONTEND_QUIT, FRONTEND_POS7X, FRONTEND_POS7Y, _("Quit Game"), WBUT_TXTCENTRE);
addSideText(FRONTEND_SIDETEXT, FRONTEND_SIDEX, FRONTEND_SIDEY, _("MAIN MENU"));
addSmallTextButton(FRONTEND_HYPERLINK, FRONTEND_POS8X, FRONTEND_POS8Y, _("Official site: http://wz2100.net/"), 0);
addSmallTextButton(FRONTEND_DONATELINK, FRONTEND_POS8X + 360, FRONTEND_POS8Y, _("Donate: http://donations.wz2100.net/"), 0);
return true;
}
static void runHyperlink(void)
{
#if defined(WZ_OS_WIN)
ShellExecuteW(NULL, L"open", L"http://wz2100.net/", NULL, NULL, SW_SHOWNORMAL);
#elif defined (WZ_OS_MAC)
// For the macs
system("open http://wz2100.net");
#else
// for linux
int stupidWarning = system("xdg-open http://wz2100.net &");
(void)stupidWarning; // Why is system() a warn_unused_result function..?
#endif
}
static void rundonatelink(void)
{
#if defined(WZ_OS_WIN)
ShellExecuteW(NULL, L"open", L"http://donations.wz2100.net/", NULL, NULL, SW_SHOWNORMAL);
#elif defined (WZ_OS_MAC)
// For the macs
system("open http://donations.wz2100.net");
#else
// for linux
int stupidWarning = system("xdg-open http://donations.wz2100.net &");
(void)stupidWarning; // Why is system() a warn_unused_result function..?
#endif
}
bool runTitleMenu(void)
{
WidgetTriggers const &triggers = widgRunScreen(psWScreen);
unsigned id = triggers.empty()? 0 : triggers.front().widget->id; // Just use first click here, since the next click could be on another menu.
switch(id)
{
case FRONTEND_QUIT:
changeTitleMode(CREDITS);
break;
case FRONTEND_MULTIPLAYER:
changeTitleMode(MULTI);
break;
case FRONTEND_SINGLEPLAYER:
changeTitleMode(SINGLE);
break;
case FRONTEND_OPTIONS:
changeTitleMode(OPTIONS);
break;
case FRONTEND_TUTORIAL:
changeTitleMode(TUTORIAL);
break;
case FRONTEND_PLAYINTRO:
changeTitleMode(SHOWINTRO);
break;
case FRONTEND_HYPERLINK:
runHyperlink();
break;
case FRONTEND_DONATELINK:
rundonatelink();
break;
default:
break;
}
widgDisplayScreen(psWScreen); // show the widgets currently running
return true;
}
// ////////////////////////////////////////////////////////////////////////////
// Tutorial Menu
static bool startTutorialMenu(void)
{
addBackdrop();
addTopForm();
addBottomForm();
addTextButton(FRONTEND_TUTORIAL, FRONTEND_POS3X,FRONTEND_POS3Y, _("Tutorial"), WBUT_TXTCENTRE);
addTextButton(FRONTEND_FASTPLAY, FRONTEND_POS4X,FRONTEND_POS4Y, _("Fast Play"), WBUT_TXTCENTRE);
addSideText (FRONTEND_SIDETEXT ,FRONTEND_SIDEX,FRONTEND_SIDEY,_("TUTORIALS"));
// TRANSLATORS: "Return", in this context, means "return to previous screen/menu"
addMultiBut(psWScreen, FRONTEND_BOTFORM, FRONTEND_QUIT, 10, 10, 30, 29, P_("menu", "Return"), IMAGE_RETURN, IMAGE_RETURN_HI, IMAGE_RETURN_HI);
return true;
}
bool runTutorialMenu(void)
{
WidgetTriggers const &triggers = widgRunScreen(psWScreen);
unsigned id = triggers.empty()? 0 : triggers.front().widget->id; // Just use first click here, since the next click could be on another menu.
switch(id)
{
case FRONTEND_TUTORIAL:
NetPlay.players[0].allocated = true;
game.skDiff[0] = UBYTE_MAX;
sstrcpy(aLevelName, TUTORIAL_LEVEL);
changeTitleMode(STARTGAME);
break;
case FRONTEND_FASTPLAY:
NETinit(true);
NetPlay.players[0].allocated = true;
game.skDiff[0] = UBYTE_MAX;
sstrcpy(aLevelName, "FASTPLAY");
changeTitleMode(STARTGAME);
break;
case FRONTEND_QUIT:
changeTitleMode(TITLE);
break;
default:
break;
}
// If close button pressed then return from this menu.
if(CancelPressed()) {
changeTitleMode(TITLE);
}
widgDisplayScreen(psWScreen); // show the widgets currently running
return true;
}
// ////////////////////////////////////////////////////////////////////////////
// Single Player Menu
static void startSinglePlayerMenu(void)
{
challengeActive = false;
addBackdrop();
addTopForm();
addBottomForm();
addTextButton(FRONTEND_NEWGAME, FRONTEND_POS2X,FRONTEND_POS2Y,_("New Campaign") , WBUT_TXTCENTRE);
addTextButton(FRONTEND_SKIRMISH, FRONTEND_POS3X,FRONTEND_POS3Y, _("Start Skirmish Game"), WBUT_TXTCENTRE);
addTextButton(FRONTEND_CHALLENGES, FRONTEND_POS4X, FRONTEND_POS4Y, _("Challenges"), WBUT_TXTCENTRE);
addTextButton(FRONTEND_LOADGAME_MISSION, FRONTEND_POS5X,FRONTEND_POS5Y, _("Load Campaign Game"), WBUT_TXTCENTRE);
addTextButton(FRONTEND_LOADGAME_SKIRMISH, FRONTEND_POS6X,FRONTEND_POS6Y, _("Load Skirmish Game"), WBUT_TXTCENTRE);
addSideText (FRONTEND_SIDETEXT ,FRONTEND_SIDEX,FRONTEND_SIDEY,_("SINGLE PLAYER"));
addMultiBut(psWScreen, FRONTEND_BOTFORM, FRONTEND_QUIT, 10, 10, 30, 29, P_("menu", "Return"), IMAGE_RETURN, IMAGE_RETURN_HI, IMAGE_RETURN_HI);
// show this only when the video sequences are not installed
if (!PHYSFS_exists("sequences/devastation.ogg"))
{
addSmallTextButton(FRONTEND_HYPERLINK, FRONTEND_POS8X, FRONTEND_POS8Y, _("Campaign videos are missing! Get them from http://wz2100.net"), 0);
}
}
static QList<CAMPAIGN_FILE> readCampaignFiles()
{
QList<CAMPAIGN_FILE> result;
char **files = PHYSFS_enumerateFiles("campaigns");
for (char **i = files; *i != NULL; ++i)
{
CAMPAIGN_FILE c;
QString filename("campaigns/");
filename += *i;
if (!filename.endsWith(".ini"))
{
continue;
}
WzConfig ini(filename, WzConfig::ReadOnlyAndRequired);
ini.beginGroup("campaign");
c.name = ini.value("name").toString();
c.level = ini.value("level").toString();
c.package = ini.value("package").toString();
c.loading = ini.value("loading").toString();
ini.endGroup();
ini.beginGroup("intro");
c.video = ini.value("video").toString();
c.captions = ini.value("captions").toString();
ini.endGroup();
result += c;
}
PHYSFS_freeList(files);
return result;
}
static void startCampaignSelector()
{
static char hackList[10][100]; // sigh...
addBackdrop();
addTopForm();
addBottomForm();
QList<CAMPAIGN_FILE> list = readCampaignFiles();
for (int i = 0; i < list.size(); i++)
{
ssprintf(hackList[i], list[i].name.toUtf8().constData()); // since widget system is crazy and takes pointers not copies
addTextButton(FRONTEND_CAMPAIGN_1 + i, FRONTEND_POS1X, FRONTEND_POS2Y + 40 * i, hackList[i], WBUT_TXTCENTRE);
}
addSideText(FRONTEND_SIDETEXT, FRONTEND_SIDEX, FRONTEND_SIDEY, _("CAMPAIGNS"));
addMultiBut(psWScreen, FRONTEND_BOTFORM, FRONTEND_QUIT, 10, 10, 30, 29, P_("menu", "Return"), IMAGE_RETURN, IMAGE_RETURN_HI, IMAGE_RETURN_HI);
// show this only when the video sequences are not installed
if (!PHYSFS_exists("sequences/devastation.ogg"))
{
addSmallTextButton(FRONTEND_HYPERLINK, FRONTEND_POS8X, FRONTEND_POS8Y, _("Campaign videos are missing! Get them from http://wz2100.net"), 0);
}
}
static void frontEndNewGame(int which)
{
QList<CAMPAIGN_FILE> list = readCampaignFiles();
sstrcpy(aLevelName, list[which].level.toUtf8().constData());
if (!list[which].video.isEmpty())
{
seq_ClearSeqList();
seq_AddSeqToList(list[which].video.toUtf8().constData(), NULL, list[which].captions.toUtf8().constData(), false);
seq_StartNextFullScreenVideo();
}
if (!list[which].package.isEmpty())
{
QString path;
path += PHYSFS_getWriteDir();
path += PHYSFS_getDirSeparator();
path += "campaigns";
path += PHYSFS_getDirSeparator();
path += list[which].package;
if (!PHYSFS_mount(path.toUtf8().constData(), NULL, PHYSFS_APPEND))
{
debug(LOG_ERROR, "Failed to load campaign mod \"%s\": %s",
path.toUtf8().constData(), PHYSFS_getLastError());
}
}
if (!list[which].loading.isEmpty())
{
debug(LOG_WZ, "Adding campaign mod level \"%s\"", list[which].loading.toUtf8().constData());
if (!loadLevFile(list[which].loading.toUtf8().constData(), mod_campaign, false, NULL))
{
debug(LOG_ERROR, "Failed to load %s", list[which].loading.toUtf8().constData());
return;
}
}
debug(LOG_WZ, "Loading campaign mod -- %s", aLevelName);
changeTitleMode(STARTGAME);
}
static void loadOK( void )
{
if(strlen(sRequestResult))
{
sstrcpy(saveGameName, sRequestResult);
changeTitleMode(LOADSAVEGAME);
}
}
static void SPinit(void)
{
uint8_t playercolor;
// clear out the skDiff array
memset(game.skDiff, 0x0, sizeof(game.skDiff));
NetPlay.bComms = false;
bMultiPlayer = false;
bMultiMessages = false;
game.type = CAMPAIGN;
NET_InitPlayers();
NetPlay.players[0].allocated = true;
NetPlay.players[0].autoGame = false;
game.skDiff[0] = UBYTE_MAX;
game.maxPlayers = MAX_PLAYERS;
// make sure we have a valid color choice for our SP game. Valid values are 0, 4-7
playercolor = war_GetSPcolor();
if (playercolor >= 1 && playercolor <= 3)
{
playercolor = 0; // default is green
}
setPlayerColour(0, playercolor);
game.hash.setZero(); // must reset this to zero
}
bool runCampaignSelector()
{
WidgetTriggers const &triggers = widgRunScreen(psWScreen);
unsigned id = triggers.empty()? 0 : triggers.front().widget->id; // Just use first click here, since the next click could be on another menu.
if (id == FRONTEND_QUIT)
{
changeTitleMode(SINGLE); // go back
}
else if (id >= FRONTEND_CAMPAIGN_1 && id <= FRONTEND_CAMPAIGN_6) // chose a campaign
{
SPinit();
frontEndNewGame(id - FRONTEND_CAMPAIGN_1);
}
widgDisplayScreen(psWScreen); // show the widgets currently running
return true;
}
bool runSinglePlayerMenu(void)
{
if(bLoadSaveUp)
{
if(runLoadSave(false))// check for file name.
{
loadOK();
}
}
else if (challengesUp)
{
runChallenges();
}
else
{
WidgetTriggers const &triggers = widgRunScreen(psWScreen);
unsigned id = triggers.empty()? 0 : triggers.front().widget->id; // Just use first click here, since the next click could be on another menu.
switch(id)
{
case FRONTEND_NEWGAME:
changeTitleMode(CAMPAIGNS);
break;
case FRONTEND_LOADGAME_MISSION:
SPinit();
addLoadSave(LOAD_FRONTEND_MISSION, _("Load Campaign Saved Game")); // change mode when loadsave returns
break;
case FRONTEND_LOADGAME_SKIRMISH:
SPinit();
bMultiPlayer = true;
addLoadSave(LOAD_FRONTEND_SKIRMISH, _("Load Skirmish Saved Game")); // change mode when loadsave returns
break;
case FRONTEND_SKIRMISH:
SPinit();
ingame.bHostSetup = true;
lastTitleMode = SINGLE;
changeTitleMode(MULTIOPTION);
break;
case FRONTEND_QUIT:
changeTitleMode(TITLE);
break;
case FRONTEND_CHALLENGES:
SPinit();
addChallenges();
break;
default:
break;
}
if(CancelPressed())
{
changeTitleMode(TITLE);
}
}
if (!bLoadSaveUp && !challengesUp) // if save/load screen is up
{
widgDisplayScreen(psWScreen); // show the widgets currently running
}
if (bLoadSaveUp) // if save/load screen is up
{
displayLoadSave();
}
else if (challengesUp)
{
displayChallenges();
}
return true;
}
// ////////////////////////////////////////////////////////////////////////////
// Multi Player Menu
static bool startMultiPlayerMenu(void)
{
addBackdrop();
addTopForm();
addBottomForm();
addSideText (FRONTEND_SIDETEXT , FRONTEND_SIDEX,FRONTEND_SIDEY,_("MULTI PLAYER"));
addTextButton(FRONTEND_HOST, FRONTEND_POS2X,FRONTEND_POS2Y, _("Host Game"), WBUT_TXTCENTRE);
addTextButton(FRONTEND_JOIN, FRONTEND_POS3X,FRONTEND_POS3Y, _("Join Game"), WBUT_TXTCENTRE);
addMultiBut(psWScreen, FRONTEND_BOTFORM, FRONTEND_QUIT, 10, 10, 30, 29, P_("menu", "Return"), IMAGE_RETURN, IMAGE_RETURN_HI, IMAGE_RETURN_HI);
// This isn't really a hyperlink for now... perhaps link to the wiki ?
addSmallTextButton(FRONTEND_HYPERLINK, FRONTEND_POS8X, FRONTEND_POS8Y, _("TCP port 2100 must be opened in your firewall or router to host games!"), 0);
return true;
}
bool runMultiPlayerMenu(void)
{
WidgetTriggers const &triggers = widgRunScreen(psWScreen);
unsigned id = triggers.empty()? 0 : triggers.front().widget->id; // Just use first click here, since the next click could be on another menu.
switch(id)
{
case FRONTEND_HOST:
// don't pretend we are running a network game. Really do it!
NetPlay.bComms = true; // use network = true
NetPlay.isUPNP_CONFIGURED = false;
NetPlay.isUPNP_ERROR = false;
ingame.bHostSetup = true;
bMultiPlayer = true;
bMultiMessages = true;
NETinit(true);
NETdiscoverUPnPDevices();
game.type = SKIRMISH; // needed?
lastTitleMode = MULTI;
changeTitleMode(MULTIOPTION);
break;
case FRONTEND_JOIN:
NETinit(true);
ingame.bHostSetup = false;
if (getLobbyError() != ERROR_INVALID)
{
setLobbyError(ERROR_NOERROR);
}
changeTitleMode(PROTOCOL);
break;
case FRONTEND_QUIT:
changeTitleMode(TITLE);
break;
default:
break;
}
widgDisplayScreen(psWScreen); // show the widgets currently running
if (CancelPressed())
{
changeTitleMode(TITLE);
}
return true;
}
// ////////////////////////////////////////////////////////////////////////////
// Options Menu
static bool startOptionsMenu(void)
{
sliderEnableDrag(true);
addBackdrop();
addTopForm();
addBottomForm();
addSideText(FRONTEND_SIDETEXT, FRONTEND_SIDEX,FRONTEND_SIDEY, _("OPTIONS"));
addTextButton(FRONTEND_GAMEOPTIONS, FRONTEND_POS2X,FRONTEND_POS2Y, _("Game Options"), WBUT_TXTCENTRE);
addTextButton(FRONTEND_GRAPHICSOPTIONS, FRONTEND_POS3X,FRONTEND_POS3Y, _("Graphics Options"), WBUT_TXTCENTRE);
addTextButton(FRONTEND_VIDEOOPTIONS, FRONTEND_POS4X,FRONTEND_POS4Y, _("Video Options"), WBUT_TXTCENTRE);
addTextButton(FRONTEND_AUDIOOPTIONS, FRONTEND_POS5X,FRONTEND_POS5Y, _("Audio Options"), WBUT_TXTCENTRE);
addTextButton(FRONTEND_MOUSEOPTIONS, FRONTEND_POS6X,FRONTEND_POS6Y, _("Mouse Options"), WBUT_TXTCENTRE);
addTextButton(FRONTEND_KEYMAP, FRONTEND_POS7X,FRONTEND_POS7Y, _("Key Mappings"), WBUT_TXTCENTRE);
addMultiBut(psWScreen, FRONTEND_BOTFORM, FRONTEND_QUIT, 10, 10, 30, 29, P_("menu", "Return"), IMAGE_RETURN, IMAGE_RETURN_HI, IMAGE_RETURN_HI);
return true;
}
bool runOptionsMenu(void)
{
WidgetTriggers const &triggers = widgRunScreen(psWScreen);
unsigned id = triggers.empty()? 0 : triggers.front().widget->id; // Just use first click here, since the next click could be on another menu.
switch(id)
{
case FRONTEND_GAMEOPTIONS:
changeTitleMode(GAME);
break;
case FRONTEND_GRAPHICSOPTIONS:
changeTitleMode(GRAPHICS_OPTIONS);
break;
case FRONTEND_AUDIOOPTIONS:
changeTitleMode(AUDIO_OPTIONS);
break;
case FRONTEND_VIDEOOPTIONS:
changeTitleMode(VIDEO_OPTIONS);
break;
case FRONTEND_MOUSEOPTIONS:
changeTitleMode(MOUSE_OPTIONS);
break;
case FRONTEND_KEYMAP:
changeTitleMode(KEYMAP);
break;
case FRONTEND_QUIT:
changeTitleMode(TITLE);
break;
default:
break;
}
// If close button pressed then return from this menu.
if (CancelPressed())
{
changeTitleMode(TITLE);
}
widgDisplayScreen(psWScreen); // show the widgets currently running
return true;
}
// ////////////////////////////////////////////////////////////////////////////
// Graphics Options
static bool startGraphicsOptionsMenu(void)
{
addBackdrop();
addTopForm();
addBottomForm();
////////////
//FMV mode.
addTextButton(FRONTEND_FMVMODE, FRONTEND_POS2X - 35, FRONTEND_POS2Y, _("Video Playback"), 0);
switch (war_GetFMVmode())
{
case FMV_1X:
addTextButton(FRONTEND_FMVMODE_R, FRONTEND_POS2M - 55,FRONTEND_POS2Y, _("1X"), 0);
break;
case FMV_2X:
addTextButton(FRONTEND_FMVMODE_R, FRONTEND_POS2M - 55,FRONTEND_POS2Y, _("2X"), 0);
break;
case FMV_FULLSCREEN:
addTextButton(FRONTEND_FMVMODE_R, FRONTEND_POS2M - 55,FRONTEND_POS2Y, _("Fullscreen"), 0);
break;
default:
ASSERT(!"invalid FMV mode", "Invalid FMV mode: %u", (unsigned int)war_GetFMVmode());
break;
}
// Scanlines
addTextButton(FRONTEND_SCANLINES, FRONTEND_POS3X - 35, FRONTEND_POS3Y, _("Scanlines"), 0);
switch (war_getScanlineMode())
{
case SCANLINES_OFF:
addTextButton(FRONTEND_SCANLINES_R, FRONTEND_POS3M - 55, FRONTEND_POS3Y, _("Off"), 0);
break;
case SCANLINES_50:
addTextButton(FRONTEND_SCANLINES_R, FRONTEND_POS3M - 55, FRONTEND_POS3Y, _("50%"), 0);
break;
case SCANLINES_BLACK:
addTextButton(FRONTEND_SCANLINES_R, FRONTEND_POS3M - 55, FRONTEND_POS3Y, _("Black"), 0);
break;
}
////////////
// screenshake
addTextButton(FRONTEND_SSHAKE, FRONTEND_POS4X-35, FRONTEND_POS4Y, _("Screen Shake"), 0);
if(getShakeStatus())
{// shaking on
addTextButton(FRONTEND_SSHAKE_R, FRONTEND_POS4M-55, FRONTEND_POS4Y, _("On"), 0);
}
else
{//shaking off.
addTextButton(FRONTEND_SSHAKE_R, FRONTEND_POS4M-55, FRONTEND_POS4Y, _("Off"), 0);
}
////////////
//subtitle mode.
addTextButton(FRONTEND_SUBTITLES, FRONTEND_POS6X - 35, FRONTEND_POS5Y, _("Subtitles"), 0);
if (!seq_GetSubtitles())
{
addTextButton(FRONTEND_SUBTITLES_R, FRONTEND_POS6M - 55, FRONTEND_POS5Y, _("Off"), 0);
}
else
{
addTextButton(FRONTEND_SUBTITLES_R, FRONTEND_POS6M - 55, FRONTEND_POS5Y, _("On"), 0);
}
////////////
//shadows
addTextButton(FRONTEND_SHADOWS, FRONTEND_POS7X - 35, FRONTEND_POS6Y, _("Shadows"), 0);
if (getDrawShadows())
{
addTextButton(FRONTEND_SHADOWS_R, FRONTEND_POS7M - 55, FRONTEND_POS6Y, _("On"), 0);
}
else
{ // not flipped
addTextButton(FRONTEND_SHADOWS_R, FRONTEND_POS7M - 55, FRONTEND_POS6Y, _("Off"), 0);
}
// Radar
addTextButton(FRONTEND_RADAR, FRONTEND_POS7X - 35, FRONTEND_POS7Y, _("Radar"), 0);
addTextButton(FRONTEND_RADAR_R, FRONTEND_POS7M - 55, FRONTEND_POS7Y, rotateRadar ? _("Rotating") : _("Fixed"), 0);
// Add some text down the side of the form
addSideText(FRONTEND_SIDETEXT, FRONTEND_SIDEX, FRONTEND_SIDEY, _("GRAPHICS OPTIONS"));
////////////
// quit.
addMultiBut(psWScreen, FRONTEND_BOTFORM, FRONTEND_QUIT, 10, 10, 30, 29, P_("menu", "Return"), IMAGE_RETURN, IMAGE_RETURN_HI, IMAGE_RETURN_HI);
return true;
}
bool runGraphicsOptionsMenu(void)
{
int mode = 0;
WidgetTriggers const &triggers = widgRunScreen(psWScreen);
unsigned id = triggers.empty()? 0 : triggers.front().widget->id; // Just use first click here, since the next click could be on another menu.
switch(id)
{
case FRONTEND_SSHAKE:
case FRONTEND_SSHAKE_R:
if( getShakeStatus() )
{
setShakeStatus(false);
widgSetString(psWScreen,FRONTEND_SSHAKE_R, _("Off"));
}
else
{
setShakeStatus(true);
widgSetString(psWScreen,FRONTEND_SSHAKE_R, _("On"));
}
break;
case FRONTEND_QUIT:
changeTitleMode(OPTIONS);
break;
case FRONTEND_SUBTITLES:
case FRONTEND_SUBTITLES_R:
if( seq_GetSubtitles())
{// turn off
seq_SetSubtitles(false);
widgSetString(psWScreen,FRONTEND_SUBTITLES_R,_("Off"));
}
else
{// turn on
seq_SetSubtitles(true);
widgSetString(psWScreen,FRONTEND_SUBTITLES_R,_("On"));
}
break;
case FRONTEND_SHADOWS:
case FRONTEND_SHADOWS_R:
setDrawShadows(!getDrawShadows());
if (getDrawShadows())
{
widgSetString(psWScreen, FRONTEND_SHADOWS_R, _("On"));
}
else
{
widgSetString(psWScreen, FRONTEND_SHADOWS_R, _("Off"));
}
break;
case FRONTEND_FMVMODE:
case FRONTEND_FMVMODE_R:
switch (mode = war_GetFMVmode())
{
case FMV_1X:
war_SetFMVmode((FMV_MODE)(mode + 1));
widgSetString(psWScreen, FRONTEND_FMVMODE_R, _("2X"));
break;
case FMV_2X:
war_SetFMVmode((FMV_MODE)(mode + 1));
widgSetString(psWScreen, FRONTEND_FMVMODE_R, _("Fullscreen"));
break;
case FMV_FULLSCREEN:
war_SetFMVmode((FMV_MODE)(mode + 1));
widgSetString(psWScreen, FRONTEND_FMVMODE_R, _("1X"));
break;
default:
ASSERT(!"invalid FMV mode", "Invalid FMV mode: %u", (unsigned int)mode);
break;
}
break;
case FRONTEND_SCANLINES:
case FRONTEND_SCANLINES_R:
switch (mode = war_getScanlineMode())
{
case SCANLINES_OFF:
war_setScanlineMode(SCANLINES_50);
widgSetString(psWScreen, FRONTEND_SCANLINES_R, _("50%"));
break;
case SCANLINES_50:
war_setScanlineMode(SCANLINES_BLACK);
widgSetString(psWScreen, FRONTEND_SCANLINES_R, _("Black"));
break;
case SCANLINES_BLACK:
war_setScanlineMode(SCANLINES_OFF);
widgSetString(psWScreen, FRONTEND_SCANLINES_R, _("Off"));
break;
}
break;
case FRONTEND_RADAR_R:
rotateRadar = !rotateRadar;
widgSetString(psWScreen, FRONTEND_RADAR_R, rotateRadar ? _("Rotating") : _("Fixed"));
break;
default:
break;
}
// If close button pressed then return from this menu.
if(CancelPressed()) {
changeTitleMode(OPTIONS);
}
widgDisplayScreen(psWScreen); // show the widgets currently running
return true;
}
// ////////////////////////////////////////////////////////////////////////////
// Audio Options Menu
static bool startAudioOptionsMenu(void)
{
addBackdrop();
addTopForm();
addBottomForm();
// 2d audio
addTextButton(FRONTEND_FX, FRONTEND_POS2X-25,FRONTEND_POS2Y, _("Voice Volume"), 0);
addFESlider(FRONTEND_FX_SL, FRONTEND_BOTFORM, FRONTEND_POS2M, FRONTEND_POS2Y+5, AUDIO_VOL_MAX, sound_GetUIVolume() * 100.0);
// 3d audio
addTextButton(FRONTEND_3D_FX, FRONTEND_POS3X-25,FRONTEND_POS3Y, _("FX Volume"), 0);
addFESlider(FRONTEND_3D_FX_SL, FRONTEND_BOTFORM, FRONTEND_POS3M, FRONTEND_POS3Y+5, AUDIO_VOL_MAX, sound_GetEffectsVolume() * 100.0);
// cd audio
addTextButton(FRONTEND_MUSIC, FRONTEND_POS4X-25,FRONTEND_POS4Y, _("Music Volume"), 0);
addFESlider(FRONTEND_MUSIC_SL, FRONTEND_BOTFORM, FRONTEND_POS4M, FRONTEND_POS4Y+5, AUDIO_VOL_MAX, sound_GetMusicVolume() * 100.0);
// quit.
addMultiBut(psWScreen, FRONTEND_BOTFORM, FRONTEND_QUIT, 10, 10, 30, 29, P_("menu", "Return"), IMAGE_RETURN, IMAGE_RETURN_HI, IMAGE_RETURN_HI);
//add some text down the side of the form
addSideText(FRONTEND_SIDETEXT, FRONTEND_SIDEX, FRONTEND_SIDEY, _("AUDIO OPTIONS"));
return true;
}
bool runAudioOptionsMenu(void)
{
WidgetTriggers const &triggers = widgRunScreen(psWScreen);
unsigned id = triggers.empty()? 0 : triggers.front().widget->id; // Just use first click here, since the next click could be on another menu.
switch(id)
{
case FRONTEND_FX:
case FRONTEND_3D_FX:
case FRONTEND_MUSIC:
break;
case FRONTEND_FX_SL:
sound_SetUIVolume((float)widgGetSliderPos(psWScreen,FRONTEND_FX_SL) / 100.0);
break;
case FRONTEND_3D_FX_SL:
sound_SetEffectsVolume((float)widgGetSliderPos(psWScreen,FRONTEND_3D_FX_SL) / 100.0);
break;
case FRONTEND_MUSIC_SL:
sound_SetMusicVolume((float)widgGetSliderPos(psWScreen, FRONTEND_MUSIC_SL) / 100.0);
break;
case FRONTEND_QUIT:
changeTitleMode(OPTIONS);
break;
default:
break;
}
// If close button pressed then return from this menu.
if(CancelPressed()) {
changeTitleMode(OPTIONS);
}
widgDisplayScreen(psWScreen); // show the widgets currently running
return true;
}
// ////////////////////////////////////////////////////////////////////////////
// Video Options
static bool startVideoOptionsMenu(void)
{
// Generate the resolution string
char resolution[43];
char textureSize[20];
ssprintf(resolution, "%d x %d", war_GetWidth(), war_GetHeight());
// Generate texture size string
ssprintf(textureSize, "%d", getTextureSize());
addBackdrop();
addTopForm();
addBottomForm();
// Add a note about changes taking effect on restart for certain options
WIDGET *parent = widgGetFromID(psWScreen, FRONTEND_BOTFORM);
W_LABEL *label = new W_LABEL(parent);
label->setGeometry(FRONTEND_POS1X + 48, FRONTEND_POS1Y, FRONTEND_BUTWIDTH - FRONTEND_POS1X - 48, FRONTEND_BUTHEIGHT);
label->setFontColour(WZCOL_TEXT_BRIGHT);
label->setString(_("* Takes effect on game restart"));
label->setTextAlignment(WLAB_ALIGNBOTTOMLEFT);
// Fullscreen/windowed
addTextButton(FRONTEND_WINDOWMODE, FRONTEND_POS2X-35, FRONTEND_POS2Y, _("Graphics Mode*"), 0);
if (war_getFullscreen())
{
addTextButton(FRONTEND_WINDOWMODE_R, FRONTEND_POS2M-55, FRONTEND_POS2Y, _("Fullscreen"), 0);
}
else
{
addTextButton(FRONTEND_WINDOWMODE_R, FRONTEND_POS2M-55, FRONTEND_POS2Y, _("Windowed"), 0);
}
// Resolution
addTextButton(FRONTEND_RESOLUTION, FRONTEND_POS3X-35, FRONTEND_POS3Y, _("Resolution*"), WBUT_SECONDARY);
addTextButton(FRONTEND_RESOLUTION_R, FRONTEND_POS3M-55, FRONTEND_POS3Y, resolution, WBUT_SECONDARY);
widgSetString(psWScreen, FRONTEND_RESOLUTION_R, resolution);
// Texture size
addTextButton(FRONTEND_TEXTURESZ, FRONTEND_POS4X-35, FRONTEND_POS4Y, _("Texture size"), 0);
addTextButton(FRONTEND_TEXTURESZ_R, FRONTEND_POS4M-55, FRONTEND_POS4Y, textureSize, 0);
// Vsync
addTextButton(FRONTEND_VSYNC, FRONTEND_POS5X-35, FRONTEND_POS5Y, _("Vertical sync"), 0);
if (war_GetVsync())
{
addTextButton(FRONTEND_VSYNC_R, FRONTEND_POS5M-55, FRONTEND_POS5Y, _("On"), 0);
}
else
{
addTextButton(FRONTEND_VSYNC_R, FRONTEND_POS5M-55, FRONTEND_POS5Y, _("Off"), 0);
}
// FSAA
addTextButton(FRONTEND_FSAA, FRONTEND_POS5X-35, FRONTEND_POS6Y, "FSAA*", 0);
switch (war_getFSAA())
{
case FSAA_OFF:
addTextButton(FRONTEND_FSAA_R, FRONTEND_POS5M-55, FRONTEND_POS6Y, _("Off"), 0);
break;
case FSAA_2X:
addTextButton(FRONTEND_FSAA_R, FRONTEND_POS5M-55, FRONTEND_POS6Y, "2X", 0);
break;
case FSAA_4X:
addTextButton(FRONTEND_FSAA_R, FRONTEND_POS5M-55, FRONTEND_POS6Y, "4X", 0);
break;
case FSAA_8X:
addTextButton(FRONTEND_FSAA_R, FRONTEND_POS5M-55, FRONTEND_POS6Y, "8X", 0);
break;
default:
// Some cards can do 16x & 32x ...
addTextButton(FRONTEND_FSAA_R, FRONTEND_POS5M-55, FRONTEND_POS6Y, _("Unsupported"), 0);
break;
}
// Add some text down the side of the form
addSideText(FRONTEND_SIDETEXT, FRONTEND_SIDEX, FRONTEND_SIDEY, _("VIDEO OPTIONS"));
// Quit/return
addMultiBut(psWScreen, FRONTEND_BOTFORM, FRONTEND_QUIT, 10, 10, 30, 29, P_("menu", "Return"), IMAGE_RETURN, IMAGE_RETURN_HI, IMAGE_RETURN_HI);
return true;
}
bool runVideoOptionsMenu(void)
{
QList<QSize> modes = wzAvailableResolutions();
WidgetTriggers const &triggers = widgRunScreen(psWScreen);
unsigned id = triggers.empty()? 0 : triggers.front().widget->id; // Just use first click here, since the next click could be on another menu.
int level;
switch (id)
{
case FRONTEND_WINDOWMODE:
case FRONTEND_WINDOWMODE_R:
if (war_getFullscreen())
{
war_setFullscreen(false);
widgSetString(psWScreen, FRONTEND_WINDOWMODE_R, _("Windowed"));
}
else
{
war_setFullscreen(true);
widgSetString(psWScreen, FRONTEND_WINDOWMODE_R, _("Fullscreen"));
}
break;
case FRONTEND_FSAA:
case FRONTEND_FSAA_R:
switch (level = war_getFSAA())
{
case FSAA_OFF:
war_setFSAA((FSAA_LEVEL)(level + 1));
widgSetString(psWScreen, FRONTEND_FSAA_R, "2X");
break;
case FSAA_2X:
war_setFSAA((FSAA_LEVEL)(level + 1));
widgSetString(psWScreen, FRONTEND_FSAA_R, "4X");
break;
case FSAA_4X:
war_setFSAA((FSAA_LEVEL)(level + 1));
widgSetString(psWScreen, FRONTEND_FSAA_R, "8X");
break;
case FSAA_8X:
war_setFSAA((FSAA_LEVEL)(level + 1));
widgSetString(psWScreen, FRONTEND_FSAA_R, _("Off"));
break;
default:
// we can't check what the max level the card is capable of, without first creating that level, and testing.
ASSERT(!"invalid FSAA level ?", "Invalid FSAA level: %u", (unsigned int)level);
addTextButton(FRONTEND_FSAA_R, FRONTEND_POS5M-55, FRONTEND_POS6Y, _("Unsupported"), 0);
break;
}
break;
case FRONTEND_RESOLUTION:
case FRONTEND_RESOLUTION_R:
{
int current, count;
// Get the current mode offset
for (count = 0, current = 0; count < modes.size(); count++)
{
if (war_GetWidth() == modes[count].width() && war_GetHeight() == modes[count].height())
{
current = count;
}
}
// Increment and clip if required
if (!mouseReleased(MOUSE_RMB))
{
if (--current < 0)
current = count - 1;
}
else
{
if (++current == count)
current = 0;
}
// We can't pick resolutions if there are any.
if (modes.isEmpty())
{
debug(LOG_ERROR,"No resolutions available to change.");
break;
}
// Set the new width and height (takes effect on restart)
war_SetWidth(modes[current].width());
war_SetHeight(modes[current].height());
// Generate the textual representation of the new width and height
char resolution[43];
ssprintf(resolution, "%d x %d", modes[current].width(), modes[current].height());
// Update the widget
widgSetString(psWScreen, FRONTEND_RESOLUTION_R, resolution);
break;
}
case FRONTEND_TRAP:
case FRONTEND_TRAP_R:
if (war_GetTrapCursor())
{
war_SetTrapCursor(false);
widgSetString(psWScreen, FRONTEND_TRAP_R, _("Off"));
}
else
{
war_SetTrapCursor(true);
widgSetString(psWScreen, FRONTEND_TRAP_R, _("On"));
}
break;
case FRONTEND_TEXTURESZ:
case FRONTEND_TEXTURESZ_R:
{
int newTexSize = getTextureSize() * 2;
// Clip such that 128 <= size <= 2048
if (newTexSize > 2048)
{
newTexSize = 128;
}
// Set the new size
setTextureSize(newTexSize);
// Generate the string representation of the new size
char textureSize[20];
ssprintf(textureSize, "%d", newTexSize);
// Update the widget
widgSetString(psWScreen, FRONTEND_TEXTURESZ_R, textureSize);
break;
}
case FRONTEND_VSYNC:
case FRONTEND_VSYNC_R:
{
wzSetSwapInterval(!war_GetVsync());
war_SetVsync(wzGetSwapInterval());
if (war_GetVsync())
{
widgSetString(psWScreen, FRONTEND_VSYNC_R, _("On"));
}
else
{
widgSetString(psWScreen, FRONTEND_VSYNC_R, _("Off"));
}
break;
}
case FRONTEND_QUIT:
changeTitleMode(OPTIONS);
break;
default:
break;
}
if (CancelPressed())
{
changeTitleMode(OPTIONS);
}
widgDisplayScreen(psWScreen);
return true;
}
// ////////////////////////////////////////////////////////////////////////////
// Mouse Options
static bool startMouseOptionsMenu(void)
{
addBackdrop();
addTopForm();
addBottomForm();
////////////
// mouseflip
addTextButton(FRONTEND_MFLIP, FRONTEND_POS2X-35, FRONTEND_POS2Y, _("Reverse Rotation"), 0);
if( getInvertMouseStatus() )
{ // flipped
addTextButton(FRONTEND_MFLIP_R, FRONTEND_POS2M-25, FRONTEND_POS2Y, _("On"), 0);
}
else
{ // not flipped
addTextButton(FRONTEND_MFLIP_R, FRONTEND_POS2M-25, FRONTEND_POS2Y, _("Off"), 0);
}
// Cursor trapping
addTextButton(FRONTEND_TRAP, FRONTEND_POS3X-35, FRONTEND_POS3Y, _("Trap Cursor"), 0);
if (war_GetTrapCursor())
{
addTextButton(FRONTEND_TRAP_R, FRONTEND_POS3M-25, FRONTEND_POS3Y, _("On"), 0);
}
else
{
addTextButton(FRONTEND_TRAP_R, FRONTEND_POS3M-25, FRONTEND_POS3Y, _("Off"), 0);
}
////////////
// left-click orders
addTextButton(FRONTEND_MBUTTONS, FRONTEND_POS2X-35, FRONTEND_POS4Y, _("Switch Mouse Buttons"), 0);
if( getRightClickOrders() )
{ // right-click orders
addTextButton(FRONTEND_MBUTTONS_R, FRONTEND_POS2M-25, FRONTEND_POS4Y, _("On"), 0);
}
else
{ // left-click orders
addTextButton(FRONTEND_MBUTTONS_R, FRONTEND_POS2M-25, FRONTEND_POS4Y, _("Off"), 0);
}
////////////
// middle-click rotate
addTextButton(FRONTEND_MMROTATE, FRONTEND_POS2X-35, FRONTEND_POS5Y, _("Rotate Screen"), 0);
if( getMiddleClickRotate() )
{ // right-click orders
addTextButton(FRONTEND_MMROTATE_R, FRONTEND_POS2M-25, FRONTEND_POS5Y, _("Middle Mouse"), 0);
}
else
{ // left-click orders
addTextButton(FRONTEND_MMROTATE_R, FRONTEND_POS2M-25, FRONTEND_POS5Y, _("Right Mouse"), 0);
}
// Add some text down the side of the form
addSideText(FRONTEND_SIDETEXT, FRONTEND_SIDEX, FRONTEND_SIDEY, _("MOUSE OPTIONS"));
// Quit/return
addMultiBut(psWScreen, FRONTEND_BOTFORM, FRONTEND_QUIT, 10, 10, 30, 29, P_("menu", "Return"), IMAGE_RETURN, IMAGE_RETURN_HI, IMAGE_RETURN_HI);
return true;
}
bool runMouseOptionsMenu(void)
{
WidgetTriggers const &triggers = widgRunScreen(psWScreen);
unsigned id = triggers.empty()? 0 : triggers.front().widget->id; // Just use first click here, since the next click could be on another menu.
switch (id)
{
case FRONTEND_MFLIP:
case FRONTEND_MFLIP_R:
if( getInvertMouseStatus() )
{// flipped
setInvertMouseStatus(false);
widgSetString(psWScreen,FRONTEND_MFLIP_R, _("Off"));
}
else
{ // not flipped
setInvertMouseStatus(true);
widgSetString(psWScreen,FRONTEND_MFLIP_R, _("On"));
}
break;
case FRONTEND_TRAP:
case FRONTEND_TRAP_R:
if (war_GetTrapCursor())
{
war_SetTrapCursor(false);
widgSetString(psWScreen, FRONTEND_TRAP_R, _("Off"));
}
else
{
war_SetTrapCursor(true);
widgSetString(psWScreen, FRONTEND_TRAP_R, _("On"));
}
break;
case FRONTEND_MBUTTONS:
case FRONTEND_MBUTTONS_R:
if( getRightClickOrders() )
{
setRightClickOrders(false);
widgSetString(psWScreen,FRONTEND_MBUTTONS_R, _("Off"));
}
else
{
setRightClickOrders(true);
widgSetString(psWScreen,FRONTEND_MBUTTONS_R, _("On"));
}
break;
case FRONTEND_MMROTATE:
case FRONTEND_MMROTATE_R:
if( getMiddleClickRotate() )
{
setMiddleClickRotate(false);
widgSetString(psWScreen,FRONTEND_MMROTATE_R, _("Right Mouse"));
}
else
{
setMiddleClickRotate(true);
widgSetString(psWScreen,FRONTEND_MMROTATE_R, _("Middle Mouse"));
}
break;
case FRONTEND_QUIT:
changeTitleMode(OPTIONS);
break;
default:
break;
}
if (CancelPressed())
{
changeTitleMode(OPTIONS);
}
widgDisplayScreen(psWScreen);
return true;
}
// ////////////////////////////////////////////////////////////////////////////
// Game Options Menu
static bool startGameOptionsMenu(void)
{
UDWORD w, h;
int playercolor;
addBackdrop();
addTopForm();
addBottomForm();
// language
addTextButton(FRONTEND_LANGUAGE, FRONTEND_POS2X - 25, FRONTEND_POS2Y, _("Language"), 0);
addTextButton(FRONTEND_LANGUAGE_R, FRONTEND_POS2M - 25, FRONTEND_POS2Y, getLanguageName(), 0);
// Difficulty
addTextButton(FRONTEND_DIFFICULTY, FRONTEND_POS3X-25, FRONTEND_POS3Y, _("Campaign Difficulty"), 0);
switch (getDifficultyLevel())
{
case DL_EASY:
addTextButton(FRONTEND_DIFFICULTY_R, FRONTEND_POS3M-25, FRONTEND_POS3Y, _("Easy"), 0);
break;
case DL_NORMAL:
addTextButton(FRONTEND_DIFFICULTY_R, FRONTEND_POS3M-25,FRONTEND_POS3Y, _("Normal"), 0);
break;
case DL_HARD:
default:
addTextButton(FRONTEND_DIFFICULTY_R, FRONTEND_POS3M-25, FRONTEND_POS3Y, _("Hard"), 0);
break;
}
// Scroll speed
addTextButton(FRONTEND_SCROLLSPEED, FRONTEND_POS4X-25, FRONTEND_POS4Y, _("Scroll Speed"), 0);
addFESlider(FRONTEND_SCROLLSPEED_SL, FRONTEND_BOTFORM, FRONTEND_POS4M, FRONTEND_POS4Y+5, 16, scroll_speed_accel / 100);
// Colour stuff
addTextButton(FRONTEND_COLOUR, FRONTEND_POS5X-25, FRONTEND_POS5Y, _("Unit Colour:"), 0);
w = iV_GetImageWidth(FrontImages, IMAGE_PLAYERN);
h = iV_GetImageHeight(FrontImages, IMAGE_PLAYERN);
addMultiBut(psWScreen, FRONTEND_BOTFORM, FE_P0, FRONTEND_POS6M+(0*(w+6)), FRONTEND_POS6Y, w, h, NULL, IMAGE_PLAYERN, IMAGE_PLAYERX, true, 0);
addMultiBut(psWScreen, FRONTEND_BOTFORM, FE_P4, FRONTEND_POS6M+(1*(w+6)), FRONTEND_POS6Y, w, h, NULL, IMAGE_PLAYERN, IMAGE_PLAYERX, true, 4);
addMultiBut(psWScreen, FRONTEND_BOTFORM, FE_P5, FRONTEND_POS6M+(2*(w+6)), FRONTEND_POS6Y, w, h, NULL, IMAGE_PLAYERN, IMAGE_PLAYERX, true, 5);
addMultiBut(psWScreen, FRONTEND_BOTFORM, FE_P6, FRONTEND_POS6M+(3*(w+6)), FRONTEND_POS6Y, w, h, NULL, IMAGE_PLAYERN, IMAGE_PLAYERX, true, 6);
addMultiBut(psWScreen, FRONTEND_BOTFORM, FE_P7, FRONTEND_POS6M+(4*(w+6)), FRONTEND_POS6Y, w, h, NULL, IMAGE_PLAYERN, IMAGE_PLAYERX, true, 7);
// FIXME: if playercolor = 1-3, then we Assert in widgSetButtonState() since we don't define FE_P1 - FE_P3
// I assume the reason is that in SP games, those are reserved for the AI? Valid values are 0, 4-7.
// This is a workaround, until we find what is setting that to 1-3. See configuration.c:701
playercolor = war_GetSPcolor();
if (playercolor >= 1 && playercolor <= 3)
{
playercolor = 0;
}
widgSetButtonState(psWScreen, FE_P0 + playercolor, WBUT_LOCK);
addTextButton(FRONTEND_COLOUR_CAM, FRONTEND_POS6X, FRONTEND_POS6Y, _("Campaign"), 0);
playercolor = war_getMPcolour();
for (int colour = -1; colour < MAX_PLAYERS_IN_GUI; ++colour)
{
int cellX = (colour + 1)%7;
int cellY = (colour + 1)/7;
addMultiBut(psWScreen, FRONTEND_BOTFORM, FE_MP_PR + colour + 1, FRONTEND_POS7M + cellX*(w+2), FRONTEND_POS7Y + cellY*(h+2) - 5, w, h, NULL, IMAGE_PLAYERN, IMAGE_PLAYERX, true, colour >= 0? colour : MAX_PLAYERS + 1);
}
widgSetButtonState(psWScreen, FE_MP_PR + playercolor + 1, WBUT_LOCK);
addTextButton(FRONTEND_COLOUR_MP, FRONTEND_POS7X, FRONTEND_POS7Y, _("Skirmish/Multiplayer"), 0);
// Quit
addMultiBut(psWScreen, FRONTEND_BOTFORM, FRONTEND_QUIT, 10, 10, 30, 29, P_("menu", "Return"), IMAGE_RETURN, IMAGE_RETURN_HI, IMAGE_RETURN_HI);
// Add some text down the side of the form
addSideText(FRONTEND_SIDETEXT, FRONTEND_SIDEX, FRONTEND_SIDEY, _("GAME OPTIONS"));
return true;
}
bool runGameOptionsMenu(void)
{
WidgetTriggers const &triggers = widgRunScreen(psWScreen);
unsigned id = triggers.empty()? 0 : triggers.front().widget->id; // Just use first click here, since the next click could be on another menu.
switch(id)
{
case FRONTEND_LANGUAGE_R:
setNextLanguage();
widgSetString(psWScreen, FRONTEND_LANGUAGE_R, getLanguageName());
/* Hack to reset current menu text, which looks fancy. */
widgSetString(psWScreen, FRONTEND_SIDETEXT, _("GAME OPTIONS"));
widgGetFromID(psWScreen, FRONTEND_QUIT)->setTip(P_("menu", "Return"));
widgSetString(psWScreen, FRONTEND_LANGUAGE, _("Language"));
widgSetString(psWScreen, FRONTEND_COLOUR, _("Unit Colour:"));
widgSetString(psWScreen, FRONTEND_COLOUR_CAM, _("Campaign"));
widgSetString(psWScreen, FRONTEND_COLOUR_MP, _("Skirmish/Multiplayer"));
widgSetString(psWScreen, FRONTEND_DIFFICULTY, _("Campaign Difficulty"));
widgSetString(psWScreen, FRONTEND_SCROLLSPEED, _("Scroll Speed"));
switch( getDifficultyLevel() )
{
case DL_EASY:
widgSetString(psWScreen,FRONTEND_DIFFICULTY_R, _("Easy"));
break;
case DL_NORMAL:
widgSetString(psWScreen,FRONTEND_DIFFICULTY_R, _("Normal"));
break;
case DL_HARD:
widgSetString(psWScreen,FRONTEND_DIFFICULTY_R, _("Hard") );
break;
case DL_INSANE:
case DL_TOUGH:
case DL_KILLER:
debug(LOG_ERROR, "Unused difficulty level selected!");
break;
}
break;
case FRONTEND_SCROLLSPEED:
break;
case FRONTEND_DIFFICULTY:
case FRONTEND_DIFFICULTY_R:
switch( getDifficultyLevel() )
{
case DL_EASY:
setDifficultyLevel(DL_NORMAL);
widgSetString(psWScreen,FRONTEND_DIFFICULTY_R, _("Normal"));
break;
case DL_NORMAL:
setDifficultyLevel(DL_HARD);
widgSetString(psWScreen,FRONTEND_DIFFICULTY_R, _("Hard") );
break;
case DL_HARD:
setDifficultyLevel(DL_EASY);
widgSetString(psWScreen,FRONTEND_DIFFICULTY_R, _("Easy"));
break;
default: // DL_TOUGH and DL_KILLER
break;
}
break;
case FRONTEND_SCROLLSPEED_SL:
scroll_speed_accel = widgGetSliderPos(psWScreen,FRONTEND_SCROLLSPEED_SL) * 100; //0-1600
if (scroll_speed_accel == 0) // make sure you CAN scroll.
{
scroll_speed_accel = 100;
}
break;
case FRONTEND_QUIT:
changeTitleMode(OPTIONS);
break;
case FE_P0:
widgSetButtonState(psWScreen, FE_P0, WBUT_LOCK);
widgSetButtonState(psWScreen, FE_P4, 0);
widgSetButtonState(psWScreen, FE_P5, 0);
widgSetButtonState(psWScreen, FE_P6, 0);
widgSetButtonState(psWScreen, FE_P7, 0);
war_SetSPcolor(0);
break;
case FE_P4:
widgSetButtonState(psWScreen, FE_P0, 0);
widgSetButtonState(psWScreen, FE_P4, WBUT_LOCK);
widgSetButtonState(psWScreen, FE_P5, 0);
widgSetButtonState(psWScreen, FE_P6, 0);
widgSetButtonState(psWScreen, FE_P7, 0);
war_SetSPcolor(4);
break;
case FE_P5:
widgSetButtonState(psWScreen, FE_P0, 0);
widgSetButtonState(psWScreen, FE_P4, 0);
widgSetButtonState(psWScreen, FE_P5, WBUT_LOCK);
widgSetButtonState(psWScreen, FE_P6, 0);
widgSetButtonState(psWScreen, FE_P7, 0);
war_SetSPcolor(5);
break;
case FE_P6:
widgSetButtonState(psWScreen, FE_P0, 0);
widgSetButtonState(psWScreen, FE_P4, 0);
widgSetButtonState(psWScreen, FE_P5, 0);
widgSetButtonState(psWScreen, FE_P6, WBUT_LOCK);
widgSetButtonState(psWScreen, FE_P7, 0);
war_SetSPcolor(6);
break;
case FE_P7:
widgSetButtonState(psWScreen, FE_P0, 0);
widgSetButtonState(psWScreen, FE_P4, 0);
widgSetButtonState(psWScreen, FE_P5, 0);
widgSetButtonState(psWScreen, FE_P6, 0);
widgSetButtonState(psWScreen, FE_P7, WBUT_LOCK);
war_SetSPcolor(7);
break;
default:
break;
}
if (id >= FE_MP_PR && id <= FE_MP_PMAX)
{
int chosenColour = id - FE_MP_PR - 1;
for (int colour = -1; colour < MAX_PLAYERS_IN_GUI; ++colour)
{
int thisID = FE_MP_PR + colour + 1;
widgSetButtonState(psWScreen, thisID, id == thisID? WBUT_LOCK : 0);
}
war_setMPcolour(chosenColour);
}
// If close button pressed then return from this menu.
if(CancelPressed()) {
changeTitleMode(OPTIONS);
}
widgDisplayScreen(psWScreen); // show the widgets currently running
return true;
}
// ////////////////////////////////////////////////////////////////////////////
// drawing functions
// show a background piccy (currently used for version and mods labels)
static void displayTitleBitmap(WZ_DECL_UNUSED WIDGET *psWidget, WZ_DECL_UNUSED UDWORD xOffset, WZ_DECL_UNUSED UDWORD yOffset)
{
char modListText[MAX_STR_LENGTH] = "";
iV_SetFont(font_regular);
iV_SetTextColour(WZCOL_GREY);
iV_DrawTextRotated(version_getFormattedVersionString(), pie_GetVideoBufferWidth() - 9, pie_GetVideoBufferHeight() - 14, 270.f);
if (*getModList())
{
sstrcat(modListText, _("Mod: "));
sstrcat(modListText, getModList());
iV_DrawText(modListText, 9, 14);
}
iV_SetTextColour(WZCOL_TEXT_BRIGHT);
iV_DrawTextRotated(version_getFormattedVersionString(), pie_GetVideoBufferWidth() - 10, pie_GetVideoBufferHeight() - 15, 270.f);
if (*getModList())
{
iV_DrawText(modListText, 10, 15);
}
}
// ////////////////////////////////////////////////////////////////////////////
// show warzone logo
static void displayLogo(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset)
{
iV_DrawImage2("image_fe_logo.png", xOffset + psWidget->x(), yOffset + psWidget->y(), psWidget->width(), psWidget->height());
}
// ////////////////////////////////////////////////////////////////////////////
// show, well have a guess..
static void displayBigSlider(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset)
{
W_SLIDER *Slider = (W_SLIDER*)psWidget;
int x = xOffset + psWidget->x();
int y = yOffset + psWidget->y();
iV_DrawImage(IntImages,IMAGE_SLIDER_BIG,x+STAT_SLD_OX,y+STAT_SLD_OY); // draw bdrop
int sx = (Slider->width() - 3 - Slider->barSize) * Slider->pos / Slider->numStops; // determine pos.
iV_DrawImage(IntImages,IMAGE_SLIDER_BIGBUT,x+3+sx,y+3); //draw amount
}
// ////////////////////////////////////////////////////////////////////////////
// show text written on its side.
static void displayTextAt270(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset)
{
SDWORD fx,fy;
W_LABEL *psLab;
psLab = (W_LABEL *)psWidget;
iV_SetFont(font_large);
fx = xOffset + psWidget->x();
fy = yOffset + psWidget->y() + iV_GetTextWidth(psLab->aText.toUtf8().constData());
iV_SetTextColour(WZCOL_GREY);
iV_DrawTextRotated(psLab->aText.toUtf8().constData(), fx+2, fy+2, 270.f);
iV_SetTextColour(WZCOL_TEXT_BRIGHT);
iV_DrawTextRotated(psLab->aText.toUtf8().constData(), fx, fy, 270.f);
}
// ////////////////////////////////////////////////////////////////////////////
// show a text option.
void displayTextOption(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset)
{
SDWORD fx,fy, fw;
W_BUTTON *psBut;
bool hilight = false;
bool greyOut = psWidget->UserData; // if option is unavailable.
psBut = (W_BUTTON *)psWidget;
iV_SetFont(psBut->FontID);
if(widgGetMouseOver(psWScreen) == psBut->id) // if mouse is over text then hilight.
{
hilight = true;
}
fw = iV_GetTextWidth(psBut->pText.toUtf8().constData());
fy = yOffset + psWidget->y() + (psWidget->height() - iV_GetTextLineSize())/2 - iV_GetTextAboveBase();
if (psWidget->style & WBUT_TXTCENTRE) //check for centering, calculate offset.
{
fx = xOffset + psWidget->x() + ((psWidget->width() - fw) / 2);
}
else
{
fx = xOffset + psWidget->x();
}
if(greyOut) // unavailable
{
iV_SetTextColour(WZCOL_TEXT_DARK);
}
else // available
{
if(hilight) // hilight
{
iV_SetTextColour(WZCOL_TEXT_BRIGHT);
}
else if (psWidget->id == FRONTEND_HYPERLINK || psWidget->id == FRONTEND_DONATELINK) // special case for our hyperlink
{
iV_SetTextColour(WZCOL_YELLOW);
}
else // dont highlight
{
iV_SetTextColour(WZCOL_TEXT_MEDIUM);
}
}
iV_DrawText(psBut->pText.toUtf8().constData(), fx, fy);
return;
}
// ////////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////////
// common widgets.
void addBackdrop(void)
{
W_FORMINIT sFormInit; // Backdrop
sFormInit.formID = 0;
sFormInit.id = FRONTEND_BACKDROP;
sFormInit.style = WFORM_PLAIN;
sFormInit.x = (SWORD)( (pie_GetVideoBufferWidth() - HIDDEN_FRONTEND_WIDTH)/2);
sFormInit.y = (SWORD)( (pie_GetVideoBufferHeight() - HIDDEN_FRONTEND_HEIGHT)/2);
sFormInit.width = HIDDEN_FRONTEND_WIDTH-1;
sFormInit.height = HIDDEN_FRONTEND_HEIGHT-1;
sFormInit.pDisplay = displayTitleBitmap;
widgAddForm(psWScreen, &sFormInit);
}
// ////////////////////////////////////////////////////////////////////////////
void addTopForm(void)
{
WIDGET *parent = widgGetFromID(psWScreen, FRONTEND_BACKDROP);
IntFormAnimated *topForm = new IntFormAnimated(parent, false);
topForm->id = FRONTEND_TOPFORM;
if (titleMode == MULTIOPTION)
{
topForm->setGeometry(FRONTEND_TOPFORM_WIDEX, FRONTEND_TOPFORM_WIDEY, FRONTEND_TOPFORM_WIDEW, FRONTEND_TOPFORM_WIDEH);
}
else
{
topForm->setGeometry(FRONTEND_TOPFORMX, FRONTEND_TOPFORMY, FRONTEND_TOPFORMW, FRONTEND_TOPFORMH);
}
W_FORMINIT sFormInit;
sFormInit.formID= FRONTEND_TOPFORM;
sFormInit.id = FRONTEND_LOGO;
int imgW = iV_GetImageWidth(FrontImages, IMAGE_FE_LOGO);
int imgH = iV_GetImageHeight(FrontImages, IMAGE_FE_LOGO);
int dstW = topForm->width();
int dstH = topForm->height();
if (imgW*dstH < imgH*dstW) // Want to set aspect ratio dstW/dstH = imgW/imgH.
{
dstW = imgW * dstH/imgH; // Too wide.
}
else if (imgW*dstH > imgH*dstW)
{
dstH = imgH * dstW/imgW; // Too high.
}
sFormInit.x = (topForm->width() - dstW)/2;
sFormInit.y = (topForm->height() - dstH)/2;
sFormInit.width = dstW;
sFormInit.height = dstH;
sFormInit.pDisplay= displayLogo;
widgAddForm(psWScreen, &sFormInit);
}
// ////////////////////////////////////////////////////////////////////////////
void addBottomForm(void)
{
WIDGET *parent = widgGetFromID(psWScreen, FRONTEND_BACKDROP);
IntFormAnimated *botForm = new IntFormAnimated(parent);
botForm->id = FRONTEND_BOTFORM;
botForm->setGeometry(FRONTEND_BOTFORMX, FRONTEND_BOTFORMY, FRONTEND_BOTFORMW, FRONTEND_BOTFORMH);
}
// ////////////////////////////////////////////////////////////////////////////
void addText(UDWORD id, UDWORD PosX, UDWORD PosY, const char *txt, UDWORD formID)
{
WIDGET *parent = widgGetFromID(psWScreen, formID);
W_LABEL *label = new W_LABEL(parent);
label->id = id;
label->setGeometry(PosX, PosY, MULTIOP_READY_WIDTH, FRONTEND_BUTHEIGHT);
label->setTextAlignment(WLAB_ALIGNCENTRE);
label->setFont(font_small, WZCOL_TEXT_BRIGHT);
label->setString(txt);
}
// ////////////////////////////////////////////////////////////////////////////
void addSideText(UDWORD id, UDWORD PosX, UDWORD PosY, const char *txt)
{
W_LABINIT sLabInit;
sLabInit.formID = FRONTEND_BACKDROP;
sLabInit.id = id;
sLabInit.x = (short) PosX;
sLabInit.y = (short) PosY;
sLabInit.width = 30;
sLabInit.height = FRONTEND_BOTFORMH;
sLabInit.FontID = font_large;
sLabInit.pDisplay = displayTextAt270;
sLabInit.pText = txt;
widgAddLabel(psWScreen, &sLabInit);
}
// ////////////////////////////////////////////////////////////////////////////
void addTextButton(UDWORD id, UDWORD PosX, UDWORD PosY, const char *txt, unsigned int style)
{
W_BUTINIT sButInit;
sButInit.formID = FRONTEND_BOTFORM;
sButInit.id = id;
sButInit.x = (short)PosX;
sButInit.y = (short)PosY;
// Align
if ( !(style & WBUT_TXTCENTRE) )
{
sButInit.width = (short)(iV_GetTextWidth(txt)+10);
sButInit.x+=35;
}
else
{
sButInit.style |= WBUT_TXTCENTRE;
sButInit.width = FRONTEND_BUTWIDTH;
}
// Enable right clicks
if (style & WBUT_SECONDARY)
{
sButInit.style |= WBUT_SECONDARY;
}
sButInit.UserData = (style & WBUT_DISABLE); // store disable state
sButInit.height = FRONTEND_BUTHEIGHT;
sButInit.pDisplay = displayTextOption;
sButInit.FontID = font_large;
sButInit.pText = txt;
widgAddButton(psWScreen, &sButInit);
// Disable button
if (style & WBUT_DISABLE)
{
widgSetButtonState(psWScreen, id, WBUT_DISABLE);
}
}
void addSmallTextButton(UDWORD id, UDWORD PosX, UDWORD PosY, const char *txt, unsigned int style)
{
W_BUTINIT sButInit;
sButInit.formID = FRONTEND_BOTFORM;
sButInit.id = id;
sButInit.x = (short)PosX;
sButInit.y = (short)PosY;
// Align
if ( !(style & WBUT_TXTCENTRE) )
{
iV_SetFont(font_small);
sButInit.width = (short)(iV_GetTextWidth(txt)+10);
sButInit.x+=35;
}
else
{
sButInit.style |= WBUT_TXTCENTRE;
sButInit.width = FRONTEND_BUTWIDTH;
}
// Enable right clicks
if (style & WBUT_SECONDARY)
{
sButInit.style |= WBUT_SECONDARY;
}
sButInit.UserData = (style & WBUT_DISABLE); // store disable state
sButInit.height = FRONTEND_BUTHEIGHT;
sButInit.pDisplay = displayTextOption;
sButInit.FontID = font_small;
sButInit.pText = txt;
widgAddButton(psWScreen, &sButInit);
// Disable button
if (style & WBUT_DISABLE)
{
widgSetButtonState(psWScreen, id, WBUT_DISABLE);
}
}
// ////////////////////////////////////////////////////////////////////////////
void addFESlider(UDWORD id, UDWORD parent, UDWORD x, UDWORD y, UDWORD stops, UDWORD pos)
{
W_SLDINIT sSldInit;
sSldInit.formID = parent;
sSldInit.id = id;
sSldInit.x = (short)x;
sSldInit.y = (short)y;
sSldInit.width = iV_GetImageWidth(IntImages,IMAGE_SLIDER_BIG);
sSldInit.height = iV_GetImageHeight(IntImages,IMAGE_SLIDER_BIG);
sSldInit.numStops = (UBYTE) stops;
sSldInit.barSize = iV_GetImageHeight(IntImages,IMAGE_SLIDER_BIG);
sSldInit.pos = (UBYTE) pos;
sSldInit.pDisplay = displayBigSlider;
sSldInit.pCallback = intUpdateQuantitySlider;
widgAddSlider(psWScreen, &sSldInit);
}
// ////////////////////////////////////////////////////////////////////////////
// Change Mode
void changeTitleMode(tMode mode)
{
tMode oldMode;
widgDelete(psWScreen, FRONTEND_BACKDROP); // delete backdrop.
oldMode = titleMode; // store old mode
titleMode = mode; // set new mode
switch(mode)
{
case CAMPAIGNS:
startCampaignSelector();
break;
case SINGLE:
startSinglePlayerMenu();
break;
case GAME:
startGameOptionsMenu();
break;
case GRAPHICS_OPTIONS:
startGraphicsOptionsMenu();
break;
case AUDIO_OPTIONS:
startAudioOptionsMenu();
break;
case VIDEO_OPTIONS:
startVideoOptionsMenu();
break;
case MOUSE_OPTIONS:
startMouseOptionsMenu();
break;
case TUTORIAL:
startTutorialMenu();
break;
case OPTIONS:
startOptionsMenu();
break;
case TITLE:
startTitleMenu();
break;
case CREDITS:
startCreditsScreen();
break;
case MULTI:
startMultiPlayerMenu(); // goto multiplayer menu
break;
case PROTOCOL:
startConnectionScreen();
break;
case MULTIOPTION:
if(oldMode == MULTILIMIT)
{
startMultiOptions(true);
}
else
{
startMultiOptions(false);
}
break;
case GAMEFIND:
startGameFind();
break;
case MULTILIMIT:
startLimitScreen();
break;
case KEYMAP:
startKeyMapEditor(true);
break;
case STARTGAME:
case QUIT:
case LOADSAVEGAME:
bLimiterLoaded = false;
case SHOWINTRO:
break;
default:
debug( LOG_FATAL, "Unknown title mode requested" );
abort();
break;
}
return;
}