Subversion Repositories eduke32

Rev

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