Torque3D/Templates/BaseGame/game/data/UI/guis/optionsMenu.tscript
marauder2k7 974f217b96 SFX API Changes
DSound has since been deprecated and xaudio2 would require us to write our own 3d spatialization and mixer
Load devices the same way we load in the gfx end
setup sfx provider
run sfx devices on startup
various fixes around sfx null device
added the bitrate and samplerate globals
added the hrtf global code is in to use this but not setup yet
Adds speed of sound to the sound system
SFXAmbience now has a property for speed of sound for different mediums, can also be set directly
2026-04-13 14:55:43 +01:00

1323 lines
42 KiB
Text

$optionsEntryPad = 10;
$OptionsMenuCategories[0] = "Video";
$OptionsMenuCategories[1] = "Audio";
$OptionsMenuCategories[2] = "KBM";
$OptionsMenuCategories[3] = "Controller";
//==============================================================================
//
// OptionsMenu General Functions
//
//==============================================================================
function OptionsMenu::onAdd(%this)
{
if(!isObject(%this.optionsCategories))
{
%this.optionsCategories = new ArrayObject();
}
%this.currentCategory = "";
callOnModules("populateOptionsMenuCategories", "Game");
}
function OptionsMenu::onWake(%this)
{
%this.optsListCount = -1;
$optionsChangeRequiresRestart = false;
%this.populateVideoSettings();
%this.populateAudioSettings();
%this.populateKBMControls();
%this.populateGamepadControls();
//establish the cached prefs values here
%this.openOptionsCategory("Video");
}
if(!isObject( OptionsMenuActionMap ) )
{
new ActionMap(OptionsMenuActionMap){};
OptionsMenuActionMap.bind( keyboard, Escape, tryCloseOptionsMenu);
OptionsMenuActionMap.bind( gamepad, btn_b, tryCloseOptionsMenu);
OptionsMenuActionMap.bind( keyboard, w, OptionMenuNavigatePrev );
OptionsMenuActionMap.bind( keyboard, s, OptionMenuNavigateNext );
OptionsMenuActionMap.bind( gamepad, yaxis, "D", "-0.23 0.23", OptionMenuStickNavigate );
OptionsMenuActionMap.bind( gamepad, upov, OptionMenuNavigatePrev );
OptionsMenuActionMap.bind( gamepad, dpov, OptionMenuNavigateNext );
OptionsMenuActionMap.bind( keyboard, a, OptionMenuPrevSetting );
OptionsMenuActionMap.bind( keyboard, d, OptionMenuNextSetting );
OptionsMenuActionMap.bind( gamepad, xaxis, "D", "-0.23 0.23", OptionMenuStickChangeSetting );
OptionsMenuActionMap.bind( gamepad, lpov, OptionMenuPrevSetting );
OptionsMenuActionMap.bind( gamepad, rpov, OptionMenuNextSetting );
OptionsMenuActionMap.bind( keyboard, q, OptionsMenuPrevCategory );
OptionsMenuActionMap.bind( gamepad, btn_l, OptionsMenuPrevCategory );
OptionsMenuActionMap.bind( keyboard, e, OptionsMenuNextCategory );
OptionsMenuActionMap.bind( gamepad, btn_r, OptionsMenuNextCategory );
OptionsMenuActionMap.bind( keyboard, R, OptionsMenuReset );
OptionsMenuActionMap.bind( gamepad, btn_x, OptionsMenuReset );
OptionsMenuActionMap.bind( keyboard, Space, OptionsMenuActivateOption );
OptionsMenuActionMap.bind( gamepad, btn_a, OptionsMenuActivateOption );
OptionsMenuActionMap.bind( keyboard, Enter, tryApplyOptions);
OptionsMenuActionMap.bind( gamepad, btn_start, tryApplyOptions);
}
//==============================================================================
// This function updates all the elements in the actual lists to ensure they're
// sized, stylized and formatted correctly, as well as up to date values
function OptionsMenuList::syncGui(%this)
{
%this.callOnChildren("setHighlighted", false);
%btn = %this.getObject(%this.listPosition);
if(%btn.class $= "OptionsListEntry" ||
%btn.class $= "OptionsListSliderEntry" ||
%btn.class $= "OptionsKeybindEntry")
%btn-->button.setHighlighted(true);
//iterate over the items and ensure that they are formatted well based on the settings selected
foreach(%option in %this)
{
%container = %option-->valuesContainer;
if(%option.class $= "OptionsListEntry")
{
%hasLevels = %option.optionsObject.getCount() <= 1;
%optionObject = %option.optionsObject;
//If it's out of range of the options, it's probably a custom value
if(%option.currentOptionIndex < %optionObject.getCount() && %option.currentOptionIndex >= 0)
{
%currentOptionLevel = %optionObject.getObject(%option.currentOptionIndex);
%currentOptionLevelTxt = %currentOptionLevel.displayName;
}
else
{
%currentOptionLevelTxt = "Custom";
}
%optionValTextWidth = %option-->optionValue.profile.getStringWidth(%currentOptionLevelTxt);
%option-->optionValue.resize(%container.extent.x - %container-->prevValButton.extent.x - %optionValTextWidth - 20, 0,
%optionValTextWidth + 20, %container.extent.y);
%option-->optionValue.text = %currentOptionLevelTxt;
%container-->prevValButton.position.x = %option-->optionValue.position.x - 20;
%container-->nextValButton.position.x = %container.extent.x - %container-->prevValButton.extent.x;
//if there's no alternatives, disable the left/right buttons
%container-->prevValButton.setHidden(%hasLevels);
%container-->nextValButton.setHidden(%hasLevels);
}
else if(%option.class $= "OptionsListSliderEntry")
{
}
else if(%option.class $= "OptionsKeybindEntry")
{
if(getWordCount(getField(%option.keymap, 1)) == 2)
{
%keymap = getField(%option.keymap, 1);
%modifierImgAsset = getButtonBitmap(%option.device, getWord(%keymap, 0));
if(%modifierImgAsset $= "UI:Keyboard_Black_Blank_image")
%modifierImgAsset = "";
%container-->modifierButton.setBitmap(%modifierImgAsset);
//
%bindImgAsset = getButtonBitmap(%option.device, getWord(%keymap, 1));
if(%bindImgAsset $= "UI:Keyboard_Black_Blank_image")
%bindImgAsset = "";
%container-->bindButton.setBitmap(%bindImgAsset);
}
else
{
%bindImgAsset = getButtonBitmap(%option.device, getField(%option.keymap, 1));
if(%bindImgAsset $= "UI:Keyboard_Black_Blank_image")
%bindImgAsset = "";
%container-->bindButton.setBitmap(%bindImgAsset);
}
}
}
}
function OptionsMenuList::checkForUnappliedChanges(%this)
{
%unappliedChanges = false;
foreach(%option in %this)
{
if(%option.class $= "OptionsListEntry")
{
if(%option.currentOptionIndex >= 0 && %option.currentOptionIndex < %option.optionsObject.getCount())
{
%targetOptionLevel = %option.optionsObject.getObject(%option.currentOptionIndex);
if(!%targetOptionLevel.isCurrent())
%unappliedChanges = true;
if(%unappliedChanges && %option.optionsObject.requiresRestart)
$optionsChangeRequiresRestart = true;
}
}
}
return %unappliedChanges;
}
function OptionsMenuList::applyChanges(%this)
{
foreach(%option in %this)
{
if(%option.class $= "OptionsListEntry")
{
//If it's custom or nonsensical index, there's some kind of external factor going on, so we're
//just going to skip applying it because we don't know what we'd be applying
if(%option.currentOptionIndex >= 0 && %option.currentOptionIndex < %option.optionsObject.getCount())
{
%targetOptionLevel = %option.optionsObject.getObject(%option.currentOptionIndex);
if(!%targetOptionLevel.isCurrent())
%targetOptionLevel.apply();
}
}
}
}
function OptionsMenu::openOptionsCategory(%this, %categoryName)
{
VideoSettingsList.setVisible(%categoryName $= "Video");
AudioSettingsList.setVisible(%categoryName $= "Audio");
KBMControlsList.setVisible(%categoryName $= "KBM");
GamepadControlsList.setVisible(%categoryName $= "Controller");
if(%categoryName $= "Video")
{
$MenuList = VideoSettingsList;
//Find our first non-group entry
while($MenuList.getObject($MenuList.listPosition).class !$= OptionsListEntry && $MenuList.listPosition < $MenuList.getCount())
{
$MenuList.listPosition += 1;
}
%this.currentCatgeoryIdx = 0;
}
else if(%categoryName $= "Audio")
{
$MenuList = AudioSettingsList;
%this.currentCatgeoryIdx = 1;
}
else if(%categoryName $= "KBM")
{
$MenuList = KBMControlsList;
%this.currentCatgeoryIdx = 2;
}
else if(%categoryName $= "Controller")
{
$MenuList = GamepadControlsList;
%this.currentCatgeoryIdx = 3;
}
$MenuList.syncGui();
%this.syncGui();
}
//==============================================================================
// This function updates the non-list items of the menu to be up to date and stylistically
// complaint. This ensures keybind hint buttons are presented correctly based on the current input
// device
function OptionsMenu::syncGui(%this)
{
OptionsMenuCategoryList.callOnChildren("setHighlighted", false);
%btn = OptionsMenuCategoryList.getObject(%this.currentCatgeoryIdx);
%btn.setHighlighted(true);
%buttonPosX = %btn.position.x + OptionsMenuCategoryList.position.x;
OptionsMenuPrevNavIcon.position.x = %buttonPosX - 5;
OptionsMenuNextNavIcon.position.x = %buttonPosX + %btn.extent.x - 35;
//Update the button imagery to comply to the last input device we'd used
%device = Canvas.getLastInputDevice();
if(%device $= "mouse")
%device = "keyboard";
OptionsMenuBackBtn.setBitmap(BaseUIActionMap.getCommandButtonBitmap(%device, "BaseUIBackOut"));
OptionsMenuResetBtn.setBitmap(OptionsMenuActionMap.getCommandButtonBitmap(%device, "OptionsMenuReset"));
OptionsMenuPrevNavIcon.setBitmap(OptionsMenuActionMap.getCommandButtonBitmap(%device, "OptionsMenuPrevCategory"));
OptionsMenuNextNavIcon.setBitmap(OptionsMenuActionMap.getCommandButtonBitmap(%device, "OptionsMenuNextCategory"));
OptionsMenuApplyBtn.setBitmap(OptionsMenuActionMap.getCommandButtonBitmap(%device, "tryApplyOptions"));
OptionsMenuRemapBtn.visible = KBMControlsList.visible || GamepadControlsList.visible;
OptionsMenuRemapBtn.setBitmap(OptionsMenuActionMap.getCommandButtonBitmap(%device, "OptionsMenuActivateOption"));
}
//==============================================================================
// Menu navigation functions
// Primarily used by keybinds
function OptionsMenuPrevCategory(%val)
{
if(%val)
{
%currentIdx = OptionsMenu.currentMenuIdx;
OptionsMenu.currentMenuIdx -= 1;
OptionsMenu.currentMenuIdx = mClamp(OptionsMenu.currentMenuIdx, 0, 3);
if(%currentIdx == OptionsMenu.currentMenuIdx)
return;
%newCategory = $OptionsMenuCategories[OptionsMenu.currentMenuIdx];
OptionsMenu.openOptionsCategory(%newCategory);
}
}
function OptionsMenuNextCategory(%val)
{
if(%val)
{
%currentIdx = OptionsMenu.currentMenuIdx;
OptionsMenu.currentMenuIdx += 1;
OptionsMenu.currentMenuIdx = mClamp(OptionsMenu.currentMenuIdx, 0, 3);
if(%currentIdx == OptionsMenu.currentMenuIdx)
return;
%newCategory = $OptionsMenuCategories[OptionsMenu.currentMenuIdx];
OptionsMenu.openOptionsCategory(%newCategory);
}
}
function OptionMenuNavigatePrev(%val)
{
if(%val)
{
$MenuList.listPosition -= 1;
while( $MenuList.listPosition >= 0 && ($MenuList.getObject($MenuList.listPosition).class !$= "OptionsListEntry" &&
$MenuList.getObject($MenuList.listPosition).class !$= "OptionsListSliderEntry" &&
$MenuList.getObject($MenuList.listPosition).class !$= "OptionsKeybindEntry"))
{
$MenuList.listPosition -= 1;
}
if($MenuList.listPosition < 0)
$MenuList.listPosition = 0;
$MenuList.syncGUI();
$BaseUI::scrollSchedule = schedule($BaseUI::scrollSpeedTimeMs, 0, "OptionMenuNavigatePrev", 1);
}
else
{
cancel($BaseUI::scrollSchedule);
}
}
function OptionMenuNavigateNext(%val)
{
if(%val)
{
$MenuList.listPosition += 1;
while($MenuList.listPosition < $MenuList.getCount() && ($MenuList.getObject($MenuList.listPosition).class !$= "OptionsListEntry" &&
$MenuList.getObject($MenuList.listPosition).class !$= "OptionsListSliderEntry" &&
$MenuList.getObject($MenuList.listPosition).class !$= "OptionsKeybindEntry"))
{
$MenuList.listPosition += 1;
}
if($MenuList.listPosition >= $MenuList.getCount())
$MenuList.listPosition = $MenuList.getCount()-1;
$MenuList.syncGUI();
$BaseUI::scrollSchedule = schedule($BaseUI::scrollSpeedTimeMs, 0, "OptionMenuNavigateNext", 1);
}
else
{
cancel($BaseUI::scrollSchedule);
}
}
function OptionMenuStickNavigate(%val)
{
if(%val == 1)
OptionMenuNavigateNext(1);
else if(%val == -1)
OptionMenuNavigatePrev(1);
else
cancel($BaseUI::scrollSchedule);
}
function OptionMenuPrevSetting(%val)
{
if(!%val)
return;
%option = $MenuList.getObject($MenuList.listPosition);
if(!isObject(%option))
return;
if(%option.class $= "OptionsListEntry")
{
%optionObject = %option.optionsObject;
%currentOptionLevel = %optionObject.getObject(%option.currentOptionIndex);
%option.currentOptionIndex = mClamp(%option.currentOptionIndex-1, 0, %optionObject.getCount()-1);
%newOptionLevel = %optionObject.getObject(%option.currentOptionIndex);
//echo("Changed option: " @ %optionObject.optionName @ " from level: " @ %currentOptionLevel.displayName @ " to level: " @ %newOptionLevel.displayName);
}
else if(%option.class $= "OptionsListSliderEntry")
{
%sliderCtrl = %option-->valuesContainer-->slider;
%minValue = %sliderCtrl.range.x;
%maxValue = %sliderCtrl.range.y;
%ticks = %sliderCtrl.ticks;
%tickIncrementVal = (%maxValue - %minValue) / %ticks;
%sliderCtrl.value -= %tickIncrementVal;
}
$MenuList.syncGUI();
}
function OptionMenuNextSetting(%val)
{
if(!%val)
return;
%option = $MenuList.getObject($MenuList.listPosition);
if(!isObject(%option) )
return;
if(%option.class $= "OptionsListEntry")
{
%optionObject = %option.optionsObject;
%currentOptionLevel = %optionObject.getObject(%option.currentOptionIndex);
%option.currentOptionIndex = mClamp(%option.currentOptionIndex+1, 0, %optionObject.getCount()-1);
%newOptionLevel = %optionObject.getObject(%option.currentOptionIndex);
//echo("Changed option: " @ %optionObject.optionName @ " from level: " @ %currentOptionLevel.displayName @ " to level: " @ %newOptionLevel.displayName);
}
else if(%option.class $= "OptionsListSliderEntry")
{
%sliderCtrl = %option-->valuesContainer-->slider;
%minValue = %sliderCtrl.range.x;
%maxValue = %sliderCtrl.range.y;
%ticks = %sliderCtrl.ticks;
%tickIncrementVal = (%maxValue - %minValue) / %ticks;
%sliderCtrl.value += %tickIncrementVal;
}
$MenuList.syncGUI();
}
function OptionMenuStickChangeSetting(%val)
{
if(%val == 1)
OptionMenuNextSetting(1);
else if(%val == -1)
OptionMenuPrevSetting(1);
}
function OptionsMenuActivateOption(%val)
{
if(!%val)
return;
%option = $MenuList.getObject($MenuList.listPosition);
if(!isObject(%option))
return;
if(%option.class $= "OptionsKeybindEntry")
{
%option-->button.execAltCommand();
}
}
function tryCloseOptionsMenu(%val)
{
if(!%val)
return;
$optionsChangeRequiresRestart = false;
%unappliedVideoChanges = VideoSettingsList.checkForUnappliedChanges();
%unappliedAudioChanges = AudioSettingsList.checkForUnappliedChanges();
//validate audio prefs
if($pref::SFX::masterVolume_tempVar !$= "" && $pref::SFX::masterVolume_tempVar != $pref::SFX::masterVolume)
%unappliedAudioChanges = true;
for(%i=1; %i < $AudioChannelCount; %i++)
{
%tempVolume = getVariable("$pref::SFX::channelVolume" @ %i @ "_tempVar");
if(%tempVolume !$= "" && $pref::SFX::channelVolume[ %i ] != %tempVolume)
%unappliedAudioChanges = true;
}
if(%unappliedVideoChanges || %unappliedAudioChanges)
{
MessageBoxOKCancel("Discard Changes?", "You have unapplied changes to your settings, do you wish to apply or discard them?",
"OptionsMenu.applyChangedOptions(); BaseUIBackOut(1);", "BaseUIBackOut(1);",
"Apply", "Discard");
}
else
{
BaseUIBackOut(1);
}
}
function tryApplyOptions(%val)
{
if(!%val)
return;
$optionsChangeRequiresRestart = false;
%unappliedVideoChanges = VideoSettingsList.checkForUnappliedChanges();
%unappliedAudioChanges = AudioSettingsList.checkForUnappliedChanges();
if(%unappliedVideoChanges || %unappliedAudioChanges)
OptionsMenu.applyChangedOptions();
}
function OptionsMenu::applyChangedOptions(%this)
{
VideoSettingsList.applyChanges();
AudioSettingsList.applyChanges();
KBMControlsList.applyChanges(); //Saves settings and binds from GamepadControlsList as well
//Process the audio channel tempvars to get their values
//and then apply them to the actual pref variable, as well as the SFXChannelVolume
$pref::SFX::masterVolume = $pref::SFX::masterVolume_tempVar;
sfxSetMasterVolume( $pref::SFX::masterVolume );
//0 is always master anyways
for(%i=1; %i < $AudioChannelCount; %i++)
{
%volume = getVariable("$pref::SFX::channelVolume" @ %i @ "_tempVar");
sfxSetChannelVolume( %i, %volume );
$pref::SFX::channelVolume[ %i ] = %volume;
}
//Finally, write our prefs to file
%prefPath = getPrefpath();
export("$pref::*", %prefPath @ "/clientPrefs." @ $TorqueScriptFileExtension, false);
if($optionsChangeRequiresRestart)
MessageBoxOK("Restart Required", "Some of your changes require the game to be restarted.");
}
//==============================================================================
// Option types
function addOptionGroup(%displayName)
{
OptionsMenu.optsListCount++;
%group = new GuiTextCtrl() {
text = %displayName;
position = "0 0";
extent = "500 45";
profile = "MenuHeaderText";
tooltipProfile = "GuiToolTipProfile";
canSave = false;
};
return %group;
}
function optionsMenuButton::onHighlighted(%this, %highlighted)
{
%container = %this.getParent();
%container-->optionName.profile = %highlighted ? MenuSubHeaderTextHighlighted : MenuSubHeaderText;
%container-->optionDescription.profile = %highlighted ? GuiMLTextProfileHighlighted : GuiMLTextProfile;
%valuesContainer = %container-->valuesContainer;
%valuesContainer-->optionValue.profile = %highlighted ? GuiMenuTextProfileHL : GuiMenuTextProfile;
OptionsMenuSettingsScroll.scrollToObject(%container);
}
function addOptionEntry(%optionObj)
{
OptionsMenu.optsListCount++;
if(!isObject(%optionObj) || (%optionObj.class !$= "OptionsSettings" && %optionObj.class !$= "AudioOptionsSettings"))
{
error("addOptionsEntry() - attempting to create a new options entry, but was provided an invalid options object");
return 0;
}
%qualityLevel = getCurrentQualityLevel(%optionObj);
if(isObject(%qualityLevel))
{
%qualityLevelText = %qualityLevel.displayName;
%qualityLevelIndex = %optionObj.getObjectIndex(%qualityLevel);
}
else
{
%qualityLevelText = %qualityLevel;
%qualityLevelIndex = %optionObj.getCount();
}
%optionNameHeight = 20;
if(%optionObj.Description $= "")
%optionNameHeight = 40;
%entry = new GuiContainer() {
position = "0 0";
extent = "800 40";
profile = GuiMenuDefaultProfile;
tooltipProfile = "GuiToolTipProfile";
horizSizing = "width";
vertSizing = "bottom";
class = "OptionsListEntry";
optionsObject = %optionObj;
currentOptionIndex = %qualityLevelIndex;
selectionID = OptionsMenu.optsListCount;
canSave = false;
new GuiButtonCtrl() {
profile = GuiMenuButtonProfile;
position = "0 0";
extent = "800 40";
horizSizing = "width";
vertSizing = "height";
internalName = "button";
class = "optionsMenuButton";
};
new GuiTextCtrl() {
text = %optionObj.OptionName;
position = $optionsEntryPad SPC -1;
extent = 400 SPC %optionNameHeight;
profile = "MenuSubHeaderText";
tooltipProfile = "GuiToolTipProfile";
internalName = "optionName";
};
new GuiTextCtrl() {
text = %optionObj.Description;
position = $optionsEntryPad SPC 17;
extent = "400 18";
profile = "GuiMLTextProfile";
tooltipProfile = "GuiToolTipProfile";
internalName = "optionDescription";
};
new GuiContainer() {
position = "400 0";
extent = "400 40";
profile = GuiModelessDialogProfile;
tooltipProfile = "GuiToolTipProfile";
horizSizing = "left";
vertSizing = "height";
internalName = "valuesContainer";
new GuiButtonCtrl() {
position = "310 0";
extent = "20 40";
text = "<";
profile = GuiMenuButtonProfile;
internalName = "prevValButton";
command = "$MenuList.listPosition = $thisControl.getParent().getParent().selectionID; OptionMenuPrevSetting(1);";
};
new GuiTextCtrl() {
text = %qualityLevelText;
position = "330 0";
extent = "50 40";
profile = "GuiMenuTextProfile";
tooltipProfile = "GuiToolTipProfile";
horizSizing = "right";
vertSizing = "center";
internalName = "optionValue";
};
new GuiButtonCtrl() {
position = "380 0";
extent = "20 40";
text = ">";
profile = GuiMenuButtonProfile;
internalName = "nextValButton";
command = "$MenuList.listPosition = $thisControl.getParent().getParent().selectionID; OptionMenuNextSetting(1);";
};
};
};
return %entry;
}
function addOptionSlider(%optionName, %optionDesc, %prefName, %sliderMin, %sliderMax, %sliderTicks)
{
OptionsMenu.optsListCount++;
%currentVal = getVariable(%prefName);
%tempVarName = %prefName @ "_tempVar";
if(%currentVal $= "")
%currentVal = %sliderMin;
setVariable(%tempVarName, %currentVal);
%optionNameHeight = 20;
if(%optionDesc $= "")
%optionNameHeight = 40;
%entry = new GuiContainer() {
position = "0 0";
extent = "800 40";
profile = GuiMenuDefaultProfile;
tooltipProfile = "GuiToolTipProfile";
horizSizing = "width";
vertSizing = "bottom";
class = "OptionsListSliderEntry";
canSave = false;
new GuiButtonCtrl() {
profile = GuiMenuButtonProfile;
position = "0 0";
extent = "800 40";
horizSizing = "width";
vertSizing = "height";
internalName = "button";
class = "optionsMenuButton";
};
new GuiTextCtrl() {
text = %optionName;
position = $optionsEntryPad SPC -1;
extent = 400 SPC %optionNameHeight;
profile = "MenuSubHeaderText";
tooltipProfile = "GuiToolTipProfile";
internalName = "optionName";
};
new GuiTextCtrl() {
text = %optionDesc;
position = $optionsEntryPad SPC 17;
extent = "400 18";
profile = "GuiMLTextProfile";
tooltipProfile = "GuiToolTipProfile";
internalName = "optionDescription";
};
new GuiContainer() {
position = "400 0";
extent = "400 40";
profile = GuiModelessDialogProfile;
tooltipProfile = "GuiToolTipProfile";
horizSizing = "left";
vertSizing = "height";
internalName = "valuesContainer";
new GuiSliderCtrl() {
range = %sliderMin SPC %sliderMax;
ticks = %sliderTicks;
snap = "1";
value = %currentVal;
variable = %tempVarName;
useFillBar = "1";
fillBarColor = $TextMediumEmphasisColor;
renderTicks = "0";
position = "0 10";
extent = "400 20";
minExtent = "8 2";
horizSizing = "right";
vertSizing = "center";
profile = GuiMenuButtonProfile;
visible = "1";
active = "1";
command = "$thisControl.updateSliderValue();";
tooltipProfile = "GuiToolTipProfile";
hovertime = "1000";
isContainer = "0";
canSave = "1";
canSaveDynamicFields = "0";
class = "OptionsSliderEntrySlider";
internalName = "slider";
};
};
};
return %entry;
}
function OptionsSliderEntrySlider::updateSliderValue(%this)
{
//update settings value here
}
//==============================================================================
//
// Video List Functions
//
//==============================================================================
//==============================================================================
// This function utilizes the VideoSettingsGroup SimGroup to populate options.
// The object is defined in core/rendering/scripts/graphicsOptions.tscript
// A majority of the options are statically defined, but some are dynamically populated
// on refresh, like the display device or available resolution options.
// Once populated, we loop over the simgroup structure to populate our option entry
// rows in the options menu itself.
function OptionsMenu::populateVideoSettings(%this)
{
VideoSettingsList.clear();
VideoSettingsGroup::populateDisplaySettings();
for(%i=0; %i < VideoSettingsGroup.getCount(); %i++)
{
%setting = VideoSettingsGroup.getObject(%i);
if(%setting.class $= "SubOptionsGroup")
{
%entry = addOptionGroup(%setting.displayName);
if(isObject(%entry))
VideoSettingsList.add(%entry);
for(%s=0; %s < %setting.getCount(); %s++)
{
%option = %setting.getObject(%s);
%optionsEntry = addOptionEntry(%option);
if(isObject(%optionsEntry))
VideoSettingsList.add(%optionsEntry);
}
}
else if(%setting.class $= "OptionsSettings")
{
%optionsEntry = addOptionEntry(%setting);
if(isObject(%optionsEntry))
VideoSettingsList.add(%optionsEntry);
}
}
//Ensure our newly templated options listings are sized right
for(%i=0; %i < VideoSettingsList.getCount(); %i++)
{
%entry = VideoSettingsList.getObject(%i);
%entry.resize(0, 0, VideoSettingsList.extent.x - 15, %entry.extent.y); //-10 for the scroll wheel pad
}
}
function OptionsMenu::resetSettings(%this)
{
MessageBoxOKCancel("", "This will set the graphical settings back to the auto-detected defaults. Do you wish to continue?", "AutodetectGraphics();", "");
}
//==============================================================================
//
// Audio List Functions
//
//==============================================================================
//==============================================================================
// This function utilizes the AudioSettingsGroup SimGroup to populate options.
// The object is defined in core/sfx/scripts/audioOptions.tscript
// Similar to the video options, it can be a mix of static and dynamically populated
// option entries, which we then iterate over and populate the entry rows for the menu
function OptionsMenu::populateAudioSettings(%this)
{
AudioSettingsList.clear();
AudioSettingsGroup.populateSettings();
//Process the lists
for(%i=0; %i < AudioSettingsGroup.getCount(); %i++)
{
%setting = AudioSettingsGroup.getObject(%i);
if(%setting.class $= "SubOptionsGroup")
{
%entry = addOptionGroup(%setting.displayName);
if(isObject(%entry))
AudioSettingsList.add(%entry);
for(%s=0; %s < %setting.getCount(); %s++)
{
%option = %setting.getObject(%s);
%optionsEntry = addOptionEntry(%option);
if(isObject(%optionsEntry))
AudioSettingsList.add(%optionsEntry);
}
}
else if(%setting.class $= "AudioOptionsSettings")
{
%optionsEntry = addOptionEntry(%setting);
if(isObject(%optionsEntry))
AudioSettingsList.add(%optionsEntry);
}
}
AudioSettingsList.add(addOptionGroup("Channel Volume"));
//Now we'll populate the sliders for the audio channels.
//The defaults of these are defined in core/sfx/scripts/audio.tscript
//These define the MasterVolume channel, as well as several other common defualt ones
//Because it's a variable list, this can be expanded by modules by just upping $AudioChannelCount
//and then defining the $AudioChannelName[x] with the displayed name and
//and the $AudioChannels[x] variable with the SFXSource object defined to it for the given channel
AudioSettingsList.add(addOptionSlider("Master Volume", "", "$pref::SFX::masterVolume", 0, 1, 10));
//We init to 1, because 0 is the reserved for the masterVolume in practice
for(%i=1; %i < $AudioChannelCount; %i++)
{
AudioSettingsList.add(addOptionSlider($AudioChannelsName[%i] @ " Volume", "", "$pref::SFX::channelVolume" @ %i, 0, 1, 10));
}
//Ensure our newly templated options listings are sized right
for(%i=0; %i < AudioSettingsList.getCount(); %i++)
{
%entry = AudioSettingsList.getObject(%i);
%entry.resize(0, 0, AudioSettingsList.extent.x - 15, %entry.extent.y); //-10 for the scroll wheel pad
}
}
//==============================================================================
//
// Keyboard & Mouse, Controller List Functions
//
//==============================================================================
function KBMControlsList::applyChanges(%this){
//Save mouse sensitivity
$pref::Input::LinkMouseSensitivity = $pref::Input::LinkMouseSensitivity_tempVar;
if(!$RemapDirty)
return;
%prefPath = getPrefpath();
%filePath = (%prefPath @ "/keybinds." @ $TorqueScriptFileExtension);
%fileWrite = new fileObject(){};
// Delete the file first if it exists
if (isFile(%filePath))
fileDelete( %filepath );
// Open / create the custom binds file
%fileWrite.openForWrite(%filePath);
// Iterate through the remapabble bindings and write them to the keyBinds file
for(%i = 0; %i < $RemapCount; %i++){
%actionMap = $RemapActionMap[%i];
%cmd = $RemapCmd[%i];
%binding = %actionMap.getBinding(%cmd);
%device = getField(%binding, 0);
%action = getField(%binding, 1);
// saves a restoreRemap call to each line of keyBinds file instead of the bind command in order to leverage functions for
// removing conflicts and duplicates
if (%device !$= "" && %action !$= ""){
%line = "restoreRemap(" @ %device @ ", " @ %actionMap @ ", \"" @ %action @ "\", \"" @ %cmd @ "\");";
%fileWrite.writeLine(%line);
}
else
continue;
}
%fileWrite.close();
%fileWrite.delete();
$RemapDirty = false;
}
// restoreRemap() is called from user custom keybinds file which is generated by KBMControlsList::applyChanges()
function restoreRemap(%device, %actionMap, %action, %cmd){
// Make sure no other "action" (key / button press) is bound to this command on this actionMap (from remapDlg.tscript)
unbindExtraActions( %cmd, %actionMap, %device, 0 );
unbindExtraActions( %cmd, %actionMap, %device, 1 );
%actionMap.bind( %device, %action, %cmd );
}
function OptionsMenu::populateKBMControls(%this){
%this.populateKeybinds("keyboard", KBMControlsList); // includes remappable actions declared with "mouse" as the device as well
%this.syncGui();
KBMControlsList.syncGui();
}
function OptionsMenu::populateGamepadControls(%this){
%this.populateKeybinds("gamepad", GamepadControlsList);
%this.syncGui();
GamepadControlsList.syncGui();
}
function OptionsMenu::populateKeybinds(%this,%device, %controlsList) {
%controlsList.clear();
if (%device $= "keyboard") {
%controlsList.add(addOptionGroup("Mouse Options"));
%controlsList.add(addOptionSlider("Mouse Sensitivity", "", "$pref::Input::LinkMouseSensitivity", 0, 1, 10));
}
//build out our list of action maps
%actionMapCount = ActionMapGroup.getCount();
%actionMapList = "";
for(%i=0; %i < %actionMapCount; %i++)
{
%actionMap = ActionMapGroup.getObject(%i);
if(%actionMap == GlobalActionMap.getId())
continue;
%actionMapName = %actionMap.humanReadableName $= "" ? %actionMap.getName() : %actionMap.humanReadableName;
//see if we have any actual listed remappable keys for this movemap. if so, drop it from the listing
%hasRemaps = false;
for ( %r = 0; %r < $RemapCount; %r++ )
{
%testMapName = $RemapActionMap[%r].humanReadableName $= "" ? $RemapActionMap[%r].getName() : $RemapActionMap[%r].humanReadableName;
if(%actionMapName $= %testMapName)
{
//got a match to at least one, so we're ok to continue
%hasRemaps = true;
break;
}
}
if(!%hasRemaps)
continue;
if(%actionMapList $= "")
%actionMapList = %actionMapName;
else
%actionMapList = %actionMapList TAB %actionMapName;
}
//If we didn't find any valid actionMaps, then just exit out
if(%actionMapList $= "")
return;
if($activeRemapControlSet $= "")
$activeRemapControlSet = getField(%actionMapList, 0);
//echo("============================================");
for(%am = 0; %am < getFieldCount(%actionMapList); %am++)
{
%currentActionMap = getField(%actionMapList, %am);
//only add the group if we've got more than one group, otherwise it's obviously
//part of the single grouping
if(getFieldCount(%actionMapList) > 1)
{
%actionMapGroupEntry = addOptionGroup(%currentActionMap);
%controlsList.add(%actionMapGroupEntry);
}
for ( %i = 0; %i < $RemapCount; %i++ )
{
//If there was no match go to the next remappable action
if(%device $= "" || %device !$= $RemapDevice[%i])
continue;
%actionMapName = $RemapActionMap[%i].humanReadableName $= "" ? $RemapActionMap[%i].getName() : $RemapActionMap[%i].humanReadableName;
if(%currentActionMap !$= %actionMapName)
continue;
%keyMap = buildFullMapString( %i, $RemapActionMap[%i], %device );
%description = $RemapDescription[%i];
//echo("Added ActionMap Entry: " @ %actionMapName @ " | " @ %device @ " | " @ %keymap @ " | " @ %description);
%remapEntry = addActionMapEntry(%actionMapName, %device, %keyMap, %i, %description);
%controlsList.add(%remapEntry);
}
}
//Ensure our newly templated options listings are sized right
for(%i=0; %i < %controlsList.getCount(); %i++)
{
%entry = %controlsList.getObject(%i);
%entry.resize(0, 0, %controlsList.extent.x - 15, %entry.extent.y); //-10 for the scroll wheel pad
}
}
function buildFullMapString( %index, %actionMap, %deviceType )
{
%name = $RemapName[%index];
%cmd = $RemapCmd[%index];
%temp = %actionMap.getBinding( %cmd );
if ( %temp $= "" )
return %name TAB "";
%mapString = "";
%count = getFieldCount( %temp );
for ( %i = 0; %i < %count; %i += 2 )
{
if ( %mapString !$= "" )
continue;
//%mapString = %mapString @ ", ";
%device = getField( %temp, %i + 0 );
%object = getField( %temp, %i + 1 );
if (startsWith(%device,"mouse"))
%deviceType = "mouse";
if(%deviceType !$= "" && !startsWith(%device, %deviceType))
continue;
%mapString = %mapString @ getMapDisplayName( %device, %object );
}
return %name TAB %mapString;
}
// Also used by remapDlg.tscript
function getMapDisplayName( %device, %action )
{
if ( %device $= "keyboard" )
return( %action );
else if ( strstr( %device, "mouse" ) != -1 )
{
// Substitute "mouse" for "button" in the action string:
%pos = strstr( %action, "button" );
if ( %pos != -1 )
{
%mods = getSubStr( %action, 0, %pos );
%object = getSubStr( %action, %pos, 1000 );
%instance = getSubStr( %object, strlen( "button" ), 1000 );
return( %mods @ "mouse" @ ( %instance + 1 ) );
}
else
error( "Mouse input object other than button passed to getDisplayMapName!" );
}
else if ( strstr( %device, "joystick" ) != -1 )
{
// Substitute "joystick" for "button" in the action string:
%pos = strstr( %action, "button" );
if ( %pos != -1 )
{
%mods = getSubStr( %action, 0, %pos );
%object = getSubStr( %action, %pos, 1000 );
%instance = getSubStr( %object, strlen( "button" ), 1000 );
return( %mods @ "joystick" @ ( %instance + 1 ) );
}
else
{
%pos = strstr( %action, "pov" );
if ( %pos != -1 )
{
%wordCount = getWordCount( %action );
%mods = %wordCount > 1 ? getWords( %action, 0, %wordCount - 2 ) @ " " : "";
%object = getWord( %action, %wordCount - 1 );
switch$ ( %object )
{
case "upov": %object = "POV1 up";
case "dpov": %object = "POV1 down";
case "lpov": %object = "POV1 left";
case "rpov": %object = "POV1 right";
case "upov2": %object = "POV2 up";
case "dpov2": %object = "POV2 down";
case "lpov2": %object = "POV2 left";
case "rpov2": %object = "POV2 right";
default: %object = "";
}
return( %mods @ %object );
}
else
error( "Unsupported Joystick input object passed to getDisplayMapName!" );
}
}
else if ( strstr( %device, "gamepad" ) != -1 )
{
return %action;
%pos = strstr( %action, "button" );
if ( %pos != -1 )
{
%mods = getSubStr( %action, 0, %pos );
%object = getSubStr( %action, %pos, 1000 );
%instance = getSubStr( %object, strlen( "button" ), 1000 );
return( %mods @ "joystick" @ ( %instance + 1 ) );
}
else
{
%pos = strstr( %action, "thumb" );
if ( %pos != -1 )
{
//%instance = getSubStr( %action, strlen( "thumb" ), 1000 );
//return( "thumb" @ ( %instance + 1 ) );
return %action;
}
else
error( "Unsupported gamepad input object passed to getDisplayMapName!" );
}
}
return( "" );
}
function addActionMapEntry(%actionMap, %device, %keyMap, %index, %description)
{
%entry = new GuiContainer() {
position = "0 0";
extent = "800 40";
profile = GuiMenuDefaultProfile;
tooltipProfile = "GuiToolTipProfile";
horizSizing = "width";
vertSizing = "bottom";
class = "OptionsKeybindEntry";
actionMap = %actionMap;
device = %device;
keymap = %keyMap;
remapIndex = %index;
canSave = false;
new GuiButtonCtrl() {
profile = GuiMenuButtonProfile;
position = "0 0";
extent = "800 40";
horizSizing = "width";
vertSizing = "height";
internalName = "button";
class = "OptionsMenuActionMapButton";
altCommand = "doKeyRemap($thisControl.getParent());";
};
new GuiTextCtrl() {
text = getField(%keyMap, 0);
position = $optionsEntryPad SPC -1;
extent = "400 40";
profile = "MenuSubHeaderText";
tooltipProfile = "GuiToolTipProfile";
internalName = "actionName";
};
new GuiContainer() {
position = "400 3";
extent = "400 34";
profile = GuiModelessDialogProfile;
tooltipProfile = "GuiToolTipProfile";
horizSizing = "left";
vertSizing = "height";
internalName = "valuesContainer";
};
};
%buttonContainer = %entry.findObjectByInternalName("valuesContainer");
//echo("Keymap: " @ %keymap @ " | Keymap word count: " @ getWordCount(getField(%keyMap, 1)));
if(getWordCount(getField(%keyMap, 1)) == 2)
{
%modifierBtn = new GuiIconButtonCtrl() {
position = 156 SPC -10;
extent = "98 45";
BitmapAsset = "";
profile = GuiRemapActionMapButtonProfile;
sizeIconToButton = true;
makeIconSquare = true;
iconLocation = "center";
internalName = "modifierButton";
active = false;
};
%combinerText = new GuiTextCtrl(){
position = 264 SPC -5;
extent = "20 45";
profile = MenuSubHeaderText;
text = " + ";
};
%bindButton = new GuiIconButtonCtrl() {
position = "300 -10";
extent = "98 45";
BitmapAsset = "";
profile = GuiRemapActionMapButtonProfile;
sizeIconToButton = true;
makeIconSquare = true;
iconLocation = "center";
internalName = "bindButton";
active = false;
};
%buttonContainer.add(%modifierBtn);
%buttonContainer.add(%combinerText);
%buttonContainer.add(%bindButton);
}
else
{
%bindButton = new GuiIconButtonCtrl() {
position = "300 -10";
extent = "98 45";
BitmapAsset = "";
profile = GuiRemapActionMapButtonProfile;
sizeIconToButton = true;
makeIconSquare = true;
iconLocation = "center";
internalName = "bindButton";
active = false;
};
%buttonContainer.add(%bindButton);
}
return %entry;
}
function OptionsMenuActionMapButton::onHighlighted(%this, %highlighted)
{
%container = %this.getParent();
%container-->actionName.profile = %highlighted ? MenuSubHeaderTextHighlighted : MenuSubHeaderText;
OptionsMenuSettingsScroll.scrollToObject(%container);
}
function doKeyRemap( %optionEntry )
{
%name = getField(%optionEntry.keymap,0);
RemapDlg-->OptRemapText.text = "Re-bind \"" @ %name @ "\" to..." ;
OptRemapInputCtrl.index = %optionEntry.remapIndex;
$remapListDevice = %optionEntry.device;
Canvas.pushDialog( RemapDlg );
}