note
	description: "[
		p_mobj.c
		Moving object handling. Spawn 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 
	P_MOBJ

inherit
	MOBJFLAG_T

	STATENUM_T

	MOBJTYPE_T

create 
	make

feature 

	i_main: I_MAIN

	make (a_i_main: like i_main)
		do
			i_main := a_i_main
			itemrespawnque := {REF_ARRAY_CREATOR [MAPTHING_T]}.make_ref_array ({P_LOCAL}.itemquesize)
			create itemrespawntime.make_filled (0, 0, {P_LOCAL}.itemquesize)
		end
	
feature -- P_RemoveMobj

	iquehead: INTEGER_32 assign set_iquehead

	set_iquehead (a_iquehead: like iquehead)
		do
			iquehead := a_iquehead
		end

	iquetail: INTEGER_32 assign set_iquetail

	set_iquetail (a_iquetail: like iquetail)
		do
			iquetail := a_iquetail
		end

	p_spawnplayer (mthing: MAPTHING_T)
			-- Called when a player is spawned on the level.
			-- Most of the player structure stays unchanged
			-- between levels.
		local
			p: PLAYER_T
			x, y, z: FIXED_T
			mobj: MOBJ_T
			i: INTEGER_32
		do
			if not i_main.G_game.Playeringame [mthing.type - 1.to_integer_32] then
			else
				p := i_main.G_game.Players [mthing.type - 1.to_integer_32]
				if p.playerstate = {PLAYER_T}.pst_reborn then
					i_main.G_game.g_playerreborn (mthing.type - 1.to_integer_32)
				end
				x := create {FIXED_T}.from_integer (mthing.x.to_integer_32 |<< {M_FIXED}.fracbits)
				y := create {FIXED_T}.from_integer (mthing.y.to_integer_32 |<< {M_FIXED}.fracbits)
				z := create {FIXED_T}.from_integer ({P_LOCAL}.onfloorz)
				mobj := p_spawnmobj (x, y, z, {INFO}.mt_player)
				if mthing.type > 1 then
					mobj.flags := mobj.flags | (mthing.type - 1).to_integer_32 |<< Mf_transshift
				end
				mobj.angle := {R_MAIN}.ang45 * create {ANGLE_T}.from_natural ((mthing.angle.to_natural_32 // 45))
				mobj.player := p
				mobj.health := p.health
				p.mo := mobj
				p.playerstate := {PLAYER_T}.pst_live
				p.refire := 0
				p.message := Void
				p.damagecount := 0
				p.bonuscount := 0
				p.extralight := 0
				p.fixedcolormap := 0
				p.viewheight := create {FIXED_T}.from_integer ({P_LOCAL}.viewheight)
				i_main.P_pspr.p_setuppsprites (p)
				if i_main.G_game.deathmatch then
					from
						i := 0
					until
						i >= {CARD_T}.numcards
					loop
						p.cards [i] := True
						i := i + 1
					end
				end
				if mthing.type - 1.to_integer_32 = i_main.G_game.consoleplayer then
					i_main.St_stuff.st_start
					i_main.Hu_stuff.hu_start
				end
			end
		end

	p_spawnmapthing (mthing: MAPTHING_T)
		local
			i: INTEGER_32
			b: INTEGER_32
			mobj: MOBJ_T
			x, y, z: FIXED_T
			returned: BOOLEAN
		do
			if mthing.type = 11 then
				if i_main.P_setup.deathmatch_p < 10 then
					i_main.P_setup.deathmatchstarts [i_main.P_setup.deathmatch_p] := mthing
					i_main.P_setup.deathmatch_p := i_main.P_setup.deathmatch_p + 1
				end
			elseif mthing.type <= 4 then
				i_main.P_setup.playerstarts [mthing.type - 1] := mthing
				if not i_main.G_game.deathmatch then
					p_spawnplayer (mthing)
				end
			elseif not i_main.G_game.netgame and mthing.options & 16 /= 0 then
			else
				if i_main.G_game.gameskill = {G_GAME}.sk_baby then
					b := 1
				elseif i_main.G_game.gameskill = {G_GAME}.sk_nightmare then
					b := 4
				else
					b := 1 |<< (i_main.G_game.gameskill - 1)
				end
				if mthing.options.to_integer_32 & b = 0 then
					returned := True
				end
				if not returned then
					from
						i := 0
					until
						i >= {INFO}.nummobjtypes or else mthing.type.to_integer_32 = {INFO}.mobjinfo [i].doomednum
					loop
						i := i + 1
					end
					if i = {INFO}.nummobjtypes then
						{I_MAIN}.i_error ("P_SpawnMapThing: Unknown type " + mthing.type.out + " at (" + mthing.x.out + ", " + mthing.y.out + ")")
					end
					if i_main.G_game.deathmatch and {INFO}.mobjinfo [i].flags & Mf_notdmatch /= 0 then
						returned := True
					end
				end
				if not returned then
					if i_main.D_main.nomonsters and (i = {INFO}.mt_skull or {INFO}.mobjinfo [i].flags & Mf_countkill /= 0) then
						returned := True
					end
				end
				if not returned then
					x := create {FIXED_T}.from_integer (mthing.x.to_integer_32 |<< {M_FIXED}.fracbits)
					y := create {FIXED_T}.from_integer (mthing.y.to_integer_32 |<< {M_FIXED}.fracbits)
					if {INFO}.mobjinfo [i].flags & Mf_spawnceiling /= 0 then
						z := create {FIXED_T}.from_integer ({P_LOCAL}.onceilingz)
					else
						z := create {FIXED_T}.from_integer ({P_LOCAL}.onfloorz)
					end
					mobj := p_spawnmobj (x, y, z, i)
					mobj.spawnpoint := mthing
					if mobj.tics > 0 then
						mobj.tics := 1 + (i_main.M_random.p_random \\ mobj.tics)
					end
					if mobj.flags & Mf_countkill /= 0 then
						i_main.G_game.totalkills := i_main.G_game.totalkills + 1
					end
					if mobj.flags & Mf_countitem /= 0 then
						i_main.G_game.totalitems := i_main.G_game.totalitems + 1
					end
					mobj.angle := create {ANGLE_T}.from_natural (({R_MAIN}.ang45.as_integer_32 * (mthing.angle.to_integer_32 // 45)).to_natural_32)
					if mthing.options.to_integer_32 & {DOOMDEF_H}.mtf_ambush /= 0 then
						mobj.flags := mobj.flags | Mf_ambush
					end
				end
			end
		end
	
feature -- P_SpawnMobj

	p_spawnmobj (x, y, z: FIXED_T; type: INTEGER_32): MOBJ_T
		local
			mobj: MOBJ_T
			st: STATE_T
			info: MOBJINFO_T
		do
			create mobj.make
			info := {INFO}.mobjinfo [type]
			mobj.type := type
			mobj.info := info
			mobj.x := x
			mobj.y := y
			mobj.radius := create {FIXED_T}.from_integer (info.radius)
			mobj.height := create {FIXED_T}.from_integer (info.height)
			mobj.flags := info.flags
			mobj.health := info.spawnhealth
			if i_main.G_game.gameskill /= {DOOMDEF_H}.sk_nightmare then
				mobj.reactiontime := info.reactiontime
			end
			mobj.lastlook := i_main.M_random.p_random \\ {DOOMDEF_H}.maxplayers
			st := {INFO}.states [info.spawnstate]
			mobj.state := st
			mobj.tics := st.tics.to_integer_32
			mobj.sprite := st.sprite
			mobj.frame := st.frame.to_integer_32
			i_main.P_maputl.p_setthingposition (mobj)
			after_p_set_thing_position (mobj, z)
			mobj.thinker.function := agent p_mobjthinker (mobj)
			i_main.P_tick.p_addthinker (mobj)
			Result := mobj
		end

	after_p_set_thing_position (mobj: MOBJ_T; z: FIXED_T)
			-- Part of P_SpawnMobj for updating coords from subsector info
		do
			check
					attached mobj.subsector as subsector
			then
				check
						attached subsector.sector as sector
				then
					mobj.floorz := sector.floorheight
					mobj.ceilingz := sector.ceilingheight
				end
			end
			if z = create {FIXED_T}.from_integer ({P_LOCAL}.onfloorz) then
				mobj.z := mobj.floorz
			elseif z = create {FIXED_T}.from_integer ({P_LOCAL}.onceilingz) then
				check
						attached mobj.info as attached_info
				then
					mobj.z := mobj.ceilingz - create {FIXED_T}.from_integer (attached_info.height)
				end
			else
				mobj.z := z
			end
		end
	
feature 

	p_mobjthinker (mobj: MOBJ_T)
		local
			returned: BOOLEAN
		do
			if mobj.momx /= create {FIXED_T}.from_integer (0) or mobj.momy /= create {FIXED_T}.from_integer (0) or mobj.flags & Mf_skullfly /= 0 then
				p_xymovement (mobj)
				if mobj.thinker.function = Void then
					returned := True
				end
			end
			if not returned then
				if mobj.z /= mobj.floorz or mobj.momz /= create {FIXED_T}.from_integer (0) then
					p_zmovement (mobj)
					if mobj.thinker.function = Void then
						returned := True
					end
				end
			end
			if not returned then
				if mobj.tics /= -1 then
					mobj.tics := mobj.tics - 1
					if mobj.tics = 0 then
						check
								attached mobj.state as state
						then
							if not p_setmobjstate (mobj, state.nextstate) then
								returned := True
							end
						end
					end
				else
					if mobj.flags & Mf_countkill = 0 then
						returned := True
					end
					if not returned then
						if not i_main.G_game.respawnmonsters then
							returned := True
						end
					end
					if not returned then
						mobj.movecount := mobj.movecount + 1
						if mobj.movecount < 12 * 35 then
							returned := True
						end
					end
					if not returned then
						if i_main.P_tick.leveltime & 31 /= 0 then
							returned := True
						end
					end
					if not returned then
						if i_main.M_random.p_random > 4 then
							returned := True
						end
					end
					if not returned then
						p_nightmarerespawn (mobj)
					end
				end
			end
		end

	Stopspeed: INTEGER_32 = 4096

	Friction: INTEGER_32 = 59392

	p_xymovement (mo: MOBJ_T)
		local
			ptryx: FIXED_T
			ptryy: FIXED_T
			xmove: FIXED_T
			ymove: FIXED_T
			returned: BOOLEAN
			did_once: BOOLEAN
		do
			if mo.momx = create {FIXED_T}.from_integer (0) and mo.momy = create {FIXED_T}.from_integer (0) then
				if mo.flags & Mf_skullfly /= 0 then
					mo.flags := mo.flags & Mf_skullfly.bit_not
					mo.momx := create {FIXED_T}.from_integer (0)
					mo.momy := create {FIXED_T}.from_integer (0)
					mo.momz := create {FIXED_T}.from_integer (0)
					check
							attached mo.info as info
					then
						p_setmobjstate (mo, info.spawnstate).do_nothing
					end
				end
				returned := True
			end
			if not returned then
				if mo.momx > create {FIXED_T}.from_integer ({P_LOCAL}.maxmove) then
					mo.momx := create {FIXED_T}.from_integer ({P_LOCAL}.maxmove)
				elseif mo.momx < create {FIXED_T}.from_integer (- {P_LOCAL}.maxmove) then
					mo.momx := create {FIXED_T}.from_integer (- {P_LOCAL}.maxmove)
				end
				if mo.momy > create {FIXED_T}.from_integer ({P_LOCAL}.maxmove) then
					mo.momy := create {FIXED_T}.from_integer ({P_LOCAL}.maxmove)
				elseif mo.momy < create {FIXED_T}.from_integer (- {P_LOCAL}.maxmove) then
					mo.momy := create {FIXED_T}.from_integer (- {P_LOCAL}.maxmove)
				end
				xmove := mo.momx
				ymove := mo.momy
			end
			from
			until
				returned or (did_once and xmove = create {FIXED_T}.from_integer (0) and ymove = create {FIXED_T}.from_integer (0))
			loop
				did_once := True
				if xmove > create {FIXED_T}.from_integer ({P_LOCAL}.maxmove // 2) or ymove > create {FIXED_T}.from_integer ({P_LOCAL}.maxmove // 2) then
					ptryx := mo.x + xmove // create {FIXED_T}.from_integer (2)
					ptryy := mo.y + ymove // create {FIXED_T}.from_integer (2)
					xmove := xmove |>> 1
					ymove := ymove |>> 1
				else
					ptryx := mo.x + xmove
					ptryy := mo.y + ymove
					xmove := create {FIXED_T}.from_integer (0)
					ymove := create {FIXED_T}.from_integer (0)
				end
				if not i_main.P_map.p_trymove (mo, ptryx, ptryy) then
					if attached mo.player then
						i_main.P_map.p_slidemove (mo)
					elseif mo.flags & Mf_missile /= 0 then
						if attached i_main.P_map.ceilingline as cl and then attached cl.backsector as bs and then bs.ceilingpic.to_integer_32 = i_main.R_sky.skyflatnum then
							p_removemobj (mo)
							returned := True
						else
							p_explodemissile (mo)
						end
					else
						mo.momx := create {FIXED_T}.from_integer (0)
						mo.momy := create {FIXED_T}.from_integer (0)
					end
				end
			end
			if not returned then
				if attached mo.player as player and then player.cheats & {CHEAT_T}.cf_nomomentum /= 0 then
					mo.momx := create {FIXED_T}.from_integer (0)
					mo.momy := create {FIXED_T}.from_integer (0)
					returned := True
				end
			end
			if not returned then
				if mo.flags & (Mf_missile | Mf_skullfly) /= 0 then
					returned := True
				end
			end
			if not returned then
				if mo.z > mo.floorz then
					returned := True
				end
			end
			if not returned then
				if mo.flags & Mf_corpse /= 0 then
					if mo.momx > create {FIXED_T}.from_integer ({M_FIXED}.fracunit // 4) or mo.momx < create {FIXED_T}.from_integer (- {M_FIXED}.fracunit // 4) or mo.momy > create {FIXED_T}.from_integer ({M_FIXED}.fracunit // 4) or mo.momy < create {FIXED_T}.from_integer (- {M_FIXED}.fracunit // 4) then
						check
								attached mo.subsector as sub and then attached sub.sector as sector
						then
							if mo.floorz /= sector.floorheight then
								returned := True
							end
						end
					end
				end
			end
			if not returned then
				if mo.momx > create {FIXED_T}.from_integer (- Stopspeed) and mo.momx < create {FIXED_T}.from_integer (Stopspeed) and mo.momy > create {FIXED_T}.from_integer (- Stopspeed) and mo.momy < create {FIXED_T}.from_integer (Stopspeed) and (mo.player = Void or (attached mo.player as player and then player.cmd.forwardmove = 0 and then player.cmd.sidemove = 0)) then
					if attached mo.player as player and then attached player.mo as pmo and then attached pmo.state as st and then st.is_player_run then
						p_setmobjstate (pmo, S_play).do_nothing
					end
					mo.momx := create {FIXED_T}.from_integer (0)
					mo.momy := create {FIXED_T}.from_integer (0)
				else
					mo.momx := {M_FIXED}.fixedmul (mo.momx, create {FIXED_T}.from_integer (Friction))
					mo.momy := {M_FIXED}.fixedmul (mo.momy, create {FIXED_T}.from_integer (Friction))
				end
			end
		end

	p_explodemissile (mo: MOBJ_T)
		do
			mo.momx := create {FIXED_T}.from_integer (0)
			mo.momy := create {FIXED_T}.from_integer (0)
			mo.momz := create {FIXED_T}.from_integer (0)
			p_setmobjstate (mo, {INFO}.mobjinfo [mo.type].deathstate).do_nothing
			mo.tics := mo.tics - (i_main.M_random.p_random & 3)
			if mo.tics < 1 then
				mo.tics := 1
			end
			mo.flags := mo.flags & Mf_missile.bit_not
			check
					attached mo.info as i
			then
				if i.deathsound /= 0 then
					i_main.S_sound.s_startsound (mo, i.deathsound)
				end
			end
		end

	p_zmovement (mo: MOBJ_T)
		local
			dist: FIXED_T
			delta: FIXED_T
			returned: BOOLEAN
		do
			if attached mo.player as player and then mo.z < mo.floorz then
				player.viewheight := player.viewheight - (mo.floorz - mo.z)
				player.deltaviewheight := create {FIXED_T}.from_integer (({P_LOCAL}.viewheight - player.viewheight.as_integer_32) |>> 3)
			end
			mo.z := mo.z + mo.momz
			if mo.flags & Mf_float /= 0 and attached mo.target as target then
				dist := i_main.P_maputl.p_aproxdistance (mo.x - target.x, mo.y - target.y)
				delta := (target.z + (mo.height |>> 1)) - mo.z
				if delta < create {FIXED_T}.from_integer (0) and dist < - (delta * create {FIXED_T}.from_integer (3)) then
					mo.z := mo.z - create {FIXED_T}.from_integer ({P_LOCAL}.floatspeed)
				elseif delta > create {FIXED_T}.from_integer (0) and dist < (delta * create {FIXED_T}.from_integer (3)) then
					mo.z := mo.z + create {FIXED_T}.from_integer ({P_LOCAL}.floatspeed)
				end
			end
			if mo.z <= mo.floorz then
				if mo.flags & Mf_skullfly /= 0 then
					mo.momz := - mo.momz
				end
				if mo.momz < create {FIXED_T}.from_integer (0) then
					if attached mo.player as player and mo.momz < create {FIXED_T}.from_integer (- {P_LOCAL}.gravity * 8) then
						player.deltaviewheight := mo.momz |>> 3
						i_main.S_sound.s_startsound (mo, {SFXENUM_T}.sfx_oof)
					end
					mo.momz := create {FIXED_T}.from_integer (0)
				end
				mo.z := mo.floorz
				if mo.flags & Mf_missile /= 0 and mo.flags & Mf_noclip = 0 then
					p_explodemissile (mo)
					returned := True
				end
			elseif not returned and mo.flags & Mf_nogravity = 0 then
				if mo.momz = create {FIXED_T}.from_integer (0) then
					mo.momz := create {FIXED_T}.from_integer (- {P_LOCAL}.gravity * 2)
				else
					mo.momz := mo.momz - create {FIXED_T}.from_integer ({P_LOCAL}.gravity)
				end
			end
			if not returned then
				if mo.z + mo.height > mo.ceilingz then
					if mo.momz > create {FIXED_T}.from_integer (0) then
						mo.momz := create {FIXED_T}.from_integer (0)
					end
					mo.z := mo.ceilingz - mo.height
					if mo.flags & Mf_skullfly /= 0 then
						mo.momz := - mo.momz
					end
					if mo.flags & Mf_missile /= 0 and mo.flags & Mf_noclip = 0 then
						p_explodemissile (mo)
					end
				end
			end
		end

	p_nightmarerespawn (mo: MOBJ_T)
		do
			{NOT_IMPLEMENTED}.not_implemented ("P_NightmareRespawn", False)
		end

	p_respawnspecials
		do
			{NOT_IMPLEMENTED}.not_implemented ("P_RespawnSpecials", False)
		end

	p_setmobjstate (mobj: MOBJ_T; a_state: INTEGER_32): BOOLEAN
			-- Returns true if the mobj is still present
		local
			st: STATE_T
			state: INTEGER_32
			did_once: BOOLEAN
		do
			state := a_state
			from
				Result := True
				did_once := False
			until
				did_once and (not Result or mobj.tics /= 0)
			loop
				did_once := True
				if state = S_null then
					mobj.state := Void
					p_removemobj (mobj)
					Result := False
				else
					st := {INFO}.states [state]
					mobj.state := st
					mobj.tics := st.tics.to_integer_32
					mobj.sprite := st.sprite
					mobj.frame := st.frame.to_integer_32
					if attached st.action as action then
						action.call (i_main.P_enemy, mobj)
					end
					state := st.nextstate
				end
			end
		end
	
feature -- P_RemoveMobj

	itemrespawnque: ARRAY [MAPTHING_T]

	itemrespawntime: ARRAY [INTEGER_32]

	p_removemobj (mobj: MOBJ_T)
		do
			if mobj.flags & Mf_special /= 0 and mobj.flags & Mf_dropped = 0 and mobj.type /= Mt_inv and mobj.type /= Mt_ins then
				check
						attached mobj.spawnpoint as sp
				then
					itemrespawnque [iquehead] := sp
				end
				itemrespawntime [iquehead] := i_main.P_tick.leveltime
				iquehead := (iquehead + 1) & ({P_LOCAL}.itemquesize - 1)
				if iquehead = iquetail then
					iquetail := (iquetail + 1) & ({P_LOCAL}.itemquesize - 1)
				end
			end
			i_main.P_maputl.p_unsetthingposition (mobj)
			i_main.S_sound.s_stopsound (mobj)
			i_main.P_tick.p_removethinker (mobj)
		end
	
feature 

	p_spawnpuff (x, y, a_z: FIXED_T)
		local
			th: MOBJ_T
			z: FIXED_T
		do
			z := a_z + create {FIXED_T}.from_integer (((i_main.M_random.p_random - i_main.M_random.p_random) |<< 10))
			th := p_spawnmobj (x, y, z, Mt_puff)
			th.momz := create {FIXED_T}.from_integer ({M_FIXED}.fracunit)
			th.tics := th.tics - (i_main.M_random.p_random & 3)
			if th.tics < 1 then
				th.tics := 1
			end
			if i_main.P_map.attackrange = create {FIXED_T}.from_integer ({P_LOCAL}.meleerange) then
				p_setmobjstate (th, S_puff3).do_nothing
			end
		end

	p_spawnblood (x, y, a_z: FIXED_T; damage: INTEGER_32)
		local
			th: MOBJ_T
			z: FIXED_T
		do
			z := a_z + create {FIXED_T}.from_integer (((i_main.M_random.p_random - i_main.M_random.p_random) |<< 10))
			th := p_spawnmobj (x, y, z, Mt_blood)
			th.momz := create {FIXED_T}.from_integer ({M_FIXED}.fracunit * 2)
			th.tics := th.tics - (i_main.M_random.p_random & 3)
			if th.tics < 1 then
				th.tics := 1
			end
			if damage <= 12 and damage >= 9 then
				p_setmobjstate (th, S_blood2).do_nothing
			elseif damage < 9 then
				p_setmobjstate (th, S_blood3).do_nothing
			end
		end

	p_spawnmissile (source, dest: MOBJ_T; type: INTEGER_32): MOBJ_T
		local
			th: MOBJ_T
			an: ANGLE_T
			dist: INTEGER_32
		do
			th := p_spawnmobj (source.x, source.y, source.z + create {FIXED_T}.from_integer (4 * 8 * {M_FIXED}.fracunit), type)
			check
					attached th.info as thinfo
			then
				i_main.S_sound.s_startsound (th, thinfo.seesound)
			end
			th.target := source
			an := i_main.R_main.r_pointtoangle2 (source.x, source.y, dest.x, dest.y)
			if dest.flags & Mf_shadow /= 0 then
				an := an + create {ANGLE_T}.from_natural (((i_main.M_random.p_random - i_main.M_random.p_random) |<< 20).to_natural_32)
			end
			th.angle := an
			an := an |>> {R_MAIN}.angletofineshift
			check
					attached th.info as i
			then
				th.momx := {M_FIXED}.fixedmul (create {FIXED_T}.from_integer (i.speed), i_main.R_main.Finecosine [an.as_integer_32])
				th.momy := {M_FIXED}.fixedmul (create {FIXED_T}.from_integer (i.speed), create {FIXED_T}.from_integer (i_main.R_main.Finesine [an.as_integer_32]))
				dist := i_main.P_maputl.p_aproxdistance (dest.x - source.x, dest.y - source.y).as_integer_32
				dist := dist // i.speed
			end
			if dist < 1 then
				dist := 1
			end
			th.momz := (dest.z - source.z) // create {FIXED_T}.from_integer (dist)
			p_checkmissilespawn (th)
			Result := th
		end

	p_checkmissilespawn (th: MOBJ_T)
			-- Moves the missile forward a bit
			-- and possibly explodes it right there
		do
			th.tics := th.tics - (i_main.M_random.p_random & 3)
			if th.tics < 1 then
				th.tics := 1
			end
			th.x := th.x + (th.momx |>> 1)
			th.y := th.y + (th.momy |>> 1)
			th.z := th.z + (th.momz |>> 1)
			if not i_main.P_map.p_trymove (th, th.x, th.y) then
				p_explodemissile (th)
			end
		end
	
end -- class P_MOBJ

Generated by ISE EiffelStudio