Subversion Repositories eduke32

Rev

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