Rev 8789 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5 | Plagman | 1 | //------------------------------------------------------------------------- |
2 | /* |
||
1652 | terminx | 3 | Copyright (C) 2010 EDuke32 developers and contributors |
5 | Plagman | 4 | |
1652 | terminx | 5 | This file is part of EDuke32. |
5 | Plagman | 6 | |
7 | EDuke32 is free software; you can redistribute it and/or |
||
8 | modify it under the terms of the GNU General Public License version 2 |
||
9 | as published by the Free Software Foundation. |
||
10 | |||
11 | This program is distributed in the hope that it will be useful, |
||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
||
14 | |||
15 | See the GNU General Public License for more details. |
||
16 | |||
17 | You should have received a copy of the GNU General Public License |
||
18 | along with this program; if not, write to the Free Software |
||
4541 | hendricks2 | 19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
5 | Plagman | 20 | */ |
21 | //------------------------------------------------------------------------- |
||
22 | |||
23 | #include "duke3d.h" |
||
1678 | terminx | 24 | #include "demo.h" |
8175 | terminx | 25 | #include "enet.h" |
5 | Plagman | 26 | |
4440 | terminx | 27 | #ifdef __ANDROID__ |
28 | #include "android.h" |
||
29 | #endif |
||
30 | |||
2652 | terminx | 31 | int32_t lastvisinc; |
3408 | helixhorne | 32 | hudweapon_t hudweap; |
33 | |||
5116 | hendricks2 | 34 | #ifdef SPLITSCREEN_MOD_HACKS |
2905 | helixhorne | 35 | static int32_t g_snum; |
5116 | hendricks2 | 36 | #endif |
5 | Plagman | 37 | |
1567 | terminx | 38 | extern int32_t g_levelTextTime, ticrandomseed; |
1068 | terminx | 39 | |
5979 | hendricks2 | 40 | int32_t g_numObituaries = 0; |
41 | int32_t g_numSelfObituaries = 0; |
||
1220 | terminx | 42 | |
6320 | hendricks2 | 43 | |
44 | int const icon_to_inv[ICON_MAX] = { GET_FIRSTAID, GET_FIRSTAID, GET_STEROIDS, GET_HOLODUKE, |
||
45 | GET_JETPACK, GET_HEATS, GET_SCUBA, GET_BOOTS }; |
||
46 | |||
47 | int const inv_to_icon[GET_MAX] = { ICON_STEROIDS, ICON_NONE, ICON_SCUBA, ICON_HOLODUKE, ICON_JETPACK, ICON_NONE, |
||
48 | ICON_NONE, ICON_HEATS, ICON_NONE, ICON_FIRSTAID, ICON_BOOTS }; |
||
49 | |||
6319 | hendricks2 | 50 | void P_AddKills(DukePlayer_t * const pPlayer, uint16_t kills) |
51 | { |
||
52 | pPlayer->actors_killed += kills; |
||
53 | } |
||
54 | |||
5826 | terminx | 55 | void P_UpdateScreenPal(DukePlayer_t * const pPlayer) |
5 | Plagman | 56 | { |
5825 | terminx | 57 | int inWater = 0; |
58 | int const playerSectnum = pPlayer->cursectnum; |
||
1899 | helixhorne | 59 | |
5825 | terminx | 60 | if (pPlayer->heat_on) |
61 | pPlayer->palette = SLIMEPAL; |
||
62 | else if (playerSectnum < 0) |
||
63 | pPlayer->palette = BASEPAL; |
||
64 | else if (sector[playerSectnum].ceilingpicnum >= FLOORSLIME && sector[playerSectnum].ceilingpicnum <= FLOORSLIME + 2) |
||
335 | terminx | 65 | { |
5825 | terminx | 66 | pPlayer->palette = SLIMEPAL; |
67 | inWater = 1; |
||
335 | terminx | 68 | } |
69 | else |
||
70 | { |
||
5825 | terminx | 71 | pPlayer->palette = (sector[pPlayer->cursectnum].lotag == ST_2_UNDERWATER) ? WATERPAL : BASEPAL; |
72 | inWater = 1; |
||
5 | Plagman | 73 | } |
2955 | helixhorne | 74 | |
5825 | terminx | 75 | g_restorePalette = 1+inWater; |
5 | Plagman | 76 | } |
77 | |||
5826 | terminx | 78 | static void P_IncurDamage(DukePlayer_t * const pPlayer) |
5 | Plagman | 79 | { |
5825 | terminx | 80 | if (VM_OnEvent(EVENT_INCURDAMAGE, pPlayer->i, P_Get(pPlayer->i)) != 0) |
3081 | terminx | 81 | return; |
5 | Plagman | 82 | |
5825 | terminx | 83 | sprite[pPlayer->i].extra -= pPlayer->extra_extra8>>8; |
5 | Plagman | 84 | |
5825 | terminx | 85 | int playerDamage = sprite[pPlayer->i].extra - pPlayer->last_extra; |
5 | Plagman | 86 | |
5825 | terminx | 87 | if (playerDamage >= 0) |
3081 | terminx | 88 | return; |
5 | Plagman | 89 | |
5825 | terminx | 90 | pPlayer->extra_extra8 = 0; |
5 | Plagman | 91 | |
5825 | terminx | 92 | if (pPlayer->inv_amount[GET_SHIELD] > 0) |
3081 | terminx | 93 | { |
5825 | terminx | 94 | int const shieldDamage = playerDamage * (20 + (krand()%30)) / 100; |
5 | Plagman | 95 | |
5825 | terminx | 96 | playerDamage -= shieldDamage; |
97 | pPlayer->inv_amount[GET_SHIELD] += shieldDamage; |
||
3081 | terminx | 98 | |
5825 | terminx | 99 | if (pPlayer->inv_amount[GET_SHIELD] < 0) |
3081 | terminx | 100 | { |
5825 | terminx | 101 | playerDamage += pPlayer->inv_amount[GET_SHIELD]; |
102 | pPlayer->inv_amount[GET_SHIELD] = 0; |
||
5 | Plagman | 103 | } |
104 | } |
||
105 | |||
5825 | terminx | 106 | sprite[pPlayer->i].extra = pPlayer->last_extra + playerDamage; |
5 | Plagman | 107 | } |
108 | |||
5826 | terminx | 109 | void P_QuickKill(DukePlayer_t * const pPlayer) |
5 | Plagman | 110 | { |
5825 | terminx | 111 | P_PalFrom(pPlayer, 48, 48,48,48); |
5 | Plagman | 112 | |
5825 | terminx | 113 | sprite[pPlayer->i].extra = 0; |
114 | sprite[pPlayer->i].cstat |= 32768; |
||
3081 | terminx | 115 | |
6911 | terminx | 116 | #ifndef EDUKE32_STANDALONE |
7808 | terminx | 117 | if (!FURY && ud.god == 0) |
5825 | terminx | 118 | A_DoGuts(pPlayer->i,JIBS6,8); |
6911 | terminx | 119 | #endif |
5 | Plagman | 120 | } |
121 | |||
6912 | terminx | 122 | static void Proj_DoWaterTracers(vec3_t startPos, vec3_t const *endPos, int n, int16_t sectNum) |
5 | Plagman | 123 | { |
6168 | terminx | 124 | if ((klabs(startPos.x - endPos->x) + klabs(startPos.y - endPos->y)) < 3084) |
5 | Plagman | 125 | return; |
126 | |||
6168 | terminx | 127 | vec3_t const v_inc = { tabledivide32_noinline(endPos->x - startPos.x, n + 1), tabledivide32_noinline(endPos->y - startPos.y, n + 1), |
128 | tabledivide32_noinline(endPos->z - startPos.z, n + 1) }; |
||
5825 | terminx | 129 | |
5829 | terminx | 130 | for (bssize_t i=n; i>0; i--) |
5 | Plagman | 131 | { |
6168 | terminx | 132 | startPos.x += v_inc.x; |
133 | startPos.y += v_inc.y; |
||
134 | startPos.z += v_inc.z; |
||
5825 | terminx | 135 | |
6168 | terminx | 136 | updatesector(startPos.x, startPos.y, §Num); |
5825 | terminx | 137 | |
138 | if (sectNum < 0) |
||
1490 | terminx | 139 | break; |
140 | |||
6912 | terminx | 141 | A_InsertSprite(sectNum, startPos.x, startPos.y, startPos.z, WATERBUBBLE, -32, 4 + (krand() & 3), 4 + (krand() & 3), krand() & 2047, 0, 0, |
142 | g_player[0].ps->i, 5); |
||
5 | Plagman | 143 | } |
144 | } |
||
145 | |||
5825 | terminx | 146 | static inline projectile_t *Proj_GetProjectile(int tile) |
5080 | terminx | 147 | { |
5159 | helixhorne | 148 | return ((unsigned)tile < MAXTILES && g_tile[tile].proj) ? g_tile[tile].proj : &DefaultProjectile; |
5080 | terminx | 149 | } |
150 | |||
5828 | terminx | 151 | static void A_HitscanProjTrail(const vec3_t *startPos, const vec3_t *endPos, int projAng, int tileNum, int16_t sectNum) |
5 | Plagman | 152 | { |
5825 | terminx | 153 | const projectile_t *const pProj = Proj_GetProjectile(tileNum); |
5 | Plagman | 154 | |
5828 | terminx | 155 | vec3_t spawnPos = { startPos->x + tabledivide32_noinline(sintable[(348 + projAng + 512) & 2047], pProj->offset), |
156 | startPos->y + tabledivide32_noinline(sintable[(projAng + 348) & 2047], pProj->offset), |
||
5825 | terminx | 157 | startPos->z + 1024 + (pProj->toffset << 8) }; |
3361 | helixhorne | 158 | |
5825 | terminx | 159 | int32_t n = ((FindDistance2D(spawnPos.x - endPos->x, spawnPos.y - endPos->y)) >> 8) + 1; |
5 | Plagman | 160 | |
5825 | terminx | 161 | vec3_t const increment = { tabledivide32_noinline((endPos->x - spawnPos.x), n), |
162 | tabledivide32_noinline((endPos->y - spawnPos.y), n), |
||
163 | tabledivide32_noinline((endPos->z - spawnPos.z), n) }; |
||
5 | Plagman | 164 | |
5825 | terminx | 165 | spawnPos.x += increment.x >> 2; |
166 | spawnPos.y += increment.y >> 2; |
||
167 | spawnPos.z += increment.z >> 2; |
||
5 | Plagman | 168 | |
5825 | terminx | 169 | int32_t j; |
252 | terminx | 170 | |
5829 | terminx | 171 | for (bssize_t i = pProj->tnum; i > 0; --i) |
5825 | terminx | 172 | { |
173 | spawnPos.x += increment.x; |
||
174 | spawnPos.y += increment.y; |
||
175 | spawnPos.z += increment.z; |
||
1207 | terminx | 176 | |
5828 | terminx | 177 | updatesectorz(spawnPos.x, spawnPos.y, spawnPos.z, §Num); |
5825 | terminx | 178 | |
179 | if (sectNum < 0) |
||
1488 | terminx | 180 | break; |
5825 | terminx | 181 | |
5828 | terminx | 182 | getzsofslope(sectNum, spawnPos.x, spawnPos.y, &n, &j); |
5825 | terminx | 183 | |
184 | if (spawnPos.z > j || spawnPos.z < n) |
||
861 | terminx | 185 | break; |
5825 | terminx | 186 | |
187 | j = A_InsertSprite(sectNum, spawnPos.x, spawnPos.y, spawnPos.z, pProj->trail, -32, |
||
5828 | terminx | 188 | pProj->txrepeat, pProj->tyrepeat, projAng, 0, 0, g_player[0].ps->i, 0); |
2642 | helixhorne | 189 | changespritestat(j, STAT_ACTOR); |
5 | Plagman | 190 | } |
191 | } |
||
192 | |||
5828 | terminx | 193 | int32_t A_GetHitscanRange(int spriteNum) |
5 | Plagman | 194 | { |
5828 | terminx | 195 | int const zOffset = (PN(spriteNum) == APLAYER) ? PHEIGHT : 0; |
5825 | terminx | 196 | hitdata_t hitData; |
5 | Plagman | 197 | |
5825 | terminx | 198 | SZ(spriteNum) -= zOffset; |
199 | hitscan((const vec3_t *)&sprite[spriteNum], SECT(spriteNum), sintable[(SA(spriteNum) + 512) & 2047], |
||
200 | sintable[SA(spriteNum) & 2047], 0, &hitData, CLIPMASK1); |
||
201 | SZ(spriteNum) += zOffset; |
||
5 | Plagman | 202 | |
5825 | terminx | 203 | return (FindDistance2D(hitData.pos.x - SX(spriteNum), hitData.pos.y - SY(spriteNum))); |
5 | Plagman | 204 | } |
205 | |||
5828 | terminx | 206 | static int A_FindTargetSprite(const spritetype *pSprite, int projAng, int projecTile) |
5 | Plagman | 207 | { |
5828 | terminx | 208 | static int const aimstats[] = { |
3955 | helixhorne | 209 | STAT_PLAYER, STAT_DUMMYPLAYER, STAT_ACTOR, STAT_ZOMBIEACTOR |
210 | }; |
||
5 | Plagman | 211 | |
5825 | terminx | 212 | int const playerNum = pSprite->picnum == APLAYER ? P_GetP(pSprite) : -1; |
4226 | helixhorne | 213 | |
6942 | terminx | 214 | if (playerNum != -1) |
335 | terminx | 215 | { |
5825 | terminx | 216 | if (!g_player[playerNum].ps->auto_aim) |
19 | terminx | 217 | return -1; |
3081 | terminx | 218 | |
5825 | terminx | 219 | if (g_player[playerNum].ps->auto_aim == 2) |
19 | terminx | 220 | { |
5825 | terminx | 221 | if (A_CheckSpriteTileFlags(projecTile,SFLAG_PROJECTILE) && (Proj_GetProjectile(projecTile)->workslike & PROJECTILE_RPG)) |
19 | terminx | 222 | return -1; |
3955 | helixhorne | 223 | |
6942 | terminx | 224 | #ifndef EDUKE32_STANDALONE |
7808 | terminx | 225 | if (!FURY) |
3955 | helixhorne | 226 | { |
7455 | terminx | 227 | switch (DYNAMICTILEMAP(projecTile)) |
228 | { |
||
229 | case TONGUE__STATIC: |
||
230 | case FREEZEBLAST__STATIC: |
||
231 | case SHRINKSPARK__STATIC: |
||
232 | case SHRINKER__STATIC: |
||
233 | case RPG__STATIC: |
||
234 | case FIRELASER__STATIC: |
||
235 | case SPIT__STATIC: |
||
236 | case COOLEXPLOSION1__STATIC: |
||
237 | return -1; |
||
238 | default: |
||
239 | break; |
||
240 | } |
||
3955 | helixhorne | 241 | } |
6942 | terminx | 242 | #endif |
19 | terminx | 243 | } |
244 | } |
||
120 | terminx | 245 | |
5825 | terminx | 246 | int const spriteAng = pSprite->ang; |
120 | terminx | 247 | |
6942 | terminx | 248 | #ifndef EDUKE32_STANDALONE |
249 | int const isShrinker = (pSprite->picnum == APLAYER && PWEAPON(playerNum, g_player[playerNum].ps->curr_weapon, WorksLike) == SHRINKER_WEAPON); |
||
250 | int const isFreezer = (pSprite->picnum == APLAYER && PWEAPON(playerNum, g_player[playerNum].ps->curr_weapon, WorksLike) == FREEZE_WEAPON); |
||
251 | #endif |
||
120 | terminx | 252 | |
5828 | terminx | 253 | vec2_t const d1 = { sintable[(spriteAng + 512 - projAng) & 2047], sintable[(spriteAng - projAng) & 2047] }; |
254 | vec2_t const d2 = { sintable[(spriteAng + 512 + projAng) & 2047], sintable[(spriteAng + projAng) & 2047] }; |
||
5825 | terminx | 255 | vec2_t const d3 = { sintable[(spriteAng + 512) & 2047], sintable[spriteAng & 2047] }; |
5 | Plagman | 256 | |
6942 | terminx | 257 | int lastDist = INT32_MAX; |
258 | int bestSprite = -1; |
||
5 | Plagman | 259 | |
5829 | terminx | 260 | for (bssize_t k=0; k<4; k++) |
5 | Plagman | 261 | { |
6942 | terminx | 262 | if (bestSprite >= 0) |
5 | Plagman | 263 | break; |
5825 | terminx | 264 | |
5829 | terminx | 265 | for (bssize_t spriteNum=headspritestat[aimstats[k]]; spriteNum >= 0; spriteNum=nextspritestat[spriteNum]) |
5825 | terminx | 266 | { |
267 | if ((sprite[spriteNum].xrepeat > 0 && sprite[spriteNum].extra >= 0 && |
||
5854 | terminx | 268 | (sprite[spriteNum].cstat & (257 + 32768)) == 257) && |
5825 | terminx | 269 | (A_CheckEnemySprite(&sprite[spriteNum]) || k < 2)) |
270 | { |
||
6942 | terminx | 271 | if (A_CheckEnemySprite(&sprite[spriteNum]) || PN(spriteNum) == APLAYER) |
5 | Plagman | 272 | { |
5825 | terminx | 273 | if (PN(spriteNum) == APLAYER && pSprite->picnum == APLAYER && pSprite != &sprite[spriteNum] && |
274 | (GTFLAGS(GAMETYPE_PLAYERSFRIENDLY) || |
||
275 | (GTFLAGS(GAMETYPE_TDM) && g_player[P_Get(spriteNum)].ps->team == g_player[playerNum].ps->team))) |
||
276 | continue; |
||
5 | Plagman | 277 | |
6942 | terminx | 278 | #ifndef EDUKE32_STANDALONE |
7808 | terminx | 279 | if (!FURY && ((isShrinker && sprite[spriteNum].xrepeat < 30 |
5863 | hendricks2 | 280 | && (PN(spriteNum) == SHARK || !(PN(spriteNum) >= GREENSLIME && PN(spriteNum) <= GREENSLIME + 7))) |
7566 | hendricks2 | 281 | || (isFreezer && sprite[spriteNum].pal == 1))) |
5825 | terminx | 282 | continue; |
6942 | terminx | 283 | #endif |
5825 | terminx | 284 | } |
5 | Plagman | 285 | |
6942 | terminx | 286 | vec2_t const vd = { (SX(spriteNum) - pSprite->x), (SY(spriteNum) - pSprite->y) }; |
5 | Plagman | 287 | |
5825 | terminx | 288 | if ((d1.y * vd.x <= d1.x * vd.y) && (d2.y * vd.x >= d2.x * vd.y)) |
289 | { |
||
6254 | hendricks2 | 290 | int const spriteDist = mulscale14(d3.x, vd.x) + mulscale14(d3.y, vd.y); |
5825 | terminx | 291 | |
292 | if (spriteDist > 512 && spriteDist < lastDist) |
||
3081 | terminx | 293 | { |
5825 | terminx | 294 | int onScreen = 1; |
3081 | terminx | 295 | |
5825 | terminx | 296 | if (pSprite->picnum == APLAYER) |
5 | Plagman | 297 | { |
7776 | terminx | 298 | auto const ps = g_player[P_GetP(pSprite)].ps; |
6725 | terminx | 299 | onScreen = (klabs(scale(SZ(spriteNum)-pSprite->z,10,spriteDist)-fix16_to_int(ps->q16horiz+ps->q16horizoff-F16(100))) < 100); |
5825 | terminx | 300 | } |
5 | Plagman | 301 | |
6942 | terminx | 302 | #ifndef EDUKE32_STANDALONE |
7808 | terminx | 303 | int const zOffset = (!FURY && (PN(spriteNum) == ORGANTIC || PN(spriteNum) == ROTATEGUN)) ? 0 : ZOFFSET5; |
6942 | terminx | 304 | #else |
7702 | terminx | 305 | int const zOffset = ZOFFSET5; |
6942 | terminx | 306 | #endif |
307 | int const canSee = cansee(SX(spriteNum), SY(spriteNum), SZ(spriteNum) - zOffset, SECT(spriteNum), |
||
308 | pSprite->x, pSprite->y, pSprite->z - ZOFFSET5, pSprite->sectnum); |
||
5 | Plagman | 309 | |
5825 | terminx | 310 | if (onScreen && canSee) |
311 | { |
||
6942 | terminx | 312 | lastDist = spriteDist; |
313 | bestSprite = spriteNum; |
||
5 | Plagman | 314 | } |
3081 | terminx | 315 | } |
5 | Plagman | 316 | } |
5825 | terminx | 317 | } |
318 | } |
||
5 | Plagman | 319 | } |
320 | |||
6942 | terminx | 321 | return bestSprite; |
5 | Plagman | 322 | } |
323 | |||
5828 | terminx | 324 | static void A_SetHitData(int spriteNum, const hitdata_t *hitData) |
2979 | helixhorne | 325 | { |
5825 | terminx | 326 | actor[spriteNum].t_data[6] = hitData->wall; |
327 | actor[spriteNum].t_data[7] = hitData->sect; |
||
328 | actor[spriteNum].t_data[8] = hitData->sprite; |
||
2979 | helixhorne | 329 | } |
330 | |||
6942 | terminx | 331 | #ifndef EDUKE32_STANDALONE |
5828 | terminx | 332 | static int CheckShootSwitchTile(int tileNum) |
2980 | helixhorne | 333 | { |
7808 | terminx | 334 | if (FURY) |
7455 | terminx | 335 | return 0; |
336 | |||
5828 | terminx | 337 | return tileNum == DIPSWITCH || tileNum == DIPSWITCH + 1 || tileNum == DIPSWITCH2 || tileNum == DIPSWITCH2 + 1 || |
338 | tileNum == DIPSWITCH3 || tileNum == DIPSWITCH3 + 1 || tileNum == HANDSWITCH || tileNum == HANDSWITCH + 1; |
||
2980 | helixhorne | 339 | } |
6942 | terminx | 340 | #endif |
2980 | helixhorne | 341 | |
5825 | terminx | 342 | static int32_t safeldist(int32_t spriteNum, const void *pSprite) |
3462 | helixhorne | 343 | { |
5825 | terminx | 344 | int32_t distance = ldist(&sprite[spriteNum], pSprite); |
345 | return distance ? distance : 1; |
||
3462 | helixhorne | 346 | } |
347 | |||
2983 | helixhorne | 348 | // flags: |
349 | // 1: do sprite center adjustment (cen-=(8<<8)) for GREENSLIME or ROTATEGUN |
||
350 | // 2: do auto getangle only if not RECON (if clear, do unconditionally) |
||
5828 | terminx | 351 | static int GetAutoAimAng(int spriteNum, int playerNum, int projecTile, int zAdjust, int aimFlags, |
352 | const vec3_t *startPos, int projVel, int32_t *pZvel, int *pAng) |
||
5 | Plagman | 353 | { |
5828 | terminx | 354 | int returnSprite = -1; |
2983 | helixhorne | 355 | |
5825 | terminx | 356 | Bassert((unsigned)playerNum < MAXPLAYERS); |
2983 | helixhorne | 357 | |
3366 | helixhorne | 358 | #ifdef LUNATIC |
5825 | terminx | 359 | g_player[playerNum].ps->autoaimang = g_player[playerNum].ps->auto_aim == 3 ? AUTO_AIM_ANGLE<<1 : AUTO_AIM_ANGLE; |
3366 | helixhorne | 360 | #else |
5825 | terminx | 361 | Gv_SetVar(g_aimAngleVarID, g_player[playerNum].ps->auto_aim == 3 ? AUTO_AIM_ANGLE<<1 : AUTO_AIM_ANGLE, spriteNum, playerNum); |
3366 | helixhorne | 362 | #endif |
3081 | terminx | 363 | |
5825 | terminx | 364 | VM_OnEvent(EVENT_GETAUTOAIMANGLE, spriteNum, playerNum); |
2983 | helixhorne | 365 | |
3366 | helixhorne | 366 | #ifdef LUNATIC |
5828 | terminx | 367 | int aimang = g_player[playerNum].ps->autoaimang; |
3366 | helixhorne | 368 | #else |
5828 | terminx | 369 | int aimang = Gv_GetVar(g_aimAngleVarID, spriteNum, playerNum); |
3366 | helixhorne | 370 | #endif |
5825 | terminx | 371 | if (aimang > 0) |
372 | returnSprite = A_FindTargetSprite(&sprite[spriteNum], aimang, projecTile); |
||
2983 | helixhorne | 373 | |
5825 | terminx | 374 | if (returnSprite >= 0) |
2983 | helixhorne | 375 | { |
7603 | terminx | 376 | auto const pSprite = (uspriteptr_t)&sprite[returnSprite]; |
377 | int zCenter = 2 * (pSprite->yrepeat * tilesiz[pSprite->picnum].y) + zAdjust; |
||
2983 | helixhorne | 378 | |
6942 | terminx | 379 | #ifndef EDUKE32_STANDALONE |
7808 | terminx | 380 | if (!FURY && aimFlags && |
6971 | terminx | 381 | ((pSprite->picnum >= GREENSLIME && pSprite->picnum <= GREENSLIME + 7) || pSprite->picnum == ROTATEGUN || pSprite->cstat & CSTAT_SPRITE_YCENTER)) |
382 | #else |
||
383 | if (aimFlags && pSprite->cstat & CSTAT_SPRITE_YCENTER) |
||
384 | #endif |
||
5825 | terminx | 385 | zCenter -= ZOFFSET3; |
2983 | helixhorne | 386 | |
5825 | terminx | 387 | int spriteDist = safeldist(g_player[playerNum].ps->i, &sprite[returnSprite]); |
388 | *pZvel = tabledivide32_noinline((pSprite->z - startPos->z - zCenter) * projVel, spriteDist); |
||
2983 | helixhorne | 389 | |
5825 | terminx | 390 | if (!(aimFlags&2) || sprite[returnSprite].picnum != RECON) |
5828 | terminx | 391 | *pAng = getangle(pSprite->x-startPos->x, pSprite->y-startPos->y); |
2983 | helixhorne | 392 | } |
393 | |||
5825 | terminx | 394 | return returnSprite; |
2983 | helixhorne | 395 | } |
396 | |||
5828 | terminx | 397 | static void Proj_MaybeSpawn(int spriteNum, int projecTile, const hitdata_t *hitData) |
3353 | helixhorne | 398 | { |
3360 | helixhorne | 399 | // atwith < 0 is for hard-coded projectiles |
5825 | terminx | 400 | projectile_t *const pProj = Proj_GetProjectile(projecTile); |
5828 | terminx | 401 | int spawnTile = projecTile < 0 ? -projecTile : pProj->spawns; |
3360 | helixhorne | 402 | |
5828 | terminx | 403 | if (spawnTile >= 0) |
3353 | helixhorne | 404 | { |
5828 | terminx | 405 | int spawned = A_Spawn(spriteNum, spawnTile); |
3359 | helixhorne | 406 | |
5825 | terminx | 407 | if (projecTile >= 0) |
3360 | helixhorne | 408 | { |
5828 | terminx | 409 | if (pProj->sxrepeat > 4) |
410 | sprite[spawned].xrepeat = pProj->sxrepeat; |
||
411 | |||
412 | if (pProj->syrepeat > 4) |
||
413 | sprite[spawned].yrepeat = pProj->syrepeat; |
||
3360 | helixhorne | 414 | } |
3359 | helixhorne | 415 | |
5825 | terminx | 416 | A_SetHitData(spawned, hitData); |
3353 | helixhorne | 417 | } |
418 | } |
||
419 | |||
3360 | helixhorne | 420 | // <extra>: damage that this shotspark does |
5828 | terminx | 421 | static int Proj_InsertShotspark(const hitdata_t *hitData, int spriteNum, int projecTile, int sparkSize, int sparkAng, int damage) |
3353 | helixhorne | 422 | { |
5828 | terminx | 423 | int returnSprite = A_InsertSprite(hitData->sect, hitData->pos.x, hitData->pos.y, hitData->pos.z, SHOTSPARK1, -15, |
424 | sparkSize, sparkSize, sparkAng, 0, 0, spriteNum, 4); |
||
3353 | helixhorne | 425 | |
5828 | terminx | 426 | sprite[returnSprite].extra = damage; |
427 | sprite[returnSprite].yvel = projecTile; // This is a hack to allow you to detect which weapon spawned a SHOTSPARK1 |
||
5825 | terminx | 428 | |
5828 | terminx | 429 | A_SetHitData(returnSprite, hitData); |
5825 | terminx | 430 | |
5828 | terminx | 431 | return returnSprite; |
3353 | helixhorne | 432 | } |
433 | |||
5828 | terminx | 434 | int Proj_GetDamage(projectile_t const *pProj) |
3359 | helixhorne | 435 | { |
5825 | terminx | 436 | Bassert(pProj); |
437 | |||
5828 | terminx | 438 | int damage = pProj->extra; |
5825 | terminx | 439 | |
440 | if (pProj->extra_rand > 0) |
||
441 | damage += (krand() % pProj->extra_rand); |
||
442 | |||
443 | return damage; |
||
3359 | helixhorne | 444 | } |
445 | |||
5828 | terminx | 446 | static void Proj_MaybeAddSpread(int doSpread, int32_t *zvel, int *shootAng, int zRange, int angRange) |
3358 | helixhorne | 447 | { |
5828 | terminx | 448 | if (doSpread) |
3358 | helixhorne | 449 | { |
3715 | helixhorne | 450 | // Ranges <= 1 mean no spread at all. A range of 1 calls krand() though. |
451 | if (zRange > 0) |
||
5828 | terminx | 452 | *zvel += (zRange >> 1) - krand() % zRange; |
453 | |||
3715 | helixhorne | 454 | if (angRange > 0) |
5828 | terminx | 455 | *shootAng += (angRange >> 1) - krand() % angRange; |
3358 | helixhorne | 456 | } |
457 | } |
||
458 | |||
5828 | terminx | 459 | static int g_overrideShootZvel = 0; // a boolean |
460 | static int g_shootZvel; // the actual zvel if the above is !=0 |
||
3465 | helixhorne | 461 | |
5828 | terminx | 462 | static int A_GetShootZvel(int defaultZvel) |
3465 | helixhorne | 463 | { |
5828 | terminx | 464 | return g_overrideShootZvel ? g_shootZvel : defaultZvel; |
3465 | helixhorne | 465 | } |
466 | |||
3358 | helixhorne | 467 | // Prepare hitscan weapon fired from player p. |
5828 | terminx | 468 | static void P_PreFireHitscan(int spriteNum, int playerNum, int projecTile, vec3_t *srcVect, int32_t *zvel, int *shootAng, |
469 | int accurateAim, int doSpread) |
||
3358 | helixhorne | 470 | { |
5828 | terminx | 471 | int angRange = 32; |
472 | int zRange = 256; |
||
473 | int aimSprite = GetAutoAimAng(spriteNum, playerNum, projecTile, 5 << 8, 0 + 1, srcVect, 256, zvel, shootAng); |
||
3358 | helixhorne | 474 | |
7776 | terminx | 475 | auto const pPlayer = g_player[playerNum].ps; |
3358 | helixhorne | 476 | |
3366 | helixhorne | 477 | #ifdef LUNATIC |
5828 | terminx | 478 | pPlayer->angrange = angRange; |
479 | pPlayer->zrange = zRange; |
||
3366 | helixhorne | 480 | #else |
6942 | terminx | 481 | Gv_SetVar(g_angRangeVarID, angRange, spriteNum, playerNum); |
482 | Gv_SetVar(g_zRangeVarID, zRange, spriteNum, playerNum); |
||
3366 | helixhorne | 483 | #endif |
3358 | helixhorne | 484 | |
5828 | terminx | 485 | VM_OnEvent(EVENT_GETSHOTRANGE, spriteNum, playerNum); |
3366 | helixhorne | 486 | |
3405 | helixhorne | 487 | #ifdef LUNATIC |
5828 | terminx | 488 | angRange = pPlayer->angrange; |
489 | zRange = pPlayer->zrange; |
||
3366 | helixhorne | 490 | #else |
5828 | terminx | 491 | angRange = Gv_GetVar(g_angRangeVarID, spriteNum, playerNum); |
492 | zRange = Gv_GetVar(g_zRangeVarID, spriteNum, playerNum); |
||
3358 | helixhorne | 493 | #endif |
3366 | helixhorne | 494 | |
5828 | terminx | 495 | if (accurateAim) |
3358 | helixhorne | 496 | { |
5828 | terminx | 497 | if (!pPlayer->auto_aim) |
3358 | helixhorne | 498 | { |
5828 | terminx | 499 | hitdata_t hitData; |
3358 | helixhorne | 500 | |
6725 | terminx | 501 | *zvel = A_GetShootZvel(fix16_to_int(F16(100)-pPlayer->q16horiz-pPlayer->q16horizoff)<<5); |
3358 | helixhorne | 502 | |
5828 | terminx | 503 | hitscan(srcVect, sprite[spriteNum].sectnum, sintable[(*shootAng + 512) & 2047], |
504 | sintable[*shootAng & 2047], *zvel << 6, &hitData, CLIPMASK1); |
||
3358 | helixhorne | 505 | |
5828 | terminx | 506 | if (hitData.sprite != -1) |
3358 | helixhorne | 507 | { |
5828 | terminx | 508 | int const statNumMap = ((1 << STAT_ACTOR) | (1 << STAT_ZOMBIEACTOR) | (1 << STAT_PLAYER) | (1 << STAT_DUMMYPLAYER)); |
509 | int const statNum = sprite[hitData.sprite].statnum; |
||
3358 | helixhorne | 510 | |
6235 | terminx | 511 | if ((unsigned)statNum <= 30 && (statNumMap & (1 << statNum))) |
5828 | terminx | 512 | aimSprite = hitData.sprite; |
3358 | helixhorne | 513 | } |
514 | } |
||
515 | |||
5828 | terminx | 516 | if (aimSprite == -1) |
6235 | terminx | 517 | goto notarget; |
3358 | helixhorne | 518 | } |
519 | else |
||
520 | { |
||
5828 | terminx | 521 | if (aimSprite == -1) // no target |
6241 | terminx | 522 | { |
6235 | terminx | 523 | notarget: |
6725 | terminx | 524 | *zvel = fix16_to_int(F16(100)-pPlayer->q16horiz-pPlayer->q16horizoff)<<5; |
6241 | terminx | 525 | } |
526 | |||
5828 | terminx | 527 | Proj_MaybeAddSpread(doSpread, zvel, shootAng, zRange, angRange); |
3358 | helixhorne | 528 | } |
529 | |||
7614 | terminx | 530 | // ZOFFSET6 is added to this position at the same time as the player's pyoff in A_ShootWithZvel() |
531 | srcVect->z -= ZOFFSET6; |
||
3358 | helixhorne | 532 | } |
533 | |||
534 | // Hitscan weapon fired from actor (sprite s); |
||
6244 | terminx | 535 | static void A_PreFireHitscan(const spritetype *pSprite, vec3_t * const srcVect, int32_t * const zvel, int * const shootAng, int const doSpread) |
3358 | helixhorne | 536 | { |
7776 | terminx | 537 | int const playerNum = A_FindPlayer(pSprite, NULL); |
538 | auto const pPlayer = g_player[playerNum].ps; |
||
539 | int const playerDist = safeldist(pPlayer->i, pSprite); |
||
3358 | helixhorne | 540 | |
5828 | terminx | 541 | *zvel = tabledivide32_noinline((pPlayer->pos.z - srcVect->z) << 8, playerDist); |
3358 | helixhorne | 542 | |
5828 | terminx | 543 | srcVect->z -= ZOFFSET6; |
3358 | helixhorne | 544 | |
6235 | terminx | 545 | if (pSprite->picnum == BOSS1) |
546 | *shootAng = getangle(pPlayer->pos.x - srcVect->x, pPlayer->pos.y - srcVect->y); |
||
3358 | helixhorne | 547 | |
6244 | terminx | 548 | Proj_MaybeAddSpread(doSpread, zvel, shootAng, 256, 128 >> (uint8_t)(pSprite->picnum != BOSS1)); |
3358 | helixhorne | 549 | } |
550 | |||
6244 | terminx | 551 | static int Proj_DoHitscan(int spriteNum, int32_t const cstatmask, const vec3_t * const srcVect, int zvel, int const shootAng, hitdata_t * const hitData) |
3359 | helixhorne | 552 | { |
7776 | terminx | 553 | auto const pSprite = &sprite[spriteNum]; |
3359 | helixhorne | 554 | |
5828 | terminx | 555 | pSprite->cstat &= ~cstatmask; |
3921 | helixhorne | 556 | zvel = A_GetShootZvel(zvel); |
8107 | terminx | 557 | int16_t sectnum = pSprite->sectnum; |
558 | updatesector(srcVect->x, srcVect->y, §num); |
||
559 | hitscan(srcVect, sectnum, sintable[(shootAng + 512) & 2047], sintable[shootAng & 2047], zvel << 6, hitData, CLIPMASK1); |
||
5828 | terminx | 560 | pSprite->cstat |= cstatmask; |
3359 | helixhorne | 561 | |
5828 | terminx | 562 | return (hitData->sect < 0); |
3359 | helixhorne | 563 | } |
564 | |||
6235 | terminx | 565 | static void Proj_DoRandDecalSize(int const spriteNum, int const projecTile) |
3362 | helixhorne | 566 | { |
5828 | terminx | 567 | const projectile_t *const proj = Proj_GetProjectile(projecTile); |
7776 | terminx | 568 | auto const pSprite = &sprite[spriteNum]; |
3362 | helixhorne | 569 | |
570 | if (proj->workslike & PROJECTILE_RANDDECALSIZE) |
||
6235 | terminx | 571 | pSprite->xrepeat = pSprite->yrepeat = clamp((krand() & proj->xrepeat), pSprite->yrepeat, pSprite->xrepeat); |
3362 | helixhorne | 572 | else |
573 | { |
||
5828 | terminx | 574 | pSprite->xrepeat = proj->xrepeat; |
575 | pSprite->yrepeat = proj->yrepeat; |
||
3362 | helixhorne | 576 | } |
577 | } |
||
578 | |||
6244 | terminx | 579 | static int SectorContainsSE13(int const sectNum) |
3362 | helixhorne | 580 | { |
5828 | terminx | 581 | if (sectNum >= 0) |
582 | { |
||
5829 | terminx | 583 | for (bssize_t SPRITES_OF_SECT(sectNum, i)) |
5828 | terminx | 584 | { |
3362 | helixhorne | 585 | if (sprite[i].statnum == STAT_EFFECTOR && sprite[i].lotag == SE_13_EXPLOSIVE) |
586 | return 1; |
||
5828 | terminx | 587 | } |
588 | } |
||
3362 | helixhorne | 589 | return 0; |
590 | } |
||
591 | |||
592 | // Maybe handle bit 2 (swap wall bottoms). |
||
593 | // (in that case walltype *hitwal may be stale) |
||
5828 | terminx | 594 | static inline void HandleHitWall(hitdata_t *hitData) |
3362 | helixhorne | 595 | { |
7603 | terminx | 596 | auto const hitWall = (uwallptr_t)&wall[hitData->wall]; |
3362 | helixhorne | 597 | |
5828 | terminx | 598 | if ((hitWall->cstat & 2) && redwallp(hitWall) && (hitData->pos.z >= sector[hitWall->nextsector].floorz)) |
599 | hitData->wall = hitWall->nextwall; |
||
3362 | helixhorne | 600 | } |
601 | |||
4204 | helixhorne | 602 | // Maybe damage a ceiling or floor as the consequence of projectile impact. |
603 | // Returns 1 if projectile hit a parallaxed ceiling. |
||
604 | // NOTE: Compare with Proj_MaybeDamageCF() in actors.c |
||
6771 | hendricks2 | 605 | static int Proj_MaybeDamageCF2(int const spriteNum, int const zvel, int const hitSect) |
4204 | helixhorne | 606 | { |
5828 | terminx | 607 | Bassert(hitSect >= 0); |
608 | |||
4204 | helixhorne | 609 | if (zvel < 0) |
610 | { |
||
5828 | terminx | 611 | if (sector[hitSect].ceilingstat&1) |
4204 | helixhorne | 612 | return 1; |
613 | |||
6771 | hendricks2 | 614 | Sect_DamageCeiling(spriteNum, hitSect); |
4204 | helixhorne | 615 | } |
4205 | helixhorne | 616 | else if (zvel > 0) |
617 | { |
||
5828 | terminx | 618 | if (sector[hitSect].floorstat&1) |
4205 | helixhorne | 619 | { |
620 | // Keep original Duke3D behavior: pass projectiles through |
||
621 | // parallaxed ceilings, but NOT through such floors. |
||
622 | return 0; |
||
623 | } |
||
624 | |||
6771 | hendricks2 | 625 | Sect_DamageFloor(spriteNum, hitSect); |
4205 | helixhorne | 626 | } |
627 | |||
4204 | helixhorne | 628 | return 0; |
629 | } |
||
630 | |||
3360 | helixhorne | 631 | // Finish shooting hitscan weapon from player <p>. <k> is the inserted SHOTSPARK1. |
5828 | terminx | 632 | // * <spawnObject> is passed to Proj_MaybeSpawn() |
633 | // * <decalTile> and <wallDamage> are for wall impact |
||
634 | // * <wallDamage> is passed to A_DamageWall() |
||
635 | // * <decalFlags> is for decals upon wall impact: |
||
3360 | helixhorne | 636 | // 1: handle random decal size (tile <atwith>) |
637 | // 2: set cstat to wall-aligned + random x/y flip |
||
638 | // |
||
639 | // TODO: maybe split into 3 cases (hit neither wall nor sprite, hit sprite, hit wall)? |
||
6942 | terminx | 640 | static int P_PostFireHitscan(int playerNum, int const spriteNum, hitdata_t *const hitData, int const spriteOwner, |
6244 | terminx | 641 | int const projecTile, int const zvel, int const spawnTile, int const decalTile, int const wallDamage, |
642 | int const decalFlags) |
||
3360 | helixhorne | 643 | { |
6942 | terminx | 644 | #ifdef EDUKE32_STANDALONE |
645 | UNREFERENCED_PARAMETER(playerNum); |
||
646 | #endif |
||
5828 | terminx | 647 | if (hitData->wall == -1 && hitData->sprite == -1) |
3360 | helixhorne | 648 | { |
6771 | hendricks2 | 649 | if (Proj_MaybeDamageCF2(spriteNum, zvel, hitData->sect)) |
3360 | helixhorne | 650 | { |
5828 | terminx | 651 | sprite[spriteNum].xrepeat = 0; |
652 | sprite[spriteNum].yrepeat = 0; |
||
4204 | helixhorne | 653 | return -1; |
3360 | helixhorne | 654 | } |
655 | |||
5828 | terminx | 656 | Proj_MaybeSpawn(spriteNum, spawnTile, hitData); |
3360 | helixhorne | 657 | } |
5828 | terminx | 658 | else if (hitData->sprite >= 0) |
3360 | helixhorne | 659 | { |
5828 | terminx | 660 | A_DamageObject(hitData->sprite, spriteNum); |
3360 | helixhorne | 661 | |
7808 | terminx | 662 | if (!FURY && sprite[hitData->sprite].picnum == APLAYER && |
3360 | helixhorne | 663 | (ud.ffire == 1 || (!GTFLAGS(GAMETYPE_PLAYERSFRIENDLY) && GTFLAGS(GAMETYPE_TDM) && |
5828 | terminx | 664 | g_player[P_Get(hitData->sprite)].ps->team != g_player[P_Get(spriteOwner)].ps->team))) |
3360 | helixhorne | 665 | { |
6942 | terminx | 666 | #ifndef EDUKE32_STANDALONE |
5828 | terminx | 667 | int jibSprite = A_Spawn(spriteNum, JIBS6); |
668 | |||
669 | sprite[spriteNum].xrepeat = sprite[spriteNum].yrepeat = 0; |
||
670 | sprite[jibSprite].z += ZOFFSET6; |
||
671 | sprite[jibSprite].xvel = 16; |
||
672 | sprite[jibSprite].xrepeat = sprite[jibSprite].yrepeat = 24; |
||
673 | sprite[jibSprite].ang += 64 - (krand() & 127); |
||
6942 | terminx | 674 | #endif |
3360 | helixhorne | 675 | } |
676 | else |
||
677 | { |
||
5828 | terminx | 678 | Proj_MaybeSpawn(spriteNum, spawnTile, hitData); |
3360 | helixhorne | 679 | } |
6942 | terminx | 680 | #ifndef EDUKE32_STANDALONE |
7808 | terminx | 681 | if (!FURY && playerNum >= 0 && CheckShootSwitchTile(sprite[hitData->sprite].picnum)) |
3360 | helixhorne | 682 | { |
5828 | terminx | 683 | P_ActivateSwitch(playerNum, hitData->sprite, 1); |
3360 | helixhorne | 684 | return -1; |
685 | } |
||
6942 | terminx | 686 | #endif |
3360 | helixhorne | 687 | } |
5828 | terminx | 688 | else if (hitData->wall >= 0) |
3360 | helixhorne | 689 | { |
7603 | terminx | 690 | auto const hitWall = (uwallptr_t)&wall[hitData->wall]; |
3360 | helixhorne | 691 | |
5828 | terminx | 692 | Proj_MaybeSpawn(spriteNum, spawnTile, hitData); |
3360 | helixhorne | 693 | |
5828 | terminx | 694 | if (CheckDoorTile(hitWall->picnum) == 1) |
3360 | helixhorne | 695 | goto SKIPBULLETHOLE; |
696 | |||
6942 | terminx | 697 | #ifndef EDUKE32_STANDALONE |
7808 | terminx | 698 | if (!FURY && playerNum >= 0 && CheckShootSwitchTile(hitWall->picnum)) |
3360 | helixhorne | 699 | { |
5828 | terminx | 700 | P_ActivateSwitch(playerNum, hitData->wall, 0); |
3360 | helixhorne | 701 | return -1; |
702 | } |
||
6942 | terminx | 703 | #endif |
3360 | helixhorne | 704 | |
5828 | terminx | 705 | if (hitWall->hitag != 0 || (hitWall->nextwall >= 0 && wall[hitWall->nextwall].hitag != 0)) |
3360 | helixhorne | 706 | goto SKIPBULLETHOLE; |
707 | |||
5828 | terminx | 708 | if ((hitData->sect >= 0 && sector[hitData->sect].lotag == 0) && |
709 | (hitWall->overpicnum != BIGFORCE && (hitWall->cstat & 16) == 0) && |
||
710 | ((hitWall->nextsector >= 0 && sector[hitWall->nextsector].lotag == 0) || (hitWall->nextsector == -1 && sector[hitData->sect].lotag == 0))) |
||
711 | { |
||
712 | int decalSprite; |
||
3360 | helixhorne | 713 | |
5828 | terminx | 714 | if (SectorContainsSE13(hitWall->nextsector)) |
715 | goto SKIPBULLETHOLE; |
||
3360 | helixhorne | 716 | |
5828 | terminx | 717 | for (SPRITES_OF(STAT_MISC, decalSprite)) |
718 | if (sprite[decalSprite].picnum == decalTile && dist(&sprite[decalSprite], &sprite[spriteNum]) < (12 + (krand() & 7))) |
||
719 | goto SKIPBULLETHOLE; |
||
3360 | helixhorne | 720 | |
5828 | terminx | 721 | if (decalTile >= 0) |
722 | { |
||
723 | decalSprite = A_Spawn(spriteNum, decalTile); |
||
3360 | helixhorne | 724 | |
7614 | terminx | 725 | auto const decal = &sprite[decalSprite]; |
726 | |||
5828 | terminx | 727 | A_SetHitData(decalSprite, hitData); |
5388 | terminx | 728 | |
5828 | terminx | 729 | if (!A_CheckSpriteFlags(decalSprite, SFLAG_DECAL)) |
730 | actor[decalSprite].flags |= SFLAG_DECAL; |
||
3360 | helixhorne | 731 | |
7614 | terminx | 732 | int32_t diffZ; |
733 | spriteheightofs(decalSprite, &diffZ, 0); |
||
5392 | terminx | 734 | |
7614 | terminx | 735 | decal->z += diffZ >> 1; |
736 | decal->ang = (getangle(hitWall->x - wall[hitWall->point2].x, hitWall->y - wall[hitWall->point2].y) + 1536) & 2047; |
||
737 | |||
5828 | terminx | 738 | if (decalFlags & 1) |
739 | Proj_DoRandDecalSize(decalSprite, projecTile); |
||
3360 | helixhorne | 740 | |
5828 | terminx | 741 | if (decalFlags & 2) |
7614 | terminx | 742 | decal->cstat = 16 + (krand() & (8 + 4)); |
3360 | helixhorne | 743 | |
5828 | terminx | 744 | A_SetSprite(decalSprite, CLIPMASK0); |
3360 | helixhorne | 745 | |
5828 | terminx | 746 | // BULLETHOLE already adds itself to the deletion queue in |
747 | // A_Spawn(). However, some other tiles do as well. |
||
748 | if (decalTile != BULLETHOLE) |
||
749 | A_AddToDeleteQueue(decalSprite); |
||
750 | } |
||
751 | } |
||
3360 | helixhorne | 752 | |
753 | SKIPBULLETHOLE: |
||
5828 | terminx | 754 | HandleHitWall(hitData); |
8080 | terminx | 755 | A_DamageWall(spriteNum, hitData->wall, hitData->pos, wallDamage); |
3360 | helixhorne | 756 | } |
757 | |||
758 | return 0; |
||
759 | } |
||
760 | |||
761 | // Finish shooting hitscan weapon from actor (sprite <i>). |
||
6235 | terminx | 762 | static int A_PostFireHitscan(const hitdata_t *hitData, int const spriteNum, int const projecTile, int const zvel, int const shootAng, |
763 | int const extra, int const spawnTile, int const wallDamage) |
||
3360 | helixhorne | 764 | { |
6235 | terminx | 765 | int const returnSprite = Proj_InsertShotspark(hitData, spriteNum, projecTile, 24, shootAng, extra); |
3360 | helixhorne | 766 | |
5828 | terminx | 767 | if (hitData->sprite >= 0) |
3360 | helixhorne | 768 | { |
5828 | terminx | 769 | A_DamageObject(hitData->sprite, returnSprite); |
3360 | helixhorne | 770 | |
5828 | terminx | 771 | if (sprite[hitData->sprite].picnum != APLAYER) |
772 | Proj_MaybeSpawn(returnSprite, spawnTile, hitData); |
||
3360 | helixhorne | 773 | else |
5828 | terminx | 774 | sprite[returnSprite].xrepeat = sprite[returnSprite].yrepeat = 0; |
3360 | helixhorne | 775 | } |
5828 | terminx | 776 | else if (hitData->wall >= 0) |
5783 | terminx | 777 | { |
8080 | terminx | 778 | A_DamageWall(returnSprite, hitData->wall, hitData->pos, wallDamage); |
5828 | terminx | 779 | Proj_MaybeSpawn(returnSprite, spawnTile, hitData); |
5783 | terminx | 780 | } |
781 | else |
||
782 | { |
||
6771 | hendricks2 | 783 | if (Proj_MaybeDamageCF2(returnSprite, zvel, hitData->sect)) |
5783 | terminx | 784 | { |
5828 | terminx | 785 | sprite[returnSprite].xrepeat = 0; |
786 | sprite[returnSprite].yrepeat = 0; |
||
5783 | terminx | 787 | } |
5828 | terminx | 788 | else Proj_MaybeSpawn(returnSprite, spawnTile, hitData); |
5783 | terminx | 789 | } |
3360 | helixhorne | 790 | |
5828 | terminx | 791 | return returnSprite; |
3360 | helixhorne | 792 | } |
793 | |||
3362 | helixhorne | 794 | // Common "spawn blood?" predicate. |
795 | // minzdiff: minimal "step" height for blood to be spawned |
||
6235 | terminx | 796 | static int Proj_CheckBlood(vec3_t const *const srcVect, hitdata_t const *const hitData, int const bloodRange, int const minZdiff) |
3362 | helixhorne | 797 | { |
5828 | terminx | 798 | if (hitData->wall < 0 || hitData->sect < 0) |
4680 | terminx | 799 | return 0; |
800 | |||
7603 | terminx | 801 | auto const hitWall = (uwallptr_t)&wall[hitData->wall]; |
4680 | terminx | 802 | |
5828 | terminx | 803 | if ((FindDistance2D(srcVect->x - hitData->pos.x, srcVect->y - hitData->pos.y) < bloodRange) |
804 | && (hitWall->overpicnum != BIGFORCE && (hitWall->cstat & 16) == 0) |
||
805 | && (sector[hitData->sect].lotag == 0) |
||
806 | && (hitWall->nextsector < 0 || (sector[hitWall->nextsector].lotag == 0 && sector[hitData->sect].lotag == 0 |
||
807 | && sector[hitData->sect].floorz - sector[hitWall->nextsector].floorz > minZdiff))) |
||
808 | return 1; |
||
3362 | helixhorne | 809 | |
810 | return 0; |
||
811 | } |
||
812 | |||
6235 | terminx | 813 | static void Proj_HandleKnee(hitdata_t *const hitData, int const spriteNum, int const playerNum, int const projecTile, int const shootAng, |
814 | const projectile_t *const proj, int const inserttile, int const randomDamage, int const spawnTile, |
||
815 | int const soundNum) |
||
3362 | helixhorne | 816 | { |
7776 | terminx | 817 | auto const pPlayer = playerNum >= 0 ? g_player[playerNum].ps : NULL; |
3362 | helixhorne | 818 | |
5828 | terminx | 819 | int kneeSprite = A_InsertSprite(hitData->sect,hitData->pos.x,hitData->pos.y,hitData->pos.z, |
820 | inserttile,-15,0,0,shootAng,32,0,spriteNum,4); |
||
3362 | helixhorne | 821 | |
822 | if (proj != NULL) |
||
823 | { |
||
824 | // Custom projectiles. |
||
5828 | terminx | 825 | SpriteProjectile[kneeSprite].workslike = Proj_GetProjectile(sprite[kneeSprite].picnum)->workslike; |
826 | sprite[kneeSprite].extra = proj->extra; |
||
3362 | helixhorne | 827 | } |
828 | |||
5828 | terminx | 829 | if (randomDamage > 0) |
830 | sprite[kneeSprite].extra += (krand()&randomDamage); |
||
3362 | helixhorne | 831 | |
5828 | terminx | 832 | if (playerNum >= 0) |
3362 | helixhorne | 833 | { |
5828 | terminx | 834 | if (spawnTile >= 0) |
3362 | helixhorne | 835 | { |
5828 | terminx | 836 | int k = A_Spawn(kneeSprite, spawnTile); |
5825 | terminx | 837 | sprite[k].z -= ZOFFSET3; |
5828 | terminx | 838 | A_SetHitData(k, hitData); |
3362 | helixhorne | 839 | } |
840 | |||
5828 | terminx | 841 | if (soundNum >= 0) |
842 | A_PlaySound(soundNum, kneeSprite); |
||
3362 | helixhorne | 843 | } |
844 | |||
7092 | terminx | 845 | if (pPlayer != NULL && pPlayer->inv_amount[GET_STEROIDS] > 0 && pPlayer->inv_amount[GET_STEROIDS] < 400) |
5828 | terminx | 846 | sprite[kneeSprite].extra += (pPlayer->max_player_health>>2); |
3362 | helixhorne | 847 | |
5828 | terminx | 848 | if (hitData->sprite >= 0 && sprite[hitData->sprite].picnum != ACCESSSWITCH && sprite[hitData->sprite].picnum != ACCESSSWITCH2) |
3362 | helixhorne | 849 | { |
5828 | terminx | 850 | A_DamageObject(hitData->sprite, kneeSprite); |
851 | if (playerNum >= 0) |
||
852 | P_ActivateSwitch(playerNum, hitData->sprite,1); |
||
3362 | helixhorne | 853 | } |
5828 | terminx | 854 | else if (hitData->wall >= 0) |
3362 | helixhorne | 855 | { |
5828 | terminx | 856 | HandleHitWall(hitData); |
3362 | helixhorne | 857 | |
5828 | terminx | 858 | if (wall[hitData->wall].picnum != ACCESSSWITCH && wall[hitData->wall].picnum != ACCESSSWITCH2) |
3362 | helixhorne | 859 | { |
8080 | terminx | 860 | A_DamageWall(kneeSprite, hitData->wall, hitData->pos, projecTile); |
5828 | terminx | 861 | if (playerNum >= 0) |
862 | P_ActivateSwitch(playerNum, hitData->wall,0); |
||
3362 | helixhorne | 863 | } |
864 | } |
||
865 | } |
||
866 | |||
5825 | terminx | 867 | #define MinibossScale(i, s) (((s)*sprite[i].yrepeat)/80) |
3992 | terminx | 868 | |
5828 | terminx | 869 | static int A_ShootCustom(int const spriteNum, int const projecTile, int shootAng, vec3_t * const startPos) |
2983 | helixhorne | 870 | { |
3992 | terminx | 871 | /* Custom projectiles */ |
5825 | terminx | 872 | hitdata_t hitData; |
873 | projectile_t *const pProj = Proj_GetProjectile(projecTile); |
||
7776 | terminx | 874 | auto const pSprite = &sprite[spriteNum]; |
5825 | terminx | 875 | int const playerNum = (pSprite->picnum == APLAYER) ? P_GetP(pSprite) : -1; |
7776 | terminx | 876 | auto const pPlayer = playerNum >= 0 ? g_player[playerNum].ps : NULL; |
2876 | helixhorne | 877 | |
5700 | terminx | 878 | #ifdef POLYMER |
6829 | terminx | 879 | if (videoGetRenderMode() == REND_POLYMER && pProj->flashcolor) |
5700 | terminx | 880 | { |
5825 | terminx | 881 | int32_t x = ((sintable[(pSprite->ang + 512) & 2047]) >> 7), y = ((sintable[(pSprite->ang) & 2047]) >> 7); |
5700 | terminx | 882 | |
5825 | terminx | 883 | pSprite->x += x; |
884 | pSprite->y += y; |
||
885 | G_AddGameLight(0, spriteNum, PHEIGHT, 8192, pProj->flashcolor, PR_LIGHT_PRIO_MAX_GAME); |
||
886 | actor[spriteNum].lightcount = 2; |
||
887 | pSprite->x -= x; |
||
888 | pSprite->y -= y; |
||
5700 | terminx | 889 | } |
890 | #endif // POLYMER |
||
891 | |||
5825 | terminx | 892 | if (pProj->offset == 0) |
893 | pProj->offset = 1; |
||
5 | Plagman | 894 | |
6632 | hendricks2 | 895 | int otherSprite = -1; |
5825 | terminx | 896 | int32_t zvel = 0; |
897 | |||
898 | switch (pProj->workslike & PROJECTILE_TYPE_MASK) |
||
5 | Plagman | 899 | { |
3992 | terminx | 900 | case PROJECTILE_HITSCAN: |
5825 | terminx | 901 | if (!(pProj->workslike & PROJECTILE_NOSETOWNERSHADE) && pSprite->extra >= 0) |
902 | pSprite->shade = pProj->shade; |
||
1207 | terminx | 903 | |
5825 | terminx | 904 | if (playerNum >= 0) |
5828 | terminx | 905 | P_PreFireHitscan(spriteNum, playerNum, projecTile, startPos, &zvel, &shootAng, |
5825 | terminx | 906 | pProj->workslike & PROJECTILE_ACCURATE_AUTOAIM, !(pProj->workslike & PROJECTILE_ACCURATE)); |
3992 | terminx | 907 | else |
5828 | terminx | 908 | A_PreFireHitscan(pSprite, startPos, &zvel, &shootAng, !(pProj->workslike & PROJECTILE_ACCURATE)); |
3081 | terminx | 909 | |
5828 | terminx | 910 | if (Proj_DoHitscan(spriteNum, (pProj->cstat >= 0) ? pProj->cstat : 256 + 1, startPos, zvel, shootAng, &hitData)) |
3992 | terminx | 911 | return -1; |
1315 | terminx | 912 | |
5825 | terminx | 913 | if (pProj->range > 0 && klabs(startPos->x - hitData.pos.x) + klabs(startPos->y - hitData.pos.y) > pProj->range) |
3992 | terminx | 914 | return -1; |
1315 | terminx | 915 | |
5825 | terminx | 916 | if (pProj->trail >= 0) |
5828 | terminx | 917 | A_HitscanProjTrail(startPos, &hitData.pos, shootAng, projecTile, pSprite->sectnum); |
5 | Plagman | 918 | |
5825 | terminx | 919 | if (pProj->workslike & PROJECTILE_WATERBUBBLES) |
3992 | terminx | 920 | { |
5825 | terminx | 921 | if ((krand() & 15) == 0 && sector[hitData.sect].lotag == ST_2_UNDERWATER) |
6912 | terminx | 922 | Proj_DoWaterTracers(hitData.pos, startPos, 8 - (ud.multimode >> 1), pSprite->sectnum); |
3992 | terminx | 923 | } |
5 | Plagman | 924 | |
5825 | terminx | 925 | if (playerNum >= 0) |
1319 | terminx | 926 | { |
5828 | terminx | 927 | otherSprite = Proj_InsertShotspark(&hitData, spriteNum, projecTile, 10, shootAng, Proj_GetDamage(pProj)); |
1402 | terminx | 928 | |
5825 | terminx | 929 | if (P_PostFireHitscan(playerNum, otherSprite, &hitData, spriteNum, projecTile, zvel, projecTile, pProj->decal, |
930 | projecTile, 1 + 2) < 0) |
||
3992 | terminx | 931 | return -1; |
1319 | terminx | 932 | } |
3992 | terminx | 933 | else |
934 | { |
||
5825 | terminx | 935 | otherSprite = |
5828 | terminx | 936 | A_PostFireHitscan(&hitData, spriteNum, projecTile, zvel, shootAng, Proj_GetDamage(pProj), projecTile, projecTile); |
3992 | terminx | 937 | } |
1319 | terminx | 938 | |
5825 | terminx | 939 | if ((krand() & 255) < 4 && pProj->isound >= 0) |
940 | S_PlaySound3D(pProj->isound, otherSprite, &hitData.pos); |
||
5 | Plagman | 941 | |
3992 | terminx | 942 | return -1; |
943 | |||
944 | case PROJECTILE_RPG: |
||
5825 | terminx | 945 | if (!(pProj->workslike & PROJECTILE_NOSETOWNERSHADE) && pSprite->extra >= 0) |
946 | pSprite->shade = pProj->shade; |
||
3992 | terminx | 947 | |
7092 | terminx | 948 | if (pPlayer != NULL) |
5 | Plagman | 949 | { |
4229 | helixhorne | 950 | // NOTE: j is a SPRITE_INDEX |
5828 | terminx | 951 | otherSprite = GetAutoAimAng(spriteNum, playerNum, projecTile, 8<<8, 0+2, startPos, pProj->vel, &zvel, &shootAng); |
5 | Plagman | 952 | |
5825 | terminx | 953 | if (otherSprite < 0) |
6725 | terminx | 954 | zvel = fix16_to_int(F16(100)-pPlayer->q16horiz-pPlayer->q16horizoff)*(pProj->vel/8); |
5 | Plagman | 955 | |
5825 | terminx | 956 | if (pProj->sound >= 0) |
957 | A_PlaySound(pProj->sound, spriteNum); |
||
3992 | terminx | 958 | } |
959 | else |
||
960 | { |
||
5825 | terminx | 961 | if (!(pProj->workslike & PROJECTILE_NOAIM)) |
5 | Plagman | 962 | { |
5826 | terminx | 963 | int const otherPlayer = A_FindPlayer(pSprite, NULL); |
964 | int const otherPlayerDist = safeldist(g_player[otherPlayer].ps->i, pSprite); |
||
3361 | helixhorne | 965 | |
5828 | terminx | 966 | shootAng = getangle(g_player[otherPlayer].ps->opos.x - startPos->x, |
5826 | terminx | 967 | g_player[otherPlayer].ps->opos.y - startPos->y); |
5 | Plagman | 968 | |
5826 | terminx | 969 | zvel = tabledivide32_noinline((g_player[otherPlayer].ps->opos.z - startPos->z) * pProj->vel, otherPlayerDist); |
5825 | terminx | 970 | |
971 | if (A_CheckEnemySprite(pSprite) && (AC_MOVFLAGS(pSprite, &actor[spriteNum]) & face_player_smart)) |
||
5828 | terminx | 972 | shootAng = pSprite->ang + (krand() & 31) - 16; |
3992 | terminx | 973 | } |
974 | } |
||
5 | Plagman | 975 | |
3992 | terminx | 976 | if (numplayers > 1 && g_netClient) return -1; |
5825 | terminx | 977 | else |
978 | { |
||
979 | // l may be a SPRITE_INDEX, see above |
||
980 | int const l = (playerNum >= 0 && otherSprite >= 0) ? otherSprite : -1; |
||
1658 | terminx | 981 | |
5825 | terminx | 982 | zvel = A_GetShootZvel(zvel); |
983 | otherSprite = A_InsertSprite(pSprite->sectnum, |
||
5828 | terminx | 984 | startPos->x + tabledivide32_noinline(sintable[(348 + shootAng + 512) & 2047], pProj->offset), |
985 | startPos->y + tabledivide32_noinline(sintable[(shootAng + 348) & 2047], pProj->offset), |
||
986 | startPos->z - (1 << 8), projecTile, 0, 14, 14, shootAng, pProj->vel, zvel, spriteNum, 4); |
||
4229 | helixhorne | 987 | |
6978 | terminx | 988 | sprite[otherSprite].extra = Proj_GetDamage(pProj); |
5 | Plagman | 989 | |
5825 | terminx | 990 | if (!(pProj->workslike & PROJECTILE_BOUNCESOFFWALLS)) |
991 | sprite[otherSprite].yvel = l; // NOT_BOUNCESOFFWALLS_YVEL |
||
992 | else |
||
993 | { |
||
994 | sprite[otherSprite].yvel = (pProj->bounces >= 1) ? pProj->bounces : g_numFreezeBounces; |
||
995 | sprite[otherSprite].zvel -= (2 << 4); |
||
996 | } |
||
5498 | terminx | 997 | |
5825 | terminx | 998 | sprite[otherSprite].pal = (pProj->pal >= 0) ? pProj->pal : 0; |
999 | sprite[otherSprite].xrepeat = pProj->xrepeat; |
||
1000 | sprite[otherSprite].yrepeat = pProj->yrepeat; |
||
1001 | sprite[otherSprite].cstat = (pProj->cstat >= 0) ? pProj->cstat : 128; |
||
1002 | sprite[otherSprite].clipdist = (pProj->clipdist != 255) ? pProj->clipdist : 40; |
||
1003 | SpriteProjectile[otherSprite] = *Proj_GetProjectile(sprite[otherSprite].picnum); |
||
5 | Plagman | 1004 | |
5825 | terminx | 1005 | return otherSprite; |
3992 | terminx | 1006 | } |
5 | Plagman | 1007 | |
3992 | terminx | 1008 | case PROJECTILE_KNEE: |
5825 | terminx | 1009 | if (playerNum >= 0) |
3992 | terminx | 1010 | { |
6725 | terminx | 1011 | zvel = fix16_to_int(F16(100) - pPlayer->q16horiz - pPlayer->q16horizoff) << 5; |
5825 | terminx | 1012 | startPos->z += (6 << 8); |
5828 | terminx | 1013 | shootAng += 15; |
3992 | terminx | 1014 | } |
5825 | terminx | 1015 | else if (!(pProj->workslike & PROJECTILE_NOAIM)) |
3992 | terminx | 1016 | { |
5825 | terminx | 1017 | int32_t playerDist; |
1018 | otherSprite = g_player[A_FindPlayer(pSprite, &playerDist)].ps->i; |
||
1019 | zvel = tabledivide32_noinline((sprite[otherSprite].z - startPos->z) << 8, playerDist + 1); |
||
5828 | terminx | 1020 | shootAng = getangle(sprite[otherSprite].x - startPos->x, sprite[otherSprite].y - startPos->y); |
3992 | terminx | 1021 | } |
5 | Plagman | 1022 | |
5828 | terminx | 1023 | Proj_DoHitscan(spriteNum, 0, startPos, zvel, shootAng, &hitData); |
5 | Plagman | 1024 | |
5825 | terminx | 1025 | if (hitData.sect < 0) return -1; |
5 | Plagman | 1026 | |
5825 | terminx | 1027 | if (pProj->range == 0) |
1028 | pProj->range = 1024; |
||
3152 | helixhorne | 1029 | |
5825 | terminx | 1030 | if (pProj->range > 0 && klabs(startPos->x - hitData.pos.x) + klabs(startPos->y - hitData.pos.y) > pProj->range) |
168 | terminx | 1031 | return -1; |
5 | Plagman | 1032 | |
5828 | terminx | 1033 | Proj_HandleKnee(&hitData, spriteNum, playerNum, projecTile, shootAng, |
1034 | pProj, projecTile, pProj->extra_rand, pProj->spawns, pProj->sound); |
||
5 | Plagman | 1035 | |
3992 | terminx | 1036 | return -1; |
1490 | terminx | 1037 | |
3992 | terminx | 1038 | case PROJECTILE_BLOOD: |
5828 | terminx | 1039 | shootAng += 64 - (krand() & 127); |
1040 | |||
1041 | if (playerNum < 0) |
||
1042 | shootAng += 1024; |
||
1043 | |||
3992 | terminx | 1044 | zvel = 1024 - (krand() & 2047); |
1209 | terminx | 1045 | |
5828 | terminx | 1046 | Proj_DoHitscan(spriteNum, 0, startPos, zvel, shootAng, &hitData); |
1209 | terminx | 1047 | |
5825 | terminx | 1048 | if (pProj->range == 0) |
1049 | pProj->range = 1024; |
||
1209 | terminx | 1050 | |
5825 | terminx | 1051 | if (Proj_CheckBlood(startPos, &hitData, pProj->range, mulscale3(pProj->yrepeat, tilesiz[pProj->decal].y) << 8)) |
3992 | terminx | 1052 | { |
7603 | terminx | 1053 | uwallptr_t const hitWall = (uwallptr_t)&wall[hitData.wall]; |
1209 | terminx | 1054 | |
5825 | terminx | 1055 | if (FindDistance2D(hitWall->x - wall[hitWall->point2].x, hitWall->y - wall[hitWall->point2].y) > |
1056 | (mulscale3(pProj->xrepeat + 8, tilesiz[pProj->decal].x))) |
||
1209 | terminx | 1057 | { |
5825 | terminx | 1058 | if (SectorContainsSE13(hitWall->nextsector)) |
3992 | terminx | 1059 | return -1; |
1209 | terminx | 1060 | |
5825 | terminx | 1061 | if (hitWall->nextwall >= 0 && wall[hitWall->nextwall].hitag != 0) |
3360 | helixhorne | 1062 | return -1; |
1209 | terminx | 1063 | |
5825 | terminx | 1064 | if (hitWall->hitag == 0 && pProj->decal >= 0) |
3992 | terminx | 1065 | { |
5825 | terminx | 1066 | otherSprite = A_Spawn(spriteNum, pProj->decal); |
1209 | terminx | 1067 | |
5825 | terminx | 1068 | A_SetHitData(otherSprite, &hitData); |
5388 | terminx | 1069 | |
5825 | terminx | 1070 | if (!A_CheckSpriteFlags(otherSprite, SFLAG_DECAL)) |
1071 | actor[otherSprite].flags |= SFLAG_DECAL; |
||
1209 | terminx | 1072 | |
5825 | terminx | 1073 | sprite[otherSprite].ang = getangle(hitWall->x - wall[hitWall->point2].x, |
1074 | hitWall->y - wall[hitWall->point2].y) + 512; |
||
1075 | Bmemcpy(&sprite[otherSprite], &hitData.pos, sizeof(vec3_t)); |
||
1209 | terminx | 1076 | |
5825 | terminx | 1077 | Proj_DoRandDecalSize(otherSprite, projecTile); |
1209 | terminx | 1078 | |
5825 | terminx | 1079 | sprite[otherSprite].z += sprite[otherSprite].yrepeat << 8; |
1209 | terminx | 1080 | |
5825 | terminx | 1081 | // sprite[spawned].cstat = 16+(krand()&12); |
1082 | sprite[otherSprite].cstat = 16; |
||
1625 | terminx | 1083 | |
3992 | terminx | 1084 | if (krand() & 1) |
5825 | terminx | 1085 | sprite[otherSprite].cstat |= 4; |
1625 | terminx | 1086 | |
3992 | terminx | 1087 | if (krand() & 1) |
5825 | terminx | 1088 | sprite[otherSprite].cstat |= 8; |
1209 | terminx | 1089 | |
5825 | terminx | 1090 | sprite[otherSprite].shade = sector[sprite[otherSprite].sectnum].floorshade; |
1209 | terminx | 1091 | |
5825 | terminx | 1092 | A_SetSprite(otherSprite, CLIPMASK0); |
1093 | A_AddToDeleteQueue(otherSprite); |
||
1094 | changespritestat(otherSprite, 5); |
||
1209 | terminx | 1095 | } |
1096 | } |
||
3992 | terminx | 1097 | } |
1209 | terminx | 1098 | |
3992 | terminx | 1099 | return -1; |
1209 | terminx | 1100 | |
3992 | terminx | 1101 | default: |
1102 | return -1; |
||
1103 | } |
||
1104 | } |
||
1567 | terminx | 1105 | |
6804 | terminx | 1106 | #ifndef EDUKE32_STANDALONE |
5828 | terminx | 1107 | static int32_t A_ShootHardcoded(int spriteNum, int projecTile, int shootAng, vec3_t startPos, |
5826 | terminx | 1108 | spritetype *pSprite, int const playerNum, DukePlayer_t * const pPlayer) |
3992 | terminx | 1109 | { |
5825 | terminx | 1110 | hitdata_t hitData; |
5826 | terminx | 1111 | int const spriteSectnum = pSprite->sectnum; |
1112 | int32_t Zvel; |
||
1113 | int vel; |
||
1209 | terminx | 1114 | |
5825 | terminx | 1115 | switch (DYNAMICTILEMAP(projecTile)) |
3992 | terminx | 1116 | { |
5826 | terminx | 1117 | case BLOODSPLAT1__STATIC: |
1118 | case BLOODSPLAT2__STATIC: |
||
1119 | case BLOODSPLAT3__STATIC: |
||
1120 | case BLOODSPLAT4__STATIC: |
||
5828 | terminx | 1121 | shootAng += 64 - (krand() & 127); |
5826 | terminx | 1122 | if (playerNum < 0) |
5828 | terminx | 1123 | shootAng += 1024; |
5826 | terminx | 1124 | Zvel = 1024 - (krand() & 2047); |
6976 | terminx | 1125 | fallthrough__; |
5826 | terminx | 1126 | case KNEE__STATIC: |
1127 | if (projecTile == KNEE) |
||
1209 | terminx | 1128 | { |
5826 | terminx | 1129 | if (playerNum >= 0) |
1130 | { |
||
6725 | terminx | 1131 | Zvel = fix16_to_int(F16(100) - pPlayer->q16horiz - pPlayer->q16horizoff) << 5; |
5826 | terminx | 1132 | startPos.z += (6 << 8); |
5828 | terminx | 1133 | shootAng += 15; |
5826 | terminx | 1134 | } |
1135 | else |
||
1136 | { |
||
1137 | int32_t playerDist; |
||
1138 | int const playerSprite = g_player[A_FindPlayer(pSprite, &playerDist)].ps->i; |
||
1139 | Zvel = tabledivide32_noinline((sprite[playerSprite].z - startPos.z) << 8, playerDist + 1); |
||
5828 | terminx | 1140 | shootAng = getangle(sprite[playerSprite].x - startPos.x, sprite[playerSprite].y - startPos.y); |
5826 | terminx | 1141 | } |
1209 | terminx | 1142 | } |
1143 | |||
5828 | terminx | 1144 | Proj_DoHitscan(spriteNum, 0, &startPos, Zvel, shootAng, &hitData); |
3992 | terminx | 1145 | |
5826 | terminx | 1146 | if (projecTile >= BLOODSPLAT1 && projecTile <= BLOODSPLAT4) |
1209 | terminx | 1147 | { |
5826 | terminx | 1148 | if (Proj_CheckBlood(&startPos, &hitData, 1024, 16 << 8)) |
1149 | { |
||
7603 | terminx | 1150 | uwallptr_t const hitwal = (uwallptr_t)&wall[hitData.wall]; |
1209 | terminx | 1151 | |
5826 | terminx | 1152 | if (SectorContainsSE13(hitwal->nextsector)) |
1153 | return -1; |
||
1209 | terminx | 1154 | |
5826 | terminx | 1155 | if (hitwal->nextwall >= 0 && wall[hitwal->nextwall].hitag != 0) |
1156 | return -1; |
||
5435 | helixhorne | 1157 | |
5826 | terminx | 1158 | if (hitwal->hitag == 0) |
1159 | { |
||
1160 | int const spawnedSprite = A_Spawn(spriteNum, projecTile); |
||
1161 | sprite[spawnedSprite].ang |
||
1162 | = (getangle(hitwal->x - wall[hitwal->point2].x, hitwal->y - wall[hitwal->point2].y) + 1536) & 2047; |
||
7973 | terminx | 1163 | sprite[spawnedSprite].pos = hitData.pos; |
5826 | terminx | 1164 | sprite[spawnedSprite].cstat |= (krand() & 4); |
1165 | A_SetSprite(spawnedSprite, CLIPMASK0); |
||
7973 | terminx | 1166 | setsprite(spawnedSprite, &sprite[spawnedSprite].pos); |
5826 | terminx | 1167 | if (PN(spriteNum) == OOZFILTER || PN(spriteNum) == NEWBEAST) |
1168 | sprite[spawnedSprite].pal = 6; |
||
1169 | } |
||
1170 | } |
||
1209 | terminx | 1171 | |
5826 | terminx | 1172 | return -1; |
5435 | helixhorne | 1173 | } |
1209 | terminx | 1174 | |
5826 | terminx | 1175 | if (hitData.sect < 0) |
1176 | break; |
||
1209 | terminx | 1177 | |
5826 | terminx | 1178 | if (klabs(startPos.x - hitData.pos.x) + klabs(startPos.y - hitData.pos.y) < 1024) |
5828 | terminx | 1179 | Proj_HandleKnee(&hitData, spriteNum, playerNum, projecTile, shootAng, NULL, KNEE, 7, SMALLSMOKE, KICK_HIT); |
5826 | terminx | 1180 | break; |
1209 | terminx | 1181 | |
5826 | terminx | 1182 | case SHOTSPARK1__STATIC: |
1183 | case SHOTGUN__STATIC: |
||
1184 | case CHAINGUN__STATIC: |
||
1185 | { |
||
1186 | if (pSprite->extra >= 0) |
||
1187 | pSprite->shade = -96; |
||
1209 | terminx | 1188 | |
5826 | terminx | 1189 | if (playerNum >= 0) |
5828 | terminx | 1190 | P_PreFireHitscan(spriteNum, playerNum, projecTile, &startPos, &Zvel, &shootAng, |
6866 | hendricks2 | 1191 | projecTile == SHOTSPARK1__STATIC && !WW2GI, 1); |
5826 | terminx | 1192 | else |
5828 | terminx | 1193 | A_PreFireHitscan(pSprite, &startPos, &Zvel, &shootAng, 1); |
3362 | helixhorne | 1194 | |
5828 | terminx | 1195 | if (Proj_DoHitscan(spriteNum, 256 + 1, &startPos, Zvel, shootAng, &hitData)) |
5826 | terminx | 1196 | return -1; |
3362 | helixhorne | 1197 | |
5826 | terminx | 1198 | if ((krand() & 15) == 0 && sector[hitData.sect].lotag == ST_2_UNDERWATER) |
6912 | terminx | 1199 | Proj_DoWaterTracers(hitData.pos, &startPos, 8 - (ud.multimode >> 1), pSprite->sectnum); |
1209 | terminx | 1200 | |
5826 | terminx | 1201 | int spawnedSprite; |
1209 | terminx | 1202 | |
5826 | terminx | 1203 | if (playerNum >= 0) |
1204 | { |
||
5828 | terminx | 1205 | spawnedSprite = Proj_InsertShotspark(&hitData, spriteNum, projecTile, 10, shootAng, G_DefaultActorHealth(projecTile) + (krand() % 6)); |
1209 | terminx | 1206 | |
5826 | terminx | 1207 | if (P_PostFireHitscan(playerNum, spawnedSprite, &hitData, spriteNum, projecTile, Zvel, -SMALLSMOKE, BULLETHOLE, SHOTSPARK1, 0) < 0) |
1208 | return -1; |
||
1209 | } |
||
1210 | else |
||
1211 | { |
||
5828 | terminx | 1212 | spawnedSprite = A_PostFireHitscan(&hitData, spriteNum, projecTile, Zvel, shootAng, G_DefaultActorHealth(projecTile), -SMALLSMOKE, |
5826 | terminx | 1213 | SHOTSPARK1); |
1214 | } |
||
1209 | terminx | 1215 | |
5826 | terminx | 1216 | if ((krand() & 255) < 4) |
1217 | S_PlaySound3D(PISTOL_RICOCHET, spawnedSprite, &hitData.pos); |
||
1209 | terminx | 1218 | |
5826 | terminx | 1219 | return -1; |
1220 | } |
||
1209 | terminx | 1221 | |
5826 | terminx | 1222 | case GROWSPARK__STATIC: |
1223 | { |
||
1224 | if (playerNum >= 0) |
||
5828 | terminx | 1225 | P_PreFireHitscan(spriteNum, playerNum, projecTile, &startPos, &Zvel, &shootAng, 1, 1); |
5826 | terminx | 1226 | else |
5828 | terminx | 1227 | A_PreFireHitscan(pSprite, &startPos, &Zvel, &shootAng, 1); |
1209 | terminx | 1228 | |
5828 | terminx | 1229 | if (Proj_DoHitscan(spriteNum, 256 + 1, &startPos, Zvel, shootAng, &hitData)) |
5826 | terminx | 1230 | return -1; |
1209 | terminx | 1231 | |
5826 | terminx | 1232 | int const otherSprite = A_InsertSprite(hitData.sect, hitData.pos.x, hitData.pos.y, hitData.pos.z, GROWSPARK, -16, 28, 28, |
5828 | terminx | 1233 | shootAng, 0, 0, spriteNum, 1); |
3989 | terminx | 1234 | |
5826 | terminx | 1235 | sprite[otherSprite].pal = 2; |
1236 | sprite[otherSprite].cstat |= 130; |
||
1237 | sprite[otherSprite].xrepeat = sprite[otherSprite].yrepeat = 1; |
||
1238 | A_SetHitData(otherSprite, &hitData); |
||
3989 | terminx | 1239 | |
5826 | terminx | 1240 | if (hitData.wall == -1 && hitData.sprite == -1 && hitData.sect >= 0) |
1241 | { |
||
6771 | hendricks2 | 1242 | Proj_MaybeDamageCF2(otherSprite, Zvel, hitData.sect); |
5826 | terminx | 1243 | } |
1244 | else if (hitData.sprite >= 0) |
||
1245 | A_DamageObject(hitData.sprite, otherSprite); |
||
1246 | else if (hitData.wall >= 0 && wall[hitData.wall].picnum != ACCESSSWITCH && wall[hitData.wall].picnum != ACCESSSWITCH2) |
||
8080 | terminx | 1247 | A_DamageWall(otherSprite, hitData.wall, hitData.pos, projecTile); |
5435 | helixhorne | 1248 | } |
1249 | break; |
||
3989 | terminx | 1250 | |
8788 | hendricks2 | 1251 | case FIREBALL__STATIC: |
1252 | if (!WORLDTOUR) |
||
1253 | break; |
||
1254 | fallthrough__; |
||
5826 | terminx | 1255 | case FIRELASER__STATIC: |
1209 | terminx | 1256 | case SPIT__STATIC: |
1257 | case COOLEXPLOSION1__STATIC: |
||
3464 | helixhorne | 1258 | { |
5826 | terminx | 1259 | if (pSprite->extra >= 0) |
1260 | pSprite->shade = -96; |
||
1209 | terminx | 1261 | |
5826 | terminx | 1262 | switch (projecTile) |
1263 | { |
||
1264 | case SPIT__STATIC: vel = 292; break; |
||
1265 | case COOLEXPLOSION1__STATIC: |
||
1266 | vel = (pSprite->picnum == BOSS2) ? 644 : 348; |
||
1267 | startPos.z -= (4 << 7); |
||
1268 | break; |
||
8788 | hendricks2 | 1269 | case FIREBALL__STATIC: |
1270 | if (pSprite->picnum == BOSS5 || pSprite->picnum == BOSS5STAYPUT) |
||
1271 | { |
||
1272 | vel = 968; |
||
1273 | startPos.z += 0x1800; |
||
1274 | break; |
||
1275 | } |
||
1276 | fallthrough__; |
||
5826 | terminx | 1277 | case FIRELASER__STATIC: |
1278 | default: |
||
1279 | vel = 840; |
||
1280 | startPos.z -= (4 << 7); |
||
1281 | break; |
||
1282 | } |
||
1209 | terminx | 1283 | |
5826 | terminx | 1284 | if (playerNum >= 0) |
1209 | terminx | 1285 | { |
8788 | hendricks2 | 1286 | if (projecTile == FIREBALL) |
1287 | { |
||
6725 | terminx | 1288 | Zvel = fix16_to_int(F16(100) - pPlayer->q16horiz - pPlayer->q16horizoff) * 98; |
8788 | hendricks2 | 1289 | startPos.x += sintable[(348+shootAng+512)&2047]/448; |
1290 | startPos.y += sintable[(348+shootAng)&2047]/448; |
||
1291 | startPos.z += 0x300; |
||
1292 | } |
||
1293 | else if (GetAutoAimAng(spriteNum, playerNum, projecTile, -ZOFFSET4, 0, &startPos, vel, &Zvel, &shootAng) < 0) |
||
1294 | Zvel = fix16_to_int(F16(100) - pPlayer->q16horiz - pPlayer->q16horizoff) * 98; |
||
1209 | terminx | 1295 | } |
1296 | else |
||
5826 | terminx | 1297 | { |
1298 | int const otherPlayer = A_FindPlayer(pSprite, NULL); |
||
5828 | terminx | 1299 | shootAng += 16 - (krand() & 31); |
5826 | terminx | 1300 | hitData.pos.x = safeldist(g_player[otherPlayer].ps->i, pSprite); |
1301 | Zvel = tabledivide32_noinline((g_player[otherPlayer].ps->opos.z - startPos.z + (3 << 8)) * vel, hitData.pos.x); |
||
1302 | } |
||
1209 | terminx | 1303 | |
5826 | terminx | 1304 | Zvel = A_GetShootZvel(Zvel); |
3465 | helixhorne | 1305 | |
5828 | terminx | 1306 | int spriteSize = (playerNum >= 0) ? 7 : 18; |
5826 | terminx | 1307 | |
1308 | if (projecTile == SPIT) |
||
1209 | terminx | 1309 | { |
5828 | terminx | 1310 | spriteSize = 18; |
5826 | terminx | 1311 | startPos.z -= (10 << 8); |
1209 | terminx | 1312 | } |
1313 | |||
5828 | terminx | 1314 | int const returnSprite = A_InsertSprite(spriteSectnum, startPos.x, startPos.y, startPos.z, projecTile, -127, spriteSize, spriteSize, |
1315 | shootAng, vel, Zvel, spriteNum, 4); |
||
1209 | terminx | 1316 | |
5826 | terminx | 1317 | sprite[returnSprite].extra += (krand() & 7); |
1209 | terminx | 1318 | |
5826 | terminx | 1319 | if (projecTile == COOLEXPLOSION1) |
1320 | { |
||
1321 | sprite[returnSprite].shade = 0; |
||
1209 | terminx | 1322 | |
5826 | terminx | 1323 | if (PN(spriteNum) == BOSS2) |
1324 | { |
||
1325 | int const saveXvel = sprite[returnSprite].xvel; |
||
1326 | sprite[returnSprite].xvel = MinibossScale(spriteNum, 1024); |
||
1327 | A_SetSprite(returnSprite, CLIPMASK0); |
||
1328 | sprite[returnSprite].xvel = saveXvel; |
||
1329 | sprite[returnSprite].ang += 128 - (krand() & 255); |
||
1330 | } |
||
1331 | } |
||
8788 | hendricks2 | 1332 | else if (projecTile == FIREBALL) |
1333 | { |
||
1334 | if (PN(spriteNum) == BOSS5 || PN(spriteNum) == BOSS5STAYPUT || playerNum >= 0) |
||
1335 | { |
||
1336 | sprite[returnSprite].xrepeat = 40; |
||
1337 | sprite[returnSprite].yrepeat = 40; |
||
1338 | } |
||
1339 | sprite[returnSprite].yvel = playerNum; |
||
1340 | //sprite[returnSprite].cstat |= 0x4000; |
||
1341 | } |
||
1209 | terminx | 1342 | |
5826 | terminx | 1343 | sprite[returnSprite].cstat = 128; |
1344 | sprite[returnSprite].clipdist = 4; |
||
1209 | terminx | 1345 | |
5826 | terminx | 1346 | return returnSprite; |
1347 | } |
||
1348 | |||
6370 | terminx | 1349 | case FREEZEBLAST__STATIC: |
1350 | startPos.z += (3 << 8); |
||
1351 | fallthrough__; |
||
5826 | terminx | 1352 | case RPG__STATIC: |
5435 | helixhorne | 1353 | { |
5826 | terminx | 1354 | // XXX: "CODEDUP" |
1355 | if (pSprite->extra >= 0) |
||
1356 | pSprite->shade = -96; |
||
1209 | terminx | 1357 | |
5826 | terminx | 1358 | vel = 644; |
1209 | terminx | 1359 | |
5826 | terminx | 1360 | int j = -1; |
1361 | |||
1362 | if (playerNum >= 0) |
||
1209 | terminx | 1363 | { |
5826 | terminx | 1364 | // NOTE: j is a SPRITE_INDEX |
5828 | terminx | 1365 | j = GetAutoAimAng(spriteNum, playerNum, projecTile, 8 << 8, 0 + 2, &startPos, vel, &Zvel, &shootAng); |
1209 | terminx | 1366 | |
5826 | terminx | 1367 | if (j < 0) |
6725 | terminx | 1368 | Zvel = fix16_to_int(F16(100) - pPlayer->q16horiz - pPlayer->q16horizoff) * 81; |
1209 | terminx | 1369 | |
5826 | terminx | 1370 | if (projecTile == RPG) |
1371 | A_PlaySound(RPG_SHOOT, spriteNum); |
||
1372 | } |
||
1373 | else |
||
1374 | { |
||
1375 | // NOTE: j is a player index |
||
1376 | j = A_FindPlayer(pSprite, NULL); |
||
5828 | terminx | 1377 | shootAng = getangle(g_player[j].ps->opos.x - startPos.x, g_player[j].ps->opos.y - startPos.y); |
5826 | terminx | 1378 | if (PN(spriteNum) == BOSS3) |
5827 | terminx | 1379 | startPos.z -= MinibossScale(spriteNum, ZOFFSET5); |
5826 | terminx | 1380 | else if (PN(spriteNum) == BOSS2) |
1381 | { |
||
1382 | vel += 128; |
||
1383 | startPos.z += MinibossScale(spriteNum, 24 << 8); |
||
1384 | } |
||
1209 | terminx | 1385 | |
5826 | terminx | 1386 | Zvel = tabledivide32_noinline((g_player[j].ps->opos.z - startPos.z) * vel, safeldist(g_player[j].ps->i, pSprite)); |
1567 | terminx | 1387 | |
5826 | terminx | 1388 | if (A_CheckEnemySprite(pSprite) && (AC_MOVFLAGS(pSprite, &actor[spriteNum]) & face_player_smart)) |
5828 | terminx | 1389 | shootAng = pSprite->ang + (krand() & 31) - 16; |
5826 | terminx | 1390 | } |
1567 | terminx | 1391 | |
5826 | terminx | 1392 | if (numplayers > 1 && g_netClient) |
1393 | return -1; |
||
1209 | terminx | 1394 | |
5826 | terminx | 1395 | Zvel = A_GetShootZvel(Zvel); |
5828 | terminx | 1396 | int const returnSprite = A_InsertSprite(spriteSectnum, startPos.x + (sintable[(348 + shootAng + 512) & 2047] / 448), |
1397 | startPos.y + (sintable[(shootAng + 348) & 2047] / 448), startPos.z - (1 << 8), |
||
1398 | projecTile, 0, 14, 14, shootAng, vel, Zvel, spriteNum, 4); |
||
7776 | terminx | 1399 | auto const pReturn = &sprite[returnSprite]; |
1209 | terminx | 1400 | |
5826 | terminx | 1401 | pReturn->extra += (krand() & 7); |
1402 | if (projecTile != FREEZEBLAST) |
||
1403 | pReturn->yvel = (playerNum >= 0 && j >= 0) ? j : -1; // RPG_YVEL |
||
1404 | else |
||
1209 | terminx | 1405 | { |
5826 | terminx | 1406 | pReturn->yvel = g_numFreezeBounces; |
1407 | pReturn->xrepeat >>= 1; |
||
1408 | pReturn->yrepeat >>= 1; |
||
1409 | pReturn->zvel -= (2 << 4); |
||
1410 | } |
||
1411 | |||
1412 | if (playerNum == -1) |
||
1413 | { |
||
1414 | if (PN(spriteNum) == BOSS3) |
||
1209 | terminx | 1415 | { |
5826 | terminx | 1416 | if (krand() & 1) |
1417 | { |
||
5828 | terminx | 1418 | pReturn->x -= MinibossScale(spriteNum, sintable[shootAng & 2047] >> 6); |
1419 | pReturn->y -= MinibossScale(spriteNum, sintable[(shootAng + 1024 + 512) & 2047] >> 6); |
||
5826 | terminx | 1420 | pReturn->ang -= MinibossScale(spriteNum, 8); |
1421 | } |
||
1422 | else |
||
1423 | { |
||
5828 | terminx | 1424 | pReturn->x += MinibossScale(spriteNum, sintable[shootAng & 2047] >> 6); |
1425 | pReturn->y += MinibossScale(spriteNum, sintable[(shootAng + 1024 + 512) & 2047] >> 6); |
||
5826 | terminx | 1426 | pReturn->ang += MinibossScale(spriteNum, 4); |
1427 | } |
||
1428 | pReturn->xrepeat = MinibossScale(spriteNum, 42); |
||
1429 | pReturn->yrepeat = MinibossScale(spriteNum, 42); |
||
1209 | terminx | 1430 | } |
5826 | terminx | 1431 | else if (PN(spriteNum) == BOSS2) |
1209 | terminx | 1432 | { |
5828 | terminx | 1433 | pReturn->x -= MinibossScale(spriteNum, sintable[shootAng & 2047] / 56); |
1434 | pReturn->y -= MinibossScale(spriteNum, sintable[(shootAng + 1024 + 512) & 2047] / 56); |
||
5826 | terminx | 1435 | pReturn->ang -= MinibossScale(spriteNum, 8) + (krand() & 255) - 128; |
1436 | pReturn->xrepeat = 24; |
||
1437 | pReturn->yrepeat = 24; |
||
1209 | terminx | 1438 | } |
5826 | terminx | 1439 | else if (projecTile != FREEZEBLAST) |
1440 | { |
||
1441 | pReturn->xrepeat = 30; |
||
1442 | pReturn->yrepeat = 30; |
||
1443 | pReturn->extra >>= 2; |
||
1444 | } |
||
1209 | terminx | 1445 | } |
5826 | terminx | 1446 | else if (PWEAPON(playerNum, g_player[playerNum].ps->curr_weapon, WorksLike) == DEVISTATOR_WEAPON) |
1209 | terminx | 1447 | { |
5826 | terminx | 1448 | pReturn->extra >>= 2; |
1449 | pReturn->ang += 16 - (krand() & 31); |
||
1450 | pReturn->zvel += 256 - (krand() & 511); |
||
1209 | terminx | 1451 | |
5826 | terminx | 1452 | if (g_player[playerNum].ps->hbomb_hold_delay) |
1453 | { |
||
5828 | terminx | 1454 | pReturn->x -= sintable[shootAng & 2047] / 644; |
1455 | pReturn->y -= sintable[(shootAng + 1024 + 512) & 2047] / 644; |
||
5826 | terminx | 1456 | } |
1457 | else |
||
1458 | { |
||
5828 | terminx | 1459 | pReturn->x += sintable[shootAng & 2047] >> 8; |
1460 | pReturn->y += sintable[(shootAng + 1024 + 512) & 2047] >> 8; |
||
5826 | terminx | 1461 | } |
1462 | pReturn->xrepeat >>= 1; |
||
1463 | pReturn->yrepeat >>= 1; |
||
1209 | terminx | 1464 | } |
1465 | |||
5826 | terminx | 1466 | pReturn->cstat = 128; |
1467 | pReturn->clipdist = (projecTile == RPG) ? 4 : 40; |
||
1209 | terminx | 1468 | |
5826 | terminx | 1469 | return returnSprite; |
1470 | } |
||
1209 | terminx | 1471 | |
5826 | terminx | 1472 | case HANDHOLDINGLASER__STATIC: |
1473 | { |
||
1474 | int const zOffset = (playerNum >= 0) ? g_player[playerNum].ps->pyoff : 0; |
||
6725 | terminx | 1475 | Zvel = (playerNum >= 0) ? fix16_to_int(F16(100) - pPlayer->q16horiz - pPlayer->q16horizoff) * 32 : 0; |
1209 | terminx | 1476 | |
5826 | terminx | 1477 | startPos.z -= zOffset; |
5828 | terminx | 1478 | Proj_DoHitscan(spriteNum, 0, &startPos, Zvel, shootAng, &hitData); |
5826 | terminx | 1479 | startPos.z += zOffset; |
1209 | terminx | 1480 | |
5826 | terminx | 1481 | int placeMine = 0; |
1482 | if (hitData.sprite >= 0) |
||
1483 | break; |
||
5435 | helixhorne | 1484 | |
5826 | terminx | 1485 | if (hitData.wall >= 0 && hitData.sect >= 0) |
1486 | if (((hitData.pos.x - startPos.x) * (hitData.pos.x - startPos.x) |
||
1487 | + (hitData.pos.y - startPos.y) * (hitData.pos.y - startPos.y)) |
||
1488 | < (290 * 290)) |
||
1209 | terminx | 1489 | { |
5826 | terminx | 1490 | // ST_2_UNDERWATER |
1491 | if (wall[hitData.wall].nextsector >= 0) |
||
1492 | { |
||
1493 | if (sector[wall[hitData.wall].nextsector].lotag <= 2 && sector[hitData.sect].lotag <= 2) |
||
1494 | placeMine = 1; |
||
1495 | } |
||
1496 | else if (sector[hitData.sect].lotag <= 2) |
||
1497 | placeMine = 1; |
||
1209 | terminx | 1498 | } |
1499 | |||
5826 | terminx | 1500 | if (placeMine == 1) |
1501 | { |
||
6244 | terminx | 1502 | int const tripBombMode = (playerNum < 0) ? 0 : |
3414 | helixhorne | 1503 | #ifdef LUNATIC |
5826 | terminx | 1504 | g_player[playerNum].ps->tripbombControl; |
3414 | helixhorne | 1505 | #else |
5826 | terminx | 1506 | Gv_GetVarByLabel("TRIPBOMB_CONTROL", TRIPBOMB_TRIPWIRE, |
1507 | g_player[playerNum].ps->i, playerNum); |
||
3414 | helixhorne | 1508 | #endif |
5826 | terminx | 1509 | int const spawnedSprite = A_InsertSprite(hitData.sect, hitData.pos.x, hitData.pos.y, hitData.pos.z, TRIPBOMB, -16, 4, 5, |
5828 | terminx | 1510 | shootAng, 0, 0, spriteNum, 6); |
6244 | terminx | 1511 | if (tripBombMode & TRIPBOMB_TIMER) |
5826 | terminx | 1512 | { |
3414 | helixhorne | 1513 | #ifdef LUNATIC |
5826 | terminx | 1514 | int32_t lLifetime = g_player[playerNum].ps->tripbombLifetime; |
1515 | int32_t lLifetimeVar = g_player[playerNum].ps->tripbombLifetimeVar; |
||
3414 | helixhorne | 1516 | #else |
5826 | terminx | 1517 | int32_t lLifetime = Gv_GetVarByLabel("STICKYBOMB_LIFETIME", NAM_GRENADE_LIFETIME, g_player[playerNum].ps->i, playerNum); |
1518 | int32_t lLifetimeVar |
||
1519 | = Gv_GetVarByLabel("STICKYBOMB_LIFETIME_VAR", NAM_GRENADE_LIFETIME_VAR, g_player[playerNum].ps->i, playerNum); |
||
3414 | helixhorne | 1520 | #endif |
5826 | terminx | 1521 | // set timer. blows up when at zero.... |
6254 | hendricks2 | 1522 | actor[spawnedSprite].t_data[7] = lLifetime + mulscale14(krand(), lLifetimeVar) - lLifetimeVar; |
5826 | terminx | 1523 | // TIMER_CONTROL |
1524 | actor[spawnedSprite].t_data[6] = 1; |
||
1525 | } |
||
1526 | else |
||
1527 | sprite[spawnedSprite].hitag = spawnedSprite; |
||
1209 | terminx | 1528 | |
5826 | terminx | 1529 | A_PlaySound(LASERTRIP_ONWALL, spawnedSprite); |
1530 | sprite[spawnedSprite].xvel = -20; |
||
1531 | A_SetSprite(spawnedSprite, CLIPMASK0); |
||
1532 | sprite[spawnedSprite].cstat = 16; |
||
1209 | terminx | 1533 | |
6244 | terminx | 1534 | int const p2 = wall[hitData.wall].point2; |
1535 | int const wallAng = getangle(wall[hitData.wall].x - wall[p2].x, wall[hitData.wall].y - wall[p2].y) - 512; |
||
5826 | terminx | 1536 | |
6244 | terminx | 1537 | actor[spawnedSprite].t_data[5] = sprite[spawnedSprite].ang = wallAng; |
1538 | |||
5826 | terminx | 1539 | return spawnedSprite; |
1209 | terminx | 1540 | } |
5826 | terminx | 1541 | return -1; |
2977 | helixhorne | 1542 | } |
3680 | helixhorne | 1543 | |
5826 | terminx | 1544 | case BOUNCEMINE__STATIC: |
1545 | case MORTER__STATIC: |
||
1546 | { |
||
1547 | if (pSprite->extra >= 0) |
||
1548 | pSprite->shade = -96; |
||
1209 | terminx | 1549 | |
5826 | terminx | 1550 | int const playerSprite = g_player[A_FindPlayer(pSprite, NULL)].ps->i; |
1551 | int const playerDist = ldist(&sprite[playerSprite], pSprite); |
||
1209 | terminx | 1552 | |
5826 | terminx | 1553 | Zvel = -playerDist >> 1; |
1209 | terminx | 1554 | |
5826 | terminx | 1555 | if (Zvel < -4096) |
1556 | Zvel = -2048; |
||
1209 | terminx | 1557 | |
5826 | terminx | 1558 | vel = playerDist >> 4; |
1559 | Zvel = A_GetShootZvel(Zvel); |
||
3465 | helixhorne | 1560 | |
5828 | terminx | 1561 | A_InsertSprite(spriteSectnum, startPos.x + (sintable[(512 + shootAng + 512) & 2047] >> 8), |
1562 | startPos.y + (sintable[(shootAng + 512) & 2047] >> 8), startPos.z + (6 << 8), projecTile, -64, 32, 32, |
||
1563 | shootAng, vel, Zvel, spriteNum, 1); |
||
5826 | terminx | 1564 | break; |
1565 | } |
||
5435 | helixhorne | 1566 | |
5826 | terminx | 1567 | case SHRINKER__STATIC: |
5435 | helixhorne | 1568 | { |
5826 | terminx | 1569 | if (pSprite->extra >= 0) |
1570 | pSprite->shade = -96; |
||
5435 | helixhorne | 1571 | |
5826 | terminx | 1572 | if (playerNum >= 0) |
1573 | { |
||
8726 | terminx | 1574 | if (NAM_WW2GI || GetAutoAimAng(spriteNum, playerNum, projecTile, ZOFFSET6, 0, &startPos, 768, &Zvel, &shootAng) < 0) |
6725 | terminx | 1575 | Zvel = fix16_to_int(F16(100) - pPlayer->q16horiz - pPlayer->q16horizoff) * 98; |
5826 | terminx | 1576 | } |
1577 | else if (pSprite->statnum != STAT_EFFECTOR) |
||
1578 | { |
||
1579 | int const otherPlayer = A_FindPlayer(pSprite, NULL); |
||
1580 | Zvel = tabledivide32_noinline((g_player[otherPlayer].ps->opos.z - startPos.z) * 512, |
||
1581 | safeldist(g_player[otherPlayer].ps->i, pSprite)); |
||
1582 | } |
||
1583 | else |
||
1584 | Zvel = 0; |
||
1209 | terminx | 1585 | |
5826 | terminx | 1586 | Zvel = A_GetShootZvel(Zvel); |
5828 | terminx | 1587 | int const returnSprite = A_InsertSprite(spriteSectnum, startPos.x + (sintable[(512 + shootAng + 512) & 2047] >> 12), |
1588 | startPos.y + (sintable[(shootAng + 512) & 2047] >> 12), startPos.z + (2 << 8), |
||
1589 | SHRINKSPARK, -16, 28, 28, shootAng, 768, Zvel, spriteNum, 4); |
||
5826 | terminx | 1590 | sprite[returnSprite].cstat = 128; |
1591 | sprite[returnSprite].clipdist = 32; |
||
5435 | helixhorne | 1592 | |
5826 | terminx | 1593 | return returnSprite; |
1594 | } |
||
8788 | hendricks2 | 1595 | case FLAMETHROWERFLAME__STATIC: |
1596 | { |
||
1597 | if (!WORLDTOUR) |
||
1598 | break; |
||
1599 | |||
1600 | if (pSprite->extra >= 0) pSprite->shade = -96; |
||
8791 | hendricks2 | 1601 | vel = 400; |
8788 | hendricks2 | 1602 | int j, underwater; |
1603 | if (playerNum >= 0) |
||
1604 | { |
||
1605 | Zvel = fix16_to_int(F16(100) - pPlayer->q16horiz - pPlayer->q16horizoff) * 81; |
||
1606 | int xv = sprite[pPlayer->i].xvel; |
||
1607 | if (xv) |
||
1608 | { |
||
1609 | int ang = getangle(startPos.x-pPlayer->opos.x,startPos.y-pPlayer->opos.y); |
||
1610 | ang = 512-(1024-klabs(klabs(ang-shootAng)-1024)); |
||
8791 | hendricks2 | 1611 | vel = 400+int(float(ang)*(1.f/512.f)*float(xv)); |
8788 | hendricks2 | 1612 | } |
1613 | underwater = sector[pPlayer->cursectnum].lotag == ST_2_UNDERWATER; |
||
1614 | } |
||
1615 | else |
||
1616 | { |
||
1617 | // NOTE: j is a player index |
||
1618 | j = A_FindPlayer(pSprite, NULL); |
||
1619 | shootAng = getangle(g_player[j].ps->opos.x - startPos.x, g_player[j].ps->opos.y - startPos.y); |
||
1620 | if (PN(spriteNum) == BOSS3 || PN(spriteNum) == BOSS3STAYPUT) |
||
1621 | startPos.z -= MinibossScale(spriteNum, ZOFFSET5); |
||
1622 | else if (PN(spriteNum) == BOSS5 || PN(spriteNum) == BOSS5STAYPUT) |
||
1623 | { |
||
1624 | vel += 128; |
||
1625 | startPos.z += MinibossScale(spriteNum, 24 << 8); |
||
1626 | } |
||
1627 | |||
1628 | Zvel = tabledivide32_noinline((g_player[j].ps->opos.z - startPos.z) * vel, safeldist(g_player[j].ps->i, pSprite)); |
||
1629 | |||
1630 | if (A_CheckEnemySprite(pSprite) && (AC_MOVFLAGS(pSprite, &actor[spriteNum]) & face_player_smart)) |
||
1631 | shootAng = pSprite->ang + (krand() & 31) - 16; |
||
1632 | underwater = sector[pSprite->sectnum].lotag == 2; |
||
1633 | } |
||
1634 | if (underwater) |
||
1635 | { |
||
1636 | if ((krand() % 5) != 0) |
||
1637 | return -1; |
||
1638 | j = A_Spawn(spriteNum, WATERBUBBLE); |
||
1639 | } |
||
1640 | else |
||
1641 | { |
||
1642 | j = A_Spawn(spriteNum, projecTile); |
||
1643 | sprite[j].zvel = Zvel; |
||
1644 | sprite[j].xvel = vel; |
||
1645 | } |
||
1646 | sprite[j].x = startPos.x+sintable[(shootAng+630)&2047]/448; |
||
1647 | sprite[j].y = startPos.y+sintable[(shootAng+112)&2047]/448; |
||
1648 | sprite[j].z = startPos.z-0x100; |
||
1649 | sprite[j].cstat = 128; |
||
1650 | sprite[j].ang = shootAng; |
||
1651 | sprite[j].xrepeat = sprite[j].xrepeat = 2; |
||
1652 | sprite[j].clipdist = 40; |
||
1653 | sprite[j].owner = spriteNum; |
||
1654 | sprite[j].yvel = playerNum; |
||
1655 | if (playerNum == -1 && (sprite[spriteNum].picnum == BOSS5 || sprite[spriteNum].picnum == BOSS5)) |
||
1656 | { |
||
1657 | sprite[j].xrepeat = sprite[j].yrepeat = 10; |
||
1658 | sprite[j].x -= sintable[shootAng&2047]/56; |
||
1659 | sprite[j].y -= sintable[(shootAng-512)&2047]/56; |
||
1660 | } |
||
1661 | return j; |
||
1662 | } |
||
1663 | case FIREFLY__STATIC: |
||
1664 | { |
||
1665 | if (!WORLDTOUR) |
||
1666 | break; |
||
1667 | |||
1668 | int j = A_Spawn(spriteNum, projecTile); |
||
1669 | sprite[j].pos = startPos; |
||
1670 | sprite[j].ang = shootAng; |
||
1671 | sprite[j].xvel = 500; |
||
1672 | sprite[j].zvel = 0; |
||
1673 | return j; |
||
1674 | } |
||
5435 | helixhorne | 1675 | } |
1676 | |||
1677 | return -1; |
||
1678 | } |
||
6804 | terminx | 1679 | #endif |
5435 | helixhorne | 1680 | |
6244 | terminx | 1681 | int A_ShootWithZvel(int const spriteNum, int const projecTile, int const forceZvel) |
5435 | helixhorne | 1682 | { |
5825 | terminx | 1683 | Bassert(projecTile >= 0); |
5435 | helixhorne | 1684 | |
8104 | terminx | 1685 | auto const pSprite = &sprite[spriteNum]; |
1686 | int const playerNum = (pSprite->picnum == APLAYER) ? P_GetP(pSprite) : -1; |
||
7776 | terminx | 1687 | auto const pPlayer = playerNum >= 0 ? g_player[playerNum].ps : NULL; |
5435 | helixhorne | 1688 | |
5825 | terminx | 1689 | if (forceZvel != SHOOT_HARDCODED_ZVEL) |
5435 | helixhorne | 1690 | { |
1691 | g_overrideShootZvel = 1; |
||
5825 | terminx | 1692 | g_shootZvel = forceZvel; |
5435 | helixhorne | 1693 | } |
1694 | else |
||
1695 | g_overrideShootZvel = 0; |
||
1696 | |||
5828 | terminx | 1697 | int shootAng; |
5825 | terminx | 1698 | vec3_t startPos; |
1699 | |||
7006 | terminx | 1700 | if (pPlayer != NULL) |
5435 | helixhorne | 1701 | { |
7697 | terminx | 1702 | startPos = pPlayer->pos; |
1703 | startPos.z += pPlayer->pyoff + ZOFFSET6; |
||
1704 | shootAng = fix16_to_int(pPlayer->q16ang); |
||
1705 | |||
7430 | terminx | 1706 | pPlayer->crack_time = PCRACKTIME; |
5435 | helixhorne | 1707 | } |
1708 | else |
||
1709 | { |
||
5828 | terminx | 1710 | shootAng = pSprite->ang; |
7697 | terminx | 1711 | startPos = pSprite->pos; |
5828 | terminx | 1712 | startPos.z -= (((pSprite->yrepeat * tilesiz[pSprite->picnum].y)<<1) - ZOFFSET6); |
5435 | helixhorne | 1713 | |
5825 | terminx | 1714 | if (pSprite->picnum != ROTATEGUN) |
5435 | helixhorne | 1715 | { |
5825 | terminx | 1716 | startPos.z -= (7<<8); |
5435 | helixhorne | 1717 | |
5825 | terminx | 1718 | if (A_CheckEnemySprite(pSprite) && PN(spriteNum) != COMMANDER) |
1209 | terminx | 1719 | { |
5828 | terminx | 1720 | startPos.x += (sintable[(shootAng+1024+96)&2047]>>7); |
1721 | startPos.y += (sintable[(shootAng+512+96)&2047]>>7); |
||
5435 | helixhorne | 1722 | } |
1723 | } |
||
5700 | terminx | 1724 | |
7410 | terminx | 1725 | #ifndef EDUKE32_STANDALONE |
5700 | terminx | 1726 | #ifdef POLYMER |
5825 | terminx | 1727 | switch (DYNAMICTILEMAP(projecTile)) |
5700 | terminx | 1728 | { |
5825 | terminx | 1729 | case FIRELASER__STATIC: |
1730 | case SHOTGUN__STATIC: |
||
1731 | case SHOTSPARK1__STATIC: |
||
1732 | case CHAINGUN__STATIC: |
||
1733 | case RPG__STATIC: |
||
1734 | case MORTER__STATIC: |
||
1735 | { |
||
6303 | hendricks2 | 1736 | vec2_t const v = { ((sintable[(pSprite->ang + 512) & 2047]) >> 7), |
5825 | terminx | 1737 | ((sintable[(pSprite->ang) & 2047]) >> 7) }; |
1738 | |||
1739 | pSprite->x += v.x; |
||
1740 | pSprite->y += v.y; |
||
1741 | G_AddGameLight(0, spriteNum, PHEIGHT, 8192, 255 + (95 << 8), PR_LIGHT_PRIO_MAX_GAME); |
||
1742 | actor[spriteNum].lightcount = 2; |
||
1743 | pSprite->x -= v.x; |
||
1744 | pSprite->y -= v.y; |
||
1745 | } |
||
1746 | |||
1747 | break; |
||
5700 | terminx | 1748 | } |
1749 | #endif // POLYMER |
||
7410 | terminx | 1750 | #endif // !EDUKE32_STANDALONE |
1209 | terminx | 1751 | } |
3465 | helixhorne | 1752 | |
6804 | terminx | 1753 | #ifdef EDUKE32_STANDALONE |
6821 | terminx | 1754 | return A_CheckSpriteTileFlags(projecTile, SFLAG_PROJECTILE) ? A_ShootCustom(spriteNum, projecTile, shootAng, &startPos) : -1; |
6804 | terminx | 1755 | #else |
5825 | terminx | 1756 | return A_CheckSpriteTileFlags(projecTile, SFLAG_PROJECTILE) |
5828 | terminx | 1757 | ? A_ShootCustom(spriteNum, projecTile, shootAng, &startPos) |
7808 | terminx | 1758 | : !FURY ? A_ShootHardcoded(spriteNum, projecTile, shootAng, startPos, pSprite, playerNum, pPlayer) : -1; |
6804 | terminx | 1759 | #endif |
1209 | terminx | 1760 | } |
1761 | |||
2917 | helixhorne | 1762 | |
1763 | //////////////////// HUD WEAPON / MISC. DISPLAY CODE //////////////////// |
||
1764 | |||
5116 | hendricks2 | 1765 | static void P_DisplaySpit(void) |
1209 | terminx | 1766 | { |
7776 | terminx | 1767 | auto const pPlayer = g_player[screenpeek].ps; |
8104 | terminx | 1768 | int const loogCounter = pPlayer->loogcnt; |
1209 | terminx | 1769 | |
5825 | terminx | 1770 | if (loogCounter == 0) |
2639 | helixhorne | 1771 | return; |
1209 | terminx | 1772 | |
5825 | terminx | 1773 | if (VM_OnEvent(EVENT_DISPLAYSPIT, pPlayer->i, screenpeek) != 0) |
5118 | hendricks2 | 1774 | return; |
1775 | |||
5825 | terminx | 1776 | int const rotY = loogCounter<<2; |
5118 | hendricks2 | 1777 | |
5829 | terminx | 1778 | for (bssize_t i=0; i < pPlayer->numloogs; i++) |
1209 | terminx | 1779 | { |
5828 | terminx | 1780 | int const rotAng = klabs(sintable[((loogCounter + i) << 5) & 2047]) >> 5; |
5825 | terminx | 1781 | int const rotZoom = 4096 + ((loogCounter + i) << 9); |
7775 | terminx | 1782 | int const rotX = (-fix16_to_int(g_player[screenpeek].input->q16avel) >> 1) + (sintable[((loogCounter + i) << 6) & 2047] >> 10); |
1209 | terminx | 1783 | |
5825 | terminx | 1784 | rotatesprite_fs((pPlayer->loogiex[i] + rotX) << 16, (200 + pPlayer->loogiey[i] - rotY) << 16, rotZoom - (i << 8), |
5828 | terminx | 1785 | 256 - rotAng, LOOGIE, 0, 0, 2); |
1209 | terminx | 1786 | } |
1787 | } |
||
1788 | |||
5825 | terminx | 1789 | int P_GetHudPal(const DukePlayer_t *p) |
2518 | helixhorne | 1790 | { |
1791 | if (sprite[p->i].pal == 1) |
||
1792 | return 1; |
||
1793 | |||
1794 | if (p->cursectnum >= 0) |
||
1795 | { |
||
5825 | terminx | 1796 | int const hudPal = sector[p->cursectnum].floorpal; |
1797 | if (!g_noFloorPal[hudPal]) |
||
1798 | return hudPal; |
||
2518 | helixhorne | 1799 | } |
1800 | |||
1801 | return 0; |
||
1802 | } |
||
1803 | |||
6954 | hendricks2 | 1804 | int P_GetKneePal(DukePlayer_t const * pPlayer) |
1805 | { |
||
1806 | return P_GetKneePal(pPlayer, P_GetHudPal(pPlayer)); |
||
1807 | } |
||
1808 | |||
1809 | int P_GetKneePal(DukePlayer_t const * pPlayer, int const hudPal) |
||
1810 | { |
||
1811 | return hudPal == 0 ? pPlayer->palookup : hudPal; |
||
1812 | } |
||
1813 | |||
6955 | hendricks2 | 1814 | int P_GetOverheadPal(DukePlayer_t const * pPlayer) |
1815 | { |
||
1816 | return sprite[pPlayer->i].pal; |
||
1817 | } |
||
1818 | |||
5825 | terminx | 1819 | static int P_DisplayFist(int const fistShade) |
1209 | terminx | 1820 | { |
5825 | terminx | 1821 | DukePlayer_t const *const pPlayer = g_player[screenpeek].ps; |
1822 | int fistInc = pPlayer->fist_incs; |
||
1209 | terminx | 1823 | |
5825 | terminx | 1824 | if (fistInc > 32) |
1825 | fistInc = 32; |
||
2932 | helixhorne | 1826 | |
5825 | terminx | 1827 | if (fistInc <= 0) |
1828 | return 0; |
||
2917 | helixhorne | 1829 | |
5825 | terminx | 1830 | switch (VM_OnEvent(EVENT_DISPLAYFIST, pPlayer->i, screenpeek)) |
5118 | hendricks2 | 1831 | { |
5825 | terminx | 1832 | case 1: return 1; |
1833 | case -1: return 0; |
||
5118 | hendricks2 | 1834 | } |
1835 | |||
5825 | terminx | 1836 | int const fistY = klabs(pPlayer->look_ang) / 9; |
1837 | int const fistZoom = clamp(65536 - (sintable[(512 + (fistInc << 6)) & 2047] << 2), 40920, 90612); |
||
1838 | int const fistYOffset = 194 + (sintable[((6 + fistInc) << 7) & 2047] >> 9); |
||
1839 | int const fistPal = P_GetHudPal(pPlayer); |
||
1840 | int wx[2] = { windowxy1.x, windowxy2.x }; |
||
1209 | terminx | 1841 | |
4249 | hendricks2 | 1842 | #ifdef SPLITSCREEN_MOD_HACKS |
2945 | helixhorne | 1843 | // XXX: this is outdated, doesn't handle above/below split. |
2957 | helixhorne | 1844 | if (g_fakeMultiMode==2) |
2932 | helixhorne | 1845 | wx[(g_snum==0)] = (wx[0]+wx[1])/2+1; |
4249 | hendricks2 | 1846 | #endif |
2932 | helixhorne | 1847 | |
7775 | terminx | 1848 | rotatesprite((-fistInc + 222 + (fix16_to_int(g_player[screenpeek].input->q16avel) >> 5)) << 16, (fistY + fistYOffset) << 16, |
5825 | terminx | 1849 | fistZoom, 0, FIST, fistShade, fistPal, 2, wx[0], windowxy1.y, wx[1], windowxy2.y); |
1209 | terminx | 1850 | |
1851 | return 1; |
||
1852 | } |
||
1853 | |||
2917 | helixhorne | 1854 | #define DRAWEAP_CENTER 262144 |
3992 | terminx | 1855 | #define weapsc(sc) scale(sc, ud.weaponscale, 100) |
2917 | helixhorne | 1856 | |
3695 | helixhorne | 1857 | static int32_t g_dts_yadd; |
1858 | |||
5825 | terminx | 1859 | static void G_DrawTileScaled(int drawX, int drawY, int tileNum, int drawShade, int drawBits, int drawPal) |
1209 | terminx | 1860 | { |
5800 | terminx | 1861 | int32_t wx[2] = { windowxy1.x, windowxy2.x }; |
1862 | int32_t wy[2] = { windowxy1.y, windowxy2.y }; |
||
2905 | helixhorne | 1863 | |
5825 | terminx | 1864 | int drawYOffset = 0; |
6028 | hendricks2 | 1865 | int drawXOffset = 192<<16; |
5825 | terminx | 1866 | |
3408 | helixhorne | 1867 | switch (hudweap.cur) |
1209 | terminx | 1868 | { |
5825 | terminx | 1869 | case DEVISTATOR_WEAPON: |
1870 | case TRIPBOMB_WEAPON: |
||
6028 | hendricks2 | 1871 | drawXOffset = 160<<16; |
5825 | terminx | 1872 | break; |
1873 | default: |
||
1874 | if (drawBits & DRAWEAP_CENTER) |
||
1875 | { |
||
6028 | hendricks2 | 1876 | drawXOffset = 160<<16; |
5825 | terminx | 1877 | drawBits &= ~DRAWEAP_CENTER; |
1878 | } |
||
1879 | break; |
||
1209 | terminx | 1880 | } |
1881 | |||
3353 | helixhorne | 1882 | // bit 4 means "flip x" for G_DrawTileScaled |
5825 | terminx | 1883 | int const drawAng = (drawBits & 4) ? 1024 : 0; |
1209 | terminx | 1884 | |
4249 | hendricks2 | 1885 | #ifdef SPLITSCREEN_MOD_HACKS |
2957 | helixhorne | 1886 | if (g_fakeMultiMode==2) |
2905 | helixhorne | 1887 | { |
5825 | terminx | 1888 | int const sideBySide = (ud.screen_size!=0); |
2944 | helixhorne | 1889 | |
2905 | helixhorne | 1890 | // splitscreen HACK |
5825 | terminx | 1891 | drawBits &= ~(1024|512|256); |
1892 | if (sideBySide) |
||
2944 | helixhorne | 1893 | { |
5825 | terminx | 1894 | drawBits &= ~8; |
2944 | helixhorne | 1895 | wx[(g_snum==0)] = (wx[0]+wx[1])/2 + 2; |
1896 | } |
||
1897 | else |
||
1898 | { |
||
5825 | terminx | 1899 | drawBits |= 8; |
2944 | helixhorne | 1900 | if (g_snum==0) |
5825 | terminx | 1901 | drawYOffset = -(100<<16); |
2944 | helixhorne | 1902 | wy[(g_snum==0)] = (wy[0]+wy[1])/2 + 2; |
1903 | } |
||
2905 | helixhorne | 1904 | } |
4249 | hendricks2 | 1905 | #endif |
2905 | helixhorne | 1906 | |
1820 | terminx | 1907 | #ifdef USE_OPENGL |
6829 | terminx | 1908 | if (videoGetRenderMode() >= REND_POLYMOST && usemodels && md_tilehasmodel(tileNum,drawPal) >= 0) |
6028 | hendricks2 | 1909 | drawYOffset += (224<<16)-weapsc(224<<16); |
1209 | terminx | 1910 | #endif |
6028 | hendricks2 | 1911 | rotatesprite(weapsc(drawX<<16) + (drawXOffset-weapsc(drawXOffset)), |
1912 | weapsc((drawY<<16) + g_dts_yadd) + ((200<<16)-weapsc(200<<16)) + drawYOffset, |
||
5825 | terminx | 1913 | weapsc(65536L),drawAng,tileNum,drawShade,drawPal,(2|drawBits), |
2944 | helixhorne | 1914 | wx[0],wy[0], wx[1],wy[1]); |
1209 | terminx | 1915 | } |
1916 | |||
6779 | hendricks2 | 1917 | static void G_DrawWeaponTile(int weaponX, int weaponY, int weaponTile, int weaponShade, int weaponBits, int weaponPal) |
1209 | terminx | 1918 | { |
6779 | hendricks2 | 1919 | static int shadef = 0; |
1920 | static int palf = 0; |
||
1657 | terminx | 1921 | |
1922 | // basic fading between player weapon shades |
||
6779 | hendricks2 | 1923 | if (shadef != weaponShade && (!weaponPal || palf == weaponPal)) |
1657 | terminx | 1924 | { |
6779 | hendricks2 | 1925 | shadef += (weaponShade - shadef) >> 2; |
1657 | terminx | 1926 | |
6779 | hendricks2 | 1927 | if (!((weaponShade - shadef) >> 2)) |
1928 | shadef = logapproach(shadef, weaponShade); |
||
1657 | terminx | 1929 | } |
1930 | else |
||
6779 | hendricks2 | 1931 | shadef = weaponShade; |
1657 | terminx | 1932 | |
6779 | hendricks2 | 1933 | palf = weaponPal; |
1657 | terminx | 1934 | |
3695 | helixhorne | 1935 | #ifdef USE_OPENGL |
6829 | terminx | 1936 | if (videoGetRenderMode() >= REND_POLYMOST) |
5826 | terminx | 1937 | { |
1938 | if (weaponTile >= CHAINGUN + 1 && weaponTile <= CHAINGUN + 4) |
||
1939 | { |
||
1940 | if (!usemodels || md_tilehasmodel(weaponTile, weaponPal) < 0) |
||
5117 | hendricks2 | 1941 | { |
1942 | // HACK: Draw the upper part of the chaingun two screen |
||
1943 | // pixels (not texels; multiplied by weapon scale) lower |
||
1944 | // first, preventing ugly horizontal seam. |
||
1945 | g_dts_yadd = tabledivide32_noinline(65536 * 2 * 200, ydim); |
||
6779 | hendricks2 | 1946 | G_DrawTileScaled(weaponX, weaponY, weaponTile, shadef, weaponBits, weaponPal); |
5117 | hendricks2 | 1947 | g_dts_yadd = 0; |
1948 | } |
||
5826 | terminx | 1949 | } |
1950 | } |
||
3695 | helixhorne | 1951 | #endif |
5826 | terminx | 1952 | |
6779 | hendricks2 | 1953 | G_DrawTileScaled(weaponX, weaponY, weaponTile, shadef, weaponBits, weaponPal); |
1209 | terminx | 1954 | } |
1955 | |||
5826 | terminx | 1956 | static inline void G_DrawWeaponTileWithID(int uniqueID, int weaponX, int weaponY, int weaponTile, int weaponShade, |
6779 | hendricks2 | 1957 | int weaponBits, int p) |
4703 | terminx | 1958 | { |
5826 | terminx | 1959 | int lastUniqueID = guniqhudid; |
1960 | guniqhudid = uniqueID; |
||
4703 | terminx | 1961 | |
6779 | hendricks2 | 1962 | G_DrawWeaponTile(weaponX, weaponY, weaponTile, weaponShade, weaponBits, p); |
5826 | terminx | 1963 | |
1964 | guniqhudid = lastUniqueID; |
||
4703 | terminx | 1965 | } |
1966 | |||
6779 | hendricks2 | 1967 | static inline void G_DrawWeaponTileUnfadedWithID(int uniqueID, int weaponX, int weaponY, int weaponTile, int weaponShade, |
1968 | int weaponBits, int p) |
||
1969 | { |
||
1970 | int lastUniqueID = guniqhudid; |
||
1971 | guniqhudid = uniqueID; |
||
1972 | |||
1973 | G_DrawTileScaled(weaponX, weaponY, weaponTile, weaponShade, weaponBits, p); // skip G_DrawWeaponTile |
||
1974 | |||
1975 | guniqhudid = lastUniqueID; |
||
1976 | } |
||
1977 | |||
5826 | terminx | 1978 | static int P_DisplayKnee(int kneeShade) |
1209 | terminx | 1979 | { |
5828 | terminx | 1980 | static int8_t const knee_y[] = { 0, -8, -16, -32, -64, -84, -108, -108, -108, -72, -32, -8 }; |
7776 | terminx | 1981 | auto const ps = g_player[screenpeek].ps; |
1209 | terminx | 1982 | |
5118 | hendricks2 | 1983 | if (ps->knee_incs == 0) |
3436 | helixhorne | 1984 | return 0; |
1209 | terminx | 1985 | |
5118 | hendricks2 | 1986 | switch (VM_OnEvent(EVENT_DISPLAYKNEE, ps->i, screenpeek)) |
1987 | { |
||
5826 | terminx | 1988 | case 1: return 1; |
1989 | case -1: return 0; |
||
5118 | hendricks2 | 1990 | } |
1991 | |||
1992 | if (ps->knee_incs >= ARRAY_SIZE(knee_y) || sprite[ps->i].extra <= 0) |
||
1993 | return 0; |
||
1994 | |||
5826 | terminx | 1995 | int const kneeY = knee_y[ps->knee_incs] + (klabs(ps->look_ang) / 9) - (ps->hard_landing << 3); |
6954 | hendricks2 | 1996 | int const kneePal = P_GetKneePal(ps); |
5118 | hendricks2 | 1997 | |
7775 | terminx | 1998 | G_DrawTileScaled(105+(fix16_to_int(g_player[screenpeek].input->q16avel)>>5)-(ps->look_ang>>1)+(knee_y[ps->knee_incs]>>2), |
6725 | terminx | 1999 | kneeY+280-(fix16_to_int(ps->q16horiz-ps->q16horizoff)>>4),KNEE,kneeShade,4+DRAWEAP_CENTER,kneePal); |
2917 | helixhorne | 2000 | |
1209 | terminx | 2001 | return 1; |
2002 | } |
||
2003 | |||
5826 | terminx | 2004 | static int P_DisplayKnuckles(int knuckleShade) |
1209 | terminx | 2005 | { |
5452 | hendricks2 | 2006 | if (WW2GI) |
2007 | return 0; |
||
2008 | |||
7776 | terminx | 2009 | auto const pPlayer = g_player[screenpeek].ps; |
5826 | terminx | 2010 | |
2011 | if (pPlayer->knuckle_incs == 0) |
||
3436 | helixhorne | 2012 | return 0; |
1209 | terminx | 2013 | |
5828 | terminx | 2014 | static int8_t const knuckleFrames[] = { 0, 1, 2, 2, 3, 3, 3, 2, 2, 1, 0 }; |
5826 | terminx | 2015 | |
2016 | switch (VM_OnEvent(EVENT_DISPLAYKNUCKLES, pPlayer->i, screenpeek)) |
||
5118 | hendricks2 | 2017 | { |
5826 | terminx | 2018 | case 1: return 1; |
2019 | case -1: return 0; |
||
5118 | hendricks2 | 2020 | } |
2021 | |||
5826 | terminx | 2022 | if ((unsigned) (pPlayer->knuckle_incs>>1) >= ARRAY_SIZE(knuckleFrames) || sprite[pPlayer->i].extra <= 0) |
5118 | hendricks2 | 2023 | return 0; |
2024 | |||
5826 | terminx | 2025 | int const knuckleY = (klabs(pPlayer->look_ang) / 9) - (pPlayer->hard_landing << 3); |
2026 | int const knucklePal = P_GetHudPal(pPlayer); |
||
5118 | hendricks2 | 2027 | |
7775 | terminx | 2028 | G_DrawTileScaled(160 + (fix16_to_int(g_player[screenpeek].input->q16avel) >> 5) - (pPlayer->look_ang >> 1), |
6725 | terminx | 2029 | knuckleY + 180 - (fix16_to_int(pPlayer->q16horiz - pPlayer->q16horizoff) >> 4), |
5826 | terminx | 2030 | CRACKKNUCKLES + knuckleFrames[pPlayer->knuckle_incs >> 1], knuckleShade, 4 + DRAWEAP_CENTER, |
2031 | knucklePal); |
||
1209 | terminx | 2032 | |
2033 | return 1; |
||
2034 | } |
||
2035 | |||
3955 | helixhorne | 2036 | #if !defined LUNATIC |
2037 | // Set C-CON's WEAPON and WORKSLIKE gamevars. |
||
5826 | terminx | 2038 | void P_SetWeaponGamevars(int playerNum, const DukePlayer_t * const pPlayer) |
3413 | helixhorne | 2039 | { |