1--       _________ __                 __
2--      /   _____//  |_____________ _/  |______     ____  __ __  ______
3--      \_____  \\   __\_  __ \__  \\   __\__  \   / ___\|  |  \/  ___/
4--      /        \|  |  |  | \// __ \|  |  / __ \_/ /_/  >  |  /\___ \
5--     /_______  /|__|  |__|  (____  /__| (____  /\___  /|____//____  >
6--             \/                  \/          \//_____/            \/
7--  ______________________                           ______________________
8--                        T H E   W A R   B E G I N S
9--         Stratagus - A free fantasy real time strategy game engine
10--
11--      (c) Copyright 2014-2019 by Andrettin
12--
13--      This program is free software; you can redistribute it and/or modify
14--      it under the terms of the GNU General Public License as published by
15--      the Free Software Foundation; either version 2 of the License, or
16--      (at your option) any later version.
17--
18--      This program is distributed in the hope that it will be useful,
19--      but WITHOUT ANY WARRANTY; without even the implied warranty of
20--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21--      GNU General Public License for more details.
22--
23--      You should have received a copy of the GNU General Public License
24--      along with this program; if not, write to the Free Software
25--      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26--
27
28RunningScenario = false
29QuestWorlds = {"~!Earth", "~!Nidavellir"}
30
31function RunQuestWorldMenu()
32	SetPlayerData(GetThisPlayer(), "RaceName", "gnome")
33
34	if not (IsMusicPlaying()) then
35		PlayMusicName("MenuTheme")
36	end
37
38	local menu = WarMenu()
39	local offx = (Video.Width - 640) / 2
40	local offy = (Video.Height - 480) / 2
41
42	menu:addLabel(_("~<Quests~>"), offx + 320, offy + 212 - 25 - (36 * 1))
43
44	local quest_world_y = 2
45	for i=1, table.getn(QuestWorlds) do
46		local quest_world_hotkey = ""
47		if (string.find(QuestWorlds[i], "~!") ~= nil) then
48			quest_world_hotkey = string.sub(string.match(_(QuestWorlds[i]), "~!%a"), 3)
49			quest_world_hotkey = string.lower(quest_world_hotkey)
50		end
51		local quest_world_name = string.gsub(QuestWorlds[i], "~!", "")
52		quest_world_name = string.lower(quest_world_name)
53
54		menu:addFullButton(_(QuestWorlds[i]), quest_world_hotkey, offx + 208, offy + 104 + 36*quest_world_y,
55		function()
56			RunQuestMenu(quest_world_name);
57			if (RunningScenario) then
58				menu:stop()
59			end
60		end)
61
62		quest_world_y = quest_world_y + 1
63	end
64
65	menu:addFullButton(_("~!Previous Menu"), "p", offx + 208, offy + 104 + 36*quest_world_y,
66		function() menu:stop() end
67	)
68	return menu:run()
69end
70
71function RunQuestMenu(world)
72	SetPlayerData(GetThisPlayer(), "RaceName", "gnome")
73
74	if not (IsMusicPlaying()) then
75		PlayMusicName("MenuTheme")
76	end
77
78	local no_randomness
79	local no_time_of_day
80	local menu = WarMenu()
81	local offx = (Video.Width - 640) / 2
82	local offy = (Video.Height - 480) / 2
83
84	RunningScenario = false
85
86	menu:addLabel(_("~<Quests~>"), offx + 320, offy + 104 + 36*-2)
87
88	local completed_quest_quantity = 0
89	local total_quest_quantity = 0
90	local item_x = 1
91	local item_y = 1
92	local quests = GetQuests()
93	for i=1, table.getn(quests) do
94		if (GetQuestData(quests[i], "Hidden") == false and GetQuestData(quests[i], "World") == world and GetQuestData(quests[i], "Map") ~= "") then
95			total_quest_quantity = total_quest_quantity + 1
96			if (GetQuestData(quests[i], "RequiredQuest") == "" or GetQuestData(GetQuestData(quests[i], "RequiredQuest"), "Completed") or GetQuestData(quests[i], "Completed")) then
97				addQuestIcon(quests[i], menu, offx + 23 + 4 + (54 * item_x), offy + 10 + 4 + (46 * (item_y + 1))) -- increase Y by 1 because there are few enough quests that it makes sense to make the existing quests more centralized in the interface
98
99				item_x = item_x + 1
100				if (item_x > 9) then
101					item_x = 1
102					item_y = item_y + 1
103				end
104				if (GetQuestData(quests[i], "Completed")) then
105					completed_quest_quantity = completed_quest_quantity + 1
106				end
107			end
108		end
109	end
110
111	--[[
112	local quest_completion_percent = completed_quest_quantity * 100 / total_quest_quantity
113	local badge_icon
114	if (quest_completion_percent == 100) then
115		badge_icon = CGraphic:New("ui/icons/badge_foil.png")
116	elseif (quest_completion_percent >= 80) then
117		badge_icon = CGraphic:New("ui/icons/badge_gold.png")
118	elseif (quest_completion_percent >= 60) then
119		badge_icon = CGraphic:New("ui/icons/badge_silver.png")
120	elseif (quest_completion_percent >= 40) then
121		badge_icon = CGraphic:New("ui/icons/badge_bronze.png")
122	elseif (quest_completion_percent >= 20) then
123		badge_icon = CGraphic:New("ui/icons/badge_glow.png")
124	else
125		badge_icon = CGraphic:New("ui/icons/badge_cracked.png")
126	end
127	badge_icon:Load()
128	local b = ImageWidget(badge_icon)
129	menu:add(b, (Video.Width / 2) - (badge_icon:getWidth() / 2), (Video.Height / 2) - (badge_icon:getHeight() / 2))
130	b:setTooltip(completed_quest_quantity .. "/" .. total_quest_quantity .. " Quests Completed")
131	--]]
132	menu:addLabel(completed_quest_quantity .. "/" .. total_quest_quantity .. _(" Quests Completed"), Video.Width / 2, Video.Height / 2, Fonts["game"], true)
133
134	no_randomness = menu:addImageCheckBox(_("No Randomness"), offx + 480, offy + 10 + 270 + 3,
135		function()
136			wyr.preferences.NoRandomness = no_randomness:isMarked()
137			SavePreferences()
138		end
139	)
140	no_randomness:setMarked(wyr.preferences.NoRandomness)
141
142	no_time_of_day = menu:addImageCheckBox(_("No Day/Night Cycle"), offx + 480, offy + 10 + 300 + 3,
143		function()
144			wyr.preferences.NoTimeOfDay = no_time_of_day:isMarked()
145			SavePreferences()
146		end
147	)
148	no_time_of_day:setMarked(wyr.preferences.NoTimeOfDay)
149
150	local difficulty_list = {_("Easy"), _("Normal"), _("Hard"),_("Brutal")}
151	local difficulty = nil
152
153	menu:addLabel(_("Difficulty:"), offx + 244, offy + (10 + 300) - 20, Fonts["game"], false)
154	difficulty = menu:addDropDown(difficulty_list, offx + 244, offy + 10 + 300,
155		function(dd)
156			wyr.preferences.Difficulty = difficulty:getSelected() + 1
157			SavePreferences()
158		end
159	)
160	difficulty:setSize(152, 20)
161	difficulty:setSelected(wyr.preferences.Difficulty - 1)
162
163	local custom_heroes = GetCustomHeroes()
164	local hero_list = {}
165	local hero_name_list = {}
166	for i=1,table.getn(custom_heroes) do
167		if (
168			(world == "earth" and (GetCustomHeroData(custom_heroes[i], "Civilization") == "germanic" or GetCustomHeroData(custom_heroes[i], "Civilization") == "anglo-saxon" or GetCustomHeroData(custom_heroes[i], "Civilization") == "english" or GetCustomHeroData(custom_heroes[i], "Civilization") == "frankish" or GetCustomHeroData(custom_heroes[i], "Civilization") == "goth" or GetCustomHeroData(custom_heroes[i], "Civilization") == "suebi" or GetCustomHeroData(custom_heroes[i], "Civilization") == "teuton" or GetCustomHeroData(custom_heroes[i], "Civilization") == "norse" or GetCustomHeroData(custom_heroes[i], "Civilization") == "latin"))
169			or (world == "nidavellir" and GetCustomHeroData(custom_heroes[i], "Civilization") == "dwarf")
170			or (world == "nidavellir" and GetCustomHeroData(custom_heroes[i], "Civilization") == "gnome")
171			or (world == "nidavellir" and GetCustomHeroData(custom_heroes[i], "Civilization") == "goblin")
172		) then
173			table.insert(hero_list, custom_heroes[i])
174		end
175	end
176	local hero_dd
177	table.sort(hero_list)
178	for i=1,table.getn(hero_list) do
179		table.insert(hero_name_list, GetCustomHeroData(hero_list[i], "FullName"))
180	end
181	table.insert(hero_list, "") -- to allow players to choose having no custom hero selected
182	table.insert(hero_name_list, "")
183	menu:addLabel(_("Custom Hero:"), offx + 30, offy + (10 + 300) - 20, Fonts["game"], false)
184	hero_dd = menu:addDropDown(hero_name_list, offx + 30, offy + 10 + 300,
185		function(dd)
186			SetCurrentCustomHero(hero_list[hero_dd:getSelected() + 1])
187			menu:stop()
188			RunQuestMenu(world)
189		end
190	)
191	hero_dd:setSize(152, 20)
192	hero_dd:setSelected(GetElementIndexFromArray(hero_list, GetCurrentCustomHero()) - 1)
193
194	menu:addFullButton(_("Create Custom ~!Hero"), "h", offx + 208, offy + 212 + (36 * 4),
195		function() CustomHeroCreationMenu(world, menu);
196		end
197	)
198
199	menu:addFullButton(_("~!Delete Custom Hero"), "d", offx + 208 + 226, offy + 212 + (36 * 4),
200		function()
201			if (GetCurrentCustomHero() ~= "") then
202				local confirm = WarGameMenu(panel(4))
203
204				confirm:resize(288,128)
205
206				confirm:addLabel(_("Delete ") .. GetCurrentCustomHero(), 288 / 2, 11)
207				confirm:addLabel(_("Are you sure?") .. " This cannot be undone.", 288 / 2, 45, Fonts["game"])
208
209				confirm:addHalfButton(_("~!Yes"), "y", 1 * (288 / 3) - 90, 120 - 16 - 27,
210					function()
211						DeleteCustomHero(GetCurrentCustomHero())
212						confirm:stop()
213						menu:stop(); RunQuestMenu(world);
214					end
215				)
216
217				confirm:addHalfButton(_("~!No"), "n", 3 * (288 / 3) - 116, 120 - 16 - 27,
218					function() confirm:stop() end
219				)
220
221				confirm:run()
222			end
223		end
224	)
225
226	menu:addFullButton(_("~!Previous Menu"), "p", offx + 208, offy + 212 + (36 * 5),
227		function()
228			SetCurrentCustomHero("")
229			menu:stop();
230		end
231	)
232
233	menu:run()
234end
235
236function addQuestIcon(quest, menu, x, y)
237	local quest_icon_frame = CIcon:Get(GetQuestData(quest, "Icon")).Frame
238	local questicon
239	local b
240	if (GetQuestData(quest, "Completed")) then
241		questicon = CIcon:Get(GetQuestData(quest, "Icon")).GScale
242	else
243		questicon = CIcon:Get(GetQuestData(quest, "Icon")).G
244	end
245	b = PlayerColorImageButton("", GetQuestData(quest, "PlayerColor"))
246	local quest_icon_x_origin = (quest_icon_frame * 46) % questicon:getGraphicWidth()
247	local quest_icon_y_origin = math.floor((quest_icon_frame * 46) / questicon:getGraphicWidth()) * 38
248	b:setActionCallback(
249		function()
250			PlaySound("click")
251
252			local quest_menu = WarGameMenu(panel(5))
253			quest_menu:setSize(352, 352)
254    		quest_menu:setPosition((Video.Width - quest_menu:getWidth()) / 2, (Video.Height - quest_menu:getHeight()) / 2)
255			quest_menu:addLabel(_(GetQuestData(quest, "Name")), 176, 11)
256			local quest_menu_image = PlayerColorImageWidget(questicon, GetQuestData(quest, "PlayerColor"))
257			quest_menu_image:setImageOrigin(quest_icon_x_origin, quest_icon_y_origin)
258			quest_menu:add(quest_menu_image, 153, 48)
259
260			local l = MultiLineLabel()
261			l:setFont(Fonts["game"])
262			l:setSize(324, 208)
263			l:setLineWidth(324)
264			quest_menu:add(l, 14, 112)
265			local quest_description = _(GetQuestData(quest, "Description"))
266			l:setCaption(quest_description)
267
268			if (GetQuestData(quest, "Map") ~= "") then
269				quest_menu:addFullButton(_("~!Play Quest"), "p", 176 - (224 / 2), 352 - 40 * 2,
270					function()
271						RunningScenario = true
272						SetCurrentQuest(quest)
273						GetMapInfo(GetQuestData(quest, "Map"))
274						for i=1,mapinfo.nplayers do
275							if ((i - 1) ~= MapPersonPlayer and mapinfo.playertypes[i] == "person") then
276								GameSettings.Presets[i-1].Type = PlayerComputer
277							end
278						end
279						GameSettings.NoRandomness = wyr.preferences.NoRandomness
280						GameSettings.NoTimeOfDay = wyr.preferences.NoTimeOfDay
281						GameSettings.Difficulty = wyr.preferences.Difficulty
282						if (GetQuestData(quest, "Briefing") ~= "") then
283							Briefing(quest)
284						end
285						mapname = GetQuestData(quest, "Map")
286						quest_menu:stop()
287						RunMap(mapname)
288						menu:stop()
289						if not (LoadGameFile) then
290							RunQuestMenu(GetQuestData(quest, "World"))
291						end
292					end
293				)
294			end
295			quest_menu:addFullButton(_("~!Close"), "c", 176 - (224 / 2), 352 - 40 * 1,
296				function()
297					quest_menu:stop()
298				end
299			)
300			quest_menu:run()
301		end
302	)
303	menu:add(b, x, y)
304	b:setImageOrigin(quest_icon_x_origin, quest_icon_y_origin)
305	b:setNormalImage(questicon)
306	b:setPressedImage(questicon)
307	b:setDisabledImage(questicon)
308	b:setSize(46, 38)
309	b:setBorderSize(0) -- Andrettin: make buttons not have the borders they previously had
310	b:setFrameImage(Preference.IconFrameG)
311	b:setPressedFrameImage(Preference.PressedIconFrameG)
312	local tooltip = _(GetQuestData(quest, "Name")) .. " (" .. GetCivilizationData(GetQuestData(quest, "Civilization"), "Display") .. ")"
313	if (GetQuestData(quest, "HighestCompletedDifficulty") >= DifficultyEasy) then
314		tooltip = tooltip .. "\nHighest Completed Difficulty: "
315		if (GetQuestData(quest, "HighestCompletedDifficulty") == DifficultyEasy) then
316			tooltip = tooltip .. _("Easy")
317		elseif (GetQuestData(quest, "HighestCompletedDifficulty") == DifficultyNormal) then
318			tooltip = tooltip .. _("Normal")
319		elseif (GetQuestData(quest, "HighestCompletedDifficulty") == DifficultyHard) then
320			tooltip = tooltip .. _("Hard")
321		elseif (GetQuestData(quest, "HighestCompletedDifficulty") == DifficultyBrutal) then
322			tooltip = tooltip .. _("Brutal")
323		end
324	end
325	b:setTooltip(tooltip)
326	return b
327end
328
329function Briefing(quest)
330	if (GetQuestData(quest, "Civilization") ~= "") then
331		SetPlayerData(GetThisPlayer(), "RaceName", GetQuestData(quest, "Civilization"))
332	end
333
334	local briefing_background = GetBackground("ui/backgrounds/wyrm.png")
335	if (GetQuestData(quest, "BriefingBackground") ~= "") then
336		briefing_background = GetBackground(GetQuestData(quest, "BriefingBackground"))
337	end
338
339	local menu = WarMenu(nil, briefing_background)
340
341	if (GetQuestData(quest, "BriefingMusic") ~= "") then
342		PlayMusic(GetQuestData(quest, "BriefingMusic"))
343	else
344		StopMusic()
345	end
346
347	menu:addLabel(quest, Video.Width / 2, 28 * Video.Height / 480, Fonts["large"], true)
348
349	local t = GetQuestData(quest, "Briefing")
350	t = "\n\n\n\n\n\n\n\n\n\n" .. t .. "\n\n\n\n\n\n\n\n\n\n\n\n\n"
351	local sw = ScrollingWidget(320, 170 * Video.Height / 480)
352	sw:setBackgroundColor(Color(0,0,0,0))
353	sw:setSpeed(0.28)
354	local l = MultiLineLabel(t)
355	l:setFont(Fonts["large"])
356	l:setAlignment(MultiLineLabel.LEFT)
357	l:setVerticalAlignment(MultiLineLabel.TOP)
358	l:setLineWidth(320)
359	l:adjustSize()
360	sw:add(l, 0, 0)
361	menu:add(sw, Video.Width / 2 - (l:getWidth() / 2), 80 * Video.Height / 480)
362
363	if (table.getn(GetQuestData(quest, "Objectives")) > 0) then
364		menu:addLabel(_("Objectives:"), 372 * Video.Width / 640, 306 * Video.Height / 480, Fonts["large"], false)
365
366		local objectives = ""
367		table.foreachi(GetQuestData(quest, "Objectives"), function(k,v) objectives = objectives .. v .. "\n" end)
368
369		local l = MultiLineLabel(objectives)
370		l:setFont(Fonts["large"])
371		l:setAlignment(MultiLineLabel.LEFT)
372		l:setLineWidth(250 * Video.Width / 640)
373		l:adjustSize()
374		menu:add(l, 372 * Video.Width / 640, (306 * Video.Height / 480) + 30)
375	end
376
377	local voice = 0
378	local channel = -1
379
380	menu:addFullButton(_("~!Continue"), "c", Video.Width / 2 - 112, 440 * Video.Height / 480,
381		function()
382			if (table.getn(GetQuestData(quest, "BriefingSounds")) > 0) then
383				if (channel ~= -1) then
384					voice = table.getn(GetQuestData(quest, "BriefingSounds"))
385					StopChannel(channel)
386				end
387			end
388			menu:stop()
389			StopMusic()
390		end
391	)
392
393	if (table.getn(GetQuestData(quest, "BriefingSounds")) > 0) then
394		function PlayNextVoice()
395			voice = voice + 1
396			if (voice <= table.getn(GetQuestData(quest, "BriefingSounds"))) then
397				channel = PlaySoundFile(GetQuestData(quest, "BriefingSounds")[voice], PlayNextVoice);
398			else
399				channel = -1
400			end
401		end
402		PlayNextVoice()
403	end
404
405	menu:run()
406end
407