Subversion Repositories eduke32

Rev

Rev 4986 | 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
 
110 terminx 23
#include "duke3d.h"
1346 terminx 24
 
3221 hendricks2 25
#include "baselayer.h"
26
#include "renderlayer.h"
3116 hendricks2 27
 
5 Plagman 28
#include "scriplib.h"
29
#include "file_lib.h"
30
#include "mathutil.h"
31
#include "gamedefs.h"
32
#include "keyboard.h"
33
#include "mouse.h"  // JBF 20030809
2728 hendricks2 34
#include "joystick.h"
5 Plagman 35
#include "function.h"
36
#include "control.h"
37
#include "fx_man.h"
38
#include "sounds.h"
39
#include "config.h"
40
#include "osd.h"
41
#include "osdfuncs.h"
42
#include "osdcmds.h"
130 terminx 43
#include "scriptfile.h"
241 terminx 44
#include "grpscan.h"
610 terminx 45
#include "gamedef.h"
640 terminx 46
#include "kplib.h"
1552 terminx 47
#include "crc32.h"
1173 terminx 48
#include "hightile.h"
1632 terminx 49
#include "control.h"
4316 hendricks2 50
#include "lz4.h"
1677 terminx 51
#include "net.h"
52
#include "premap.h"
53
#include "gameexec.h"
54
#include "menus.h"
55
#include "savegame.h"
56
#include "anim.h"
57
#include "demo.h"
2542 helixhorne 58
#include "common.h"
2726 hendricks2 59
#include "common_game.h"
2728 hendricks2 60
#include "input.h"
3170 helixhorne 61
#include "compat.h"
1552 terminx 62
 
2721 helixhorne 63
#ifdef LUNATIC
3148 helixhorne 64
# include "lunatic_game.h"
2034 helixhorne 65
#endif
66
 
3726 helixhorne 67
// Uncomment to prevent anything except mirrors from drawing. It is sensible to
4875 helixhorne 68
// also uncomment ENGINE_CLEAR_SCREEN in build/src/engine_priv.h.
3726 helixhorne 69
//#define DEBUG_MIRRORS_ONLY
70
 
1595 helixhorne 71
#if KRANDDEBUG
72
# define GAME_INLINE
73
# define GAME_STATIC
74
#else
75
# define GAME_INLINE inline
76
# define GAME_STATIC static
77
#endif
78
 
418 terminx 79
#ifdef _WIN32
3221 hendricks2 80
# include "winlayer.h"
81
# define WIN32_LEAN_AND_MEAN
82
# include <windows.h>
83
# include <shellapi.h>
84
# define UPDATEINTERVAL 604800 // 1w
85
# include "winbits.h"
933 terminx 86
#else
3221 hendricks2 87
# ifndef GEKKO
88
#  include <sys/ioctl.h>
89
# endif
1008 hnt_ts 90
#endif /* _WIN32 */
1587 terminx 91
 
4538 hendricks2 92
const char* AppProperName = "EDuke32";
93
const char* AppTechnicalName = "eduke32";
94
 
1587 terminx 95
int32_t g_quitDeadline = 0;
418 terminx 96
 
3405 helixhorne 97
#ifdef LUNATIC
98
camera_t g_camera;
99
#else
1205 terminx 100
int32_t g_cameraDistance = 0, g_cameraClock = 0;
3405 helixhorne 101
#endif
1587 terminx 102
static int32_t g_quickExit;
1205 terminx 103
static int32_t g_commandSetup = 0;
104
int32_t g_noSetup = 0;
105
static int32_t g_noAutoLoad = 0;
106
static int32_t g_noSound = 0;
107
static int32_t g_noMusic = 0;
2561 helixhorne 108
static const char *CommandMap = NULL;
109
static const char *CommandName = NULL;
1587 terminx 110
int32_t g_forceWeaponChoice = 0;
2879 helixhorne 111
int32_t g_fakeMultiMode = 0;
1632 terminx 112
 
3947 helixhorne 113
double g_moveActorsTime = 0;  // in ms, smoothed
114
 
1068 terminx 115
char boardfilename[BMAX_PATH] = {0}, currentboardfilename[BMAX_PATH] = {0};
1587 terminx 116
 
1205 terminx 117
int32_t voting = -1;
118
int32_t vote_map = -1, vote_episode = -1;
147 terminx 119
 
1587 terminx 120
static int32_t g_Debug = 0;
1205 terminx 121
static int32_t g_noLogoAnim = 0;
122
static int32_t g_noLogo = 0;
249 terminx 123
 
2726 hendricks2 124
const char *defaultrtsfilename[GAMECOUNT] = { "DUKE.RTS", "NAM.RTS", "NAPALM.RTS", "WW2GI.RTS" };
1205 terminx 125
 
2561 helixhorne 126
// g_rtsNamePtr can point to an argv[] element
127
const char *g_rtsNamePtr = NULL;
1205 terminx 128
 
129
int32_t g_Shareware = 0;
130
 
1037 terminx 131
#define MAXUSERQUOTES 6
1677 terminx 132
int32_t quotebot, quotebotgoal;
1205 terminx 133
static int32_t user_quote_time[MAXUSERQUOTES];
444 terminx 134
static char user_quote[MAXUSERQUOTES][178];
249 terminx 135
 
1658 terminx 136
// This was 32 for a while, but I think lowering it to 24 will help things like the Dingoo.
137
// Ideally, we would look at our memory usage on our most cramped platform and figure out
138
// how much of that is needed for the underlying OS and things like SDL instead of guessing
2628 helixhorne 139
#ifndef GEKKO
1658 terminx 140
static int32_t MAXCACHE1DSIZE = (24*1048576);
2628 helixhorne 141
#else
142
static int32_t MAXCACHE1DSIZE = (8*1048576);
143
#endif
253 terminx 144
 
1205 terminx 145
int32_t tempwallptr;
249 terminx 146
 
1205 terminx 147
static int32_t nonsharedtimer;
249 terminx 148
 
1552 terminx 149
int32_t ticrandomseed;
150
 
1205 terminx 151
static void G_DrawCameraText(int16_t i);
1595 helixhorne 152
GAME_STATIC GAME_INLINE int32_t G_MoveLoop(void);
1143 terminx 153
static void G_DoOrderScreen(void);
395 terminx 154
 
4919 terminx 155
#define FTAOPAQUETIME 30
156
 
157
#define ftapulseshade                                                                                                  \
158
    ((hud_glowingquotes && (getrendermode() == REND_CLASSIC || ps->fta >= FTAOPAQUETIME)) ?                            \
159
     (sintable[((uint32_t)ps->fta << 7) & 2047] >> 11) :                                                               \
160
     (sintable[((uint32_t)FTAOPAQUETIME << 7) & 2047] >> 11))
161
 
3773 helixhorne 162
#define quotepulseshade (sintable[((uint32_t)totalclock<<5)&2047]>>11)
1552 terminx 163
 
1205 terminx 164
int32_t althud_numbertile = 2930;
165
int32_t althud_numberpal = 0;
4595 terminx 166
 
4852 hendricks2 167
#ifdef EDUKE32_TOUCH_DEVICES
4595 terminx 168
int32_t althud_shadows = 0;
169
#else
1205 terminx 170
int32_t althud_shadows = 1;
4595 terminx 171
#endif
172
 
1205 terminx 173
int32_t althud_flashing = 1;
174
int32_t hud_glowingquotes = 1;
175
int32_t hud_showmapname = 1;
937 terminx 176
 
1205 terminx 177
int32_t g_levelTextTime = 0;
1068 terminx 178
 
1205 terminx 179
int32_t r_maxfps = 0;
180
uint32_t g_frameDelay = 0;
1086 terminx 181
 
1176 terminx 182
#if defined(RENDERTYPEWIN) && defined(USE_OPENGL)
1120 terminx 183
extern char forcegl;
184
#endif
185
 
1652 terminx 186
void M32RunScript(const char *s) { UNREFERENCED_PARAMETER(s); };  // needed for linking since it's referenced from build/src/osd.c
1649 helixhorne 187
 
2726 hendricks2 188
const char *G_DefaultRtsFile(void)
1909 terminx 189
{
2726 hendricks2 190
    if (DUKE)
191
        return defaultrtsfilename[GAME_DUKE];
192
    else if (WW2GI)
193
        return defaultrtsfilename[GAME_WW2GI];
194
    else if (NAPALM)
195
    {
2752 helixhorne 196
        if (!testkopen(defaultrtsfilename[GAME_NAPALM],0) && testkopen(defaultrtsfilename[GAME_NAM],0))
3618 hendricks2 197
            return defaultrtsfilename[GAME_NAM]; // NAM/NAPALM Sharing
2726 hendricks2 198
        else
199
            return defaultrtsfilename[GAME_NAPALM];
200
    }
201
    else if (NAM)
202
    {
2752 helixhorne 203
        if (!testkopen(defaultrtsfilename[GAME_NAM],0) && testkopen(defaultrtsfilename[GAME_NAPALM],0))
3618 hendricks2 204
            return defaultrtsfilename[GAME_NAPALM]; // NAM/NAPALM Sharing
2726 hendricks2 205
        else
206
            return defaultrtsfilename[GAME_NAM];
207
    }
1909 terminx 208
 
2726 hendricks2 209
    return defaultrtsfilename[0];
1909 terminx 210
}
211
 
1677 terminx 212
enum gametokens
335 terminx 213
{
505 terminx 214
    T_INCLUDE = 0,
249 terminx 215
    T_INTERFACE = 0,
505 terminx 216
    T_LOADGRP = 1,
249 terminx 217
    T_MODE = 1,
505 terminx 218
    T_CACHESIZE = 2,
626 terminx 219
    T_ALLOW = 2,
220
    T_NOAUTOLOAD,
1909 terminx 221
    T_INCLUDEDEFAULT,
634 terminx 222
    T_MUSIC,
223
    T_SOUND,
224
    T_FILE,
4987 terminx 225
    T_CUTSCENE,
2242 helixhorne 226
    T_ANIMSOUNDS,
2517 helixhorne 227
    T_NOFLOORPALRANGE,
4987 terminx 228
    T_ID,
229
    T_DELAY
249 terminx 230
};
231
 
232
 
3399 helixhorne 233
static int32_t sbarsc(int32_t sc)
234
{
235
    return scale(sc,ud.statusbarscale,100);
236
}
5 Plagman 237
 
2640 helixhorne 238
static int32_t sbarx(int32_t x)
5 Plagman 239
{
3399 helixhorne 240
    if (ud.screen_size == 4) return sbarsc(x<<16);
241
    return (((320<<16) - sbarsc(320<<16)) >> 1) + sbarsc(x<<16);
5 Plagman 242
}
243
 
2640 helixhorne 244
static int32_t sbarxr(int32_t x)
934 terminx 245
{
3399 helixhorne 246
    if (ud.screen_size == 4) return (320<<16) - sbarsc(x<<16);
247
    return (((320<<16) - sbarsc(320<<16)) >> 1) + sbarsc(x<<16);
934 terminx 248
}
249
 
2640 helixhorne 250
static int32_t sbary(int32_t y)
5 Plagman 251
{
4602 terminx 252
    if (ud.althud == 2 && ud.screen_size == 4) return sbarsc(y << 16);
253
    else return (200<<16) - sbarsc(200<<16) + sbarsc(y<<16);
5 Plagman 254
}
255
 
3612 hendricks2 256
static int32_t sbarx16(int32_t x)
257
{
258
    if (ud.screen_size == 4) return sbarsc(x);
259
    return (((320<<16) - sbarsc(320<<16)) >> 1) + sbarsc(x);
260
}
261
 
262
#if 0 // enable if ever needed
263
static int32_t sbarxr16(int32_t x)
264
{
265
    if (ud.screen_size == 4) return (320<<16) - sbarsc(x);
266
    return (((320<<16) - sbarsc(320<<16)) >> 1) + sbarsc(x);
267
}
268
#endif
269
 
270
static int32_t sbary16(int32_t y)
271
{
272
    return (200<<16) - sbarsc(200<<16) + sbarsc(y);
273
}
274
 
2728 hendricks2 275
int32_t textsc(int32_t sc)
1095 terminx 276
{
1097 terminx 277
    // prevent ridiculousness to a degree
1099 terminx 278
    if (xdim <= 320) return sc;
279
    else if (xdim <= 640) return scale(sc,min(200,ud.textscale),100);
280
    else if (xdim <= 800) return scale(sc,min(300,ud.textscale),100);
281
    else if (xdim <= 1024) return scale(sc,min(350,ud.textscale),100);
1095 terminx 282
    return scale(sc,ud.textscale,100);
283
}
284
 
1205 terminx 285
static void G_PatchStatusBar(int32_t x1, int32_t y1, int32_t x2, int32_t y2)
5 Plagman 286
{
3399 helixhorne 287
    int32_t scl = sbarsc(65536);
4623 terminx 288
    int32_t tx = sbarx16((160<<16) - (tilesiz[BOTTOMSTATUSBAR].x<<15)); // centered
289
    int32_t ty = sbary(200-tilesiz[BOTTOMSTATUSBAR].y);
5 Plagman 290
 
3399 helixhorne 291
    int32_t clx1 = sbarsc(scale(x1,xdim,320)), cly1 = sbarsc(scale(y1,ydim,200));
292
    int32_t clx2 = sbarsc(scale(x2,xdim,320)), cly2 = sbarsc(scale(y2,ydim,200));
293
    int32_t clofx = (xdim - sbarsc(xdim)) >> 1, clofy = (ydim - sbarsc(ydim));
5 Plagman 294
 
508 terminx 295
    rotatesprite(tx,ty,scl,0,BOTTOMSTATUSBAR,4,0,10+16+64,clx1+clofx,cly1+clofy,clx2+clofx-1,cly2+clofy-1);
5 Plagman 296
}
297
 
1772 plagman 298
void P_SetGamePalette(DukePlayer_t *player, uint8_t palid, int32_t set)
5 Plagman 299
{
1772 plagman 300
    if (palid >= BASEPALCOUNT)
301
        palid = BASEPAL;
1604 terminx 302
 
2954 helixhorne 303
    player->palette = palid;
304
 
564 terminx 305
    if (player != g_player[screenpeek].ps)
5 Plagman 306
        return;
1918 terminx 307
 
1781 plagman 308
    setbrightness(ud.brightness>>2, palid, set);
5 Plagman 309
}
310
 
3833 hendricks2 311
// get the string length until the next '\n'
312
int32_t G_GetStringLineLength(const char *text, const char *end, const int32_t iter)
313
{
314
    int32_t length = 0;
2947 helixhorne 315
 
3833 hendricks2 316
    while (*text != '\n' && text != end)
317
    {
318
        ++length;
319
 
320
        text += iter;
321
    }
322
 
323
    return length;
324
}
325
 
326
int32_t G_GetStringNumLines(const char *text, const char *end, const int32_t iter)
327
{
328
    int32_t count = 1;
329
 
330
    while (text != end)
331
    {
332
        if (*text == '\n')
333
            ++count;
334
        text += iter;
335
    }
336
 
337
    return count;
338
}
339
// Note: Neither of these care about TEXT_LINEWRAP. This is intended.
340
 
341
// This function requires you to Bfree() the returned char*.
342
char* G_GetSubString(const char *text, const char *end, const int32_t iter, const int32_t length)
343
{
4491 helixhorne 344
    char *line = (char*)Xmalloc((length+1) * sizeof(char));
3833 hendricks2 345
    int32_t counter = 0;
346
 
347
    while (counter < length && text != end)
348
    {
349
        line[counter] = *text;
350
 
351
        text += iter;
352
        ++counter;
353
    }
354
 
3852 helixhorne 355
    line[counter] = '\0';
3833 hendricks2 356
 
357
    return line;
358
}
359
 
360
// assign the character's tilenum
361
int32_t G_GetStringTile(int32_t font, char *t, int32_t f)
362
{
363
    if (f & TEXT_DIGITALNUMBER)
364
        return *t - '0' + font; // copied from digitalnumber
365
    else if (f & (TEXT_BIGALPHANUM|TEXT_GRAYFONT))
366
    {
367
        int32_t offset = (f & TEXT_GRAYFONT) ? 26 : 0;
368
 
369
        if (*t >= '0' && *t <= '9')
370
            return *t - '0' + font + ((f & TEXT_GRAYFONT) ? 26 : -10);
371
        else if (*t >= 'a' && *t <= 'z')
372
            return *t - 'a' + font + ((f & TEXT_GRAYFONT) ? -26 : 26);
373
        else if (*t >= 'A' && *t <= 'Z')
374
            return *t - 'A' + font;
375
        else switch (*t)
376
        {
377
            case '_':
378
            case '-':
379
                return font - (11 + offset);
380
                break;
381
            case '.':
382
                return font + (BIGPERIOD - (BIGALPHANUM + offset));
383
                break;
384
            case ',':
385
                return font + (BIGCOMMA - (BIGALPHANUM + offset));
386
                break;
387
            case '!':
388
                return font + (BIGX_ - (BIGALPHANUM + offset));
389
                break;
390
            case '?':
391
                return font + (BIGQ - (BIGALPHANUM + offset));
392
                break;
393
            case ';':
394
                return font + (BIGSEMI - (BIGALPHANUM + offset));
395
                break;
396
            case ':':
397
                return font + (BIGCOLIN - (BIGALPHANUM + offset));
398
                break;
399
            case '\\':
400
            case '/':
401
                return font + (68 - offset); // 3008-2940
402
                break;
403
            case '%':
404
                return font + (69 - offset); // 3009-2940
405
                break;
406
            case '`':
407
            case '\"': // could be better hacked in
408
            case '\'':
409
                return font + (BIGAPPOS - (BIGALPHANUM + offset));
410
                break;
411
            default: // unknown character
412
                *t = ' '; // whitespace-ize
4856 hendricks2 413
            case '\n':
3833 hendricks2 414
                return font;
415
                break;
416
        }
417
    }
418
    else
419
        return *t - '!' + font; // uses ASCII order
420
}
421
 
3850 hendricks2 422
#define NUMHACKACTIVE ((f & TEXT_GAMETEXTNUMHACK) && t >= '0' && t <= '9')
423
 
3833 hendricks2 424
// qstrdim
425
vec2_t G_ScreenTextSize(const int32_t font,
426
                        int32_t x, int32_t y, const int32_t z, const int32_t blockangle,
427
                        const char *str, const int32_t o,
428
                        int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween,
429
                        const int32_t f,
430
                        int32_t x1, int32_t y1, int32_t x2, int32_t y2)
431
{
432
    vec2_t size = { 0, 0, }; // eventually the return value
433
    vec2_t pos = { 0, 0, }; // holds the coordinate position as we draw each character tile of the string
434
    vec2_t extent = { 0, 0, }; // holds the x-width of each character and the greatest y-height of each line
435
    vec2_t offset = { 0, 0, }; // temporary; holds the last movement made in both directions
436
 
437
    int32_t tile;
438
    char t;
439
 
440
    // set the start and end points depending on direction
441
    int32_t iter = (f & TEXT_BACKWARDS) ? -1 : 1; // iteration direction
442
 
443
    const char *end;
444
    const char *text;
445
 
446
    if (str == NULL)
447
        return size;
448
 
449
    end = (f & TEXT_BACKWARDS) ? str-1 : Bstrchr(str,'\0');
450
    text = (f & TEXT_BACKWARDS) ? Bstrchr(str,'\0')-1 : str;
451
 
452
    // optimization: justification in both directions
453
    if ((f & TEXT_XJUSTIFY) && (f & TEXT_YJUSTIFY))
454
    {
455
        size.x = xbetween;
456
        size.y = ybetween;
457
        return size;
458
    }
459
 
460
    // for best results, we promote 320x200 coordinates to full precision before any math
461
    if (!(o & ROTATESPRITE_FULL16))
462
    {
463
        x <<= 16;
464
        y <<= 16;
465
        xspace <<= 16;
466
        yline <<= 16;
467
        xbetween <<= 16;
468
        ybetween <<= 16;
469
    }
470
    // coordinate values should be shifted left by 16
471
 
472
    // handle zooming where applicable
473
    xspace = scale(xspace, z, 65536);
474
    yline = scale(yline, z, 65536);
475
    xbetween = scale(xbetween, z, 65536);
476
    ybetween = scale(ybetween, z, 65536);
477
    // size/width/height/spacing/offset values should be multiplied or scaled by $z, zoom (since 100% is 65536, the same as 1<<16)
478
 
479
    // loop through the string
480
    while ((t = *text) && text != end)
481
    {
482
        // handle escape sequences
483
        if (t == '^' && Bisdigit(*(text+iter)) && !(f & TEXT_LITERALESCAPE))
484
        {
485
            text += iter + iter;
486
            if (Bisdigit(*text))
487
                text += iter;
488
            continue;
489
        }
490
 
491
        // handle case bits
492
        if (f & TEXT_UPPERCASE)
493
        {
494
            if (f & TEXT_INVERTCASE) // optimization...?
495
            { // v^ important that these two ifs remain separate due to the else below
496
                if (Bisupper(t))
497
                    t = Btolower(t);
498
            }
499
            else if (Bislower(t))
500
                t = Btoupper(t);
501
        }
502
        else if (f & TEXT_INVERTCASE)
503
        {
504
            if (Bisupper(t))
505
                t = Btolower(t);
506
            else if (Bislower(t))
507
                t = Btoupper(t);
508
        }
509
 
510
        // translate the character to a tilenum
511
        tile = G_GetStringTile(font, &t, f);
512
 
513
        // reset this here because we haven't printed anything yet this loop
514
        extent.x = 0;
515
 
516
        // reset this here because the act of printing something on this line means that we include the margin above in the total size
517
        offset.y = 0;
518
 
519
        // handle each character itself in the context of screen drawing
520
        switch (t)
521
        {
522
            case '\t':
523
            case ' ':
524
                // width
525
                extent.x = xspace;
526
 
527
                if (f & (TEXT_INTERNALSPACE|TEXT_TILESPACE))
528
                {
529
                    char space = '.'; // this is subject to change as an implementation detail
530
                    if (f & TEXT_TILESPACE)
531
                        space = '\x7F'; // tile after '~'
532
                    tile = G_GetStringTile(font, &space, f);
533
 
4623 terminx 534
                    extent.x += (tilesiz[tile].x * z);
3833 hendricks2 535
                }
536
 
537
                // prepare the height // near-CODEDUP the other two near-CODEDUPs for this section
538
                {
539
                    int32_t tempyextent = yline;
540
 
541
                    if (f & (TEXT_INTERNALLINE|TEXT_TILELINE))
542
                    {
543
                        char line = 'A'; // this is subject to change as an implementation detail
544
                        if (f & TEXT_TILELINE)
545
                            line = '\x7F'; // tile after '~'
546
                        tile = G_GetStringTile(font, &line, f);
547
 
4623 terminx 548
                        tempyextent += tilesiz[tile].y * z;
3833 hendricks2 549
                    }
550
 
551
                    SetIfGreater(&extent.y, tempyextent);
552
                }
553
 
554
                if (t == '\t')
555
                    extent.x <<= 2; // *= 4
556
 
557
                break;
558
 
559
            case '\n': // near-CODEDUP "if (wrap)"
4913 hendricks2 560
                extent.x = 0;
561
 
3833 hendricks2 562
                // save the position
3850 hendricks2 563
                if (!(f & TEXT_XOFFSETZERO)) // we want the entire offset to count as the character width
564
                    pos.x -= offset.x;
3833 hendricks2 565
                SetIfGreater(&size.x, pos.x);
566
 
567
                // reset the position
568
                pos.x = 0;
569
 
570
                // prepare the height
571
                {
572
                    int32_t tempyextent = yline;
573
 
574
                    if (f & (TEXT_INTERNALLINE|TEXT_TILELINE))
575
                    {
576
                        char line = 'A'; // this is subject to change as an implementation detail
577
                        if (f & TEXT_TILELINE)
578
                            line = '\x7F'; // tile after '~'
579
                        tile = G_GetStringTile(font, &line, f);
580
 
4623 terminx 581
                        tempyextent += tilesiz[tile].y * z;
3833 hendricks2 582
                    }
583
 
584
                    SetIfGreater(&extent.y, tempyextent);
585
                }
586
 
587
                // move down the line height
588
                if (!(f & TEXT_YOFFSETZERO))
589
                    pos.y += extent.y;
590
 
591
                // reset the current height
592
                extent.y = 0;
593
 
594
                // line spacing
595
                offset.y = (f & TEXT_YJUSTIFY) ? 0 : ybetween; // ternary to prevent overflow
596
                pos.y += offset.y;
597
 
598
                break;
599
 
600
            default:
601
                // width
4623 terminx 602
                extent.x = tilesiz[tile].x * z;
3833 hendricks2 603
 
604
                // obnoxious hardcoded functionality from gametext
3850 hendricks2 605
                if (NUMHACKACTIVE)
3833 hendricks2 606
                {
607
                    char numeral = '0'; // this is subject to change as an implementation detail
4623 terminx 608
                    extent.x = (tilesiz[G_GetStringTile(font, &numeral, f)].x-1) * z;
3833 hendricks2 609
                }
610
 
611
                // height
4623 terminx 612
                SetIfGreater(&extent.y, (tilesiz[tile].y * z));
3833 hendricks2 613
 
614
                break;
615
        }
616
 
617
        // incrementing the coordinate counters
618
        offset.x = 0;
619
 
620
        // advance the x coordinate
3850 hendricks2 621
        if (!(f & TEXT_XOFFSETZERO) || NUMHACKACTIVE)
3833 hendricks2 622
            offset.x += extent.x;
623
 
624
        // account for text spacing
3850 hendricks2 625
        if (!NUMHACKACTIVE // this "if" line ONLY == replicating hardcoded stuff
626
            && t != '\n'
3833 hendricks2 627
            && !(f & TEXT_XJUSTIFY)) // to prevent overflow
628
            offset.x += xbetween;
629
 
630
        // line wrapping
631
        if ((f & TEXT_LINEWRAP) && !(f & TEXT_XRIGHT) && !(f & TEXT_XCENTER) && blockangle % 512 == 0)
632
        {
633
            int32_t wrap = 0;
634
            const int32_t ang = blockangle % 2048;
635
 
636
            // this is the only place in qstrdim where angle actually affects direction, but only in the wrapping measurement
637
            switch (ang)
638
            {
639
                case 0:
3849 hendricks2 640
                    wrap = (x + (pos.x + offset.x) > ((o & 2) ? (320<<16) : ((x2 - USERQUOTE_RIGHTOFFSET)<<16)));
3833 hendricks2 641
                    break;
642
                case 512:
3849 hendricks2 643
                    wrap = (y + (pos.x + offset.x) > ((o & 2) ? (200<<16) : ((y2 - USERQUOTE_RIGHTOFFSET)<<16)));
3833 hendricks2 644
                    break;
645
                case 1024:
3849 hendricks2 646
                    wrap = (x - (pos.x + offset.x) < ((o & 2) ? 0 : ((x1 + USERQUOTE_RIGHTOFFSET)<<16)));
3833 hendricks2 647
                    break;
648
                case 1536:
3849 hendricks2 649
                    wrap = (y - (pos.x + offset.x) < ((o & 2) ? 0 : ((y1 + USERQUOTE_RIGHTOFFSET)<<16)));
3833 hendricks2 650
                    break;
651
            }
652
            if (wrap) // near-CODEDUP "case '\n':"
653
            {
654
                // save the position
655
                SetIfGreater(&size.x, pos.x);
656
 
657
                // reset the position
658
                pos.x = 0;
659
 
660
                // prepare the height
661
                {
662
                    int32_t tempyextent = yline;
663
 
664
                    if (f & (TEXT_INTERNALLINE|TEXT_TILELINE))
665
                    {
666
                        char line = 'A'; // this is subject to change as an implementation detail
667
                        if (f & TEXT_TILELINE)
668
                            line = '\x7F'; // tile after '~'
669
                        tile = G_GetStringTile(font, &line, f);
670
 
4623 terminx 671
                        tempyextent += tilesiz[tile].y * z;
3833 hendricks2 672
                    }
673
 
674
                    SetIfGreater(&extent.y, tempyextent);
675
                }
676
 
677
                // move down the line height
678
                if (!(f & TEXT_YOFFSETZERO))
679
                    pos.y += extent.y;
680
 
681
                // reset the current height
682
                extent.y = 0;
683
 
684
                // line spacing
685
                offset.y = (f & TEXT_YJUSTIFY) ? 0 : ybetween; // ternary to prevent overflow
686
                pos.y += offset.y;
687
            }
688
            else
689
                pos.x += offset.x;
690
        }
691
        else
692
            pos.x += offset.x;
693
 
3850 hendricks2 694
        // save some trouble with calculation in case the line breaks
695
        if (!(f & TEXT_XOFFSETZERO) || NUMHACKACTIVE)
3833 hendricks2 696
            offset.x -= extent.x;
697
 
698
        // iterate to the next character in the string
699
        text += iter;
700
    }
701
 
702
    // calculate final size
3850 hendricks2 703
    if (!(f & TEXT_XOFFSETZERO))
704
        pos.x -= offset.x;
3833 hendricks2 705
 
3850 hendricks2 706
    if (!(f & TEXT_YOFFSETZERO))
707
    {
708
        pos.y -= offset.y;
709
        pos.y += extent.y;
710
    }
711
    else
712
        pos.y += ybetween;
713
 
3833 hendricks2 714
    SetIfGreater(&size.x, pos.x);
715
    SetIfGreater(&size.y, pos.y);
716
 
717
    // justification where only one of the two directions is set, so we have to iterate
718
    if (f & TEXT_XJUSTIFY)
719
        size.x = xbetween;
720
    if (f & TEXT_YJUSTIFY)
721
        size.y = ybetween;
722
 
723
    // return values in the same manner we receive them
724
    if (!(o & ROTATESPRITE_FULL16))
725
    {
726
        size.x >>= 16;
727
        size.y >>= 16;
728
    }
729
 
730
    return size;
731
}
732
 
733
void G_AddCoordsFromRotation(vec2_t *coords, const vec2_t *unitDirection, const int32_t magnitude)
734
{
735
    coords->x += scale(magnitude, unitDirection->x, 16384);
736
    coords->y += scale(magnitude, unitDirection->y, 16384);
737
}
738
 
739
// screentext
740
vec2_t G_ScreenText(const int32_t font,
741
                    int32_t x, int32_t y, const int32_t z, const int32_t blockangle, const int32_t charangle,
4428 helixhorne 742
                    const char *str, const int32_t shade, int32_t pal, int32_t o, int32_t alpha,
3833 hendricks2 743
                    int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween, const int32_t f,
744
                    const int32_t x1, const int32_t y1, const int32_t x2, const int32_t y2)
745
{
746
    vec2_t size = { 0, 0, }; // eventually the return value
747
    vec2_t origin = { 0, 0, }; // where to start, depending on the alignment
748
    vec2_t pos = { 0, 0, }; // holds the coordinate position as we draw each character tile of the string
749
    vec2_t extent = { 0, 0, }; // holds the x-width of each character and the greatest y-height of each line
750
    const vec2_t Xdirection = { sintable[(blockangle+512)&2047], sintable[blockangle&2047], };
751
    const vec2_t Ydirection = { sintable[(blockangle+1024)&2047], sintable[(blockangle+512)&2047], };
752
 
4428 helixhorne 753
    int32_t blendidx=0, tile;
3833 hendricks2 754
    char t;
755
 
756
    // set the start and end points depending on direction
757
    int32_t iter = (f & TEXT_BACKWARDS) ? -1 : 1; // iteration direction
758
 
759
    const char *end;
760
    const char *text;
761
 
762
    if (str == NULL)
763
        return size;
764
 
4428 helixhorne 765
    NEG_ALPHA_TO_BLEND(alpha, blendidx, o);
766
 
3833 hendricks2 767
    end = (f & TEXT_BACKWARDS) ? str-1 : Bstrchr(str,'\0');
768
    text = (f & TEXT_BACKWARDS) ? Bstrchr(str,'\0')-1 : str;
769
 
770
    // for best results, we promote 320x200 coordinates to full precision before any math
771
    if (!(o & ROTATESPRITE_FULL16))
772
    {
773
        x <<= 16;
774
        y <<= 16;
775
        xspace <<= 16;
776
        yline <<= 16;
777
        xbetween <<= 16;
778
        ybetween <<= 16;
779
    }
780
    // coordinate values should be shifted left by 16
781
 
782
    // eliminate conflicts, necessary here to get the correct size value
783
    // especially given justification's special handling in G_ScreenTextSize()
784
    if ((f & TEXT_XRIGHT) || (f & TEXT_XCENTER) || (f & TEXT_XJUSTIFY) || (f & TEXT_YJUSTIFY) || blockangle % 512 != 0)
785
        o &= ~TEXT_LINEWRAP;
786
 
787
    // size is the return value, and we need it for alignment
788
    size = G_ScreenTextSize(font, x, y, z, blockangle, str, o | ROTATESPRITE_FULL16, xspace, yline, (f & TEXT_XJUSTIFY) ? 0 : xbetween, (f & TEXT_YJUSTIFY) ? 0 : ybetween, f & ~(TEXT_XJUSTIFY|TEXT_YJUSTIFY), x1, y1, x2, y2);
789
 
790
    // handle zooming where applicable
791
    xspace = scale(xspace, z, 65536);
792
    yline = scale(yline, z, 65536);
793
    xbetween = scale(xbetween, z, 65536);
794
    ybetween = scale(ybetween, z, 65536);
795
    // size/width/height/spacing/offset values should be multiplied or scaled by $z, zoom (since 100% is 65536, the same as 1<<16)
796
 
797
    // alignment
798
    // near-CODEDUP "case '\n':"
799
    {
800
        int32_t lines = G_GetStringNumLines(text, end, iter);
801
 
802
        if ((f & TEXT_XJUSTIFY) || (f & TEXT_XRIGHT) || (f & TEXT_XCENTER))
803
        {
804
            const int32_t length = G_GetStringLineLength(text, end, iter);
805
 
806
            int32_t linewidth = size.x;
807
 
808
            if (lines != 1)
809
            {
810
                char *line = G_GetSubString(text, end, iter, length);
811
 
4913 hendricks2 812
                linewidth = G_ScreenTextSize(font, x, y, z, blockangle, line, o | ROTATESPRITE_FULL16, xspace, yline, (f & TEXT_XJUSTIFY) ? 0 : xbetween, (f & TEXT_YJUSTIFY) ? 0 : ybetween, f & ~(TEXT_XJUSTIFY|TEXT_YJUSTIFY|TEXT_BACKWARDS), x1, y1, x2, y2).x;
3833 hendricks2 813
 
814
                Bfree(line);
815
            }
816
 
817
            if (f & TEXT_XJUSTIFY)
818
            {
819
                size.x = xbetween;
820
 
4658 terminx 821
                xbetween = (length == 1) ? 0 : tabledivide32_noinline((xbetween - linewidth), (length - 1));
3833 hendricks2 822
 
823
                linewidth = size.x;
824
            }
825
 
826
            if (f & TEXT_XRIGHT)
827
                origin.x = -linewidth;
828
            else if (f & TEXT_XCENTER)
829
                origin.x = -(linewidth / 2);
830
        }
831
 
832
        if (f & TEXT_YJUSTIFY)
833
        {
834
            const int32_t tempswap = ybetween;
4658 terminx 835
            ybetween = (lines == 1) ? 0 : tabledivide32_noinline(ybetween - size.y, lines - 1);
3833 hendricks2 836
            size.y = tempswap;
837
        }
838
 
839
        if (f & TEXT_YBOTTOM)
840
            origin.y = -size.y;
841
        else if (f & TEXT_YCENTER)
842
            origin.y = -(size.y / 2);
843
    }
844
 
845
    // loop through the string
846
    while ((t = *text) && text != end)
847
    {
848
        int32_t orientation = o;
849
        int32_t angle = blockangle + charangle;
850
 
851
        // handle escape sequences
852
        if (t == '^' && Bisdigit(*(text+iter)) && !(f & TEXT_LITERALESCAPE))
853
        {
854
            char smallbuf[4];
855
 
856
            text += iter;
857
            smallbuf[0] = *text;
858
 
859
            text += iter;
860
            if (Bisdigit(*text))
861
            {
862
                smallbuf[1] = *text;
863
                smallbuf[2] = '\0';
864
                text += iter;
865
            }
866
            else
867
                smallbuf[1] = '\0';
868
 
869
            if (!(f & TEXT_IGNOREESCAPE))
870
                pal = Batoi(smallbuf);
871
 
872
            continue;
873
        }
874
 
875
        // handle case bits
876
        if (f & TEXT_UPPERCASE)
877
        {
878
            if (f & TEXT_INVERTCASE) // optimization...?
879
            { // v^ important that these two ifs remain separate due to the else below
880
                if (Bisupper(t))
881
                    t = Btolower(t);
882
            }
883
            else if (Bislower(t))
884
                t = Btoupper(t);
885
        }
886
        else if (f & TEXT_INVERTCASE)
887
        {
888
            if (Bisupper(t))
889
                t = Btolower(t);
890
            else if (Bislower(t))
891
                t = Btoupper(t);
892
        }
893
 
894
        // translate the character to a tilenum
895
        tile = G_GetStringTile(font, &t, f);
896
 
897
        switch (t)
898
        {
899
            case '\t':
900
            case ' ':
901
            case '\n':
902
            case '\x7F':
903
                break;
904
 
905
            default:
906
            {
907
                vec2_t location = { x, y, };
908
 
909
                G_AddCoordsFromRotation(&location, &Xdirection, origin.x);
910
                G_AddCoordsFromRotation(&location, &Ydirection, origin.y);
911
 
912
                G_AddCoordsFromRotation(&location, &Xdirection, pos.x);
913
                G_AddCoordsFromRotation(&location, &Ydirection, pos.y);
914
 
4428 helixhorne 915
                rotatesprite_(location.x, location.y, z, angle, tile, shade, pal, orientation, alpha, blendidx, x1, y1, x2, y2);
3833 hendricks2 916
 
917
                break;
918
            }
919
        }
920
 
921
        // reset this here because we haven't printed anything yet this loop
922
        extent.x = 0;
923
 
924
        // handle each character itself in the context of screen drawing
925
        switch (t)
926
        {
927
            case '\t':
928
            case ' ':
929
                // width
930
                extent.x = xspace;
931
 
932
                if (f & (TEXT_INTERNALSPACE|TEXT_TILESPACE))
933
                {
934
                    char space = '.'; // this is subject to change as an implementation detail
935
                    if (f & TEXT_TILESPACE)
936
                        space = '\x7F'; // tile after '~'
937
                    tile = G_GetStringTile(font, &space, f);
938
 
4623 terminx 939
                    extent.x += (tilesiz[tile].x * z);
3833 hendricks2 940
                }
941
 
942
                // prepare the height // near-CODEDUP the other two near-CODEDUPs for this section
943
                {
944
                    int32_t tempyextent = yline;
945
 
946
                    if (f & (TEXT_INTERNALLINE|TEXT_TILELINE))
947
                    {
948
                        char line = 'A'; // this is subject to change as an implementation detail
949
                        if (f & TEXT_TILELINE)
950
                            line = '\x7F'; // tile after '~'
951
                        tile = G_GetStringTile(font, &line, f);
952
 
4623 terminx 953
                        tempyextent += tilesiz[tile].y * z;
3833 hendricks2 954
                    }
955
 
956
                    SetIfGreater(&extent.y, tempyextent);
957
                }
958
 
959
                if (t == '\t')
960
                    extent.x <<= 2; // *= 4
961
 
962
                break;
963
 
964
            case '\n': // near-CODEDUP "if (wrap)"
4913 hendricks2 965
                extent.x = 0;
966
 
3833 hendricks2 967
                // reset the position
968
                pos.x = 0;
969
 
970
                // prepare the height
971
                {
972
                    int32_t tempyextent = yline;
973
 
974
                    if (f & (TEXT_INTERNALLINE|TEXT_TILELINE))
975
                    {
976
                        char line = 'A'; // this is subject to change as an implementation detail
977
                        if (f & TEXT_TILELINE)
978
                            line = '\x7F'; // tile after '~'
979
                        tile = G_GetStringTile(font, &line, f);
980
 
4623 terminx 981
                        tempyextent += tilesiz[tile].y * z;
3833 hendricks2 982
                    }
983
 
984
                    SetIfGreater(&extent.y, tempyextent);
985
                }
986
 
987
                // move down the line height
988
                if (!(f & TEXT_YOFFSETZERO))
989
                    pos.y += extent.y;
990
 
991
                // reset the current height
992
                extent.y = 0;
993
 
994
                // line spacing
995
                pos.y += ybetween;
996
 
997
                // near-CODEDUP "alignments"
998
                if ((f & TEXT_XJUSTIFY) || (f & TEXT_XRIGHT) || (f & TEXT_XCENTER))
999
                {
4913 hendricks2 1000
                    const int32_t length = G_GetStringLineLength(text+1, end, iter);
3833 hendricks2 1001
 
4913 hendricks2 1002
                    char *line = G_GetSubString(text+1, end, iter, length);
3833 hendricks2 1003
 
4913 hendricks2 1004
                    int32_t linewidth = G_ScreenTextSize(font, x, y, z, blockangle, line, o | ROTATESPRITE_FULL16, xspace, yline, (f & TEXT_XJUSTIFY) ? 0 : xbetween, (f & TEXT_YJUSTIFY) ? 0 : ybetween, f & ~(TEXT_XJUSTIFY|TEXT_YJUSTIFY|TEXT_BACKWARDS), x1, y1, x2, y2).x;
3833 hendricks2 1005
 
1006
                    Bfree(line);
1007
 
1008
                    if (f & TEXT_XJUSTIFY)
1009
                    {
4658 terminx 1010
                        xbetween = (length == 1) ? 0 : tabledivide32_noinline(xbetween - linewidth, length - 1);
3833 hendricks2 1011
 
1012
                        linewidth = size.x;
1013
                    }
1014
 
1015
                    if (f & TEXT_XRIGHT)
1016
                        origin.x = -linewidth;
1017
                    else if (f & TEXT_XCENTER)
1018
                        origin.x = -(linewidth / 2);
1019
                }
1020
 
1021
                break;
1022
 
1023
            default:
1024
                // width
4623 terminx 1025
                extent.x = tilesiz[tile].x * z;
3833 hendricks2 1026
 
1027
                // obnoxious hardcoded functionality from gametext
3850 hendricks2 1028
                if (NUMHACKACTIVE)
3833 hendricks2 1029
                {
1030
                    char numeral = '0'; // this is subject to change as an implementation detail
4623 terminx 1031
                    extent.x = (tilesiz[G_GetStringTile(font, &numeral, f)].x-1) * z;
3833 hendricks2 1032
                }
1033
 
1034
                // height
4623 terminx 1035
                SetIfGreater(&extent.y, (tilesiz[tile].y * z));
3833 hendricks2 1036
 
1037
                break;
1038
        }
1039
 
1040
        // incrementing the coordinate counters
1041
        {
1042
            int32_t xoffset = 0;
1043
 
1044
            // advance the x coordinate
3850 hendricks2 1045
            if (!(f & TEXT_XOFFSETZERO) || NUMHACKACTIVE)
3833 hendricks2 1046
                xoffset += extent.x;
1047
 
1048
            // account for text spacing
3850 hendricks2 1049
            if (!NUMHACKACTIVE // this "if" line ONLY == replicating hardcoded stuff
1050
                && t != '\n')
3833 hendricks2 1051
                xoffset += xbetween;
1052
 
1053
            // line wrapping
1054
            if (f & TEXT_LINEWRAP)
1055
            {
1056
                int32_t wrap = 0;
1057
                const int32_t ang = blockangle % 2048;
1058
 
1059
                // it's safe to make some assumptions and not go through G_AddCoordsFromRotation() since we limit to four directions
1060
                switch (ang)
1061
                {
1062
                    case 0:
3849 hendricks2 1063
                        wrap = (x + (pos.x + xoffset) > ((orientation & 2) ? (320<<16) : ((x2 - USERQUOTE_RIGHTOFFSET)<<16)));
3833 hendricks2 1064
                        break;
1065
                    case 512:
3849 hendricks2 1066
                        wrap = (y + (pos.x + xoffset) > ((orientation & 2) ? (200<<16) : ((y2 - USERQUOTE_RIGHTOFFSET)<<16)));
3833 hendricks2 1067
                        break;
1068
                    case 1024:
3849 hendricks2 1069
                        wrap = (x - (pos.x + xoffset) < ((orientation & 2) ? 0 : ((x1 + USERQUOTE_RIGHTOFFSET)<<16)));
3833 hendricks2 1070
                        break;
1071
                    case 1536:
3849 hendricks2 1072
                        wrap = (y - (pos.x + xoffset) < ((orientation & 2) ? 0 : ((y1 + USERQUOTE_RIGHTOFFSET)<<16)));
3833 hendricks2 1073
                        break;
1074
                }
1075
                if (wrap) // near-CODEDUP "case '\n':"
1076
                {
1077
                    // reset the position
1078
                    pos.x = 0;
1079
 
1080
                    // prepare the height
1081
                    {
1082
                        int32_t tempyextent = yline;
1083
 
1084
                        if (f & (TEXT_INTERNALLINE|TEXT_TILELINE))
1085
                        {
1086
                            char line = 'A'; // this is subject to change as an implementation detail
1087
                            if (f & TEXT_TILELINE)
1088
                                line = '\x7F'; // tile after '~'
1089
                            tile = G_GetStringTile(font, &line, f);
1090
 
4623 terminx 1091
                            tempyextent += tilesiz[tile].y * z;
3833 hendricks2 1092
                        }
1093
 
1094
                        SetIfGreater(&extent.y, tempyextent);
1095
                    }
1096
 
1097
                    // move down the line height
1098
                    if (!(f & TEXT_YOFFSETZERO))
1099
                        pos.y += extent.y;
1100
 
1101
                    // reset the current height
1102
                    extent.y = 0;
1103
 
1104
                    // line spacing
1105
                    pos.y += ybetween;
1106
                }
1107
                else
1108
                    pos.x += xoffset;
1109
            }
1110
            else
1111
                pos.x += xoffset;
1112
        }
1113
 
1114
        // iterate to the next character in the string
1115
        text += iter;
1116
    }
1117
 
1118
    // return values in the same manner we receive them
1119
    if (!(o & ROTATESPRITE_FULL16))
1120
    {
1121
        size.x >>= 16;
1122
        size.y >>= 16;
1123
    }
1124
 
1125
    return size;
1126
}
1127
 
3838 hendricks2 1128
vec2_t G_ScreenTextShadow(int32_t sx, int32_t sy,
1129
                          const int32_t font,
1130
                          int32_t x, int32_t y, const int32_t z, const int32_t blockangle, const int32_t charangle,
1131
                          const char *str, const int32_t shade, int32_t pal, int32_t o, const int32_t alpha,
1132
                          int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween, const int32_t f,
1133
                          const int32_t x1, const int32_t y1, const int32_t x2, const int32_t y2)
1134
{
1135
    vec2_t size = { 0, 0, }; // eventually the return value
1136
 
1137
    if (!(o & ROTATESPRITE_FULL16))
1138
    {
1139
        sx <<= 16;
1140
        sy <<= 16;
1141
        x <<= 16;
1142
        y <<= 16;
1143
        xspace <<= 16;
1144
        yline <<= 16;
1145
        xbetween <<= 16;
1146
        ybetween <<= 16;
1147
    }
1148
 
1149
    G_ScreenText(font, x + scale(sx,z,65536), y + scale(sy,z,65536), z, blockangle, charangle, str, 127, 4, o|ROTATESPRITE_FULL16, alpha, xspace, yline, xbetween, ybetween, f, x1, y1, x2, y2);
1150
 
1151
    size = G_ScreenText(font, x, y, z, blockangle, charangle, str, shade, pal, o|ROTATESPRITE_FULL16, alpha, xspace, yline, xbetween, ybetween, f, x1, y1, x2, y2);
1152
 
1153
    // return values in the same manner we receive them
1154
    if (!(o & ROTATESPRITE_FULL16))
1155
    {
1156
        size.x >>= 16;
1157
        size.y >>= 16;
1158
    }
1159
 
1160
    return size;
1161
}
1162
 
2961 helixhorne 1163
// flags
1164
//  4: small font, wrap strings?
3836 hendricks2 1165
int32_t G_PrintGameText(int32_t hack, int32_t tile, int32_t x,  int32_t y,  const char *t,
1166
                        int32_t s,    int32_t p,    int32_t o,
4919 terminx 1167
                        int32_t x1,   int32_t y1,   int32_t x2, int32_t y2, int32_t z, int32_t a)
587 terminx 1168
{
3836 hendricks2 1169
    vec2_t dim;
1170
    int32_t f = TEXT_GAMETEXTNUMHACK;
1171
    int32_t xbetween = 0;
3849 hendricks2 1172
    const int32_t orient = (hack & 4) || (hack & 1) ? (8|16|(o&1)|(o&32)) : (2|o);
5 Plagman 1173
 
1604 terminx 1174
    if (t == NULL)
1175
        return -1;
1176
 
3608 hendricks2 1177
    if (!(o & ROTATESPRITE_FULL16))
966 hnt_ts 1178
    {
3608 hendricks2 1179
        x <<= 16;
1180
        y <<= 16;
966 hnt_ts 1181
    }
5 Plagman 1182
 
3836 hendricks2 1183
    if (hack & 4)
1604 terminx 1184
    {
3836 hendricks2 1185
        x = textsc(x);
1186
        z = textsc(z);
1187
        f |= TEXT_LINEWRAP;
5 Plagman 1188
    }
1604 terminx 1189
 
3836 hendricks2 1190
    if (hack & 8)
5 Plagman 1191
    {
3836 hendricks2 1192
        f |= TEXT_XOFFSETZERO;
1193
        xbetween = 8;
1194
    }
1604 terminx 1195
 
3836 hendricks2 1196
    // order is important, this bit comes after the rest
3838 hendricks2 1197
    if ((hack & 2) && !NAM) // squishtext
3836 hendricks2 1198
        --xbetween;
1604 terminx 1199
 
3836 hendricks2 1200
    if (x == (160<<16))
1201
        f |= TEXT_XCENTER;
1604 terminx 1202
 
4919 terminx 1203
    dim = G_ScreenText(tile, x, y, z, 0, 0, t, s, p, orient|ROTATESPRITE_FULL16, a, (5<<16), (8<<16), (xbetween<<16), 0, f, x1, y1, x2, y2);
1604 terminx 1204
 
3836 hendricks2 1205
    x += dim.x;
5 Plagman 1206
 
3836 hendricks2 1207
    if (!(o & ROTATESPRITE_FULL16))
1208
        x >>= 16;
1604 terminx 1209
 
3836 hendricks2 1210
    return x;
5 Plagman 1211
}
1212
 
1205 terminx 1213
int32_t G_GameTextLen(int32_t x,const char *t)
877 terminx 1214
{
3836 hendricks2 1215
    vec2_t dim;
867 terminx 1216
 
877 terminx 1217
    if (t == NULL)
1218
        return -1;
1219
 
3836 hendricks2 1220
    dim = G_ScreenTextSize(STARTALPHANUM, x, 0, textsc(65536L), 0, t, 2, 5, 8, 0, 0, TEXT_GAMETEXTNUMHACK, 0, 0, xdim-1, ydim-1);
877 terminx 1221
 
3836 hendricks2 1222
    x += dim.x;
1625 terminx 1223
 
3836 hendricks2 1224
    return x;
877 terminx 1225
}
1226
 
2944 helixhorne 1227
// minitext_yofs: in hud_scale-independent, (<<16)-scaled, 0-200-normalized y coords,
1228
// (sb&ROTATESPRITE_MAX) only.
1229
static int32_t minitext_yofs = 0;
4496 hendricks2 1230
int32_t minitext_lowercase = 0;
1205 terminx 1231
int32_t minitext_(int32_t x,int32_t y,const char *t,int32_t s,int32_t p,int32_t sb)
5 Plagman 1232
{
3836 hendricks2 1233
    vec2_t dim;
1234
    int32_t z = 65536L;
1235
    int32_t f = 0;
5 Plagman 1236
 
1918 terminx 1237
    if (t == NULL)
1238
    {
1239
        OSD_Printf("minitext: NULL text!\n");
1240
        return 0;
1241
    }
1884 terminx 1242
 
3836 hendricks2 1243
    if (!(sb & ROTATESPRITE_FULL16))
3608 hendricks2 1244
    {
1245
        x<<=16;
1246
        y<<=16;
1247
    }
1248
 
3836 hendricks2 1249
    if (!minitext_lowercase)
1250
        f |= TEXT_UPPERCASE;
1251
 
1252
    if (sb & ROTATESPRITE_MAX)
5 Plagman 1253
    {
3836 hendricks2 1254
        x = sbarx16(x);
1255
        y = minitext_yofs+sbary16(y);
1256
        z = sbarsc(z);
1257
    }
3606 hendricks2 1258
 
3836 hendricks2 1259
    sb &= (ROTATESPRITE_MAX-1)|RS_CENTERORIGIN;
5 Plagman 1260
 
3836 hendricks2 1261
    dim = G_ScreenText(MINIFONT, x, y, z, 0, 0, t, s, p, sb|ROTATESPRITE_FULL16, 0, (4<<16), (8<<16), (1<<16), 0, f, 0, 0, xdim-1, ydim-1);
5 Plagman 1262
 
3836 hendricks2 1263
    x += dim.x;
1625 terminx 1264
 
3836 hendricks2 1265
    if (!(sb & ROTATESPRITE_FULL16))
1266
        x >>= 16;
1267
 
1268
    return x;
5 Plagman 1269
}
4496 hendricks2 1270
 
1143 terminx 1271
void G_AddUserQuote(const char *daquote)
5 Plagman 1272
{
1205 terminx 1273
    int32_t i;
5 Plagman 1274
 
1229 terminx 1275
    for (i=MAXUSERQUOTES-1; i>0; i--)
5 Plagman 1276
    {
232 terminx 1277
        Bstrcpy(user_quote[i],user_quote[i-1]);
5 Plagman 1278
        user_quote_time[i] = user_quote_time[i-1];
1279
    }
232 terminx 1280
    Bstrcpy(user_quote[0],daquote);
864 terminx 1281
    OSD_Printf("%s\n",daquote);
87 terminx 1282
 
88 terminx 1283
    user_quote_time[0] = ud.msgdisptime;
5 Plagman 1284
    pub = NUMPAGES;
1285
}
1286
 
1143 terminx 1287
void G_HandleSpecialKeys(void)
5 Plagman 1288
{
1552 terminx 1289
    // we need CONTROL_GetInput in order to pick up joystick button presses
1290
    if (CONTROL_Started && !(g_player[myconnectindex].ps->gm & MODE_GAME))
1291
    {
1292
        ControlInfo noshareinfo;
1293
        CONTROL_GetInput(&noshareinfo);
1294
    }
1295
 
1632 terminx 1296
//    CONTROL_ProcessBinds();
808 terminx 1297
 
1802 terminx 1298
    if (g_networkMode != NET_DEDICATED_SERVER && ALT_IS_PRESSED && KB_KeyPressed(sc_Enter))
114 terminx 1299
    {
563 terminx 1300
        if (setgamemode(!ud.config.ScreenMode,ud.config.ScreenWidth,ud.config.ScreenHeight,ud.config.ScreenBPP))
335 terminx 1301
        {
909 terminx 1302
            OSD_Printf(OSD_ERROR "Failed setting fullscreen video mode.\n");
563 terminx 1303
            if (setgamemode(ud.config.ScreenMode, ud.config.ScreenWidth, ud.config.ScreenHeight, ud.config.ScreenBPP))
1143 terminx 1304
                G_GameExit("Failed to recover from failure to set fullscreen video mode.\n");
114 terminx 1305
        }
563 terminx 1306
        else ud.config.ScreenMode = !ud.config.ScreenMode;
114 terminx 1307
        KB_ClearKeyDown(sc_Enter);
1143 terminx 1308
        g_restorePalette = 1;
1309
        G_UpdateScreenArea();
114 terminx 1310
    }
1311
 
824 terminx 1312
    if (KB_UnBoundKeyPressed(sc_F12))
472 terminx 1313
    {
1852 helixhorne 1314
        char titlebuf[256];
1315
        Bsprintf(titlebuf,HEAD2 " %s",s_buildRev);
1316
 
472 terminx 1317
        KB_ClearKeyDown(sc_F12);
1852 helixhorne 1318
        screencapture("duke0000.tga",0,titlebuf);
1802 terminx 1319
        P_DoQuote(QUOTE_SCREEN_SAVED,g_player[myconnectindex].ps);
472 terminx 1320
    }
1321
 
5 Plagman 1322
    // only dispatch commands here when not in a game
1574 terminx 1323
    if (!(g_player[myconnectindex].ps->gm & MODE_GAME))
335 terminx 1324
        OSD_DispatchQueued();
5 Plagman 1325
 
1587 terminx 1326
    if (g_quickExit == 0 && KB_KeyPressed(sc_LeftControl) && KB_KeyPressed(sc_LeftAlt) && (KB_KeyPressed(sc_Delete)||KB_KeyPressed(sc_End)))
5 Plagman 1327
    {
1587 terminx 1328
        g_quickExit = 1;
1143 terminx 1329
        G_GameExit("Quick Exit.");
5 Plagman 1330
    }
1143 terminx 1331
}
5 Plagman 1332
 
1571 terminx 1333
void G_GameQuit(void)
1552 terminx 1334
{
1574 terminx 1335
    if (numplayers < 2)
1336
        G_GameExit(" ");
1337
 
1338
    if (g_gameQuit == 0)
1552 terminx 1339
    {
1593 terminx 1340
        g_gameQuit = 1;
1341
        g_quitDeadline = totalclock+120;
1342
        g_netDisconnect = 1;
1552 terminx 1343
    }
1344
 
1587 terminx 1345
    if ((totalclock > g_quitDeadline) && (g_gameQuit == 1))
1552 terminx 1346
        G_GameExit("Timed out.");
1347
}
1348
 
4255 helixhorne 1349
#if !defined DEBUG_ALLOCACHE_AS_MALLOC
1205 terminx 1350
extern int32_t cacnum;
5 Plagman 1351
extern cactype cac[];
4255 helixhorne 1352
#endif
5 Plagman 1353
 
1143 terminx 1354
static void G_ShowCacheLocks(void)
5 Plagman 1355
{
1205 terminx 1356
    int16_t i,k;
5 Plagman 1357
 
1916 helixhorne 1358
    if (offscreenrendering)
1359
        return;
1360
 
5 Plagman 1361
    k = 0;
4255 helixhorne 1362
#if !defined DEBUG_ALLOCACHE_AS_MALLOC
1229 terminx 1363
    for (i=cacnum-1; i>=0; i--)
5 Plagman 1364
        if ((*cac[i].lock) >= 200)
1365
        {
1916 helixhorne 1366
            if (k >= ydim-12)
1367
                break;
1368
 
584 terminx 1369
            Bsprintf(tempbuf,"Locked- %d: Leng:%d, Lock:%d",i,cac[i].leng,*cac[i].lock);
335 terminx 1370
            printext256(0L,k,31,-1,tempbuf,1);
1371
            k += 6;
5 Plagman 1372
        }
4255 helixhorne 1373
#endif
1916 helixhorne 1374
    if (k < ydim-12)
1375
        k += 6;
5 Plagman 1376
 
1229 terminx 1377
    for (i=10; i>=0; i--)
1677 terminx 1378
        if (rts_lumplockbyte[i] >= 200)
5 Plagman 1379
        {
1916 helixhorne 1380
            if (k >= ydim-12)
1381
                break;
1382
 
5 Plagman 1383
            Bsprintf(tempbuf,"RTS Locked %d:",i);
2441 helixhorne 1384
            printext256(0,k,31,-1,tempbuf,1);
335 terminx 1385
            k += 6;
5 Plagman 1386
        }
1916 helixhorne 1387
 
1388
    if (k >= ydim-12 && k<ydim-6)
2441 helixhorne 1389
        printext256(0,k,31,-1,"(MORE . . .)",1);
1390
 
1391
    // sounds
1392
    if (xdim < 640)
1393
        return;
1394
 
1395
    k = 18;
1396
    for (i=0; i<=g_maxSoundPos; i++)
1397
        if (g_sounds[i].num > 0)
1398
        {
1399
            int32_t j, n=g_sounds[i].num;
1400
 
1401
            for (j=0; j<n; j++)
1402
            {
1403
                if (k >= ydim-12)
1404
                    break;
1405
 
1406
                Bsprintf(tempbuf, "snd #%d inst %d: voice %d, ow %d", i, j,
2442 helixhorne 1407
                         g_sounds[i].SoundOwner[j].voice, g_sounds[i].SoundOwner[j].ow);
2441 helixhorne 1408
                printext256(240,k,31,-1,tempbuf,0);
1409
 
1410
                k += 9;
1411
            }
1412
        }
5 Plagman 1413
}
1414
 
1205 terminx 1415
int32_t A_CheckInventorySprite(spritetype *s)
5 Plagman 1416
{
2297 helixhorne 1417
    switch (DYNAMICTILEMAP(s->picnum))
5 Plagman 1418
    {
337 terminx 1419
    case FIRSTAID__STATIC:
1420
    case STEROIDS__STATIC:
1421
    case HEATSENSOR__STATIC:
1422
    case BOOTS__STATIC:
1423
    case JETPACK__STATIC:
1424
    case HOLODUKE__STATIC:
1425
    case AIRTANK__STATIC:
1426
        return 1;
1672 terminx 1427
    default:
1428
        return 0;
5 Plagman 1429
    }
1430
}
1431
 
3645 helixhorne 1432
// MYOS* CON commands.
1433
LUNATIC_EXTERN void G_DrawTileGeneric(int32_t x, int32_t y, int32_t zoom, int32_t tilenum,
1434
                                      int32_t shade, int32_t orientation, int32_t p)
5 Plagman 1435
{
2896 helixhorne 1436
    int32_t a = 0;
5 Plagman 1437
 
3479 helixhorne 1438
    orientation &= (ROTATESPRITE_MAX-1);
1439
 
331 terminx 1440
    if (orientation&4)
5 Plagman 1441
        a = 1024;
1442
 
3608 hendricks2 1443
    if (!(orientation&ROTATESPRITE_FULL16))
1444
    {
1445
        x<<=16;
1446
        y<<=16;
1447
    }
1448
 
1449
    rotatesprite_win(x,y,zoom,a,tilenum,shade,p,2|orientation);
5 Plagman 1450
}
1451
 
3479 helixhorne 1452
#if !defined LUNATIC
2896 helixhorne 1453
void G_DrawTile(int32_t x, int32_t y, int32_t tilenum, int32_t shade, int32_t orientation)
5 Plagman 1454
{
2896 helixhorne 1455
    DukePlayer_t *ps = g_player[screenpeek].ps;
1456
    int32_t p = ps->cursectnum >= 0 ? sector[ps->cursectnum].floorpal : 0;
5 Plagman 1457
 
2896 helixhorne 1458
    G_DrawTileGeneric(x,y,65536, tilenum,shade,orientation, p);
1459
}
5 Plagman 1460
 
2896 helixhorne 1461
void G_DrawTilePal(int32_t x, int32_t y, int32_t tilenum, int32_t shade, int32_t orientation, int32_t p)
1462
{
1463
    G_DrawTileGeneric(x,y,65536, tilenum,shade,orientation, p);
5 Plagman 1464
}
1465
 
1205 terminx 1466
void G_DrawTileSmall(int32_t x, int32_t y, int32_t tilenum, int32_t shade, int32_t orientation)
5 Plagman 1467
{
2896 helixhorne 1468
    DukePlayer_t *ps = g_player[screenpeek].ps;
1469
    int32_t p = ps->cursectnum >= 0 ? sector[ps->cursectnum].floorpal : 0;
5 Plagman 1470
 
2896 helixhorne 1471
    G_DrawTileGeneric(x,y,32768, tilenum,shade,orientation, p);
5 Plagman 1472
}
1473
 
1205 terminx 1474
void G_DrawTilePalSmall(int32_t x, int32_t y, int32_t tilenum, int32_t shade, int32_t orientation, int32_t p)
5 Plagman 1475
{
2896 helixhorne 1476
    G_DrawTileGeneric(x,y,32768, tilenum,shade,orientation, p);
5 Plagman 1477
}
3479 helixhorne 1478
#endif
5 Plagman 1479
 
1148 terminx 1480
#define POLYMOSTTRANS (1)
1481
#define POLYMOSTTRANS2 (1|32)
1482
 
2944 helixhorne 1483
// Draws inventory numbers in the HUD for both the full and mini status bars.
1484
// yofs: in hud_scale-independent, (<<16)-scaled, 0-200-normalized y coords.
1485
static void G_DrawInvNum(int32_t x, int32_t yofs, int32_t y, char num1, char ha, int32_t sbits)
5 Plagman 1486
{
2896 helixhorne 1487
    char dabuf[16];
2316 helixhorne 1488
    int32_t i, shd = (x < 0);
934 terminx 1489
 
2896 helixhorne 1490
    const int32_t sbscale = sbarsc(65536);
2944 helixhorne 1491
    const int32_t sby = yofs+sbary(y), sbyp1 = yofs+sbary(y+1);
2896 helixhorne 1492
 
946 terminx 1493
    if (shd) x = -x;
934 terminx 1494
 
2896 helixhorne 1495
    Bsprintf(dabuf, "%d", num1);
1496
 
331 terminx 1497
    if (num1 > 99)
5 Plagman 1498
    {
3346 terminx 1499
        if (shd && ud.screen_size == 4 && getrendermode() >= REND_POLYMOST && althud_shadows)
934 terminx 1500
        {
2316 helixhorne 1501
            for (i=0; i<=2; i++)
2896 helixhorne 1502
                rotatesprite_fs(sbarx(x+(-4+4*i)+1),sbyp1,sbscale,0,THREEBYFIVE+dabuf[i]-'0',
3837 hendricks2 1503
                                127, 4, POLYMOSTTRANS|sbits);
934 terminx 1504
        }
2316 helixhorne 1505
 
1506
        for (i=0; i<=2; i++)
2896 helixhorne 1507
            rotatesprite_fs(sbarx(x+(-4+4*i)),sby,sbscale,0,THREEBYFIVE+dabuf[i]-'0',ha, 0, sbits);
425 terminx 1508
        return;
5 Plagman 1509
    }
2896 helixhorne 1510
 
425 terminx 1511
    if (num1 > 9)
5 Plagman 1512
    {
3346 terminx 1513
        if (shd && ud.screen_size == 4 && getrendermode() >= REND_POLYMOST && althud_shadows)
934 terminx 1514
        {
3837 hendricks2 1515
            rotatesprite_fs(sbarx(x+1),sbyp1,sbscale,0,THREEBYFIVE+dabuf[0]-'0',127,4,POLYMOSTTRANS|sbits);
1516
            rotatesprite_fs(sbarx(x+4+1),sbyp1,sbscale,0,THREEBYFIVE+dabuf[1]-'0',127,4,POLYMOSTTRANS|sbits);
934 terminx 1517
        }
1518
 
2896 helixhorne 1519
        rotatesprite_fs(sbarx(x),sby,sbscale,0,THREEBYFIVE+dabuf[0]-'0',ha,0,sbits);
1520
        rotatesprite_fs(sbarx(x+4),sby,sbscale,0,THREEBYFIVE+dabuf[1]-'0',ha,0,sbits);
425 terminx 1521
        return;
5 Plagman 1522
    }
2896 helixhorne 1523
 
1524
    rotatesprite_fs(sbarx(x+4+1),sbyp1,sbscale,0,THREEBYFIVE+dabuf[0]-'0',ha,4,sbits);
1525
    rotatesprite_fs(sbarx(x+4),sby,sbscale,0,THREEBYFIVE+dabuf[0]-'0',ha,0,sbits);
5 Plagman 1526
}
1527
 
1658 terminx 1528
static void G_DrawWeapNum(int16_t ind,int32_t x,int32_t y,int32_t num1, int32_t num2,int32_t ha)
5 Plagman 1529
{
2896 helixhorne 1530
    char dabuf[16];
5 Plagman 1531
 
2896 helixhorne 1532
    const int32_t sbscale = sbarsc(65536);
1533
    const int32_t sby = sbary(y);
425 terminx 1534
 
2896 helixhorne 1535
    rotatesprite_fs(sbarx(x-7),sby,sbscale,0,THREEBYFIVE+ind+1,ha-10,7,10);
1536
    rotatesprite_fs(sbarx(x-3),sby,sbscale,0,THREEBYFIVE+10,ha,0,10);
1537
 
425 terminx 1538
    if (VOLUMEONE && (ind > HANDBOMB_WEAPON || ind < 0))
1539
    {
1658 terminx 1540
        minitextshade(x+1,y-4,"ORDER",20,11,2+8+16+ROTATESPRITE_MAX);
425 terminx 1541
        return;
1542
    }
1543
 
2896 helixhorne 1544
    rotatesprite_fs(sbarx(x+9),sby,sbscale,0,THREEBYFIVE+11,ha,0,10);
5 Plagman 1545
 
331 terminx 1546
    if (num1 > 99) num1 = 99;
1547
    if (num2 > 99) num2 = 99;
5 Plagman 1548
 
584 terminx 1549
    Bsprintf(dabuf,"%d",num1);
331 terminx 1550
    if (num1 > 9)
5 Plagman 1551
    {
2896 helixhorne 1552
        rotatesprite_fs(sbarx(x),sby,sbscale,0,THREEBYFIVE+dabuf[0]-'0',ha,0,10);
1553
        rotatesprite_fs(sbarx(x+4),sby,sbscale,0,THREEBYFIVE+dabuf[1]-'0',ha,0,10);
5 Plagman 1554
    }
2896 helixhorne 1555
    else rotatesprite_fs(sbarx(x+4),sby,sbscale,0,THREEBYFIVE+dabuf[0]-'0',ha,0,10);
5 Plagman 1556
 
584 terminx 1557
    Bsprintf(dabuf,"%d",num2);
331 terminx 1558
    if (num2 > 9)
5 Plagman 1559
    {
2896 helixhorne 1560
        rotatesprite_fs(sbarx(x+13),sby,sbscale,0,THREEBYFIVE+dabuf[0]-'0',ha,0,10);
1561
        rotatesprite_fs(sbarx(x+17),sby,sbscale,0,THREEBYFIVE+dabuf[1]-'0',ha,0,10);
425 terminx 1562
        return;
5 Plagman 1563
    }
2896 helixhorne 1564
    rotatesprite_fs(sbarx(x+13),sby,sbscale,0,THREEBYFIVE+dabuf[0]-'0',ha,0,10);
5 Plagman 1565
}
1566
 
1205 terminx 1567
static void G_DrawWeapNum2(char ind,int32_t x,int32_t y,int32_t num1, int32_t num2,char ha)
5 Plagman 1568
{
2896 helixhorne 1569
    char dabuf[16];
5 Plagman 1570
 
2896 helixhorne 1571
    const int32_t sbscale = sbarsc(65536);
1572
    const int32_t sby = sbary(y);
5 Plagman 1573
 
2896 helixhorne 1574
    rotatesprite_fs(sbarx(x-7),sby,sbscale,0,THREEBYFIVE+ind+1,ha-10,7,10);
1575
    rotatesprite_fs(sbarx(x-4),sby,sbscale,0,THREEBYFIVE+10,ha,0,10);
1576
    rotatesprite_fs(sbarx(x+13),sby,sbscale,0,THREEBYFIVE+11,ha,0,10);
1577
 
584 terminx 1578
    Bsprintf(dabuf,"%d",num1);
331 terminx 1579
    if (num1 > 99)
5 Plagman 1580
    {
2896 helixhorne 1581
        rotatesprite_fs(sbarx(x),sby,sbscale,0,THREEBYFIVE+dabuf[0]-'0',ha,0,10);
1582
        rotatesprite_fs(sbarx(x+4),sby,sbscale,0,THREEBYFIVE+dabuf[1]-'0',ha,0,10);
1583
        rotatesprite_fs(sbarx(x+8),sby,sbscale,0,THREEBYFIVE+dabuf[2]-'0',ha,0,10);
5 Plagman 1584
    }
331 terminx 1585
    else if (num1 > 9)
5 Plagman 1586
    {
2896 helixhorne 1587
        rotatesprite_fs(sbarx(x+4),sby,sbscale,0,THREEBYFIVE+dabuf[0]-'0',ha,0,10);
1588
        rotatesprite_fs(sbarx(x+8),sby,sbscale,0,THREEBYFIVE+dabuf[1]-'0',ha,0,10);
5 Plagman 1589
    }
2896 helixhorne 1590
    else rotatesprite_fs(sbarx(x+8),sby,sbscale,0,THREEBYFIVE+dabuf[0]-'0',ha,0,10);
5 Plagman 1591
 
584 terminx 1592
    Bsprintf(dabuf,"%d",num2);
331 terminx 1593
    if (num2 > 99)
5 Plagman 1594
    {
2896 helixhorne 1595
        rotatesprite_fs(sbarx(x+17),sby,sbscale,0,THREEBYFIVE+dabuf[0]-'0',ha,0,10);
1596
        rotatesprite_fs(sbarx(x+21),sby,sbscale,0,THREEBYFIVE+dabuf[1]-'0',ha,0,10);
1597
        rotatesprite_fs(sbarx(x+25),sby,sbscale,0,THREEBYFIVE+dabuf[2]-'0',ha,0,10);
5 Plagman 1598
    }
331 terminx 1599
    else if (num2 > 9)
5 Plagman 1600
    {
2896 helixhorne 1601
        rotatesprite_fs(sbarx(x+17),sby,sbscale,0,THREEBYFIVE+dabuf[0]-'0',ha,0,10);
1602
        rotatesprite_fs(sbarx(x+21),sby,sbscale,0,THREEBYFIVE+dabuf[1]-'0',ha,0,10);
425 terminx 1603
        return;
5 Plagman 1604
    }
587 terminx 1605
    else
2896 helixhorne 1606
        rotatesprite_fs(sbarx(x+25),sby,sbscale,0,THREEBYFIVE+dabuf[0]-'0',ha,0,10);
5 Plagman 1607
}
1608
 
2896 helixhorne 1609
static void G_DrawWeapAmounts(const DukePlayer_t *p,int32_t x,int32_t y,int32_t u)
5 Plagman 1610
{
1205 terminx 1611
    int32_t cw = p->curr_weapon;
5 Plagman 1612
 
1613
    if (u&4)
1614
    {
1144 terminx 1615
        if (u != -1) G_PatchStatusBar(88,178,88+37,178+6); //original code: (96,178,96+12,178+6);
1143 terminx 1616
        G_DrawWeapNum2(PISTOL_WEAPON,x,y,
1617
                       p->ammo_amount[PISTOL_WEAPON],p->max_ammo_amount[PISTOL_WEAPON],
1618
                       12-20*(cw == PISTOL_WEAPON));
5 Plagman 1619
    }
1620
    if (u&8)
1621
    {
1144 terminx 1622
        if (u != -1) G_PatchStatusBar(88,184,88+37,184+6); //original code: (96,184,96+12,184+6);
1143 terminx 1623
        G_DrawWeapNum2(SHOTGUN_WEAPON,x,y+6,
1624
                       p->ammo_amount[SHOTGUN_WEAPON],p->max_ammo_amount[SHOTGUN_WEAPON],
1625 terminx 1625
                       (((p->gotweapon & (1<<SHOTGUN_WEAPON)) == 0)*9)+12-18*
1143 terminx 1626
                       (cw == SHOTGUN_WEAPON));
5 Plagman 1627
    }
1628
    if (u&16)
1629
    {
1144 terminx 1630
        if (u != -1) G_PatchStatusBar(88,190,88+37,190+6); //original code: (96,190,96+12,190+6);
1143 terminx 1631
        G_DrawWeapNum2(CHAINGUN_WEAPON,x,y+12,
1632
                       p->ammo_amount[CHAINGUN_WEAPON],p->max_ammo_amount[CHAINGUN_WEAPON],
1625 terminx 1633
                       (((p->gotweapon & (1<<CHAINGUN_WEAPON)) == 0)*9)+12-18*
1143 terminx 1634
                       (cw == CHAINGUN_WEAPON));
5 Plagman 1635
    }
1636
    if (u&32)
1637
    {
1144 terminx 1638
        if (u != -1) G_PatchStatusBar(127,178,127+29,178+6); //original code: (135,178,135+8,178+6);
1143 terminx 1639
        G_DrawWeapNum(RPG_WEAPON,x+39,y,
1640
                      p->ammo_amount[RPG_WEAPON],p->max_ammo_amount[RPG_WEAPON],
1625 terminx 1641
                      (((p->gotweapon & (1<<RPG_WEAPON)) == 0)*9)+12-19*
1143 terminx 1642
                      (cw == RPG_WEAPON));
5 Plagman 1643
    }
1644
    if (u&64)
1645
    {
1144 terminx 1646
        if (u != -1) G_PatchStatusBar(127,184,127+29,184+6); //original code: (135,184,135+8,184+6);
1143 terminx 1647
        G_DrawWeapNum(HANDBOMB_WEAPON,x+39,y+6,
1648
                      p->ammo_amount[HANDBOMB_WEAPON],p->max_ammo_amount[HANDBOMB_WEAPON],
1625 terminx 1649
                      (((!p->ammo_amount[HANDBOMB_WEAPON])|((p->gotweapon & (1<<HANDBOMB_WEAPON)) == 0))*9)+12-19*
1143 terminx 1650
                      ((cw == HANDBOMB_WEAPON) || (cw == HANDREMOTE_WEAPON)));
5 Plagman 1651
    }
1652
    if (u&128)
1653
    {
1144 terminx 1654
        if (u != -1) G_PatchStatusBar(127,190,127+29,190+6); //original code: (135,190,135+8,190+6);
5 Plagman 1655
 
425 terminx 1656
        if (p->subweapon&(1<<GROW_WEAPON))
1143 terminx 1657
            G_DrawWeapNum(SHRINKER_WEAPON,x+39,y+12,
1658
                          p->ammo_amount[GROW_WEAPON],p->max_ammo_amount[GROW_WEAPON],
1625 terminx 1659
                          (((p->gotweapon & (1<<GROW_WEAPON)) == 0)*9)+12-18*
1143 terminx 1660
                          (cw == GROW_WEAPON));
335 terminx 1661
        else
1143 terminx 1662
            G_DrawWeapNum(SHRINKER_WEAPON,x+39,y+12,
1663
                          p->ammo_amount[SHRINKER_WEAPON],p->max_ammo_amount[SHRINKER_WEAPON],
1625 terminx 1664
                          (((p->gotweapon & (1<<SHRINKER_WEAPON)) == 0)*9)+12-18*
1143 terminx 1665
                          (cw == SHRINKER_WEAPON));
5 Plagman 1666
    }
1667
    if (u&256)
1668
    {
1144 terminx 1669
        if (u != -1) G_PatchStatusBar(158,178,162+29,178+6); //original code: (166,178,166+8,178+6);
5 Plagman 1670
 
1143 terminx 1671
        G_DrawWeapNum(DEVISTATOR_WEAPON,x+70,y,
1672
                      p->ammo_amount[DEVISTATOR_WEAPON],p->max_ammo_amount[DEVISTATOR_WEAPON],
1625 terminx 1673
                      (((p->gotweapon & (1<<DEVISTATOR_WEAPON)) == 0)*9)+12-18*
1143 terminx 1674
                      (cw == DEVISTATOR_WEAPON));
5 Plagman 1675
    }
1676
    if (u&512)
1677
    {
1144 terminx 1678
        if (u != -1) G_PatchStatusBar(158,184,162+29,184+6); //original code: (166,184,166+8,184+6);
428 terminx 1679
 
1143 terminx 1680
        G_DrawWeapNum(TRIPBOMB_WEAPON,x+70,y+6,
1681
                      p->ammo_amount[TRIPBOMB_WEAPON],p->max_ammo_amount[TRIPBOMB_WEAPON],
1625 terminx 1682
                      (((p->gotweapon & (1<<TRIPBOMB_WEAPON)) == 0)*9)+12-18*
1143 terminx 1683
                      (cw == TRIPBOMB_WEAPON));
5 Plagman 1684
    }
1685
 
1686
    if (u&65536L)
1687
    {
1144 terminx 1688
        if (u != -1) G_PatchStatusBar(158,190,162+29,190+6); //original code: (166,190,166+8,190+6);
425 terminx 1689
 
1143 terminx 1690
        G_DrawWeapNum(-1,x+70,y+12,
1691
                      p->ammo_amount[FREEZE_WEAPON],p->max_ammo_amount[FREEZE_WEAPON],
1625 terminx 1692
                      (((p->gotweapon & (1<<FREEZE_WEAPON)) == 0)*9)+12-18*
1143 terminx 1693
                      (cw == FREEZE_WEAPON));
5 Plagman 1694
    }
1695
}
1696
 
2944 helixhorne 1697
// yofs: in hud_scale-independent, (<<16)-scaled, 0-200-normalized y coords.
1698
static void G_DrawDigiNum_(int32_t x, int32_t yofs, int32_t y, int32_t n, char s, int32_t cs)
5 Plagman 1699
{
3836 hendricks2 1700
    if (!(cs & ROTATESPRITE_FULL16))
5 Plagman 1701
    {
3836 hendricks2 1702
        x <<= 16;
1703
        y <<= 16;
5 Plagman 1704
    }
1705
 
3836 hendricks2 1706
    G_DrawTXDigiNumZ(DIGITALNUM, sbarx16(x), yofs + sbary16(y), n, s, 0, cs|ROTATESPRITE_FULL16, 0, 0, xdim-1, ydim-1, sbarsc(65536L));
5 Plagman 1707
}
1708
 
2944 helixhorne 1709
static inline void G_DrawDigiNum(int32_t x, int32_t y, int32_t n, char s, int32_t cs)
1710
{
1711
    G_DrawDigiNum_(x, 0, y, n, s, cs);
1712
}
1713
 
1658 terminx 1714
void G_DrawTXDigiNumZ(int32_t starttile, int32_t x,int32_t y,int32_t n,int32_t s,int32_t pal,
1715
                      int32_t cs,int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t z)
5 Plagman 1716
{
2086 helixhorne 1717
    char b[12];
3836 hendricks2 1718
    Bsprintf(b,"%d",n);
5 Plagman 1719
 
3836 hendricks2 1720
    if (!(cs & ROTATESPRITE_FULL16))
5 Plagman 1721
    {
3836 hendricks2 1722
        x <<= 16;
1723
        y <<= 16;
5 Plagman 1724
    }
1725
 
3836 hendricks2 1726
    G_ScreenText(starttile, x, y, z, 0, 0, b, s, pal, cs|2|ROTATESPRITE_FULL16, 0, (4<<16), (8<<16), (1<<16), 0, TEXT_XCENTER|TEXT_DIGITALNUMBER, x1, y1, x2, y2);
5 Plagman 1727
}
1728
 
2566 helixhorne 1729
static void G_DrawAltDigiNum(int32_t x, int32_t y, int32_t n, char s, int32_t cs)
934 terminx 1730
{
1205 terminx 1731
    int32_t i, j = 0, k, p, c;
2086 helixhorne 1732
    char b[12];
1205 terminx 1733
    int32_t rev = (x < 0);
1734
    int32_t shd = (y < 0);
934 terminx 1735
 
2896 helixhorne 1736
    const int32_t sbscale = sbarsc(65536);
1737
 
934 terminx 1738
    if (rev) x = -x;
946 terminx 1739
    if (shd) y = -y;
934 terminx 1740
 
2086 helixhorne 1741
    i = Bsprintf(b,"%d",n);
934 terminx 1742
 
1229 terminx 1743
    for (k=i-1; k>=0; k--)
934 terminx 1744
    {
2566 helixhorne 1745
        p = althud_numbertile + b[k]-'0';
4623 terminx 1746
        j += tilesiz[p].x+1;
934 terminx 1747
    }
1748
    c = x-(j>>1);
1749
 
1750
    if (rev)
1751
    {
1229 terminx 1752
        for (k=0; k<i; k++)
934 terminx 1753
        {
2566 helixhorne 1754
            p = althud_numbertile + b[k]-'0';
3346 terminx 1755
            if (shd && getrendermode() >= REND_POLYMOST && althud_shadows)
3837 hendricks2 1756
                rotatesprite_fs(sbarxr(c+j-1),sbary(y+1),sbscale,0,p,127,4,cs|POLYMOSTTRANS2);
2896 helixhorne 1757
            rotatesprite_fs(sbarxr(c+j),sbary(y),sbscale,0,p,s,althud_numberpal,cs);
4623 terminx 1758
            j -= tilesiz[p].x+1;
934 terminx 1759
        }
1760
        return;
1761
    }
2566 helixhorne 1762
 
934 terminx 1763
    j = 0;
1229 terminx 1764
    for (k=0; k<i; k++)
934 terminx 1765
    {
2566 helixhorne 1766
        p = althud_numbertile + b[k]-'0';
3346 terminx 1767
        if (shd && getrendermode() >= REND_POLYMOST && althud_shadows)
3837 hendricks2 1768
            rotatesprite_fs(sbarx(c+j+1),sbary(y+1),sbscale,0,p,127,4,cs|POLYMOSTTRANS2);
2896 helixhorne 1769
        rotatesprite_fs(sbarx(c+j),sbary(y),sbscale,0,p,s,althud_numberpal,cs);
4623 terminx 1770
        j += tilesiz[p].x+1;
934 terminx 1771
    }
1772
}
1773
 
3676 hendricks2 1774
static int32_t invensc(int32_t maximum) // used to reposition the inventory icon selector as the HUD scales
1775
{
1776
    return scale(maximum << 16, ud.statusbarscale - 36, 100 - 36);
1777
}
1778
 
2896 helixhorne 1779
static void G_DrawInventory(const DukePlayer_t *p)
5 Plagman 1780
{
3676 hendricks2 1781
    int32_t n, j = 0, x = 0, y;
5 Plagman 1782
 
1572 terminx 1783
    n = (p->inv_amount[GET_JETPACK] > 0)<<3;
335 terminx 1784
    if (n&8) j++;
1572 terminx 1785
    n |= (p->inv_amount[GET_SCUBA] > 0)<<5;
335 terminx 1786
    if (n&32) j++;
1572 terminx 1787
    n |= (p->inv_amount[GET_STEROIDS] > 0)<<1;
335 terminx 1788
    if (n&2) j++;
1572 terminx 1789
    n |= (p->inv_amount[GET_HOLODUKE] > 0)<<2;
335 terminx 1790
    if (n&4) j++;
1572 terminx 1791
    n |= (p->inv_amount[GET_FIRSTAID] > 0);
335 terminx 1792
    if (n&1) j++;
1572 terminx 1793
    n |= (p->inv_amount[GET_HEATS] > 0)<<4;
335 terminx 1794
    if (n&16) j++;
1572 terminx 1795
    n |= (p->inv_amount[GET_BOOTS] > 0)<<6;
335 terminx 1796
    if (n&64) j++;
5 Plagman 1797
 
3676 hendricks2 1798
    x = (160-(j*11))<<16; // nearly center
5 Plagman 1799
 
1800
    j = 0;
1801
 
3676 hendricks2 1802
    if (ud.screen_size < 8) // mini-HUDs or no HUD
1803
    {
1804
        y = 172<<16;
5 Plagman 1805
 
4595 terminx 1806
        if (ud.screen_size == 4 && ud.althud == 1) // modern mini-HUD
4623 terminx 1807
            y -= invensc(tilesiz[BIGALPHANUM].y+10); // slide on the y-axis
3676 hendricks2 1808
    }
1809
    else // full HUD
1810
    {
4623 terminx 1811
        y = (200<<16) - (sbarsc(tilesiz[BOTTOMSTATUSBAR].y<<16) + (12<<16) + (tilesiz[BOTTOMSTATUSBAR].y<<(16-1)));
3676 hendricks2 1812
 
1813
        if (!ud.statusbarmode) // original non-overlay mode
4623 terminx 1814
            y += sbarsc(tilesiz[BOTTOMSTATUSBAR].y<<16)>>1; // account for the viewport y-size as the HUD scales
3676 hendricks2 1815
    }
1816
 
1817
    if (ud.screen_size == 4 && !ud.althud) // classic mini-HUD
1818
        x += invensc(ud.multimode > 1 ? 56 : 65); // slide on the x-axis
1819
 
333 terminx 1820
    while (j <= 9)
5 Plagman 1821
    {
333 terminx 1822
        if (n&(1<<j))
5 Plagman 1823
        {
333 terminx 1824
            switch (n&(1<<j))
5 Plagman 1825
            {
1632 terminx 1826
            case 1:
3676 hendricks2 1827
                rotatesprite_win(x,y,65536L,0,FIRSTAID_ICON,0,0,2+16);
337 terminx 1828
                break;
1632 terminx 1829
            case 2:
3676 hendricks2 1830
                rotatesprite_win(x+(1<<16),y,65536L,0,STEROIDS_ICON,0,0,2+16);
337 terminx 1831
                break;
1632 terminx 1832
            case 4:
3676 hendricks2 1833
                rotatesprite_win(x+(2<<16),y,65536L,0,HOLODUKE_ICON,0,0,2+16);
337 terminx 1834
                break;
1632 terminx 1835
            case 8:
3676 hendricks2 1836
                rotatesprite_win(x,y,65536L,0,JETPACK_ICON,0,0,2+16);
337 terminx 1837
                break;
1632 terminx 1838
            case 16:
3676 hendricks2 1839
                rotatesprite_win(x,y,65536L,0,HEAT_ICON,0,0,2+16);
337 terminx 1840
                break;
1632 terminx 1841
            case 32:
3676 hendricks2 1842
                rotatesprite_win(x,y,65536L,0,AIRTANK_ICON,0,0,2+16);
337 terminx 1843
                break;
1844
            case 64:
3676 hendricks2 1845
                rotatesprite_win(x,y-(1<<16),65536L,0,BOOT_ICON,0,0,2+16);
337 terminx 1846
                break;
5 Plagman 1847
            }
1848
 
3676 hendricks2 1849
            x += 22<<16;
5 Plagman 1850
 
331 terminx 1851
            if (p->inven_icon == j+1)
3676 hendricks2 1852
                rotatesprite_win(x-(2<<16),y+(19<<16),65536L,1024,ARROW,-32,0,2+16);
5 Plagman 1853
        }
1854
 
1855
        j++;
1856
    }
1857
}
1858
 
1143 terminx 1859
void G_DrawFrags(void)
5 Plagman 1860
{
1205 terminx 1861
    int32_t i, j = 0;
2896 helixhorne 1862
    const int32_t orient = 2+8+16+64;
5 Plagman 1863
 
2379 helixhorne 1864
    for (TRAVERSE_CONNECT(i))
2896 helixhorne 1865
        if (i > j)
1866
            j = i;
5 Plagman 1867
 
2896 helixhorne 1868
    for (i=0; i<=(j>>2); i++)
1869
        rotatesprite_fs(0,(8*i)<<16,65600, 0, FRAGBAR, 0,0,orient);
5 Plagman 1870
 
2379 helixhorne 1871
    for (TRAVERSE_CONNECT(i))
5 Plagman 1872
    {
2896 helixhorne 1873
        const DukePlayer_t *ps = g_player[i].ps;
1874
        minitext(21+(73*(i&3)), 2+((i&28)<<1), g_player[i].user_name, ps->palookup, 2+8+16);
1875
        Bsprintf(tempbuf, "%d", ps->frag-ps->fraggedself);
1876
        minitext(17+50+(73*(i&3)), 2+((i&28)<<1), tempbuf, ps->palookup, 2+8+16);
5 Plagman 1877
    }
1878
}
1879
 
2896 helixhorne 1880
static int32_t G_GetInvAmount(const DukePlayer_t *p)
1881
{
1882
    switch (p->inven_icon)
1883
    {
3115 terminx 1884
    case ICON_FIRSTAID:
2896 helixhorne 1885
        return p->inv_amount[GET_FIRSTAID];
3115 terminx 1886
    case ICON_STEROIDS:
2896 helixhorne 1887
        return ((p->inv_amount[GET_STEROIDS]+3)>>2);
3115 terminx 1888
    case ICON_HOLODUKE:
2896 helixhorne 1889
        return ((p->inv_amount[GET_HOLODUKE]+15)/24);
3115 terminx 1890
    case ICON_JETPACK:
2896 helixhorne 1891
        return ((p->inv_amount[GET_JETPACK]+15)>>4);
3115 terminx 1892
    case ICON_HEATS:
2896 helixhorne 1893
        return p->inv_amount[GET_HEATS]/12;
3115 terminx 1894
    case ICON_SCUBA:
2896 helixhorne 1895
        return ((p->inv_amount[GET_SCUBA]+63)>>6);
3115 terminx 1896
    case ICON_BOOTS:
2896 helixhorne 1897
        return (p->inv_amount[GET_BOOTS]>>1);
1898
    }
261 terminx 1899
 
2896 helixhorne 1900
    return -1;
1901
}
1902
 
1903
static int32_t G_GetInvOn(const DukePlayer_t *p)
1904
{
1905
    switch (p->inven_icon)
1906
    {
3115 terminx 1907
    case ICON_HOLODUKE:
2896 helixhorne 1908
        return p->holoduke_on;
3115 terminx 1909
    case ICON_JETPACK:
2896 helixhorne 1910
        return p->jetpack_on;
3115 terminx 1911
    case ICON_HEATS:
2896 helixhorne 1912
        return p->heat_on;
1913
    }
1914
 
1915
    return 0x80000000;
1916
}
1917
 
3556 helixhorne 1918
static int32_t G_GetMorale(int32_t p_i, int32_t snum)
1919
{
1920
#if !defined LUNATIC
1921
    return Gv_GetVarByLabel("PLR_MORALE",-1, p_i, snum);
1922
#else
3557 helixhorne 1923
    UNREFERENCED_PARAMETER(p_i);
1924
    UNREFERENCED_PARAMETER(snum);
3556 helixhorne 1925
    return -1;
1926
#endif
1927
}
1928
 
4595 terminx 1929
static inline void rotatesprite_althud(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t picnum,int8_t dashade, char dapalnum, int32_t dastat)
1930
{
1931
        if (getrendermode() >= REND_POLYMOST && althud_shadows)
1932
                rotatesprite_(sbarx(sx+1), sbary(sy+1), z, a, picnum, 127, 4, dastat + POLYMOSTTRANS2, 0, 0, 0, 0, xdim - 1, ydim - 1);
1933
        rotatesprite_(sbarx(sx), sbary(sy), z, a, picnum, dashade, dapalnum, dastat, 0, 0, 0, 0, xdim - 1, ydim - 1);
1934
}
1935
 
1936
static inline void rotatesprite_althudr(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t picnum, int8_t dashade, char dapalnum, int32_t dastat)
1937
{
1938
        if (getrendermode() >= REND_POLYMOST && althud_shadows)
1939
                rotatesprite_(sbarxr(sx + 1), sbary(sy + 1), z, a, picnum, 127, 4, dastat + POLYMOSTTRANS2, 0, 0, 0, 0, xdim - 1, ydim - 1);
1940
        rotatesprite_(sbarxr(sx), sbary(sy), z, a, picnum, dashade, dapalnum, dastat, 0, 0, 0, 0, xdim - 1, ydim - 1);
1941
}
1942
 
1205 terminx 1943
static void G_DrawStatusBar(int32_t snum)
5 Plagman 1944
{
2896 helixhorne 1945
    const DukePlayer_t *const p = g_player[snum].ps;
2900 helixhorne 1946
    int32_t i, j, o, u;
1205 terminx 1947
    int32_t permbit = 0;
5 Plagman 1948
 
4249 hendricks2 1949
#ifdef SPLITSCREEN_MOD_HACKS
2944 helixhorne 1950
    const int32_t ss = g_fakeMultiMode ? 4 : ud.screen_size;
2900 helixhorne 1951
    const int32_t althud = g_fakeMultiMode ? 0 : ud.althud;
4249 hendricks2 1952
#else
1953
    const int32_t ss = ud.screen_size;
1954
    const int32_t althud = ud.althud;
1955
#endif
2900 helixhorne 1956
 
4623 terminx 1957
    const int32_t SBY = (200-tilesiz[BOTTOMSTATUSBAR].y);
532 terminx 1958
 
2896 helixhorne 1959
    const int32_t sb15 = sbarsc(32768), sb15h = sbarsc(49152);
1960
    const int32_t sb16 = sbarsc(65536);
1961
 
1962
    static int32_t item_icons[8];
1963
 
1964
    if (ss < 4)
1965
        return;
1966
 
1967
    if (item_icons[0] == 0)
1968
    {
1969
        int32_t iicons[8] = { -1, FIRSTAID_ICON, STEROIDS_ICON, HOLODUKE_ICON,
1970
                              JETPACK_ICON, HEAT_ICON, AIRTANK_ICON, BOOT_ICON };
1971
        Bmemcpy(item_icons, iicons, sizeof(item_icons));
1972
    }
1973
 
3346 terminx 1974
    if (getrendermode() >= REND_POLYMOST) pus = NUMPAGES;   // JBF 20040101: always redraw in GL
5 Plagman 1975
 
2901 helixhorne 1976
    if ((g_netServer || ud.multimode > 1) && ((GametypeFlags[ud.coop] & GAMETYPE_FRAGBAR) || g_fakeMultiMode))
5 Plagman 1977
    {
1978
        if (pus)
1143 terminx 1979
            G_DrawFrags();
5 Plagman 1980
        else
1981
        {
2379 helixhorne 1982
            for (TRAVERSE_CONNECT(i))
1983
                if (g_player[i].ps->frag != sbar.frag[i])
1984
                {
1985
                    G_DrawFrags();
1986
                    break;
1987
                }
331 terminx 1988
 
5 Plagman 1989
        }
2379 helixhorne 1990
        for (TRAVERSE_CONNECT(i))
1991
            if (i != myconnectindex)
1992
                sbar.frag[i] = g_player[i].ps->frag;
5 Plagman 1993
    }
1994
 
1995
    if (ss == 4)   //DRAW MINI STATUS BAR:
1996
    {
2900 helixhorne 1997
        if (althud)
934 terminx 1998
        {
2900 helixhorne 1999
            // ALTERNATIVE STATUS BAR
2000
 
4595 terminx 2001
                        int32_t hudoffset = althud == 2 ? 32 : 200;
1205 terminx 2002
            static int32_t ammo_sprites[MAX_WEAPONS];
934 terminx 2003
 
2896 helixhorne 2004
            if (ammo_sprites[0] == 0)
934 terminx 2005
            {
2006
                /* this looks stupid but it lets us initialize static memory to dynamic values
2007
                   these values can be changed from the CONs with dynamic tile remapping
2008
                   but we don't want to have to recreate the values in memory every time
2009
                   the HUD is drawn */
2010
 
2896 helixhorne 2011
                int32_t asprites[MAX_WEAPONS] = { BOOTS, AMMO, SHOTGUNAMMO, BATTERYAMMO,
2012
                                                  RPGAMMO, HBOMBAMMO, CRYSTALAMMO, DEVISTATORAMMO,
1207 terminx 2013
                                                  TRIPBOMBSPRITE, FREEZEAMMO+1, HBOMBAMMO, GROWAMMO
2014
                                                };
2896 helixhorne 2015
                Bmemcpy(ammo_sprites, asprites, sizeof(ammo_sprites));
934 terminx 2016
            }
2017
 
2896 helixhorne 2018
//            rotatesprite_fs(sbarx(5+1),sbary(200-25+1),sb15h,0,SIXPAK,0,4,10+16+1+32);
2019
//            rotatesprite_fs(sbarx(5),sbary(200-25),sb15h,0,SIXPAK,0,0,10+16);
4595 terminx 2020
            rotatesprite_althud(2,hudoffset-21,sb15h,0,COLA,0,0,10+16+256);
935 terminx 2021
 
934 terminx 2022
            if (sprite[p->i].pal == 1 && p->last_extra < 2)
4595 terminx 2023
                G_DrawAltDigiNum(40,-(hudoffset-22),1,-16,10+16+256);
953 terminx 2024
            else if (!althud_flashing || p->last_extra > (p->max_player_health>>2) || totalclock&32)
1089 terminx 2025
            {
1205 terminx 2026
                int32_t s = -8;
1089 terminx 2027
                if (althud_flashing && p->last_extra > p->max_player_health)
2028
                    s += (sintable[(totalclock<<5)&2047]>>10);
4595 terminx 2029
                G_DrawAltDigiNum(40,-(hudoffset-22),p->last_extra,s,10+16+256);
1089 terminx 2030
            }
934 terminx 2031
 
4595 terminx 2032
            rotatesprite_althud(62,hudoffset-25,sb15h,0,SHIELD,0,0,10+16+256);
934 terminx 2033
 
1490 terminx 2034
            {
3556 helixhorne 2035
                int32_t lAmount = G_GetMorale(p->i, snum);
2036
                if (lAmount == -1)
2037
                    lAmount = p->inv_amount[GET_SHIELD];
4595 terminx 2038
                G_DrawAltDigiNum(105,-(hudoffset-22),lAmount,-16,10+16+256);
1490 terminx 2039
            }
4595 terminx 2040
 
4650 terminx 2041
            i = (tilesiz[ammo_sprites[p->curr_weapon]].y > 50) ? 16384 : 32768;
1658 terminx 2042
 
4595 terminx 2043
            rotatesprite_althudr(57,hudoffset-15,sbarsc(i),0,ammo_sprites[p->curr_weapon],0,0,10+512);
934 terminx 2044
 
4650 terminx 2045
            if (PWEAPON(snum, p->curr_weapon, WorksLike) == HANDREMOTE_WEAPON) i = HANDBOMB_WEAPON;
934 terminx 2046
            else i = p->curr_weapon;
1658 terminx 2047
 
4650 terminx 2048
            if (PWEAPON(snum, p->curr_weapon, WorksLike) != KNEE_WEAPON &&
962 terminx 2049
                    (!althud_flashing || totalclock&32 || p->ammo_amount[i] > (p->max_ammo_amount[i]/10)))
4595 terminx 2050
                G_DrawAltDigiNum(-20,-(hudoffset-22),p->ammo_amount[i],-16,10+16+512);
934 terminx 2051
 
941 terminx 2052
            o = 102;
934 terminx 2053
            permbit = 0;
2054
 
2055
            if (p->inven_icon)
2056
            {
2896 helixhorne 2057
                const int32_t orient = 10+16+permbit+256;
2058
 
3115 terminx 2059
                i = ((unsigned)p->inven_icon < ICON_MAX) ? item_icons[p->inven_icon] : -1;
4595 terminx 2060
 
934 terminx 2061
                if (i >= 0)
4595 terminx 2062
                    rotatesprite_althud(231-o,hudoffset-21-2,sb16,0,i,0,0,orient);
934 terminx 2063
 
3346 terminx 2064
                if (getrendermode() >= REND_POLYMOST && althud_shadows)
4595 terminx 2065
                    minitextshade(292-30-o+1,hudoffset-10-3+1,"%",127,4, POLYMOSTTRANS+orient+ROTATESPRITE_MAX);
2066
                minitext(292-30-o,hudoffset-10-3,"%",6, orient+ROTATESPRITE_MAX);
934 terminx 2067
 
2896 helixhorne 2068
                i = G_GetInvAmount(p);
2069
                j = G_GetInvOn(p);
2070
 
4595 terminx 2071
                G_DrawInvNum(-(284-30-o),0,hudoffset-6-3,(uint8_t)i,0,10+permbit+256);
2896 helixhorne 2072
 
934 terminx 2073
                if (j > 0)
2074
                {
3346 terminx 2075
                    if (getrendermode() >= REND_POLYMOST && althud_shadows)
4595 terminx 2076
                        minitextshade(288-30-o+1,hudoffset-20-3+1,"On",127,4, POLYMOSTTRANS+orient+ROTATESPRITE_MAX);
2077
                    minitext(288-30-o,hudoffset-20-3,"On",0, orient+ROTATESPRITE_MAX);
934 terminx 2078
                }
1205 terminx 2079
                else if ((uint32_t)j != 0x80000000)
934 terminx 2080
                {
3346 terminx 2081
                    if (getrendermode() >= REND_POLYMOST && althud_shadows)
4595 terminx 2082
                        minitextshade(284-30-o+1,hudoffset-20-3+1,"Off",127,4, POLYMOSTTRANS+orient+ROTATESPRITE_MAX);
2083
                    minitext(284-30-o,hudoffset-20-3,"Off",2, orient+ROTATESPRITE_MAX);
934 terminx 2084
                }
1677 terminx 2085
 
3115 terminx 2086
                if (p->inven_icon >= ICON_SCUBA)
934 terminx 2087
                {
3346 terminx 2088
                    if (getrendermode() >= REND_POLYMOST && althud_shadows)
4595 terminx 2089
                        minitextshade(284-35-o+1,hudoffset-20-3+1,"Auto",127,4, POLYMOSTTRANS+orient+ROTATESPRITE_MAX);
2090
                    minitext(284-35-o,hudoffset-20-3,"Auto",2, orient+ROTATESPRITE_MAX);
934 terminx 2091
                }
2092
            }
4602 terminx 2093
 
2094
            if (ud.althud == 2)
2095
                hudoffset += 40;
2096
 
2097
            if (p->got_access&1) rotatesprite_althudr(39, hudoffset-43, sb15, 0, ACCESSCARD, 0, 0, 10+16+512);
2098
            if (p->got_access&4) rotatesprite_althudr(34, hudoffset-41, sb15, 0, ACCESSCARD, 0, 23, 10+16+512);
2099
            if (p->got_access&2) rotatesprite_althudr(29, hudoffset-39, sb15, 0, ACCESSCARD, 0, 21, 10+16+512);
934 terminx 2100
        }
2900 helixhorne 2101
        else
2102
        {
2103
            // ORIGINAL MINI STATUS BAR
4249 hendricks2 2104
            int32_t orient = 2+8+16+256, yofssh=0;
1658 terminx 2105
 
4249 hendricks2 2106
#ifdef SPLITSCREEN_MOD_HACKS
2107
            int32_t yofs=0;
2108
 
2944 helixhorne 2109
            if (g_fakeMultiMode)
2110
            {
2111
                const int32_t sidebyside = (ud.screen_size!=0);
2112
 
2113
                if (sidebyside && snum==1)
2114
                {
2115
                    orient |= RS_CENTERORIGIN;
2116
                }
2117
                else if (!sidebyside && snum==0)
2118
                {
2119
                    yofs = -100;
2120
                    yofssh = yofs<<16;
2121
                }
2122
            }
4249 hendricks2 2123
#endif
2944 helixhorne 2124
 
2125
            rotatesprite_fs(sbarx(5), yofssh+sbary(200-28), sb16, 0, HEALTHBOX, 0, 21, orient);
2900 helixhorne 2126
            if (p->inven_icon)
2944 helixhorne 2127
                rotatesprite_fs(sbarx(69), yofssh+sbary(200-30), sb16, 0, INVENTORYBOX, 0, 21, orient);
5 Plagman 2128
 
2902 helixhorne 2129
            // health
2935 helixhorne 2130
            {
2131
                int32_t health = (sprite[p->i].pal == 1 && p->last_extra < 2) ? 1 : p->last_extra;
2944 helixhorne 2132
                G_DrawDigiNum_(20, yofssh, 200-17, health, -16, orient);
2935 helixhorne 2133
            }
5 Plagman 2134
 
2944 helixhorne 2135
            rotatesprite_fs(sbarx(37), yofssh+sbary(200-28), sb16, 0, AMMOBOX, 0, 21, orient);
5 Plagman 2136
 
4650 terminx 2137
            if (PWEAPON(snum, p->curr_weapon, WorksLike) == HANDREMOTE_WEAPON)
2944 helixhorne 2138
                i = HANDBOMB_WEAPON;
2139
            else
2140
                i = p->curr_weapon;
2141
            G_DrawDigiNum_(53, yofssh, 200-17, p->ammo_amount[i], -16, orient);
5 Plagman 2142
 
2900 helixhorne 2143
            o = 158;
2144
            permbit = 0;
2145
            if (p->inven_icon)
2146
            {
2935 helixhorne 2147
//                orient |= permbit;
5 Plagman 2148
 
3115 terminx 2149
                i = ((unsigned)p->inven_icon < ICON_MAX) ? item_icons[p->inven_icon] : -1;
2900 helixhorne 2150
                if (i >= 0)
2944 helixhorne 2151
                    rotatesprite_fs(sbarx(231-o), yofssh+sbary(200-21), sb16, 0, i, 0, 0, orient);
5 Plagman 2152
 
2935 helixhorne 2153
                // scale by status bar size
2154
                orient |= ROTATESPRITE_MAX;
2896 helixhorne 2155
 
2944 helixhorne 2156
                minitext_yofs = yofssh;
2157
                minitext(292-30-o, 190, "%", 6, orient);
2902 helixhorne 2158
 
2900 helixhorne 2159
                i = G_GetInvAmount(p);
2160
                j = G_GetInvOn(p);
2896 helixhorne 2161
 
2944 helixhorne 2162
                G_DrawInvNum(284-30-o, yofssh, 200-6, (uint8_t)i, 0, orient&~16);
2896 helixhorne 2163
 
2900 helixhorne 2164
                if (j > 0)
2944 helixhorne 2165
                    minitext(288-30-o, 180, "On", 0, orient);
2900 helixhorne 2166
                else if ((uint32_t)j != 0x80000000)
2944 helixhorne 2167
                    minitext(284-30-o, 180, "Off", 2, orient);
2896 helixhorne 2168
 
3115 terminx 2169
                if (p->inven_icon >= ICON_SCUBA)
2944 helixhorne 2170
                    minitext(284-35-o, 180, "Auto", 2, orient);
2171
 
2172
                minitext_yofs = 0;
2900 helixhorne 2173
            }
5 Plagman 2174
        }
2900 helixhorne 2175
 
5 Plagman 2176
        return;
2177
    }
2178
 
2179
    //DRAW/UPDATE FULL STATUS BAR:
2180
 
335 terminx 2181
    if (pus)
2182
    {
2183
        pus = 0;
2184
        u = -1;
2185
    }
331 terminx 2186
    else u = 0;
5 Plagman 2187
 
335 terminx 2188
    if (sbar.frag[myconnectindex] != p->frag)
2189
    {
2190
        sbar.frag[myconnectindex] = p->frag;
2191
        u |= 32768;
2192
    }
2193
    if (sbar.got_access != p->got_access)
2194
    {
2195
        sbar.got_access = p->got_access;
2196
        u |= 16384;
2197
    }
261 terminx 2198
 
423 terminx 2199
    if (sbar.last_extra != p->last_extra)
5 Plagman 2200
    {
423 terminx 2201
        sbar.last_extra = p->last_extra;
2202
        u |= 1;
2203
    }
2204
 
2205
    {
3556 helixhorne 2206
        int32_t lAmount = G_GetMorale(p->i, snum);
331 terminx 2207
        if (lAmount == -1)
2896 helixhorne 2208
            lAmount = p->inv_amount[GET_SHIELD];
2209
        if (sbar.inv_amount[GET_SHIELD] != lAmount)
5 Plagman 2210
        {
2896 helixhorne 2211
            sbar.inv_amount[GET_SHIELD] = lAmount;
2212
            u |= 2;
5 Plagman 2213
        }
2214
    }
261 terminx 2215
 
335 terminx 2216
    if (sbar.curr_weapon != p->curr_weapon)
2217
    {
2218
        sbar.curr_weapon = p->curr_weapon;