Hitscan
hitscan <x1> <y1> <z1> <sect1> <cos of ang> <sin of ang> <zvel> <hit sector return var> <hit wall return var> <hit sprite return var> <hit x return var> <hit y return var> <hit z return var> <clip mask>
Hitscan returns the values of what would be hit if one travelled in a straight line from a set of coordinates in a specified direction.
All parameters are gamevars. The first three are the coordinates from which the hitscan occurs, followed by the scanning sector. The cos, then the sin of an angle (typically the ang of the actor performing the scan) come next, followed by the z angle, which must be calculated before the hitscan. The six return gamevars hold the values of what the hitscan hits. The value of clipmask tells hitscan which sorts of things it can hit. A clipmask of 4294901808 is useful for most purposes.
HITWALL and HITSPRITE's default value is -1. They will be filled up with the wall id or sprite id that is hit. In other words, if running hitscan against an actor and HITWALL's value is not -1, that means the target actor is not hit. If it is hit, HITSPRITE will be set to the id of the actor.
Example of hitscan originating from the player:
// This state will return the sector, wall, and sprite(id, x ,y, and z data)currently under the crosshair. state checkhitscan getplayer[THISACTOR].posx MY_X getplayer[THISACTOR].posy MY_Y getplayer[THISACTOR].posz MY_Z getplayer[THISACTOR].cursectnum MY_SECTOR getplayer[THISACTOR].ang MY_ANGLE getplayer[THISACTOR].horiz MY_ZDIST subvar MY_ZDIST 100 mulvar MY_ZDIST -2048 cos MY_COS MY_ANGLE sin MY_SIN MY_ANGLE hitscan MY_X MY_Y MY_Z MY_SECTOR MY_COS MY_SIN MY_ZDIST HITSECTOR HITWALL HITSPRITE HITX HITY HITZ 4294901808 ends
If the hitscan does not originate from the player but from another actor, the code is a bit different:
- Ensure the hitscan cstat bit is set on the target actor
- The angle needs to be calculated
- The zdist calculation is different
- If appropriate, the "my_z" coordinate needs to be shifted up to the "eye level" of the actor. You should be able to get away with using a constant value around 4096-8192 for most cases, but it depends on the exact height of the actor.
state checkhitscan geta[].x MY_X geta[].y MY_Y geta[].z MY_Z geta[].sectnum MY_SECTOR geta[otheractor].x OTHER_X geta[otheractor].y OTHER_Y geta[otheractor].y OTHER_Z geta[otheractor].cstat CSTAT_BACKUP seta[otheractor].cstat 256 // enable hitscan bit is set or the sprite will not be detected // Calculate angle sub OTHER_X MY_X sub OTHER_Y MY_Y getangle MY_ANGLE OTHER_X OTHER_Y cos MY_COS MY_ANGLE sin MY_SIN MY_ANGLE // Calculate zdist set MY_ZDIST OTHER_Z sub MY_ZDIST MY_Z shiftvarl MY_ZDIST 14 ldist xydist THISACTOR otheractor ife xydist 0 set xydist 1 divvarvar MY_ZDIST xydist // Bring Z position to "eye level", exact value needed here depends on height of the sprite // This could maybe also be calculated using ysize sub MY_Z 8192 hitscan MY_X MY_Y MY_Z MY_SECTOR MY_COS MY_SIN MY_ZDIST HITSECTOR HITWALL HITSPRITE HITX HITY HITZ 4294901808 // reinstate original cstat (useful in case the sprite you're checking against is a non-blocking effect sprite for instance) seta[otheractor].cstat CSTAT_BACKUP ends