note
	description: "[
		d_main.c
		DOOM main program (D_DoomMain) and game loop (D_DoomLoop),
		plus functions to determine game mode (shareware, registered),
		parse command line parameters, configure game parameters (turbo),
		and call the startup functions.
	]"
	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 
	D_MAIN

create 
	make

feature 

	i_main: I_MAIN

	wadfiles: LIST [STRING_8]

	make (a_i_main: I_MAIN)
		do
			i_main := a_i_main
			create {LINKED_LIST [STRING_8]} wadfiles.make
			pagename := ""
			singletics := True
		end
	
feature 

	startskill: INTEGER_32

	startepisode: INTEGER_32

	startmap: INTEGER_32

	autostart: BOOLEAN

	singletics: BOOLEAN assign set_singletics
			-- debug flag to cancel adaptiveness

	set_singletics (a_singletics: like singletics)
		do
			singletics := a_singletics
		end

	debugfile: detachable FILE
	
feature -- DEMO LOOP

	demosequence: INTEGER_32

	pagetic: INTEGER_32

	pagename: STRING_8
	
feature 

	devparm: BOOLEAN assign set_devparm
			-- started game with -devparm

	set_devparm (a_devparm: like devparm)
		do
			devparm := a_devparm
		end

	nomonsters: BOOLEAN assign set_nomonsters
			-- checkparm of -nomonsters

	set_nomonsters (a_nomonsters: like nomonsters)
		do
			nomonsters := a_nomonsters
		end

	respawnparm: BOOLEAN assign set_respawnparm
			-- checkparm of -respawn

	set_respawnparm (a_respawnparm: like respawnparm)
		do
			respawnparm := a_respawnparm
		end

	fastparm: BOOLEAN assign set_fastparm
			-- checkparm of -fast

	set_fastparm (a_fastparm: like fastparm)
		do
			fastparm := a_fastparm
		end
	
feature 

	d_doommain
		local
			p: INTEGER_32
			file: STRING_8
		do
			{NOT_IMPLEMENTED}.not_implemented ("D_DoomMain", False)
			findresponsefile
			identifyversion
			if i_main.Doomstat_h.gamemode = {GAME_MODE_T}.shareware then
				print ("            DOOM Shareware Startup%N")
			end
			p := i_main.m_argv.m_checkparm ("-playdemo")
			if not p.to_boolean then
				p := i_main.m_argv.m_checkparm ("-timedemo")
			end
			if p.to_boolean and p <= i_main.m_argv.myargv.upper then
				file := i_main.m_argv.myargv [p + 1].to_string_32 + ".lmp".as_string_8
				d_addfile (file)
				print ("Playing demo " + i_main.m_argv.myargv [p + 1] + ".lmp.%N")
			end
			startskill := {DOOMDEF_H}.sk_medium
			startepisode := 1
			startmap := 1
			autostart := False
			print ("V_Init: allocate screens.%N")
			i_main.V_video.v_init
			print ("M_LoadDefaults: Load system defauls.%N")
			i_main.M_misc.m_loaddefaults
			print ("W_Init: Init WADfiles.%N")
			i_main.W_wad.w_initmultiplefiles (wadfiles)
			print ("added%N")
			print ("==================%N")
			print ("   Shareware!%N")
			print ("==================%N")
			print ("M_Init: Init miscellaneous info.%N")
			i_main.M_menu.m_init
			print ("R_Init: Init DOOM refresh daemon - ")
			i_main.R_main.r_init
			print ("%NP_Init: Init Playloop state.%N")
			i_main.P_setup.p_init
			print ("I_Init: Setting up machine state.%N")
			i_main.I_system.i_init
			print ("D_CheckNetGame: Checking network game status.%N")
			i_main.D_net.d_checknetgame
			print ("S_Init: Setting up sound.%N")
			i_main.S_sound.s_init (i_main.S_sound.snd_sfxvolume * 8, i_main.S_sound.snd_musicvolume * 8)
			print ("HU_Init: Setting up heads up display.%N")
			i_main.Hu_stuff.hu_init
			print ("ST_Init: Init status bar.%N")
			i_main.St_stuff.st_init
			p := i_main.m_argv.m_checkparm ("-record")
			if p.to_boolean and p < i_main.m_argv.myargv.count - 1 then
				i_main.G_game.g_recorddemo (i_main.m_argv.myargv [p + 1].to_string_32.as_string_8)
				autostart := True
			end
			p := i_main.m_argv.m_checkparm ("-timedemo")
			if p /= 0 and p <= i_main.m_argv.myargv.upper then
				i_main.G_game.g_timedemo (i_main.m_argv.myargv [p + 1].to_string_32.as_string_8)
				d_doomloop
			end
			if i_main.G_game.gameaction /= i_main.G_game.Ga_loadgame then
				if autostart or i_main.G_game.netgame then
					i_main.G_game.g_initnew (startskill, startepisode, startmap)
				else
					d_starttitle
				end
			end
			d_doomloop
		end

	d_starttitle
		do
			i_main.G_game.gameaction := {G_GAME}.ga_nothing
			demosequence := -1
			d_advancedemo
		end

	advancedemo: BOOLEAN

	d_advancedemo
			-- Called after each demo or intro demosequence finishes
		do
			advancedemo := True
		end

	findresponsefile
		do
			{NOT_IMPLEMENTED}.not_implemented ("FindResponseFile", False)
		end

	identifyversion
		do
			{NOT_IMPLEMENTED}.not_implemented ("IdentifyVersion", False)
			i_main.Doomstat_h.gamemode := {GAME_MODE_T}.shareware
			d_addfile ("doom1.wad")
		end

	d_addfile (a_wadfile: STRING_8)
		do
			wadfiles.extend (a_wadfile)
		end
	
feature -- D_DoomLoop

	drone: BOOLEAN

	d_grabmousecallback: BOOLEAN
			-- Called to determine whether to grab the mouse pointer
		do
			if drone then
				Result := False
			elseif i_main.M_menu.menuactive or i_main.G_game.paused then
				Result := False
			else
				Result := (i_main.G_game.gamestate = {DOOMDEF_H}.gs_level) and not i_main.G_game.demoplayback and not advancedemo
			end
		end

	d_doomloop
		do
			{NOT_IMPLEMENTED}.not_implemented ("D_DoomLoop", False)
			if i_main.G_game.demorecording then
				i_main.G_game.g_beginrecording
			end
			i_main.I_video.grabmouse_callback := agent d_grabmousecallback
			check
					attached i_main.I_video as iv
			then
				iv.i_initgraphics
			end
			from
			until
				False
			loop
				d_runframe
			end
		end

	wipestart: INTEGER_32

	wipe: BOOLEAN

	d_runframe
		local
			nowtime: INTEGER_32
			tics: INTEGER_32
			perf_start, perf_end, perf_total: NATURAL_64
		do
			if wipe then
				from
					tics := 0
				until
					tics > 0
				loop
					nowtime := i_main.I_system.i_gettime
					tics := nowtime - wipestart
					i_main.I_system.i_sleep (1)
				end
				perf_start := i_main.I_timer.i_get_time_us
				wipestart := nowtime
				wipe := not i_main.F_wipe.wipe_screenwipe ({F_WIPE}.wipe_melt, 0, 0, {DOOMDEF_H}.screenwidth, {DOOMDEF_H}.screenheight, tics)
				i_main.I_video.i_updatenoblit
				i_main.M_menu.m_drawer
				i_main.I_video.i_finishupdate
				perf_end := i_main.I_timer.i_get_time_us
				perf_total := perf_end - perf_start
				i_main.I_timer.i_log_perf_frame (perf_total, "wipe")
			else
				if not i_main.G_game.timingdemo then
					print ("DOOM LOOP GAMETIC: " + i_main.G_game.gametic.out + ", state " + i_main.G_game.gamestate.out + "%N")
				else
					perf_start := i_main.I_timer.i_get_time_us
				end
				i_main.I_video.i_startframe
				if singletics then
					i_main.I_video.i_starttic
					d_processevents
					i_main.G_game.g_buildticcmd (i_main.D_net.Netcmds [i_main.G_game.consoleplayer] [i_main.D_net.maketic \\ {D_NET}.backuptics])
					if advancedemo then
						d_doadvancedemo
					end
					i_main.M_menu.m_ticker
					i_main.G_game.g_ticker
					i_main.G_game.gametic := i_main.G_game.gametic + 1
					i_main.D_net.maketic := i_main.D_net.maketic + 1
				else
					i_main.D_net.tryruntics
				end
				i_main.S_sound.s_updatesounds (i_main.G_game.Players [i_main.G_game.consoleplayer].mo)
				if i_main.I_video.Screenvisible and not i_main.G_game.nodrawers then
					wipe := i_main.D_display.d_display
					if wipe then
						i_main.F_wipe.wipe_endscreen (0, 0, {DOOMDEF_H}.screenwidth, {DOOMDEF_H}.screenheight)
						wipestart := i_main.I_system.i_gettime - 1
					else
						i_main.I_video.i_finishupdate
						perf_end := i_main.I_timer.i_get_time_us
						perf_total := perf_end - perf_start
						i_main.I_timer.i_log_perf_frame (perf_total, "gamestate " + i_main.G_game.gamestate.out)
					end
				end
			end
		end

	d_processevents
			-- Send all the events of the given timestamp down the responder chain
		local
			event: EVENT_T
			res: BOOLEAN
		do
			if i_main.Doomstat_h.gamemode = {GAME_MODE_T}.commercial and i_main.W_wad.w_checknumforname ("map01") < 0 then
			else
				from
				until
					eventtail = eventhead
				loop
					event := Events [eventtail]
					if not i_main.M_menu.m_responder (event) then
						res := i_main.G_game.g_responder (event)
					end
					eventtail := (eventtail + 1).bit_and ({D_EVENT}.maxevents - 1)
				end
			end
		end

	d_doadvancedemo
			-- This cycles through the demo sequences.
			-- FIXME - version dependend demo numbers?
		do
			i_main.G_game.Players [i_main.G_game.consoleplayer].playerstate := {PLAYER_T}.pst_live
			advancedemo := False
			i_main.G_game.usergame := False
			i_main.G_game.paused := False
			i_main.G_game.gameaction := {G_GAME}.ga_nothing
			if i_main.Doomstat_h.gamemode = {GAME_MODE_T}.retail then
				demosequence := (demosequence + 1) \\ 7
			else
				demosequence := (demosequence + 1) \\ 6
			end
			inspect demosequence
			when 0 then
				if i_main.Doomstat_h.gamemode = {GAME_MODE_T}.commercial then
					pagetic := 35 * 11
				else
					pagetic := 170
				end
				i_main.G_game.gamestate := {DOOMDEF_H}.gs_demoscreen
				pagename := "TITLEPIC"
				if i_main.Doomstat_h.gamemode = {GAME_MODE_T}.commercial then
					i_main.S_sound.s_startmusic ({SOUNDS_H}.mus_dm2ttl)
				else
					i_main.S_sound.s_startmusic ({SOUNDS_H}.mus_intro)
				end
			when 1 then
				i_main.G_game.g_deferedplaydemo ("demo1")
			when 2 then
				pagetic := 200
				i_main.G_game.gamestate := {DOOMDEF_H}.gs_demoscreen
				pagename := "CREDIT"
			when 3 then
				i_main.G_game.g_deferedplaydemo ("demo2")
			when 4 then
				i_main.G_game.gamestate := {DOOMDEF_H}.gs_demoscreen
				if i_main.Doomstat_h.gamemode = {GAME_MODE_T}.commercial then
					pagetic := 35 * 11
					pagename := "TITLEPIC"
					i_main.S_sound.s_startmusic ({SOUNDS_H}.mus_dm2ttl)
				else
					pagetic := 200
					if i_main.Doomstat_h.gamemode = {GAME_MODE_T}.retail then
						pagename := "CREDIT"
					else
						pagename := "HELP2"
					end
				end
			when 5 then
				i_main.G_game.g_deferedplaydemo ("demo3")
			when 6 then
				i_main.G_game.g_deferedplaydemo ("demo4")
			else
			end
		end
	
feature -- EVENT HANDLING
-- Events are asynchronous inputs generally generated by the game user.
-- Events can be discarded if no responder claims them

	Events: ARRAY [EVENT_T]
		once
			create Result.make_filled (create {EVENT_T}.make, 0, {D_EVENT}.maxevents)
		end

	eventhead: INTEGER_32

	eventtail: INTEGER_32

	d_postevent (event: EVENT_T)
		do
			Events [eventhead] := event
			eventhead := (eventhead + 1).bit_and ({D_EVENT}.maxevents - 1)
		ensure
			advanced_if_there_was_space: old eventhead < {D_EVENT}.maxevents - 1 implies eventhead = old eventhead + 1
			wrapped_if_there_was_no_space: old eventhead = {D_EVENT}.maxevents - 1 implies eventhead = 0
		end

	d_pageticker
			-- Handles timing for warped projection
		do
			pagetic := pagetic - 1
			if pagetic < 0 then
				d_advancedemo
			end
		end
	
end -- class D_MAIN

Generated by ISE EiffelStudio