note
	description: "[
		p_setup.c
		Do all the WAD I/O, get map description,
		set up initial state and misc. LUTs.
	]"
	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 
	P_SETUP

inherit
	DOOMDATA_H

create 
	make

feature 

	i_main: I_MAIN

	make (a_i_main: like i_main)
		local
			i: INTEGER_32
		do
			i_main := a_i_main
			create deathmatchstarts.make_filled (create {MAPTHING_T}, 0, Max_deathmatch_starts - 1)
			create nodes.make_empty
			create subsectors.make_empty
			create segs.make_empty
			create blocklinks.make_empty
			create blockmaplump.make_empty
			create vertexes.make_empty
			create sectors.make_empty
			create sides.make_empty
			create lines.make_empty
			create playerstarts.make_filled (create {MAPTHING_T}, 0, {DOOMDEF_H}.maxplayers - 1)
			from
				i := 0
			until
				i > playerstarts.upper
			loop
				playerstarts [i] := create {MAPTHING_T}
				i := i + 1
			end
		end
	
feature 

	rejectmatrix: detachable ARRAY [NATURAL_8]

	Max_deathmatch_starts: INTEGER_32 = 10

	deathmatchstarts: ARRAY [MAPTHING_T]

	deathmatch_p: INTEGER_32 assign set_deathmatch_p
			-- index in deathmatchstarts

	set_deathmatch_p (a_deathmatch_p: like deathmatch_p)
		do
			deathmatch_p := a_deathmatch_p
		end

	numnodes: INTEGER_32

	nodes: ARRAY [NODE_T]

	subsectors: ARRAY [SUBSECTOR_T]

	numsegs: INTEGER_32

	segs: ARRAY [SEG_T]

	numvertexes: INTEGER_32

	vertexes: ARRAY [VERTEX_T]

	numsectors: INTEGER_32

	sectors: ARRAY [SECTOR_T]

	numsides: INTEGER_32

	sides: ARRAY [SIDE_T]

	numlines: INTEGER_32

	lines: ARRAY [LINE_T]

	playerstarts: ARRAY [MAPTHING_T]
	
feature -- Blockmap
-- Created from axis aligned bounding box
-- of the map, a rectangular array of
-- blocks of size ...
-- Used to speed up collision detection
-- by spatial subdivision in 2D.

	bmapwidth: INTEGER_32

	bmapheight: INTEGER_32
			-- size in mapblocks

	blockmap: detachable INDEX_IN_ARRAY [INTEGER_16]
			-- int for larger maps

	blockmaplump: ARRAY [INTEGER_16]
			-- offsets in blockmap are from here

	bmaporgx: FIXED_T
			-- origin of block map

	bmaporgy: FIXED_T
			-- origin of block map

	blocklinks: ARRAY [detachable MOBJ_T]
			-- for thing chains
	
feature 

	p_init
		do
			i_main.P_switch.p_initswitchlist
			i_main.P_spec.p_initpicanims
			i_main.R_things.r_initsprites (i_main.Info.Sprnames)
		end

	p_setuplevel (episode, map, playermask, skill: INTEGER_32)
		local
			i: INTEGER_32
			lumpname: STRING_8
			lumpnum: INTEGER_32
			reject_mp: MANAGED_POINTER
		do
			i_main.G_game.totalkills := 0
			i_main.G_game.totalitems := 0
			i_main.G_game.totalsecret := 0
			i_main.G_game.wminfo.maxfrags := 0
			i_main.G_game.wminfo.partime := 180
			from
				i := 0
			until
				i >= {DOOMDEF_H}.maxplayers
			loop
				i_main.G_game.Players [i].killcount := 0
				i_main.G_game.Players [i].secretcount := 0
				i_main.G_game.Players [i].itemcount := 0
				i := i + 1
			end
			i_main.G_game.Players [i_main.G_game.consoleplayer].viewz := create {FIXED_T}.from_integer (1)
			i_main.S_sound.s_start
			i_main.P_tick.p_initthinkers
			i_main.W_wad.w_reload
			if i_main.Doomstat_h.gamemode = {GAME_MODE_T}.commercial then
				if map < 10 then
					lumpname := "map0" + map.out
				else
					lumpname := "map" + map.out
				end
			else
				lumpname := "E" + episode.out + "M" + map.out
			end
			lumpnum := i_main.W_wad.w_getnumforname (lumpname)
			i_main.P_tick.leveltime := 0
			p_loadblockmap (lumpnum + Ml_blockmap)
			p_loadvertexes (lumpnum + Ml_vertexes)
			p_loadsectors (lumpnum + Ml_sectors)
			p_loadsidedefs (lumpnum + Ml_sidedefs)
			p_loadlinedefs (lumpnum + Ml_linedefs)
			p_loadsubsectors (lumpnum + Ml_ssectors)
			p_loadnodes (lumpnum + Ml_nodes)
			p_loadsegs (lumpnum + Ml_segs)
			reject_mp := i_main.W_wad.w_cachelumpnum (lumpnum + Ml_reject)
			rejectmatrix := reject_mp.read_array (0, reject_mp.count)
			check
					attached rejectmatrix as rm
			then
				rm.rebase (0)
			end
			p_grouplines
			i_main.G_game.bodyqueslot := 0
			deathmatch_p := deathmatchstarts.lower
			p_loadthings (lumpnum + Ml_things)
			if i_main.G_game.deathmatch then
				from
					i := 0
				until
					i >= {DOOMDEF_H}.maxplayers
				loop
					i_main.G_game.Players [i].mo := Void
					i_main.G_game.g_deathmatchspawnplayer (i)
					i := i + 1
				end
			end
			i_main.P_mobj.iquehead := 0
			i_main.P_mobj.iquetail := 0
			i_main.P_spec.p_spawnspecials
			if i_main.Doomstat_h.precache then
				i_main.R_data.r_precachelevel
			end
		end

	p_loadblockmap (lump: INTEGER_32)
		do
			blockmaplump := {WAD_READER}.read_array_integer_16 (i_main.W_wad.w_cachelumpnum (lump))
			create blockmap.make (4, blockmaplump)
			bmaporgx := create {FIXED_T}.from_integer (blockmaplump [0].to_integer_32 |<< {M_FIXED}.fracbits)
			bmaporgy := create {FIXED_T}.from_integer (blockmaplump [1].to_integer_32 |<< {M_FIXED}.fracbits)
			bmapwidth := blockmaplump [2].to_integer_32
			bmapheight := blockmaplump [3].to_integer_32
			create blocklinks.make_filled (Void, 0, bmapwidth * bmapheight)
		end

	p_loadvertexes (lump: INTEGER_32)
		local
			data: MANAGED_POINTER
			i: INTEGER_32
		do
			numvertexes := i_main.W_wad.w_lumplength (lump) // {VERTEX_T}.structure_size
			create vertexes.make_filled (create {VERTEX_T}.default_create, 0, numvertexes - 1)
			data := i_main.W_wad.w_cachelumpnum (lump)
			from
				i := 0
			until
				i >= vertexes.upper
			loop
				vertexes [i] := create {VERTEX_T}.from_pointer (data, i * {VERTEX_T}.structure_size)
				i := i + 1
			end
		end

	p_loadsectors (lump: INTEGER_32)
		local
			data: MANAGED_POINTER
			i: INTEGER_32
		do
			numsectors := i_main.W_wad.w_lumplength (lump) // {SECTOR_T}.structure_size
			create sectors.make_filled (create {SECTOR_T}.make, 0, numsectors - 1)
			data := i_main.W_wad.w_cachelumpnum (lump)
			from
				i := 0
			until
				i > sectors.upper
			loop
				sectors [i] := create {SECTOR_T}.from_pointer (data, i * {SECTOR_T}.structure_size, i_main)
				i := i + 1
			end
		end

	p_loadsidedefs (lump: INTEGER_32)
		local
			data: MANAGED_POINTER
			i: INTEGER_32
		do
			numsides := i_main.W_wad.w_lumplength (lump) // {SIDE_T}.structure_size
			create sides.make_filled (create {SIDE_T}, 0, numsides - 1)
			data := i_main.W_wad.w_cachelumpnum (lump)
			from
				i := 0
			until
				i >= numsides
			loop
				sides [i] := create {SIDE_T}.from_pointer (data, i * {SIDE_T}.structure_size, i_main)
				i := i + 1
			end
		end

	p_loadlinedefs (lump: INTEGER_32)
			-- Also counts secret lines for intermissions.
		local
			data: MANAGED_POINTER
			i: INTEGER_32
		do
			numlines := i_main.W_wad.w_lumplength (lump) // {LINE_T}.structure_size
			create lines.make_filled (create {LINE_T}.make, 0, numlines - 1)
			data := i_main.W_wad.w_cachelumpnum (lump)
			from
				i := 0
			until
				i >= numlines
			loop
				lines [i] := create {LINE_T}.from_pointer (data, i * {LINE_T}.structure_size, i_main)
				i := i + 1
			end
		end

	p_loadsubsectors (lump: INTEGER_32)
		local
			data: MANAGED_POINTER
			i: INTEGER_32
			numsubsectors: INTEGER_32
		do
			numsubsectors := i_main.W_wad.w_lumplength (lump) // {SUBSECTOR_T}.structure_size
			create subsectors.make_filled (create {SUBSECTOR_T}, 0, numsubsectors - 1)
			data := i_main.W_wad.w_cachelumpnum (lump)
			from
				i := 0
			until
				i >= numsubsectors
			loop
				subsectors [i] := create {SUBSECTOR_T}.from_pointer (data, i * {SUBSECTOR_T}.structure_size)
				i := i + 1
			end
		end

	p_loadnodes (lump: INTEGER_32)
		local
			data: MANAGED_POINTER
			i: INTEGER_32
		do
			numnodes := i_main.W_wad.w_lumplength (lump) // {NODE_T}.structure_size
			create nodes.make_filled (create {NODE_T}.make, 0, numnodes - 1)
			data := i_main.W_wad.w_cachelumpnum (lump)
			from
				i := 0
			until
				i >= numnodes
			loop
				nodes [i] := create {NODE_T}.from_pointer (data, i * {NODE_T}.structure_size)
				i := i + 1
			end
		end

	p_loadsegs (lump: INTEGER_32)
		local
			data: MANAGED_POINTER
			i: INTEGER_32
		do
			numsegs := i_main.W_wad.w_lumplength (lump) // {SEG_T}.structure_size
			create segs.make_filled (create {SEG_T}.make, 0, numsegs - 1)
			data := i_main.W_wad.w_cachelumpnum (lump)
			from
				i := 0
			until
				i >= numsegs
			loop
				segs [i] := create {SEG_T}.from_pointer (data, i * {SEG_T}.structure_size, i_main)
				i := i + 1
			end
		end

	p_grouplines
			-- Builds sector line lists and subsector sector numbers.
			-- Finds block bounding boxes for sectors.
		local
			linebuffer: ARRAY [LINE_T]
			i, j: INTEGER_32
			total: INTEGER_32
			seg: SEG_T
			bbox: ARRAY [FIXED_T]
			block: INTEGER_32
		do
			create bbox.make_filled (create {FIXED_T}.from_integer (0), 0, 3)
			from
				i := subsectors.lower
			until
				i > subsectors.upper
			loop
				seg := segs [subsectors [i].firstline.to_integer_32]
				subsectors [i].sector := seg.sidedef.sector
				i := i + 1
			end
			total := 0
			from
				i := 0
			until
				i >= numlines
			loop
				total := total + 1
				check
						attached lines [i].frontsector as frontsector
				then
					frontsector.linecount := frontsector.linecount + 1
				end
				if attached lines [i].backsector as bs and then bs /= lines [i].frontsector then
					bs.linecount := bs.linecount + 1
				end
				i := i + 1
			end
			create linebuffer.make_filled (create {LINE_T}.make, 0, total - 1)
			from
				i := 0
			until
				i >= numsectors
			loop
				{M_BBOX}.m_clearbox (bbox)
				from
					j := 0
				until
					j >= numlines
				loop
					if lines [j].frontsector = sectors [i] or lines [j].backsector = sectors [i] then
						sectors [i].lines.extend (lines [j])
						{M_BBOX}.m_addtobox (bbox, lines [j].v1.x, lines [j].v1.y)
						{M_BBOX}.m_addtobox (bbox, lines [j].v2.x, lines [j].v2.y)
					end
					j := j + 1
				end
				check
						sectors [i].lines.count = sectors [i].linecount
				end
				sectors [i].soundorg.x := (bbox [{M_BBOX}.boxright] + bbox [{M_BBOX}.boxleft]) // create {FIXED_T}.from_integer (2)
				sectors [i].soundorg.y := (bbox [{M_BBOX}.boxtop] + bbox [{M_BBOX}.boxbottom]) // create {FIXED_T}.from_integer (2)
				block := ((bbox [{M_BBOX}.boxtop] - bmaporgy + create {FIXED_T}.from_integer ({P_LOCAL}.maxradius)) |>> {P_LOCAL}.mapblockshift).to_integer_32
				block := if block >= bmapheight then
					bmapheight - 1
				else
					block
				end
				sectors [i].blockbox [{M_BBOX}.boxtop] := block
				block := ((bbox [{M_BBOX}.boxbottom] - bmaporgy - create {FIXED_T}.from_integer ({P_LOCAL}.maxradius)) |>> {P_LOCAL}.mapblockshift).to_integer_32
				block := if block < 0 then
					0
				else
					block
				end
				sectors [i].blockbox [{M_BBOX}.boxbottom] := block
				block := ((bbox [{M_BBOX}.boxright] - bmaporgx + create {FIXED_T}.from_integer ({P_LOCAL}.maxradius)) |>> {P_LOCAL}.mapblockshift).to_integer_32
				block := if block >= bmapwidth then
					bmapwidth - 1
				else
					block
				end
				sectors [i].blockbox [{M_BBOX}.boxright] := block
				block := ((bbox [{M_BBOX}.boxleft] - bmaporgx - create {FIXED_T}.from_integer ({P_LOCAL}.maxradius)) |>> {P_LOCAL}.mapblockshift).to_integer_32
				block := if block < 0 then
					0
				else
					block
				end
				sectors [i].blockbox [{M_BBOX}.boxleft] := block
				i := i + 1
			end
		end
	
feature -- P_LoadThings

	Commercial_monsters: ARRAY [INTEGER_32]
		once
			Result := <<68, 64, 88, 89, 69, 67, 71, 65, 66, 84>>
		ensure
			instance_free: class
		end

	p_loadthings (lump: INTEGER_32)
		local
			data: MANAGED_POINTER
			i: INTEGER_32
			mt: MAPTHING_T
			numthings: INTEGER_32
			spawn: BOOLEAN
		do
			data := i_main.W_wad.w_cachelumpnum (lump)
			numthings := i_main.W_wad.w_lumplength (lump) // {MAPTHING_T}.structure_size
			from
				i := 0
				spawn := True
			until
				not spawn or i >= numthings
			loop
				spawn := True
				create mt.from_pointer (data, i * {MAPTHING_T}.structure_size)
				if i_main.Doomstat_h.gamemode /= {GAME_MODE_T}.commercial then
					if Commercial_monsters.has (mt.type.to_integer_32) then
						spawn := False
					end
				end
				if spawn then
					i_main.P_mobj.p_spawnmapthing (mt)
				end
				i := i + 1
			end
		end
	
invariant
		playerstarts.lower = 0
		playerstarts.count = {DOOMDEF_H}.maxplayers
		deathmatchstarts.lower = 0 and deathmatchstarts.count = Max_deathmatch_starts

end -- class P_SETUP

Generated by ISE EiffelStudio