optionsMenu.tscript 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135
  1. $reportKeymapping = false;
  2. $optionsEntryPad = 10;
  3. $OptionsMenuCategories[0] = "Video";
  4. $OptionsMenuCategories[1] = "Audio";
  5. $OptionsMenuCategories[2] = "KBM";
  6. $OptionsMenuCategories[3] = "Controller";
  7. function OptionsMenu::onAdd(%this)
  8. {
  9. if(!isObject(%this.optionsCategories))
  10. {
  11. %this.optionsCategories = new ArrayObject();
  12. }
  13. %this.currentCategory = "";
  14. callOnModules("populateOptionsMenuCategories", "Game");
  15. }
  16. function OptionsMenu::onWake(%this)
  17. {
  18. %this.optsListCount = -1;
  19. $optionsChangeRequiresRestart = false;
  20. %this.populateVideoSettings();
  21. %this.populateAudioSettings();
  22. %this.populateKBMControls();
  23. %this.populateGamepadControls();
  24. //establish the cached prefs values here
  25. %this.openOptionsCategory("Video");
  26. }
  27. if(!isObject( OptionsMenuActionMap ) )
  28. {
  29. new ActionMap(OptionsMenuActionMap){};
  30. OptionsMenuActionMap.bind( keyboard, Escape, tryCloseOptionsMenu);
  31. OptionsMenuActionMap.bind( gamepad, btn_b, tryCloseOptionsMenu);
  32. OptionsMenuActionMap.bind( keyboard, w, OptionMenuNavigatePrev );
  33. OptionsMenuActionMap.bind( keyboard, s, OptionMenuNavigateNext );
  34. OptionsMenuActionMap.bind( gamepad, yaxis, "D", "-0.23 0.23", OptionMenuStickNavigate );
  35. OptionsMenuActionMap.bind( gamepad, upov, OptionMenuNavigatePrev );
  36. OptionsMenuActionMap.bind( gamepad, dpov, OptionMenuNavigateNext );
  37. OptionsMenuActionMap.bind( keyboard, a, OptionMenuPrevSetting );
  38. OptionsMenuActionMap.bind( keyboard, d, OptionMenuNextSetting );
  39. OptionsMenuActionMap.bind( gamepad, xaxis, "D", "-0.23 0.23", OptionMenuStickChangeSetting );
  40. OptionsMenuActionMap.bind( gamepad, lpov, OptionMenuPrevSetting );
  41. OptionsMenuActionMap.bind( gamepad, rpov, OptionMenuNextSetting );
  42. OptionsMenuActionMap.bind( keyboard, q, OptionsMenuPrevCategory );
  43. OptionsMenuActionMap.bind( gamepad, btn_l, OptionsMenuPrevCategory );
  44. OptionsMenuActionMap.bind( keyboard, e, OptionsMenuNextCategory );
  45. OptionsMenuActionMap.bind( gamepad, btn_r, OptionsMenuNextCategory );
  46. OptionsMenuActionMap.bind( keyboard, R, OptionsMenuReset );
  47. OptionsMenuActionMap.bind( gamepad, btn_x, OptionsMenuReset );
  48. OptionsMenuActionMap.bind( keyboard, Space, OptionsMenuActivateOption );
  49. OptionsMenuActionMap.bind( gamepad, btn_a, OptionsMenuActivateOption );
  50. OptionsMenuActionMap.bind( keyboard, Enter, tryApplyOptions);
  51. OptionsMenuActionMap.bind( gamepad, btn_start, tryApplyOptions);
  52. }
  53. //==============================================================================
  54. // This function updates all the elements in the actual lists to ensure they're
  55. // sized, stylized and formatted correctly, as well as up to date values
  56. function OptionsMenuList::syncGui(%this)
  57. {
  58. %this.callOnChildren("setHighlighted", false);
  59. %btn = %this.getObject(%this.listPosition);
  60. if(%btn.class $= "OptionsListEntry" ||
  61. %btn.class $= "OptionsListSliderEntry" ||
  62. %btn.class $= "OptionsKeybindEntry")
  63. %btn-->button.setHighlighted(true);
  64. //iterate over the items and ensure that they are formatted well based on the settings selected
  65. foreach(%option in %this)
  66. {
  67. %container = %option-->valuesContainer;
  68. if(%option.class $= "OptionsListEntry")
  69. {
  70. %hasLevels = %option.optionsObject.getCount() <= 1;
  71. %optionObject = %option.optionsObject;
  72. //If it's out of range of the options, it's probably a custom value
  73. if(%option.currentOptionIndex < %optionObject.getCount() && %option.currentOptionIndex >= 0)
  74. {
  75. %currentOptionLevel = %optionObject.getObject(%option.currentOptionIndex);
  76. %currentOptionLevelTxt = %currentOptionLevel.displayName;
  77. }
  78. else
  79. {
  80. %currentOptionLevelTxt = "Custom";
  81. }
  82. %optionValTextWidth = %option-->optionValue.profile.getStringWidth(%currentOptionLevelTxt);
  83. %option-->optionValue.resize(%container.extent.x - %container-->prevValButton.extent.x - %optionValTextWidth - 20, 0,
  84. %optionValTextWidth + 20, %container.extent.y);
  85. %option-->optionValue.text = %currentOptionLevelTxt;
  86. %container-->prevValButton.position.x = %option-->optionValue.position.x - 20;
  87. %container-->nextValButton.position.x = %container.extent.x - %container-->prevValButton.extent.x;
  88. //if there's no alternatives, disable the left/right buttons
  89. %container-->prevValButton.setHidden(%hasLevels);
  90. %container-->nextValButton.setHidden(%hasLevels);
  91. }
  92. else if(%option.class $= "OptionsListSliderEntry")
  93. {
  94. }
  95. else if(%option.class $= "OptionsKeybindEntry")
  96. {
  97. if(getWordCount(getField(%option.keymap, 1)) == 2)
  98. {
  99. %keymap = getField(%option.keymap, 1);
  100. %modifierImgAsset = getButtonBitmap(%option.device, getWord(%keymap, 0));
  101. if(%modifierImgAsset $= "UI:Keyboard_Black_Blank_image")
  102. %modifierImgAsset = "";
  103. %container-->modifierButton.setBitmap(%modifierImgAsset);
  104. //
  105. %bindImgAsset = getButtonBitmap(%option.device, getWord(%keymap, 1));
  106. if(%bindImgAsset $= "UI:Keyboard_Black_Blank_image")
  107. %bindImgAsset = "";
  108. %container-->bindButton.setBitmap(%bindImgAsset);
  109. }
  110. else
  111. {
  112. %bindImgAsset = getButtonBitmap(%option.device, getField(%option.keymap, 1));
  113. if(%bindImgAsset $= "UI:Keyboard_Black_Blank_image")
  114. %bindImgAsset = "";
  115. %container-->bindButton.setBitmap(%bindImgAsset);
  116. }
  117. }
  118. }
  119. }
  120. function OptionsMenuList::checkForUnappliedChanges(%this)
  121. {
  122. %unappliedChanges = false;
  123. foreach(%option in %this)
  124. {
  125. if(%option.class $= "OptionsListEntry")
  126. {
  127. if(%option.currentOptionIndex >= 0 && %option.currentOptionIndex < %option.optionsObject.getCount())
  128. {
  129. %targetOptionLevel = %option.optionsObject.getObject(%option.currentOptionIndex);
  130. if(!%targetOptionLevel.isCurrent())
  131. %unappliedChanges = true;
  132. if(%unappliedChanges && %option.optionsObject.requiresRestart)
  133. $optionsChangeRequiresRestart = true;
  134. }
  135. }
  136. }
  137. return %unappliedChanges;
  138. }
  139. function OptionsMenuList::applyChanges(%this)
  140. {
  141. foreach(%option in %this)
  142. {
  143. if(%option.class $= "OptionsListEntry")
  144. {
  145. //If it's custom or nonsensical index, there's some kind of external factor going on, so we're
  146. //just going to skip applying it because we don't know what we'd be applying
  147. if(%option.currentOptionIndex >= 0 && %option.currentOptionIndex < %option.optionsObject.getCount())
  148. {
  149. %targetOptionLevel = %option.optionsObject.getObject(%option.currentOptionIndex);
  150. if(!%targetOptionLevel.isCurrent())
  151. %targetOptionLevel.apply();
  152. }
  153. }
  154. }
  155. }
  156. function OptionsMenu::openOptionsCategory(%this, %categoryName)
  157. {
  158. VideoSettingsList.setVisible(%categoryName $= "Video");
  159. AudioSettingsList.setVisible(%categoryName $= "Audio");
  160. KBMControlsList.setVisible(%categoryName $= "KBM");
  161. GamepadControlsList.setVisible(%categoryName $= "Controller");
  162. if(%categoryName $= "Video")
  163. {
  164. $MenuList = VideoSettingsList;
  165. //Find our first non-group entry
  166. while($MenuList.getObject($MenuList.listPosition).class !$= OptionsListEntry && $MenuList.listPosition < $MenuList.getCount())
  167. {
  168. $MenuList.listPosition += 1;
  169. }
  170. %this.currentCatgeoryIdx = 0;
  171. }
  172. else if(%categoryName $= "Audio")
  173. {
  174. $MenuList = AudioSettingsList;
  175. %this.currentCatgeoryIdx = 1;
  176. }
  177. else if(%categoryName $= "KBM")
  178. {
  179. $MenuList = KBMControlsList;
  180. %this.currentCatgeoryIdx = 2;
  181. }
  182. else if(%categoryName $= "Controller")
  183. {
  184. $MenuList = GamepadControlsList;
  185. %this.currentCatgeoryIdx = 3;
  186. }
  187. $MenuList.syncGui();
  188. %this.syncGui();
  189. }
  190. //==============================================================================
  191. // This function updates the non-list items of the menu to be up to date and stylistically
  192. // complaint. This ensures keybind hint buttons are presented correctly based on the current input
  193. // device
  194. function OptionsMenu::syncGui(%this)
  195. {
  196. OptionsMenuCategoryList.callOnChildren("setHighlighted", false);
  197. %btn = OptionsMenuCategoryList.getObject(%this.currentCatgeoryIdx);
  198. %btn.setHighlighted(true);
  199. %buttonPosX = %btn.position.x + OptionsMenuCategoryList.position.x;
  200. OptionsMenuPrevNavIcon.position.x = %buttonPosX - 5;
  201. OptionsMenuNextNavIcon.position.x = %buttonPosX + %btn.extent.x - 35;
  202. //Update the button imagery to comply to the last input device we'd used
  203. %device = Canvas.getLastInputDevice();
  204. if(%device $= "mouse")
  205. %device = "keyboard";
  206. OptionsMenuBackBtn.setBitmap(BaseUIActionMap.getCommandButtonBitmap(%device, "BaseUIBackOut"));
  207. OptionsMenuResetBtn.setBitmap(OptionsMenuActionMap.getCommandButtonBitmap(%device, "OptionsMenuReset"));
  208. OptionsMenuPrevNavIcon.setBitmap(OptionsMenuActionMap.getCommandButtonBitmap(%device, "OptionsMenuPrevCategory"));
  209. OptionsMenuNextNavIcon.setBitmap(OptionsMenuActionMap.getCommandButtonBitmap(%device, "OptionsMenuNextCategory"));
  210. OptionsMenuApplyBtn.setBitmap(OptionsMenuActionMap.getCommandButtonBitmap(%device, "tryApplyOptions"));
  211. OptionsMenuRemapBtn.visible = KBMControlsList.visible || GamepadControlsList.visible;
  212. OptionsMenuRemapBtn.setBitmap(OptionsMenuActionMap.getCommandButtonBitmap(%device, "OptionsMenuActivateOption"));
  213. }
  214. //==============================================================================
  215. // Menu navigation functions
  216. // Primarily used by keybinds
  217. function OptionsMenuPrevCategory(%val)
  218. {
  219. if(%val)
  220. {
  221. %currentIdx = OptionsMenu.currentMenuIdx;
  222. OptionsMenu.currentMenuIdx -= 1;
  223. OptionsMenu.currentMenuIdx = mClamp(OptionsMenu.currentMenuIdx, 0, 3);
  224. if(%currentIdx == OptionsMenu.currentMenuIdx)
  225. return;
  226. %newCategory = $OptionsMenuCategories[OptionsMenu.currentMenuIdx];
  227. OptionsMenu.openOptionsCategory(%newCategory);
  228. }
  229. }
  230. function OptionsMenuNextCategory(%val)
  231. {
  232. if(%val)
  233. {
  234. %currentIdx = OptionsMenu.currentMenuIdx;
  235. OptionsMenu.currentMenuIdx += 1;
  236. OptionsMenu.currentMenuIdx = mClamp(OptionsMenu.currentMenuIdx, 0, 3);
  237. if(%currentIdx == OptionsMenu.currentMenuIdx)
  238. return;
  239. %newCategory = $OptionsMenuCategories[OptionsMenu.currentMenuIdx];
  240. OptionsMenu.openOptionsCategory(%newCategory);
  241. }
  242. }
  243. function OptionMenuNavigatePrev(%val)
  244. {
  245. if(%val)
  246. {
  247. $MenuList.listPosition -= 1;
  248. while( $MenuList.listPosition >= 0 && ($MenuList.getObject($MenuList.listPosition).class !$= "OptionsListEntry" &&
  249. $MenuList.getObject($MenuList.listPosition).class !$= "OptionsListSliderEntry" &&
  250. $MenuList.getObject($MenuList.listPosition).class !$= "OptionsKeybindEntry"))
  251. {
  252. $MenuList.listPosition -= 1;
  253. }
  254. if($MenuList.listPosition < 0)
  255. $MenuList.listPosition = 0;
  256. $MenuList.syncGUI();
  257. $BaseUI::scrollSchedule = schedule($BaseUI::scrollSpeedTimeMs, 0, "OptionMenuNavigatePrev", 1);
  258. }
  259. else
  260. {
  261. cancel($BaseUI::scrollSchedule);
  262. }
  263. }
  264. function OptionMenuNavigateNext(%val)
  265. {
  266. if(%val)
  267. {
  268. $MenuList.listPosition += 1;
  269. while($MenuList.listPosition < $MenuList.getCount() && ($MenuList.getObject($MenuList.listPosition).class !$= "OptionsListEntry" &&
  270. $MenuList.getObject($MenuList.listPosition).class !$= "OptionsListSliderEntry" &&
  271. $MenuList.getObject($MenuList.listPosition).class !$= "OptionsKeybindEntry"))
  272. {
  273. $MenuList.listPosition += 1;
  274. }
  275. if($MenuList.listPosition >= $MenuList.getCount())
  276. $MenuList.listPosition = $MenuList.getCount()-1;
  277. $MenuList.syncGUI();
  278. $BaseUI::scrollSchedule = schedule($BaseUI::scrollSpeedTimeMs, 0, "OptionMenuNavigateNext", 1);
  279. }
  280. else
  281. {
  282. cancel($BaseUI::scrollSchedule);
  283. }
  284. }
  285. function OptionMenuStickNavigate(%val)
  286. {
  287. if(%val == 1)
  288. OptionMenuNavigateNext(1);
  289. else if(%val == -1)
  290. OptionMenuNavigatePrev(1);
  291. else
  292. cancel($BaseUI::scrollSchedule);
  293. }
  294. function OptionMenuPrevSetting(%val)
  295. {
  296. if(!%val)
  297. return;
  298. %option = $MenuList.getObject($MenuList.listPosition);
  299. if(!isObject(%option))
  300. return;
  301. if(%option.class $= "OptionsListEntry")
  302. {
  303. %optionObject = %option.optionsObject;
  304. %currentOptionLevel = %optionObject.getObject(%option.currentOptionIndex);
  305. %option.currentOptionIndex = mClamp(%option.currentOptionIndex-1, 0, %optionObject.getCount()-1);
  306. %newOptionLevel = %optionObject.getObject(%option.currentOptionIndex);
  307. //echo("Changed option: " @ %optionObject.optionName @ " from level: " @ %currentOptionLevel.displayName @ " to level: " @ %newOptionLevel.displayName);
  308. }
  309. else if(%option.class $= "OptionsListSliderEntry")
  310. {
  311. %sliderCtrl = %option-->valuesContainer-->slider;
  312. %minValue = %sliderCtrl.range.x;
  313. %maxValue = %sliderCtrl.range.y;
  314. %ticks = %sliderCtrl.ticks;
  315. %tickIncrementVal = (%maxValue - %minValue) / %ticks;
  316. %sliderCtrl.value -= %tickIncrementVal;
  317. }
  318. $MenuList.syncGUI();
  319. }
  320. function OptionMenuNextSetting(%val)
  321. {
  322. if(!%val)
  323. return;
  324. %option = $MenuList.getObject($MenuList.listPosition);
  325. if(!isObject(%option) )
  326. return;
  327. if(%option.class $= "OptionsListEntry")
  328. {
  329. %optionObject = %option.optionsObject;
  330. %currentOptionLevel = %optionObject.getObject(%option.currentOptionIndex);
  331. %option.currentOptionIndex = mClamp(%option.currentOptionIndex+1, 0, %optionObject.getCount()-1);
  332. %newOptionLevel = %optionObject.getObject(%option.currentOptionIndex);
  333. //echo("Changed option: " @ %optionObject.optionName @ " from level: " @ %currentOptionLevel.displayName @ " to level: " @ %newOptionLevel.displayName);
  334. }
  335. else if(%option.class $= "OptionsListSliderEntry")
  336. {
  337. %sliderCtrl = %option-->valuesContainer-->slider;
  338. %minValue = %sliderCtrl.range.x;
  339. %maxValue = %sliderCtrl.range.y;
  340. %ticks = %sliderCtrl.ticks;
  341. %tickIncrementVal = (%maxValue - %minValue) / %ticks;
  342. %sliderCtrl.value += %tickIncrementVal;
  343. }
  344. $MenuList.syncGUI();
  345. }
  346. function OptionMenuStickChangeSetting(%val)
  347. {
  348. if(%val == 1)
  349. OptionMenuNextSetting(1);
  350. else if(%val == -1)
  351. OptionMenuPrevSetting(1);
  352. }
  353. function OptionsMenuActivateOption(%val)
  354. {
  355. if(!%val)
  356. return;
  357. %option = $MenuList.getObject($MenuList.listPosition);
  358. if(!isObject(%option))
  359. return;
  360. if(%option.class $= "OptionsKeybindEntry")
  361. {
  362. %option-->button.execAltCommand();
  363. }
  364. }
  365. //==============================================================================
  366. // This function utilizes the VideoSettingsGroup SimGroup to populate options.
  367. // The object is defined in core/rendering/scripts/graphicsOptions.tscript
  368. // A majority of the options are statically defined, but some are dynamically populated
  369. // on refresh, like the display device or available resolution options.
  370. // Once populated, we loop over the simgroup structure to populate our option entry
  371. // rows in the options menu itself.
  372. function OptionsMenu::populateVideoSettings(%this)
  373. {
  374. VideoSettingsList.clear();
  375. VideoSettingsGroup::populateDisplaySettings();
  376. for(%i=0; %i < VideoSettingsGroup.getCount(); %i++)
  377. {
  378. %setting = VideoSettingsGroup.getObject(%i);
  379. if(%setting.class $= "SubOptionsGroup")
  380. {
  381. %entry = addOptionGroup(%setting.displayName);
  382. if(isObject(%entry))
  383. VideoSettingsList.add(%entry);
  384. for(%s=0; %s < %setting.getCount(); %s++)
  385. {
  386. %option = %setting.getObject(%s);
  387. %optionsEntry = addOptionEntry(%option);
  388. if(isObject(%optionsEntry))
  389. VideoSettingsList.add(%optionsEntry);
  390. }
  391. }
  392. else if(%setting.class $= "OptionsSettings")
  393. {
  394. %optionsEntry = addOptionEntry(%setting);
  395. if(isObject(%optionsEntry))
  396. VideoSettingsList.add(%optionsEntry);
  397. }
  398. }
  399. //Ensure our newly templated options listings are sized right
  400. for(%i=0; %i < VideoSettingsList.getCount(); %i++)
  401. {
  402. %entry = VideoSettingsList.getObject(%i);
  403. %entry.resize(0, 0, VideoSettingsList.extent.x - 15, %entry.extent.y); //-10 for the scroll wheel pad
  404. }
  405. }
  406. //==============================================================================
  407. // This function utilizes the AudioSettingsGroup SimGroup to populate options.
  408. // The object is defined in core/sfx/scripts/audioOptions.tscript
  409. // Similar to the video options, it can be a mix of static and dynamically populated
  410. // option entries, which we then iterate over and populate the entry rows for the menu
  411. function OptionsMenu::populateAudioSettings(%this)
  412. {
  413. AudioSettingsList.clear();
  414. AudioSettingsGroup.populateSettings();
  415. //Process the lists
  416. for(%i=0; %i < AudioSettingsGroup.getCount(); %i++)
  417. {
  418. %setting = AudioSettingsGroup.getObject(%i);
  419. if(%setting.class $= "SubOptionsGroup")
  420. {
  421. %entry = addOptionGroup(%setting.displayName);
  422. if(isObject(%entry))
  423. AudioSettingsList.add(%entry);
  424. for(%s=0; %s < %setting.getCount(); %s++)
  425. {
  426. %option = %setting.getObject(%s);
  427. %optionsEntry = addOptionEntry(%option);
  428. if(isObject(%optionsEntry))
  429. AudioSettingsList.add(%optionsEntry);
  430. }
  431. }
  432. else if(%setting.class $= "AudioOptionsSettings")
  433. {
  434. %optionsEntry = addOptionEntry(%setting);
  435. if(isObject(%optionsEntry))
  436. AudioSettingsList.add(%optionsEntry);
  437. }
  438. }
  439. AudioSettingsList.add(addOptionGroup("Channel Volume"));
  440. //Now we'll populate the sliders for the audio channels.
  441. //The defaults of these are defined in core/sfx/scripts/audio.tscript
  442. //These define the MasterVolume channel, as well as several other common defualt ones
  443. //Because it's a variable list, this can be expanded by modules by just upping $AudioChannelCount
  444. //and then defining the $AudioChannelName[x] with the displayed name and
  445. //and the $AudioChannels[x] variable with the SFXSource object defined to it for the given channel
  446. AudioSettingsList.add(addOptionSlider("Master Volume", "", "$pref::SFX::masterVolume", 0, 1, 10));
  447. //We init to 1, because 0 is the reserved for the masterVolume in practice
  448. for(%i=1; %i < $AudioChannelCount; %i++)
  449. {
  450. AudioSettingsList.add(addOptionSlider($AudioChannelsName[%i] @ " Volume", "", "$pref::SFX::channelVolume" @ %i, 0, 1, 10));
  451. }
  452. //Ensure our newly templated options listings are sized right
  453. for(%i=0; %i < AudioSettingsList.getCount(); %i++)
  454. {
  455. %entry = AudioSettingsList.getObject(%i);
  456. %entry.resize(0, 0, AudioSettingsList.extent.x - 15, %entry.extent.y); //-10 for the scroll wheel pad
  457. }
  458. }
  459. function OptionsMenu::populateKBMControls(%this)
  460. {
  461. %this.populateKeybinds("keyboard", KBMControlsList);
  462. %this.syncGui();
  463. KBMControlsList.syncGui();
  464. }
  465. function OptionsMenu::populateGamepadControls(%this)
  466. {
  467. %this.populateKeybinds("gamepad", GamepadControlsList);
  468. %this.syncGui();
  469. GamepadControlsList.syncGui();
  470. }
  471. function OptionsMenu::populateKeybinds(%this, %device, %controlsList)
  472. {
  473. %controlsList.clear();
  474. //build out our list of action maps
  475. %actionMapCount = ActionMapGroup.getCount();
  476. %actionMapList = "";
  477. for(%i=0; %i < %actionMapCount; %i++)
  478. {
  479. %actionMap = ActionMapGroup.getObject(%i);
  480. if(%actionMap == GlobalActionMap.getId())
  481. continue;
  482. %actionMapName = %actionMap.humanReadableName $= "" ? %actionMap.getName() : %actionMap.humanReadableName;
  483. //see if we have any actual listed remappable keys for this movemap. if so, drop it from the listing
  484. %hasRemaps = false;
  485. for ( %r = 0; %r < $RemapCount; %r++ )
  486. {
  487. %testMapName = $RemapActionMap[%r].humanReadableName $= "" ? $RemapActionMap[%r].getName() : $RemapActionMap[%r].humanReadableName;
  488. if(%actionMapName $= %testMapName)
  489. {
  490. //got a match to at least one, so we're ok to continue
  491. %hasRemaps = true;
  492. break;
  493. }
  494. }
  495. if(!%hasRemaps)
  496. continue;
  497. if(%actionMapList $= "")
  498. %actionMapList = %actionMapName;
  499. else
  500. %actionMapList = %actionMapList TAB %actionMapName;
  501. }
  502. //If we didn't find any valid actionMaps, then just exit out
  503. if(%actionMapList $= "")
  504. return;
  505. if($activeRemapControlSet $= "")
  506. $activeRemapControlSet = getField(%actionMapList, 0);
  507. echo("============================================");
  508. for(%am = 0; %am < getFieldCount(%actionMapList); %am++)
  509. {
  510. %currentActionMap = getField(%actionMapList, %am);
  511. //only add the group if we've got more than one group, otherwise it's obviously
  512. //part of the single grouping
  513. if(getFieldCount(%actionMapList) > 1)
  514. {
  515. %actionMapGroupEntry = addOptionGroup(%currentActionMap);
  516. %controlsList.add(%actionMapGroupEntry);
  517. }
  518. for ( %i = 0; %i < $RemapCount; %i++ )
  519. {
  520. if(%device !$= "" && %device !$= $RemapDevice[%i])
  521. continue;
  522. %actionMapName = $RemapActionMap[%i].humanReadableName $= "" ? $RemapActionMap[%i].getName() : $RemapActionMap[%i].humanReadableName;
  523. if(%currentActionMap !$= %actionMapName)
  524. continue;
  525. %keyMap = buildFullMapString( %i, $RemapActionMap[%i], %device );
  526. %description = $RemapDescription[%i];
  527. if ($reportKeymapping)
  528. echo("Added ActionMap Entry: " @ %actionMapName @ " | " @ %device @ " | " @ %keymap @ " | " @ %description);
  529. %remapEntry = addActionMapEntry(%actionMapName, %device, %keyMap, %i, %description);
  530. %controlsList.add(%remapEntry);
  531. }
  532. }
  533. //Ensure our newly templated options listings are sized right
  534. for(%i=0; %i < %controlsList.getCount(); %i++)
  535. {
  536. %entry = %controlsList.getObject(%i);
  537. %entry.resize(0, 0, %controlsList.extent.x - 15, %entry.extent.y); //-10 for the scroll wheel pad
  538. }
  539. }
  540. //==============================================================================
  541. function tryCloseOptionsMenu(%val)
  542. {
  543. if(!%val)
  544. return;
  545. $optionsChangeRequiresRestart = false;
  546. %unappliedVideoChanges = VideoSettingsList.checkForUnappliedChanges();
  547. %unappliedAudioChanges = AudioSettingsList.checkForUnappliedChanges();
  548. //validate audio prefs
  549. if($pref::SFX::masterVolume_tempVar !$= "" && $pref::SFX::masterVolume_tempVar != $pref::SFX::masterVolume)
  550. %unappliedAudioChanges = true;
  551. for(%i=1; %i < $AudioChannelCount; %i++)
  552. {
  553. %tempVolume = getVariable("$pref::SFX::channelVolume" @ %i @ "_tempVar");
  554. if(%tempVolume !$= "" && $pref::SFX::channelVolume[ %i ] != %tempVolume)
  555. %unappliedAudioChanges = true;
  556. }
  557. if(%unappliedVideoChanges || %unappliedAudioChanges)
  558. {
  559. MessageBoxOKCancel("Discard Changes?", "You have unapplied changes to your settings, do you wish to apply or discard them?",
  560. "OptionsMenu.applyChangedOptions(); BaseUIBackOut(1);", "BaseUIBackOut(1);",
  561. "Apply", "Discard");
  562. }
  563. else
  564. {
  565. BaseUIBackOut(1);
  566. }
  567. }
  568. function tryApplyOptions(%val)
  569. {
  570. if(!%val)
  571. return;
  572. $optionsChangeRequiresRestart = false;
  573. %unappliedVideoChanges = VideoSettingsList.checkForUnappliedChanges();
  574. %unappliedAudioChanges = AudioSettingsList.checkForUnappliedChanges();
  575. if(%unappliedVideoChanges || %unappliedAudioChanges)
  576. OptionsMenu.applyChangedOptions();
  577. }
  578. function OptionsMenu::applyChangedOptions(%this)
  579. {
  580. VideoSettingsList.applyChanges();
  581. AudioSettingsList.applyChanges();
  582. //Process the audio channel tempvars to get their values
  583. //and then apply them to the actual pref variable, as well as the SFXChannelVolume
  584. $pref::SFX::masterVolume = $pref::SFX::masterVolume_tempVar;
  585. sfxSetMasterVolume( $pref::SFX::masterVolume );
  586. //0 is always master anyways
  587. for(%i=1; %i < $AudioChannelCount; %i++)
  588. {
  589. %volume = getVariable("$pref::SFX::channelVolume" @ %i @ "_tempVar");
  590. sfxSetChannelVolume( %i, %volume );
  591. $pref::SFX::channelVolume[ %i ] = %volume;
  592. }
  593. //Finally, write our prefs to file
  594. %prefPath = getPrefpath();
  595. export("$pref::*", %prefPath @ "/clientPrefs." @ $TorqueScriptFileExtension, false);
  596. if($optionsChangeRequiresRestart)
  597. MessageBoxOK("Restart Required", "Some of your changes require the game to be restarted.");
  598. }
  599. function doKeyRemap( %optionEntry )
  600. {
  601. %name = getField(%optionEntry.keymap,0);
  602. RemapDlg-->OptRemapText.text = "Re-bind \"" @ %name @ "\" to..." ;
  603. OptRemapInputCtrl.index = %optionEntry.remapIndex;
  604. $remapListDevice = %optionEntry.device;
  605. Canvas.pushDialog( RemapDlg );
  606. }
  607. function OptionsMenu::resetSettings(%this)
  608. {
  609. MessageBoxOKCancel("", "This will set the graphical settings back to the auto-detected defaults. Do you wish to continue?", "AutodetectGraphics();", "");
  610. }
  611. //==============================================================================
  612. // Option types
  613. function addOptionGroup(%displayName)
  614. {
  615. OptionsMenu.optsListCount++;
  616. %group = new GuiTextCtrl() {
  617. text = %displayName;
  618. position = "0 0";
  619. extent = "500 45";
  620. profile = "MenuHeaderText";
  621. tooltipProfile = "GuiToolTipProfile";
  622. canSave = false;
  623. };
  624. return %group;
  625. }
  626. function optionsMenuButton::onHighlighted(%this, %highlighted)
  627. {
  628. %container = %this.getParent();
  629. %container-->optionName.profile = %highlighted ? MenuSubHeaderTextHighlighted : MenuSubHeaderText;
  630. %container-->optionDescription.profile = %highlighted ? GuiMLTextProfileHighlighted : GuiMLTextProfile;
  631. %valuesContainer = %container-->valuesContainer;
  632. %valuesContainer-->optionValue.profile = %highlighted ? GuiMenuTextProfileHL : GuiMenuTextProfile;
  633. OptionsMenuSettingsScroll.scrollToObject(%container);
  634. }
  635. function addOptionEntry(%optionObj)
  636. {
  637. OptionsMenu.optsListCount++;
  638. if(!isObject(%optionObj) || (%optionObj.class !$= "OptionsSettings" && %optionObj.class !$= "AudioOptionsSettings"))
  639. {
  640. error("addOptionsEntry() - attempting to create a new options entry, but was provided an invalid options object");
  641. return 0;
  642. }
  643. %qualityLevel = getCurrentQualityLevel(%optionObj);
  644. if(isObject(%qualityLevel))
  645. {
  646. %qualityLevelText = %qualityLevel.displayName;
  647. %qualityLevelIndex = %optionObj.getObjectIndex(%qualityLevel);
  648. }
  649. else
  650. {
  651. %qualityLevelText = %qualityLevel;
  652. %qualityLevelIndex = %optionObj.getCount();
  653. }
  654. %optionNameHeight = 20;
  655. if(%optionObj.Description $= "")
  656. %optionNameHeight = 40;
  657. %entry = new GuiContainer() {
  658. position = "0 0";
  659. extent = "800 40";
  660. profile = GuiMenuDefaultProfile;
  661. tooltipProfile = "GuiToolTipProfile";
  662. horizSizing = "width";
  663. vertSizing = "bottom";
  664. class = "OptionsListEntry";
  665. optionsObject = %optionObj;
  666. currentOptionIndex = %qualityLevelIndex;
  667. selectionID = OptionsMenu.optsListCount;
  668. canSave = false;
  669. new GuiButtonCtrl() {
  670. profile = GuiMenuButtonProfile;
  671. position = "0 0";
  672. extent = "800 40";
  673. horizSizing = "width";
  674. vertSizing = "height";
  675. internalName = "button";
  676. class = "optionsMenuButton";
  677. };
  678. new GuiTextCtrl() {
  679. text = %optionObj.OptionName;
  680. position = $optionsEntryPad SPC -1;
  681. extent = 400 SPC %optionNameHeight;
  682. profile = "MenuSubHeaderText";
  683. tooltipProfile = "GuiToolTipProfile";
  684. internalName = "optionName";
  685. };
  686. new GuiTextCtrl() {
  687. text = %optionObj.Description;
  688. position = $optionsEntryPad SPC 17;
  689. extent = "400 18";
  690. profile = "GuiMLTextProfile";
  691. tooltipProfile = "GuiToolTipProfile";
  692. internalName = "optionDescription";
  693. };
  694. new GuiContainer() {
  695. position = "400 0";
  696. extent = "400 40";
  697. profile = GuiModelessDialogProfile;
  698. tooltipProfile = "GuiToolTipProfile";
  699. horizSizing = "left";
  700. vertSizing = "height";
  701. internalName = "valuesContainer";
  702. new GuiButtonCtrl() {
  703. position = "310 0";
  704. extent = "20 40";
  705. text = "<";
  706. profile = GuiMenuButtonProfile;
  707. internalName = "prevValButton";
  708. command = "$MenuList.listPosition = $thisControl.getParent().getParent().selectionID; OptionMenuPrevSetting(1);";
  709. };
  710. new GuiTextCtrl() {
  711. text = %qualityLevelText;
  712. position = "330 0";
  713. extent = "50 40";
  714. profile = "GuiMenuTextProfile";
  715. tooltipProfile = "GuiToolTipProfile";
  716. horizSizing = "right";
  717. vertSizing = "center";
  718. internalName = "optionValue";
  719. };
  720. new GuiButtonCtrl() {
  721. position = "380 0";
  722. extent = "20 40";
  723. text = ">";
  724. profile = GuiMenuButtonProfile;
  725. internalName = "nextValButton";
  726. command = "$MenuList.listPosition = $thisControl.getParent().getParent().selectionID; OptionMenuNextSetting(1);";
  727. };
  728. };
  729. };
  730. return %entry;
  731. }
  732. function addOptionSlider(%optionName, %optionDesc, %prefName, %sliderMin, %sliderMax, %sliderTicks)
  733. {
  734. OptionsMenu.optsListCount++;
  735. %currentVal = getVariable(%prefName);
  736. %tempVarName = %prefName @ "_tempVar";
  737. if(%currentVal $= "")
  738. %currentVal = %sliderMin;
  739. setVariable(%tempVarName, %currentVal);
  740. %optionNameHeight = 20;
  741. if(%optionDesc $= "")
  742. %optionNameHeight = 40;
  743. %entry = new GuiContainer() {
  744. position = "0 0";
  745. extent = "800 40";
  746. profile = GuiMenuDefaultProfile;
  747. tooltipProfile = "GuiToolTipProfile";
  748. horizSizing = "width";
  749. vertSizing = "bottom";
  750. class = "OptionsListSliderEntry";
  751. canSave = false;
  752. new GuiButtonCtrl() {
  753. profile = GuiMenuButtonProfile;
  754. position = "0 0";
  755. extent = "800 40";
  756. horizSizing = "width";
  757. vertSizing = "height";
  758. internalName = "button";
  759. class = "optionsMenuButton";
  760. };
  761. new GuiTextCtrl() {
  762. text = %optionName;
  763. position = $optionsEntryPad SPC -1;
  764. extent = 400 SPC %optionNameHeight;
  765. profile = "MenuSubHeaderText";
  766. tooltipProfile = "GuiToolTipProfile";
  767. internalName = "optionName";
  768. };
  769. new GuiTextCtrl() {
  770. text = %optionDesc;
  771. position = $optionsEntryPad SPC 17;
  772. extent = "400 18";
  773. profile = "GuiMLTextProfile";
  774. tooltipProfile = "GuiToolTipProfile";
  775. internalName = "optionDescription";
  776. };
  777. new GuiContainer() {
  778. position = "400 0";
  779. extent = "400 40";
  780. profile = GuiModelessDialogProfile;
  781. tooltipProfile = "GuiToolTipProfile";
  782. horizSizing = "left";
  783. vertSizing = "height";
  784. internalName = "valuesContainer";
  785. new GuiSliderCtrl() {
  786. range = %sliderMin SPC %sliderMax;
  787. ticks = %sliderTicks;
  788. snap = "1";
  789. value = %currentVal;
  790. variable = %tempVarName;
  791. useFillBar = "1";
  792. fillBarColor = $TextMediumEmphasisColor;
  793. renderTicks = "0";
  794. position = "0 10";
  795. extent = "400 20";
  796. minExtent = "8 2";
  797. horizSizing = "right";
  798. vertSizing = "center";
  799. profile = GuiMenuButtonProfile;
  800. visible = "1";
  801. active = "1";
  802. command = "$thisControl.updateSliderValue();";
  803. tooltipProfile = "GuiToolTipProfile";
  804. hovertime = "1000";
  805. isContainer = "0";
  806. canSave = "1";
  807. canSaveDynamicFields = "0";
  808. class = "OptionsSliderEntrySlider";
  809. internalName = "slider";
  810. };
  811. };
  812. };
  813. return %entry;
  814. }
  815. function OptionsSliderEntrySlider::updateSliderValue(%this)
  816. {
  817. //update settings value here
  818. }
  819. function OptionsMenuActionMapButton::onHighlighted(%this, %highlighted)
  820. {
  821. %container = %this.getParent();
  822. %container-->actionName.profile = %highlighted ? MenuSubHeaderTextHighlighted : MenuSubHeaderText;
  823. OptionsMenuSettingsScroll.scrollToObject(%container);
  824. }
  825. function addActionMapEntry(%actionMap, %device, %keyMap, %index, %description)
  826. {
  827. %entry = new GuiContainer() {
  828. position = "0 0";
  829. extent = "800 40";
  830. profile = GuiMenuDefaultProfile;
  831. tooltipProfile = "GuiToolTipProfile";
  832. horizSizing = "width";
  833. vertSizing = "bottom";
  834. class = "OptionsKeybindEntry";
  835. actionMap = %actionMap;
  836. device = %device;
  837. keymap = %keyMap;
  838. remapIndex = %index;
  839. canSave = false;
  840. new GuiButtonCtrl() {
  841. profile = GuiMenuButtonProfile;
  842. position = "0 0";
  843. extent = "800 40";
  844. horizSizing = "width";
  845. vertSizing = "height";
  846. internalName = "button";
  847. class = "OptionsMenuActionMapButton";
  848. altCommand = "doKeyRemap($thisControl.getParent());";
  849. };
  850. new GuiTextCtrl() {
  851. text = getField(%keyMap, 0);
  852. position = $optionsEntryPad SPC -1;
  853. extent = "400 40";
  854. profile = "MenuSubHeaderText";
  855. tooltipProfile = "GuiToolTipProfile";
  856. internalName = "actionName";
  857. };
  858. new GuiContainer() {
  859. position = "400 3";
  860. extent = "400 34";
  861. profile = GuiModelessDialogProfile;
  862. tooltipProfile = "GuiToolTipProfile";
  863. horizSizing = "left";
  864. vertSizing = "height";
  865. internalName = "valuesContainer";
  866. };
  867. };
  868. %buttonContainer = %entry.findObjectByInternalName("valuesContainer");
  869. if ($reportKeymapping)
  870. echo("Keymap: " @ %keymap @ " | Keymap word count: " @ getWordCount(getField(%keyMap, 1)));
  871. if(getWordCount(getField(%keyMap, 1)) == 2)
  872. {
  873. %modifierBtn = new GuiIconButtonCtrl() {
  874. position = 156 SPC -10;
  875. extent = "98 45";
  876. BitmapAsset = "";
  877. profile = GuiRemapActionMapButtonProfile;
  878. sizeIconToButton = true;
  879. makeIconSquare = true;
  880. iconLocation = "center";
  881. internalName = "modifierButton";
  882. active = false;
  883. };
  884. %combinerText = new GuiTextCtrl(){
  885. position = 264 SPC -5;
  886. extent = "20 45";
  887. profile = MenuSubHeaderText;
  888. text = " + ";
  889. };
  890. %bindButton = new GuiIconButtonCtrl() {
  891. position = "300 -10";
  892. extent = "98 45";
  893. BitmapAsset = "";
  894. profile = GuiRemapActionMapButtonProfile;
  895. sizeIconToButton = true;
  896. makeIconSquare = true;
  897. iconLocation = "center";
  898. internalName = "bindButton";
  899. active = false;
  900. };
  901. %buttonContainer.add(%modifierBtn);
  902. %buttonContainer.add(%combinerText);
  903. %buttonContainer.add(%bindButton);
  904. }
  905. else
  906. {
  907. %bindButton = new GuiIconButtonCtrl() {
  908. position = "300 -10";
  909. extent = "98 45";
  910. BitmapAsset = "";
  911. profile = GuiRemapActionMapButtonProfile;
  912. sizeIconToButton = true;
  913. makeIconSquare = true;
  914. iconLocation = "center";
  915. internalName = "bindButton";
  916. active = false;
  917. };
  918. %buttonContainer.add(%bindButton);
  919. }
  920. return %entry;
  921. }