Subversion Repositories eduke32

Rev

Rev 8658 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5614 terminx 1
//-------------------------------------------------------------------------
2
/*
3
Copyright (C) 2016 EDuke32 developers and contributors
4
 
5
This file is part of EDuke32.
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
19
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20
*/
21
//-------------------------------------------------------------------------
22
 
23
#include "duke3d.h"
24
#include "compat.h"
25
#include "sbar.h"
6209 hendricks2 26
#include "menus.h"
5614 terminx 27
 
8659 hendricks2 28
void G_InitText()
29
{
30
    // check if the minifont will support lowercase letters (3136-3161)
31
    // there is room for them in tiles012.art between "[\]^_." and "{|}~"
32
    minitext_lowercase = 1;
33
 
34
    for (int i = MINIFONT + ('a'-'!'); minitext_lowercase && i < MINIFONT + ('z'-'!') + 1; ++i)
35
        minitext_lowercase &= (int)tileLoad(i);
36
}
37
 
5614 terminx 38
// assign the character's tilenum
8658 hendricks2 39
int32_t G_GetStringTile(int32_t font, char c, int32_t f)
5614 terminx 40
{
41
    if (f & TEXT_DIGITALNUMBER)
8658 hendricks2 42
        return c - '0' + font;
5614 terminx 43
    else if (f & (TEXT_BIGALPHANUM|TEXT_GRAYFONT))
44
    {
45
        int32_t offset = (f & TEXT_GRAYFONT) ? 26 : 0;
46
 
8658 hendricks2 47
        if (c >= '0' && c <= '9')
48
            return c - '0' + font + ((f & TEXT_GRAYFONT) ? 26 : -10);
49
        else if (c >= 'a' && c <= 'z')
50
            return c - 'a' + font + ((f & TEXT_GRAYFONT) ? -26 : 26);
51
        else if (c >= 'A' && c <= 'Z')
52
            return c - 'A' + font;
53
        else switch (c)
5614 terminx 54
        {
55
        case '_':
56
        case '-':
57
            return font - (11 + offset);
58
        case '.':
59
            return font + (BIGPERIOD - (BIGALPHANUM + offset));
60
        case ',':
61
            return font + (BIGCOMMA - (BIGALPHANUM + offset));
62
        case '!':
63
            return font + (BIGX_ - (BIGALPHANUM + offset));
64
        case '?':
65
            return font + (BIGQ - (BIGALPHANUM + offset));
66
        case ';':
67
            return font + (BIGSEMI - (BIGALPHANUM + offset));
68
        case ':':
69
            return font + (BIGCOLIN - (BIGALPHANUM + offset));
70
        case '\\':
71
        case '/':
72
            return font + (68 - offset); // 3008-2940
73
        case '%':
74
            return font + (69 - offset); // 3009-2940
75
        case '`':
76
        case '\"': // could be better hacked in
77
        case '\'':
78
            return font + (BIGAPPOS - (BIGALPHANUM + offset));
8658 hendricks2 79
 
80
        case '\x7F':
81
            return font;
5614 terminx 82
            break;
8658 hendricks2 83
 
84
        case '\n':
85
            return SCREENTEXT_NEWLINE;
6684 hendricks2 86
        case '\t':
8658 hendricks2 87
            return SCREENTEXT_TAB;
6684 hendricks2 88
        case ' ':
8658 hendricks2 89
        default: // unknown character
90
            return SCREENTEXT_SPACE;
5614 terminx 91
        }
92
    }
93
    else
8658 hendricks2 94
        return c - '!' + font; // uses ASCII order
5614 terminx 95
}
96
 
8658 hendricks2 97
uint32_t G_ScreenTextFromString(ScreenTextGlyph_t * const textbuf, char const * str, char const * const end, int32_t font, int32_t flags)
98
{
99
    ScreenTextGlyph_t * text = textbuf;
100
    char c;
101
 
102
    while (str < end && (c = *str))
103
    {
104
        // handle escape sequences
105
        if (c == '^' && str + 1 < end && Bisdigit(*(str + 1)) && !(flags & TEXT_LITERALESCAPE))
106
        {
107
            char smallbuf[4];
108
 
109
            ++str;
110
            smallbuf[0] = *str;
111
 
112
            ++str;
113
            if (str < end && Bisdigit(*str))
114
            {
115
                smallbuf[1] = *str;
116
                smallbuf[2] = '\0';
117
                ++str;
118
            }
119
            else
120
                smallbuf[1] = '\0';
121
 
122
            if (!(flags & TEXT_IGNOREESCAPE))
123
            {
124
                uint8_t const pal = Batoi(smallbuf);
125
                *text++ = SCREENTEXT_PALCHANGE | pal;
126
            }
127
 
128
            continue;
129
        }
130
 
131
        // handle case bits
132
        if (flags & TEXT_UPPERCASE)
133
        {
134
            if (flags & TEXT_INVERTCASE) // optimization...?
135
            { // v^ important that these two ifs remain separate due to the else below
136
                if (Bisupper(c))
137
                    c = Btolower(c);
138
            }
139
            else if (Bislower(c))
140
                c = Btoupper(c);
141
        }
142
        else if (flags & TEXT_INVERTCASE)
143
        {
144
            if (Bisupper(c))
145
                c = Btolower(c);
146
            else if (Bislower(c))
147
                c = Btoupper(c);
148
        }
149
 
150
        if ((flags & TEXT_CONSTWIDTHNUMS) && c >= '0' && c <= '9')
151
            *text++ = SCREENTEXT_CONSTWIDTH;
152
 
153
        if (c == '\n')
154
            *text++ = SCREENTEXT_NEWLINE;
155
        else if (c == '\t')
156
            *text++ = SCREENTEXT_TAB;
157
        else if (c == ' ')
158
            *text++ = SCREENTEXT_SPACE;
159
        else
160
            *text++ = G_GetStringTile(font, c, flags);
161
 
162
        ++str;
163
    }
164
 
165
    *text = 0;
166
 
167
    return text - textbuf;
168
}
169
 
8656 hendricks2 170
void G_SetScreenTextEmpty(vec2_t & empty, int32_t font, int32_t f)
171
{
172
    if (f & (TEXT_INTERNALSPACE|TEXT_TILESPACE))
173
    {
174
        char space = '.'; // this is subject to change as an implementation detail
175
        if (f & TEXT_TILESPACE)
176
            space = '\x7F'; // tile after '~'
8658 hendricks2 177
        uint32_t const tile = G_GetStringTile(font, space, f);
178
        Bassert(tile < MAXTILES);
8656 hendricks2 179
 
180
        empty.x += tilesiz[tile].x << 16;
181
    }
182
 
183
    if (f & (TEXT_INTERNALLINE|TEXT_TILELINE))
184
    {
185
        char line = 'A'; // this is subject to change as an implementation detail
186
        if (f & TEXT_TILELINE)
187
            line = '\x7F'; // tile after '~'
8658 hendricks2 188
        uint32_t const tile = G_GetStringTile(font, line, f);
189
        Bassert(tile < MAXTILES);
8656 hendricks2 190
 
191
        empty.y += tilesiz[tile].y << 16;
192
    }
193
}
194
 
6210 hendricks2 195
void G_PrintGameText(int32_t tile, int32_t x, int32_t y, const char *t,
196
                     int32_t s, int32_t p, int32_t o,
197
                     int32_t x1, int32_t y1, int32_t x2, int32_t y2,
198
                     int32_t z, int32_t a)
5614 terminx 199
{
8650 hendricks2 200
    int32_t f = TEXT_CONSTWIDTHNUMS;
5614 terminx 201
 
202
    if (t == NULL)
6210 hendricks2 203
        return;
5614 terminx 204
 
205
    if (!(o & ROTATESPRITE_FULL16))
206
    {
207
        x <<= 16;
208
        y <<= 16;
209
    }
210
 
211
    if (x == (160<<16))
212
        f |= TEXT_XCENTER;
213
 
8653 hendricks2 214
    G_ScreenText(tile, x, y, z, 0, 0, t, s, p, 2|o, a, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, x1, y1, x2, y2);
6210 hendricks2 215
}
5614 terminx 216
 
6247 hendricks2 217
vec2_t gametext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t o, int32_t a, int32_t f)
6210 hendricks2 218
{
8653 hendricks2 219
    return G_ScreenText(MF_Bluefont.tilenum, x, y, MF_Bluefont.zoom, 0, 0, t, s, p, o|2|8|16, a, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, 0, 0, xdim-1, ydim-1);
5614 terminx 220
}
6210 hendricks2 221
void gametext_simple(int32_t x, int32_t y, const char *t)
222
{
8653 hendricks2 223
    G_ScreenText(MF_Bluefont.tilenum, x, y, MF_Bluefont.zoom, 0, 0, t, 0, MF_Bluefont.pal, 2|8|16, 0, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags, 0, 0, xdim-1, ydim-1);
6210 hendricks2 224
}
6247 hendricks2 225
vec2_t mpgametext(int32_t x, int32_t y, const char *t, int32_t s, int32_t o, int32_t a, int32_t f)
5614 terminx 226
{
8653 hendricks2 227
    return G_ScreenText(MF_Bluefont.tilenum, x, y, textsc(MF_Bluefont.zoom), 0, 0, t, s, MF_Bluefont.pal, o|2|8|16, a, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, 0, 0, xdim-1, ydim-1);
5614 terminx 228
}
6247 hendricks2 229
vec2_t mpgametextsize(const char *t, int32_t f)
230
{
8653 hendricks2 231
    return G_ScreenTextSize(MF_Bluefont.tilenum, 0, 0, textsc(MF_Bluefont.zoom), 0, t, 2|8|16, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, 0, 0, xdim-1, ydim-1);
6247 hendricks2 232
}
5614 terminx 233
 
234
// minitext_yofs: in hud_scale-independent, (<<16)-scaled, 0-200-normalized y coords,
235
// (sb&ROTATESPRITE_MAX) only.
236
int32_t minitext_yofs = 0;
237
int32_t minitext_lowercase = 0;
238
int32_t minitext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t sb)
239
{
240
    vec2_t dim;
6613 hendricks2 241
    int32_t z = MF_Minifont.zoom;
5614 terminx 242
 
243
    if (t == NULL)
244
    {
245
        OSD_Printf("minitext: NULL text!\n");
246
        return 0;
247
    }
248
 
249
    if (!(sb & ROTATESPRITE_FULL16))
250
    {
251
        x<<=16;
252
        y<<=16;
253
    }
254
 
255
    if (sb & ROTATESPRITE_MAX)
256
    {
257
        x = sbarx16(x);
258
        y = minitext_yofs+sbary16(y);
259
        z = sbarsc(z);
260
    }
261
 
262
    sb &= (ROTATESPRITE_MAX-1)|RS_CENTERORIGIN;
263
 
8653 hendricks2 264
    dim = G_ScreenText(MF_Minifont.tilenum, x, y, z, 0, 0, t, s, p, sb, 0, MF_Minifont.emptychar.x, MF_Minifont.emptychar.y, MF_Minifont.between.x, MF_Minifont.between.y, MF_Minifont.textflags, 0, 0, xdim-1, ydim-1);
5614 terminx 265
 
266
    x += dim.x;
267
 
268
    if (!(sb & ROTATESPRITE_FULL16))
269
        x >>= 16;
270
 
271
    return x;
272
}
273
 
6208 hendricks2 274
void menutext_(int32_t x, int32_t y, int32_t s, char const *t, int32_t o, int32_t f)
275
{
8653 hendricks2 276
    G_ScreenText(MF_Redfont.tilenum, x, y - (12<<16), MF_Redfont.zoom, 0, 0, t, s, MF_Redfont.pal, o, 0, MF_Redfont.emptychar.x, MF_Redfont.emptychar.y, MF_Redfont.between.x, MF_Redfont.between.y, f|MF_Redfont.textflags|TEXT_LITERALESCAPE, 0, 0, xdim-1, ydim-1);
6208 hendricks2 277
}
278
 
6613 hendricks2 279
void captionmenutext(int32_t x, int32_t y, char const *t)
280
{
8653 hendricks2 281
    G_ScreenText(MF_Redfont.tilenum, x, y - (12<<16), MF_Redfont.zoom, 0, 0, t, 0, ud.menutitle_pal, 2|8|16, 0, MF_Redfont.emptychar.x, MF_Redfont.emptychar.y, MF_Redfont.between.x, MF_Redfont.between.y, MF_Redfont.textflags|TEXT_LITERALESCAPE|TEXT_XCENTER|TEXT_YCENTER, 0, 0, xdim-1, ydim-1);
6613 hendricks2 282
}
6247 hendricks2 283
 
284
 
285
int32_t user_quote_time[MAXUSERQUOTES];
286
static char user_quote[MAXUSERQUOTES][178];
287
 
5614 terminx 288
void G_AddUserQuote(const char *daquote)
289
{
290
    int32_t i;
291
 
292
    for (i=MAXUSERQUOTES-1; i>0; i--)
293
    {
294
        Bstrcpy(user_quote[i], user_quote[i-1]);
295
        user_quote_time[i] = user_quote_time[i-1];
296
    }
297
    Bstrcpy(user_quote[0], daquote);
298
    OSD_Printf("%s\n", daquote);
299
 
300
    user_quote_time[0] = ud.msgdisptime;
301
    pub = NUMPAGES;
302
}
303
 
6247 hendricks2 304
int32_t textsc(int32_t sc)
305
{
306
    return scale(sc, ud.textscale, 400);
307
}
308
 
309
int32_t hud_glowingquotes = 1;
310
 
311
#define FTAOPAQUETIME 30
312
 
313
// alpha increments of 8 --> 256 / 8 = 32 --> round up to power of 2 --> 32 --> divide by 2 --> 16 alphatabs required
314
static inline int32_t textsh(uint32_t t)
315
{
6829 terminx 316
    return (hud_glowingquotes && ((videoGetRenderMode() == REND_CLASSIC && numalphatabs < 15) || t >= FTAOPAQUETIME))
6247 hendricks2 317
        ? sintable[(t << 7) & 2047] >> 11
318
        : (sintable[(FTAOPAQUETIME << 7) & 2047] >> 11);
319
}
320
 
5614 terminx 321
// orientation flags depending on time that a quote has still to be displayed
322
static inline int32_t texto(int32_t t)
323
{
6829 terminx 324
    if (videoGetRenderMode() != REND_CLASSIC || numalphatabs >= 15 || t > 4)
6247 hendricks2 325
        return 0;
326
 
327
    if (t > 2)
328
        return 1;
329
 
6210 hendricks2 330
    return 1|32;
5614 terminx 331
}
332
 
333
static inline int32_t texta(int32_t t)
334
{
6829 terminx 335
    if (videoGetRenderMode() == REND_CLASSIC && numalphatabs < 15)
6247 hendricks2 336
        return 0;
5614 terminx 337
 
6247 hendricks2 338
    return 255 - clamp(t<<3, 0, 255);
5614 terminx 339
}
340
 
6247 hendricks2 341
static FORCE_INLINE int32_t text_ypos(void)
342
{
6588 hendricks2 343
    if (ud.hudontop == 1 && ud.screen_size == 4 && ud.althud == 1)
6247 hendricks2 344
        return 32<<16;
345
 
346
#ifdef GEKKO
347
    return 16<<16;
348
#elif defined EDUKE32_TOUCH_DEVICES
349
    return 24<<16;
350
#else
351
    return 1<<16;
352
#endif
353
}
354
 
5614 terminx 355
// this handles both multiplayer and item pickup message type text
356
// both are passed on to gametext
357
void G_PrintGameQuotes(int32_t snum)
358
{
7776 terminx 359
    auto const ps = g_player[snum].ps;
5614 terminx 360
    const int32_t reserved_quote = (ps->ftq >= QUOTE_RESERVED && ps->ftq <= QUOTE_RESERVED3);
361
    // NOTE: QUOTE_RESERVED4 is not included.
362
 
6587 hendricks2 363
    int32_t const ybase = (fragbarheight()<<16) + text_ypos();
6247 hendricks2 364
    int32_t height = 0;
365
    int32_t k = ps->fta;
5614 terminx 366
 
367
 
6247 hendricks2 368
    // primary quote
5614 terminx 369
 
6247 hendricks2 370
    do
5614 terminx 371
    {
6247 hendricks2 372
        if (k <= 1)
373
            break;
5614 terminx 374
 
6247 hendricks2 375
        if (EDUKE32_PREDICT_FALSE(apStrings[ps->ftq] == NULL))
5614 terminx 376
        {
8649 hendricks2 377
            OSD_Printf(OSD_ERROR "%s %d null quote %d\n", "text:", __LINE__, ps->ftq);
6247 hendricks2 378
            break;
5614 terminx 379
        }
380
 
6247 hendricks2 381
        int32_t y = ybase;
5614 terminx 382
        if (reserved_quote)
383
        {
384
#ifdef SPLITSCREEN_MOD_HACKS
385
            if (!g_fakeMultiMode)
6247 hendricks2 386
                y = 140<<16;
5614 terminx 387
            else
6247 hendricks2 388
                y = 70<<16;
5614 terminx 389
#else
6247 hendricks2 390
            y = 140<<16;
5614 terminx 391
#endif
392
        }
6247 hendricks2 393
 
394
        int32_t pal = 0;
395
        int32_t x = 160<<16;
396
 
397
#ifdef SPLITSCREEN_MOD_HACKS
398
        if (g_fakeMultiMode)
5614 terminx 399
        {
6247 hendricks2 400
            pal = g_player[snum].pcolor;
401
            const int32_t sidebyside = ud.screen_size != 0;
402
 
403
            if (sidebyside)
404
                x = snum == 1 ? 240<<16 : 80<<16;
405
            else if (snum == 1)
406
                y += 100<<16;
407
        }
5614 terminx 408
#endif
6247 hendricks2 409
 
410
        height = gametext_(x, y, apStrings[ps->ftq], textsh(k), pal, texto(k), texta(k), TEXT_XCENTER).y + (1<<16);
5614 terminx 411
    }
6247 hendricks2 412
    while (0);
5614 terminx 413
 
414
 
6247 hendricks2 415
    // userquotes
416
 
417
    int32_t y = ybase;
418
 
419
    if (k > 1 && !reserved_quote)
420
        y += k <= 8 ? (height * (k-1))>>3 : height;
421
 
7673 terminx 422
    for (int i = 0; i < MAXUSERQUOTES; i++)
5614 terminx 423
    {
6247 hendricks2 424
        k = user_quote_time[i];
5614 terminx 425
 
6247 hendricks2 426
        if (k <= 0)
427
            continue;
5614 terminx 428
 
6247 hendricks2 429
        // int32_t const sh = hud_glowingquotes ? sintable[((totalclock+(i<<2))<<5)&2047]>>11 : 0;
430
 
8657 hendricks2 431
        // could use some kind of word wrap here
432
        height = mpgametext(mpgametext_x, y, user_quote[i], textsh(k), texto(k), texta(k), 0).y + textsc(1<<16);
6247 hendricks2 433
        y += k <= 4 ? (height * (k-1))>>2 : height;
5614 terminx 434
    }
435
}
436
 
437
void P_DoQuote(int32_t q, DukePlayer_t *p)
438
{
439
    int32_t cq = 0;
440
 
441
    if (ud.fta_on == 0 || q < 0 || !(p->gm & MODE_GAME))
442
        return;
443
 
444
    if (q & MAXQUOTES)
445
    {
446
        cq = 1;
447
        q &= ~MAXQUOTES;
448
    }
449
 
5825 terminx 450
    if (EDUKE32_PREDICT_FALSE(apStrings[q] == NULL))
5614 terminx 451
    {
8649 hendricks2 452
        OSD_Printf(OSD_ERROR "%s %d null quote %d\n", "text:", __LINE__, q);
5614 terminx 453
        return;
454
    }
455
 
456
    if (p->fta > 0 && q != QUOTE_RESERVED && q != QUOTE_RESERVED2)
457
        if (p->ftq == QUOTE_RESERVED || p->ftq == QUOTE_RESERVED2) return;
458
 
459
    p->fta = 100;
460
 
461
    if (p->ftq != q)
462
    {
6297 terminx 463
        if (p == g_player[screenpeek].ps && apStrings[q][0] != '\0')
464
            OSD_Printf(cq ? OSDTEXT_DEFAULT "%s\n" : "%s\n", apStrings[q]);
5614 terminx 465
 
466
        p->ftq = q;
467
    }
6297 terminx 468
 
5614 terminx 469
    pub = NUMPAGES;
470
    pus = NUMPAGES;
471
}