1-- Copyright © 2008-2021 Pioneer Developers. See AUTHORS.txt for details
2-- Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
3
4local Engine = require 'Engine'
5local Game = require 'Game'
6local Ship = require 'Ship'
7local ShipDef = require 'ShipDef'
8local SystemPath = require 'SystemPath'
9local Equipment = require 'Equipment'
10local Format = require 'Format'
11local MusicPlayer = require 'modules.MusicPlayer'
12local Lang = require 'Lang'
13local FlightLog = require ("FlightLog")
14
15local lc = Lang.GetResource("core")
16local lui = Lang.GetResource("ui-core")
17local qlc = Lang.GetResource("quitconfirmation-core")
18local elc = Lang.GetResource("equipment-core")
19local clc = Lang.GetResource("commodity")
20
21local ui = require 'pigui'
22
23local cargo = Equipment.cargo
24local misc = Equipment.misc
25local laser = Equipment.laser
26local hyperspace = Equipment.hyperspace
27
28local player = nil
29local colors = ui.theme.colors
30local pionillium = ui.fonts.pionillium
31local orbiteer = ui.fonts.orbiteer
32local icons = ui.theme.icons
33
34local mainButtonSize = Vector2(400,46) * (ui.screenHeight / 1200)
35local dialogButtonSize = Vector2(150,46) * (ui.screenHeight / 1200)
36local mainButtonFontSize = 24 * (ui.screenHeight / 1200)
37
38local showQuitConfirm = false
39local quitConfirmMsg
40local max_flavours = 22
41
42local startLocations = {
43	{['name']=lui.START_AT_MARS,
44	 ['desc']=lui.START_AT_MARS_DESC,
45	 ['location']=SystemPath.New(0,0,0,0,18),
46	 ['logmsg']=lui.START_LOG_ENTRY_1,
47	 ['shipType']='sinonatrix',['money']=100,['hyperdrive']=true,
48	 ['equipment']={
49		{laser.pulsecannon_1mw,1},
50		{misc.atmospheric_shielding,1},
51		{misc.autopilot,1},
52		{misc.radar,1},
53		{cargo.hydrogen,2}}},
54	{['name']=lui.START_AT_NEW_HOPE,
55	 ['desc']=lui.START_AT_NEW_HOPE_DESC,
56	 ['location']=SystemPath.New(1,-1,-1,0,4),
57	 ['logmsg']=lui.START_LOG_ENTRY_2,
58	 ['shipType']='pumpkinseed',['money']=100,['hyperdrive']=true,
59	 ['equipment']={
60		{laser.pulsecannon_1mw,1},
61		{misc.atmospheric_shielding,1},
62		{misc.autopilot,1},
63		{misc.radar,1},
64		{cargo.hydrogen,2}}},
65	{['name']=lui.START_AT_BARNARDS_STAR,
66	 ['desc']=lui.START_AT_BARNARDS_STAR_DESC,
67	 ['location']=SystemPath.New(-1,0,0,0,16),
68	 ['logmsg']=lui.START_LOG_ENTRY_3,
69	 ['shipType']='xylophis',['money']=100,['hyperdrive']=false,
70	 ['equipment']={
71		{misc.atmospheric_shielding,1},
72		{misc.autopilot,1},
73		{misc.radar,1},
74		{cargo.hydrogen,2}}}
75}
76
77local function dialogTextButton(label, enabled, callback)
78	local bgcolor = enabled and colors.buttonBlue or colors.grey
79
80	local button
81	ui.withFont(pionillium.large.name, mainButtonFontSize, function()
82		button = ui.coloredSelectedButton(label, dialogButtonSize, false, bgcolor, nil, enabled)
83	end)
84	if button then
85		callback()
86	end
87	return button
88end
89
90local function mainTextButton(label, tooltip, enabled, callback)
91	local bgcolor = enabled and colors.buttonBlue or colors.grey
92
93	local button
94	ui.withFont(pionillium.large.name, mainButtonFontSize, function()
95		button = ui.coloredSelectedButton(label, mainButtonSize, false, bgcolor, tooltip, enabled)
96	end)
97	if button and enabled then
98		callback()
99	end
100	return button
101end --mainTextButton
102
103local function confirmQuit()
104	ui.setNextWindowPosCenter('Always')
105
106	ui.withStyleColors({["WindowBg"] = colors.commsWindowBackground}, function()
107		-- TODO: this window should be ShowBorders
108		ui.window("MainMenuQuitConfirm", {"NoTitleBar", "NoResize", "AlwaysAutoResize"}, function()
109			ui.withFont(pionillium.large.name, mainButtonFontSize, function()
110				ui.text(qlc.QUIT)
111			end)
112			ui.withFont(pionillium.large.name, pionillium.large.size, function()
113				ui.pushTextWrapPos(450)
114				ui.textWrapped(quitConfirmMsg)
115				ui.popTextWrapPos()
116			end)
117			ui.dummy(Vector2(5,15)) -- small vertical spacing
118			ui.dummy(Vector2(30, 5))
119			ui.sameLine()
120			dialogTextButton(qlc.YES, true, Engine.Quit)
121			ui.sameLine()
122			ui.dummy(Vector2(30, 5))
123			ui.sameLine()
124			dialogTextButton(qlc.NO, true, function() showQuitConfirm = false end)
125		end)
126	end)
127end
128
129local function showOptions()
130	ui.optionsWindow:open()
131end
132
133local function quitGame()
134	if Engine.GetConfirmQuit() then
135		quitConfirmMsg = string.interp(qlc["MSG_" .. Engine.rand:Integer(1, max_flavours)],{yes = qlc.YES, no = qlc.NO})
136		showQuitConfirm = true
137	else
138		Engine.Quit()
139	end
140end
141
142local function continueGame()
143	if Game.CanLoadGame('_exit') and ( Engine.GetAutosaveEnabled() or not Game.CanLoadGame('_quicksave') ) then
144		Game.LoadGame("_exit")
145	else
146		Game.LoadGame('_quicksave')
147	end
148end
149
150local function canContinue()
151	return Game.CanLoadGame('_exit') or Game.CanLoadGame('_quicksave')
152end
153
154local hasMusicList = false -- required false at init, see showMainMenu() for usage
155local function startAtLocation(location)
156	hasMusicList = false -- set false so that player restarts music
157	Game.StartGame(location.location)
158	Game.player:SetShipType(location.shipType)
159	Game.player:SetLabel(Ship.MakeRandomLabel())
160	if location.hyperdrive then
161		Game.player:AddEquip(hyperspace['hyperdrive_'..ShipDef[Game.player.shipId].hyperdriveClass])
162	end
163	Game.player:SetMoney(location.money)
164	for _,equip in pairs(location.equipment) do
165		Game.player:AddEquip(equip[1],equip[2])
166	end
167	-- XXX horrible hack here to avoid paying a spawn-in docking fee
168	Game.player:setprop("is_first_spawn", true)
169	FlightLog.MakeCustomEntry(location.logmsg)
170end
171
172local function callModules(mode)
173	for k,v in ipairs(ui.getModules(mode)) do
174		v.draw()
175	end
176end
177
178local overlayWindowFlags = ui.WindowFlags {"NoTitleBar", "NoResize", "NoFocusOnAppearing", "NoBringToFrontOnFocus", "AlwaysAutoResize"}
179local mainMenuFlags = ui.WindowFlags{"NoTitleBar", "NoResize", "NoFocusOnAppearing", "NoBringToFrontOnFocus"}
180local function showMainMenu()
181	if not hasMusicList then
182		hasMusicList = true
183		MusicPlayer.rebuildSongList()
184		MusicPlayer.playRandomSongFromCategory("menu", true)
185	end
186
187	local showContinue = canContinue()
188	local buttons = 4
189
190	local winPos = Vector2(ui.screenWidth - mainButtonSize.x - 100, ui.screenHeight/2 - (buttons * mainButtonSize.y)/2 - (2*mainButtonSize.y)/2 - 8)
191
192	ui.setNextWindowPos(Vector2(110,65),'Always')
193	ui.withStyleColors({["WindowBg"]=colors.transparent}, function()
194		ui.window("headingWindow", overlayWindowFlags, function()
195			ui.withFont("orbiteer",36 * (ui.screenHeight/1200),function() ui.text("Pioneer") end)
196		end)
197	end)
198	if Engine.IsIntroZooming() then
199		ui.setNextWindowPos(Vector2(0,0),'Always')
200		ui.setNextWindowSize(Vector2(ui.screenWidth, ui.screenHeight), 'Always')
201		ui.withStyleColors({["WindowBg"]=colors.transparent}, function()
202			ui.window("shipinfoWindow", overlayWindowFlags, function()
203				local mn = Engine.GetIntroCurrentModelName()
204				if mn then
205					local sd = ShipDef[mn]
206					if sd then
207						ui.addFancyText(Vector2(ui.screenWidth / 3, ui.screenHeight / 5.0 * 4), ui.anchor.center, ui.anchor.bottom, {{text=sd.name, color=colors.white, font=orbiteer.medlarge}}, colors.transparent)
208						ui.addFancyText(Vector2(ui.screenWidth / 3, ui.screenHeight / 5.0 * 4.02), ui.anchor.center, ui.anchor.top, {{text=lui[sd.shipClass:upper()], color=colors.white, font=orbiteer.medium}}, colors.transparent)
209					end
210				end
211			end)
212		end)
213	end
214	local build_text = Engine.version
215	ui.withFont("orbiteer", 16 * (ui.screenHeight/1200),
216		function()
217			ui.setNextWindowPos(Vector2(ui.screenWidth - ui.calcTextSize(build_text).x * 1.2,ui.screenHeight - 50), 'Always')
218			ui.withStyleColors({["WindowBg"] = colors.transparent}, function()
219				ui.window("buildLabel", overlayWindowFlags, function()
220					ui.text(build_text)
221				end)
222			end)
223	end)
224
225	ui.setNextWindowPos(winPos,'Always')
226	ui.setNextWindowSize(Vector2(0,0), 'Always')
227	ui.withStyleColors({["WindowBg"] = colors.lightBlackBackground}, function()
228		ui.window("MainMenuButtons", mainMenuFlags, function()
229			mainTextButton(lui.CONTINUE_GAME, nil, showContinue, continueGame)
230
231			for _,loc in pairs(startLocations) do
232				local desc = loc.desc .. "\n"
233				local name = loc.shipType
234				local sd = ShipDef[loc.shipType]
235				if sd then
236					name = sd.name
237				end
238				desc = desc .. lc.SHIP .. ": " .. name .. "\n"
239				desc = desc .. lui.CREDITS .. ": "  .. Format.Money(loc.money) .. "\n"
240				desc = desc .. lui.HYPERDRIVE .. ": " .. (loc.hyperdrive and lui.YES or lui.NO) .. "\n"
241				desc = desc .. lui.EQUIPMENT .. ":\n"
242				for _,eq in pairs(loc.equipment) do
243					local equipname = rawget(elc, eq[1].l10n_key) or rawget(clc, eq[1].l10n_key)
244					desc = desc .. "  - " .. equipname
245					if eq[2] > 1 then
246						desc = desc .. " x" .. eq[2] .. "\n"
247					else desc = desc .. "\n"
248					end
249				end
250				mainTextButton(loc.name, desc, true, function() startAtLocation(loc) end)
251			end
252
253			mainTextButton(lui.LOAD_GAME, nil, true, function()
254				ui.saveLoadWindow.mode = "LOAD"
255				ui.saveLoadWindow:open()
256			end)
257
258			mainTextButton(lui.OPTIONS, nil, true, showOptions)
259			mainTextButton(lui.QUIT, nil, true, quitGame)
260
261			if showQuitConfirm then confirmQuit() end
262		end)
263	end)
264
265	callModules('mainMenu')
266	callModules('modal')
267end -- showMainMenu
268
269ui.registerHandler('mainMenu',function(delta)
270	showMainMenu()
271end)
272