note
	description: "[
		m_menu.c
		DOOM selection menu, options, episodes etc.
		Sliders and icons. Kinda widget stuff.
	]"
	license: "[
		Copyright (C) 1993-1996 by id Software, Inc.
		Copyright (C) 2005-2014 Simon Howard
		Copyright (C) 2021 Ilgiz Mustafin
		
		This program is free software; you can redistribute it and/or modify
		it under the terms of the GNU General Public License as published by
		the Free Software Foundation; either version 2 of the License, or
		(at your option) any later version.
		
		This program is distributed in the hope that it will be useful,
		but WITHOUT ANY WARRANTY; without even the implied warranty of
		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
		GNU General Public License for more details.
		
		You should have received a copy of the GNU General Public License along
		with this program; if not, write to the Free Software Foundation, Inc.,
		51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
	]"

class 
	M_MENU

create 
	make

feature 

	i_main: I_MAIN

	make (a_i_main: like i_main)
		do
			i_main := a_i_main
			messagestring := ""
			itemon := 1
		end
	
feature -- defaulted values

	mousesensitivity: INTEGER_32 assign set_mousesensitivity
			-- has default

	set_mousesensitivity (a_mousesensitivity: like mousesensitivity)
		do
			mousesensitivity := a_mousesensitivity
		end

	showmessages: INTEGER_32 assign set_showmessages
			-- Show messages has default, 0 = off, 1 = on

	set_showmessages (a_showmessages: like showmessages)
		do
			showmessages := a_showmessages
		end

	detaillevel: INTEGER_32 assign set_screenblocks
			-- Blocky mode, has default, 0 = high, 1 = normal

	set_detaillevel (a_detaillevel: like detaillevel)
		do
			detaillevel := a_detaillevel
		end

	screenblocks: INTEGER_32 assign set_screenblocks

	set_screenblocks (a_screenblocks: like screenblocks)
		do
			screenblocks := a_screenblocks
		end
	
feature 

	Lineheight: INTEGER_32 = 16

	Skullxoff: INTEGER_32 = -32

	Skullname: ARRAY [STRING_8]
		once
			create Result.make_filled ("", 0, 1)
			Result [0] := "M_SKULL1"
			Result [1] := "M_SKULL2"
		end
	
feature -- main_e

	Newgame: INTEGER_32 = 0

	Options: INTEGER_32 = 1

	Loadgame: INTEGER_32 = 2

	Savegame: INTEGER_32 = 3

	Readthis: INTEGER_32 = 4

	Quitdoom: INTEGER_32 = 5

	Main_end: INTEGER_32 = 6
	
feature -- newgame_e

	Killthings: INTEGER_32 = 0

	Toorough: INTEGER_32 = 1

	Hurtme: INTEGER_32 = 2

	Violence: INTEGER_32 = 3

	Nightmare: INTEGER_32 = 4

	Newg_end: INTEGER_32 = 5
	
feature 

	currentmenu: detachable MENU_T

	Maindef: MENU_T
		once
			create Result.make (Main_end, Void, Mainmenu, agent m_drawmainmenu, 97, 64, 1)
		end

	Newgamemenu: ARRAY [MENUITEM_T]
		once
			Result := <<create {MENUITEM_T}.make (1, "M_JKILL", agent m_chooseskill, 'i'), create {MENUITEM_T}.make (1, "M_ROUGH", agent m_chooseskill, 'h'), create {MENUITEM_T}.make (1, "M_HURT", agent m_chooseskill, 'h'), create {MENUITEM_T}.make (1, "M_ULTRA", agent m_chooseskill, 'u'), create {MENUITEM_T}.make (1, "M_NMARE", agent m_chooseskill, 'n')>>
		end

	Newdef: MENU_T
		once
			create Result.make (Newg_end, Epidef, Newgamemenu, agent m_drawnewgame, 48, 63, Hurtme + 1)
		end

	Mainmenu: ARRAY [MENUITEM_T]
		once
			Result := <<create {MENUITEM_T}.make (1, "M_NGAME", agent m_newgame, 'n'), create {MENUITEM_T}.make (1, "M_OPTION", agent m_options, 'o'), create {MENUITEM_T}.make (1, "M_LOADG", agent m_loadgame, 'l'), create {MENUITEM_T}.make (1, "M_SAVEG", agent m_savegame, 's'), create {MENUITEM_T}.make (1, "M_RDTHIS", agent m_readthis, 'r'), create {MENUITEM_T}.make (1, "M_QUITG", agent m_quitdoom, 'q')>>
		end

	inhelpscreens: BOOLEAN

	menuactive: BOOLEAN

	itemon: INTEGER_32
			-- menu item skull is on

	whichskull: INTEGER_32
			-- which skull to draw

	skullanimcounter: INTEGER_32
			-- skull animation counter

	screensize: INTEGER_32
			-- temp for screenblocks (0-9)

	messagetoprint: BOOLEAN
			-- (was int) 1 = message to be printed

	messagestring: STRING_8
			-- ...and here is the message string!

	messagelastmenuactive: BOOLEAN
			-- (was int)

	messageroutine: detachable PROCEDURE [INTEGER_32]

	messageneedsinput: BOOLEAN
			-- timed message = no input from user

	quicksaveslot: INTEGER_32
			-- -1 = no quicksave slot picked!
	
feature -- Read This! MENU 1 & 2

	Rdthssempty1: INTEGER_32 = 0

	Read1_end: INTEGER_32 = 1

	Readmenu1: ARRAY [MENUITEM_T]
		once
			Result := <<create {MENUITEM_T}.make (1, "", agent m_readthis2, '0')>>
		end

	Readdef1: MENU_T
		once
			create Result.make (Read1_end, Maindef, Readmenu1, agent m_drawreadthis1, 280, 185, 1)
		end

	Rdthsempty2: INTEGER_32 = 0

	Read2_end: INTEGER_32 = 1

	Readmenu2: ARRAY [MENUITEM_T]
		once
			Result := <<create {MENUITEM_T}.make (1, "", agent m_finishreadthis, '0')>>
		end

	Readdef2: MENU_T
		once
			create Result.make (Read2_end, Readdef1, Readmenu2, agent m_drawreadthis2, 330, 175, 0)
		end
	
feature -- Read This Menus (Had a "quick hack to fix romero bug")

	m_drawreadthis1
		local
			gamemode: GAME_MODE_T
		do
			inhelpscreens := True
			gamemode := i_main.Doomstat_h.gamemode
			if gamemode = {GAME_MODE_T}.commercial then
				i_main.V_video.v_drawpatchdirect (0, 0, create {PATCH_T}.from_pointer (i_main.W_wad.w_cachelumpname ("HELP")))
			elseif gamemode = {GAME_MODE_T}.shareware or gamemode = {GAME_MODE_T}.registered or gamemode = {GAME_MODE_T}.retail then
				i_main.V_video.v_drawpatchdirect (0, 0, create {PATCH_T}.from_pointer (i_main.W_wad.w_cachelumpname ("HELP1")))
			end
		end

	m_drawreadthis2
		local
			gamemode: GAME_MODE_T
		do
			inhelpscreens := True
			gamemode := i_main.Doomstat_h.gamemode
			if gamemode = {GAME_MODE_T}.retail or gamemode = {GAME_MODE_T}.commercial then
				i_main.V_video.v_drawpatchdirect (0, 0, create {PATCH_T}.from_pointer (i_main.W_wad.w_cachelumpname ("CREDIT")))
			elseif gamemode = {GAME_MODE_T}.shareware or gamemode = {GAME_MODE_T}.registered then
				i_main.V_video.v_drawpatchdirect (0, 0, create {PATCH_T}.from_pointer (i_main.W_wad.w_cachelumpname ("HELP2")))
			end
		end
	
feature 

	m_finishreadthis (choice: INTEGER_32)
		do
			{NOT_IMPLEMENTED}.not_implemented ("M_FinishReadThis", False)
		end

	m_drawepisode
		do
			i_main.V_video.v_drawpatchdirect (54, 38, create {PATCH_T}.from_pointer (i_main.W_wad.w_cachelumpname ("M_EPISOD")))
		end

	m_readthis2 (choice: INTEGER_32)
		do
			{NOT_IMPLEMENTED}.not_implemented ("M_ReadThis2", False)
		end

	m_newgame (choice: INTEGER_32)
		do
			if i_main.G_game.netgame and not i_main.G_game.demoplayback then
				m_startmessage ({D_ENGLSH}.newgame, Void, False)
			else
				if i_main.Doomstat_h.gamemode = {GAME_MODE_T}.commercial then
					m_setupnextmenu (Newdef)
				else
					m_setupnextmenu (Epidef)
				end
			end
		end

	m_options (choice: INTEGER_32)
		do
			{NOT_IMPLEMENTED}.not_implemented ("M_Options", False)
		end

	m_loadgame (choice: INTEGER_32)
		do
			{NOT_IMPLEMENTED}.not_implemented ("M_LoadGame", False)
		end

	m_savegame (choice: INTEGER_32)
		do
			{NOT_IMPLEMENTED}.not_implemented ("M_SaveGame", False)
		end

	m_readthis (choice: INTEGER_32)
		do
			{NOT_IMPLEMENTED}.not_implemented ("M_ReadThis", False)
		end

	m_quitdoom (choice: INTEGER_32)
		do
			{NOT_IMPLEMENTED}.not_implemented ("M_QuitDOOM", False)
			i_main.I_system.i_quit
		end

	m_drawnewgame
		do
			i_main.V_video.v_drawpatchdirect (96, 14, create {PATCH_T}.from_pointer (i_main.W_wad.w_cachelumpname ("M_NEWG")))
			i_main.V_video.v_drawpatchdirect (54, 38, create {PATCH_T}.from_pointer (i_main.W_wad.w_cachelumpname ("M_SKILL")))
		end

	m_chooseskill (a_choice: INTEGER_32)
		local
			choice: INTEGER_32
		do
			choice := a_choice - 1
			if choice = Nightmare then
				m_startmessage ({D_ENGLSH}.nightmare, agent m_verifynightmare, True)
			else
				i_main.G_game.g_deferedinitnew (choice, epi + 1, 1)
				m_clearmenus
			end
		end

	m_verifynightmare (ch: INTEGER_32)
		do
			if ch = ('y').code then
				i_main.G_game.g_deferedinitnew (Nightmare, epi + 1, 1)
				m_clearmenus
			end
		end

	m_drawmainmenu
		do
			i_main.V_video.v_drawpatchdirect (94, 2, create {PATCH_T}.from_pointer (i_main.W_wad.w_cachelumpname ("M_DOOM")))
		end
	
feature 

	m_clearmenus
		do
			menuactive := False
		end
	
feature 

	m_startmessage (string: STRING_8; routine: like messageroutine; input: BOOLEAN)
		do
			messagelastmenuactive := menuactive
			messagetoprint := True
			messagestring := string
			messageroutine := routine
			messageneedsinput := input
			menuactive := True
		end
	
feature 

	m_setupnextmenu (menudef: MENU_T)
		do
			currentmenu := menudef
			itemon := menudef.laston
		end
	
feature -- EPISODE SELECT

	Ep1: INTEGER_32 = 0

	Ep2: INTEGER_32 = 1

	Ep3: INTEGER_32 = 2

	Ep4: INTEGER_32 = 3

	Ep_end: INTEGER_32 = 4

	Episodemenu: ARRAY [MENUITEM_T]
		once
			Result := <<create {MENUITEM_T}.make (1, "M_EPI1", agent m_episode, 'k'), create {MENUITEM_T}.make (1, "M_EPI2", agent m_episode, 't'), create {MENUITEM_T}.make (1, "M_EPI3", agent m_episode, 'i'), create {MENUITEM_T}.make (1, "M_EPI4", agent m_episode, 't')>>
		end

	Epidef: MENU_T
		once
			create Result.make (Ep_end, Maindef, Episodemenu, agent m_drawepisode, 48, 63, 1)
		end
	
feature -- M_Episode

	epi: INTEGER_32

	m_episode (a_choice: INTEGER_32)
		local
			choice: INTEGER_32
		do
			choice := a_choice - 1
			if i_main.Doomstat_h.gamemode = {GAME_MODE_T}.shareware and choice /= 0 then
				m_startmessage ({D_ENGLSH}.swstring, Void, False)
				m_setupnextmenu (Readdef1)
			else
				if i_main.Doomstat_h.gamemode = {GAME_MODE_T}.registered and choice > 2 then
					print ("M_Episode: 4th episode requires UltimateDOOM%N")
					choice := 0
				end
				epi := choice
				m_setupnextmenu (Newdef)
			end
		end
	
feature 

	savestringenter: BOOLEAN
			-- we are going to be entering a savegame string
	
feature -- CONTROL PANEL

	m_responder (ev: EVENT_T): BOOLEAN
		local
			ch: INTEGER_32
		do
			{NOT_IMPLEMENTED}.not_implemented ("M_Responder", False)
			if ev.type = ev.Ev_quit then
				i_main.S_sound.s_startsound (Void, {SOUNDS_H}.sfx_swtchn)
				m_quitdoom (0)
			end
			ch := -1
			if ev.type = ev.Ev_keydown then
				ch := ev.data1
			end
			if ch /= -1 then
				if savestringenter then
				elseif messagetoprint then
				elseif False then
				elseif not menuactive then
					if ch = {DOOMDEF_H}.key_escape then
						m_startcontrolpanel
						i_main.S_sound.s_startsound (Void, {SOUNDS_H}.sfx_swtchn)
						Result := True
					else
						Result := False
					end
				else
					if attached currentmenu as currentmenuattached then
						if ch = {DOOMDEF_H}.key_downarrow then
							from
								if itemon >= currentmenuattached.numitems then
									itemon := 1
								else
									itemon := itemon + 1
								end
								i_main.S_sound.s_startsound (Void, {SOUNDS_H}.sfx_pstop)
							until
								currentmenuattached.menuitems [itemon].status /= -1
							loop
								if itemon + 1 > currentmenuattached.numitems - 1 then
									itemon := 0
								else
									itemon := itemon + 1
								end
								i_main.S_sound.s_startsound (Void, {SOUNDS_H}.sfx_pstop)
							end
							Result := True
						elseif ch = {DOOMDEF_H}.key_uparrow then
							from
								if itemon = 1 then
									itemon := currentmenuattached.numitems
								else
									itemon := itemon - 1
								end
								i_main.S_sound.s_startsound (Void, {SOUNDS_H}.sfx_pstop)
							until
								currentmenuattached.menuitems [itemon].status /= -1
							loop
								if itemon = 0 then
									itemon := currentmenuattached.numitems - 1
								else
									itemon := itemon - 1
								end
								i_main.S_sound.s_startsound (Void, {SOUNDS_H}.sfx_pstop)
							end
							Result := True
						elseif ch = {DOOMDEF_H}.key_enter then
							if currentmenuattached.menuitems [itemon].status /= 0 then
								currentmenuattached.laston := itemon
								if currentmenuattached.menuitems [itemon].status = 2 then
									currentmenuattached.menuitems [itemon].routine.call (1)
									i_main.S_sound.s_startsound (Void, {SOUNDS_H}.sfx_stnmov)
								else
									currentmenuattached.menuitems [itemon].routine (itemon)
									i_main.S_sound.s_startsound (Void, {SOUNDS_H}.sfx_pistol)
								end
							end
						end
					end
				end
			end
		end
	
feature 

	m_init
		do
			currentmenu := Maindef
			menuactive := False
			if attached currentmenu as c then
				itemon := c.laston
			end
			whichskull := 0
			skullanimcounter := 10
			screensize := screenblocks - 3
			messagetoprint := False
			messagelastmenuactive := menuactive
			quicksaveslot := -1
			if i_main.Doomstat_h.gamemode = {GAME_MODE_T}.commercial then
				Mainmenu [Readthis] := Mainmenu [Quitdoom]
				Maindef.numitems := Maindef.numitems - 1
				Maindef.y := Maindef.y + 8
				Newdef.prevmenu := Maindef
				Readdef1.routine := agent m_drawreadthis1
				Readdef1.x := 330
				Readdef1.y := 165
				Readmenu1 [0].routine := agent m_finishreadthis
			elseif i_main.Doomstat_h.gamemode = {GAME_MODE_T}.shareware then
				Epidef.numitems := Epidef.numitems - 1
			elseif i_main.Doomstat_h.gamemode = {GAME_MODE_T}.registered then
				Epidef.numitems := Epidef.numitems - 1
			end
		end
	
feature 

	m_ticker
		do
			skullanimcounter := skullanimcounter - 1
			if skullanimcounter <= 0 then
				whichskull := whichskull.bit_xor (1)
				skullanimcounter := 8
			end
		end
	
feature -- M_Drawer

	x: INTEGER_32

	y: INTEGER_32

	m_drawer
			-- Called after the view has been rendered,
			-- but before it has been blitted.
		local
			i: INTEGER_32
			max: INTEGER_32
		do
			{NOT_IMPLEMENTED}.not_implemented ("M_Drawer", False)
			inhelpscreens := False
			if messagetoprint then
			elseif not menuactive then
			else
				if attached currentmenu as cm then
					if attached cm.routine as r then
						r.call
					end
					x := cm.x
					y := cm.y
					max := cm.numitems
					from
						i := 1
					until
						i > cm.numitems
					loop
						if not cm.menuitems [i].name.is_empty then
							i_main.V_video.v_drawpatchdirect (x, y, create {PATCH_T}.from_pointer (i_main.W_wad.w_cachelumpname (cm.menuitems [i].name)))
						end
						y := y + Lineheight
						i := i + 1
					end
					i_main.V_video.v_drawpatchdirect (x + Skullxoff, cm.y - 5 + (itemon - 1) * Lineheight, create {PATCH_T}.from_pointer (i_main.W_wad.w_cachelumpname (Skullname [whichskull])))
				end
			end
		end
	
feature 

	m_startcontrolpanel
		do
			if menuactive then
			else
				menuactive := True
				currentmenu := Maindef
				itemon := Maindef.laston
			end
		end
	
invariant
		itemon >= 1
		attached currentmenu as i_cm implies itemon <= i_cm.numitems

end -- class M_MENU

Generated by ISE EiffelStudio