note description: "[ p_pspr.c Weapon sprite animation, weapon objects. Action functions for weapons. ]" 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_PSPR inherit WEAPONTYPE_T AMMOTYPE_T SFXENUM_T STATENUM_T create make feature i_main: I_MAIN make (a_i_main: like i_main) do i_main := a_i_main end feature -- psprnum_t Ps_weapon: INTEGER_32 = 0 Ps_flash: INTEGER_32 = 1 Numpsprites: INTEGER_32 = 2 Ff_framemask: INTEGER_32 = 32767 Ff_fullbright: INTEGER_32 = 32768 -- flag in thing->frame Bfgcells: INTEGER_32 = 40 -- plasma cells for a bfg attack feature Weaponbottom: INTEGER_32 once Result := 128 * {M_FIXED}.fracunit ensure instance_free: class end Weapontop: INTEGER_32 once Result := 32 * {M_FIXED}.fracunit end Raisespeed: INTEGER_32 once Result := {M_FIXED}.fracunit * 6 ensure instance_free: class end Lowerspeed: INTEGER_32 once Result := {M_FIXED}.fracunit * 6 end feature a_raise (player: PLAYER_T; psp: PSPDEF_T) local newstate: INTEGER_32 do psp.sy := psp.sy - create {FIXED_T}.from_integer (Raisespeed) if psp.sy > create {FIXED_T}.from_integer (Weapontop) then else psp.sy := create {FIXED_T}.from_integer (Weapontop) newstate := {D_ITEMS}.weaponinfo [player.readyweapon].readystate p_setpsprite (player, Ps_weapon, newstate) end end a_weaponready (player: PLAYER_T; psp: PSPDEF_T) -- The player can fire the weapon -- or change to another weapon at this time. -- Follows after getting weapon up, -- or after previous attack/fire sequence. local newstate: INTEGER_32 angle: INTEGER_32 returned: BOOLEAN do check attached player.mo as mo then if mo.state = {INFO}.states [{INFO}.s_play_atk1] or mo.state = {INFO}.states [{INFO}.s_play_atk2] then i_main.P_mobj.p_setmobjstate (mo, {INFO}.s_play).do_nothing end if player.readyweapon = Wp_chainsaw and psp.state = {INFO}.states [{INFO}.s_saw] then i_main.S_sound.s_startsound (mo, {SFXENUM_T}.sfx_sawidl) end if player.pendingweapon /= Wp_nochange or player.health = 0 then newstate := {D_ITEMS}.weaponinfo [player.readyweapon].downstate p_setpsprite (player, Ps_weapon, newstate) returned := True end if not returned then if player.cmd.buttons & {D_EVENT}.bt_attack /= 0 then if not player.attackdown or (player.readyweapon /= Wp_missile and player.readyweapon /= Wp_bfg) then player.attackdown := True p_fireweapon (player) returned := True end else player.attackdown := False end end if not returned then angle := (128 * i_main.P_tick.leveltime) & {R_MAIN}.finemask psp.sx := create {FIXED_T}.from_integer ({M_FIXED}.fracunit + {M_FIXED}.fixedmul (player.bob, {R_MAIN}.finecosine [angle]).as_integer_32) angle := angle & ({R_MAIN}.fineangles // 2 - 1) psp.sy := create {FIXED_T}.from_integer (Weapontop + {M_FIXED}.fixedmul (player.bob, create {FIXED_T}.from_integer ({R_MAIN}.finesine [angle])).as_integer_32) end end end feature p_fireweapon (player: PLAYER_T) local newstate: INTEGER_32 do if not p_checkammo (player) then else check attached player.mo as mo then i_main.P_mobj.p_setmobjstate (mo, {STATENUM_T}.s_play_atk1).do_nothing newstate := {D_ITEMS}.weaponinfo [player.readyweapon].atkstate p_setpsprite (player, Ps_weapon, newstate) i_main.P_enemy.p_noisealert (mo, mo) end end end p_checkammo (player: PLAYER_T): BOOLEAN -- Returns true if there is enough ammo to shoot. -- If not, selects the next weapon to use. local ammo: INTEGER_32 count: INTEGER_32 do ammo := {D_ITEMS}.weaponinfo [player.readyweapon].ammo if player.readyweapon = Wp_bfg then count := Bfgcells elseif player.readyweapon = Wp_supershotgun then count := 2 else count := 1 end if ammo = Am_noammo or player.ammo [ammo] >= count then Result := True else from player.pendingweapon := Wp_nochange until player.pendingweapon /= Wp_nochange loop if player.weaponowned [Wp_plasma] and player.ammo [Am_cell] /= 0 and i_main.Doomstat_h.gamemode /= {GAME_MODE_T}.shareware then player.pendingweapon := Wp_plasma elseif player.weaponowned [Wp_supershotgun] and player.ammo [Am_shell] > 2 and i_main.Doomstat_h.gamemode = {GAME_MODE_T}.commercial then player.pendingweapon := Wp_supershotgun elseif player.weaponowned [Wp_chaingun] and player.ammo [Am_clip] /= 0 then player.pendingweapon := Wp_chaingun elseif player.weaponowned [Wp_shotgun] and player.ammo [Am_shell] /= 0 then player.pendingweapon := Wp_shotgun elseif player.ammo [Am_clip] /= 0 then player.pendingweapon := Wp_pistol elseif player.weaponowned [Wp_chainsaw] then player.pendingweapon := Wp_chainsaw elseif player.weaponowned [Wp_missile] and player.ammo [Am_misl] /= 0 then player.pendingweapon := Wp_missile elseif player.weaponowned [Wp_bfg] and player.ammo [Am_cell] > 40 and (i_main.Doomstat_h.gamemode /= {GAME_MODE_T}.shareware) then player.pendingweapon := Wp_bfg else player.pendingweapon := Wp_fist end end p_setpsprite (player, Ps_weapon, {D_ITEMS}.weaponinfo [player.readyweapon].downstate) Result := False end end feature p_setuppsprites (player: PLAYER_T) -- Called at start of level for each player local i: INTEGER_32 do from i := 0 until i >= Numpsprites loop player.psprites [i].state := Void i := i + 1 end player.pendingweapon := player.readyweapon p_bringupweapon (player) end p_bringupweapon (player: PLAYER_T) -- Starts bringing up the pending weapon up -- from the bottom of the screen. -- Uses player local newstate: INTEGER_32 do if player.pendingweapon = Wp_nochange then player.pendingweapon := player.readyweapon end if player.pendingweapon = Wp_chainsaw then i_main.S_sound.s_startsound (player.mo, {SFXENUM_T}.sfx_sawup) end newstate := {D_ITEMS}.weaponinfo [player.pendingweapon].upstate player.pendingweapon := Wp_nochange player.psprites [Ps_weapon].sy := create {FIXED_T}.from_integer (Weaponbottom) p_setpsprite (player, Ps_weapon, newstate) end p_setpsprite (player: PLAYER_T; position: INTEGER_32; a_stnum: INTEGER_32) local psp: PSPDEF_T state: STATE_T break: BOOLEAN stnum: INTEGER_32 did: BOOLEAN action_target: STRING_8 do stnum := a_stnum psp := player.psprites [position] from until did and (break or psp.tics /= 0) loop did := True if stnum = 0 then psp.state := Void break := True end if not break then state := {INFO}.states [stnum] psp.state := state psp.tics := state.tics.to_integer_32 if state.misc1 /= 0 then psp.sx := create {FIXED_T}.from_integer ((state.misc1 |<< {M_FIXED}.fracbits).to_integer_32) psp.sy := create {FIXED_T}.from_integer ((state.misc2 |<< {M_FIXED}.fracbits).to_integer_32) end if attached state.action as action then action.call (i_main.P_pspr, player, psp) if psp.state = Void then break := True end end end if not break then check attached psp.state as s then stnum := s.nextstate end end end end p_movepsprites (player: PLAYER_T) -- Called every tic by player thinking routine. local i: INTEGER_32 psp: INTEGER_32 state: STATE_T do psp := 0 from i := 0 until i >= Numpsprites loop state := player.psprites [psp].state if state /= Void then if player.psprites [psp].tics /= -1 then player.psprites [psp].tics := player.psprites [psp].tics - 1 if player.psprites [psp].tics = 0 then p_setpsprite (player, i, state.nextstate) end end end psp := psp + 1 i := i + 1 end player.psprites [Ps_flash].sx := player.psprites [Ps_weapon].sx player.psprites [Ps_flash].sy := player.psprites [Ps_weapon].sy end feature a_light0 (player: PLAYER_T; psp: PSPDEF_T) do player.extralight := 0 ensure instance_free: class end a_lower (player: PLAYER_T; psp: PSPDEF_T) -- Lowers current weapon, -- and changes weapon at bottom. do psp.sy := psp.sy + create {FIXED_T}.from_integer (Lowerspeed) if psp.sy < create {FIXED_T}.from_integer (Weaponbottom) then else if player.playerstate = {D_PLAYER}.pst_dead then psp.sy := create {FIXED_T}.from_integer (Weaponbottom) else if player.health = 0 then p_setpsprite (player, Ps_weapon, S_null) else player.readyweapon := player.pendingweapon p_bringupweapon (player) end end end end a_punch (player: PLAYER_T; psp: PSPDEF_T) local angle: ANGLE_T damage: INTEGER_32 slope: INTEGER_32 do damage := (i_main.M_random.p_random \\ 10 + 1) |<< 1 if player.powers [{POWERTYPE_T}.pw_strength] /= 0 then damage := damage * 10 end check attached player.mo as mo then angle := mo.angle angle := angle + create {ANGLE_T}.from_natural (((i_main.M_random.p_random - i_main.M_random.p_random) |<< 18).to_natural_32) slope := i_main.P_map.p_aimlineattack (mo, angle, create {FIXED_T}.from_integer ({P_LOCAL}.meleerange)).as_integer_32 i_main.P_map.p_lineattack (mo, angle, create {FIXED_T}.from_integer ({P_LOCAL}.meleerange), create {FIXED_T}.from_integer (slope), damage) if attached i_main.P_map.linetarget as lt then i_main.S_sound.s_startsound (mo, Sfx_punch) mo.angle := i_main.R_main.r_pointtoangle2 (mo.x, mo.y, lt.x, lt.y) end end end a_refire (player: PLAYER_T; psp: PSPDEF_T) -- The player can re-fire the weapon -- without lowering it entirely. do if player.cmd.buttons & {D_EVENT}.bt_attack /= 0 and player.pendingweapon = Wp_nochange and player.health /= 0 then player.refire := player.refire + 1 p_fireweapon (player) else player.refire := 0 p_checkammo (player).do_nothing end end a_firepistol (player: PLAYER_T; psp: PSPDEF_T) do check attached player.mo as mo then i_main.S_sound.s_startsound (mo, Sfx_pistol) i_main.P_mobj.p_setmobjstate (mo, S_play_atk2).do_nothing player.ammo [{D_ITEMS}.weaponinfo [player.readyweapon].ammo] := player.ammo [{D_ITEMS}.weaponinfo [player.readyweapon].ammo] - 1 p_setpsprite (player, Ps_flash, {D_ITEMS}.weaponinfo [player.readyweapon].flashstate) p_bulletslope (mo) p_gunshot (mo, not player.refire.to_boolean) end end bulletslope: FIXED_T p_bulletslope (mo: MOBJ_T) -- Sets a slope so a near miss is at aproximately -- the height of the intended target local an: ANGLE_T do an := mo.angle bulletslope := i_main.P_map.p_aimlineattack (mo, an, create {FIXED_T}.from_integer (16 * 64 * {M_FIXED}.fracunit)) if i_main.P_map.linetarget = Void then an := an + create {ANGLE_T}.from_natural ((1 |<< 26).to_natural_32) bulletslope := i_main.P_map.p_aimlineattack (mo, an, create {FIXED_T}.from_integer (16 * 64 * {M_FIXED}.fracunit)) if i_main.P_map.linetarget = Void then an := an - create {ANGLE_T}.from_natural ((2 |<< 26).to_natural_32) bulletslope := i_main.P_map.p_aimlineattack (mo, an, create {FIXED_T}.from_integer (16 * 64 * {M_FIXED}.fracunit)) end end end p_gunshot (mo: MOBJ_T; accurate: BOOLEAN) local angle: ANGLE_T damage: INTEGER_32 do damage := 5 * (i_main.M_random.p_random \\ 3 + 1) angle := mo.angle if not accurate then angle := angle + create {ANGLE_T}.from_natural (((i_main.M_random.p_random - i_main.M_random.p_random) |<< 18).to_natural_32) end i_main.P_map.p_lineattack (mo, angle, create {FIXED_T}.from_integer ({P_LOCAL}.missilerange), bulletslope, damage) end a_light1 (player: PLAYER_T; psp: PSPDEF_T) do {NOT_IMPLEMENTED}.not_implemented ("A_Light1", False) end a_light2 (player: PLAYER_T; psp: PSPDEF_T) do {NOT_IMPLEMENTED}.not_implemented ("A_Light2", False) end a_fireshotgun (player: PLAYER_T; psp: PSPDEF_T) do {NOT_IMPLEMENTED}.not_implemented ("A_FireShotgun", False) end a_fireshotgun2 (player: PLAYER_T; psp: PSPDEF_T) do {NOT_IMPLEMENTED}.not_implemented ("A_FireShotgun2", False) end a_checkreload (player: PLAYER_T; psp: PSPDEF_T) do {NOT_IMPLEMENTED}.not_implemented ("A_CheckReload", False) end a_firecgun (player: PLAYER_T; psp: PSPDEF_T) do {NOT_IMPLEMENTED}.not_implemented ("A_FireCGun", False) end a_gunflash (player: PLAYER_T; psp: PSPDEF_T) do {NOT_IMPLEMENTED}.not_implemented ("A_GunFlash", False) end a_firemissile (player: PLAYER_T; psp: PSPDEF_T) do {NOT_IMPLEMENTED}.not_implemented ("A_FireMissile", False) end a_saw (player: PLAYER_T; psp: PSPDEF_T) do {NOT_IMPLEMENTED}.not_implemented ("A_Saw", False) end a_fireplasma (player: PLAYER_T; psp: PSPDEF_T) do {NOT_IMPLEMENTED}.not_implemented ("A_FirePlasma", False) end a_bfgsound (player: PLAYER_T; psp: PSPDEF_T) do {NOT_IMPLEMENTED}.not_implemented ("A_BFGSound", False) end a_firebfg (player: PLAYER_T; psp: PSPDEF_T) do {NOT_IMPLEMENTED}.not_implemented ("A_FireBFG", False) end a_bfgspray (mo: MOBJ_T) -- Spawn a BFG explosion on every monster in view do {NOT_IMPLEMENTED}.not_implemented ("A_BFGSpray", False) end feature p_dropweapon (player: PLAYER_T) -- Player died, so put the weapon away do p_setpsprite (player, Ps_weapon, {D_ITEMS}.weaponinfo [player.readyweapon].downstate) end end -- class P_PSPR
Generated by ISE EiffelStudio