note
	description: "[
		p_user.c
		
		Player related stuff.
		Bobbing POV/weapon, movement.
		Pending weapon.
	]"
	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_USER

inherit
	CHEAT_T

	MOBJFLAG_T

	STATENUM_T

	DOOMDEF_H

	POWERTYPE_T

	WEAPONTYPE_T

create 
	make

feature 

	i_main: I_MAIN

	make (a_i_main: like i_main)
		do
			i_main := a_i_main
		end
	
feature 

	Maxbob: INTEGER_32 = 1048576
			-- 16 pixels of bob

	Inversecolormap: INTEGER_32 = 32
			-- Index of the special effects (INVUL inverse) map.
	
feature 

	onground: BOOLEAN
	
feature 

	p_playerthink (player: PLAYER_T)
		local
			cmd: TICCMD_T
			newweapon: INTEGER_32
		do
			if attached player.mo as mo then
			end
			if player.cheats & Cf_noclip /= 0 then
				check
						attached player.mo as mo
				then
					mo.flags := mo.flags | Mf_noclip
				end
			else
				check
						attached player.mo as mo
				then
					mo.flags := mo.flags & Mf_noclip.bit_not
				end
			end
			cmd := player.cmd
			check
					attached player.mo as mo
			then
				if mo.flags & Mf_justattacked /= 0 then
					cmd.angleturn := 0
					cmd.forwardmove := (51200 // 512).to_integer_8
					cmd.sidemove := (0).to_integer_8
					mo.flags := mo.flags & Mf_justattacked.bit_not
				end
			end
			if player.playerstate = {D_PLAYER}.pst_dead then
				p_deaththink (player)
			else
				check
						attached player.mo as mo
				then
					if mo.reactiontime /= 0 then
						mo.reactiontime := mo.reactiontime - 1
					else
						p_moveplayer (player)
					end
				end
				p_calcheight (player)
				check
						attached player.mo as mo
				then
					check
							attached mo.subsector as subsector
					then
						check
								attached subsector.sector as sector
						then
							if sector.special /= 0 then
								i_main.P_spec.p_playerinspecialsector (player)
							end
						end
					end
				end
				if cmd.buttons & {D_EVENT}.bt_special /= 0 then
					cmd.buttons := 0
				end
				if cmd.buttons & {D_EVENT}.bt_change /= 0 then
					newweapon := (cmd.buttons & {D_EVENT}.bt_weaponmask) |>> {D_EVENT}.bt_weaponshift
					if newweapon = Wp_fist and player.weaponowned [Wp_chainsaw] and not (player.readyweapon = Wp_chainsaw and player.powers [Pw_strength] /= 0) then
						newweapon := Wp_chainsaw
					end
					if i_main.Doomstat_h.gamemode = {GAME_MODE_T}.commercial and newweapon = Wp_shotgun and player.weaponowned [Wp_supershotgun] and player.readyweapon /= Wp_supershotgun then
						newweapon := Wp_supershotgun
					end
					if player.weaponowned [newweapon] and newweapon /= player.readyweapon then
						if (newweapon /= Wp_plasma and newweapon /= Wp_bfg) or (i_main.Doomstat_h.gamemode /= {GAME_MODE_T}.shareware) then
							player.pendingweapon := newweapon
						end
					end
				end
				if cmd.buttons & {D_EVENT}.bt_use /= 0 then
					if not player.usedown then
						i_main.P_map.p_uselines (player)
						player.usedown := True
					end
				else
					player.usedown := False
				end
				i_main.P_pspr.p_movepsprites (player)
				if player.powers [Pw_strength] /= 0 then
					player.powers [Pw_strength] := player.powers [Pw_strength] + 1
				end
				if player.powers [Pw_invulnerability] /= 0 then
					player.powers [Pw_invulnerability] := player.powers [Pw_invulnerability] - 1
				end
				if player.powers [Pw_invisibility] /= 0 then
					player.powers [Pw_invisibility] := player.powers [Pw_invisibility] - 1
					if player.powers [Pw_invisibility] = 0 then
						check
								attached player.mo as mo
						then
							mo.flags := mo.flags & Mf_shadow.bit_not
						end
					end
				end
				if player.powers [Pw_infrared] /= 0 then
					player.powers [Pw_infrared] := player.powers [Pw_infrared] - 1
				end
				if player.powers [Pw_ironfeet] /= 0 then
					player.powers [Pw_ironfeet] := player.powers [Pw_ironfeet] - 1
				end
				if player.damagecount /= 0 then
					player.damagecount := player.damagecount - 1
				end
				if player.bonuscount /= 0 then
					player.bonuscount := player.bonuscount - 1
				end
				if player.powers [Pw_invulnerability] /= 0 then
					if player.powers [Pw_invulnerability] > 4 * 32 or player.powers [Pw_invulnerability] & 8 /= 0 then
						player.fixedcolormap := Inversecolormap
					else
						player.fixedcolormap := 0
					end
				elseif player.powers [Pw_infrared] > 0 then
					if player.powers [Pw_infrared] > 4 * 32 or player.powers [Pw_infrared] & 8 /= 0 then
						player.fixedcolormap := 1
					else
						player.fixedcolormap := 0
					end
				else
					player.fixedcolormap := 0
				end
			end
		end

	p_deaththink (player: PLAYER_T)
			-- Fall on your face when dying.
			-- Decrease POV height to floor height.
		local
			angle: ANGLE_T
			delta: ANGLE_T
		do
			i_main.P_pspr.p_movepsprites (player)
			if player.viewheight > create {FIXED_T}.from_integer (6 * {M_FIXED}.fracunit) then
				player.viewheight := player.viewheight - create {FIXED_T}.from_integer ({M_FIXED}.fracunit)
			end
			if player.viewheight < create {FIXED_T}.from_integer (6 * {M_FIXED}.fracunit) then
				player.viewheight := create {FIXED_T}.from_integer (6 * {M_FIXED}.fracunit)
			end
			player.deltaviewheight := create {FIXED_T}.from_integer (0)
			check
					attached player.mo as mo
			then
				onground := (mo.z <= mo.floorz)
				p_calcheight (player)
				if attached player.attacker as attacker and then attacker /= mo then
					angle := i_main.R_main.r_pointtoangle2 (mo.x, mo.y, attacker.x, attacker.y)
					delta := angle - mo.angle
					if delta < {R_MAIN}.ang45 or delta > - {R_MAIN}.ang45 then
						mo.angle := angle
						if player.damagecount /= 0 then
							player.damagecount := player.damagecount - 1
						end
					elseif delta < {R_MAIN}.ang180 then
						mo.angle := mo.angle + {R_MAIN}.ang45
					else
						mo.angle := mo.angle - {R_MAIN}.ang45
					end
				elseif player.damagecount /= 0 then
					player.damagecount := player.damagecount - 1
				end
				if player.cmd.buttons & {D_EVENT}.bt_use /= 0 then
					player.playerstate := {D_PLAYER}.pst_reborn
				end
			end
		end

	p_moveplayer (player: PLAYER_T)
		local
			cmd: TICCMD_T
			b: BOOLEAN
		do
			cmd := player.cmd
			check
					attached player.mo as mo
			then
				mo.angle := mo.angle + create {ANGLE_T}.from_natural ((cmd.angleturn.as_natural_32 |<< 16))
				onground := (mo.z <= mo.floorz)
				if cmd.forwardmove /= 0 and onground then
					p_thrust (player, mo.angle, create {FIXED_T}.from_integer (cmd.forwardmove.to_integer_32 * 2048))
				end
				if cmd.sidemove /= 0 and onground then
					p_thrust (player, mo.angle - {R_MAIN}.ang90, create {FIXED_T}.from_integer (cmd.sidemove.to_integer_32 * 2048))
				end
				if (cmd.forwardmove /= 0 or cmd.sidemove /= 0) and mo.state = {INFO}.states [{INFO}.s_play] then
					i_main.P_mobj.p_setmobjstate (mo, S_play_run1).do_nothing
				end
			end
		end

	p_thrust (player: PLAYER_T; a_angle: ANGLE_T; move: FIXED_T)
		local
			angle: ANGLE_T
		do
			angle := a_angle
			angle := angle |>> {R_MAIN}.angletofineshift
			check
					attached player.mo as mo
			then
				mo.momx := mo.momx + {M_FIXED}.fixedmul (move, {R_MAIN}.finecosine [angle.as_integer_32])
				mo.momy := mo.momy + {M_FIXED}.fixedmul (move, create {FIXED_T}.from_integer ({TABLES}.finesine [angle.as_integer_32]))
			end
		end

	p_calcheight (player: PLAYER_T)
			-- Calculate the walking / running height adjustment
		local
			angle: INTEGER_32
			bob: FIXED_T
		do
			check
					attached player.mo as mo
			then
				player.bob := {M_FIXED}.fixedmul (mo.momx, mo.momx) + {M_FIXED}.fixedmul (mo.momy, mo.momy)
				player.bob := player.bob |>> 2
				if player.bob > create {FIXED_T}.from_integer (Maxbob) then
					player.bob := create {FIXED_T}.from_integer (Maxbob)
				end
				if player.cheats & Cf_nomomentum /= 0 or not onground then
					player.viewz := mo.z + create {FIXED_T}.from_integer ({P_LOCAL}.viewheight)
					if player.viewz > mo.ceilingz - create {FIXED_T}.from_integer (4 * {M_FIXED}.fracunit) then
						player.viewz := mo.ceilingz - create {FIXED_T}.from_integer (4 * {M_FIXED}.fracunit)
					end
					player.viewz := mo.z + player.viewheight
				else
					angle := ({R_MAIN}.fineangles // 20 * i_main.P_tick.leveltime) & {R_MAIN}.finemask
					bob := {M_FIXED}.fixedmul (player.bob // create {FIXED_T}.from_integer (2), create {FIXED_T}.from_integer ({TABLES}.finesine [angle]))
					if player.playerstate = {PLAYER_T}.pst_live then
						player.viewheight := player.viewheight + player.deltaviewheight
						if player.viewheight > create {FIXED_T}.from_integer ({P_LOCAL}.viewheight) then
							player.viewheight := create {FIXED_T}.from_integer ({P_LOCAL}.viewheight)
							player.deltaviewheight := create {FIXED_T}.from_integer (0)
						end
						if player.viewheight < create {FIXED_T}.from_integer ({P_LOCAL}.viewheight // 2) then
							player.viewheight := create {FIXED_T}.from_integer ({P_LOCAL}.viewheight // 2)
							if player.deltaviewheight <= create {FIXED_T}.from_integer (0) then
								player.deltaviewheight := create {FIXED_T}.from_integer (1)
							end
						end
						if player.deltaviewheight /= create {FIXED_T}.from_integer (0) then
							player.deltaviewheight := player.deltaviewheight + create {FIXED_T}.from_integer ({M_FIXED}.fracunit // 4)
							if player.deltaviewheight = create {FIXED_T}.from_integer (0) then
								player.deltaviewheight := create {FIXED_T}.from_integer (1)
							end
						end
					end
					player.viewz := mo.z + player.viewheight + bob
					if player.viewz > mo.ceilingz - create {FIXED_T}.from_integer (4 * {M_FIXED}.fracunit) then
						player.viewz := mo.ceilingz - create {FIXED_T}.from_integer (4 * {M_FIXED}.fracunit)
					end
				end
			end
		end
	
end -- class P_USER

Generated by ISE EiffelStudio