init.lua 69 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663
  1. local S = minetest.get_translator("advtrains_livery_designer")
  2. ----------------------------------------------------------------------------------------
  3. local function get_materials_minetest_game()
  4. return {
  5. base_game = "Minetest Game",
  6. bronze_ingot = "default:bronze_ingot",
  7. diamond = "default:diamond",
  8. dye_blue = "dye:blue",
  9. dye_green = "dye:green",
  10. dye_red = "dye:red",
  11. glass = "default:glass",
  12. gold_ingot = "default:gold_ingot",
  13. mese = "default:mese",
  14. obsidian_glass = "default:obsidian_glass",
  15. }
  16. end
  17. local function get_materials_mineclonia()
  18. return {
  19. base_game = "Mineclonia",
  20. bronze_ingot = "mcl_core:gold_ingot", -- bronze is not available
  21. diamond = "mcl_core:diamond",
  22. dye_blue = "mcl_dyes:blue",
  23. dye_green = "mcl_dyes:green",
  24. dye_red = "mcl_dyes:red",
  25. glass = "mcl_core:glass",
  26. gold_ingot = "mcl_core:gold_ingot",
  27. mese = minetest.get_modpath("mesecons_torch") and "mesecons_torch:redstoneblock" or "mcl_core:lapisblock",
  28. obsidian_glass = "mcl_core:glass_black", -- obsidian glass is not available
  29. }
  30. end
  31. local function get_materials_voxelibre()
  32. return {
  33. base_game = "VoxeLibre/MineClone2",
  34. bronze_ingot = "mcl_core:gold_ingot", -- bronze is not available
  35. diamond = "mcl_core:diamond",
  36. dye_blue = "mcl_dye:blue",
  37. dye_green = "mcl_dye:green",
  38. dye_red = "mcl_dye:red",
  39. glass = "mcl_core:glass",
  40. gold_ingot = "mcl_core:gold_ingot",
  41. mese = minetest.get_modpath("mesecons_torch") and "mesecons_torch:redstoneblock" or "mcl_core:lapisblock",
  42. obsidian_glass = "mcl_core:glass_black", -- obsidian glass is not available
  43. }
  44. end
  45. local function get_materials_farlands_reloaded()
  46. return {
  47. base_game = "Farlands Reloaded",
  48. bronze_ingot = "fl_ores:bronze_ingot",
  49. diamond = "fl_ores:diamond_ore",
  50. dye_blue = "fl_dyes:blue_dye",
  51. dye_green = "fl_dyes:green_dye",
  52. dye_red = "fl_dyes:red_dye",
  53. glass = "fl_glass:framed_glass",
  54. gold_ingot = "fl_ores:gold_ingot",
  55. mese = "fl_ores:bronze_ingot",
  56. obsidian_glass = "fl_ores:bronze_ingot", -- obsidian is not yet available, use an alternate for now.
  57. }
  58. end
  59. local function get_materials_hades_revisited()
  60. return {
  61. base_game = "Hades Revisited",
  62. bronze_ingot = "hades_core:bronze_ingot",
  63. diamond = "hades_core:diamond",
  64. dye_blue = "hades_dye:blue",
  65. dye_green = "hades_dye:green",
  66. dye_red = "hades_dye:red",
  67. glass = "hades_core:glass",
  68. gold_ingot = "hades_core:gold_ingot",
  69. mese = "hades_core:mese",
  70. obsidian_glass = "hades_core:obsidian_glass",
  71. }
  72. end
  73. local function get_materials()
  74. if minetest.get_modpath("default") and minetest.get_modpath("dye") then
  75. return get_materials_minetest_game()
  76. end
  77. if minetest.get_modpath("mcl_core") and minetest.get_modpath("mcl_dyes") then
  78. return get_materials_mineclonia()
  79. end
  80. if minetest.get_modpath("mcl_core") and minetest.get_modpath("mcl_dye") then
  81. return get_materials_voxelibre()
  82. end
  83. if minetest.get_modpath("fl_dyes") and minetest.get_modpath("fl_glass") and minetest.get_modpath("fl_ores") then
  84. return get_materials_farlands_reloaded()
  85. end
  86. if minetest.get_modpath("hades_core") and minetest.get_modpath("hades_dye") then
  87. return get_materials_hades_revisited()
  88. end
  89. return nil
  90. end
  91. local materials = get_materials()
  92. ----------------------------------------------------------------------------------------
  93. local callback_functions = {}
  94. local livery_designer_tool = "advtrains_livery_designer:livery_designer"
  95. local livery_designer_form = "advtrains_livery_designer:livery_designer_form"
  96. local max_visible_overlay_controls = 5
  97. local overlay_row_height = 0.8
  98. local overlay_list_scroll_height = overlay_row_height * max_visible_overlay_controls
  99. local overlay_list_height = 0.1 + overlay_list_scroll_height
  100. local overlay_control_height = overlay_row_height - 0.2
  101. local edit_livery_design_tooltip = "tooltip[11.25,7.0;2.0,0.8;"..S("Copies the livery design into the editor and then activates the editor.").."\n\n"..S("The existing design in the editor will be overwritten.").."]"
  102. local apply_livery_design_tooltip = "tooltip[13.375,7.0;2.0,0.8;"..S("Applies the livery design to the wagon.").."]"
  103. local undefined_str = "<"..S("Undefined")..">"
  104. local unknown_str = "<"..S("Unknown")..">"
  105. minetest.register_tool(livery_designer_tool, {
  106. description = S("Livery Designer Tool"),
  107. inventory_image = "advtrains_livery_designer_tool.png",
  108. wield_image = "advtrains_livery_designer_tool.png",
  109. stack_max = 1,
  110. })
  111. -- Only register the crafting recipe if the needed mods and their materials are available.
  112. if materials then
  113. minetest.register_craft({
  114. output = livery_designer_tool,
  115. recipe = {
  116. {materials.dye_red, materials.obsidian_glass, materials.diamond},
  117. {materials.dye_green, materials.mese, materials.gold_ingot},
  118. {materials.dye_blue, materials.glass, materials.bronze_ingot},
  119. }
  120. })
  121. end
  122. advtrains_livery_designer = {
  123. contexts = {},
  124. tool_name = livery_designer_tool,
  125. }
  126. --------------------------------------------------------------------------------------------------------
  127. function advtrains_livery_designer.get_mod_version()
  128. return {major = 0, minor = 8, patch = 5}
  129. end
  130. -- This utility function is intended to allow dependent mods to check if the
  131. -- needed version of advtrains_livery_designer is in use. It returns true if
  132. -- the current version of advtrains_livery_designer is equal to or greater
  133. -- than the given version info. The given version info can have nil values for
  134. -- patch or patch and minor numbers in which case those values will be
  135. -- ignored.
  136. function advtrains_livery_designer.is_compatible_mod_version(version_info)
  137. local current_mod_info = advtrains_livery_designer.get_mod_version()
  138. local major = tonumber(version_info.major)
  139. if not major or major > current_mod_info.major then
  140. return false
  141. end
  142. if major < current_mod_info.major then
  143. return true
  144. end
  145. local minor = tonumber(version_info.minor)
  146. local patch = tonumber(version_info.patch)
  147. if not minor then
  148. return not patch
  149. end
  150. if minor > current_mod_info.minor then
  151. return false
  152. end
  153. if minor < current_mod_info.minor then
  154. return true
  155. end
  156. if patch and patch > current_mod_info.patch then
  157. return false
  158. end
  159. return true
  160. end
  161. --------------------------------------------------------------------------------------------------------
  162. local color_definitions = {
  163. {value = "#FA8072", name = S("Salmon")},
  164. {value = "#DC143C", name = S("Crimson")},
  165. {value = "#FF0000", name = S("Red")},
  166. {value = "#800000", name = S("Maroon")},
  167. {value = "#FFC0CB", name = S("Pink")},
  168. {value = "#FF1493", name = S("Deep Pink")},
  169. {value = "#FF7F50", name = S("Coral")},
  170. {value = "#FF4500", name = S("Orange Red")},
  171. {value = "#FF8C00", name = S("Dark Orange")},
  172. {value = "#FFA500", name = S("Orange")},
  173. {value = "#FFD700", name = S("Gold")},
  174. {value = "#FFFF00", name = S("Yellow")},
  175. {value = "#F0E68C", name = S("Khaki")},
  176. {value = "#DDA0DD", name = S("Plumb")},
  177. {value = "#DA70D6", name = S("Orchid")},
  178. {value = "#FF00FF", name = S("Magenta")},
  179. {value = "#8A2BE2", name = S("Blue Violet")},
  180. {value = "#800080", name = S("Purple")},
  181. {value = "#6A5ACD", name = S("Slate Blue")},
  182. {value = "#ADFF2F", name = S("Green Yellow")},
  183. {value = "#00FF00", name = S("Lime")},
  184. {value = "#2E8B57", name = S("Sea Green")},
  185. {value = "#008000", name = S("Green")},
  186. {value = "#006400", name = S("Dark Green")},
  187. {value = "#808000", name = S("Olive")},
  188. {value = "#008080", name = S("Teal")},
  189. {value = "#00FFFF", name = S("Cyan")},
  190. {value = "#40E0D0", name = S("Turquoise")},
  191. {value = "#ADD8E6", name = S("Light Blue")},
  192. {value = "#87CEEB", name = S("Sky Blue")},
  193. {value = "#4682B4", name = S("Steel Blue")},
  194. {value = "#4169E1", name = S("Royal Blue")},
  195. {value = "#0000FF", name = S("Blue")},
  196. {value = "#000080", name = S("Navy")},
  197. {value = "#F5DEB3", name = S("Wheat")},
  198. {value = "#D2B48C", name = S("Tan")},
  199. {value = "#DAA520", name = S("Goldenrod")},
  200. {value = "#D2691E", name = S("Chocolate")},
  201. {value = "#A0522D", name = S("Sienna")},
  202. {value = "#8B4513", name = S("Saddle Brown")},
  203. {value = "#A52A2A", name = S("Brown")},
  204. {value = "#FFFFFF", name = S("White")},
  205. {value = "#FFFAFA", name = S("Snow")},
  206. {value = "#F0FFFF", name = S("Azure")},
  207. {value = "#FFFFF0", name = S("Ivory")},
  208. {value = "#FAF0E6", name = S("Linen")},
  209. {value = "#F5F5DC", name = S("Beige")},
  210. {value = "#C0C0C0", name = S("Silver")},
  211. {value = "#808080", name = S("Grey")},
  212. {value = "#708090", name = S("Slate Grey")},
  213. {value = "#696969", name = S("Dim Grey")},
  214. {value = "#2F4F4F", name = S("Dark Slate Grey")},
  215. {value = "#000000", name = S("Black")},
  216. }
  217. -- Build a table for lookup of a color value by name
  218. local color_definitions_name_lookup = {}
  219. for _, color_definition in ipairs(color_definitions) do
  220. color_definitions_name_lookup[color_definition.name] = color_definition.value
  221. end
  222. local function get_color_by_name(color_name)
  223. return color_definitions_name_lookup[color_name]
  224. end
  225. -- Build a table for lookup of a color name by value
  226. local color_definitions_value_lookup = {}
  227. for _, color_definition in ipairs(color_definitions) do
  228. color_definitions_value_lookup[color_definition.value] = color_definition.name
  229. end
  230. local function get_color_name_by_value(color)
  231. return color_definitions_value_lookup[color]
  232. end
  233. -- Build a table of color override options
  234. local color_overrides = {
  235. S("None"),
  236. S("Custom"),
  237. }
  238. for _, color_definition in ipairs(color_definitions) do
  239. table.insert(color_overrides, color_definition.name)
  240. end
  241. local color_override_options = table.concat(color_overrides, ",")
  242. -- Build a table of predefined color options (for use by the color selector)
  243. local predefined_colors = {
  244. S("Custom"),
  245. }
  246. for _, color_definition in ipairs(color_definitions) do
  247. table.insert(predefined_colors, color_definition.name)
  248. end
  249. local predefined_color_options = table.concat(predefined_colors, ",")
  250. --------------------------------------------------------------------------------------------------------
  251. local function get_index(array, value)
  252. for idx, val in ipairs(array) do
  253. if val == value then
  254. return idx
  255. end
  256. end
  257. return nil
  258. end
  259. local function get_livery_name_index(array, value)
  260. for idx, val in ipairs(array) do
  261. if val.livery_name == value then
  262. return idx
  263. end
  264. end
  265. return nil
  266. end
  267. local function is_valid_wagon(wagon)
  268. return wagon and wagon.id and advtrains.wagons[wagon.id] and advtrains.wagons[wagon.id].type
  269. end
  270. --------------------------------------------------------------------------------------------------------
  271. local function get_color_from_color_components(r, g, b)
  272. return string.format("#%02X%02X%02X", r, g, b)
  273. end
  274. local function get_color_components_from_color(color)
  275. -- Skip leading "#" in color
  276. local color_components = {
  277. r = tonumber("0x"..color:sub(2, 3)),
  278. g = tonumber("0x"..color:sub(4, 5)),
  279. b = tonumber("0x"..color:sub(6, 7)),
  280. }
  281. return color_components
  282. end
  283. local function is_valid_color(color)
  284. return #color == 7 and color:match("#%x%x%x%x%x%x")
  285. end
  286. --------------------------------------------------------------------------------------------------------
  287. local function get_or_create_context(player)
  288. local name = player:get_player_name()
  289. local context = advtrains_livery_designer.contexts[name]
  290. if not context then
  291. advtrains_livery_designer.contexts[name] = {}
  292. end
  293. return context
  294. end
  295. local function set_context(player, context)
  296. advtrains_livery_designer.contexts[player:get_player_name()] = context
  297. end
  298. local function remove_context(player)
  299. advtrains_livery_designer.contexts[player:get_player_name()] = nil
  300. end
  301. minetest.register_on_joinplayer(function(player)
  302. get_or_create_context(player)
  303. end)
  304. minetest.register_on_leaveplayer(function(player)
  305. remove_context(player)
  306. end)
  307. local function play_apply_sound(wagon)
  308. minetest.sound_play("advtrains_livery_designerr_tool", {object = wagon.object, gain = 0.06, max_hear_distance = 11})
  309. end
  310. --------------------------------------------------------------------------------------------------------
  311. function advtrains_livery_designer.register_mod(mod_name, apply_wagon_livery_textures, optional_callback_functions)
  312. assert(mod_name, "Missing required mod name")
  313. assert(apply_wagon_livery_textures, "Missing required callback function")
  314. advtrains_livery_database.register_mod(mod_name, optional_callback_functions)
  315. if not callback_functions[mod_name] then
  316. callback_functions[mod_name] = {
  317. apply_wagon_livery_textures = apply_wagon_livery_textures,
  318. }
  319. end
  320. end
  321. local function update_overlay_controls(wagon_livery_template, livery_design, overlay_controls)
  322. if not wagon_livery_template or not livery_design then
  323. return
  324. end
  325. -- Clear the overlay control values but keep the control entries since they determine what is visible in the UI.
  326. for key, _ in pairs(overlay_controls) do
  327. overlay_controls[key] = nil
  328. end
  329. for id, overlay in ipairs(wagon_livery_template.overlays) do -- This will need to change if supporting resequenced overlays.
  330. local overlay_color = livery_design.overlays and livery_design.overlays[id] and livery_design.overlays[id].color or nil -- A template overlay is not required to be present in a livery_design
  331. local override_selection_idx = overlay_color and 2 or 1
  332. -- Update override_selection_idx if the overlay color matches one of the named colors
  333. if override_selection_idx == 2 then
  334. local predefined_color_name = get_color_name_by_value(overlay_color)
  335. override_selection_idx = get_index(color_overrides, predefined_color_name) or 2
  336. end
  337. overlay_controls[id] = {
  338. name = overlay.name or undefined_str,
  339. override_selection_idx = override_selection_idx,
  340. override_selection_name = color_overrides[override_selection_idx],
  341. color = livery_design.overlays[id] and livery_design.overlays[id].color,
  342. }
  343. end
  344. end
  345. local function update_color_selector_controls(color_selector_dialog)
  346. local color = color_selector_dialog.current_color
  347. local color_name = get_color_name_by_value(color)
  348. -- Update the quick select control
  349. color_selector_dialog.controls.predefined_color_selection_idx = get_index(predefined_colors, color_name) or 1
  350. -- Update the color component scrollbars
  351. local color_components = get_color_components_from_color(color)
  352. color_selector_dialog.controls.component_scrollbar_pos = {
  353. r = color_components.r,
  354. g = color_components.g,
  355. b = color_components.b,
  356. }
  357. end
  358. local function clone_control_settings(src_controls)
  359. local controls = {
  360. livery_template_name_selection = src_controls.livery_template_name_selection,
  361. overlays = {},
  362. }
  363. for id, overlay in ipairs(src_controls.overlays) do
  364. controls.overlays[id] = {
  365. name = overlay.name,
  366. override_selection_idx = overlay.override_selection_idx,
  367. override_selection_name = overlay.override_selection_name,
  368. color = overlay.color,
  369. }
  370. end
  371. return controls
  372. end
  373. local function clone_tab(src_tab)
  374. local tab = {
  375. textures = advtrains_livery_database.clone_textures(src_tab.textures),
  376. livery_design = advtrains_livery_database.clone_livery_design(src_tab.livery_design),
  377. controls = clone_control_settings(src_tab.controls),
  378. }
  379. return tab
  380. end
  381. -- This function is similar to clone_tab() but is used when copying a livery design from
  382. -- the predefined_liveries_tab which doesn't have the same controls as the other tabs. Thus,
  383. -- the target tab must be updated from the selected livery rather than have values copied
  384. -- from the source tab.
  385. local function update_tab_from_predefined_livery_design(context, target_tab)
  386. target_tab.textures = advtrains_livery_database.clone_textures(context.predefined_liveries_tab.textures)
  387. target_tab.livery_design = advtrains_livery_database.clone_livery_design(context.predefined_liveries_tab.livery_design)
  388. local wagon_livery_template = advtrains_livery_database.get_wagon_livery_template(context.wagon_type, target_tab.livery_design.livery_template_name)
  389. target_tab.controls.livery_template_name_selection = get_index(context.wagon_valid_livery_template_names, target_tab.livery_design.livery_template_name)
  390. update_overlay_controls(wagon_livery_template, target_tab.livery_design, target_tab.controls.overlays)
  391. end
  392. -- Record the current state of the override values. These values are restored to the override
  393. -- controls later when switching to a different livery template in order to view the newly
  394. -- selected template with the overrides that had been displayed.
  395. local function save_override_values(context)
  396. context.override_values = {}
  397. for seq_num, overlay in ipairs(context.livery_editor_tab.controls.overlays) do
  398. if overlay.color then
  399. context.override_values[seq_num] = overlay.color
  400. end
  401. end
  402. end
  403. local function save_override_value(context, idx, color)
  404. context.override_values[idx] = color
  405. end
  406. local function restore_override_values(context)
  407. -- Update the color overlays in the livery design
  408. if context.override_values then
  409. for idx, override_value in pairs(context.override_values) do
  410. -- Update the livery design with the specified color
  411. if not context.livery_editor_tab.livery_design.overlays[idx] then
  412. -- Only add an overlay to the livery design if the template supports it.
  413. local wagon_livery_template = advtrains_livery_database.get_wagon_livery_template(context.wagon_type, context.livery_editor_tab.livery_design.livery_template_name)
  414. if wagon_livery_template and wagon_livery_template.overlays and idx <= #wagon_livery_template.overlays then
  415. -- A color override did not previously exist in the livery design so create one
  416. context.livery_editor_tab.livery_design.overlays[idx] = {
  417. id = idx,
  418. color = override_value,
  419. }
  420. end
  421. else
  422. -- Update the existing color override value in the livery design
  423. context.livery_editor_tab.livery_design.overlays[idx].color = override_value
  424. end
  425. end
  426. end
  427. end
  428. local function update_predefined_liveries_tab_selection(context, selection_idx)
  429. context.predefined_liveries_tab.controls.livery_name_selection_idx = selection_idx
  430. context.predefined_liveries_tab.selected_livery_name = context.wagon_predefined_livery_names[selection_idx].livery_name
  431. context.predefined_liveries_tab.livery_design = advtrains_livery_database.get_predefined_livery(context.wagon_type, context.predefined_liveries_tab.selected_livery_name)
  432. context.predefined_liveries_tab.textures = advtrains_livery_database.get_livery_textures_from_design(context.predefined_liveries_tab.livery_design, context.wagon.id)
  433. end
  434. local function are_livery_templates_equivalent(livery_template_1, livery_template_2)
  435. if not livery_template_1 or
  436. not livery_template_2 or
  437. livery_template_1.overlays and not livery_template_2.overlays or
  438. not livery_template_1.overlays and livery_template_2.overlays then
  439. return false
  440. end
  441. -- Every overlay in livery template 1 should be in livery template 2 and...
  442. for id, overlay in pairs(livery_template_1.overlays) do
  443. if not livery_template_2.overlays[id] or
  444. overlay.name ~= livery_template_2.overlays[id].name then
  445. return false
  446. end
  447. end
  448. -- ...every overlay in livery template 2 should also be in livery template 1
  449. for id, overlay in pairs(livery_template_2.overlays) do
  450. if not livery_template_1.overlays[id] or
  451. overlay.name ~= livery_template_1.overlays[id].name then
  452. return false
  453. end
  454. end
  455. return true
  456. end
  457. local function are_livery_designs_equivalent(livery_design_1, livery_design_2)
  458. if not livery_design_1 or
  459. not livery_design_2 or
  460. livery_design_1.wagon_type ~= livery_design_2.wagon_type or
  461. livery_design_1.livery_template_name ~= livery_design_2.livery_template_name or
  462. livery_design_1.overlays and not livery_design_2.overlays or
  463. not livery_design_1.overlays and livery_design_2.overlays then
  464. return false
  465. end
  466. -- Every overlay in livery design 1 should be in livery design 2 and...
  467. for seq_number, overlay in pairs(livery_design_1.overlays) do
  468. if not livery_design_2.overlays[seq_number] or
  469. overlay.id ~= livery_design_2.overlays[seq_number].id or
  470. overlay.color ~= livery_design_2.overlays[seq_number].color then
  471. return false
  472. end
  473. end
  474. -- ...every overlay in livery design 2 should also be in livery design 1
  475. for seq_number, overlay in pairs(livery_design_2.overlays) do
  476. if not livery_design_1.overlays[seq_number] or
  477. overlay.id ~= livery_design_1.overlays[seq_number].id or
  478. overlay.color ~= livery_design_1.overlays[seq_number].color then
  479. return false
  480. end
  481. end
  482. return true
  483. end
  484. local function get_livery_designer_context(player, wagon)
  485. -- Validate the given wagon
  486. if not is_valid_wagon(wagon) then
  487. return
  488. end
  489. local wagon_type = advtrains.wagons[wagon.id].type
  490. local wagon_mod_name = advtrains_livery_database.get_wagon_mod_name(wagon_type)
  491. if not wagon_mod_name then
  492. return
  493. end
  494. -- Validate that livery options have been registered for the given wagon.
  495. local livery_template_names = advtrains_livery_database.get_livery_template_names_for_wagon(wagon_type)
  496. if #livery_template_names < 1 then
  497. -- There is no reason to continue if there are no valid options to present to the player.
  498. return
  499. end
  500. table.sort(livery_template_names, function(a, b) return a < b end)
  501. local actual_textures = advtrains_livery_database.clone_textures(advtrains.wagon_objects[wagon.id]:get_properties().textures)
  502. local livery_design = advtrains_livery_database.get_livery_design_from_textures(wagon_type, actual_textures, wagon.id)
  503. local current_textures = livery_design and advtrains_livery_database.get_livery_textures_from_design(livery_design, wagon.id)
  504. local editor_livery_design = livery_design
  505. local editor_textures = advtrains_livery_database.clone_textures(current_textures)
  506. if not editor_livery_design then
  507. -- The current livery texture cannot be mapped to a known livery design. Initialize the editor
  508. -- with a default design for for given wagon type so that the user can optionally replace the
  509. -- unknown livery with a known one.
  510. editor_livery_design = {
  511. wagon_type = wagon_type,
  512. livery_template_name = livery_template_names[1],
  513. overlays = {},
  514. }
  515. editor_textures = advtrains_livery_database.get_livery_textures_from_design(editor_livery_design, wagon.id)
  516. end
  517. -- Initialize predefined livery name options
  518. local predefined_livery_names = advtrains_livery_database.get_predefined_livery_names(wagon_type)
  519. table.sort(predefined_livery_names, function(a, b) return a.livery_name < b.livery_name end)
  520. local predefined_livery_options = {}
  521. for _, predefined_livery_name in ipairs(predefined_livery_names) do
  522. table.insert(predefined_livery_options, minetest.formspec_escape(predefined_livery_name.livery_name))
  523. end
  524. local context = {
  525. current_tab = 2,
  526. -- This is information about the selected wagon. It does not change while the livery tool is active.
  527. wagon = wagon,
  528. wagon_type = wagon_type,
  529. wagon_model = wagon.mesh,
  530. wagon_mod_name = wagon_mod_name,
  531. wagon_valid_livery_template_names = livery_template_names,
  532. wagon_livery_options = table.concat(livery_template_names, ","),
  533. wagon_predefined_livery_names = predefined_livery_names,
  534. wagon_predefined_livery_options = table.concat(predefined_livery_options, ","),
  535. -- These controls on the current/edit/saved livery tabs share a common state.
  536. common_controls = {
  537. overlay_scrollbar_pos = 0,
  538. rotate_checkbox = true,
  539. },
  540. -- The following is a cache of override values that is used to preserve them when
  541. -- switching between liveries. They are sequence based, not related to overlay names.
  542. -- The cache is not part of livery_editor_tab since it is not to be included when
  543. -- cloning tabs.
  544. override_values = {},
  545. -- This a a snapshot of the selected wagon's design. It is only updated when the user applies
  546. -- a livery design to the wagon. It should otherwise not be updated or edited.
  547. current_livery_tab = {
  548. textures = current_textures,
  549. livery_design = advtrains_livery_database.clone_livery_design(livery_design),
  550. controls = {
  551. livery_template_name_selection = livery_design and get_index(livery_template_names, livery_design.livery_template_name) or 1,
  552. overlays = {},
  553. },
  554. },
  555. -- This is the livery design currently being edited. It can be updated by the user making edits
  556. -- or when the user copies a livry design to the editer from a different tab.
  557. livery_editor_tab = {
  558. textures = editor_textures,
  559. livery_design = advtrains_livery_database.clone_livery_design(editor_livery_design),
  560. controls = {
  561. livery_template_name_selection = editor_livery_design and get_index(livery_template_names, editor_livery_design.livery_template_name) or 1,
  562. overlays = {},
  563. },
  564. },
  565. predefined_liveries_tab = {
  566. livery_names = advtrains_livery_database.get_predefined_livery_names(wagon_type),
  567. controls = {
  568. livery_name_selection_idx = 1,
  569. }
  570. },
  571. -- This is the color picker control. It needs to be initialized with a color and the id of the
  572. -- button that initiated it. It will then update the color override for the applicable override
  573. -- when the user selects the "OK" button.
  574. color_selector_dialog = {
  575. is_active = false,
  576. color_button_idx = 0, -- 0 is an invalid id. A value of 0 indicates that the dialog has not been initialized.
  577. current_color = "#404040",
  578. controls = {
  579. predefined_color_selection_idx = 1,
  580. component_scrollbar_pos = {r = 500, g = 500, b = 500},
  581. },
  582. },
  583. -- This is the model preview control which is used to display an enlarged preview of the model.
  584. model_preview_dialog = {
  585. is_active = false,
  586. textures = {},
  587. },
  588. -- This is the livery template info dialog which is used to display some additional info about a template.
  589. livery_template_info_dialog = {
  590. is_active = false,
  591. livery_template_name = nil,
  592. textures = {},
  593. },
  594. applied = true, -- The current livery is is prepopulated into the livery editor so consider it to be "applied".
  595. }
  596. -- Update context.current_livery_tab.controls and context.livery_editor_tab.controls with overlay information.
  597. local wagon_livery_template = livery_design and advtrains_livery_database.get_wagon_livery_template(wagon_type, livery_design.livery_template_name)
  598. update_overlay_controls(wagon_livery_template, livery_design, context.current_livery_tab.controls.overlays)
  599. local editor_livery_template = editor_livery_design and advtrains_livery_database.get_wagon_livery_template(wagon_type, editor_livery_design.livery_template_name)
  600. update_overlay_controls(editor_livery_template, editor_livery_design, context.livery_editor_tab.controls.overlays)
  601. -- Initialize override_values
  602. save_override_values(context)
  603. -- Restore the relevant values from the previous invocation of the tool, if they exist.
  604. local previous_context = get_or_create_context(player)
  605. if previous_context.common_controls then
  606. -- Get the rotation checkbox from the previous session
  607. context.common_controls.rotate_checkbox = previous_context.common_controls.rotate_checkbox
  608. end
  609. if previous_context.current_tab then
  610. -- Get the tab that was last active
  611. context.current_tab = previous_context.current_tab
  612. end
  613. if previous_context.saved_livery_tab and previous_context.saved_livery_tab.textures and previous_context.saved_livery_tab.livery_design then
  614. if context.wagon_type == previous_context.wagon_type then
  615. -- Get the saved livery
  616. context.saved_livery_tab = clone_tab(previous_context.saved_livery_tab)
  617. else
  618. -- If the previous_context's save livery tab is not empty and its livery design's
  619. -- template name exists for the current wagon type and the templates for the
  620. -- previous and curent wagon types are equivalent then convert the previous
  621. -- context's save tab into one that is valid for the new context.
  622. local previous_livery_template_name = previous_context.saved_livery_tab.livery_design.livery_template_name
  623. if previous_livery_template_name then
  624. local previous_livery_template = advtrains_livery_database.get_wagon_livery_template(previous_context.wagon_type, previous_livery_template_name)
  625. if previous_livery_template then
  626. -- Determine if the template name is valid for the current wagon type
  627. local current_livery_template = advtrains_livery_database.get_wagon_livery_template(context.wagon_type, previous_livery_template_name)
  628. if current_livery_template and are_livery_templates_equivalent(current_livery_template, previous_livery_template) then
  629. -- Now that equivalent livery templates are confirmed to exist
  630. -- for both the current and previous wagon types, copy the
  631. -- previously saved livery design tab to the current context
  632. -- and adjust it as needed for the current wagon type.
  633. context.saved_livery_tab = clone_tab(previous_context.saved_livery_tab)
  634. context.saved_livery_tab.livery_design.wagon_type = context.wagon_type
  635. context.saved_livery_tab.textures = advtrains_livery_database.get_livery_textures_from_design(context.saved_livery_tab.livery_design, context.wagon.id)
  636. context.saved_livery_tab.controls.livery_template_name_selection = get_index(context.wagon_valid_livery_template_names, context.saved_livery_tab.livery_design.livery_template_name) or 1
  637. end
  638. end
  639. end
  640. end
  641. end
  642. if previous_context.predefined_liveries_tab then
  643. if context.wagon_type == previous_context.wagon_type then
  644. -- Get the selected predefined livery selection from the previous session
  645. context.predefined_liveries_tab.controls.livery_name_selection_idx = previous_context.predefined_liveries_tab.controls.livery_name_selection_idx
  646. elseif previous_context.predefined_liveries_tab.selected_livery_name then
  647. -- Since the wagon types are different, try to find the same predefined livery
  648. -- name for the current wagon type that was selected for the previous wagon type.
  649. -- They could be at different index postions for their respective wagon types
  650. -- since each wagon type can have a different set of predefined liveries.
  651. local livery_name_selection_idx = get_livery_name_index(context.wagon_predefined_livery_names, previous_context.predefined_liveries_tab.selected_livery_name)
  652. if livery_name_selection_idx then
  653. context.predefined_liveries_tab.controls.livery_name_selection_idx = livery_name_selection_idx
  654. end
  655. end
  656. end
  657. if previous_context.color_selector_dialog and previous_context.color_selector_dialog.saved_color then
  658. -- Get saved color from previous session of the color selector dialog
  659. context.color_selector_dialog.saved_color = previous_context.color_selector_dialog.saved_color
  660. end
  661. if context.wagon_predefined_livery_names and #context.wagon_predefined_livery_names > 0 then
  662. update_predefined_liveries_tab_selection(context, context.predefined_liveries_tab.controls.livery_name_selection_idx)
  663. else
  664. -- There are no predefined liveries for the wagon type
  665. context.predefined_liveries_tab.selected_livery_name = nil
  666. context.predefined_liveries_tab.textures = nil
  667. context.predefined_liveries_tab.livery_design = nil
  668. context.predefined_liveries_tab.controls.livery_name_selection_idx = 0
  669. end
  670. return context
  671. end
  672. local function get_model_preview_formspec(context, wagon_textures, show_rotate_checkbox)
  673. local formspec = ""
  674. if context.wagon_model and wagon_textures and #wagon_textures > 0 then
  675. local textures = table.concat(wagon_textures, ",")
  676. local rotate_model = false
  677. if show_rotate_checkbox then
  678. rotate_model = context.common_controls.rotate_checkbox
  679. end
  680. formspec = formspec..
  681. "container[11.25,1.5]"..
  682. "box[0,0;6.25,5;#ffffff09]"..
  683. "model[0,0;6.25,5;WagonModelPreview;"..context.wagon_model..";"..textures..";-15,45;"..tostring(rotate_model)..";true;0,0]"
  684. if show_rotate_checkbox then
  685. formspec = formspec..
  686. "checkbox[0.1,4.75;RotationCheckbox;"..S("Rotate")..";"..tostring(rotate_model).."]"
  687. end
  688. formspec = formspec..
  689. "button[5.75,4.5;0.4,0.4;ExpandPreviewButton;<>]"..
  690. "tooltip[5.75,4.5;0.4,0.4;"..S("Expands the livery preview.").."]"..
  691. "container_end[]"
  692. end
  693. return formspec
  694. end
  695. local function get_model_preview_formspec_section(context)
  696. local formspec = ""
  697. if context.wagon_model and context.model_preview_dialog.textures and context.model_preview_dialog.textures[1] then
  698. local rotate_model = context.common_controls.rotate_checkbox
  699. local textures = table.concat(context.model_preview_dialog.textures, ",")
  700. formspec = formspec..
  701. "container[0.25,0.25]"..
  702. "box[0,0;19.5,15.5;#ffffff09]"..
  703. "model[0,0;19.5,15.5;WagonModelPreview;"..context.wagon_model..";"..textures..";-15,45;"..tostring(rotate_model)..";true;0,0]"..
  704. "checkbox[0.1,15.25;RotationCheckbox;"..S("Rotate")..";"..tostring(rotate_model).."]"..
  705. "button[19.0,15.0;0.4,0.4;CollapsePreviewButton;><]"..
  706. "tooltip[19.0,15.0;0.4,0.4;"..S("Collapses the livery preview.").."]"..
  707. "container_end[]"
  708. end
  709. return formspec
  710. end
  711. local function get_livery_template_info_formspec_section(context)
  712. local formspec = ""
  713. if context.wagon_type and context.wagon_model and context.livery_template_info_dialog.livery_template_name then
  714. local livery_template = advtrains_livery_database.get_wagon_livery_template(context.wagon_type, context.livery_template_info_dialog.livery_template_name)
  715. formspec = formspec..
  716. "container[0.1,0.1]"..
  717. "box[0,0;13.8,0.5;#555555ff]"..
  718. "label[5.0,0.275;"..S("Livery Template Information").."]"..
  719. "container_end[]"..
  720. "container[0.25,1.00]"..
  721. "container[0.0,0.25]"..
  722. "label[0.00,0.000;"..S("Livery Template")..":]"..
  723. "label[0.30,0.575;"..context.livery_template_info_dialog.livery_template_name.."]"..
  724. "container_end[]"..
  725. "container[0.0,1.5]"..
  726. "label[0.00,0.000;"..S("Source Mod")..":]"..
  727. "label[0.30,0.575;"..(livery_template.livery_mod or "").."]"..
  728. "container_end[]"..
  729. "container[0.0,2.75]"..
  730. "label[0.00,0.000;"..S("Template Designer")..":]"..
  731. "label[0.30,0.575;"..(livery_template.designer or "").."]"..
  732. "container_end[]"..
  733. "container[0.0,4.00]"..
  734. "label[0.00,0.000;"..S("Base Texture Filename")..":]"..
  735. "label[0.30,0.575;"..(livery_template.base_textures[1] or "").."]"..
  736. "container_end[]"..
  737. "container[0.0,5.25]"..
  738. "label[0.00,0.000;"..S("Texture Creator")..":]"..
  739. "label[0.30,0.575;"..(livery_template.texture_creator or "").."]"..
  740. "container_end[]"..
  741. "container[0.0,6.5]"..
  742. "label[0.00,0.000;"..S("Texture License")..":]"..
  743. "label[0.30,0.575;"..(livery_template.texture_license or "").."]"..
  744. "container_end[]"..
  745. "container[0.0,7.75]"..
  746. "label[0.00,0.000;"..S("Notes")..":]"..
  747. "textarea[0.30,0.275;13.0,1.0;;;"..(livery_template.notes or "").."]"..
  748. "container_end[]"..
  749. "button[11.4,9.25;2.0,0.8;CloseLiveryTemplateInfoDialogButton;OK]"..
  750. "container_end[]"
  751. end
  752. return formspec
  753. end
  754. local function get_current_livery_formspec_section(context)
  755. local current_livery_design = context.current_livery_tab.livery_design
  756. local current_livery_template_name = current_livery_design and current_livery_design.livery_template_name or unknown_str
  757. local formspec =
  758. "container[0.25,1.0]"..
  759. "label[0,0.25;"..S("Livery Template")..":]"..
  760. "label[0.30,0.825;"..current_livery_template_name.."]"
  761. if current_livery_design then
  762. formspec = formspec..
  763. "label[0,1.45;"..S("Color Overrides")..":]"..
  764. "container[0.25,1.65]"..
  765. "box[0,0;10.5,"..overlay_list_height..";#ffffff09]"
  766. local overlay_count = #context.current_livery_tab.controls.overlays
  767. local scroll_pos = context.common_controls.overlay_scrollbar_pos
  768. local overlay_box_width = 10.4
  769. local use_overlay_scrollbar = overlay_count > max_visible_overlay_controls
  770. if use_overlay_scrollbar then
  771. overlay_box_width = overlay_box_width - .25
  772. local max_step = overlay_count - max_visible_overlay_controls
  773. formspec = formspec..
  774. "scrollbaroptions[arrows=default;thumbsize=1;max="..max_step..";min=0;smallstep=1;largestep=1]"..
  775. "scroll_container[0,0;10.5,"..overlay_list_scroll_height..";OverlayScrollbar;vertical;"..overlay_row_height.."]"
  776. end
  777. for id, overlay in ipairs(context.current_livery_tab.controls.overlays) do
  778. local overlay_name = overlay.name or undefined_str
  779. local overlay_color_override = overlay.override_selection_name or "None"
  780. local overlay_color = overlay.color
  781. formspec = formspec..
  782. "container[0,"..(0.1 + (id - 1) * overlay_row_height).."]"..
  783. "box[0.05,0.0;"..overlay_box_width..","..(overlay_row_height - 0.1)..";#ffffff09]"..
  784. "label[0.1,0.35;"..id..".]"..
  785. "label[0.6,0.35;"..overlay_name.."]"..
  786. "label[4.15,0.35;"..overlay_color_override.."]"
  787. if overlay_color then
  788. formspec = formspec..
  789. "box[8.75,0.05;"..overlay_control_height..","..overlay_control_height..";#252525ff]"..
  790. "box[8.80,0.09;"..(overlay_control_height - 0.08)..","..(overlay_control_height - 0.08)..";"..overlay_color.."]"..
  791. "tooltip[8.80,0.09;"..(overlay_control_height - 0.08)..","..(overlay_control_height - 0.08)..";"..overlay_color.."]"
  792. end
  793. formspec = formspec..
  794. "container_end[]"
  795. end
  796. if use_overlay_scrollbar then
  797. formspec = formspec..
  798. "scroll_container_end[]"..
  799. "scrollbar[10.25,0.0;.25,"..overlay_list_height..";vertical;OverlayScrollbar;"..scroll_pos.."]"
  800. end
  801. formspec = formspec..
  802. "container_end[]"
  803. end
  804. formspec = formspec..
  805. "container_end[]"..
  806. get_model_preview_formspec(context, context.current_livery_tab.textures, true)
  807. if current_livery_design then
  808. if not are_livery_designs_equivalent(current_livery_design, context.livery_editor_tab.livery_design) then
  809. formspec = formspec..
  810. "button[11.25,7.0;2.0,0.8;CurrentLiveryEditButton;"..S("Edit").."]"..
  811. edit_livery_design_tooltip
  812. end
  813. end
  814. return formspec
  815. end
  816. local function get_livery_editor_formspec_section(context)
  817. local livery_design = context.livery_editor_tab.livery_design
  818. local livery_template_name = livery_design and livery_design.livery_template_name or unknown_str
  819. local formspec =
  820. "container[0.25,1.0]"..
  821. "label[0,0.25;"..S("Livery Template")..":]"
  822. if livery_design then
  823. local wagon_livery_options = context.wagon_livery_options or undefined_str
  824. local livery_template_name_selection = context.livery_editor_tab.controls.livery_template_name_selection or 1
  825. formspec = formspec..
  826. "dropdown[0.27,0.52;10.5,0.6;EditorLiveryTemplateName;"..wagon_livery_options..";"..livery_template_name_selection.."]"..
  827. "label[0,1.45;"..S("Color Overrides")..":]"..
  828. "container[0.25,1.65]"..
  829. "box[0,0;10.5,"..overlay_list_height..";#ffffff09]"
  830. local overlay_count = #context.livery_editor_tab.controls.overlays
  831. local scroll_pos = context.common_controls.overlay_scrollbar_pos
  832. local overlay_box_width = 10.4
  833. local use_overlay_scrollbar = overlay_count > max_visible_overlay_controls
  834. if use_overlay_scrollbar then
  835. overlay_box_width = overlay_box_width - .25
  836. local max_step = overlay_count - max_visible_overlay_controls
  837. formspec = formspec..
  838. "scrollbaroptions[arrows=default;thumbsize=1;max="..max_step..";min=0;smallstep=1;largestep=1]"..
  839. "scroll_container[0,0;10.5,"..overlay_list_scroll_height..";OverlayScrollbar;vertical;"..overlay_row_height.."]"
  840. end
  841. local override_count = 0
  842. for id, overlay in ipairs(context.livery_editor_tab.controls.overlays) do
  843. local overlay_name = overlay.name or undefined_str
  844. local overlay_color_override = context.livery_editor_tab.controls.overlays and context.livery_editor_tab.controls.overlays[id] and context.livery_editor_tab.controls.overlays[id].override_selection_idx or 1
  845. local overlay_color = overlay.color
  846. formspec = formspec..
  847. "container[0,"..(0.1 + (id - 1) * overlay_row_height).."]"..
  848. "box[0.05,0.0;"..overlay_box_width..","..(overlay_row_height - 0.1)..";#ffffff09]"..
  849. "label[0.1,0.35;"..id..".]"..
  850. "label[0.6,0.35;"..overlay_name.."]"..
  851. "dropdown[4.12,0.05;4.5,"..overlay_control_height..";ColorOverride"..id..";"..color_override_options..";"..(overlay_color_override or 1).."]"
  852. if overlay.override_selection_idx > 1 then
  853. override_count = override_count + 1
  854. formspec = formspec..
  855. "box[8.75,0.05;"..overlay_control_height..","..overlay_control_height..";#252525ff]"..
  856. "box[8.80,0.09;"..(overlay_control_height - 0.08)..","..(overlay_control_height - 0.08)..";"..(overlay_color or "#00000000").."]"..
  857. "tooltip[8.80,0.09;"..(overlay_control_height - 0.08)..","..(overlay_control_height - 0.08)..";"..(overlay_color or "#00000000").."]"
  858. if overlay.override_selection_idx > 1 then
  859. formspec = formspec..
  860. "button[9.45,0.05;"..overlay_control_height..","..overlay_control_height..";EditColorButton"..(id)..";...]"..
  861. "tooltip[9.45,0.05;"..overlay_control_height..","..overlay_control_height..";"..S("Edit Color").."]"
  862. end
  863. end
  864. formspec = formspec..
  865. "container_end[]"
  866. end
  867. if use_overlay_scrollbar then
  868. formspec = formspec..
  869. "scroll_container_end[]"..
  870. "scrollbar[10.25,0.0;.25,"..overlay_list_height..";vertical;OverlayScrollbar;"..scroll_pos.."]"
  871. end
  872. formspec = formspec..
  873. "container_end[]"..
  874. "container_end[]"..
  875. get_model_preview_formspec(context, context.livery_editor_tab.textures, false)..
  876. "button[0.5,7.0;0.8,0.8;InfoButton;i]"..
  877. "tooltip[0.5,7.0;0.8,0.8;"..S("Displays information about the current livery template.").."]"
  878. if override_count > 0 then
  879. formspec = formspec..
  880. "button[1.425,7.0;2.0,0.8;EditorResetButton;"..S("Reset").."]"..
  881. "tooltip[1.425,7.0;2.0,0.8;"..S("Resets all color overrides to 'None'.").."]"
  882. end
  883. if not context.saved_livery_tab or not are_livery_designs_equivalent(context.saved_livery_tab.livery_design, context.livery_editor_tab.livery_design) then
  884. formspec = formspec..
  885. "button[11.25,7.0;2.0,0.8;EditorSaveButton;"..S("Save").."]"..
  886. "tooltip[11.25,7.0;2.0,0.8;"..S("Copies the livery design to the saved livery tab and then activates the saved livery tab.").."\n\n"..S("The currently saved livery design will be overwritten.").."]"
  887. end
  888. if not context.applied then
  889. formspec = formspec..
  890. "button[13.375,7.0;2.0,0.8;ApplyButton;"..S("Apply").."]"..
  891. apply_livery_design_tooltip
  892. end
  893. else
  894. formspec = formspec..
  895. "label[0.30,0.825;"..livery_template_name.."]"..
  896. "container_end[]"..
  897. get_model_preview_formspec(context, context.livery_editor_tab.textures, false)
  898. end
  899. return formspec
  900. end
  901. local function get_saved_livery_formspec_section(context)
  902. local formspec = "textarea[0.5,2.5;13.5,2;;;"..S("A livery for this wagon type has not been recently saved.").."]"
  903. if context.saved_livery_tab and context.saved_livery_tab.livery_design then
  904. local livery_template_name = context.saved_livery_tab.livery_design.livery_template_name or unknown_str
  905. formspec =
  906. "container[0.25,1.0]"..
  907. "label[0,0.25;"..S("Livery Template")..":]"..
  908. "label[0.30,0.825;"..livery_template_name.."]"..
  909. "label[0,1.45;"..S("Color Overrides")..":]"..
  910. "container[0.25,1.65]"..
  911. "box[0,0;10.5,"..overlay_list_height..";#ffffff09]"
  912. local overlay_count = #context.saved_livery_tab.controls.overlays
  913. local scroll_pos = context.common_controls.overlay_scrollbar_pos
  914. local overlay_box_width = 10.4
  915. local use_overlay_scrollbar = overlay_count > max_visible_overlay_controls
  916. if use_overlay_scrollbar then
  917. overlay_box_width = overlay_box_width - .25
  918. local max_step = overlay_count - max_visible_overlay_controls
  919. formspec = formspec..
  920. "scrollbaroptions[arrows=default;thumbsize=1;max="..max_step..";min=0;smallstep=1;largestep=1]"..
  921. "scroll_container[0,0;10.5,"..overlay_list_scroll_height..";OverlayScrollbar;vertical;"..overlay_row_height.."]"
  922. end
  923. for id, overlay in ipairs(context.saved_livery_tab.controls.overlays) do
  924. local overlay_name = overlay.name or undefined_str
  925. local overlay_color_override = overlay.override_selection_name or "None"
  926. local overlay_color = overlay.color
  927. formspec = formspec..
  928. "container[0,"..(0.1 + (id - 1) * overlay_row_height).."]"..
  929. "box[0.05,0.0;"..overlay_box_width..","..(overlay_row_height - 0.1)..";#ffffff09]"..
  930. "label[0.1,0.35;"..id..".]"..
  931. "label[0.6,0.35;"..overlay_name.."]"..
  932. "label[4.15,0.35;"..overlay_color_override.."]"
  933. if overlay_color then
  934. formspec = formspec..
  935. "box[8.75,0.05;"..overlay_control_height..","..overlay_control_height..";#252525ff]"..
  936. "box[8.80,0.09;"..(overlay_control_height - 0.08)..","..(overlay_control_height - 0.08)..";"..overlay_color.."]"..
  937. "tooltip[8.80,0.09;"..(overlay_control_height - 0.08)..","..(overlay_control_height - 0.08)..";"..overlay_color.."]"
  938. end
  939. formspec = formspec..
  940. "container_end[]"
  941. end
  942. if use_overlay_scrollbar then
  943. formspec = formspec..
  944. "scroll_container_end[]"..
  945. "scrollbar[10.25,0.0;.25,"..overlay_list_height..";vertical;OverlayScrollbar;"..scroll_pos.."]"
  946. end
  947. formspec = formspec..
  948. "container_end[]"..
  949. "container_end[]"..
  950. get_model_preview_formspec(context, context.saved_livery_tab.textures, true)
  951. if not are_livery_designs_equivalent(context.saved_livery_tab.livery_design, context.livery_editor_tab.livery_design) then
  952. formspec = formspec..
  953. "button[11.25,7.0;2.0,0.8;SavedLiveryEditButton;"..S("Edit").."]"..
  954. edit_livery_design_tooltip
  955. end
  956. if not are_livery_designs_equivalent(context.saved_livery_tab.livery_design, context.current_livery_tab.livery_design) then
  957. formspec = formspec..
  958. "button[13.375,7.0;2.0,0.8;SavedLiveryApplyButton;"..S("Apply").."]"..
  959. apply_livery_design_tooltip
  960. end
  961. end
  962. return formspec
  963. end
  964. local function get_predefined_liveries_formspec_section(context)
  965. local predefined_livery_count = #context.wagon_predefined_livery_names
  966. local formspec = "textarea[0.5,2.5;13.5,2;;;"..S("No predefined liveries are available for this wagon type.").."]"
  967. if predefined_livery_count > 0 then
  968. local selection_idx = context.predefined_liveries_tab.controls.livery_name_selection_idx
  969. formspec =
  970. "container[0.25,1]"..
  971. "textlist[0,0.5;10.5,5;PredefinedLiveriesTextList;"..context.wagon_predefined_livery_options..";"..selection_idx..";false]"..
  972. "container_end[]"..
  973. get_model_preview_formspec(context, context.predefined_liveries_tab.textures, false)
  974. if not are_livery_designs_equivalent(context.predefined_liveries_tab.livery_design, context.livery_editor_tab.livery_design) then
  975. formspec = formspec..
  976. "button[11.25,7.0;2.0,0.8;PredefinedLiveriesEditButton;"..S("Edit").."]"..
  977. edit_livery_design_tooltip
  978. end
  979. if not are_livery_designs_equivalent(context.predefined_liveries_tab.livery_design, context.current_livery_tab.livery_design) then
  980. formspec = formspec..
  981. "button[13.375,7.0;2.0,0.8;PredefinedLiveriesApplyButton;"..S("Apply").."]"..
  982. apply_livery_design_tooltip
  983. end
  984. end
  985. return formspec
  986. end
  987. local function get_color_selector_formspec_section(context)
  988. local color = context.color_selector_dialog.current_color or "#000000"
  989. local saved_color = context.color_selector_dialog.saved_color or "#000000"
  990. local formspec =
  991. "container[0,0]"..
  992. "box[0,0;14,7;#333333ff]"..
  993. "container[0.1,0.1]"..
  994. "box[0,0;13.8,0.5;#555555ff]"..
  995. "label[6.0,0.275;"..S("Color Selector").."]"..
  996. "container_end[]"..
  997. "container[0.4,1.0]"..
  998. "label[0.1,0.1;"..S("Preview")..":]"..
  999. "box[0.0,0.5;3.7,3.7;#0a0a0aff]"..
  1000. "box[0.1,0.6;3.5,3.5;"..color.."ff]"..
  1001. "tooltip[0.1,0.6;3.5,3.5;"..color.."]"..
  1002. "container_end[]"..
  1003. "container[4.5,0.75]"..
  1004. "box[0,0;4.35,1.3;#ffffff09]"..
  1005. "label[0.1,0.28;"..S("Color")..":]"..
  1006. "dropdown[0.1,0.5;4.15,0.7;ColorSelectorQuickSelectDropdown;"..predefined_color_options..";"..context.color_selector_dialog.controls.predefined_color_selection_idx..";true]"..
  1007. "container_end[]"..
  1008. "container[9.25,0.75]"..
  1009. "box[0,0;4.6,1.3;#ffffff09]"..
  1010. "label[0.1,0.28;"..S("Hex Value")..":]"..
  1011. "field[0.1,0.5;2.25,0.7;ColorSelectorInputColor;;"..color.."]"..
  1012. "field_close_on_enter[ColorSelectorInputColor;false]"..
  1013. "button[2.5,0.5;2.0,0.7;ColorSelectorUpdateButton;"..S("Update").."]"..
  1014. "tooltip[2.5,0.5;2.0,0.7;"..S("Updates the current color based on the entered hex value.").."]"..
  1015. "container_end[]"..
  1016. "container[4.5,2.0]"..
  1017. "scrollbaroptions[arrows=default;thumbsize=8;max=255;min=0;smallstep=1;largestep=32]"..
  1018. "container[0,0.5]"..
  1019. "label[0,0;"..S("Red")..":]"..
  1020. "scrollbar[0,0.25;8.2,0.4;horizontal;ColorSelectorScrollBarR;"..context.color_selector_dialog.controls.component_scrollbar_pos.r.."]"..
  1021. "label[8.3,0.47;"..context.color_selector_dialog.controls.component_scrollbar_pos.r.."]"..
  1022. "container_end[]"..
  1023. "container[0,1.5]"..
  1024. "label[0,0;"..S("Green")..":]"..
  1025. "scrollbar[0,0.25;8.2,0.4;horizontal;ColorSelectorScrollBarG;"..context.color_selector_dialog.controls.component_scrollbar_pos.g.."]"..
  1026. "label[8.3,0.47;"..context.color_selector_dialog.controls.component_scrollbar_pos.g.."]"..
  1027. "container_end[]"..
  1028. "container[0,2.5]"..
  1029. "label[0,0;"..S("Blue")..":]"..
  1030. "scrollbar[0,0.25;8.2,0.4;horizontal;ColorSelectorScrollBarB;"..context.color_selector_dialog.controls.component_scrollbar_pos.b.."]"..
  1031. "label[8.3,0.47;"..context.color_selector_dialog.controls.component_scrollbar_pos.b.."]"..
  1032. "container_end[]"..
  1033. "container_end[]"..
  1034. "container[0.3,5.5]"..
  1035. "box[0,0;5.1,1.3;#ffffff09]"..
  1036. "label[0.1,0.25;"..S("Saved Color")..":]"..
  1037. "box[0.1,0.5;0.7,0.7;#0a0a0aff]"..
  1038. "box[0.2,0.6;0.5,0.5;"..saved_color.."ff]"..
  1039. "tooltip[0.2,0.6;0.5,0.5;"..saved_color.."]"..
  1040. "button[0.9,0.5;2.0,0.7;ColorSelectorSaveColorButton;"..S("Update").."]"..
  1041. "tooltip[0.9,0.5;2.0,0.7;"..S("Updates the saved color to match the current color.").."]"..
  1042. "button[3.0,0.5;2.0,0.7;ColorSelectorRecallButton;"..S("Recall").."]"..
  1043. "tooltip[3.0,0.5;2.0,0.7;"..S("Updates the current color to match the saved color.").."]"..
  1044. "container_end[]"..
  1045. "button[8.25,6;2.5,0.8;ColorSelectorOkButton;"..S("OK").."]"..
  1046. "button[11.0,6;2.5,0.8;ColorSelectorCancelButton;"..S("Cancel").."]"..
  1047. "container_end[]"
  1048. return formspec
  1049. end
  1050. local function get_formspec(player, context)
  1051. local tab_names = S("Current Livery")..", "..S("Editor")..", "..S("Saved Livery")..", "..S("Predefined Liveries")
  1052. local wagon_type = context.wagon_type and context.wagon_type or undefined_str
  1053. local formspec =
  1054. "formspec_version[4]"
  1055. if context.model_preview_dialog.is_active then
  1056. formspec = formspec..
  1057. "size[20,16]"..
  1058. "position[0.5,0.5]"..
  1059. get_model_preview_formspec_section(context)
  1060. elseif context.livery_template_info_dialog.is_active then
  1061. formspec = formspec..
  1062. "size[14,11.25]"..
  1063. "position[0.5,0.5]"..
  1064. get_livery_template_info_formspec_section(context)
  1065. elseif context.color_selector_dialog.is_active then
  1066. formspec = formspec..
  1067. "size[14,7]"..
  1068. "position[0.5,0.5]"..
  1069. get_color_selector_formspec_section(context)
  1070. else
  1071. formspec = formspec..
  1072. "size[18,8]"..
  1073. "position[0.5,0.5]"..
  1074. "tabheader[0,0;CurrentTab;"..tab_names..";"..context.current_tab.."]"..
  1075. "container[0.1,0.1]"..
  1076. "box[0.00,0.00;17.80,0.80;#ffffff09]"..
  1077. "label[0.15,0.38;"..(minetest.registered_items[wagon_type].description or wagon_type or "<"..S("Unknown Wagon")..">").."]"..
  1078. "container_end[]"
  1079. if context.current_tab == 1 then
  1080. formspec = formspec..get_current_livery_formspec_section(context)
  1081. elseif context.current_tab == 2 then
  1082. formspec = formspec..get_livery_editor_formspec_section(context)
  1083. elseif context.current_tab == 3 then
  1084. formspec = formspec..get_saved_livery_formspec_section(context)
  1085. elseif context.current_tab == 4 then
  1086. formspec = formspec..get_predefined_liveries_formspec_section(context)
  1087. end
  1088. formspec = formspec..
  1089. "button_exit[15.5,7.0;2.0,0.8;exit_button;"..S("Exit").."]"
  1090. end
  1091. return formspec
  1092. end
  1093. local function show_livery_designer_form(player, wagon)
  1094. local context = get_livery_designer_context(player, wagon)
  1095. if context then
  1096. set_context(player, context)
  1097. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1098. else
  1099. -- This is an unsupported wagon type or no livery templates have been registered for the wagon type.
  1100. minetest.chat_send_player(player:get_player_name(), S("No livery templates are defined for the wagon."))
  1101. end
  1102. end
  1103. local function get_indexed_selection(base_name, max_idx, fields)
  1104. if not base_name or not max_idx or max_idx < 1 or not fields then
  1105. return
  1106. end
  1107. local len = #base_name
  1108. for key, val in pairs(fields) do
  1109. if key:sub(1, len) == base_name then
  1110. for i = 1, max_idx do
  1111. if key == base_name..i then
  1112. return i, val
  1113. end
  1114. end
  1115. end
  1116. end
  1117. end
  1118. minetest.register_on_player_receive_fields(function(player, formname, fields)
  1119. if formname == livery_designer_form then
  1120. local itemstack = player:get_wielded_item()
  1121. if itemstack:get_name() ~= livery_designer_tool then
  1122. minetest.debug("ERROR: Not wielding the correct livery tool.")
  1123. return
  1124. end
  1125. local context = get_or_create_context(player)
  1126. if fields.quit then
  1127. set_context(player, context)
  1128. return
  1129. end
  1130. if context.model_preview_dialog.is_active then
  1131. if fields.RotationCheckbox then
  1132. context.common_controls.rotate_checkbox = fields.RotationCheckbox == "true"
  1133. set_context(player, context)
  1134. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1135. return
  1136. end
  1137. if fields.CollapsePreviewButton then
  1138. context.model_preview_dialog.is_active = false
  1139. context.model_preview_dialog.textures = {}
  1140. set_context(player, context)
  1141. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1142. return
  1143. end
  1144. end
  1145. if context.livery_template_info_dialog.is_active then
  1146. if fields.CloseLiveryTemplateInfoDialogButton then
  1147. context.livery_template_info_dialog.is_active = false
  1148. context.livery_template_info_dialog.livery_template_name = nil
  1149. context.livery_template_info_dialog.textures = {}
  1150. set_context(player, context)
  1151. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1152. return
  1153. end
  1154. end
  1155. if context.color_selector_dialog.is_active then
  1156. if fields.ColorSelectorCancelButton or fields.ColorSelectorOkButton then
  1157. if context.color_selector_dialog.color_button_idx and fields.ColorSelectorOkButton then
  1158. local override_idx = context.color_selector_dialog.color_button_idx
  1159. -- Update the livery design
  1160. context.livery_editor_tab.livery_design.overlays[override_idx].color = context.color_selector_dialog.current_color
  1161. -- Update context.livery_editor_tab.textures
  1162. context.livery_editor_tab.textures = advtrains_livery_database.get_livery_textures_from_design(context.livery_editor_tab.livery_design, context.wagon.id)
  1163. -- Update context.livery_editor_tab.controls to match the updated livery design
  1164. local wagon_livery_template = advtrains_livery_database.get_wagon_livery_template(context.wagon_type, context.livery_editor_tab.livery_design.livery_template_name)
  1165. update_overlay_controls(wagon_livery_template, context.livery_editor_tab.livery_design, context.livery_editor_tab.controls.overlays)
  1166. -- Update the applicable context.override_values[] to the updated value
  1167. save_override_value(context, override_idx, context.livery_editor_tab.livery_design.overlays[override_idx].color)
  1168. context.applied = are_livery_designs_equivalent(context.current_livery_tab.livery_design, context.livery_editor_tab.livery_design)
  1169. end
  1170. context.color_selector_dialog.is_active = false
  1171. set_context(player, context)
  1172. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1173. return
  1174. end
  1175. if fields.ColorSelectorSaveColorButton and context.color_selector_dialog.saved_color ~= context.color_selector_dialog.current_color then
  1176. context.color_selector_dialog.saved_color = context.color_selector_dialog.current_color
  1177. update_color_selector_controls(context.color_selector_dialog)
  1178. set_context(player, context)
  1179. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1180. return
  1181. end
  1182. if fields.ColorSelectorRecallButton and context.color_selector_dialog.current_color ~= context.color_selector_dialog.saved_color then
  1183. context.color_selector_dialog.current_color = context.color_selector_dialog.saved_color
  1184. update_color_selector_controls(context.color_selector_dialog)
  1185. set_context(player, context)
  1186. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1187. return
  1188. end
  1189. if fields.ColorSelectorUpdateButton and is_valid_color(fields.ColorSelectorInputColor) then
  1190. context.color_selector_dialog.current_color = fields.ColorSelectorInputColor
  1191. update_color_selector_controls(context.color_selector_dialog)
  1192. set_context(player, context)
  1193. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1194. return
  1195. end
  1196. local scrollbar_changed = false
  1197. if fields.ColorSelectorScrollBarR and fields.ColorSelectorScrollBarR:sub(1, 3) == "CHG" then
  1198. context.color_selector_dialog.controls.component_scrollbar_pos.r = tonumber(fields.ColorSelectorScrollBarR:sub(5, 8))
  1199. scrollbar_changed = true
  1200. elseif fields.ColorSelectorScrollBarG and fields.ColorSelectorScrollBarG:sub(1, 3) == "CHG" then
  1201. context.color_selector_dialog.controls.component_scrollbar_pos.g = tonumber(fields.ColorSelectorScrollBarG:sub(5, 8))
  1202. scrollbar_changed = true
  1203. elseif fields.ColorSelectorScrollBarB and fields.ColorSelectorScrollBarB:sub(1, 3) == "CHG" then
  1204. context.color_selector_dialog.controls.component_scrollbar_pos.b = tonumber(fields.ColorSelectorScrollBarB:sub(5, 8))
  1205. scrollbar_changed = true
  1206. end
  1207. if scrollbar_changed then
  1208. context.color_selector_dialog.current_color = get_color_from_color_components(
  1209. context.color_selector_dialog.controls.component_scrollbar_pos.r,
  1210. context.color_selector_dialog.controls.component_scrollbar_pos.g,
  1211. context.color_selector_dialog.controls.component_scrollbar_pos.b)
  1212. context.color_selector_dialog.controls.predefined_color_selection_idx = get_index(predefined_colors, get_color_name_by_value(context.color_selector_dialog.current_color)) or 1
  1213. elseif fields.ColorSelectorQuickSelectDropdown ~= context.color_selector_dialog.controls.predefined_color_selection_idx then
  1214. local selection_idx = tonumber(fields.ColorSelectorQuickSelectDropdown)
  1215. if selection_idx > 1 then
  1216. context.color_selector_dialog.current_color = get_color_by_name(predefined_colors[selection_idx])
  1217. update_color_selector_controls(context.color_selector_dialog)
  1218. end
  1219. end
  1220. set_context(player, context)
  1221. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1222. return
  1223. end
  1224. if fields.OverlayScrollbar and fields.OverlayScrollbar:sub(1, 3) == "CHG" then
  1225. context.common_controls.overlay_scrollbar_pos = tonumber(fields.OverlayScrollbar:sub(5, 8))
  1226. return
  1227. end
  1228. if fields.ExpandPreviewButton then
  1229. context.model_preview_dialog.is_active = true
  1230. if context.current_tab == 1 then
  1231. context.model_preview_dialog.textures = context.current_livery_tab.textures
  1232. elseif context.current_tab == 2 then
  1233. context.model_preview_dialog.textures = context.livery_editor_tab.textures
  1234. elseif context.current_tab == 3 then
  1235. context.model_preview_dialog.textures = context.saved_livery_tab.textures
  1236. elseif context.current_tab == 4 then
  1237. context.model_preview_dialog.textures = context.predefined_liveries_tab.textures
  1238. end
  1239. set_context(player, context)
  1240. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1241. return
  1242. end
  1243. if fields.InfoButton then
  1244. context.livery_template_info_dialog.is_active = true
  1245. local livery_design = context.livery_editor_tab.livery_design
  1246. local livery_template_name = livery_design and livery_design.livery_template_name
  1247. if livery_template_name then
  1248. context.livery_template_info_dialog.livery_template_name = livery_template_name
  1249. set_context(player, context)
  1250. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1251. end
  1252. return
  1253. end
  1254. local color_button_idx = get_indexed_selection("EditColorButton", advtrains_livery_database.get_overlays_per_template_limit(), fields)
  1255. if color_button_idx then
  1256. context.color_selector_dialog.is_active = true
  1257. context.color_selector_dialog.color_button_idx = color_button_idx
  1258. context.color_selector_dialog.current_color = context.livery_editor_tab.controls.overlays[color_button_idx].color or "#808080"
  1259. if not context.color_selector_dialog.saved_color then
  1260. context.color_selector_dialog.saved_color = context.color_selector_dialog.current_color
  1261. end
  1262. update_color_selector_controls(context.color_selector_dialog)
  1263. set_context(player, context)
  1264. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1265. return
  1266. end
  1267. if fields.CurrentLiveryEditButton then
  1268. context.livery_editor_tab = clone_tab(context.current_livery_tab)
  1269. -- Update override_values in order to keep them in sync with the new livery design loaded into the editor.
  1270. save_override_values(context)
  1271. context.current_tab = 2 -- Switch to the editor tab
  1272. context.applied = are_livery_designs_equivalent(context.current_livery_tab.livery_design, context.livery_editor_tab.livery_design) -- should always be true
  1273. set_context(player, context)
  1274. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1275. return
  1276. end
  1277. if fields.SavedLiveryEditButton then
  1278. context.livery_editor_tab = clone_tab(context.saved_livery_tab)
  1279. -- Update override_values in order to keep them in sync with the new livery design loaded into the editor.
  1280. save_override_values(context)
  1281. context.current_tab = 2 -- Switch to the editor tab
  1282. context.applied = are_livery_designs_equivalent(context.current_livery_tab.livery_design, context.livery_editor_tab.livery_design)
  1283. set_context(player, context)
  1284. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1285. return
  1286. end
  1287. if fields.SavedLiveryApplyButton then
  1288. callback_functions[context.wagon_mod_name].apply_wagon_livery_textures(player, context.wagon, context.saved_livery_tab.textures)
  1289. play_apply_sound(context.wagon)
  1290. context.current_livery_tab = clone_tab(context.saved_livery_tab)
  1291. context.applied = are_livery_designs_equivalent(context.saved_livery_tab.livery_design, context.livery_editor_tab.livery_design)
  1292. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context))
  1293. return
  1294. end
  1295. if fields.ApplyButton then
  1296. callback_functions[context.wagon_mod_name].apply_wagon_livery_textures(player, context.wagon, context.livery_editor_tab.textures)
  1297. play_apply_sound(context.wagon)
  1298. context.current_livery_tab = clone_tab(context.livery_editor_tab)
  1299. context.applied = true
  1300. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context))
  1301. return
  1302. end
  1303. if fields.EditorSaveButton then
  1304. context.saved_livery_tab = clone_tab(context.livery_editor_tab)
  1305. context.current_tab = 3 -- Switch to the save livery tab
  1306. set_context(player, context)
  1307. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1308. return
  1309. end
  1310. if fields.CurrentTab then
  1311. local tab = tonumber(fields.CurrentTab)
  1312. if tab ~= context.current_tab then
  1313. context.current_tab = tab
  1314. set_context(player, context)
  1315. return minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1316. end
  1317. end
  1318. if fields.RotationCheckbox then
  1319. context.common_controls.rotate_checkbox = fields.RotationCheckbox == "true"
  1320. set_context(player, context)
  1321. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1322. end
  1323. if fields.EditorResetButton then
  1324. context.livery_editor_tab.livery_design.overlays = {}
  1325. context.override_values = {}
  1326. -- Update context.livery_editor_tab.textures
  1327. context.livery_editor_tab.textures = advtrains_livery_database.get_livery_textures_from_design(context.livery_editor_tab.livery_design, context.wagon.id)
  1328. context.applied = are_livery_designs_equivalent(context.current_livery_tab.livery_design, context.livery_editor_tab.livery_design)
  1329. set_context(player, context)
  1330. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1331. end
  1332. if fields.EditorLiveryTemplateName then
  1333. -- Update context.livery_editor_tab.livery_design
  1334. context.livery_editor_tab.livery_design.livery_template_name = fields.EditorLiveryTemplateName
  1335. context.livery_editor_tab.livery_design.overlays = {}
  1336. -- Update all color overlays in the livery design based on recent edits/changes
  1337. -- (Without this, all color override values would be lost whenever a different livery template is selected.)
  1338. restore_override_values(context)
  1339. -- Update context.livery_editor_tab.textures
  1340. context.livery_editor_tab.textures = advtrains_livery_database.get_livery_textures_from_design(context.livery_editor_tab.livery_design, context.wagon.id)
  1341. -- Update context.livery_editor_tab.controls
  1342. context.livery_editor_tab.controls.livery_template_name_selection = get_index(context.wagon_valid_livery_template_names, fields.EditorLiveryTemplateName) or 1
  1343. local wagon_livery_template = advtrains_livery_database.get_wagon_livery_template(context.wagon_type, context.livery_editor_tab.livery_design.livery_template_name)
  1344. update_overlay_controls(wagon_livery_template, context.livery_editor_tab.livery_design, context.livery_editor_tab.controls.overlays)
  1345. context.applied = are_livery_designs_equivalent(context.current_livery_tab.livery_design, context.livery_editor_tab.livery_design)
  1346. set_context(player, context)
  1347. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1348. return
  1349. end
  1350. if fields.PredefinedLiveriesTextList and fields.PredefinedLiveriesTextList:sub(1, 3) == "CHG" then
  1351. update_predefined_liveries_tab_selection(context, tonumber(fields.PredefinedLiveriesTextList:sub(5, 8)))
  1352. set_context(player, context)
  1353. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1354. return
  1355. end
  1356. if fields.PredefinedLiveriesEditButton then
  1357. update_tab_from_predefined_livery_design(context, context.livery_editor_tab)
  1358. -- Update override_values in order to keep them in sync with the new livery design loaded into the editor.
  1359. -- (Without this, all color override values would be lost whenever a different livery template is selected.)
  1360. save_override_values(context)
  1361. context.current_tab = 2 -- Switch to the editor tab
  1362. context.applied = are_livery_designs_equivalent(context.current_livery_tab.livery_design, context.livery_editor_tab.livery_design)
  1363. set_context(player, context)
  1364. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1365. return
  1366. end
  1367. if fields.PredefinedLiveriesApplyButton then
  1368. callback_functions[context.wagon_mod_name].apply_wagon_livery_textures(player, context.wagon, context.predefined_liveries_tab.textures)
  1369. play_apply_sound(context.wagon)
  1370. update_tab_from_predefined_livery_design(context, context.current_livery_tab)
  1371. context.applied = false
  1372. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context))
  1373. return
  1374. end
  1375. local override_idx, selection_value = get_indexed_selection("ColorOverride", advtrains_livery_database.get_overlays_per_template_limit(), fields)
  1376. if override_idx then
  1377. local selection_idx = get_index(color_overrides, selection_value)
  1378. if not selection_idx then
  1379. return
  1380. end
  1381. -- Update the applicable color overlay in the livery design based on the color override field that was changed.
  1382. if context.livery_editor_tab.livery_design.overlays then
  1383. if selection_idx > 1 then
  1384. -- A color override was specified, make note of it in the livery design
  1385. local color = get_color_by_name(color_overrides[selection_idx])
  1386. if selection_idx == 2 then -- "Custom"
  1387. if context.livery_editor_tab.livery_design.overlays[override_idx] and
  1388. context.livery_editor_tab.livery_design.overlays[override_idx].color then
  1389. -- Keep color if switching from an existing override.
  1390. color = context.livery_editor_tab.livery_design.overlays[override_idx].color
  1391. else
  1392. color = "#7F7F7F" -- An unnamed color
  1393. end
  1394. end
  1395. context.livery_editor_tab.livery_design.overlays[override_idx] = {
  1396. id = override_idx, -- This should be an index to an overlay in livery_templates. Currently, it will likely a cause a problem if a template's overlays are not registered with contiguous numbers starting with 1.
  1397. color = color
  1398. }
  1399. elseif context.livery_editor_tab.livery_design.overlays[override_idx] then
  1400. -- The color override was removed so remove if from the livery design.
  1401. context.livery_editor_tab.livery_design.overlays[override_idx] = nil
  1402. end
  1403. end
  1404. -- Update context.livery_editor_tab.textures
  1405. context.livery_editor_tab.textures = advtrains_livery_database.get_livery_textures_from_design(context.livery_editor_tab.livery_design, context.wagon.id)
  1406. -- Update context.livery_editor_tab.controls to match the updated livery design
  1407. context.livery_editor_tab.controls.overlays[override_idx].override_selection_idx = selection_idx
  1408. context.livery_editor_tab.controls.overlays[override_idx].override_selection_name = selection_value
  1409. context.livery_editor_tab.controls.overlays[override_idx].color =
  1410. context.livery_editor_tab.livery_design.overlays and
  1411. context.livery_editor_tab.livery_design.overlays[override_idx] and
  1412. context.livery_editor_tab.livery_design.overlays[override_idx].color or nil
  1413. -- Update the applicable context.override_values[] to the updated value
  1414. save_override_value(context, override_idx, override_idx and context.livery_editor_tab.livery_design.overlays and
  1415. context.livery_editor_tab.livery_design.overlays[override_idx] and
  1416. context.livery_editor_tab.livery_design.overlays[override_idx].color or nil)
  1417. context.applied = are_livery_designs_equivalent(context.current_livery_tab.livery_design, context.livery_editor_tab.livery_design)
  1418. set_context(player, context)
  1419. minetest.show_formspec(player:get_player_name(), livery_designer_form, get_formspec(player, context) )
  1420. return
  1421. end
  1422. end
  1423. end)
  1424. function advtrains_livery_designer.activate_tool(player, wagon, mod_name)
  1425. assert(mod_name, "Invalid mod name")
  1426. assert(callback_functions[mod_name], "Attempted use of unregistered mod '"..mod_name.."'")
  1427. assert(callback_functions[mod_name].apply_wagon_livery_textures, "Missing registration of apply_wagon_livery_textures() for '"..mod_name.."' mod.")
  1428. show_livery_designer_form(player, wagon)
  1429. end