note description: "[ p_map.c Movement, collision handling. Shooting and aiming ]" 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_MAP inherit MOBJFLAG_T MOBJTYPE_T create make feature i_main: I_MAIN make (a_i_main: like i_main) do i_main := a_i_main create spechit.make_filled (Void, 0, Maxspecialcross - 1) create tmbbox.make_filled (0, 0, 3) end feature ceilingline: detachable LINE_T -- keep track of the line that lowers the ceiling, -- so missiles don't explode against sky hack walls floatok: BOOLEAN -- If true, move would be ok -- if within tmfloorz - tmceilingz tmbbox: ARRAY [INTEGER_32] tmthing: detachable MOBJ_T tmflags: INTEGER_32 tmx: INTEGER_32 tmy: INTEGER_32 tmfloorz: FIXED_T tmceilingz: FIXED_T tmdropoffz: FIXED_T numspechit: INTEGER_32 assign set_numspechit set_numspechit (a_numspechit: like numspechit) do numspechit := a_numspechit end spechit: ARRAY [detachable LINE_T] Maxspecialcross: INTEGER_32 = 8 feature usething: detachable MOBJ_T p_uselines (player: PLAYER_T) -- Looks for special lines in front of the player to activate require player.mo /= Void local angle: INTEGER_32 x1: FIXED_T y1: FIXED_T x2: FIXED_T y2: FIXED_T do check attached player.mo as mo then usething := mo angle := mo.angle |>> {TABLES}.angletofineshift.as_integer_32 x1 := mo.x y1 := mo.y x2 := x1 + create {FIXED_T}.from_integer (({P_LOCAL}.userange |>> {M_FIXED}.fracbits) * i_main.R_main.Finecosine [angle].as_integer_32) y2 := y1 + create {FIXED_T}.from_integer (({P_LOCAL}.userange |>> {M_FIXED}.fracbits) * i_main.R_main.Finesine [angle]) i_main.P_maputl.p_pathtraverse (x1, y1, x2, y2, {P_LOCAL}.pt_addlines, agent ptr_usetraverse).do_nothing end end ptr_usetraverse (in: INTERCEPT_T): BOOLEAN require usething /= Void local side: INTEGER_32 do check attached in.line as line and then attached usething as ut then if line.special = 0 then i_main.P_maputl.p_lineopening (line) if i_main.P_maputl.openrange <= create {FIXED_T}.from_integer (0) then i_main.S_sound.s_startsound (usething, {SFXENUM_T}.sfx_noway) Result := False else Result := True end else side := 0 if i_main.P_maputl.p_pointonlineside (ut.x, ut.y, line) = 1 then side := 1 end i_main.P_switch.p_usespecialline (ut, line, side).do_nothing Result := False end end end p_trymove (thing: MOBJ_T; x, y: FIXED_T): BOOLEAN -- Attempt to move to a new position, -- crossing special lines unless MF_TELEPORT is set local oldx: FIXED_T oldy: FIXED_T side: INTEGER_32 oldside: INTEGER_32 ld: LINE_T returned: BOOLEAN do floatok := False if not p_checkposition (thing, x, y) then returned := True Result := False end if not returned then if thing.flags & {MOBJFLAG_T}.mf_noclip = 0 then if tmceilingz - tmfloorz < thing.height then returned := True Result := False end if not returned then floatok := True if thing.flags & {MOBJFLAG_T}.mf_teleport = 0 and tmceilingz - thing.z < thing.height then returned := True Result := False end end if not returned then if thing.flags & {MOBJFLAG_T}.mf_teleport = 0 and tmfloorz - thing.z > create {FIXED_T}.from_integer (24 * {M_FIXED}.fracunit) then returned := True Result := False end end if not returned then if thing.flags & ({MOBJFLAG_T}.mf_dropoff | {MOBJFLAG_T}.mf_float) = 0 and tmfloorz - tmdropoffz > create {FIXED_T}.from_integer (24 * {M_FIXED}.fracunit) then returned := True Result := False end end end end if not returned then i_main.P_maputl.p_unsetthingposition (thing) oldx := thing.x oldy := thing.y thing.floorz := tmfloorz thing.ceilingz := tmceilingz thing.x := x thing.y := y i_main.P_maputl.p_setthingposition (thing) if thing.flags & ({MOBJFLAG_T}.mf_teleport | {MOBJFLAG_T}.mf_noclip) = 0 then from until numspechit <= 0 loop numspechit := numspechit - 1 ld := spechit [numspechit] check attached ld then side := i_main.P_maputl.p_pointonlineside (thing.x, thing.y, ld) oldside := i_main.P_maputl.p_pointonlineside (oldx, oldy, ld) if side /= oldside then if ld.special /= 0 then i_main.P_spec.p_crossspecialline ({UTILS [LINE_T]}.first_index (i_main.P_setup.lines, ld), oldside, thing) end end end end end Result := True end ensure (not Result) implies thing ~ old thing end p_checkposition (thing: MOBJ_T; x, y: FIXED_T): BOOLEAN -- This is purely informative, nothing is modified -- (except things picked up). -- -- in: -- a mobj_t (can be valid or invalid) -- a position to be checked -- (doesn't need to be related to the mobj_t->x,y) -- -- during: -- special things are touched if MF_PICKUP -- early out in solid lines? -- -- out: -- newsubsec -- floorz -- ceilingz -- tmdropoffz -- the lowest point contacted -- (monsters won't move to a dropoff) -- speciallines[] -- numspeciallines local xl: INTEGER_32 xh: INTEGER_32 yl: INTEGER_32 yh: INTEGER_32 bx: INTEGER_32 by: INTEGER_32 newsubsec: SUBSECTOR_T returned: BOOLEAN do tmthing := thing tmflags := thing.flags tmx := x.as_integer_32 tmy := y.as_integer_32 tmbbox [{M_BBOX}.boxtop] := (y + thing.radius).as_integer_32 tmbbox [{M_BBOX}.boxbottom] := (y - thing.radius).as_integer_32 tmbbox [{M_BBOX}.boxright] := (x + thing.radius).as_integer_32 tmbbox [{M_BBOX}.boxleft] := (x - thing.radius).as_integer_32 newsubsec := i_main.R_main.r_pointinsubsector (x, y) ceilingline := Void check attached newsubsec.sector as sector then tmfloorz := sector.floorheight tmdropoffz := tmfloorz tmceilingz := sector.ceilingheight end i_main.R_main.validcount := i_main.R_main.validcount + 1 numspechit := 0 if tmflags & {MOBJFLAG_T}.mf_noclip /= 0 then Result := True returned := True end if not returned then xl := (tmbbox [{M_BBOX}.boxleft] - i_main.P_setup.bmaporgx.as_integer_32 - {P_LOCAL}.maxradius) |>> {P_LOCAL}.mapblockshift xh := (tmbbox [{M_BBOX}.boxright] - i_main.P_setup.bmaporgx.as_integer_32 + {P_LOCAL}.maxradius) |>> {P_LOCAL}.mapblockshift yl := (tmbbox [{M_BBOX}.boxbottom] - i_main.P_setup.bmaporgy.as_integer_32 - {P_LOCAL}.maxradius) |>> {P_LOCAL}.mapblockshift yh := (tmbbox [{M_BBOX}.boxtop] - i_main.P_setup.bmaporgy.as_integer_32 + {P_LOCAL}.maxradius) |>> {P_LOCAL}.mapblockshift from bx := xl until returned or bx > xh loop from by := yl until returned or by > yh loop if not i_main.P_maputl.p_blockthingsiterator (bx, by, agent pit_checkthing) then Result := False returned := True end by := by + 1 end bx := bx + 1 end end if not returned then xl := (tmbbox [{M_BBOX}.boxleft] - i_main.P_setup.bmaporgx.as_integer_32) |>> {P_LOCAL}.mapblockshift xh := (tmbbox [{M_BBOX}.boxright] - i_main.P_setup.bmaporgx.as_integer_32) |>> {P_LOCAL}.mapblockshift yl := (tmbbox [{M_BBOX}.boxbottom] - i_main.P_setup.bmaporgy.as_integer_32) |>> {P_LOCAL}.mapblockshift yh := (tmbbox [{M_BBOX}.boxtop] - i_main.P_setup.bmaporgy.as_integer_32) |>> {P_LOCAL}.mapblockshift from bx := xl until returned or bx > xh loop from by := yl until returned or by > yh loop if not i_main.P_maputl.p_blocklinesiterator (bx, by, agent pit_checkline) then Result := False returned := True end by := by + 1 end bx := bx + 1 end end if not returned then Result := True end end pit_checkthing (thing: MOBJ_T): BOOLEAN local blockdist: FIXED_T solid: BOOLEAN damage: INTEGER_32 returned: BOOLEAN do if thing.flags & (Mf_solid | Mf_special | Mf_shootable) = 0 then Result := True returned := True end if not returned then check attached tmthing as tmt then blockdist := thing.radius + tmt.radius end if (thing.x - create {FIXED_T}.from_integer (tmx)).abs >= blockdist.as_integer_32 or (thing.y - create {FIXED_T}.from_integer (tmy)).abs >= blockdist.as_integer_32 then Result := True returned := True end end if not returned then if thing = tmthing then Result := True returned := True end end if not returned then check attached tmthing as tmt then if tmt.flags & Mf_skullfly /= 0 then check attached tmt.info as info then damage := ((i_main.M_random.p_random \\ 8) + 1) * info.damage i_main.P_inter.p_damagemobj (thing, tmthing, tmthing, damage) tmt.flags := tmt.flags & Mf_skullfly.bit_not tmt.momx := create {FIXED_T}.from_integer (0) tmt.momy := create {FIXED_T}.from_integer (0) tmt.momz := create {FIXED_T}.from_integer (0) i_main.P_mobj.p_setmobjstate (tmt, info.spawnstate).do_nothing Result := False returned := True end end end end if not returned then check attached tmthing as tmt then if tmt.flags & Mf_missile /= 0 then if tmt.z > thing.z + thing.height then Result := True returned := True elseif tmt.z + tmt.height < thing.z then Result := True returned := True end if not returned then if attached tmt.target as target and then (target.type = thing.type or (target.type = Mt_knight and thing.type = Mt_bruiser) or (target.type = Mt_bruiser and thing.type = Mt_knight)) then if thing = tmt.target then Result := True returned := True elseif thing.type /= Mt_player then Result := False returned := True end end end if not returned then if thing.flags & Mf_shootable = 0 then Result := thing.flags & Mf_solid = 0 returned := True end end if not returned then check attached tmt.info as info then damage := ((i_main.M_random.p_random \\ 8) + 1) * info.damage i_main.P_inter.p_damagemobj (thing, tmthing, tmt.target, damage) end Result := False returned := True end end end end if not returned then if thing.flags & Mf_special /= 0 then solid := thing.flags & Mf_solid /= 0 if tmflags & Mf_pickup /= 0 then check attached tmthing as tmt then i_main.P_inter.p_touchspecialthing (thing, tmt) end end Result := not solid returned := True end end if not returned then Result := thing.flags & Mf_solid = 0 end end pit_checkline (ld: LINE_T): BOOLEAN -- Adjusts tmfloorz and tmceilingz as lines are contacted local returned: BOOLEAN do if tmbbox [{M_BBOX}.boxright] <= ld.bbox [{M_BBOX}.boxleft].as_integer_32 or tmbbox [{M_BBOX}.boxleft] >= ld.bbox [{M_BBOX}.boxright].as_integer_32 or tmbbox [{M_BBOX}.boxtop] <= ld.bbox [{M_BBOX}.boxbottom].as_integer_32 or tmbbox [{M_BBOX}.boxbottom] >= ld.bbox [{M_BBOX}.boxtop].as_integer_32 then Result := True returned := True end if not returned then if i_main.P_maputl.p_boxonlineside (tmbbox, ld) /= -1 then Result := True returned := True end end if not returned then if ld.backsector = Void then Result := False returned := True end end if not returned then check attached tmthing as tmt then if tmt.flags & Mf_missile = 0 then if ld.flags.to_integer_32 & {DOOMDATA_H}.ml_blocking /= 0 then Result := False returned := True elseif tmt.player = Void and ld.flags.to_integer_32 & {DOOMDATA_H}.ml_blockmonsters /= 0 then Result := False returned := True end end end end if not returned then i_main.P_maputl.p_lineopening (ld) if i_main.P_maputl.opentop < tmceilingz then tmceilingz := i_main.P_maputl.opentop ceilingline := ld end if i_main.P_maputl.openbottom > tmfloorz then tmfloorz := i_main.P_maputl.openbottom end if i_main.P_maputl.lowfloor < tmdropoffz then tmdropoffz := i_main.P_maputl.lowfloor end if ld.special /= 0 then spechit [numspechit] := ld numspechit := numspechit + 1 end Result := True end end feature -- SLIDE MOVE -- Allows the player to slide along any anled walls. slidemo: detachable MOBJ_T bestslidefrac: FIXED_T bestslideline: detachable LINE_T secondslidefrac: FIXED_T secondslideline: detachable LINE_T tmxmove: FIXED_T tmymove: FIXED_T p_slidemove_stairstep -- What is done at stairstep: label of P_SlideMove do check attached slidemo as mo then if not p_trymove (mo, mo.x, mo.y + mo.momy) then p_trymove (mo, mo.x + mo.momx, mo.y).do_nothing end end end p_slidemove_try: BOOLEAN -- One try o P_SlideMove -- Returns False if move was accomplished. -- If returned True, you P_SlideMove would have retried (goto retry:) local leadx: FIXED_T leady: FIXED_T trailx: FIXED_T traily: FIXED_T newx: FIXED_T newy: FIXED_T do check attached slidemo as mo then if mo.momx > create {FIXED_T}.from_integer (0) then leadx := mo.x + mo.radius trailx := mo.x - mo.radius else leadx := mo.x - mo.radius trailx := mo.x + mo.radius end if mo.momy > create {FIXED_T}.from_integer (0) then leady := mo.y + mo.radius traily := mo.y - mo.radius else leady := mo.y - mo.radius traily := mo.y + mo.radius end bestslidefrac := create {FIXED_T}.from_integer ({M_FIXED}.fracunit + 1) i_main.P_maputl.p_pathtraverse (leadx, leady, leadx + mo.momx, leady + mo.momy, {P_LOCAL}.pt_addlines, agent ptr_slidetraverse).do_nothing i_main.P_maputl.p_pathtraverse (trailx, leady, trailx + mo.momx, leady + mo.momy, {P_LOCAL}.pt_addlines, agent ptr_slidetraverse).do_nothing i_main.P_maputl.p_pathtraverse (leadx, traily, leadx + mo.momx, traily + mo.momy, {P_LOCAL}.pt_addlines, agent ptr_slidetraverse).do_nothing if bestslidefrac = create {FIXED_T}.from_integer ({M_FIXED}.fracunit + 1) then p_slidemove_stairstep Result := True else bestslidefrac := bestslidefrac - create {FIXED_T}.from_integer (2048) if bestslidefrac > create {FIXED_T}.from_integer (0) then newx := {M_FIXED}.fixedmul (mo.momx, bestslidefrac) newy := {M_FIXED}.fixedmul (mo.momy, bestslidefrac) if not p_trymove (mo, mo.x + newx, mo.y + newy) then p_slidemove_stairstep Result := True end else bestslidefrac := create {FIXED_T}.from_integer ({M_FIXED}.fracunit - (bestslidefrac + create {FIXED_T}.from_integer (2048)).as_integer_32) if bestslidefrac > create {FIXED_T}.from_integer ({M_FIXED}.fracunit) then bestslidefrac := create {FIXED_T}.from_integer ({M_FIXED}.fracunit) end if bestslidefrac <= create {FIXED_T}.from_integer (0) then Result := True else tmxmove := {M_FIXED}.fixedmul (mo.momx, bestslidefrac) tmymove := {M_FIXED}.fixedmul (mo.momy, bestslidefrac) check attached bestslideline as bs then p_hitslideline (bs) end mo.momx := tmxmove mo.momy := tmymove Result := not p_trymove (mo, mo.x + tmxmove, mo.y + tmymove) end end end end end p_slidemove (mo: MOBJ_T) -- The momx/momy move is bad, so try to slide -- along a wall. -- Find the first line hit, move flush to it, -- and slide along it -- -- This is a kludgy mess. local hitcount: INTEGER_32 move_done: BOOLEAN do slidemo := mo from hitcount := 1 until move_done or hitcount >= 3 loop move_done := p_slidemove_try hitcount := hitcount + 1 end end ptr_slidetraverse (in: INTERCEPT_T): BOOLEAN require slidemo_set: attached slidemo local returned: BOOLEAN goto_isblocking: BOOLEAN do if not in.isaline then i_main.i_error ("PTR_SlideTraverse: not a line?") end check attached slidemo as sm then check attached in.line as li then if li.flags.to_integer_32 & {DOOMDATA_H}.ml_twosided = 0 then if i_main.P_maputl.p_pointonlineside (sm.x, sm.y, li) /= 0 then Result := True returned := True else goto_isblocking := True end end if not returned and not goto_isblocking then i_main.P_maputl.p_lineopening (li) if i_main.P_maputl.openrange < sm.height then goto_isblocking := True elseif i_main.P_maputl.opentop - sm.z < sm.height then goto_isblocking := True elseif i_main.P_maputl.openbottom - sm.z > create {FIXED_T}.from_integer (24 * {M_FIXED}.fracunit) then goto_isblocking := True else Result := True returned := True end end if not returned then if in.frac < bestslidefrac then secondslidefrac := bestslidefrac secondslideline := bestslideline bestslidefrac := in.frac bestslideline := li end end end end end p_hitslideline (ld: LINE_T) -- Adjusts the xmove / ymove -- so that the next move will slide along the wall require slidemo_set: attached slidemo local side: INTEGER_32 lineangle: ANGLE_T moveangle: ANGLE_T deltaangle: ANGLE_T movelen: FIXED_T newlen: FIXED_T do if ld.slopetype = {R_DEFS}.st_horizontal then tmymove := create {FIXED_T}.from_integer (0) elseif ld.slopetype = {R_DEFS}.st_vertical then tmxmove := create {FIXED_T}.from_integer (0) else check attached slidemo as sm then side := i_main.P_maputl.p_pointonlineside (sm.x, sm.y, ld) lineangle := i_main.R_main.r_pointtoangle2 (create {FIXED_T}.from_integer (0), create {FIXED_T}.from_integer (0), ld.dx, ld.dy) if side = 1 then lineangle := lineangle + {TABLES}.ang180 end moveangle := i_main.R_main.r_pointtoangle2 (create {FIXED_T}.from_integer (0), create {FIXED_T}.from_integer (0), tmxmove, tmymove) deltaangle := moveangle - lineangle if deltaangle > {TABLES}.ang180 then deltaangle := deltaangle + {TABLES}.ang180 end lineangle := lineangle |>> {TABLES}.angletofineshift deltaangle := deltaangle |>> {TABLES}.angletofineshift movelen := i_main.P_maputl.p_aproxdistance (tmxmove, tmymove) newlen := {M_FIXED}.fixedmul (movelen, i_main.R_main.Finecosine [deltaangle.as_integer_32]) tmxmove := {M_FIXED}.fixedmul (newlen, i_main.R_main.Finecosine [lineangle.as_integer_32]) tmymove := {M_FIXED}.fixedmul (newlen, create {FIXED_T}.from_integer (i_main.R_main.Finesine [lineangle.as_integer_32])) end end end feature -- SECTOR HEIGHT CHANGING -- After modifying a sectors floor or ceiling height, -- call this routine to adjust the positions -- of all things that touch the sector. -- -- If anything doesn't fit anymore, true will be returned. -- If crunch is true, they will take damage -- as they are being crushed. -- If Crunch is false, you should set the sector height back -- the way it was and call P_ChangeSector again to undo the changes. crushchange: BOOLEAN nofit: BOOLEAN p_thingheightclip (thing: MOBJ_T): BOOLEAN local onfloor: BOOLEAN do onfloor := (thing.z = thing.floorz) p_checkposition (thing, thing.x, thing.y).do_nothing thing.floorz := tmfloorz thing.ceilingz := tmceilingz if onfloor then thing.z := thing.floorz else if thing.z + thing.height > thing.ceilingz then thing.z := thing.ceilingz - thing.height end end if thing.ceilingz - thing.floorz < thing.height then Result := False else Result := True end end pit_changesector (thing: MOBJ_T): BOOLEAN local mo: MOBJ_T do if p_thingheightclip (thing) then Result := True else if thing.health <= 0 then i_main.P_mobj.p_setmobjstate (thing, {STATENUM_T}.s_gibs).do_nothing thing.flags := thing.flags & Mf_solid.bit_not thing.height := create {FIXED_T}.from_integer (0) thing.radius := create {FIXED_T}.from_integer (0) Result := True else if thing.flags & Mf_dropped /= 0 then i_main.P_mobj.p_removemobj (thing) Result := True else if thing.flags & Mf_shootable = 0 then Result := True else nofit := True if crushchange and i_main.P_tick.leveltime & 3 = 0 then i_main.P_inter.p_damagemobj (thing, Void, Void, 10) mo := i_main.P_mobj.p_spawnmobj (thing.x, thing.y, thing.z + thing.height // create {FIXED_T}.from_integer (2), Mt_blood) mo.momx := create {FIXED_T}.from_integer ((i_main.M_random.p_random - i_main.M_random.p_random) |<< 12) mo.momy := create {FIXED_T}.from_integer ((i_main.M_random.p_random - i_main.M_random.p_random) |<< 12) end Result := True end end end end end p_changesector (sector: SECTOR_T; crunch: BOOLEAN): BOOLEAN local x: INTEGER_32 y: INTEGER_32 do nofit := False crushchange := crunch from x := sector.blockbox [{M_BBOX}.boxleft] until x > sector.blockbox [{M_BBOX}.boxright] loop from y := sector.blockbox [{M_BBOX}.boxbottom] until y > sector.blockbox [{M_BBOX}.boxtop] loop i_main.P_maputl.p_blockthingsiterator (x, y, agent pit_changesector).do_nothing y := y + 1 end x := x + 1 end Result := nofit end feature linetarget: detachable MOBJ_T -- who got hit (or NULL) shootthing: detachable MOBJ_T shootz: FIXED_T -- Height if not aiming up or down -- ???: use slope for monsters? la_damage: INTEGER_32 attackrange: FIXED_T aimslope: FIXED_T p_aimlineattack (t1: MOBJ_T; a_angle: ANGLE_T; distance: FIXED_T): FIXED_T local x2, y2: FIXED_T angle: ANGLE_T do angle := a_angle |>> {R_MAIN}.angletofineshift shootthing := t1 x2 := t1.x + (distance |>> {M_FIXED}.fracbits) * i_main.R_main.Finecosine [angle.as_integer_32] y2 := t1.y + (distance |>> {M_FIXED}.fracbits) * create {FIXED_T}.from_integer (i_main.R_main.Finesine [angle.as_integer_32]) shootz := t1.z + (t1.height |>> 1) + create {FIXED_T}.from_integer (8 * {M_FIXED}.fracunit) i_main.P_sight.topslope := create {FIXED_T}.from_integer (100 * {M_FIXED}.fracunit // 160) i_main.P_sight.bottomslope := create {FIXED_T}.from_integer (-100 * {M_FIXED}.fracunit // 160) attackrange := distance linetarget := Void i_main.P_maputl.p_pathtraverse (t1.x, t1.y, x2, y2, {P_LOCAL}.pt_addlines | {P_LOCAL}.pt_addthings, agent ptr_aimtraverse).do_nothing if linetarget /= Void then Result := aimslope else Result := create {FIXED_T}.from_integer (0) end end feature -- PTR_AimTraverse ptr_aimtraverse (in: INTERCEPT_T): BOOLEAN -- Sets linetarget and aimslope when a target is aimed at. local slope: FIXED_T dist: FIXED_T thingtopslope: FIXED_T thingbottomslope: FIXED_T do if in.isaline then check attached in.line as li then if li.flags.to_integer_32 & {DOOMDATA_H}.ml_twosided = 0 then Result := False else i_main.P_maputl.p_lineopening (li) if i_main.P_maputl.openbottom >= i_main.P_maputl.opentop then Result := False else dist := {M_FIXED}.fixedmul (attackrange, in.frac) check attached li.frontsector as front and then attached li.backsector as back then if front.floorheight /= back.floorheight then slope := {M_FIXED}.fixeddiv (i_main.P_maputl.openbottom - shootz, dist) if slope > i_main.P_sight.bottomslope then i_main.P_sight.bottomslope := slope end end if front.ceilingheight /= back.ceilingheight then slope := {M_FIXED}.fixeddiv (i_main.P_maputl.opentop - shootz, dist) if slope < i_main.P_sight.topslope then i_main.P_sight.topslope := slope end end end if i_main.P_sight.topslope <= i_main.P_sight.bottomslope then Result := False else Result := True end end end end else check attached in.thing as th then if th = shootthing then Result := True else if th.flags & Mf_shootable = 0 then Result := True else dist := {M_FIXED}.fixedmul (attackrange, in.frac) thingtopslope := {M_FIXED}.fixeddiv (th.z + th.height - shootz, dist) if thingtopslope < i_main.P_sight.bottomslope then Result := True else thingbottomslope := {M_FIXED}.fixeddiv (th.z - shootz, dist) if thingbottomslope > i_main.P_sight.topslope then Result := True else if thingtopslope > i_main.P_sight.topslope then thingtopslope := i_main.P_sight.topslope end if thingbottomslope < i_main.P_sight.bottomslope then thingbottomslope := i_main.P_sight.bottomslope end aimslope := (thingtopslope + thingbottomslope) // create {FIXED_T}.from_integer (2) linetarget := th Result := False end end end end end end end p_lineattack (t1: MOBJ_T; a_angle: ANGLE_T; distance: FIXED_T; slope: FIXED_T; damage: INTEGER_32) -- If damage == 0, it is just a test trace -- that will leave linetarget set. local x2, y2: FIXED_T angle: ANGLE_T do angle := a_angle |>> {R_MAIN}.angletofineshift shootthing := t1 la_damage := damage x2 := t1.x + (distance |>> {M_FIXED}.fracbits) * i_main.R_main.Finecosine [angle.as_integer_32] y2 := t1.y + (distance |>> {M_FIXED}.fracbits) * create {FIXED_T}.from_integer (i_main.R_main.Finesine [angle.as_integer_32]) shootz := t1.z + (t1.height |>> 1) + create {FIXED_T}.from_integer (8 * {M_FIXED}.fracunit) attackrange := distance aimslope := slope i_main.P_maputl.p_pathtraverse (t1.x, t1.y, x2, y2, {P_LOCAL}.pt_addlines | {P_LOCAL}.pt_addthings, agent ptr_shoottraverse).do_nothing end feature -- PTR_ShootTraverse ptr_shoottraverse_line_hitline (li: LINE_T; in: INTERCEPT_T): BOOLEAN local frac: FIXED_T x, y, z: FIXED_T hit_sky: BOOLEAN do frac := in.frac - {M_FIXED}.fixeddiv (create {FIXED_T}.from_integer (4 * {M_FIXED}.fracunit), attackrange) x := i_main.P_maputl.trace.x + {M_FIXED}.fixedmul (i_main.P_maputl.trace.dx, frac) y := i_main.P_maputl.trace.y + {M_FIXED}.fixedmul (i_main.P_maputl.trace.dy, frac) z := shootz + {M_FIXED}.fixedmul (aimslope, {M_FIXED}.fixedmul (frac, attackrange)) check attached li.frontsector as front then if front.ceilingpic.to_integer_32 = i_main.R_sky.skyflatnum then if z > front.ceilingheight then hit_sky := True end if not hit_sky and then attached li.backsector as back and then back.ceilingpic.to_integer_32 = i_main.R_sky.skyflatnum then hit_sky := True end end end if not hit_sky then i_main.P_mobj.p_spawnpuff (x, y, z) end Result := False end ptr_shoottraverse (in: INTERCEPT_T): BOOLEAN local goto_hitline: BOOLEAN dist: FIXED_T slope: FIXED_T x, y, z, frac: FIXED_T thingtopslope, thingbottomslope: FIXED_T do if in.isaline then check attached in.line as li then if li.special /= 0 then check attached shootthing as st then i_main.P_spec.p_shootspecialline (st, li) end end if li.flags.to_integer_32 & {DOOMDATA_H}.ml_twosided = 0 then goto_hitline := True else i_main.P_maputl.p_lineopening (li) dist := {M_FIXED}.fixedmul (attackrange, in.frac) check attached li.frontsector as front and then attached li.backsector as back then if front.floorheight /= back.floorheight then slope := {M_FIXED}.fixeddiv (i_main.P_maputl.openbottom - shootz, dist) if slope > aimslope then goto_hitline := True end end if front.ceilingheight /= back.ceilingheight then slope := {M_FIXED}.fixeddiv (i_main.P_maputl.opentop - shootz, dist) if slope < aimslope then goto_hitline := True end end end end if goto_hitline then Result := ptr_shoottraverse_line_hitline (li, in) else Result := True end end else check attached in.thing as th then if th = shootthing then Result := True else if th.flags & Mf_shootable = 0 then Result := True else dist := {M_FIXED}.fixedmul (attackrange, in.frac) thingtopslope := {M_FIXED}.fixeddiv (th.z + th.height - shootz, dist) if thingtopslope < aimslope then Result := True else thingbottomslope := {M_FIXED}.fixeddiv (th.z - shootz, dist) if thingbottomslope > aimslope then Result := True else frac := in.frac - {M_FIXED}.fixeddiv (create {FIXED_T}.from_integer (10 * {M_FIXED}.fracunit), attackrange) x := i_main.P_maputl.trace.x + {M_FIXED}.fixedmul (i_main.P_maputl.trace.dx, frac) y := i_main.P_maputl.trace.y + {M_FIXED}.fixedmul (i_main.P_maputl.trace.dy, frac) z := shootz + {M_FIXED}.fixedmul (aimslope, {M_FIXED}.fixedmul (frac, attackrange)) if th.flags & Mf_noblood /= 0 then i_main.P_mobj.p_spawnpuff (x, y, z) else i_main.P_mobj.p_spawnblood (x, y, z, la_damage) end if la_damage /= 0 then i_main.P_inter.p_damagemobj (th, shootthing, shootthing, la_damage) end Result := False end end end end end end end invariant spechit.lower = 0 and spechit.count = Maxspecialcross tmbbox.lower = 0 and tmbbox.count = 4 end -- class P_MAP
Generated by ISE EiffelStudio