Subversion Repositories eduke32

Rev

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