Subversion Repositories eduke32

Rev

Rev 4994 | 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"
2726 hendricks2 24
#include "common_game.h"
149 terminx 25
#include "osd.h"
1677 terminx 26
#include "player.h"
1678 terminx 27
#include "demo.h"
1567 terminx 28
#include "enet/enet.h"
5 Plagman 29
 
4440 terminx 30
#ifdef __ANDROID__
31
#include "android.h"
32
#endif
33
 
2652 terminx 34
int32_t lastvisinc;
3408 helixhorne 35
hudweapon_t hudweap;
36
 
2905 helixhorne 37
static int32_t g_snum;
5 Plagman 38
 
1567 terminx 39
extern int32_t g_levelTextTime, ticrandomseed;
1068 terminx 40
 
1220 terminx 41
int32_t g_numObituaries = 0;
42
int32_t g_numSelfObituaries = 0;
43
 
1143 terminx 44
void P_UpdateScreenPal(DukePlayer_t *p)
5 Plagman 45
{
1899 helixhorne 46
    int32_t intowater = 0;
2955 helixhorne 47
    const int32_t sect = p->cursectnum;
1899 helixhorne 48
 
1772 plagman 49
    if (p->heat_on) p->palette = SLIMEPAL;
2955 helixhorne 50
    else if (sect < 0) p->palette = BASEPAL;
51
    else if (sector[sect].ceilingpicnum >= FLOORSLIME && sector[sect].ceilingpicnum <= FLOORSLIME+2)
335 terminx 52
    {
1772 plagman 53
        p->palette = SLIMEPAL;
1899 helixhorne 54
        intowater = 1;
335 terminx 55
    }
56
    else
57
    {
3073 helixhorne 58
        if (sector[p->cursectnum].lotag == ST_2_UNDERWATER) p->palette = WATERPAL;
1772 plagman 59
        else p->palette = BASEPAL;
1899 helixhorne 60
        intowater = 1;
5 Plagman 61
    }
2955 helixhorne 62
 
1899 helixhorne 63
    g_restorePalette = 1+intowater;
5 Plagman 64
}
65
 
1143 terminx 66
static void P_IncurDamage(DukePlayer_t *p)
5 Plagman 67
{
1611 terminx 68
    int32_t damage;
5 Plagman 69
 
4745 terminx 70
    if (VM_OnEvent(EVENT_INCURDAMAGE, p->i, P_Get(p->i)) != 0)
3081 terminx 71
        return;
5 Plagman 72
 
3081 terminx 73
    sprite[p->i].extra -= p->extra_extra8>>8;
5 Plagman 74
 
3081 terminx 75
    damage = sprite[p->i].extra - p->last_extra;
5 Plagman 76
 
3081 terminx 77
    if (damage >= 0)
78
        return;
5 Plagman 79
 
3081 terminx 80
    p->extra_extra8 = 0;
5 Plagman 81
 
3081 terminx 82
    if (p->inv_amount[GET_SHIELD] > 0)
83
    {
84
        int32_t shield_damage =  damage * (20 + (krand()%30)) / 100;
85
        damage -= shield_damage;
5 Plagman 86
 
3081 terminx 87
        p->inv_amount[GET_SHIELD] += shield_damage;
88
 
89
        if (p->inv_amount[GET_SHIELD] < 0)
90
        {
91
            damage += p->inv_amount[GET_SHIELD];
92
            p->inv_amount[GET_SHIELD] = 0;
5 Plagman 93
        }
94
    }
95
 
3081 terminx 96
    sprite[p->i].extra = p->last_extra + damage;
5 Plagman 97
}
98
 
1143 terminx 99
void P_QuickKill(DukePlayer_t *p)
5 Plagman 100
{
2643 helixhorne 101
    P_PalFrom(p, 48, 48,48,48);
5 Plagman 102
 
103
    sprite[p->i].extra = 0;
104
    sprite[p->i].cstat |= 32768;
3081 terminx 105
 
1220 terminx 106
    if (ud.god == 0)
107
        A_DoGuts(p->i,JIBS6,8);
5 Plagman 108
}
109
 
1205 terminx 110
static void A_DoWaterTracers(int32_t x1,int32_t y1,int32_t z1,int32_t x2,int32_t y2,int32_t z2,int32_t n)
5 Plagman 111
{
1205 terminx 112
    int32_t i, xv, yv, zv;
113
    int16_t sect = -1;
5 Plagman 114
 
115
    i = n+1;
4658 terminx 116
    xv = tabledivide32_noinline(x2-x1, i);
117
    yv = tabledivide32_noinline(y2-y1, i);
118
    zv = tabledivide32_noinline(z2-z1, i);
5 Plagman 119
 
333 terminx 120
    if ((klabs(x1-x2)+klabs(y1-y2)) < 3084)
5 Plagman 121
        return;
122
 
1229 terminx 123
    for (i=n; i>0; i--)
5 Plagman 124
    {
125
        x1 += xv;
126
        y1 += yv;
127
        z1 += zv;
128
        updatesector(x1,y1,&sect);
1490 terminx 129
        if (sect < 0)
130
            break;
131
 
3073 helixhorne 132
        if (sector[sect].lotag == ST_2_UNDERWATER)
1490 terminx 133
            A_InsertSprite(sect,x1,y1,z1,WATERBUBBLE,-32,4+(krand()&3),4+(krand()&3),krand()&2047,0,0,g_player[0].ps->i,5);
134
        else
135
            A_InsertSprite(sect,x1,y1,z1,SMALLSMOKE,-32,14,14,0,0,0,g_player[0].ps->i,5);
5 Plagman 136
    }
137
}
138
 
1207 terminx 139
static void A_HitscanProjTrail(const vec3_t *sv, const vec3_t *dv, int32_t ang, int32_t atwith)
5 Plagman 140
{
1205 terminx 141
    int32_t n, j, i;
142
    int16_t sect = -1;
1207 terminx 143
    vec3_t srcvect;
144
    vec3_t destvect;
5 Plagman 145
 
3361 helixhorne 146
    const projectile_t *const proj = &ProjectileData[atwith];
147
 
1208 terminx 148
    Bmemcpy(&destvect, dv, sizeof(vec3_t));
5 Plagman 149
 
4658 terminx 150
    srcvect.x = sv->x + tabledivide32_noinline(sintable[(348+ang+512)&2047], proj->offset);
151
    srcvect.y = sv->y + tabledivide32_noinline(sintable[(ang+348)&2047], proj->offset);
3361 helixhorne 152
    srcvect.z = sv->z + 1024+(proj->toffset<<8);
5 Plagman 153
 
1207 terminx 154
    n = ((FindDistance2D(srcvect.x-destvect.x,srcvect.y-destvect.y))>>8)+1;
5 Plagman 155
 
4658 terminx 156
    destvect.x = tabledivide32_noinline((destvect.x-srcvect.x), n);
157
    destvect.y = tabledivide32_noinline((destvect.y-srcvect.y), n);
158
    destvect.z = tabledivide32_noinline((destvect.z-srcvect.z), n);
252 terminx 159
 
1207 terminx 160
    srcvect.x += destvect.x>>2;
161
    srcvect.y += destvect.y>>2;
162
    srcvect.z += (destvect.z>>2);
163
 
3361 helixhorne 164
    for (i=proj->tnum; i>0; i--)
5 Plagman 165
    {
1207 terminx 166
        srcvect.x += destvect.x;
167
        srcvect.y += destvect.y;
168
        srcvect.z += destvect.z;
169
        updatesector(srcvect.x,srcvect.y,&sect);
1488 terminx 170
        if (sect < 0)
171
            break;
1207 terminx 172
        getzsofslope(sect,srcvect.x,srcvect.y,&n,&j);
1488 terminx 173
        if (srcvect.z > j || srcvect.z < n)
861 terminx 174
            break;
3361 helixhorne 175
        j = A_InsertSprite(sect,srcvect.x,srcvect.y,srcvect.z,proj->trail,-32,
176
                           proj->txrepeat,proj->tyrepeat,ang,0,0,g_player[0].ps->i,0);
2642 helixhorne 177
        changespritestat(j, STAT_ACTOR);
5 Plagman 178
    }
179
}
180
 
1205 terminx 181
int32_t A_GetHitscanRange(int32_t i)
5 Plagman 182
{
1611 terminx 183
    int32_t zoff = (PN == APLAYER) ? PHEIGHT : 0;
2877 helixhorne 184
    hitdata_t hit;
5 Plagman 185
 
1208 terminx 186
    SZ -= zoff;
187
    hitscan((const vec3_t *)&sprite[i],SECT,
5 Plagman 188
            sintable[(SA+512)&2047],
189
            sintable[SA&2047],
2877 helixhorne 190
            0,&hit,CLIPMASK1);
1611 terminx 191
    SZ += zoff;
5 Plagman 192
 
2877 helixhorne 193
    return (FindDistance2D(hit.pos.x-SX,hit.pos.y-SY));
5 Plagman 194
}
195
 
3955 helixhorne 196
static int32_t A_FindTargetSprite(const spritetype *s, int32_t aang, int32_t atwith)
5 Plagman 197
{
1205 terminx 198
    int32_t gotshrinker,gotfreezer;
199
    int32_t i, j, a, k, cans;
3955 helixhorne 200
    static const int32_t aimstats[] = {
201
        STAT_PLAYER, STAT_DUMMYPLAYER, STAT_ACTOR, STAT_ZOMBIEACTOR
202
    };
1205 terminx 203
    int32_t dx1, dy1, dx2, dy2, dx3, dy3, smax, sdist;
204
    int32_t xv, yv;
5 Plagman 205
 
4226 helixhorne 206
    const int32_t snum = s->picnum == APLAYER ? P_GetP(s) : -1;
207
 
335 terminx 208
    if (s->picnum == APLAYER)
209
    {
4226 helixhorne 210
        if (!g_player[snum].ps->auto_aim)
19 terminx 211
            return -1;
3081 terminx 212
 
4226 helixhorne 213
        if (g_player[snum].ps->auto_aim == 2)
19 terminx 214
        {
4351 helixhorne 215
            if (A_CheckSpriteTileFlags(atwith,SFLAG_PROJECTILE) && (ProjectileData[atwith].workslike & PROJECTILE_RPG))
19 terminx 216
                return -1;
3955 helixhorne 217
 
218
            switch (DYNAMICTILEMAP(atwith))
219
            {
220
            case TONGUE__STATIC:
221
            case FREEZEBLAST__STATIC:
222
            case SHRINKSPARK__STATIC:
223
            case SHRINKER__STATIC:
224
            case RPG__STATIC:
225
            case FIRELASER__STATIC:
226
            case SPIT__STATIC:
227
            case COOLEXPLOSION1__STATIC:
228
                return -1;
229
            default:
230
                break;
231
            }
19 terminx 232
        }
233
    }
120 terminx 234
 
235
    a = s->ang;
236
 
237
    j = -1;
238
 
4654 terminx 239
    gotshrinker = (s->picnum == APLAYER && PWEAPON(snum, g_player[snum].ps->curr_weapon, WorksLike) == SHRINKER_WEAPON);
240
    gotfreezer = (s->picnum == APLAYER && PWEAPON(snum, g_player[snum].ps->curr_weapon, WorksLike) == FREEZE_WEAPON);
5 Plagman 241
 
2984 helixhorne 242
    smax = INT32_MAX;
5 Plagman 243
 
244
    dx1 = sintable[(a+512-aang)&2047];
245
    dy1 = sintable[(a-aang)&2047];
246
    dx2 = sintable[(a+512+aang)&2047];
247
    dy2 = sintable[(a+aang)&2047];
248
 
249
    dx3 = sintable[(a+512)&2047];
250
    dy3 = sintable[a&2047];
251
 
1229 terminx 252
    for (k=0; k<4; k++)
5 Plagman 253
    {
333 terminx 254
        if (j >= 0)
5 Plagman 255
            break;
1229 terminx 256
        for (i=headspritestat[aimstats[k]]; i >= 0; i=nextspritestat[i])
333 terminx 257
            if (sprite[i].xrepeat > 0 && sprite[i].extra >= 0 && (sprite[i].cstat&(257+32768)) == 257)
1143 terminx 258
                if (A_CheckEnemySprite(&sprite[i]) || k < 2)
5 Plagman 259
                {
1143 terminx 260
                    if (A_CheckEnemySprite(&sprite[i]) || PN == APLAYER || PN == SHARK)
5 Plagman 261
                    {
4226 helixhorne 262
                        if (PN == APLAYER && s->picnum == APLAYER && s != &sprite[i] &&
5 Plagman 263
                                //                        ud.ffire == 0 &&
1611 terminx 264
                                (GTFLAGS(GAMETYPE_PLAYERSFRIENDLY) || (GTFLAGS(GAMETYPE_TDM) &&
4226 helixhorne 265
                                        g_player[P_Get(i)].ps->team == g_player[snum].ps->team)))
5 Plagman 266
                            continue;
267
 
333 terminx 268
                        if (gotshrinker && sprite[i].xrepeat < 30)
5 Plagman 269
                        {
335 terminx 270
                            if (PN == SHARK)
271
                            {
331 terminx 272
                                if (sprite[i].xrepeat < 20) continue;
5 Plagman 273
                                continue;
331 terminx 274
                            }
398 terminx 275
                            else if (!(PN >= GREENSLIME && PN <= GREENSLIME+7))
5 Plagman 276
                                continue;
277
                        }
331 terminx 278
                        if (gotfreezer && sprite[i].pal == 1) continue;
5 Plagman 279
                    }
280
 
281
                    xv = (SX-s->x);
282
                    yv = (SY-s->y);
283
 
3081 terminx 284
                    if ((dy1*xv <= dx1*yv) && (dy2*xv >= dx2*yv))
285
                    {
286
                        sdist = mulscale(dx3,xv,14) + mulscale(dy3,yv,14);
287
 
288
                        if (sdist > 512 && sdist < smax)
5 Plagman 289
                        {
3081 terminx 290
                            if (s->picnum == APLAYER)
4226 helixhorne 291
                            {
292
                                const DukePlayer_t *const ps = g_player[P_GetP(s)].ps;
293
                                a = (klabs(scale(SZ-s->z,10,sdist)-(ps->horiz+ps->horizoff-100)) < 100);
294
                            }
3081 terminx 295
                            else a = 1;
5 Plagman 296
 
3081 terminx 297
                            if (PN == ORGANTIC || PN == ROTATEGUN)
298
                                cans = cansee(SX,SY,SZ,SECT,s->x,s->y,s->z-(32<<8),s->sectnum);
299
                            else cans = cansee(SX,SY,SZ-(32<<8),SECT,s->x,s->y,s->z-(32<<8),s->sectnum);
5 Plagman 300
 
3081 terminx 301
                            if (a && cans)
302
                            {
303
                                smax = sdist;
304
                                j = i;
5 Plagman 305
                            }
306
                        }
3081 terminx 307
                    }
5 Plagman 308
                }
309
    }
310
 
311
    return j;
312
}
313
 
2979 helixhorne 314
static void A_SetHitData(int32_t i, const hitdata_t *hit)
315
{
316
    actor[i].t_data[6] = hit->wall;
317
    actor[i].t_data[7] = hit->sect;
318
    actor[i].t_data[8] = hit->sprite;
319
}
320
 
2980 helixhorne 321
static int32_t CheckShootSwitchTile(int32_t pn)
322
{
323
    return pn == DIPSWITCH || pn == DIPSWITCH+1 ||
324
        pn == DIPSWITCH2 || pn == DIPSWITCH2+1 ||
325
        pn == DIPSWITCH3 || pn == DIPSWITCH3+1 ||
326
        pn == HANDSWITCH || pn == HANDSWITCH+1;
327
}
328
 
3462 helixhorne 329
static int32_t safeldist(int32_t spritenum1, const spritetype *s2)
330
{
331
    int32_t dst = ldist(&sprite[spritenum1], s2);
332
    return dst ? dst : 1;
333
}
334
 
2983 helixhorne 335
// flags:
336
//  1: do sprite center adjustment (cen-=(8<<8)) for GREENSLIME or ROTATEGUN
337
//  2: do auto getangle only if not RECON (if clear, do unconditionally)
338
static int32_t GetAutoAimAngle(int32_t i, int32_t p, int32_t atwith,
339
                               int32_t cen_add, int32_t flags,
340
                               const vec3_t *srcvect, int32_t vel,
341
                               int32_t *zvel, int16_t *sa)
5 Plagman 342
{
3359 helixhorne 343
    int32_t j = -1;
2983 helixhorne 344
 
345
    Bassert((unsigned)p < MAXPLAYERS);
346
 
3366 helixhorne 347
#ifdef LUNATIC
4595 terminx 348
    g_player[p].ps->autoaimang = g_player[p].ps->auto_aim == 3 ? AUTO_AIM_ANGLE<<1 : AUTO_AIM_ANGLE;
3366 helixhorne 349
#else
4595 terminx 350
    Gv_SetVar(g_iAimAngleVarID, g_player[p].ps->auto_aim == 3 ? AUTO_AIM_ANGLE<<1 : AUTO_AIM_ANGLE, i, p);
3366 helixhorne 351
#endif
3081 terminx 352
 
4745 terminx 353
    VM_OnEvent(EVENT_GETAUTOAIMANGLE, i, p);
2983 helixhorne 354
 
355
    {
3366 helixhorne 356
#ifdef LUNATIC
357
        int32_t aimang = g_player[p].ps->autoaimang;
358
#else
2983 helixhorne 359
        int32_t aimang = Gv_GetVar(g_iAimAngleVarID, i, p);
3366 helixhorne 360
#endif
2983 helixhorne 361
        if (aimang > 0)
362
            j = A_FindTargetSprite(&sprite[i], aimang, atwith);
363
    }
364
 
365
    if (j >= 0)
366
    {
367
        const spritetype *const spr = &sprite[j];
4623 terminx 368
        int32_t cen = 2*(spr->yrepeat*tilesiz[spr->picnum].y) + cen_add;
2983 helixhorne 369
        int32_t dst;
370
 
371
        if (flags)
372
        {
373
            int32_t pn = spr->picnum;
374
            if ((pn >= GREENSLIME && pn <= GREENSLIME+7) || spr->picnum==ROTATEGUN)
375
            {
376
                cen -= (8<<8);
377
            }
378
        }
379
 
3462 helixhorne 380
        dst = safeldist(g_player[p].ps->i, &sprite[j]);
4658 terminx 381
        *zvel = tabledivide32_noinline((spr->z - srcvect->z - cen)*vel, dst);
2983 helixhorne 382
 
383
        if (!(flags&2) || sprite[j].picnum != RECON)
384
            *sa = getangle(spr->x-srcvect->x, spr->y-srcvect->y);
385
    }
386
 
387
    return j;
388
}
389
 
3353 helixhorne 390
static void Proj_MaybeSpawn(int32_t k, int32_t atwith, const hitdata_t *hit)
391
{
3360 helixhorne 392
    // atwith < 0 is for hard-coded projectiles
393
    int32_t spawntile = atwith < 0 ? -atwith : ProjectileData[atwith].spawns;
394
 
395
    if (spawntile >= 0)
3353 helixhorne 396
    {
3360 helixhorne 397
        int32_t wh = A_Spawn(k, spawntile);
3359 helixhorne 398
 
3360 helixhorne 399
        if (atwith >= 0)
400
        {
401
            if (ProjectileData[atwith].sxrepeat > 4)
402
                sprite[wh].xrepeat = ProjectileData[atwith].sxrepeat;
403
            if (ProjectileData[atwith].syrepeat > 4)
404
                sprite[wh].yrepeat = ProjectileData[atwith].syrepeat;
405
        }
3359 helixhorne 406
 
3353 helixhorne 407
        A_SetHitData(wh, hit);
408
    }
409
}
410
 
3360 helixhorne 411
// <extra>: damage that this shotspark does
3359 helixhorne 412
static int32_t Proj_InsertShotspark(const hitdata_t *hit, int32_t i, int32_t atwith,
413
                                    int32_t xyrepeat, int32_t ang, int32_t extra)
3353 helixhorne 414
{
3359 helixhorne 415
    int32_t k = A_InsertSprite(hit->sect, hit->pos.x, hit->pos.y, hit->pos.z,
416
                               SHOTSPARK1,-15, xyrepeat,xyrepeat, ang,0,0,i,4);
417
    sprite[k].extra = extra;
418
    // This is a hack to allow you to detect which weapon spawned a SHOTSPARK1:
419
    sprite[k].yvel = atwith;
3353 helixhorne 420
    A_SetHitData(k, hit);
421
 
422
    return k;
423
}
424
 
3359 helixhorne 425
static int32_t Proj_GetExtra(int32_t atwith)
426
{
427
    int32_t extra = ProjectileData[atwith].extra;
428
    if (ProjectileData[atwith].extra_rand > 0)
429
        extra += (krand()%ProjectileData[atwith].extra_rand);
430
    return extra;
431
}
432
 
3358 helixhorne 433
static void Proj_MaybeAddSpread(int32_t not_accurate_p, int32_t *zvel, int16_t *sa,
434
                                int32_t zRange, int32_t angRange)
435
{
436
    if (not_accurate_p)
437
    {
3715 helixhorne 438
        // Ranges <= 1 mean no spread at all. A range of 1 calls krand() though.
439
        if (zRange > 0)
440
            *zvel += zRange/2 - krand()%zRange;
441
        if (angRange > 0)
442
            *sa += angRange/2 - krand()%angRange;
3358 helixhorne 443
    }
444
}
445
 
3465 helixhorne 446
 
3921 helixhorne 447
static int32_t g_overrideShootZvel = 0;  // a boolean
448
static int32_t g_shootZvel;  // the actual zvel if the above is !=0
3465 helixhorne 449
 
3921 helixhorne 450
static int32_t A_GetShootZvel(int32_t defaultzvel)
3465 helixhorne 451
{
3921 helixhorne 452
    return g_overrideShootZvel ? g_shootZvel : defaultzvel;
3465 helixhorne 453
}
454
 
3358 helixhorne 455
// Prepare hitscan weapon fired from player p.
456
static void P_PreFireHitscan(int32_t i, int32_t p, int32_t atwith,
457
                             vec3_t *srcvect, int32_t *zvel, int16_t *sa,
458
                             int32_t accurate_autoaim_p,
459
                             int32_t not_accurate_p)
460
{
461
    int32_t angRange=32;
462
    int32_t zRange=256;
463
 
464
    int32_t j = GetAutoAimAngle(i, p, atwith, 5<<8, 0+1, srcvect, 256, zvel, sa);
3366 helixhorne 465
    DukePlayer_t *const ps = g_player[p].ps;
3358 helixhorne 466
 
3366 helixhorne 467
#ifdef LUNATIC
468
    ps->angrange = angRange;
469
    ps->zrange = zRange;
470
#else
3358 helixhorne 471
    Gv_SetVar(g_iAngRangeVarID,angRange, i,p);
472
    Gv_SetVar(g_iZRangeVarID,zRange,i,p);
3366 helixhorne 473
#endif
3358 helixhorne 474
 
4745 terminx 475
    VM_OnEvent(EVENT_GETSHOTRANGE, i, p);
3366 helixhorne 476
 
3405 helixhorne 477
#ifdef LUNATIC
3366 helixhorne 478
    angRange = ps->angrange;
479
    zRange = ps->zrange;
480
#else
3358 helixhorne 481
    angRange=Gv_GetVar(g_iAngRangeVarID,i,p);
482
    zRange=Gv_GetVar(g_iZRangeVarID,i,p);
483
#endif
3366 helixhorne 484
 
3358 helixhorne 485
    if (accurate_autoaim_p)
486
    {
487
        if (!ps->auto_aim)
488
        {
489
            hitdata_t hit;
490
 
3921 helixhorne 491
            *zvel = A_GetShootZvel((100-ps->horiz-ps->horizoff)<<5);
3358 helixhorne 492
 
493
            hitscan(srcvect, sprite[i].sectnum, sintable[(*sa+512)&2047], sintable[*sa&2047],
494
                    *zvel<<6,&hit,CLIPMASK1);
495
 
496
            if (hit.sprite != -1)
497
            {
498
                const int32_t hitstatnumsbitmap =
499
                    ((1<<STAT_ACTOR) | (1<<STAT_ZOMBIEACTOR) | (1<<STAT_PLAYER) | (1<<STAT_DUMMYPLAYER));
500
                const int32_t st = sprite[hit.sprite].statnum;
501
 
502
                if (st>=0 && st<=30 && (hitstatnumsbitmap&(1<<st)))
503
                    j = hit.sprite;
504
            }
505
        }
506
 
507
        if (j == -1)
508
        {
509
            *zvel = (100-ps->horiz-ps->horizoff)<<5;
510
            Proj_MaybeAddSpread(not_accurate_p, zvel, sa, zRange, angRange);
511
        }
512
    }
513
    else
514
    {
515
        if (j == -1)  // no target
516
            *zvel = (100-ps->horiz-ps->horizoff)<<5;
517
        Proj_MaybeAddSpread(not_accurate_p, zvel, sa, zRange, angRange);
518
    }
519
 
520
    srcvect->z -= (2<<8);
521
}
522
 
523
// Hitscan weapon fired from actor (sprite s);
524
static void A_PreFireHitscan(const spritetype *s, vec3_t *srcvect, int32_t *zvel, int16_t *sa,
525
                             int32_t not_accurate_p)
526
{
3680 helixhorne 527
    const int32_t j = A_FindPlayer(s, NULL);
3358 helixhorne 528
    const DukePlayer_t *targetps = g_player[j].ps;
529
 
3680 helixhorne 530
    const int32_t d = safeldist(targetps->i, s);
4658 terminx 531
    *zvel = tabledivide32_noinline((targetps->pos.z-srcvect->z)<<8, d);
3358 helixhorne 532
 
533
    srcvect->z -= (4<<8);
534
 
535
    if (s->picnum != BOSS1)
536
    {
537
        Proj_MaybeAddSpread(not_accurate_p, zvel, sa, 256, 64);
538
    }
539
    else
540
    {
541
        *sa = getangle(targetps->pos.x-srcvect->x, targetps->pos.y-srcvect->y);
542
 
543
        Proj_MaybeAddSpread(not_accurate_p, zvel, sa, 256, 128);
544
    }
545
}
546
 
3360 helixhorne 547
static int32_t Proj_DoHitscan(int32_t i, int32_t cstatmask,
548
                              const vec3_t *srcvect, int32_t zvel, int16_t sa,
549
                              hitdata_t *hit)
3359 helixhorne 550
{
551
    spritetype *const s = &sprite[i];
552
 
553
    s->cstat &= ~cstatmask;
554
 
3921 helixhorne 555
    zvel = A_GetShootZvel(zvel);
3359 helixhorne 556
 
557
    hitscan(srcvect, s->sectnum,
558
            sintable[(sa+512)&2047],
559
            sintable[sa&2047],
560
            zvel<<6, hit, CLIPMASK1);
561
 
562
    s->cstat |= cstatmask;
563
 
564
    return (hit->sect < 0);
565
}
566
 
3362 helixhorne 567
static void Proj_DoRandDecalSize(int32_t spritenum, int32_t atwith)
568
{
569
    const projectile_t *const proj = &ProjectileData[atwith];
570
 
571
    if (proj->workslike & PROJECTILE_RANDDECALSIZE)
572
    {
573
        int32_t wh = (krand()&proj->xrepeat);
574
        if (wh < proj->yrepeat)
575
            wh = proj->yrepeat;
576
        sprite[spritenum].xrepeat = wh;
577
        sprite[spritenum].yrepeat = wh;
578
    }
579
    else
580
    {
581
        sprite[spritenum].xrepeat = proj->xrepeat;
582
        sprite[spritenum].yrepeat = proj->yrepeat;
583
    }
584
}
585
 
586
static int32_t SectorContainsSE13(int32_t sectnum)
587
{
588
    int32_t i;
589
    if (sectnum >= 0)
590
        for (SPRITES_OF_SECT(sectnum, i))
591
            if (sprite[i].statnum == STAT_EFFECTOR && sprite[i].lotag == SE_13_EXPLOSIVE)
592
                return 1;
593
    return 0;
594
}
595
 
596
// Maybe handle bit 2 (swap wall bottoms).
597
// (in that case walltype *hitwal may be stale)
4745 terminx 598
static inline void HandleHitWall(hitdata_t *hit)
3362 helixhorne 599
{
600
    const walltype *const hitwal = &wall[hit->wall];
601
 
602
    if ((hitwal->cstat&2) && redwallp(hitwal))
603
        if (hit->pos.z >= sector[hitwal->nextsector].floorz)
604
            hit->wall = hitwal->nextwall;
605
}
606
 
4204 helixhorne 607
// Maybe damage a ceiling or floor as the consequence of projectile impact.
608
// Returns 1 if projectile hit a parallaxed ceiling.
609
// NOTE: Compare with Proj_MaybeDamageCF() in actors.c
610
static int32_t Proj_MaybeDamageCF2(int32_t zvel, int32_t hitsect)
611
{
612
    if (zvel < 0)
613
    {
614
        Bassert(hitsect >= 0);
615
 
616
        if (sector[hitsect].ceilingstat&1)
617
            return 1;
618
 
4205 helixhorne 619
        Sect_DamageCeilingOrFloor(0, hitsect);
4204 helixhorne 620
    }
4205 helixhorne 621
    else if (zvel > 0)
622
    {
623
        Bassert(hitsect >= 0);
4204 helixhorne 624
 
4205 helixhorne 625
        if (sector[hitsect].floorstat&1)
626
        {
627
            // Keep original Duke3D behavior: pass projectiles through
628
            // parallaxed ceilings, but NOT through such floors.
629
            return 0;
630
        }
631
 
632
        Sect_DamageCeilingOrFloor(1, hitsect);
633
    }
634
 
4204 helixhorne 635
    return 0;
636
}
637
 
3360 helixhorne 638
// Finish shooting hitscan weapon from player <p>. <k> is the inserted SHOTSPARK1.
639
// * <spawnatimpacttile> is passed to Proj_MaybeSpawn()
640
// * <decaltile> and <damagewalltile> are for wall impact
641
// * <damagewalltile> is passed to A_DamageWall()
642
// * <flags> is for decals upon wall impact:
643
//    1: handle random decal size (tile <atwith>)
644
//    2: set cstat to wall-aligned + random x/y flip
645
//
646
// TODO: maybe split into 3 cases (hit neither wall nor sprite, hit sprite, hit wall)?
647
static int32_t P_PostFireHitscan(int32_t p, int32_t k, hitdata_t *hit, int32_t i, int32_t atwith, int32_t zvel,
648
                                 int32_t spawnatimpacttile, int32_t decaltile, int32_t damagewalltile,
649
                                 int32_t flags)
650
{
651
    if (hit->wall == -1 && hit->sprite == -1)
652
    {
4204 helixhorne 653
        if (Proj_MaybeDamageCF2(zvel, hit->sect))
3360 helixhorne 654
        {
4204 helixhorne 655
            sprite[k].xrepeat = 0;
656
            sprite[k].yrepeat = 0;
657
            return -1;
3360 helixhorne 658
        }
659
 
660
        Proj_MaybeSpawn(k, spawnatimpacttile, hit);
661
    }
662
    else if (hit->sprite >= 0)
663
    {
664
        A_DamageObject(hit->sprite, k);
665
 
666
        if (sprite[hit->sprite].picnum == APLAYER &&
667
            (ud.ffire == 1 || (!GTFLAGS(GAMETYPE_PLAYERSFRIENDLY) && GTFLAGS(GAMETYPE_TDM) &&
4226 helixhorne 668
                               g_player[P_Get(hit->sprite)].ps->team != g_player[P_Get(i)].ps->team)))
3360 helixhorne 669
        {
670
            int32_t l = A_Spawn(k, JIBS6);
671
            sprite[k].xrepeat = sprite[k].yrepeat = 0;
672
            sprite[l].z += (4<<8);
673
            sprite[l].xvel = 16;
674
            sprite[l].xrepeat = sprite[l].yrepeat = 24;
675
            sprite[l].ang += 64-(krand()&127);
676
        }
677
        else
678
        {
679
            Proj_MaybeSpawn(k, spawnatimpacttile, hit);
680
        }
681
 
682
        if (p >= 0 && CheckShootSwitchTile(sprite[hit->sprite].picnum))
683
        {
684
            P_ActivateSwitch(p, hit->sprite, 1);
685
            return -1;
686
        }
687
    }
688
    else if (hit->wall >= 0)
689
    {
690
        const walltype *const hitwal = &wall[hit->wall];
691
 
692
        Proj_MaybeSpawn(k, spawnatimpacttile, hit);
693
 
694
        if (CheckDoorTile(hitwal->picnum) == 1)
695
            goto SKIPBULLETHOLE;
696
 
697
        if (p >= 0 && CheckShootSwitchTile(hitwal->picnum))
698
        {
699
            P_ActivateSwitch(p, hit->wall, 0);
700
            return -1;
701
        }
702
 
703
        if (hitwal->hitag != 0 || (hitwal->nextwall >= 0 && wall[hitwal->nextwall].hitag != 0))
704
            goto SKIPBULLETHOLE;
705
 
706
        if (hit->sect >= 0 && sector[hit->sect].lotag == 0)
707
            if (hitwal->overpicnum != BIGFORCE && (hitwal->cstat&16) == 0)
708
                if ((hitwal->nextsector >= 0 && sector[hitwal->nextsector].lotag == 0) ||
709
                    (hitwal->nextsector == -1 && sector[hit->sect].lotag == 0))
710
                {
711
                    int32_t l;
712
 
3362 helixhorne 713
                    if (SectorContainsSE13(hitwal->nextsector))
714
                        goto SKIPBULLETHOLE;
3360 helixhorne 715
 
716
                    for (SPRITES_OF(STAT_MISC, l))
717
                        if (sprite[l].picnum == decaltile)
718
                            if (dist(&sprite[l],&sprite[k]) < (12+(krand()&7)))
719
                                goto SKIPBULLETHOLE;
720
 
721
                    if (decaltile >= 0)
722
                    {
723
                        l = A_Spawn(k, decaltile);
724
 
4351 helixhorne 725
                        if (!A_CheckSpriteFlags(l, SFLAG_DECAL))
726
                            actor[l].flags |= SFLAG_DECAL;
3360 helixhorne 727
 
728
                        sprite[l].xvel = -1;
729
                        sprite[l].ang = getangle(hitwal->x-wall[hitwal->point2].x,
730
                                                 hitwal->y-wall[hitwal->point2].y)+512;
731
                        if (flags&1)
3362 helixhorne 732
                            Proj_DoRandDecalSize(l, atwith);
3360 helixhorne 733
 
734
                        if (flags&2)
735
                            sprite[l].cstat = 16+(krand()&(8+4));
736
 
737
                        sprite[l].x -= sintable[(sprite[l].ang+2560)&2047]>>13;
738
                        sprite[l].y -= sintable[(sprite[l].ang+2048)&2047]>>13;
739
 
740
                        A_SetSprite(l, CLIPMASK0);
741
 
742
                        // BULLETHOLE already adds itself to the deletion queue in
743
                        // A_Spawn(). However, some other tiles do as well.
744
                        if (decaltile != BULLETHOLE)
745
                            A_AddToDeleteQueue(l);
746
                    }
747
                }
748
 
749
SKIPBULLETHOLE:
3362 helixhorne 750
        HandleHitWall(hit);
3360 helixhorne 751
 
752
        A_DamageWall(k, hit->wall, &hit->pos, damagewalltile);
753
    }
754
 
755
    return 0;
756
}
757
 
758
// Finish shooting hitscan weapon from actor (sprite <i>).
759
static int32_t A_PostFireHitscan(const hitdata_t *hit, int32_t i, int32_t atwith, int32_t sa, int32_t extra,
760
                                 int32_t spawnatimpacttile, int32_t damagewalltile)
761
{
762
    int32_t k = Proj_InsertShotspark(hit, i, atwith, 24, sa, extra);
763
 
764
    if (hit->sprite >= 0)
765
    {
766
        A_DamageObject(hit->sprite, k);
767
 
768
        if (sprite[hit->sprite].picnum != APLAYER)
769
            Proj_MaybeSpawn(k, spawnatimpacttile, hit);
770
        else
771
            sprite[k].xrepeat = sprite[k].yrepeat = 0;
772
    }
773
    else if (hit->wall >= 0)
774
        A_DamageWall(k, hit->wall, &hit->pos, damagewalltile);
775
 
776
    return k;
777
}
778
 
3362 helixhorne 779
// Common "spawn blood?" predicate.
780
// minzdiff: minimal "step" height for blood to be spawned
781
static int32_t Proj_CheckBlood(const vec3_t *srcvect, const hitdata_t *hit,
782
                               int32_t projrange, int32_t minzdiff)
783
{
4680 terminx 784
    const walltype * hitwal;
3362 helixhorne 785
 
4680 terminx 786
    if (hit->wall < 0 || hit->sect < 0)
787
        return 0;
788
 
789
    hitwal = &wall[hit->wall];
790
 
791
    if (FindDistance2D(srcvect->x-hit->pos.x, srcvect->y-hit->pos.y) < projrange)
792
        if (hitwal->overpicnum != BIGFORCE && (hitwal->cstat&16) == 0)
793
            if (sector[hit->sect].lotag == 0)
794
                if (hitwal->nextsector < 0 ||
795
                    (sector[hitwal->nextsector].lotag == 0 && sector[hit->sect].lotag == 0 &&
796
                    sector[hit->sect].floorz-sector[hitwal->nextsector].floorz > minzdiff))
3362 helixhorne 797
                    return 1;
798
 
799
    return 0;
800
}
801
 
802
static void Proj_HandleKnee(hitdata_t *hit, int32_t i, int32_t p, int32_t atwith, int32_t sa,
803
                            const projectile_t *proj, int32_t inserttile,
804
                            int32_t addrandextra, int32_t spawnatimpacttile, int32_t soundnum)
805
{
806
    const DukePlayer_t *const ps = p >= 0 ? g_player[p].ps : NULL;
807
 
808
    int32_t j = A_InsertSprite(hit->sect,hit->pos.x,hit->pos.y,hit->pos.z,
809
                               inserttile,-15,0,0,sa,32,0,i,4);
810
 
811
    if (proj != NULL)
812
    {
813
        // Custom projectiles.
814
        SpriteProjectile[j].workslike = ProjectileData[sprite[j].picnum].workslike;
815
        sprite[j].extra = proj->extra;
816
    }
817
 
818
    if (addrandextra > 0)
819
        sprite[j].extra += (krand()&addrandextra);
820
 
821
    if (p >= 0)
822
    {
823
        if (spawnatimpacttile >= 0)
824
        {
825
            int32_t k = A_Spawn(j, spawnatimpacttile);
826
            sprite[k].z -= (8<<8);
827
            A_SetHitData(k, hit);
828
        }
829
 
830
        if (soundnum >= 0)
831
            A_PlaySound(soundnum, j);
832
    }
833
 
834
    if (p >= 0 && ps->inv_amount[GET_STEROIDS] > 0 && ps->inv_amount[GET_STEROIDS] < 400)
835
        sprite[j].extra += (ps->max_player_health>>2);
836
 
837
    if (hit->sprite >= 0 && sprite[hit->sprite].picnum != ACCESSSWITCH && sprite[hit->sprite].picnum != ACCESSSWITCH2)
838
    {
839
        A_DamageObject(hit->sprite, j);
840
        if (p >= 0)
841
            P_ActivateSwitch(p, hit->sprite,1);
842
    }
843
    else if (hit->wall >= 0)
844
    {
845
        HandleHitWall(hit);
846
 
847
        if (wall[hit->wall].picnum != ACCESSSWITCH && wall[hit->wall].picnum != ACCESSSWITCH2)
848
        {
849
            A_DamageWall(j, hit->wall, &hit->pos, atwith);
850
            if (p >= 0)
851
                P_ActivateSwitch(p, hit->wall,0);
852
        }
853
    }
854
}
855
 
3544 hendricks2 856
#define MinibossScale(s) (((s)*sprite[i].yrepeat)/80)
3992 terminx 857
 
858
static int32_t A_ShootCustom(const int32_t i, const int32_t atwith, int16_t sa, vec3_t * const srcvect)
2983 helixhorne 859
{
3992 terminx 860
    /* Custom projectiles */
861
    projectile_t *const proj = &ProjectileData[atwith];
862
    int32_t j, k = -1, l;
3680 helixhorne 863
    int32_t vel, zvel = 0;
2877 helixhorne 864
    hitdata_t hit;
2977 helixhorne 865
    spritetype *const s = &sprite[i];
866
    const int16_t sect = s->sectnum;
4226 helixhorne 867
    const int32_t p = (s->picnum == APLAYER) ? P_GetP(s) : -1;
2876 helixhorne 868
    DukePlayer_t *const ps = p >= 0 ? g_player[p].ps : NULL;
869
 
3992 terminx 870
#ifdef POLYMER
4680 terminx 871
    if (getrendermode() == REND_POLYMER && proj->flashcolor)
3465 helixhorne 872
    {
3992 terminx 873
        int32_t x = ((sintable[(s->ang + 512) & 2047]) >> 7), y = ((sintable[(s->ang) & 2047]) >> 7);
874
 
875
        s->x += x;
876
        s->y += y;
877
        G_AddGameLight(0, i, PHEIGHT, 8192, proj->flashcolor, PR_LIGHT_PRIO_MAX_GAME);
878
        actor[i].lightcount = 2;
879
        s->x -= x;
880
        s->y -= y;
3465 helixhorne 881
    }
3992 terminx 882
#endif // POLYMER
3465 helixhorne 883
 
3992 terminx 884
    if (proj->offset == 0)
885
        proj->offset = 1;
5 Plagman 886
 
3992 terminx 887
    switch (proj->workslike & PROJECTILE_TYPE_MASK)
5 Plagman 888
    {
3992 terminx 889
    case PROJECTILE_HITSCAN:
890
        if (s->extra >= 0) s->shade = proj->shade;
1207 terminx 891
 
3992 terminx 892
        if (p >= 0)
893
            P_PreFireHitscan(i, p, atwith, srcvect, &zvel, &sa,
894
            proj->workslike & PROJECTILE_ACCURATE_AUTOAIM,
895
            !(proj->workslike & PROJECTILE_ACCURATE));
896
        else
897
            A_PreFireHitscan(s, srcvect, &zvel, &sa,
898
            !(proj->workslike & PROJECTILE_ACCURATE));
3081 terminx 899
 
3992 terminx 900
        if (Proj_DoHitscan(i, (proj->cstat >= 0) ? proj->cstat : 256 + 1,
901
            srcvect, zvel, sa, &hit))
902
            return -1;
1315 terminx 903
 
3992 terminx 904
        if (proj->range > 0 && klabs(srcvect->x - hit.pos.x) + klabs(srcvect->y - hit.pos.y) > proj->range)
905
            return -1;
1315 terminx 906
 
3992 terminx 907
        if (proj->trail >= 0)
908
            A_HitscanProjTrail(srcvect, &hit.pos, sa, atwith);
5 Plagman 909
 
3992 terminx 910
        if (proj->workslike & PROJECTILE_WATERBUBBLES)
911
        {
912
            if ((krand() & 15) == 0 && sector[hit.sect].lotag == ST_2_UNDERWATER)
913
                A_DoWaterTracers(hit.pos.x, hit.pos.y, hit.pos.z,
914
                srcvect->x, srcvect->y, srcvect->z, 8 - (ud.multimode >> 1));
915
        }
5 Plagman 916
 
3992 terminx 917
        if (p >= 0)
1319 terminx 918
        {
3992 terminx 919
            k = Proj_InsertShotspark(&hit, i, atwith, 10, sa, Proj_GetExtra(atwith));
1402 terminx 920
 
3992 terminx 921
            if (P_PostFireHitscan(p, k, &hit, i, atwith, zvel,
922
                atwith, proj->decal, atwith, 1 + 2) < 0)
923
                return -1;
1319 terminx 924
        }
3992 terminx 925
        else
926
        {
927
            k = A_PostFireHitscan(&hit, i, atwith, sa, Proj_GetExtra(atwith),
928
                atwith, atwith);
929
        }
1319 terminx 930
 
3992 terminx 931
        if ((krand() & 255) < 4 && proj->isound >= 0)
932
            S_PlaySound3D(proj->isound, k, &hit.pos);
5 Plagman 933
 
3992 terminx 934
        return -1;
935
 
936
    case PROJECTILE_RPG:
937
        if (s->extra >= 0) s->shade = proj->shade;
938
 
939
        vel = proj->vel;
940
 
941
        j = -1;
942
 
943
        if (p >= 0)
5 Plagman 944
        {
4229 helixhorne 945
            // NOTE: j is a SPRITE_INDEX
946
            j = GetAutoAimAngle(i, p, atwith, 8<<8, 0+2, srcvect, vel, &zvel, &sa);
5 Plagman 947
 
3992 terminx 948
            if (j < 0)
4229 helixhorne 949
                zvel = (100-ps->horiz-ps->horizoff)*(proj->vel/8);
5 Plagman 950
 
3992 terminx 951
            if (proj->sound >= 0)
952
                A_PlaySound(proj->sound, i);
953
        }
954
        else
955
        {
956
            if (!(proj->workslike & PROJECTILE_NOAIM))
5 Plagman 957
            {
4229 helixhorne 958
                // NOTE: j is a player index
3992 terminx 959
                j = A_FindPlayer(s, NULL);
4229 helixhorne 960
                sa = getangle(g_player[j].ps->opos.x-srcvect->x, g_player[j].ps->opos.y-srcvect->y);
3361 helixhorne 961
 
3992 terminx 962
                l = safeldist(g_player[j].ps->i, s);
4658 terminx 963
                zvel = tabledivide32_noinline((g_player[j].ps->opos.z - srcvect->z)*vel, l);
5 Plagman 964
 
4377 helixhorne 965
                if (A_CheckEnemySprite(s) && (AC_MOVFLAGS(s, &actor[i]) & face_player_smart))
3992 terminx 966
                    sa = s->ang + (krand() & 31) - 16;
967
            }
968
        }
5 Plagman 969
 
3992 terminx 970
        if (numplayers > 1 && g_netClient) return -1;
1658 terminx 971
 
4229 helixhorne 972
        // l may be a SPRITE_INDEX, see above
973
        l = (p >= 0 && j >= 0) ? j : -1;
974
 
3992 terminx 975
        zvel = A_GetShootZvel(zvel);
976
        j = A_InsertSprite(sect,
4658 terminx 977
            srcvect->x + tabledivide32_noinline(sintable[(348 + sa + 512) & 2047], proj->offset),
978
            srcvect->y + tabledivide32_noinline(sintable[(sa + 348) & 2047], proj->offset),
3992 terminx 979
            srcvect->z - (1 << 8), atwith, 0, 14, 14, sa, vel, zvel, i, 4);
5 Plagman 980
 
3992 terminx 981
        sprite[j].xrepeat = proj->xrepeat;
982
        sprite[j].yrepeat = proj->yrepeat;
5 Plagman 983
 
3992 terminx 984
        if (proj->extra_rand > 0)
985
            sprite[j].extra += (krand()&proj->extra_rand);
5 Plagman 986
 
3992 terminx 987
        if (!(proj->workslike & PROJECTILE_BOUNCESOFFWALLS))
4229 helixhorne 988
            sprite[j].yvel = l;  // NOT_BOUNCESOFFWALLS_YVEL
3992 terminx 989
        else
990
        {
991
            if (proj->bounces >= 1) sprite[j].yvel = proj->bounces;
992
            else sprite[j].yvel = g_numFreezeBounces;
993
            sprite[j].zvel -= (2 << 4);
994
        }
5 Plagman 995
 
3992 terminx 996
        if (proj->cstat >= 0) sprite[j].cstat = proj->cstat;
997
        else sprite[j].cstat = 128;
5 Plagman 998
 
3992 terminx 999
        if (proj->clipdist != 255) sprite[j].clipdist = proj->clipdist;
1000
        else sprite[j].clipdist = 40;
3361 helixhorne 1001
 
3992 terminx 1002
        {
1003
            int32_t picnum = sprite[j].picnum; // why?
1004
            Bmemcpy(&SpriteProjectile[j], &ProjectileData[picnum], sizeof(projectile_t));
1005
        }
3362 helixhorne 1006
 
3992 terminx 1007
        return j;
3361 helixhorne 1008
 
3992 terminx 1009
    case PROJECTILE_KNEE:
1010
        if (p >= 0)
1011
        {
1012
            zvel = (100 - ps->horiz - ps->horizoff) << 5;
1013
            srcvect->z += (6 << 8);
1014
            sa += 15;
1015
        }
1016
        else if (!(proj->workslike & PROJECTILE_NOAIM))
1017
        {
1018
            int32_t x;
1019
            j = g_player[A_FindPlayer(s, &x)].ps->i;
4658 terminx 1020
            zvel = tabledivide32_noinline((sprite[j].z - srcvect->z) << 8, x + 1);
3992 terminx 1021
            sa = getangle(sprite[j].x - srcvect->x, sprite[j].y - srcvect->y);
1022
        }
5 Plagman 1023
 
3992 terminx 1024
        Proj_DoHitscan(i, 0, srcvect, zvel, sa, &hit);
5 Plagman 1025
 
3992 terminx 1026
        if (hit.sect < 0) return -1;
5 Plagman 1027
 
3992 terminx 1028
        if (proj->range == 0)
1029
            proj->range = 1024;
3152 helixhorne 1030
 
3992 terminx 1031
        if (proj->range > 0 && klabs(srcvect->x - hit.pos.x) + klabs(srcvect->y - hit.pos.y) > proj->range)
168 terminx 1032
            return -1;
5 Plagman 1033
 
3992 terminx 1034
        Proj_HandleKnee(&hit, i, p, atwith, sa,
1035
            proj, atwith,
1036
            proj->extra_rand,
1037
            proj->spawns, proj->sound);
5 Plagman 1038
 
3992 terminx 1039
        return -1;
1490 terminx 1040
 
3992 terminx 1041
    case PROJECTILE_BLOOD:
1042
        sa += 64 - (krand() & 127);
1043
        if (p < 0) sa += 1024;
1044
        zvel = 1024 - (krand() & 2047);
1209 terminx 1045
 
3992 terminx 1046
        Proj_DoHitscan(i, 0, srcvect, zvel, sa, &hit);
1209 terminx 1047
 
3992 terminx 1048
        if (proj->range == 0)
1049
            proj->range = 1024;
1209 terminx 1050
 
3992 terminx 1051
        if (Proj_CheckBlood(srcvect, &hit, proj->range,
4623 terminx 1052
            mulscale3(proj->yrepeat, tilesiz[proj->decal].y) << 8))
3992 terminx 1053
        {
1054
            const walltype *const hitwal = &wall[hit.wall];
1209 terminx 1055
 
3992 terminx 1056
            if (FindDistance2D(hitwal->x - wall[hitwal->point2].x, hitwal->y - wall[hitwal->point2].y) >
4623 terminx 1057
                (mulscale3(proj->xrepeat + 8, tilesiz[proj->decal].x)))
1209 terminx 1058
            {
3992 terminx 1059
                if (SectorContainsSE13(hitwal->nextsector))
1060
                    return -1;
1209 terminx 1061
 
3992 terminx 1062
                if (hitwal->nextwall >= 0 && wall[hitwal->nextwall].hitag != 0)
3360 helixhorne 1063
                    return -1;
1209 terminx 1064
 
3992 terminx 1065
                if (hitwal->hitag == 0 && proj->decal >= 0)
1066
                {
1067
                    k = A_Spawn(i, proj->decal);
1209 terminx 1068
 
4351 helixhorne 1069
                    if (!A_CheckSpriteFlags(k, SFLAG_DECAL))
1070
                        actor[k].flags |= SFLAG_DECAL;
1209 terminx 1071
 
3992 terminx 1072
                    sprite[k].xvel = -1;
1073
                    sprite[k].ang = getangle(hitwal->x - wall[hitwal->point2].x,
1074
                        hitwal->y - wall[hitwal->point2].y) + 512;
1075
                    Bmemcpy(&sprite[k], &hit.pos, sizeof(vec3_t));
1209 terminx 1076
 
3992 terminx 1077
                    Proj_DoRandDecalSize(k, atwith);
1209 terminx 1078
 
3992 terminx 1079
                    sprite[k].z += sprite[k].yrepeat << 8;
1209 terminx 1080
 
3992 terminx 1081
                    //                                sprite[k].cstat = 16+(krand()&12);
1082
                    sprite[k].cstat = 16;
1625 terminx 1083
 
3992 terminx 1084
                    if (krand() & 1)
1085
                        sprite[k].cstat |= 4;
1625 terminx 1086
 
3992 terminx 1087
                    if (krand() & 1)
1088
                        sprite[k].cstat |= 8;
1209 terminx 1089
 
3992 terminx 1090
                    sprite[k].shade = sector[sprite[k].sectnum].floorshade;
1209 terminx 1091
 
3992 terminx 1092
                    sprite[k].x -= sintable[(sprite[k].ang + 2560) & 2047] >> 13;
1093
                    sprite[k].y -= sintable[(sprite[k].ang + 2048) & 2047] >> 13;
1094
 
1095
                    A_SetSprite(k, CLIPMASK0);
1096
                    A_AddToDeleteQueue(k);
1097
                    changespritestat(k, 5);
1209 terminx 1098
                }
1099
            }
3992 terminx 1100
        }
1209 terminx 1101
 
3992 terminx 1102
        return -1;
1209 terminx 1103
 
3992 terminx 1104
    default:
1105
        return -1;
1106
    }
1107
}
1567 terminx 1108
 
3992 terminx 1109
int32_t A_ShootWithZvel(int32_t i, int32_t atwith, int32_t override_zvel)
1110
{
1111
    int16_t sa;
1112
    vec3_t srcvect;
1113
    spritetype *const s = &sprite[i];
4226 helixhorne 1114
    const int32_t p = (s->picnum == APLAYER) ? P_GetP(s) : -1;
3992 terminx 1115
    DukePlayer_t *const ps = p >= 0 ? g_player[p].ps : NULL;
1209 terminx 1116
 
3992 terminx 1117
    Bassert(atwith >= 0);
1209 terminx 1118
 
3992 terminx 1119
    if (override_zvel != SHOOT_HARDCODED_ZVEL)
1120
    {
1121
        g_overrideShootZvel = 1;
1122
        g_shootZvel = override_zvel;
1123
    }
1124
    else
1125
        g_overrideShootZvel = 0;
1126
 
1127
    if (s->picnum == APLAYER)
1128
    {
1129
        Bmemcpy(&srcvect,ps,sizeof(vec3_t));
1130
        srcvect.z += ps->pyoff+(4<<8);
1131
        sa = ps->ang;
1132
 
1133
        ps->crack_time = 777;
1134
    }
1135
    else
1136
    {
1137
        sa = s->ang;
1138
        Bmemcpy(&srcvect,s,sizeof(vec3_t));
4623 terminx 1139
        srcvect.z -= (((s->yrepeat*tilesiz[s->picnum].y)<<1)-(4<<8));
3992 terminx 1140
 
1141
        if (s->picnum != ROTATEGUN)
1142
        {
1143
            srcvect.z -= (7<<8);
1144
 
1145
            if (A_CheckEnemySprite(s) && PN != COMMANDER)
1209 terminx 1146
            {
3992 terminx 1147
                srcvect.x += (sintable[(sa+1024+96)&2047]>>7);
1148
                srcvect.y += (sintable[(sa+512+96)&2047]>>7);
1209 terminx 1149
            }
3992 terminx 1150
        }
3462 helixhorne 1151
 
3992 terminx 1152
#ifdef POLYMER
1153
        switch (DYNAMICTILEMAP(atwith))
1154
        {
1155
        case FIRELASER__STATIC:
1156
        case SHOTGUN__STATIC:
1157
        case SHOTSPARK1__STATIC:
1158
        case CHAINGUN__STATIC:
1159
        case RPG__STATIC:
1160
        case MORTER__STATIC:
3152 helixhorne 1161
            {
3992 terminx 1162
                int32_t x = ((sintable[(s->ang+512)&2047])>>7), y = ((sintable[(s->ang)&2047])>>7);
1163
                s->x += x;
1164
                s->y += y;
1165
                G_AddGameLight(0, i, PHEIGHT, 8192, 255+(95<<8), PR_LIGHT_PRIO_MAX_GAME);
1166
                actor[i].lightcount = 2;
1167
                s->x -= x;
1168
                s->y -= y;
3152 helixhorne 1169
            }
1209 terminx 1170
 
3992 terminx 1171
            break;
1209 terminx 1172
        }
3992 terminx 1173
#endif // POLYMER
1174
    }
1209 terminx 1175
 
4351 helixhorne 1176
    if (A_CheckSpriteTileFlags(atwith, SFLAG_PROJECTILE))
3992 terminx 1177
        return A_ShootCustom(i, atwith, sa, &srcvect);
1178
    else
1209 terminx 1179
    {
3992 terminx 1180
        int32_t j, k = -1, l;
1181
        int32_t vel, zvel = 0;
1182
        hitdata_t hit;
1183
        const int16_t sect = s->sectnum;
1184
 
2297 helixhorne 1185
        switch (DYNAMICTILEMAP(atwith))
1209 terminx 1186
        {
1187
        case BLOODSPLAT1__STATIC:
1188
        case BLOODSPLAT2__STATIC:
1189
        case BLOODSPLAT3__STATIC:
1190
        case BLOODSPLAT4__STATIC:
1672 terminx 1191
            sa += 64 - (krand()&127);
1192
            if (p < 0) sa += 1024;
1209 terminx 1193
            zvel = 1024-(krand()&2047);
3685 helixhorne 1194
            // fall-through
1209 terminx 1195
        case KNEE__STATIC:
1196
            if (atwith == KNEE)
1197
            {
1198
                if (p >= 0)
1199
                {
2876 helixhorne 1200
                    zvel = (100-ps->horiz-ps->horizoff)<<5;
1209 terminx 1201
                    srcvect.z += (6<<8);
1202
                    sa += 15;
1203
                }
1204
                else
1205
                {
3680 helixhorne 1206
                    int32_t x;
1209 terminx 1207
                    j = g_player[A_FindPlayer(s,&x)].ps->i;
4658 terminx 1208
                    zvel = tabledivide32_noinline((sprite[j].z-srcvect.z)<<8, x+1);
1209 terminx 1209
                    sa = getangle(sprite[j].x-srcvect.x,sprite[j].y-srcvect.y);
1210
                }
1211
            }
1212
 
3464 helixhorne 1213
            Proj_DoHitscan(i, 0, &srcvect, zvel, sa, &hit);
1209 terminx 1214
 
1220 terminx 1215
            if (atwith >= BLOODSPLAT1 && atwith <= BLOODSPLAT4)
1209 terminx 1216
            {
3362 helixhorne 1217
                if (Proj_CheckBlood(&srcvect, &hit, 1024, 16<<8))
1209 terminx 1218
                {
3362 helixhorne 1219
                    const walltype *const hitwal = &wall[hit.wall];
1209 terminx 1220
 
3362 helixhorne 1221
                    if (SectorContainsSE13(hitwal->nextsector))
1222
                        return -1;
1209 terminx 1223
 
3362 helixhorne 1224
                    if (hitwal->nextwall >= 0 && wall[hitwal->nextwall].hitag != 0)
1225
                        return -1;
1209 terminx 1226
 
3362 helixhorne 1227
                    if (hitwal->hitag == 0)
1209 terminx 1228
                    {
3362 helixhorne 1229
                        k = A_Spawn(i,atwith);
1230
                        sprite[k].xvel = -12;
1231
                        sprite[k].ang = getangle(hitwal->x-wall[hitwal->point2].x,
1232
                                                 hitwal->y-wall[hitwal->point2].y)+512;
1233
                        Bmemcpy(&sprite[k], &hit.pos, sizeof(vec3_t));
1209 terminx 1234
 
3362 helixhorne 1235
                        sprite[k].cstat |= (krand()&4);
1236
                        A_SetSprite(k,CLIPMASK0);
1237
                        setsprite(k, (vec3_t *)&sprite[k]);
1238
                        if (PN == OOZFILTER || PN == NEWBEAST)
1239
                            sprite[k].pal = 6;
1209 terminx 1240
                    }
1241
                }
1242
 
3362 helixhorne 1243
                return -1;
1209 terminx 1244
            }
3362 helixhorne 1245
 
1246
            if (hit.sect < 0) break;
1247
 
1248
            if (klabs(srcvect.x-hit.pos.x)+klabs(srcvect.y-hit.pos.y) < 1024)
1249
                Proj_HandleKnee(&hit, i, p, atwith, sa,
1250
                                NULL, KNEE, 7, SMALLSMOKE, KICK_HIT);
1209 terminx 1251
            break;
1252
 
1253
        case SHOTSPARK1__STATIC:
1254
        case SHOTGUN__STATIC:
1255
        case CHAINGUN__STATIC:
1256
            if (s->extra >= 0) s->shade = -96;
1257
 
1258
            if (p >= 0)
3453 helixhorne 1259
                P_PreFireHitscan(i, p, atwith, &srcvect, &zvel, &sa,
1260
                                 atwith == SHOTSPARK1__STATIC && !WW2GI && !NAM,
1261
                                 1);
1209 terminx 1262
            else
3358 helixhorne 1263
                A_PreFireHitscan(s, &srcvect, &zvel, &sa, 1);
1209 terminx 1264
 
3359 helixhorne 1265
            if (Proj_DoHitscan(i, 256+1, &srcvect, zvel, sa, &hit))
1266
                return -1;
1209 terminx 1267
 
3073 helixhorne 1268
            if ((krand()&15) == 0 && sector[hit.sect].lotag == ST_2_UNDERWATER)
2877 helixhorne 1269
                A_DoWaterTracers(hit.pos.x,hit.pos.y,hit.pos.z,
1209 terminx 1270
                                 srcvect.x,srcvect.y,srcvect.z,8-(ud.multimode>>1));
1271
 
1272
            if (p >= 0)
1273
            {
3359 helixhorne 1274
                k = Proj_InsertShotspark(&hit, i, atwith, 10, sa,
1275
                                         G_InitialActorStrength(atwith) + (krand()%6));
1209 terminx 1276
 
3360 helixhorne 1277
                if (P_PostFireHitscan(p, k, &hit, i, atwith, zvel,
1278
                                      -SMALLSMOKE, BULLETHOLE, SHOTSPARK1, 0) < 0)
1279
                    return -1;
1209 terminx 1280
            }
1281
            else
1282
            {
3360 helixhorne 1283
                k = A_PostFireHitscan(&hit, i, atwith, sa, G_InitialActorStrength(atwith),
1284
                                      -SMALLSMOKE, SHOTSPARK1);
1209 terminx 1285
            }
1286
 
1287
            if ((krand()&255) < 4)
3360 helixhorne 1288
                S_PlaySound3D(PISTOL_RICOCHET, k, &hit.pos);
1209 terminx 1289
 
1290
            return -1;
1291
 
3989 terminx 1292
        case GROWSPARK__STATIC:
1293
            if (p >= 0)
1294
                P_PreFireHitscan(i, p, atwith, &srcvect, &zvel, &sa, 1, 1);
1295
            else
1296
                A_PreFireHitscan(s, &srcvect, &zvel, &sa, 1);
1297
 
1298
            if (Proj_DoHitscan(i, 256 + 1, &srcvect, zvel, sa, &hit))
1299
                return -1;
1300
 
1301
            j = A_InsertSprite(hit.sect,hit.pos.x,hit.pos.y,hit.pos.z,GROWSPARK,-16,28,28,sa,0,0,i,1);
1302
 
1303
            sprite[j].pal = 2;
1304
            sprite[j].cstat |= 130;
1305
            sprite[j].xrepeat = sprite[j].yrepeat = 1;
1306
 
1307
            if (hit.wall == -1 && hit.sprite == -1 && hit.sect >= 0)
1308
            {
4204 helixhorne 1309
                Proj_MaybeDamageCF2(zvel, hit.sect);
3989 terminx 1310
            }
1311
            else if (hit.sprite >= 0) A_DamageObject(hit.sprite,j);
1312
            else if (hit.wall >= 0 && wall[hit.wall].picnum != ACCESSSWITCH && wall[hit.wall].picnum != ACCESSSWITCH2)
1313
                A_DamageWall(j,hit.wall,&hit.pos,atwith);
1314
 
1315
            break;
1316
 
1209 terminx 1317
        case FIRELASER__STATIC:
1318
        case SPIT__STATIC:
1319
        case COOLEXPLOSION1__STATIC:
3464 helixhorne 1320
        {
1321
            int32_t tsiz;
1209 terminx 1322
 
1323
            if (s->extra >= 0) s->shade = -96;
1324
 
3992 terminx 1325
            switch (atwith)
1209 terminx 1326
            {
3992 terminx 1327
            case SPIT__STATIC:
1328
                vel = 292;
1329
                break;
1330
            case COOLEXPLOSION1__STATIC:
1331
                if (s->picnum == BOSS2) vel = 644;
1332
                else vel = 348;
1333
                srcvect.z -= (4<<7);
1334
                break;
1335
            case FIRELASER__STATIC:
1336
            default:
1337
                vel = 840;
1338
                srcvect.z -= (4<<7);
1339
                break;
1209 terminx 1340
            }
1341
 
1342
            if (p >= 0)
1343
            {
2983 helixhorne 1344
                j = GetAutoAimAngle(i, p, atwith, -(12<<8), 0, &srcvect, vel, &zvel, &sa);
1209 terminx 1345
 
2983 helixhorne 1346
                if (j < 0)
2876 helixhorne 1347
                    zvel = (100-ps->horiz-ps->horizoff)*98;
1209 terminx 1348
            }
1349
            else
1350
            {
3680 helixhorne 1351
                j = A_FindPlayer(s, NULL);
1625 terminx 1352
                //                sa = getangle(g_player[j].ps->opos.x-sx,g_player[j].ps->opos.y-sy);
1209 terminx 1353
                sa += 16-(krand()&31);
3462 helixhorne 1354
                hit.pos.x = safeldist(g_player[j].ps->i, s);
4658 terminx 1355
                zvel = tabledivide32_noinline((g_player[j].ps->opos.z - srcvect.z + (3<<8))*vel, hit.pos.x);
1209 terminx 1356
            }
1357
 
3921 helixhorne 1358
            zvel = A_GetShootZvel(zvel);
3465 helixhorne 1359
 
1209 terminx 1360
            if (atwith == SPIT)
1361
            {
3464 helixhorne 1362
                tsiz = 18;
1672 terminx 1363
                srcvect.z -= (10<<8);
1209 terminx 1364
            }
1672 terminx 1365
            else if (p >= 0)
3464 helixhorne 1366
                tsiz = 7;
1209 terminx 1367
            else
1368
            {
1369
                if (atwith == FIRELASER)
1370
                {
1371
                    if (p >= 0)
3464 helixhorne 1372
                        tsiz = 34;
1209 terminx 1373
                    else
3464 helixhorne 1374
                        tsiz = 18;
1209 terminx 1375
                }
1376
                else
3464 helixhorne 1377
                    tsiz = 18;
1209 terminx 1378
            }
1379
 
1672 terminx 1380
            j = A_InsertSprite(sect,srcvect.x,srcvect.y,srcvect.z,
3464 helixhorne 1381
                               atwith,-127,tsiz,tsiz,sa,vel,zvel,i,4);
1672 terminx 1382
            sprite[j].extra += (krand()&7);
1209 terminx 1383
 
1672 terminx 1384
            if (atwith == COOLEXPLOSION1)
1209 terminx 1385
            {
1672 terminx 1386
                sprite[j].shade = 0;
1387
                if (PN == BOSS2)
1209 terminx 1388
                {
1672 terminx 1389
                    l = sprite[j].xvel;
3544 hendricks2 1390
                    sprite[j].xvel = MinibossScale(1024);
1672 terminx 1391
                    A_SetSprite(j,CLIPMASK0);
1392
                    sprite[j].xvel = l;
1393
                    sprite[j].ang += 128-(krand()&255);
1209 terminx 1394
                }
1672 terminx 1395
            }
1209 terminx 1396
 
1672 terminx 1397
            sprite[j].cstat = 128;
1398
            sprite[j].clipdist = 4;
1209 terminx 1399
 
1672 terminx 1400
            sa = s->ang+32-(krand()&63);
3680 helixhorne 1401
            zvel += 512-(krand()&1023);
1209 terminx 1402
 
1403
            return j;
3464 helixhorne 1404
        }
1209 terminx 1405
 
1406
        case FREEZEBLAST__STATIC:
1407
            srcvect.z += (3<<8);
1408
        case RPG__STATIC:
3680 helixhorne 1409
            // XXX: "CODEDUP"
1209 terminx 1410
            if (s->extra >= 0) s->shade = -96;
1411
 
1412
            vel = 644;
1413
 
1414
            j = -1;
1415
 
1416
            if (p >= 0)
1417
            {
4229 helixhorne 1418
                // NOTE: j is a SPRITE_INDEX
2983 helixhorne 1419
                j = GetAutoAimAngle(i, p, atwith, 8<<8, 0+2, &srcvect, vel, &zvel, &sa);
1209 terminx 1420
 
2983 helixhorne 1421
                if (j < 0)
1422
                    zvel = (100-ps->horiz-ps->horizoff)*81;
1423
 
1209 terminx 1424
                if (atwith == RPG)
1425
                    A_PlaySound(RPG_SHOOT,i);
1426
            }
1427
            else
1428
            {
4229 helixhorne 1429
                // NOTE: j is a player index
3680 helixhorne 1430
                j = A_FindPlayer(s, NULL);
4229 helixhorne 1431
                sa = getangle(g_player[j].ps->opos.x-srcvect.x, g_player[j].ps->opos.y-srcvect.y);
1209 terminx 1432
                if (PN == BOSS3)
3544 hendricks2 1433
                    srcvect.z -= MinibossScale(32<<8);
1209 terminx 1434
                else if (PN == BOSS2)
1435
                {
1436
                    vel += 128;
3544 hendricks2 1437
                    srcvect.z += MinibossScale(24<<8);
1209 terminx 1438
                }
1439
 
3462 helixhorne 1440
                l = safeldist(g_player[j].ps->i, s);
4658 terminx 1441
                zvel = tabledivide32_noinline((g_player[j].ps->opos.z - srcvect.z)*vel, l);
1209 terminx 1442
 
4377 helixhorne 1443
                if (A_CheckEnemySprite(s) && (AC_MOVFLAGS(s, &actor[i]) & face_player_smart))
1209 terminx 1444
                    sa = s->ang+(krand()&31)-16;
1445
            }
1446
 
4229 helixhorne 1447
            if (numplayers > 1 && g_netClient)
1448
                return -1;
1567 terminx 1449
 
4229 helixhorne 1450
            // l may be a SPRITE_INDEX, see above
1451
            l = (p >= 0 && j >= 0) ? j : -1;
1567 terminx 1452
 
3921 helixhorne 1453
            zvel = A_GetShootZvel(zvel);
1209 terminx 1454
            j = A_InsertSprite(sect,
1455
                               srcvect.x+(sintable[(348+sa+512)&2047]/448),
1456
                               srcvect.y+(sintable[(sa+348)&2047]/448),
1457
                               srcvect.z-(1<<8),atwith,0,14,14,sa,vel,zvel,i,4);
1458
 
1459
            sprite[j].extra += (krand()&7);
1460
            if (atwith != FREEZEBLAST)
4229 helixhorne 1461
                sprite[j].yvel = l;  // RPG_YVEL
1209 terminx 1462
            else
1463
            {
1464
                sprite[j].yvel = g_numFreezeBounces;
1465
                sprite[j].xrepeat >>= 1;
1466
                sprite[j].yrepeat >>= 1;
1467
                sprite[j].zvel -= (2<<4);
1468
            }
1469
 
1470
            if (p == -1)
1471
            {
1472
                if (PN == BOSS3)
1473
                {
1474
                    if (krand()&1)
1475
                    {
3544 hendricks2 1476
                        sprite[j].x -= MinibossScale(sintable[sa&2047]>>6);
1477
                        sprite[j].y -= MinibossScale(sintable[(sa+1024+512)&2047]>>6);
1478
                        sprite[j].ang -= MinibossScale(8);
1209 terminx 1479
                    }
1480
                    else
1481
                    {
3544 hendricks2 1482
                        sprite[j].x += MinibossScale(sintable[sa&2047]>>6);
1483
                        sprite[j].y += MinibossScale(sintable[(sa+1024+512)&2047]>>6);
1484
                        sprite[j].ang += MinibossScale(4);
1209 terminx 1485
                    }
3544 hendricks2 1486
                    sprite[j].xrepeat = MinibossScale(42);
1487
                    sprite[j].yrepeat = MinibossScale(42);
1209 terminx 1488
                }
1489
                else if (PN == BOSS2)
1490
                {
3544 hendricks2 1491
                    sprite[j].x -= MinibossScale(sintable[sa&2047]/56);
1492
                    sprite[j].y -= MinibossScale(sintable[(sa+1024+512)&2047]/56);
1493
                    sprite[j].ang -= MinibossScale(8)+(krand()&255)-128;
1209 terminx 1494
                    sprite[j].xrepeat = 24;
1495
                    sprite[j].yrepeat = 24;
1496
                }
1497
                else if (atwith != FREEZEBLAST)
1498
                {
1499
                    sprite[j].xrepeat = 30;
1500
                    sprite[j].yrepeat = 30;
1501
                    sprite[j].extra >>= 2;
1502
                }
1503
            }
4654 terminx 1504
            else if (PWEAPON(p, g_player[p].ps->curr_weapon, WorksLike) == DEVISTATOR_WEAPON)
1209 terminx 1505
            {
1506
                sprite[j].extra >>= 2;
1507
                sprite[j].ang += 16-(krand()&31);
1508
                sprite[j].zvel += 256-(krand()&511);
1509
 
1510
                if (g_player[p].ps->hbomb_hold_delay)
1511
                {
1512
                    sprite[j].x -= sintable[sa&2047]/644;
1513
                    sprite[j].y -= sintable[(sa+1024+512)&2047]/644;
1514
                }
1515
                else
1516
                {
1517
                    sprite[j].x += sintable[sa&2047]>>8;
1518
                    sprite[j].y += sintable[(sa+1024+512)&2047]>>8;
1519
                }
1520
                sprite[j].xrepeat >>= 1;
1521
                sprite[j].yrepeat >>= 1;
1522
            }
1523
 
1524
            sprite[j].cstat = 128;
1525
            if (atwith == RPG)
1526
                sprite[j].clipdist = 4;
1527
            else
1528
                sprite[j].clipdist = 40;
1529
 
1530
            return j;
1531
 
1532
        case HANDHOLDINGLASER__STATIC:
2977 helixhorne 1533
        {
1534
            const int32_t zoff = (p>=0) ? g_player[p].ps->pyoff : 0;
1209 terminx 1535
            if (p >= 0)
2876 helixhorne 1536
                zvel = (100-ps->horiz-ps->horizoff)*32;
1209 terminx 1537
            else zvel = 0;
1538
 
2977 helixhorne 1539
            srcvect.z -= zoff;
3464 helixhorne 1540
            Proj_DoHitscan(i, 0, &srcvect, zvel, sa, &hit);
2977 helixhorne 1541
            srcvect.z += zoff;
1209 terminx 1542
 
1543
            j = 0;
2877 helixhorne 1544
            if (hit.sprite >= 0) break;
1209 terminx 1545
 
2877 helixhorne 1546
            if (hit.wall >= 0 && hit.sect >= 0)
1547
                if (((hit.pos.x-srcvect.x)*(hit.pos.x-srcvect.x)+(hit.pos.y-srcvect.y)*(hit.pos.y-srcvect.y)) < (290*290))
1209 terminx 1548
                {
3073 helixhorne 1549
                    // ST_2_UNDERWATER
2877 helixhorne 1550
                    if (wall[hit.wall].nextsector >= 0)
1209 terminx 1551
                    {
2877 helixhorne 1552
                        if (sector[wall[hit.wall].nextsector].lotag <= 2 && sector[hit.sect].lotag <= 2)
1209 terminx 1553
                            j = 1;
1554
                    }
2877 helixhorne 1555
                    else if (sector[hit.sect].lotag <= 2)
1209 terminx 1556
                        j = 1;
1557
                }
1558
 
1559
            if (j == 1)
1560
            {
2977 helixhorne 1561
                int32_t lTripBombControl = (p < 0) ? 0 :
3414 helixhorne 1562
#ifdef LUNATIC
1563
                    g_player[p].ps->tripbombControl;
1564
#else
2977 helixhorne 1565
                    Gv_GetVarByLabel("TRIPBOMB_CONTROL", TRIPBOMB_TRIPWIRE, g_player[p].ps->i, p);
3414 helixhorne 1566
#endif
2877 helixhorne 1567
                k = A_InsertSprite(hit.sect,hit.pos.x,hit.pos.y,hit.pos.z,TRIPBOMB,-16,4,5,sa,0,0,i,6);
1209 terminx 1568
                if (lTripBombControl & TRIPBOMB_TIMER)
1569
                {
3414 helixhorne 1570
#ifdef LUNATIC
1571
                    int32_t lLifetime = g_player[p].ps->tripbombLifetime;
1572
                    int32_t lLifetimeVar = g_player[p].ps->tripbombLifetimeVar;
1573
#else
1209 terminx 1574
                    int32_t lLifetime=Gv_GetVarByLabel("STICKYBOMB_LIFETIME", NAM_GRENADE_LIFETIME, g_player[p].ps->i, p);
1575
                    int32_t lLifetimeVar=Gv_GetVarByLabel("STICKYBOMB_LIFETIME_VAR", NAM_GRENADE_LIFETIME_VAR, g_player[p].ps->i, p);
3414 helixhorne 1576
#endif
1209 terminx 1577
                    // set timer.  blows up when at zero....
1625 terminx 1578
                    actor[k].t_data[7]=lLifetime
1677 terminx 1579
                                       + mulscale(krand(),lLifetimeVar, 14)
1580
                                       - lLifetimeVar;
4256 helixhorne 1581
                    // TIMER_CONTROL
1625 terminx 1582
                    actor[k].t_data[6]=1;
1209 terminx 1583
                }
1584
                else
2977 helixhorne 1585
                    sprite[k].hitag = k;
1209 terminx 1586
 
1587
                A_PlaySound(LASERTRIP_ONWALL,k);
1588
                sprite[k].xvel = -20;
1589
                A_SetSprite(k,CLIPMASK0);
1590
                sprite[k].cstat = 16;
1591
 
2977 helixhorne 1592
                {
1593
                    int32_t p2 = wall[hit.wall].point2;
1594
                    int32_t a = getangle(wall[hit.wall].x-wall[p2].x, wall[hit.wall].y-wall[p2].y)-512;
1595
                    actor[k].t_data[5] = sprite[k].ang = a;
1596
                }
1209 terminx 1597
            }
1598
            return j?k:-1;
2977 helixhorne 1599
        }
3680 helixhorne 1600
 
1209 terminx 1601
        case BOUNCEMINE__STATIC:
1602
        case MORTER__STATIC:
3680 helixhorne 1603
        {
1604
            int32_t x;
1209 terminx 1605
 
1606
            if (s->extra >= 0) s->shade = -96;
1607
 
3680 helixhorne 1608
            j = g_player[A_FindPlayer(s, NULL)].ps->i;
1209 terminx 1609
            x = ldist(&sprite[j],s);
1610
 
1611
            zvel = -x>>1;
1612
 
1613
            if (zvel < -4096)
1614
                zvel = -2048;
1615
            vel = x>>4;
3465 helixhorne 1616
 
3921 helixhorne 1617
            zvel = A_GetShootZvel(zvel);
1209 terminx 1618
            A_InsertSprite(sect,
1619
                           srcvect.x+(sintable[(512+sa+512)&2047]>>8),
1620
                           srcvect.y+(sintable[(sa+512)&2047]>>8),
1621
                           srcvect.z+(6<<8),atwith,-64,32,32,sa,vel,zvel,i,1);
1622
            break;
3680 helixhorne 1623
        }
1209 terminx 1624
 
1625
        case SHRINKER__STATIC:
1626
            if (s->extra >= 0) s->shade = -96;
1627
            if (p >= 0)
1628
            {
2983 helixhorne 1629
                j = GetAutoAimAngle(i, p, atwith, 4<<8, 0, &srcvect, 768, &zvel, &sa);
1209 terminx 1630
 
2983 helixhorne 1631
                if (j < 0)
1632
                    zvel = (100-ps->horiz-ps->horizoff)*98;
1209 terminx 1633
            }
3073 helixhorne 1634
            else if (s->statnum != STAT_EFFECTOR)
1209 terminx 1635
            {
3680 helixhorne 1636
                j = A_FindPlayer(s, NULL);
3462 helixhorne 1637
                l = safeldist(g_player[j].ps->i, s);
4658 terminx 1638
                zvel = tabledivide32_noinline((g_player[j].ps->opos.z-srcvect.z)*512, l);
1209 terminx 1639
            }
1640
            else zvel = 0;
3465 helixhorne 1641
 
3921 helixhorne 1642
            zvel = A_GetShootZvel(zvel);
1209 terminx 1643
            j = A_InsertSprite(sect,
1644
                               srcvect.x+(sintable[(512+sa+512)&2047]>>12),
1645
                               srcvect.y+(sintable[(sa+512)&2047]>>12),
1646
                               srcvect.z+(2<<8),SHRINKSPARK,-16,28,28,sa,768,zvel,i,4);
1647
 
1648
            sprite[j].cstat = 128;
1649
            sprite[j].clipdist = 32;
1650
 
1651
            return j;
1652
        }
1653
    }
3465 helixhorne 1654
 
1209 terminx 1655
    return -1;
1656
}
1657
 
2917 helixhorne 1658
 
1659
//////////////////// HUD WEAPON / MISC. DISPLAY CODE ////////////////////
1660
 
1611 terminx 1661
static void P_DisplaySpit(int32_t snum)
1209 terminx 1662
{
2876 helixhorne 1663
    DukePlayer_t *const ps = g_player[snum].ps;
4734 helixhorne 1664
    const int32_t loogcnt = ps->loogcnt;
1665
    const int32_t y = loogcnt<<2;
1209 terminx 1666
 
4734 helixhorne 1667
    if (loogcnt == 0)
2639 helixhorne 1668
        return;
1209 terminx 1669
 
4734 helixhorne 1670
    for (int32_t i=0; i < ps->numloogs; i++)
1209 terminx 1671
    {
4734 helixhorne 1672
        int32_t a = klabs(sintable[((loogcnt+i)<<5)&2047])>>5;
1673
        int32_t z = 4096 + ((loogcnt+i)<<9);
1674
        int32_t x = (-g_player[snum].sync->avel>>1) + (sintable[((loogcnt+i)<<6)&2047]>>10);
1209 terminx 1675
 
2308 helixhorne 1676
        rotatesprite_fs(
4734 helixhorne 1677
            (ps->loogiex[i]+x)<<16, (200+ps->loogiey[i]-y)<<16,
1678
            z-(i<<8), 256-a,
2308 helixhorne 1679
            LOOGIE,0,0,2);
1209 terminx 1680
    }
1681
}
1682
 
3353 helixhorne 1683
static int32_t P_GetHudPal(const DukePlayer_t *p)
2518 helixhorne 1684
{
1685
    if (sprite[p->i].pal == 1)
1686
        return 1;
1687
 
1688
    if (p->cursectnum >= 0)
1689
    {
1690
        int32_t dapal = sector[p->cursectnum].floorpal;
1691
        if (!g_noFloorPal[dapal])
1692
            return dapal;
1693
    }
1694
 
1695
    return 0;
1696
}
1697
 
1611 terminx 1698
static int32_t P_DisplayFist(int32_t gs,int32_t snum)
1209 terminx 1699
{
1700
    int32_t looking_arc,fisti,fistpal;
1701
    int32_t fistzoom, fistz;
1702
 
2932 helixhorne 1703
    int32_t wx[2] = { windowx1, windowx2 };
1704
 
2917 helixhorne 1705
    const DukePlayer_t *const ps = g_player[snum].ps;
1706
 
1707
    fisti = ps->fist_incs;
1209 terminx 1708
    if (fisti > 32) fisti = 32;
1709
    if (fisti <= 0) return 0;
1710
 
2917 helixhorne 1711
    looking_arc = klabs(ps->look_ang)/9;
1209 terminx 1712
 
2639 helixhorne 1713
    fistzoom = 65536 - (sintable[(512+(fisti<<6))&2047]<<2);
1714
    fistzoom = clamp(fistzoom, 40920, 90612);
1715
 
1209 terminx 1716
    fistz = 194 + (sintable[((6+fisti)<<7)&2047]>>9);
1717
 
3353 helixhorne 1718
    fistpal = P_GetHudPal(ps);
1209 terminx 1719
 
4249 hendricks2 1720
#ifdef SPLITSCREEN_MOD_HACKS
2945 helixhorne 1721
    // XXX: this is outdated, doesn't handle above/below split.
2957 helixhorne 1722
    if (g_fakeMultiMode==2)
2932 helixhorne 1723
        wx[(g_snum==0)] = (wx[0]+wx[1])/2+1;
4249 hendricks2 1724
#endif
2932 helixhorne 1725
 
1726
    rotatesprite(
4703 terminx 1727
        (-fisti+222+(g_player[snum].sync->avel>>5))<<16,
1209 terminx 1728
        (looking_arc+fistz)<<16,
2932 helixhorne 1729
        fistzoom,0,FIST,gs,fistpal,2,
1730
        wx[0],windowy1,wx[1],windowy2);
1209 terminx 1731
 
1732
    return 1;
1733
}
1734
 
2917 helixhorne 1735
#define DRAWEAP_CENTER 262144
3992 terminx 1736
#define weapsc(sc) scale(sc, ud.weaponscale, 100)
2917 helixhorne 1737
 
3695 helixhorne 1738
static int32_t g_dts_yadd;
1739
 
1209 terminx 1740
static void G_DrawTileScaled(int32_t x, int32_t y, int32_t tilenum, int32_t shade, int32_t orientation, int32_t p)
1741
{
2931 helixhorne 1742
    int32_t ang = 0;
1209 terminx 1743
    int32_t xoff = 192;
1744
 
2931 helixhorne 1745
    int32_t wx[2] = { windowx1, windowx2 };
2944 helixhorne 1746
    int32_t wy[2] = { windowy1, windowy2 };
1747
    int32_t yofs = 0;
2905 helixhorne 1748
 
3408 helixhorne 1749
    switch (hudweap.cur)
1209 terminx 1750
    {
1751
    case DEVISTATOR_WEAPON:
1752
    case TRIPBOMB_WEAPON:
1753
        xoff = 160;
1754
        break;
1755
    default:
2917 helixhorne 1756
        if (orientation & DRAWEAP_CENTER)
1209 terminx 1757
        {
1758
            xoff = 160;
2917 helixhorne 1759
            orientation &= ~DRAWEAP_CENTER;
1209 terminx 1760
        }
1761
        break;
1762
    }
1763
 
3353 helixhorne 1764
    // bit 4 means "flip x" for G_DrawTileScaled
1209 terminx 1765
    if (orientation&4)
2931 helixhorne 1766
        ang = 1024;
1209 terminx 1767
 
4249 hendricks2 1768
#ifdef SPLITSCREEN_MOD_HACKS
2957 helixhorne 1769
    if (g_fakeMultiMode==2)
2905 helixhorne 1770
    {
2944 helixhorne 1771
        const int32_t sidebyside = (ud.screen_size!=0);
1772
 
2905 helixhorne 1773
        // splitscreen HACK
2944 helixhorne 1774
        orientation &= ~(1024|512|256);
1775
        if (sidebyside)
1776
        {
1777
            orientation &= ~8;
1778
            wx[(g_snum==0)] = (wx[0]+wx[1])/2 + 2;
1779
        }
1780
        else
1781
        {
1782
            orientation |= 8;
1783
            if (g_snum==0)
1784
                yofs = -(100<<16);
1785
            wy[(g_snum==0)] = (wy[0]+wy[1])/2 + 2;
1786
        }
2905 helixhorne 1787
    }
4249 hendricks2 1788
#endif
2905 helixhorne 1789
 
1820 terminx 1790
#ifdef USE_OPENGL
3346 terminx 1791
    if (getrendermode() >= REND_POLYMOST && usemodels && md_tilehasmodel(tilenum,p) >= 0)
1209 terminx 1792
        y += (224-weapsc(224));
1793
#endif
2931 helixhorne 1794
    rotatesprite(weapsc(x<<16) + ((xoff-weapsc(xoff))<<16),
3695 helixhorne 1795
                 weapsc((y<<16) + g_dts_yadd) + ((200-weapsc(200))<<16) + yofs,
2931 helixhorne 1796
                 weapsc(65536L),ang,tilenum,shade,p,(2|orientation),
2944 helixhorne 1797
                 wx[0],wy[0], wx[1],wy[1]);
1209 terminx 1798
}
1799
 
4703 terminx 1800
static void G_DrawWeaponTile(int32_t x, int32_t y, int32_t tilenum, int32_t shade, int32_t orientation, int32_t p,
1801
                             uint8_t slot)
1209 terminx 1802
{
4703 terminx 1803
    static int32_t shadef[2] = { 0, 0 }, palf[2] = { 0, 0 };
1657 terminx 1804
 
1946 hendricks2 1805
    // sanity checking the slot value
1806
    if (slot > 1)
1807
        slot = 1;
1808
 
1657 terminx 1809
    // basic fading between player weapon shades
1946 hendricks2 1810
    if (shadef[slot] != shade && (!p || palf[slot] == p))
1657 terminx 1811
    {
4703 terminx 1812
        shadef[slot] += (shade - shadef[slot]) >> 2;
1657 terminx 1813
 
4703 terminx 1814
        if (!((shade - shadef[slot]) >> 2))
4392 helixhorne 1815
            shadef[slot] = logapproach(shadef[slot], shade);
1657 terminx 1816
    }
1817
    else
1946 hendricks2 1818
        shadef[slot] = shade;
1657 terminx 1819
 
1946 hendricks2 1820
    palf[slot] = p;
1657 terminx 1821
 
1625 terminx 1822
    switch (ud.drawweapon)
1823
    {
4703 terminx 1824
        case 1:
3695 helixhorne 1825
#ifdef USE_OPENGL
4703 terminx 1826
            if (getrendermode() >= REND_POLYMOST)
1827
                if (tilenum >= CHAINGUN + 1 && tilenum <= CHAINGUN + 4)
1828
                    if (!usemodels || md_tilehasmodel(tilenum, p) < 0)
1829
                    {
1830
                        // HACK: Draw the upper part of the chaingun two screen
1831
                        // pixels (not texels; multiplied by weapon scale) lower
1832
                        // first, preventing ugly horizontal seam.
1833
                        g_dts_yadd = tabledivide32_noinline(65536 * 2 * 200, ydim);
1834
                        G_DrawTileScaled(x, y, tilenum, shadef[slot], orientation, p);
1835
                        g_dts_yadd = 0;
1836
                    }
3695 helixhorne 1837
#endif
4703 terminx 1838
            G_DrawTileScaled(x, y, tilenum, shadef[slot], orientation, p);
1839
            return;
3695 helixhorne 1840
 
4703 terminx 1841
        case 2:
1842
        {
1843
            const DukePlayer_t *const ps = g_player[screenpeek].ps;
1844
            const int32_t sc = scale(65536, ud.statusbarscale, 100);
2945 helixhorne 1845
 
4703 terminx 1846
            if ((unsigned)hudweap.cur < MAX_WEAPONS && hudweap.cur != KNEE_WEAPON)
1847
                rotatesprite_win(160 << 16, (180 + (ps->weapon_pos * ps->weapon_pos)) << 16, sc, 0,
1848
                                 hudweap.cur == GROW_WEAPON ? GROWSPRITEICON : WeaponPickupSprites[hudweap.cur], 0,
1849
                                 0, 2);
1850
            return;
1851
        }
1209 terminx 1852
    }
1853
}
1854
 
4703 terminx 1855
static inline void G_DrawWeaponTileWithID(int32_t id, int32_t x, int32_t y, int32_t tilenum, int32_t shade,
1856
                                          int32_t orientation, int32_t p, uint8_t slot)
1857
{
1858
    int oldid = guniqhudid;
1859
 
1860
    guniqhudid = id;
1861
    G_DrawWeaponTile(x, y, tilenum, shade, orientation, p, slot);
1862
    guniqhudid = oldid;
1863
}
1864
 
1611 terminx 1865
static int32_t P_DisplayKnee(int32_t gs,int32_t snum)
1209 terminx 1866
{
2917 helixhorne 1867
    static const int8_t knee_y[] = {0,-8,-16,-32,-64,-84,-108,-108,-108,-72,-32,-8};
2518 helixhorne 1868
    int32_t looking_arc, pal;
1209 terminx 1869
 
2917 helixhorne 1870
    const DukePlayer_t *const ps = g_player[snum].ps;
1209 terminx 1871
 
3436 helixhorne 1872
    if (ps->knee_incs == 0 || ps->knee_incs >= ARRAY_SIZE(knee_y) || sprite[ps->i].extra <= 0)
1873
        return 0;
1209 terminx 1874
 
2917 helixhorne 1875
    looking_arc = knee_y[ps->knee_incs] + klabs(ps->look_ang)/9;
1209 terminx 1876
 
2917 helixhorne 1877
    looking_arc -= (ps->hard_landing<<3);
1878
 
3353 helixhorne 1879
    pal = P_GetHudPal(ps);
2518 helixhorne 1880
    if (pal == 0)
2917 helixhorne 1881
        pal = ps->palookup;
1209 terminx 1882
 
4703 terminx 1883
    G_DrawTileScaled(105+(g_player[snum].sync->avel>>5)-(ps->look_ang>>1)+(knee_y[ps->knee_incs]>>2),
2917 helixhorne 1884
                     looking_arc+280-((ps->horiz-ps->horizoff)>>4),KNEE,gs,4+DRAWEAP_CENTER,pal);
1209 terminx 1885
 
1886
    return 1;
1887
}
1888
 
1611 terminx 1889
static int32_t P_DisplayKnuckles(int32_t gs,int32_t snum)
1209 terminx 1890
{
2917 helixhorne 1891
    static const int8_t knuckle_frames[] = {0,1,2,2,3,3,3,2,2,1,0};
2518 helixhorne 1892
    int32_t looking_arc, pal;
1209 terminx 1893
 
2917 helixhorne 1894
    const DukePlayer_t *const ps = g_player[snum].ps;
1209 terminx 1895
 
3673 hendricks2 1896
    if (ps->knuckle_incs == 0 || (unsigned) (ps->knuckle_incs>>1) >= ARRAY_SIZE(knuckle_frames) || sprite[ps->i].extra <= 0)
3436 helixhorne 1897
        return 0;
1209 terminx 1898
 
2917 helixhorne 1899
    looking_arc = klabs(ps->look_ang)/9;
1209 terminx 1900
 
2917 helixhorne 1901
    looking_arc -= (ps->hard_landing<<3);
1209 terminx 1902
 
3353 helixhorne 1903
    pal = P_GetHudPal(ps);
1209 terminx 1904
 
4703 terminx 1905
    G_DrawTileScaled(160+(g_player[snum].sync->avel>>5)-(ps->look_ang>>1),
2917 helixhorne 1906
                     looking_arc+180-((ps->horiz-ps->horizoff)>>4),
1907
                     CRACKKNUCKLES+knuckle_frames[ps->knuckle_incs>>1],gs,4+DRAWEAP_CENTER,pal);
1908
 
1209 terminx 1909
    return 1;
1910
}
1911
 
3955 helixhorne 1912
#if !defined LUNATIC
1913
// Set C-CON's WEAPON and WORKSLIKE gamevars.
3413 helixhorne 1914
void P_SetWeaponGamevars(int32_t snum, const DukePlayer_t *p)
1915
{
1916
    Gv_SetVar(g_iWeaponVarID, p->curr_weapon, p->i, snum);
1917
    Gv_SetVar(g_iWorksLikeVarID,
1918
              ((unsigned)p->curr_weapon < MAX_WEAPONS) ? PWEAPON(snum, p->curr_weapon, WorksLike) : -1,
1919
              p->i, snum);
3955 helixhorne 1920
}
3413 helixhorne 1921
#endif
1922
 
4227 helixhorne 1923
static void P_FireWeapon(int32_t snum)
1209 terminx 1924
{
4227 helixhorne 1925
    int32_t i;
1926
    DukePlayer_t *const p = g_player[snum].ps;
1209 terminx 1927
 
4745 terminx 1928
    if (VM_OnEvent(EVENT_DOFIRE, p->i, snum) || p->weapon_pos != 0)
4703 terminx 1929
        return;
1209 terminx 1930
 
4703 terminx 1931
    if (PWEAPON(snum, p->curr_weapon, WorksLike) != KNEE_WEAPON)
1932
        p->ammo_amount[p->curr_weapon]--;
1209 terminx 1933
 
4703 terminx 1934
    if (PWEAPON(snum, p->curr_weapon, FireSound) > 0)
1935
        A_PlaySound(PWEAPON(snum, p->curr_weapon, FireSound), p->i);
1209 terminx 1936
 
4703 terminx 1937
    P_SetWeaponGamevars(snum, p);
1938
    //        OSD_Printf("doing %d %d %d\n",PWEAPON(snum, p->curr_weapon, Shoots),p->curr_weapon,snum);
1939
    A_Shoot(p->i, PWEAPON(snum, p->curr_weapon, Shoots));
1611 terminx 1940
 
4703 terminx 1941
    for (i = PWEAPON(snum, p->curr_weapon, ShotsPerBurst) - 1; i > 0; i--)
1942
    {
1943
        if (PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_FIREEVERYOTHER)
1209 terminx 1944
        {
4703 terminx 1945
            // this makes the projectiles fire on a delay from player code
1946
            actor[p->i].t_data[7] = (PWEAPON(snum, p->curr_weapon, ShotsPerBurst)) << 1;
1947
        }
1948
        else
1949
        {
1950
            if (PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_AMMOPERSHOT &&
1951
                PWEAPON(snum, p->curr_weapon, WorksLike) != KNEE_WEAPON)
1209 terminx 1952
            {
4703 terminx 1953
                if (p->ammo_amount[p->curr_weapon] > 0)
1954
                    p->ammo_amount[p->curr_weapon]--;
1955
                else
1956
                    break;
1209 terminx 1957
            }
3955 helixhorne 1958
 
4703 terminx 1959
            A_Shoot(p->i, PWEAPON(snum, p->curr_weapon, Shoots));
1209 terminx 1960
        }
4703 terminx 1961
    }
1209 terminx 1962
 
4703 terminx 1963
    if (!(PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_NOVISIBLE))
1964
    {
1336 terminx 1965
#ifdef POLYMER
4703 terminx 1966
        spritetype *s = &sprite[p->i];
1967
        int32_t x = ((sintable[(s->ang + 512) & 2047]) >> 7), y = ((sintable[(s->ang) & 2047]) >> 7);
1312 terminx 1968
 
4703 terminx 1969
        s->x += x;
1970
        s->y += y;
1971
        G_AddGameLight(0, p->i, PHEIGHT, 8192, PWEAPON(snum, p->curr_weapon, FlashColor), PR_LIGHT_PRIO_MAX_GAME);
1972
        actor[p->i].lightcount = 2;
1973
        s->x -= x;
1974
        s->y -= y;
1975
#endif  // POLYMER
1976
        p->visibility = 0;
1209 terminx 1977
    }
1978
}
1979
 
4227 helixhorne 1980
static void P_DoWeaponSpawn(int32_t snum)
1209 terminx 1981
{
4227 helixhorne 1982
    int32_t j;
1983
    const DukePlayer_t *const p = g_player[snum].ps;
1209 terminx 1984
 
3955 helixhorne 1985
    // NOTE: For the 'Spawn' member, 0 means 'none', too (originally so,
1986
    // i.e. legacy). The check for <0 was added to the check because mod
1987
    // authors (rightly) assumed that -1 is the no-op value.
3328 helixhorne 1988
    if (PWEAPON(snum, p->curr_weapon, Spawn) <= 0)  // <=0 : AMC TC beta/RC2 has WEAPONx_SPAWN -1
1209 terminx 1989
        return;
1990
 
3328 helixhorne 1991
    j = A_Spawn(p->i, PWEAPON(snum, p->curr_weapon, Spawn));
1209 terminx 1992
 
3328 helixhorne 1993
    if ((PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_SPAWNTYPE3))
1209 terminx 1994
    {
1995
        // like chaingun shells
1996
        sprite[j].ang += 1024;
1997
        sprite[j].ang &= 2047;
1998
        sprite[j].xvel += 32;
1999
        sprite[j].z += (3<<8);
2000
    }
2001
 
2002
    A_SetSprite(j,CLIPMASK0);
2003
 
2004
}
2005
 
1611 terminx 2006
void P_DisplayScuba(int32_t snum)
1209 terminx 2007
{
2008
    if (g_player[snum].ps->scuba_on)
2009
    {
3353 helixhorne 2010
        int32_t p = P_GetHudPal(g_player[snum].ps);
2524 helixhorne 2011
 
2933 helixhorne 2012
        g_snum = snum;
3688 terminx 2013
#ifdef USE_OPENGL
2014
        if (getrendermode() >= REND_POLYMOST)
4623 terminx 2015
            G_DrawTileScaled(44, (200-tilesiz[SCUBAMASK].y), SCUBAMASK, 0, 2+16+DRAWEAP_CENTER, p);
3688 terminx 2016
#endif
4623 terminx 2017
        G_DrawTileScaled(43, (200-tilesiz[SCUBAMASK].y), SCUBAMASK, 0, 2+16+DRAWEAP_CENTER, p);
2018
        G_DrawTileScaled(320-43, (200-tilesiz[SCUBAMASK].y), SCUBAMASK, 0, 2+4+16+DRAWEAP_CENTER, p);
1209 terminx 2019
    }
2020
}
2021
 
4703 terminx 2022
static const int8_t access_tip_y [] ={
2023
    0, -8, -16, -32, -64, -84, -108, -108, -108, -108, -108, -108, -108, -108, -108, -108, -96, -72, -64, -32, -16,
2024
    /* EDuke32: */ 0, 16, 32, 48,
2025
    // At y coord 64, the hand is already not shown.
2026
};
2027
 
2028
static int32_t P_DisplayTip(int32_t gs, int32_t snum)
1209 terminx 2029
{
2917 helixhorne 2030
    const DukePlayer_t *const ps = g_player[snum].ps;
4703 terminx 2031
    int y, looking_arc, p = 0;
1209 terminx 2032
 
3630 helixhorne 2033
    if (ps->tipincs == 0)
3436 helixhorne 2034
        return 0;
1209 terminx 2035
 
3630 helixhorne 2036
    // Report that the tipping hand has been drawn so that the otherwise
2037
    // selected weapon is not drawn.
4703 terminx 2038
    if ((unsigned)ps->tipincs >= ARRAY_SIZE(access_tip_y))
3630 helixhorne 2039
        return 1;
2040
 
4703 terminx 2041
    looking_arc = (klabs(ps->look_ang) / 9) - (ps->hard_landing << 3);
2917 helixhorne 2042
 
3353 helixhorne 2043
    p = P_GetHudPal(ps);
2917 helixhorne 2044
 
4703 terminx 2045
    y = access_tip_y[ps->tipincs] >> 1;
2171 helixhorne 2046
 
4703 terminx 2047
    guniqhudid = 201;
1209 terminx 2048
 
4703 terminx 2049
    G_DrawTileScaled(170 + (g_player[snum].sync->avel >> 5) - (ps->look_ang >> 1),
2050
                     y + looking_arc + 240 - ((ps->horiz - ps->horizoff) >> 4), TIP + ((26 - ps->tipincs) >> 4), gs,
2051
                     DRAWEAP_CENTER, p);
2052
 
2053
    guniqhudid = 0;
2054
 
1209 terminx 2055
    return 1;
2056
}
2057
 
4703 terminx 2058
static int32_t P_DisplayAccess(int32_t gs, int32_t snum)
1209 terminx 2059
{
2917 helixhorne 2060
    const DukePlayer_t *const ps = g_player[snum].ps;
4703 terminx 2061
    int y, looking_arc, p = 0;
1209 terminx 2062
 
4703 terminx 2063
    if (ps->access_incs == 0)
3436 helixhorne 2064
        return 0;
1209 terminx 2065
 
4703 terminx 2066
    if ((unsigned)ps->access_incs >= ARRAY_SIZE(access_tip_y)-4 || sprite[ps->i].extra <= 0)
2067
        return 1;
1209 terminx 2068
 
4703 terminx 2069
    looking_arc = access_tip_y[ps->access_incs] + (klabs(ps->look_ang) / 9) - (ps->hard_landing << 3);
2070
 
2917 helixhorne 2071
    if (ps->access_spritenum >= 0)
2072
        p = sprite[ps->access_spritenum].pal;
1625 terminx 2073
 
4703 terminx 2074
    y = access_tip_y[ps->access_incs] >> 2;
2075
 
2076
    guniqhudid = 200;
2077
 
2078
    if ((ps->access_incs - 3) > 0 && (ps->access_incs - 3) >> 3)
2339 helixhorne 2079
    {
4703 terminx 2080
        G_DrawTileScaled(170 + (g_player[snum].sync->avel >> 5) - (ps->look_ang >> 1) + y,
2081
                         looking_arc + 266 - ((ps->horiz - ps->horizoff) >> 4),
2082
                         HANDHOLDINGLASER + (ps->access_incs >> 3), gs, DRAWEAP_CENTER, p);
2339 helixhorne 2083
    }
1209 terminx 2084
    else
2339 helixhorne 2085
    {
4703 terminx 2086
        G_DrawTileScaled(170 + (g_player[snum].sync->avel >> 5) - (ps->look_ang >> 1) + y,
2087
                         looking_arc + 266 - ((ps->horiz - ps->horizoff) >> 4), HANDHOLDINGACCESS, gs,
2088
                         4 + DRAWEAP_CENTER, p);
2339 helixhorne 2089
    }
1209 terminx 2090
 
4703 terminx 2091
    guniqhudid = 0;
2092
 
1209 terminx 2093
    return 1;
2094
}
2095
 
2096
 
2097
static int32_t fistsign;
2098
 
2099
void P_DisplayWeapon(int32_t snum)
2100
{
2101
    int32_t gun_pos, looking_arc, cw;
2102
    int32_t weapon_xoffset, i, j;
2103
    int32_t o = 0,pal = 0;
2876 helixhorne 2104
    DukePlayer_t *const p = g_player[snum].ps;
3353 helixhorne 2105
    const uint8_t *const kb = &p->kickback_pic;
1209 terminx 2106
    int32_t gs;
2107
 
2905 helixhorne 2108
    g_snum = snum;
2109
 
1209 terminx 2110
    looking_arc = klabs(p->look_ang)/9;
2111
 
2112
    gs = sprite[p->i].shade;
2113
    if (gs > 24) gs = 24;
2114
 
1625 terminx 2115
    if (p->newowner >= 0 || ud.camerasprite >= 0 || p->over_shoulder_on > 0 || (sprite[p->i].pal != 1 && sprite[p->i].extra <= 0) ||
1677 terminx 2116
            P_DisplayFist(gs,snum) || P_DisplayKnuckles(gs,snum) || P_DisplayTip(gs,snum) || P_DisplayAccess(gs,snum))
1209 terminx 2117
        return;
2118
 
1611 terminx 2119
    P_DisplayKnee(gs,snum);
1209 terminx 2120
 
2121
    gun_pos = 80-(p->weapon_pos*p->weapon_pos);
2122
 
2123
    weapon_xoffset = (160)-90;
2124
 
2125
    if (ud.weaponsway)
2126
    {
2127
        weapon_xoffset -= (sintable[((p->weapon_sway>>1)+512)&2047]/(1024+512));
2128
 
2129
        if (sprite[p->i].xrepeat < 32)
2130
            gun_pos -= klabs(sintable[(p->weapon_sway<<2)&2047]>>9);
2131
        else gun_pos -= klabs(sintable[(p->weapon_sway>>1)&2047]>>10);
2132
    }
2133
    else gun_pos -= 16;
2134
 
2135
    weapon_xoffset -= 58 + p->weapon_ang;
2136
    gun_pos -= (p->hard_landing<<3);
2137
 
4703 terminx 2138
    cw = PWEAPON(snum, (p->last_weapon >= 0) ? p->last_weapon : p->curr_weapon, WorksLike);
1209 terminx 2139
 
3408 helixhorne 2140
    hudweap.gunposy=gun_pos;
2141
    hudweap.lookhoriz=looking_arc;
2142
    hudweap.cur=cw;
2143
    hudweap.gunposx=weapon_xoffset;
2144
    hudweap.shade=gs;
2145
    hudweap.count=*kb;
2146
    hudweap.lookhalfang=p->look_ang>>1;
1209 terminx 2147
 
4745 terminx 2148
    if (VM_OnEvent(EVENT_DISPLAYWEAPON, p->i, screenpeek) == 0)
1209 terminx 2149
    {
2150
        j = 14-p->quick_kick;
2151
        if (j != 14 || p->last_quick_kick)
2152
        {
3353 helixhorne 2153
            pal = P_GetHudPal(p);
2518 helixhorne 2154
            if (pal == 0)
2155
                pal = p->palookup;
1209 terminx 2156
 
2157
            guniqhudid = 100;
2158
            if (j < 6 || j > 12)
2159
                G_DrawTileScaled(weapon_xoffset+80-(p->look_ang>>1),
2917 helixhorne 2160
                                 looking_arc+250-gun_pos,KNEE,gs,o|4|DRAWEAP_CENTER,pal);
1209 terminx 2161
            else G_DrawTileScaled(weapon_xoffset+160-16-(p->look_ang>>1),
2934 helixhorne 2162
                                  looking_arc+214-gun_pos,KNEE+1,gs,o|4|DRAWEAP_CENTER,pal);
1209 terminx 2163
            guniqhudid = 0;
2164
        }
2165
 
2166
        if (sprite[p->i].xrepeat < 40)
2167
        {
3353 helixhorne 2168
            pal = P_GetHudPal(p);
2934 helixhorne 2169
 
1209 terminx 2170
            if