Subversion Repositories eduke32

Rev

Rev 4336 | 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
 
484 terminx 7
EDuke32 is free software; you can redistribute it and/or
5 Plagman 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
331 terminx 13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 Plagman 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20
*/
21
//-------------------------------------------------------------------------
22
 
23
#include "compat.h"
24
#include "build.h"
25
#include "editor.h"
26
#include "pragmas.h"
3116 hendricks2 27
 
5 Plagman 28
#include "baselayer.h"
3221 hendricks2 29
#include "renderlayer.h"
3116 hendricks2 30
 
5 Plagman 31
#include "osd.h"
32
#include "cache1d.h"
33
 
1952 helixhorne 34
#include "osdfuncs.h"
35
#include "names.h"
36
 
2542 helixhorne 37
#include "common.h"
2726 hendricks2 38
#include "common_game.h"
5 Plagman 39
#include "mapster32.h"
40
#include "keys.h"
1346 terminx 41
 
5 Plagman 42
#include "keyboard.h"
249 terminx 43
#include "scriptfile.h"
534 terminx 44
#include "crc32.h"
5 Plagman 45
 
1247 helixhorne 46
#include "sounds_mapster32.h"
47
#include "fx_man.h"
48
 
1341 terminx 49
#include "macros.h"
4316 hendricks2 50
#include "lz4.h"
1341 terminx 51
 
1493 helixhorne 52
#include "m32script.h"
53
#include "m32def.h"
54
 
3056 helixhorne 55
#ifdef LUNATIC
56
# include "lunatic_m32.h"
57
#endif
58
 
3337 hendricks2 59
static const char *
60
    #include "rev.h"
1824 terminx 61
 
910 terminx 62
#ifdef _WIN32
63
#define WIN32_LEAN_AND_MEAN
64
#include <windows.h>
1100 terminx 65
#include <shellapi.h>
910 terminx 66
#endif
67
 
1661 helixhorne 68
#include <signal.h>
69
 
4072 hendricks2 70
// Workaround for namespace pollution in <sys/stat.h> introduced in MinGW 4.8.
71
#ifdef stat
72
# undef stat
73
#endif
74
 
1205 terminx 75
static int32_t floor_over_floor;
1901 helixhorne 76
static int32_t g_fillCurSector = 0;
5 Plagman 77
 
1904 helixhorne 78
static char g_modDir[BMAX_PATH];
2096 helixhorne 79
static char levelname[BMAX_PATH];
1904 helixhorne 80
 
653 terminx 81
// static char *startwin_labeltext = "Starting Mapster32...";
2551 helixhorne 82
static char setupfilename[BMAX_PATH] = "mapster32.cfg";
2564 helixhorne 83
 
2110 helixhorne 84
int32_t fixmaponsave_sprites = 1;
85
static int32_t fixmaponsave_walls = 0;
1205 terminx 86
static int32_t lastsave = -180*60;
87
static int32_t NoAutoLoad = 0;
1644 helixhorne 88
static int32_t spnoclip=1;
5 Plagman 89
 
1909 terminx 90
static char *default_tiles_cfg = "tiles.cfg";
1695 helixhorne 91
static int32_t pathsearchmode_oninit;
92
 
3056 helixhorne 93
#ifdef LUNATIC
3148 helixhorne 94
static L_State g_EmState;
3056 helixhorne 95
#endif
96
 
1454 terminx 97
#pragma pack(push,1)
1247 helixhorne 98
sound_t g_sounds[MAXSOUNDS];
1454 terminx 99
#pragma pack(pop)
100
 
1247 helixhorne 101
static int16_t g_definedsndnum[MAXSOUNDS];  // maps parse order index to g_sounds index
102
static int16_t g_sndnum[MAXSOUNDS];  // maps current order index to g_sounds index
103
int32_t g_numsounds = 0;
1665 terminx 104
static int32_t lastupdate, mousecol, mouseadd = 1, bstatus;
1247 helixhorne 105
 
654 terminx 106
#if !defined(_WIN32)
1205 terminx 107
static int32_t usecwd = 0;
654 terminx 108
#endif
109
 
2795 helixhorne 110
char *scripthist[SCRIPTHISTSIZ];
1661 helixhorne 111
int32_t scripthistend = 0;
727 terminx 112
 
1908 helixhorne 113
int32_t g_lazy_tileselector = 0;
1691 helixhorne 114
int32_t showambiencesounds=2;
115
 
1751 helixhorne 116
int32_t autocorruptcheck = 0;
117
static int32_t corruptchecktimer;
1927 helixhorne 118
static int32_t curcorruptthing=-1, corrupt_tryfix_alt=0;
1931 helixhorne 119
int32_t corruptcheck_noalreadyrefd=0;
1751 helixhorne 120
 
1792 helixhorne 121
int32_t corruptlevel=0, numcorruptthings=0, corruptthings[MAXCORRUPTTHINGS];
1760 helixhorne 122
 
1803 helixhorne 123
static uint32_t templenrepquot=1;
1733 helixhorne 124
 
1644 helixhorne 125
//////////////////// Key stuff ////////////////////
126
 
127
#define eitherALT   (keystatus[KEYSC_LALT] || keystatus[KEYSC_RALT])
128
#define eitherCTRL  (keystatus[KEYSC_LCTRL] || keystatus[KEYSC_RCTRL])
129
#define eitherSHIFT (keystatus[KEYSC_LSHIFT] || keystatus[KEYSC_RSHIFT])
130
 
131
#define PRESSED_KEYSC(Key) (keystatus[KEYSC_##Key] && !(keystatus[KEYSC_##Key]=0))
132
 
133
 
134
//////////////////// Aiming ////////////////////
135
static const char *Typestr[] = { "Wall", "Ceiling", "Floor", "Sprite", "Wall" };
136
static const char *typestr[] = { "wall", "ceiling", "floor", "sprite", "wall" };
137
static const char *Typestr_wss[] = { "Wall", "Sector", "Sector", "Sprite", "Wall" };
1660 terminx 138
/*static const char *typestr_wss[] = { "wall", "sector", "sector", "sprite", "wall" };*/
1361 terminx 139
 
1644 helixhorne 140
/** The following macros multiplex between identically named fields of sector/wall/sprite,
141
 * based on a macro parameter or the currently aimed at object (AIMED_ versions).
142
 * They can be used on either side of an assignment. */
143
 
144
// select wall, only makes a difference with walls that have 'swap bottom of walls' bit set
145
#define SELECT_WALL() (AIMING_AT_WALL ? searchbottomwall : searchwall)
146
 
147
#define SECFLD(i, Field)  (sector[i].Field)
148
#define WALFLD(i, Field)  (wall[i].Field)
149
#define SPRFLD(i, Field)  (sprite[i].Field)
150
 
151
// valid fields: z, stat, picnum, heinum, shade, pal, xpanning, ypanning
152
#define CEILINGFLOOR(iSec, Field) (*(AIMING_AT_CEILING ? &(sector[iSec].ceiling##Field) : &(sector[iSec].floor##Field)))
153
#define AIMED_CEILINGFLOOR(Field) CEILINGFLOOR(searchsector, Field)
154
 
155
#define AIMED_SEL_WALL(Field) WALFLD(SELECT_WALL(), Field)
156
 
157
// selects from wall proper or its mask
158
#define OVR_WALL(iWal, Field) (*(AIMING_AT_WALL ? &WALFLD(iWal, Field) : &(wall[iWal].over##Field)))
159
#define AIMED_SELOVR_WALL(Field) OVR_WALL(SELECT_WALL(), Field)
160
 
161
// the base macro to construct field multiplexing macros: wall and sector cases undetermined
162
#define MUXBASE(Field, SectorCase, WallCase) (*(AIMING_AT_CEILING_OR_FLOOR ? (SectorCase) : \
163
                                               (AIMING_AT_WALL_OR_MASK ? (WallCase) : \
164
                                                &SPRFLD(searchwall, Field))))
165
 
166
#define SFBASE_CF(Field, WallCase) MUXBASE(Field, &AIMED_CEILINGFLOOR(Field), WallCase)
167
 
168
#define SFBASE_(Field, WallCase) MUXBASE(Field, &SECFLD(searchsector,Field), WallCase)
169
 
170
#define AIMED(Field) SFBASE_(Field, &WALFLD(searchwall, Field))
171
#define AIMED_SEL(Field) SFBASE_(Field, &AIMED_SEL_WALL(Field))
172
//#define AIMED_CF(Field) SFBASE_CF(Field, &WALFLD(searchwall,Field))
173
#define AIMED_CF_SEL(Field) SFBASE_CF(Field, &AIMED_SEL_WALL(Field))
174
 
175
// OVR makes sense only with picnum
176
//#define AIMED_OVR_PICNUM  SFBASE_CF(picnum, &OVR_WALL(searchwall, picnum))
177
#define AIMED_SELOVR_PICNUM SFBASE_CF(picnum, &AIMED_SELOVR_WALL(picnum))
178
 
179
 
180
static const char *ONOFF_[] = {"OFF","ON"};
181
#define ONOFF(b) (ONOFF_[!!(b)])
182
 
1867 helixhorne 183
// always CRLF for us
184
#ifdef _WIN32
185
# define OURNEWL "\n"
186
#else
187
# define OURNEWL "\r\n"
188
#endif
1644 helixhorne 189
 
1598 helixhorne 190
static int32_t tsign, mouseaction=0, mouseax=0, mouseay=0;
1361 terminx 191
static int32_t repeatcountx, repeatcounty;
192
static int32_t infobox=3; // bit0: current window, bit1: mouse pointer, the variable should be renamed
193
 
1508 terminx 194
static char wallshades[MAXWALLS];
195
static char sectorshades[MAXSECTORS][2];
196
static char spriteshades[MAXSPRITES];
197
static char wallpals[MAXWALLS];
198
static char sectorpals[MAXSECTORS][2];
199
static char spritepals[MAXSPRITES];
1854 helixhorne 200
static uint8_t wallflag[MAXWALLS>>3];
1695 helixhorne 201
 
1854 helixhorne 202
#ifdef YAX_ENABLE
2566 helixhorne 203
static const char *yupdownwall[2] = {"upwall","downwall"};
204
static const char *YUPDOWNWALL[2] = {"UPWALL","DOWNWALL"};
1997 helixhorne 205
 
1854 helixhorne 206
static uint8_t havebunch[YAX_MAXBUNCHES];
207
static int32_t *tempzar[YAX_MAXBUNCHES];
208
 
209
static void silentmessage(const char *fmt, ...);
210
static int32_t yax_invalidop()
211
{
212
    silentmessage("Operation forbidden on extended sector.");
213
    return 0;
214
}
215
 
1900 helixhorne 216
static int32_t yax_invalidslope()
217
{
218
    silentmessage("Firstwalls must coincide for changing slope.");
219
    return 0;
220
}
221
 
222
// 1: ok
223
static int32_t yax_checkslope(int16_t sectnum, int32_t othersectnum)
224
{
225
    int16_t w1 = sector[sectnum].wallptr, w2 = wall[w1].point2;
226
    int16_t nw1 = sector[othersectnum].wallptr, nw2 = wall[nw1].point2;
227
 
228
    if (nw1 < 0)
229
        return 0;  // error
230
 
231
    nw2 = wall[nw1].point2;
232
    if (wall[w1].x != wall[nw1].x || wall[w1].y != wall[nw1].y ||
233
            wall[w2].x != wall[nw2].x || wall[w2].y != wall[nw2].y)
234
        return 0;
235
 
236
    return 1;
237
}
238
 
239
# define YAXSLOPECHK(s,os)  (yax_checkslope(s,os) || yax_invalidslope())
1854 helixhorne 240
# define YAXCHK(p) ((p) || yax_invalidop())
241
#endif
242
 
1695 helixhorne 243
// tile marking in tile selector for custom creation of tile groups
1867 helixhorne 244
static uint8_t tilemarked[(MAXTILES+7)>>3];
1695 helixhorne 245
 
1508 terminx 246
#ifdef POLYMER
247
static int16_t spritelightid[MAXSPRITES];
248
_prlight *spritelightptr[MAXSPRITES];
1760 helixhorne 249
 
1854 helixhorne 250
static int32_t check_prlight_colors(int32_t i)
1760 helixhorne 251
{
1854 helixhorne 252
    return (sprite[i].xvel != spritelightptr[i]->color[0]) ||
253
        (sprite[i].yvel != spritelightptr[i]->color[1]) ||
254
        (sprite[i].zvel != spritelightptr[i]->color[2]);
255
}
256
 
257
static void copy_prlight_colors(_prlight *mylightptr, int32_t i)
258
{
259
    mylightptr->color[0] = sprite[i].xvel;
260
    mylightptr->color[1] = sprite[i].yvel;
261
    mylightptr->color[2] = sprite[i].zvel;
262
}
263
 
264
static void addprlight_common1(_prlight *mylightptr, int32_t i)
265
{
266
    mylightptr->sector = SECT;
267
    Bmemcpy(mylightptr, &sprite[i], sizeof(vec3_t));
268
    mylightptr->range = SHT;
269
    copy_prlight_colors(mylightptr, i);
270
    mylightptr->angle = SA;
271
    mylightptr->horiz = SH;
272
    mylightptr->minshade = sprite[i].xoffset;
273
    mylightptr->maxshade = sprite[i].yoffset;
274
 
275
    // overridden for spot lights
276
    mylightptr->radius = mylightptr->faderadius = mylightptr->tilenum = 0;
277
 
278
    if (CS & 2)
279
    {
280
        if (CS & 512)
281
            mylightptr->priority = PR_LIGHT_PRIO_LOW;
282
        else
283
            mylightptr->priority = PR_LIGHT_PRIO_HIGH;
284
    }
285
    else
286
        mylightptr->priority = PR_LIGHT_PRIO_MAX;
287
 
3092 Plagman 288
    mylightptr->publicflags.negative = !!(CS & 128);
289
 
1854 helixhorne 290
    spritelightid[i] = polymer_addlight(mylightptr);
291
    if (spritelightid[i] >= 0)
292
        spritelightptr[i] = &prlights[spritelightid[i]];
293
}
294
 
295
static void DeletePolymerLights(void)
296
{
1760 helixhorne 297
    int32_t i;
298
    for (i=0; i<MAXSPRITES; i++)
299
        if (spritelightptr[i] != NULL)
300
        {
301
            polymer_deletelight(spritelightid[i]);
2169 helixhorne 302
            spritelightid[i] = -1;
1760 helixhorne 303
            spritelightptr[i] = NULL;
304
        }
305
}
2006 helixhorne 306
 
307
void G_Polymer_UnInit(void)
308
{
309
    DeletePolymerLights();
310
}
1508 terminx 311
#endif
312
 
1454 terminx 313
extern int32_t mskip;
1361 terminx 314
 
1843 helixhorne 315
//extern int32_t fillsector(int16_t sectnum, char fillcolor);
1361 terminx 316
 
1854 helixhorne 317
static void drawgradient(void)
1644 helixhorne 318
{
319
    int32_t i, col = whitecol-21;
320
    begindrawing();
321
    for (i=ydim-STATUS2DSIZ+16; i<ydim && col>0; i++,col--)
1648 helixhorne 322
        CLEARLINES2D(i, 1, (col<<24)|(col<<16)|(col<<8)|col);
323
    CLEARLINES2D(i, ydim-i, 0);
1644 helixhorne 324
    enddrawing();
325
}
326
 
1854 helixhorne 327
static void message_common1(const char *tmpstr)
328
{
2559 helixhorne 329
    Bstrncpyz(getmessage, tmpstr, sizeof(getmessage));
1854 helixhorne 330
 
331
    getmessageleng = Bstrlen(getmessage);
1869 helixhorne 332
    getmessagetimeoff = totalclock + 120*2 + getmessageleng*(120/30);
1886 helixhorne 333
//    lastmessagetime = totalclock;
1854 helixhorne 334
}
335
 
1361 terminx 336
void message(const char *fmt, ...)
337
{
338
    char tmpstr[256];
339
    va_list va;
340
 
341
    va_start(va, fmt);
342
    Bvsnprintf(tmpstr, 256, fmt, va);
343
    va_end(va);
344
 
1854 helixhorne 345
    message_common1(tmpstr);
1644 helixhorne 346
 
1361 terminx 347
    if (!mouseaction)
1740 helixhorne 348
        OSD_Printf("%s\n", tmpstr);
1361 terminx 349
}
350
 
1854 helixhorne 351
static void silentmessage(const char *fmt, ...)
352
{
353
    char tmpstr[256];
354
    va_list va;
355
 
356
    va_start(va, fmt);
357
    Bvsnprintf(tmpstr, 256, fmt, va);
358
    va_end(va);
359
 
360
    message_common1(tmpstr);
361
}
362
 
2492 helixhorne 363
 
364
static int32_t osdcmd_quit(const osdfuncparm_t *parm);
365
 
366
////////// UNDO/REDO SYSTEM //////////
1973 helixhorne 367
#if M32_UNDO
2492 helixhorne 368
typedef struct mapundo_
1361 terminx 369
{
2492 helixhorne 370
    int32_t revision;
371
    int32_t num[3];  // numsectors, numwalls, numsprites
1361 terminx 372
 
2492 helixhorne 373
    // These exist temporarily as sector/wall/sprite data, but are compressed
374
    // most of the time.  +4 bytes refcount at the beginning.
375
    char *sws[3];  // sector, wall, sprite
1361 terminx 376
 
2492 helixhorne 377
    uint32_t crc[3];
1361 terminx 378
 
2492 helixhorne 379
    struct mapundo_ *next;  // 'redo' loads this
380
    struct mapundo_ *prev;  // 'undo' loads this
1361 terminx 381
} mapundo_t;
382
 
383
mapundo_t *mapstate = NULL;
384
 
1444 terminx 385
int32_t map_revision = 1;
1361 terminx 386
 
1801 helixhorne 387
#define QADDNSZ 400
388
 
2492 helixhorne 389
 
390
static int32_t try_match_with_prev(int32_t idx, int32_t numsthgs, uint32_t crc)
1361 terminx 391
{
2492 helixhorne 392
    if (mapstate->prev && mapstate->prev->num[idx]==numsthgs && mapstate->prev->crc[idx]==crc)
393
    {
394
        // found match!
395
        mapstate->sws[idx] = mapstate->prev->sws[idx];
396
        (*(int32_t *)mapstate->sws[idx])++;  // increase refcount!
1361 terminx 397
 
2492 helixhorne 398
        return 1;
399
    }
1361 terminx 400
 
2492 helixhorne 401
    return 0;
402
}
403
 
404
static void create_compressed_block(int32_t idx, const void *srcdata, uint32_t size, uint32_t crc)
405
{
406
    uint32_t j;
407
 
408
    // allocate
3176 helixhorne 409
    mapstate->sws[idx] = (char *)Bmalloc(4 + size + QADDNSZ);
2492 helixhorne 410
    if (!mapstate->sws[idx]) { initprintf("OUT OF MEM in undo/redo\n"); osdcmd_quit(NULL); }
411
 
412
    // compress & realloc
4316 hendricks2 413
    j = LZ4_compress((const char*)srcdata, mapstate->sws[idx]+4, size);
3176 helixhorne 414
    mapstate->sws[idx] = (char *)Brealloc(mapstate->sws[idx], 4 + j);
2492 helixhorne 415
    if (!mapstate->sws[idx]) { initprintf("COULD not realloc in undo/redo\n"); osdcmd_quit(NULL); }
416
 
417
    // write refcount
418
    *(int32_t *)mapstate->sws[idx] = 1;
419
 
420
    mapstate->crc[idx] = crc;
421
}
422
 
423
static void free_self_and_successors(mapundo_t *mapst)
424
{
425
    mapundo_t *cur = mapst;
426
 
427
    mapst->prev = NULL;  // break the back link
428
 
429
    while (cur->next)
430
        cur = cur->next;
431
 
432
    while (1)
433
    {
434
        int32_t i;
435
        mapundo_t *const prev = cur->prev;
436
 
437
        for (i=0; i<3; i++)
438
        {
439
            int32_t *const refcnt = (int32_t *)cur->sws[i];
440
 
441
            if (refcnt)
442
            {
443
                (*refcnt)--;
444
                if (*refcnt == 0)
445
                    Bfree(refcnt);  // free the block!
446
            }
447
        }
448
 
449
        Bfree(cur);
450
 
451
        if (!prev)
452
            break;
453
 
454
        cur = prev;
455
    }
456
}
457
 
458
// NOTE: only _consecutive_ matching (size+crc) sector/wall/sprite blocks are
459
// shared!
460
void create_map_snapshot(void)
461
{
1444 terminx 462
    if (mapstate == NULL)
1361 terminx 463
    {
2492 helixhorne 464
        // create initial mapstate
465
 
466
        map_revision = 1;
467
 
3176 helixhorne 468
        mapstate = (mapundo_t *)Bcalloc(1, sizeof(mapundo_t));
2492 helixhorne 469
        mapstate->revision = map_revision;
1444 terminx 470
        mapstate->prev = mapstate->next = NULL;
471
    }
472
    else
473
    {
2492 helixhorne 474
        if (mapstate->next)
475
            free_self_and_successors(mapstate->next);
476
        // now, have no successors
1361 terminx 477
 
2492 helixhorne 478
        // calloc because not everything may be set in the following:
3176 helixhorne 479
        mapstate->next = (mapundo_t *)Bcalloc(1, sizeof(mapundo_t));
1444 terminx 480
        mapstate->next->prev = mapstate;
481
 
482
        mapstate = mapstate->next;
2492 helixhorne 483
 
1444 terminx 484
        mapstate->revision = ++map_revision;
1361 terminx 485
    }
486
 
2492 helixhorne 487
 
1361 terminx 488
    fixspritesectors();
489
 
2492 helixhorne 490
    mapstate->num[0] = numsectors;
491
    mapstate->num[1] = numwalls;
492
    mapstate->num[2] = Numsprites;
1361 terminx 493
 
1362 terminx 494
 
1447 terminx 495
    if (numsectors)
1361 terminx 496
    {
2492 helixhorne 497
        int32_t j;
498
        uint32_t tempcrc = crc32once((uint8_t *)sector, numsectors*sizeof(sectortype));
1361 terminx 499
 
2492 helixhorne 500
        if (!try_match_with_prev(0, numsectors, tempcrc))
501
            create_compressed_block(0, sector, numsectors*sizeof(sectortype), tempcrc);
502
 
1447 terminx 503
        if (numwalls)
504
        {
2492 helixhorne 505
            tempcrc = crc32once((uint8_t *)wall, numwalls*sizeof(walltype));
1362 terminx 506
 
2492 helixhorne 507
            if (!try_match_with_prev(1, numwalls, tempcrc))
508
                create_compressed_block(1, wall, numwalls*sizeof(walltype), tempcrc);
1447 terminx 509
        }
1361 terminx 510
 
2478 helixhorne 511
        if (Numsprites)
1447 terminx 512
        {
2492 helixhorne 513
            tempcrc = crc32once((uint8_t *)sprite, MAXSPRITES*sizeof(spritetype));
1362 terminx 514
 
2492 helixhorne 515
            if (!try_match_with_prev(2, Numsprites, tempcrc))
1447 terminx 516
            {
517
                int32_t i = 0;
3176 helixhorne 518
                spritetype *const tspri = (spritetype *)Bmalloc(Numsprites*sizeof(spritetype) + 4);
2482 helixhorne 519
                spritetype *spri = tspri;
520
 
2492 helixhorne 521
                if (!tspri) { initprintf("OUT OF MEM in undo/redo (2)\n"); osdcmd_quit(NULL); }
1361 terminx 522
 
2478 helixhorne 523
                for (j=0; j<MAXSPRITES && i < Numsprites; j++)
1447 terminx 524
                    if (sprite[j].statnum != MAXSTATUS)
525
                    {
1803 helixhorne 526
                        Bmemcpy(spri++, &sprite[j], sizeof(spritetype));
1447 terminx 527
                        i++;
528
                    }
1803 helixhorne 529
 
2492 helixhorne 530
                create_compressed_block(2, tspri, Numsprites*sizeof(spritetype), tempcrc);
1447 terminx 531
                Bfree(tspri);
1444 terminx 532
            }
1361 terminx 533
        }
534
    }
1832 helixhorne 535
 
2490 helixhorne 536
    CheckMapCorruption(5, 0);
1361 terminx 537
}
538
 
1384 terminx 539
void map_undoredo_free(void)
540
{
541
    if (mapstate)
542
    {
2492 helixhorne 543
        free_self_and_successors(mapstate);
1384 terminx 544
        mapstate = NULL;
545
    }
546
 
1444 terminx 547
    map_revision = 1;
1384 terminx 548
}
549
 
1363 terminx 550
int32_t map_undoredo(int32_t dir)
1361 terminx 551
{
552
    int32_t i;
553
 
1444 terminx 554
    if (mapstate == NULL) return 1;
555
 
1363 terminx 556
    if (dir)
557
    {
2492 helixhorne 558
        if (mapstate->next == NULL || !mapstate->next->num[0]) return 1;
1361 terminx 559
 
1444 terminx 560
        //        while (map_revision+1 != mapstate->revision && mapstate->next)
561
        mapstate = mapstate->next;
1363 terminx 562
    }
563
    else
564
    {
2492 helixhorne 565
        if (mapstate->prev == NULL || !mapstate->prev->num[0]) return 1;
1361 terminx 566
 
1444 terminx 567
        //        while (map_revision-1 != mapstate->revision && mapstate->prev)
568
        mapstate = mapstate->prev;
1361 terminx 569
    }
570
 
2492 helixhorne 571
    numsectors = mapstate->num[0];
572
    numwalls = mapstate->num[1];
1444 terminx 573
    map_revision = mapstate->revision;
1361 terminx 574
 
1644 helixhorne 575
    Bmemset(show2dsector, 0, sizeof(show2dsector));
1384 terminx 576
 
2943 helixhorne 577
    reset_highlightsector();
578
    reset_highlight();
579
 
2485 helixhorne 580
    initspritelists();
581
 
2492 helixhorne 582
    if (mapstate->num[0])
1447 terminx 583
    {
2492 helixhorne 584
        // restore sector[]
4316 hendricks2 585
        LZ4_decompress_fast(mapstate->sws[0]+4, (char*)sector, numsectors*sizeof(sectortype));
1361 terminx 586
 
2492 helixhorne 587
        if (mapstate->num[1])  // restore wall[]
4316 hendricks2 588
            LZ4_decompress_fast(mapstate->sws[1]+4, (char*)wall, numwalls*sizeof(walltype));
1447 terminx 589
 
2492 helixhorne 590
        if (mapstate->num[2])  // restore sprite[]
4316 hendricks2 591
            LZ4_decompress_fast(mapstate->sws[2]+4, (char*)sprite, (mapstate->num[2])*sizeof(spritetype));
1447 terminx 592
    }
593
 
2492 helixhorne 594
    // insert sprites
595
    for (i=0; i<mapstate->num[2]; i++)
1361 terminx 596
    {
597
        if ((sprite[i].cstat & 48) == 48) sprite[i].cstat &= ~48;
2547 helixhorne 598
        Bassert((unsigned)sprite[i].sectnum < (unsigned)numsectors
2492 helixhorne 599
                   && (unsigned)sprite[i].statnum < MAXSTATUS);
600
        insertsprite(sprite[i].sectnum, sprite[i].statnum);
1361 terminx 601
    }
602
 
2547 helixhorne 603
    Bassert(Numsprites == mapstate->num[2]);
2478 helixhorne 604
 
1362 terminx 605
#ifdef POLYMER
3823 helixhorne 606
    if (in3dmode() && getrendermode() == REND_POLYMER)
1362 terminx 607
        polymer_loadboard();
608
#endif
1860 helixhorne 609
#ifdef YAX_ENABLE
610
    yax_update(0);
1869 helixhorne 611
    yax_updategrays(pos.z);
1860 helixhorne 612
#endif
1801 helixhorne 613
    CheckMapCorruption(4, 0);
614
 
1361 terminx 615
    return 0;
616
}
1973 helixhorne 617
#endif
1361 terminx 618
 
2496 helixhorne 619
 
1874 helixhorne 620
#define M32_NUM_SPRITE_MODES ((signed)(sizeof(SpriteMode)/sizeof(SpriteMode[0])))
1644 helixhorne 621
static const char *SpriteMode[]=
559 terminx 622
{
623
    "NONE",
624
    "SECTORS",
625
    "WALLS",
626
    "SPRITES",
627
    "ALL",
628
    "ITEMS ONLY",
629
    "CURRENT SPRITE ONLY",
630
    "ONLY SECTOREFFECTORS AND SECTORS",
631
    "NO SECTOREFFECTORS OR SECTORS"
632
};
5 Plagman 633
 
634
#define MAXSKILL 5
1644 helixhorne 635
static const char *SKILLMODE[MAXSKILL]=
559 terminx 636
{
637
    "Actor skill display: PIECE OF CAKE",
638
    "Actor skill display: LET'S ROCK",
639
    "Actor skill display: COME GET SOME",
640
    "Actor skill display: DAMN I'M GOOD",
641
    "Actor skill display: ALL SKILL LEVELS"
642
};
5 Plagman 643
 
644
#define MAXNOSPRITES 4
1644 helixhorne 645
static const char *SPRDSPMODE[MAXNOSPRITES]=
559 terminx 646
{
647
    "Sprite display: DISPLAY ALL SPRITES",
648
    "Sprite display: NO EFFECTORS",
649
    "Sprite display: NO ACTORS",
650
    "Sprite display: NO EFFECTORS OR ACTORS"
651
};
5 Plagman 652
 
1874 helixhorne 653
#define MAXHELP3D ((signed)(sizeof(Help3d)/sizeof(Help3d[0])))
1644 helixhorne 654
static const char *Help3d[]=
559 terminx 655
{
656
    "Mapster32 3D mode help",
657
    " ",
658
    " F2 = TOGGLE CLIPBOARD",
1856 helixhorne 659
    " F3 = TOGGLE MOUSELOOK",
660
    " F4 = TOGGLE AMBIENT SOUNDS",
559 terminx 661
    " F6 = AUTOMATIC SECTOREFFECTOR HELP",
662
    " F7 = AUTOMATIC SECTOR TAG HELP",
663
    "",
664
    " ' A = TOGGLE AUTOSAVE",
665
    " ' D = CYCLE SPRITE SKILL DISPLAY",
666
    " ' R = TOGGLE FRAMERATE DISPLAY",
667
    " ' W = TOGGLE SPRITE DISPLAY",
763 terminx 668
    " ' X = MAP SHADE PREVIEW",
1856 helixhorne 669
    " ' I = TOGGLE INVISIBLE SPRITES",
559 terminx 670
    "",
671
    " ' T = CHANGE LOTAG",
672
    " ' H = CHANGE HITAG",
673
    " ' S = CHANGE SHADE",
674
    " ' M = CHANGE EXTRA",
675
    " ' V = CHANGE VISIBILITY",
676
    " ' L = CHANGE OBJECT COORDINATES",
677
    " ' C = CHANGE GLOBAL SHADE",
678
    "",
679
    " ' ENTER = PASTE GRAPHIC ONLY",
680
    " ' P & ; P = PASTE PALETTE TO ALL SELECTED SECTORS",
681
    " ; V = SET VISIBILITY ON ALL SELECTED SECTORS",
682
    " ' DEL = CSTAT=0",
683
    " CTRL-S = SAVE BOARD",
684
    " HOME = PGUP/PGDN MODIFIER (256 UNITS)",
685
    " END = PGUP/PGDN MODIFIER (512 UNITS)",
686
};
5 Plagman 687
 
1904 helixhorne 688
int32_t kopen4loadfrommod(const char *filename, char searchfirst)
689
{
690
    static char fn[BMAX_PATH];
691
    int32_t r=-1;
692
 
693
    if (g_modDir[0])
694
    {
695
        Bsnprintf(fn,sizeof(fn),"%s/%s",g_modDir,filename);
696
        r = kopen4load(fn,searchfirst);
697
    }
698
 
699
    if (r < 0)
700
        r = kopen4load(filename,searchfirst);
701
 
702
    return r;
703
}
704
 
1824 terminx 705
const char *ExtGetVer(void)
706
{
707
    return s_buildRev;
708
}
709
 
2110 helixhorne 710
void ExtSetupMapFilename(const char *mapname)
711
{
712
    Bstrcpy(levelname, mapname);
713
 
714
    Bsprintf(tempbuf, "Mapster32 - %s", mapname);
715
    wm_setapptitle(tempbuf);
716
}
717
 
5 Plagman 718
void ExtLoadMap(const char *mapname)
719
{
783 terminx 720
    getmessageleng = 0;
721
    getmessagetimeoff = 0;
722
 
2110 helixhorne 723
    ExtSetupMapFilename(mapname);
1882 helixhorne 724
 
3976 helixhorne 725
    // Old-fashioned multi-psky handling setup.
726
    G_SetupGlobalPsky();
1882 helixhorne 727
 
3975 helixhorne 728
    parallaxtype = 0;
5 Plagman 729
 
1882 helixhorne 730
    //////////
1973 helixhorne 731
#if M32_UNDO
1384 terminx 732
    map_undoredo_free();
1973 helixhorne 733
#endif
4244 hendricks2 734
 
735
    VM_OnEvent(EVENT_LOADMAP, -1);
5 Plagman 736
}
737
 
738
void ExtSaveMap(const char *mapname)
739
{
654 terminx 740
    UNREFERENCED_PARAMETER(mapname);
3042 helixhorne 741
    saveboard("backup.map", &pos, ang, cursectnum);
4244 hendricks2 742
 
743
    VM_OnEvent(EVENT_SAVEMAP, -1);
5 Plagman 744
}
745
 
1866 helixhorne 746
 
747
////////// tag labeling system //////////
748
 
1867 helixhorne 749
typedef struct
750
{
751
    hashtable_t hashtab;
752
    char *label[32768];
753
    int32_t numlabels;
754
} taglab_t;
755
 
756
static taglab_t g_taglab;
757
 
758
static void tstrtoupper(char *s)
759
{
760
    int32_t i;
761
    for (i=0; s[i]; i++)
762
        s[i] = Btoupper(s[i]);
763
}
764
 
765
void taglab_init()
766
{
767
    int32_t i;
768
 
769
    g_taglab.numlabels = 0;
770
    g_taglab.hashtab.size = 16384;
771
    hash_init(&g_taglab.hashtab);
772
 
773
    for (i=0; i<32768; i++)
774
    {
775
        if (g_taglab.label[i])
776
            Bfree(g_taglab.label[i]);
777
        g_taglab.label[i] = NULL;
778
    }
779
}
780
 
781
int32_t taglab_load(const char *filename, int32_t flags)
782
{
783
    int32_t fil, len, i;
784
    char buf[BMAX_PATH], *dot, *filebuf;
785
 
786
    taglab_init();
787
 
788
    len = Bstrlen(filename);
1876 helixhorne 789
    if (len >= BMAX_PATH-1)
1867 helixhorne 790
        return -1;
1876 helixhorne 791
    Bmemcpy(buf, filename, len+1);
1867 helixhorne 792
 
793
    //
794
    dot = Bstrrchr(buf, '.');
795
    if (!dot)
796
        dot = &buf[len];
797
 
798
    if (dot-buf+8 >= BMAX_PATH)
799
        return -1;
800
    Bmemcpy(dot, ".maptags", 9);
801
    //
802
 
803
    if ((fil = kopen4load(buf,flags)) == -1)
804
        return -1;
805
 
806
    len = kfilelength(fil);
807
 
3176 helixhorne 808
    filebuf = (char *)Bmalloc(len+1);
1867 helixhorne 809
    if (!filebuf)
810
    {
811
        kclose(fil);
812
        return -1;
813
    }
814
 
815
    kread(fil, filebuf, len);
816
    filebuf[len] = 0;
817
    kclose(fil);
818
 
819
    // ----
820
 
821
    {
822
        int32_t tag;
823
        char *cp=filebuf, *bp, *ep;
824
 
825
        while (1)
826
        {
827
#define XTAGLAB_STRINGIFY(X) TAGLAB_STRINGIFY(X)
828
#define TAGLAB_STRINGIFY(X) #X
829
            i = sscanf(cp, "%d %" XTAGLAB_STRINGIFY(TAGLAB_MAX) "s", &tag, buf);
830
#undef XTAGLAB_STRINGIFY
831
#undef TAGLAB_STRINGIFY
832
            if (i != 2 || !buf[0] || tag<0 || tag>=32768)
833
                goto nextline;
834
 
835
            buf[TAGLAB_MAX-1] = 0;
836
 
837
            i = Bstrlen(buf);
838
            bp = buf; while (*bp && isspace(*bp)) bp++;
839
            ep = &buf[i-1]; while (ep>buf && isspace(*ep)) ep--;
840
            ep++;
841
 
842
            if (!(ep > bp))
843
                goto nextline;
844
            *ep = 0;
845
 
846
            taglab_add(bp, tag);
847
//initprintf("add tag %s:%d\n", bp, tag);
848
nextline:
849
            while (*cp && *cp!='\n')
850
                cp++;
851
            while (*cp=='\r' || *cp=='\n')
852
                cp++;
853
            if (*cp == 0)
854
                break;
855
        }
856
    }
857
 
858
    // ----
859
    Bfree(filebuf);
860
 
861
    return 0;
862
}
863
 
864
int32_t taglab_save(const char *mapname)
865
{
866
    int32_t fil, len, i;
867
    char buf[BMAX_PATH], *dot;
868
    const char *label;
869
 
870
    if (g_taglab.numlabels==0)
871
        return 1;
872
 
2559 helixhorne 873
    Bstrncpyz(buf, mapname, BMAX_PATH);
1867 helixhorne 874
 
875
    len = Bstrlen(buf);
876
    //
877
    dot = Bstrrchr(buf, '.');
878
    if (!dot)
879
        dot = &buf[len];
880
 
881
    if (dot-buf+8 >= BMAX_PATH)
882
        return -1;
883
    Bmemcpy(dot, ".maptags", 9);
884
    //
885
 
886
    if ((fil = Bopen(buf,BO_BINARY|BO_TRUNC|BO_CREAT|BO_WRONLY,BS_IREAD|BS_IWRITE)) == -1)
887
    {
888
        initprintf("Couldn't open \"%s\" for writing: %s\n", buf, strerror(errno));
889
        return -1;
890
    }
891
 
892
    for (i=0; i<32768; i++)
893
    {
894
        label = taglab_getlabel(i);
895
        if (!label)
896
            continue;
897
 
4321 hendricks2 898
        len = Bsprintf(buf, "%d %s" OURNEWL, i, label);
1867 helixhorne 899
        if (Bwrite(fil, buf, len)!=len)
900
            break;
901
    }
902
 
903
    Bclose(fil);
904
 
905
    return (i!=32768);
906
}
907
 
908
int32_t taglab_add(const char *label, int16_t tag)
909
{
910
    const char *otaglabel;
911
    char buf[TAGLAB_MAX];
912
    int32_t olabeltag, diddel=0;
913
 
914
    if (tag < 0)
915
        return -1;
916
 
2559 helixhorne 917
    Bstrncpyz(buf, label, sizeof(buf));
1867 helixhorne 918
    // upcase the tag for storage and comparison
919
    tstrtoupper(buf);
920
 
921
    otaglabel = g_taglab.label[tag];
922
    if (otaglabel)
923
    {
924
        if (!Bstrcasecmp(otaglabel, buf))
925
            return 0;
926
 
927
//        hash_delete(&g_taglab.hashtab, g_taglab.label[tag]);
928
 
929
        // a label having the same tag number as 'tag' is deleted
930
        Bfree(g_taglab.label[tag]);
931
        g_taglab.label[tag] = NULL;
932
        diddel |= 1;
933
    }
934
    else
935
    {
936
        olabeltag = hash_findcase(&g_taglab.hashtab, buf);
937
        if (olabeltag==tag)
938
            return 0;
939
 
940
        if (olabeltag>=0)
941
        {
942
            // the label gets assigned to a new tag number ('tag deleted')
943
            Bfree(g_taglab.label[olabeltag]);
944
            g_taglab.label[olabeltag] = NULL;
945
            diddel |= 2;
946
        }
947
    }
948
 
949
    if (!diddel)
950
        g_taglab.numlabels++;
951
    g_taglab.label[tag] = Bstrdup(buf);
952
//initprintf("added %s %d to hash\n", g_taglab.label[tag], tag);
953
    hash_add(&g_taglab.hashtab, g_taglab.label[tag], tag, 1);
954
 
955
    return diddel;
956
}
957
 
958
const char *taglab_getlabel(int16_t tag)
959
{
960
    if (tag < 0)  // || tag>=32768 implicitly
961
        return NULL;
962
 
963
    return g_taglab.label[tag];
964
}
965
 
966
int32_t taglab_gettag(const char *label)
967
{
968
    char buf[TAGLAB_MAX];
969
 
2559 helixhorne 970
    Bstrncpyz(buf, label, TAGLAB_MAX);
1867 helixhorne 971
 
972
    // need to upcase since hash_findcase doesn't work as expected:
973
    // getting the code is still (necessarily) case-sensitive...
974
    tstrtoupper(buf);
975
 
976
    return hash_findcase(&g_taglab.hashtab, buf);
977
}
978
 
979
#define TLCHAR "+"
980
#define TLCHR(Cond) ((Cond)?TLCHAR:"")
3108 helixhorne 981
static uint64_t taglab_nolink_SEs = (1ull<<10)|(1ull<<27)|(1ull<<28)|(1ull<<29)|
982
    (1ull<<31)|(1ull<<32)|(1ull<<49)|(1ull<<50);
1866 helixhorne 983
 
984
// Whether the individual tags have linking semantics. Based on
985
//  http://infosuite.duke4.net/index.php?page=references_special_textures
986
// The return value is an OR of the following:
987
//  1: lotag has linking semantics
988
//  2: hitag
989
//  4: extra
990
//  8: xvel
991
//  16: yvel
992
//  32: zvel
993
//  64: owner
1877 helixhorne 994
// This function is only supposed to say something about the potential of a tag:
995
// it will also 'say yes' if a particular tag is zero.
1866 helixhorne 996
int32_t taglab_linktags(int32_t spritep, int32_t num)
997
{
998
    int32_t picnum;
999
    int32_t l, link = 0;
1000
 
1001
    if (spritep)
1002
        picnum = sprite[num].picnum;
1003
    else
1004
        picnum = wall[num].picnum;
1005
 
1006
    if (spritep)
1007
    {
1008
        switch (picnum)
1009
        {
1010
        case SECTOREFFECTOR:
1011
            // SEs potentially link by their hitag
1012
            l = sprite[num].lotag;
1013
            if (l>=0 && l<=63 && (taglab_nolink_SEs&(1ull<<l)))
1014
                break;
3424 helixhorne 1015
            link = 2;
1866 helixhorne 1016
            break;
1017
 
1018
            // various lotag-linkers
1019
        case ACTIVATOR: case TOUCHPLATE: case ACTIVATORLOCKED: case MASTERSWITCH:
1020
        case RESPAWN:  // ---
1021
        case ACCESSSWITCH: case ACCESSSWITCH2:
1022
        case MULTISWITCH:  // *
1023
        case DIPSWITCH: case TECHSWITCH: case ALIENSWITCH: case TARGET: case DUCK:
1024
        case REACTOR:
1025
        case CAMERA1:
3424 helixhorne 1026
            link = 1;
1866 helixhorne 1027
            break;
1028
 
1029
            // various hitag-linkers
1030
        case VIEWSCREEN2: case VIEWSCREEN:
1031
        case CRACK1: case CRACK2: case CRACK3: case CRACK4: case FIREEXT:
1032
        case FEM1: case FEM2: case FEM3: case FEM4: case FEM5: case FEM6:
1033
        case FEM7: case FEM8: case FEM9: case FEM10: case PODFEM1: case NAKED1: //case STATUE: //?
1034
        case SEENINE: case OOZFILTER:
1035
        case CRANEPOLE: case CRANE:
1036
        case NATURALLIGHTNING:
3424 helixhorne 1037
            link = 2;
1866 helixhorne 1038
            break;
1039
        }
1040
    }
1041
    else  // walls
1042
    {
2496 helixhorne 1043
#ifdef YAX_ENABLE
1044
        if (yax_getnextwall(num, YAX_CEILING) < 0)
1045
#endif
1866 helixhorne 1046
        switch (picnum)
1047
        {
1048
        case TECHLIGHT2: case TECHLIGHT4: case WALLLIGHT4:
1049
        case WALLLIGHT3: case WALLLIGHT1: case WALLLIGHT2:
1050
        case BIGFORCE: case W_FORCEFIELD:
3424 helixhorne 1051
            link = 1;
1866 helixhorne 1052
            break;
1053
        }
1054
    }
1055
 
1056
    if (!link)
2496 helixhorne 1057
#ifdef YAX_ENABLE
1058
    if (spritep || yax_getnextwall(num, YAX_CEILING) < 0)
1059
#endif
1866 helixhorne 1060
    {
1061
        // try a few that work both as sprites and as walls
1062
        switch (picnum)
1063
        {
1064
        case ACCESSSWITCH: case SLOTDOOR: case LIGHTSWITCH: case SPACEDOORSWITCH:
1065
        case SPACELIGHTSWITCH: case FRANKENSTINESWITCH: case MULTISWITCH:
1066
        case DIPSWITCH: case DIPSWITCH2: case TECHSWITCH: case DIPSWITCH3:
1067
        case ACCESSSWITCH2: case LIGHTSWITCH2: case POWERSWITCH1: case LOCKSWITCH1:
1068
        case POWERSWITCH2: case HANDSWITCH: case PULLSWITCH: case ALIENSWITCH:  // ---
1069
        case DOORTILE5: case DOORTILE6: case DOORTILE1: case DOORTILE2: case DOORTILE3:
1070
        case DOORTILE4: case DOORTILE7: case DOORTILE8: case DOORTILE9: case DOORTILE10:
1071
        case DOORTILE22: case DOORTILE18: case DOORTILE19: case DOORTILE20:
1072
        case DOORTILE14: case DOORTILE16: case DOORTILE15: case DOORTILE21:
1073
        case DOORTILE17: case DOORTILE11: case DOORTILE12: case DOORTILE23:  // ---
3424 helixhorne 1074
            link = 1;
1866 helixhorne 1075
            break;
1076
        }
1077
    }
1867 helixhorne 1078
 
1079
    g_iReturnVar = link;
1080
    VM_OnEvent(EVENT_LINKTAGS, spritep?num:-1);
1081
    link = g_iReturnVar;
1082
 
1866 helixhorne 1083
    return link;
1084
}
1085
 
1867 helixhorne 1086
int32_t taglab_getnextfreetag(void)
1087
{
3108 helixhorne 1088
    int32_t i, nextfreetag=1;
1089
 
1867 helixhorne 1090
    for (i=0; i<MAXSPRITES; i++)
1091
    {
3108 helixhorne 1092
        int32_t tag;
1093
 
1867 helixhorne 1094
        if (sprite[i].statnum == MAXSTATUS)
1095
            continue;
1096
 
1097
        if (sprite[i].picnum==MULTISWITCH)
1098
        {
1099
            // MULTISWITCH needs special care
1100
            int32_t endtag = sprite[i].lotag+3;
1101
            if (nextfreetag <= endtag)
1102
                nextfreetag = endtag+1;
1103
            continue;
1104
        }
1105
 
3108 helixhorne 1106
        tag = select_sprite_tag(i);
1107
 
1108
        if (tag != INT32_MIN && nextfreetag <= tag)
1109
            nextfreetag = tag+1;
1867 helixhorne 1110
    }
1111
 
1112
    for (i=0; i<numwalls; i++)
1113
    {
3108 helixhorne 1114
        int32_t lt = taglab_linktags(0, i);
1115
 
1867 helixhorne 1116
        if ((lt&1) && nextfreetag <= wall[i].lotag)
1117
            nextfreetag = wall[i].lotag+1;
1118
        if ((lt&2) && nextfreetag <= wall[i].hitag)
1119
            nextfreetag = wall[i].hitag+1;        
1120
    }
1121
 
1122
    if (nextfreetag < 32768)
1123
        return nextfreetag;
1124
 
1125
    return 0;
1126
}
1127
 
1128
 
1129
static void taglab_handle1(int32_t linktagp, int32_t tagnum, char *buf)
1130
{
1131
    const char *label = NULL;
1132
    if (linktagp && showtags==2)
1133
        label = taglab_getlabel(tagnum);
1134
 
1135
    if (label)
2158 helixhorne 1136
        Bsprintf(buf, "%d<%s>", tagnum, label);
1867 helixhorne 1137
    else
2158 helixhorne 1138
        Bsprintf(buf, "%d%s", tagnum, TLCHR(linktagp));
1867 helixhorne 1139
}
1866 helixhorne 1140
////////// end tag labeling system //////////
1141
 
1142
 
1644 helixhorne 1143
static int32_t getTileGroup(const char *groupName)
858 terminx 1144
{
1205 terminx 1145
    int32_t temp;
858 terminx 1146
    for (temp = 0; temp < MAX_TILE_GROUPS; temp++)
1147
    {
859 terminx 1148
        if (s_TileGroups[temp].szText == NULL)
858 terminx 1149
            return -1;
1644 helixhorne 1150
 
1151
        if (!Bstrcmp(s_TileGroups[temp].szText, groupName))
858 terminx 1152
            return temp;
1153
    }
1154
    return -1;
1155
}
1156
 
1644 helixhorne 1157
static int32_t tileInGroup(int32_t group, int32_t tilenum)
858 terminx 1158
{
1159
    // @todo Make a bitmap instead of doing this slow search..
1205 terminx 1160
    int32_t temp;
858 terminx 1161
    if (group < 0 || group >= MAX_TILE_GROUPS || s_TileGroups[group].szText == NULL)
1162
    {
1163
        // group isn't valid.
1164
        return 0;
1165
    }
1644 helixhorne 1166
    for (temp=0; temp<s_TileGroups[group].nIds; temp++)
858 terminx 1167
    {
1168
        if (tilenum == s_TileGroups[group].pIds[temp])
1169
            return 1;
1170
    }
1171
    return 0;
1172
}
1173
 
1205 terminx 1174
const char *ExtGetSectorType(int32_t lotag)
1049 terminx 1175
{
1176
    switch (lotag)
1177
    {
1865 helixhorne 1178
    case 1: return "WATER (SE 7)";
1179
    case 2: return "UNDERWATER (SE 7)";
1180
    case 9: return "STAR TREK DOORS";
1181
    case 15: return "ELEVATOR TRANSPORT (SE 17)";
1182
    case 16: return "ELEVATOR PLATFORM DOWN";
1183
    case 17: return "ELEVATOR PLATFORM UP";
1184
    case 18: return "ELEVATOR DOWN";
1185
    case 19: return "ELEVATOR UP";
1186
    case 20: return "CEILING DOOR";
1187
    case 21: return "FLOOR DOOR";
1188
    case 22: return "SPLIT DOOR";
1189
    case 23: return "SWING DOOR (SE 11)";
1190
    case 25: return "SLIDE DOOR (SE 15)";
1191
    case 26: return "SPLIT STAR TREK DOOR";
1192
    case 27: return "BRIDGE (SE 20)";
1193
    case 28: return "DROP FLOOR (SE 21)";
1194
    case 29: return "TEETH DOOR (SE 22)";
1195
    case 30: return "ROTATE RISE BRIDGE";
1196
    case 31: return "2 WAY TRAIN (SE=30)";
1197
    case 32767: return "SECRET ROOM";
1198
    case -1: return "END OF LEVEL";
1199
    default:
1049 terminx 1200
        if (lotag > 10000 && lotag < 32767)
1865 helixhorne 1201
            return "1 TIME SOUND";
1202
//        else Bsprintf(tempbuf,"%hu",lotag);
1049 terminx 1203
    }
1865 helixhorne 1204
 
1205
    return "";
1049 terminx 1206
}
1207
 
1205 terminx 1208
const char *ExtGetSectorCaption(int16_t sectnum)
5 Plagman 1209
{
1049 terminx 1210
    static char tempbuf[64];
5 Plagman 1211
 
1644 helixhorne 1212
    Bmemset(tempbuf, 0, sizeof(tempbuf));
1213
 
3823 helixhorne 1214
    if (!in3dmode() && ((onnames!=1 && onnames!=4 && onnames!=7) || onnames==8))
1644 helixhorne 1215
        return tempbuf;
1216
 
3823 helixhorne 1217
    if (in3dmode() || (sector[sectnum].lotag|sector[sectnum].hitag))
5 Plagman 1218
    {
1644 helixhorne 1219
        Bstrcpy(lo, ExtGetSectorType(sector[sectnum].lotag));
3823 helixhorne 1220
        if (!in3dmode())
3238 hendricks2 1221
            Bsprintf_nowarn(tempbuf,"%hu,%hu %s", TrackerCast(sector[sectnum].hitag), TrackerCast(sector[sectnum].lotag), lo);
1644 helixhorne 1222
        else
3238 hendricks2 1223
            Bsprintf_nowarn(tempbuf,"%hu %s", TrackerCast(sector[sectnum].lotag), lo);
5 Plagman 1224
    }
1225
    return(tempbuf);
1226
}
1227
 
1205 terminx 1228
const char *ExtGetWallCaption(int16_t wallnum)
5 Plagman 1229
{
1049 terminx 1230
    static char tempbuf[64];
1047 terminx 1231
 
1044 terminx 1232
    Bmemset(tempbuf,0,sizeof(tempbuf));
1047 terminx 1233
 
1234
    if (wall[wallnum].cstat & (1<<14))
1235
    {
1644 helixhorne 1236
        Bsprintf(tempbuf,"%d", wallength(wallnum));
1047 terminx 1237
        wall[wallnum].cstat &= ~(1<<14);
1238
        return(tempbuf);
1239
    }
1240
 
331 terminx 1241
    if (!(onnames==2 || onnames==4))
5 Plagman 1242
    {
1243
        tempbuf[0] = 0;
1244
        return(tempbuf);
1245
    }
1246
 
1247
    // HERE
1248
 
1249
    if ((wall[wallnum].lotag|wall[wallnum].hitag) == 0)
1250
        tempbuf[0] = 0;
1251
    else
1865 helixhorne 1252
    {
1866 helixhorne 1253
        int32_t lt = taglab_linktags(0, wallnum);
1867 helixhorne 1254
        char histr[TAGLAB_MAX+16], lostr[TAGLAB_MAX+16];
1255
 
3178 helixhorne 1256
        lt &= ~(int)(wall[wallnum].lotag<=0);
1257
        lt &= ~(int)((wall[wallnum].hitag<=0)<<1);
1867 helixhorne 1258
 
1259
        taglab_handle1(lt&2, wall[wallnum].hitag, histr);
1260
 
3658 helixhorne 1261
#ifdef YAX_ENABLE__COMPAT
1865 helixhorne 1262
        if (yax_getnextwall(wallnum, YAX_CEILING) >= 0)  // ceiling nextwall: lotag
1263
        {
1264
            if (wall[wallnum].hitag == 0)
1265
                tempbuf[0] = 0;
1266
            else
1867 helixhorne 1267
                Bsprintf(tempbuf, "%s,*", histr);
1865 helixhorne 1268
        }
1269
        else
1270
#endif
1867 helixhorne 1271
        {
1272
            taglab_handle1(lt&1, wall[wallnum].lotag, lostr);
1273
            Bsprintf(tempbuf, "%s,%s", histr, lostr);
1274
        }
1865 helixhorne 1275
    }
1644 helixhorne 1276
 
5 Plagman 1277
    return(tempbuf);
1278
} //end
1279
 
1205 terminx 1280
const char *SectorEffectorTagText(int32_t lotag)
5 Plagman 1281
{
1049 terminx 1282
    static char tempbuf[64];
1644 helixhorne 1283
 
1677 terminx 1284
    static const char *tags[] =
1285
    {
1644 helixhorne 1286
        "ROTATED SECTOR",                // 0
1287
        "PIVOT SPRITE FOR SE 0",
1288
        "EARTHQUAKE",
1289
        "RANDOM LIGHTS AFTER SHOT OUT",
1290
        "RANDOM LIGHTS",
1291
        "(UNKNOWN)",                     // 5
1292
        "SUBWAY",
1293
        "TRANSPORT",
1294
        "UP OPEN DOOR LIGHTS",
1295
        "DOWN OPEN DOOR LIGHTS",
1296
        "DOOR AUTO CLOSE (H=DELAY)",     // 10
1297
        "ROTATE SECTOR DOOR",
1298
        "LIGHT SWITCH",
1299
        "EXPLOSIVE",
1300
        "SUBWAY CAR",
1301
        "SLIDE DOOR (ST 25)",            // 15
1302
        "ROTATE REACTOR SECTOR",
1303
        "ELEVATOR TRANSPORT (ST 15)",
1304
        "INCREMENTAL SECTOR RISE/FALL",
1305
        "CEILING FALL ON EXPLOSION",
1306
        "BRIDGE (ST 27)",                // 20
1307
        "DROP FLOOR (ST 28)",
1308
        "TEETH DOOR (ST 29)",
1309
        "1-WAY SE7 DESTINATION (H=SE 7)",
1866 helixhorne 1310
        "CONVEYER BELT",
1644 helixhorne 1311
        "ENGINE",                        // 25
1312
        "(UNKNOWN)",
1833 helixhorne 1313
        "CAMERA FOR PLAYBACK",
1866 helixhorne 1314
        "LIGHTNING (H=TILE#4890)",
1644 helixhorne 1315
        "FLOAT",
1316
        "2 WAY TRAIN (ST=31)",           // 30
1924 helixhorne 1317
        "FLOOR RISE/FALL",
1318
        "CEILING RISE/FALL",
1644 helixhorne 1319
        "SPAWN JIB W/QUAKE",
1320
    };
1321
 
1044 terminx 1322
    Bmemset(tempbuf,0,sizeof(tempbuf));
1644 helixhorne 1323
 
1324
    if (lotag>=0 && lotag<(int32_t)(sizeof(tags)/sizeof(tags[0])))
1325
        Bsprintf(tempbuf, "%d: %s", lotag, tags[lotag]);
1326
    else
1327
        switch (lotag)
1328
        {
1329
        case 36:
1866 helixhorne 1330
            Bsprintf(tempbuf,"%d: SHOOTER",lotag);
1644 helixhorne 1331
            break;
1332
        case 49:
1333
            Bsprintf(tempbuf,"%d: POINT LIGHT",lotag);
1334
            break;
1335
        case 50:
1336
            Bsprintf(tempbuf,"%d: SPOTLIGHT",lotag);
1337
            break;
1338
        default:
1339
            Bsprintf(tempbuf,"%d: (UNKNOWN)",lotag);
1340
            break;
1341
        }
1342
 
5 Plagman 1343
    return (tempbuf);
1344
}
1345
 
1253 helixhorne 1346
const char *MusicAndSFXTagText(int32_t lotag)
1347
{
1348
    static char tempbuf[16];
1349
 
1350
    Bmemset(tempbuf, 0, sizeof(tempbuf));
1351
 
1352
    if (g_numsounds <= 0)
1316 terminx 1353
        return tempbuf;
1253 helixhorne 1354
 
1355
    if (lotag>0 && lotag<999 && g_sounds[lotag].definedname)
1356
        return g_sounds[lotag].definedname;
1357
 
1358
    if (lotag>=1000 && lotag<2000)
1359
        Bsprintf(tempbuf, "REVERB");
1360
    return tempbuf;
1361
}
1362
 
1205 terminx 1363
const char *SectorEffectorText(int32_t spritenum)
1049 terminx 1364
{
1365
    static char tempbuf[64];
1644 helixhorne 1366
 
1367
    Bmemset(tempbuf, 0, sizeof(tempbuf));
1368
    Bmemset(lo, 0, sizeof(lo));
1369
 
1370
    Bstrcpy(lo, SectorEffectorTagText(sprite[spritenum].lotag));
1049 terminx 1371
    if (!lo[5]) // tags are 5 chars or less
1644 helixhorne 1372
        SpriteName(spritenum, tempbuf);
1373
    else
1374
        Bsprintf(tempbuf, "SE %s",lo);
1375
 
1049 terminx 1376
    return (tempbuf);
1377
}
1378
 
1205 terminx 1379
const char *ExtGetSpriteCaption(int16_t spritenum)
5 Plagman 1380
{
1041 terminx 1381
    static char tempbuf[1024];
1866 helixhorne 1382
    int32_t retfast = 0, lt;
1044 terminx 1383
 
1384
    Bmemset(tempbuf,0,sizeof(tempbuf));
5 Plagman 1385
 
1644 helixhorne 1386
    if (!(onnames>=3 && onnames<=8) || (onnames==7 && sprite[spritenum].picnum!=SECTOREFFECTOR))
1387
        retfast = 1;
1388
    if (onnames==5 && !tileInGroup(tilegroupItems, sprite[spritenum].picnum))
1389
        retfast = 1;
1390
    if (onnames==6 && sprite[spritenum].picnum != sprite[cursprite].picnum)
1391
        retfast = 1;
5 Plagman 1392
 
1644 helixhorne 1393
    if (retfast)
1867 helixhorne 1394
        return tempbuf;
5 Plagman 1395
 
1866 helixhorne 1396
    lt = taglab_linktags(1, spritenum);
3178 helixhorne 1397
    lt &= ~(int)(sprite[spritenum].lotag<=0);
1398
    lt &= ~(int)((sprite[spritenum].hitag<=0)<<1);
1866 helixhorne 1399
 
5 Plagman 1400
    if ((sprite[spritenum].lotag|sprite[spritenum].hitag) == 0)
1401
    {
1402
        SpriteName(spritenum,lo);
331 terminx 1403
        if (lo[0]!=0)
5 Plagman 1404
        {
1866 helixhorne 1405
            if (sprite[spritenum].pal==1)
1406
                Bsprintf(tempbuf,"%s (MULTIPLAYER)",lo);
1407
            else
1408
                Bsprintf(tempbuf,"%s",lo);
5 Plagman 1409
        }
1867 helixhorne 1410
 
1411
        return tempbuf;
5 Plagman 1412
    }
1867 helixhorne 1413
 
1229 terminx 1414
    {
1867 helixhorne 1415
        char histr[TAGLAB_MAX+16], lostr[TAGLAB_MAX+16];
1416
 
1417
        taglab_handle1(lt&2, sprite[spritenum].hitag, histr);
1418
 
1419
        if (sprite[spritenum].picnum==SECTOREFFECTOR)
5 Plagman 1420
        {
1867 helixhorne 1421
            if (onnames!=8)
1422
            {
1423
                Bsprintf(lo,"%s",SectorEffectorText(spritenum));
1424
                Bsprintf(tempbuf,"%s, %s",lo, histr);
1425
            }
5 Plagman 1426
        }
1427
        else
1867 helixhorne 1428
        {
1429
            taglab_handle1(lt&1, sprite[spritenum].lotag, lostr);
1430
 
1431
            SpriteName(spritenum,lo);
1432
            if (sprite[spritenum].extra != -1)
3238 hendricks2 1433
                Bsprintf_nowarn(tempbuf,"%s,%s,%d %s", histr, lostr, TrackerCast(sprite[spritenum].extra), lo);
1867 helixhorne 1434
            else
1435
                Bsprintf(tempbuf,"%s,%s %s", histr, lostr, lo);
1436
        }
1229 terminx 1437
    }
1644 helixhorne 1438
 
1867 helixhorne 1439
    return tempbuf;
5 Plagman 1440
 
1441
} //end
1442
 
1443
//printext16 parameters:
1205 terminx 1444
//printext16(int32_t xpos, int32_t ypos, int16_t col, int16_t backcol,
5 Plagman 1445
//           char name[82], char fontsize)
1446
//  xpos 0-639   (top left)
1447
//  ypos 0-479   (top left)
1448
//  col 0-15
1449
//  backcol 0-15, -1 is transparent background
1450
//  name
1451
//  fontsize 0=8*8, 1=3*5
1452
 
1453
//drawline16 parameters:
1205 terminx 1454
// drawline16(int32_t x1, int32_t y1, int32_t x2, int32_t y2, char col)
5 Plagman 1455
//  x1, x2  0-639
1456
//  y1, y2  0-143  (status bar is 144 high, origin is top-left of STATUS BAR)
1457
//  col     0-15
1458
 
1797 helixhorne 1459
static void PrintStatus(const char *string, int32_t num, int32_t x, int32_t y, int32_t color)
1460
{
1461
    Bsprintf(tempbuf, "%s %d", string, num);
1462
    printext16(x*8, ydim-STATUS2DSIZ+y*8, editorcolors[color], -1, tempbuf, 0);
1463
}
1464
 
1205 terminx 1465
void ExtShowSectorData(int16_t sectnum)   //F5
5 Plagman 1466
{
1205 terminx 1467
    int32_t x,x2,y;
1644 helixhorne 1468
    int32_t i,yi;
1205 terminx 1469
    int32_t secrets=0;
1470
    int32_t totalactors1=0,totalactors2=0,totalactors3=0,totalactors4=0;
1471
    int32_t totalrespawn=0;
5 Plagman 1472
 
654 terminx 1473
    UNREFERENCED_PARAMETER(sectnum);
3823 helixhorne 1474
    if (in3dmode())
5 Plagman 1475
        return;
1476
 
1229 terminx 1477
    for (i=0; i<numsectors; i++)
1644 helixhorne 1478
        secrets += (sector[i].lotag==32767);
5 Plagman 1479
 
1865 helixhorne 1480
    for (i=headspritestat[0]; i != -1; i=nextspritestat[i])
5 Plagman 1481
    {
858 terminx 1482
        // Count all non-player actors.
1483
        if (tileInGroup(tilegroupActors, sprite[i].picnum))
5 Plagman 1484
        {
808 terminx 1485
            if (sprite[i].lotag<=1) totalactors1++;
1486
            if (sprite[i].lotag<=2) totalactors2++;
1487
            if (sprite[i].lotag<=3) totalactors3++;
1488
            if (sprite[i].lotag<=4) totalactors4++;
858 terminx 1489
        }
5 Plagman 1490
 
1797 helixhorne 1491
        if (sprite[i].picnum == RESPAWN)
1492
            totalrespawn++;
5 Plagman 1493
    }
1494
 
1644 helixhorne 1495
    Bmemset(numsprite, 0, sizeof(numsprite));
1496
    Bmemset(multisprite, 0, sizeof(numsprite));
1497
 
1229 terminx 1498
    for (i=0; i<MAXSPRITES; i++)
5 Plagman 1499
    {
1797 helixhorne 1500
        if (sprite[i].statnum==0 && sprite[i].picnum>=0 && sprite[i].picnum<MAXTILES)
5 Plagman 1501
        {
1644 helixhorne 1502
            if (sprite[i].pal!=0)
1503
                multisprite[sprite[i].picnum]++;
1504
            else
1505
                numsprite[sprite[i].picnum]++;
5 Plagman 1506
        }
1507
    }
1508
 
1509
    clearmidstatbar16();             //Clear middle of status bar
1392 helixhorne 1510
 
1511
    ydim -= 8;
1644 helixhorne 1512
    drawgradient();
1392 helixhorne 1513
    ydim += 8;
1514
 
1867 helixhorne 1515
    printmessage16("Level %s next tag %d", levelname, taglab_getnextfreetag());
5 Plagman 1516
 
1644 helixhorne 1517
#define PRSTAT(Str, Tiledef) \
1648 helixhorne 1518
    PrintStatus(Str, numsprite[Tiledef], x, y+yi, numsprite[Tiledef]?11:7); \
1519
    PrintStatus("",multisprite[Tiledef], x2,y+yi, multisprite[Tiledef]?9:7); \
1644 helixhorne 1520
    yi++;
1521
 
1522
    ydim -= 8; // vvvvvv reset at end!!
1523
 
1797 helixhorne 1524
    begindrawing();  //{{{
1525
 
1644 helixhorne 1526
    x=1; x2=14;
1527
    y=4; yi=2;
1528
    printext16(x*8, ydim-STATUS2DSIZ+y*8, editorcolors[11], -1, "Item Count", 0);
5 Plagman 1529
 
1644 helixhorne 1530
    PRSTAT("10%health=", COLA);
1531
    PRSTAT("30%health=", SIXPAK);
1532
    PRSTAT("Med-Kit  =", FIRSTAID);
1533
    PRSTAT("Atom     =", ATOMICHEALTH);
1534
    PRSTAT("Shields  =", SHIELD);
1535
 
1536
    x=17; x2=30;
1537
    y=4; yi=2;
1538
    printext16(x*8, ydim-STATUS2DSIZ+y*8, editorcolors[11], -1, "Inventory", 0);
5 Plagman 1539
 
1644 helixhorne 1540
    PRSTAT("Steroids =", STEROIDS);
1541
    PRSTAT("Airtank  =", AIRTANK);
1542
    PRSTAT("Jetpack  =", JETPACK);
1543
    PRSTAT("Goggles  =", HEATSENSOR);
1544
    PRSTAT("Boots    =", BOOTS);
1545
    PRSTAT("HoloDuke =", HOLODUKE);
1546
    PRSTAT("Multi D  =", APLAYER);
1547
 
1548
    x=33; x2=46;
1549
    y=4; yi=2;
1550
    printext16(x*8, ydim-STATUS2DSIZ+y*8, editorcolors[11], -1, "Weapon Count", 0);
5 Plagman 1551
 
1644 helixhorne 1552
    PRSTAT("Pistol   =", FIRSTGUNSPRITE);
1553
    PRSTAT("Shotgun  =", SHOTGUNSPRITE);
1554
    PRSTAT("Chaingun =", CHAINGUNSPRITE);
1555
    PRSTAT("RPG      =", RPGSPRITE);
1556
    PRSTAT("Pipe Bomb=", HEAVYHBOMB);
1557
    PRSTAT("Shrinker =", SHRINKERSPRITE);
1558
    PRSTAT("Devastatr=", DEVISTATORSPRITE);
1559
    PRSTAT("Trip mine=", TRIPBOMBSPRITE);
1560
    PRSTAT("Freezeray=", FREEZESPRITE);
1561
 
1562
    x=49; x2=62;
1563
    y=4; yi=2;
1361 terminx 1564
    printext16(x*8,ydim-STATUS2DSIZ+y*8,editorcolors[11],-1,"Ammo Count",0);
5 Plagman 1565
 
1644 helixhorne 1566
    PRSTAT("Pistol   =", AMMO);
1567
    PRSTAT("Shot     =", SHOTGUNAMMO);
1568
    PRSTAT("Chain    =", BATTERYAMMO);
1569
    PRSTAT("RPG Box  =", RPGAMMO);
1570
    PRSTAT("Pipe Bomb=", HBOMBAMMO);
1571
    PRSTAT("Shrinker =", CRYSTALAMMO);
1572
    PRSTAT("Devastatr=", DEVISTATORAMMO);
1573
    PRSTAT("Expander =", GROWAMMO);
1574
    PRSTAT("Freezeray=", FREEZEAMMO);
1575
 
1576
    printext16(65*8, ydim-STATUS2DSIZ+4*8, editorcolors[11], -1, "MISC", 0);
1577
    printext16(65*8, ydim-STATUS2DSIZ+8*8, editorcolors[11], -1, "ACTORS", 0);
5 Plagman 1578
 
1644 helixhorne 1579
#undef PRSTAT
1580
 
1581
    PrintStatus("Secrets =", secrets, 65, 6, 11);
1582
    PrintStatus("Skill 1 =", totalactors1, 65, 10, 11);
1583
    PrintStatus("Skill 2 =", totalactors2, 65, 11, 11);
1584
    PrintStatus("Skill 3 =", totalactors3, 65, 12, 11);
1585
    PrintStatus("Skill 4 =", totalactors4, 65, 13, 11);
1586
    PrintStatus("Respawn =", totalrespawn, 65, 14, 11);
1587
 
1797 helixhorne 1588
    enddrawing();  //}}}
1589
 
1644 helixhorne 1590
    ydim += 8; // ^^^^^^ see above!
1867 helixhorne 1591
}
1644 helixhorne 1592
 
1205 terminx 1593
void ExtShowWallData(int16_t wallnum)       //F6
5 Plagman 1594
{
1867 helixhorne 1595
    int32_t i, runi, total=0, x, y, yi;
5 Plagman 1596
 
654 terminx 1597
    UNREFERENCED_PARAMETER(wallnum);
649 terminx 1598
 
3823 helixhorne 1599
    if (in3dmode())
5 Plagman 1600
        return;
1601
 
1644 helixhorne 1602
    clearmidstatbar16();
1603
    drawgradient();
1604
 
1867 helixhorne 1605
    printmessage16("Level %s next tag %d", levelname, taglab_getnextfreetag());
1644 helixhorne 1606
 
1607
 
1608
#define CASES_LIZTROOP \
1609
    LIZTROOP: case LIZTROOPRUNNING : case LIZTROOPSTAYPUT: case LIZTROOPSHOOT: \
1610
              case LIZTROOPJETPACK: case LIZTROOPONTOILET: case LIZTROOPDUCKING
1611
#define CASES_BOSS1  BOSS1: case BOSS1STAYPUT: case BOSS1SHOOT: case BOSS1LOB: case BOSSTOP
1612
 
1613
    Bmemset(numsprite, 0, sizeof(numsprite));
1614
    Bmemset(multisprite, 0, sizeof(multisprite));
1615
 
1229 terminx 1616
    for (i=0; i<MAXSPRITES; i++)
5 Plagman 1617
    {
1644 helixhorne 1618
        if (sprite[i].statnum==0 && sprite[i].pal)
1619
            switch (sprite[i].picnum)
1620
            {
1621
            case CASES_LIZTROOP:
1622
                numsprite[LIZTROOP]++;
1623
                break;
1624
            case CASES_BOSS1:
1625
                multisprite[BOSS1]++;
1626
                break;
1627
            case BOSS2:
1628
                multisprite[BOSS2]++;
1629
                break;
1630
            case BOSS3:
1631
                multisprite[BOSS3]++;
1632
            default:
1633
                break;
1634
            }
1635
    }
1636
 
1797 helixhorne 1637
    // runi==0: Count Normal Actors
1638
    // runi==1: Count Respawn Actors
1644 helixhorne 1639
    for (runi=0; runi<2; runi++)
1640
    {
1797 helixhorne 1641
        if (runi==1)
5 Plagman 1642
        {
1644 helixhorne 1643
            Bmemset(numsprite, 0, sizeof(numsprite));
1644
            Bmemset(multisprite, 0, sizeof(multisprite));
1645
        }
5 Plagman 1646
 
1644 helixhorne 1647
        for (i=0; i<MAXSPRITES; i++)
1648
        {
1797 helixhorne 1649
            int32_t pic;
1650
 
1651
            if (sprite[i].statnum!=0)
1652
                continue;
1653
 
1654
            if (runi==0 && sprite[i].pal!=0)
1655
                continue;
1656
 
1657
            if (runi==1 && sprite[i].picnum!=RESPAWN)
1658
                continue;
1659
 
3178 helixhorne 1660
            pic = (runi==0) ? (int)sprite[i].picnum : (int)sprite[i].hitag;
1797 helixhorne 1661
            if (pic<0 || pic>=MAXTILES)
1662
                continue;
1663
 
1664
            switch (pic)
1644 helixhorne 1665
            {
1797 helixhorne 1666
            case CASES_LIZTROOP:
1667
                numsprite[LIZTROOP]++;
1668
                break;
1669
            case PIGCOP: case PIGCOPSTAYPUT: case PIGCOPDIVE:
1670
                numsprite[PIGCOP]++;
1671
                break;
1672
            case LIZMAN: case LIZMANSTAYPUT: case LIZMANSPITTING: case LIZMANFEEDING: case LIZMANJUMP:
1673
                numsprite[LIZMAN]++;
1674
                break;
1675
            case CASES_BOSS1:
1676
                if (runi==0 || sprite[i].pal==0)
1677
                    numsprite[BOSS1]++;
1678
                else
1679
                    multisprite[BOSS1]++;
1680
                break;
1681
            case COMMANDER:
1682
            case COMMANDERSTAYPUT:
1683
                numsprite[COMMANDER]++;
1684
                break;
1685
            case OCTABRAIN:
1686
            case OCTABRAINSTAYPUT:
1687
                numsprite[OCTABRAIN]++;
1688
                break;
1689
            case RECON: case DRONE: case ROTATEGUN: case EGG: case ORGANTIC: case GREENSLIME:
1690
            case BOSS2: case BOSS3: case TANK: case NEWBEAST: case NEWBEASTSTAYPUT: case BOSS4:
1691
                numsprite[pic]++;
1692
                break;
1693
            default:
1694
                break;
1695
            }
1696
        }
337 terminx 1697
 
1644 helixhorne 1698
#undef CASES_LIZTROOP
1699
#undef CASES_BOSS1
337 terminx 1700
 
1644 helixhorne 1701
        total=0;
1797 helixhorne 1702
        for (i=0; i<MAXTILES; i++)
1644 helixhorne 1703
            total += numsprite[i];
1797 helixhorne 1704
        for (i=0; i<MAXTILES; i++)
1644 helixhorne 1705
            total += multisprite[i];
1392 helixhorne 1706
 
1797 helixhorne 1707
        begindrawing();  //{{{
1708
 
1644 helixhorne 1709
        x=2+runi*34;
1710
        y=4;
1648 helixhorne 1711
        PrintStatus(runi==0?"Normal actors:":"Respawn actors:", total, x, y, 11);
337 terminx 1712
 
1648 helixhorne 1713
#define PRSTAT(Str, Tiledef)  PrintStatus(Str, numsprite[Tiledef], x, y+(yi++), numsprite[Tiledef]?11:7);
1644 helixhorne 1714
        yi=1;
337 terminx 1715
 
1644 helixhorne 1716
        PRSTAT(" Liztroop  =", LIZTROOP);
1717
        PRSTAT(" Lizman    =", LIZMAN);
1718
        PRSTAT(" Commander =", COMMANDER);
1719
        PRSTAT(" Octabrain =", OCTABRAIN);
1720
        PRSTAT(" PigCop    =", PIGCOP);
1721
        PRSTAT(" Recon Car =", RECON);
1722
        PRSTAT(" Drone     =", DRONE);
1723
        PRSTAT(" Turret    =", ROTATEGUN);
1724
        PRSTAT(" Egg       =", EGG);
337 terminx 1725
 
1644 helixhorne 1726
        x+=17;
1727
        yi=1;
1728
        PRSTAT("Slimer    =", GREENSLIME);
1729
        PRSTAT("Boss1     =", BOSS1);
1648 helixhorne 1730
        PrintStatus("MiniBoss1 =", multisprite[BOSS1], x, y+(yi++), multisprite[BOSS1]?11:7);
1644 helixhorne 1731
        PRSTAT("Boss2     =", BOSS2);
1732
        PRSTAT("Boss3     =", BOSS3);
1733
        PRSTAT("Riot Tank =", TANK);
1734
        PRSTAT("Newbeast  =", NEWBEAST);
1735
        PRSTAT("Boss4     =", BOSS4);
1736
#undef PRSTAT
1797 helixhorne 1737
 
1738
        enddrawing();  //}}}
1644 helixhorne 1739
    }
1867 helixhorne 1740
}
5 Plagman 1741
 
1797 helixhorne 1742
// formerly Show2dText and Show3dText
1959 helixhorne 1743
static void ShowFileText(const char *name)
5 Plagman 1744
{
3823 helixhorne 1745
    int32_t fp,t;
1205 terminx 1746
    uint8_t x=0,y=4,xmax=0,xx=0,col=0;
1644 helixhorne 1747
 
3823 helixhorne 1748
    if (!in3dmode())
1797 helixhorne 1749
    {
1750
        clearmidstatbar16();
1751
        drawgradient();
1752
    }
1392 helixhorne 1753
 
331 terminx 1754
    if ((fp=kopen4load(name,0)) == -1)
5 Plagman 1755
    {
2538 hendricks2 1756
        Bsprintf(tempbuf, "ERROR: file \"%s\" not found.", name);
3823 helixhorne 1757
        if (in3dmode())
1797 helixhorne 1758
            printext256(1*4,4*8,whitecol,-1,tempbuf,0);
1759
        else
1760
            printext16(1*4,ydim-STATUS2DSIZ+4*8,editorcolors[11],-1,tempbuf,0);
5 Plagman 1761
        return;
1762
    }
1763
 
1764
    t=65;
1765
    begindrawing();
331 terminx 1766
    while (t!=EOF && col<5)
5 Plagman 1767
    {
1768
        t = 0;
1769
        if (kread(fp,&t,1)<=0)
1770
            t = EOF;
331 terminx 1771
        while (t!=EOF && t!='\n' && x<250)
5 Plagman 1772
        {
1773
            tempbuf[x]=t;
335 terminx 1774
            t = 0;
1775
            if (kread(fp,&t,1)<=0) t = EOF;
1776
            x++;
1777
            if (x>xmax) xmax=x;
5 Plagman 1778
        }
1779
        tempbuf[x]=0;
1797 helixhorne 1780
 
3823 helixhorne 1781
        if (in3dmode())
1797 helixhorne 1782
            printext256(xx*4,(y*6)+2,whitecol,-1,tempbuf,1);
1783
        else
1784
            printext16(xx*4,ydim-STATUS2DSIZ+(y*6)+2,editorcolors[11],-1,tempbuf,1);
1785
 
335 terminx 1786
        x=0;
1787
        y++;
1788
        if (y>18)
1789
        {
1790
            col++;
1791
            y=6;
1792
            xx+=xmax;
1793
            xmax=0;
5 Plagman 1794
        }
1795
    }
1796
    enddrawing();
1797
 
1798
    kclose(fp);
1799
 
1867 helixhorne 1800
}
5 Plagman 1801
 
764 terminx 1802
// PK_ vvvv
1803
typedef struct helppage_
1804
{
1205 terminx 1805
    int32_t numlines;
764 terminx 1806
    char line[][80];  // C99 flexible array member
1807
} helppage_t;
1808
 
1644 helixhorne 1809
static helppage_t **helppage=NULL;
1810
static int32_t numhelppages=0;
764 terminx 1811
 
1205 terminx 1812
static int32_t emptyline(const char *start)
1048 terminx 1813
{
1205 terminx 1814
    int32_t i;
1048 terminx 1815
    for (i=0; i<80; i++)
1816
    {
1817
        if (start[i]=='\n' || !start[i]) break;
1818
        if (start[i]!=' ' && start[i]!='\t' && start[i]!='\r')
1819
            return 0;
1820
    }
1821
    return 1;
1822
}
1823
 
1205 terminx 1824
static int32_t newpage(const char *start)
764 terminx 1825
{
1205 terminx 1826
    int32_t i;
976 terminx 1827
    for (i=80-1; i>=0; i--)
764 terminx 1828
    {
784 terminx 1829
        if (start[i] == '^' && start[i+1] == 'P')
1830
            return 1;
764 terminx 1831
    }
784 terminx 1832
    return 0;
764 terminx 1833
}
1834
 
1835
#define IHELP_INITPAGES 32
1836
#define IHELP_INITLINES 16
1837
 
1838
static void ReadHelpFile(const char *name)
1839
{
1840
    BFILE *fp;
1205 terminx 1841
    int32_t i, j, k, numallocpages;
1842
    int32_t pos, charsread=0;
764 terminx 1843
    helppage_t *hp;
1844
    char skip=0;
1845
 
1040 terminx 1846
    initprintf("Loading \"%s\"\n",name);
1847
 
764 terminx 1848
    if ((fp=fopenfrompath(name,"rb")) == NULL)
1849
    {
1850
        initprintf("Error initializing integrated help: file \"%s\" not found.\n", name);
1851
        return;
1852
    }
1853
 
3176 helixhorne 1854
    helppage=(helppage_t **)Bmalloc(IHELP_INITPAGES * sizeof(helppage_t *));
764 terminx 1855
    numallocpages=IHELP_INITPAGES;
910 terminx 1856
    if (!helppage) goto HELPFILE_ERROR;
764 terminx 1857
 
1858
    i=0;
1859
    while (!Bfeof(fp) && !ferror(fp))
1860
    {
1861
        while (!Bfeof(fp))    // skip empty lines
1862
        {
1863
            pos = ftell(fp);
1103 terminx 1864
            if (Bfgets(tempbuf, 80, fp) == NULL) break;
764 terminx 1865
            charsread = ftell(fp)-pos;
784 terminx 1866
            if (!newpage(tempbuf))
764 terminx 1867
            {
1868
                break;
1869
            }
1870
        }
1871
 
1872
        if (Bfeof(fp) || charsread<=0) break;
1873
 
3176 helixhorne 1874
        hp=(helppage_t *)Bcalloc(1,sizeof(helppage_t) + IHELP_INITLINES*80);
910 terminx 1875
        if (!hp) goto HELPFILE_ERROR;
764 terminx 1876
        hp->numlines = IHELP_INITLINES;
1877
 
1878
        if (charsread == 79 && tempbuf[78]!='\n') skip=1;
1879
        j=0;
1880
 
1881
        do
1882
        {
1883
            if (j >= hp->numlines)
1884
            {
3176 helixhorne 1885
                hp=(helppage_t *)Brealloc(hp, sizeof(helppage_t) + 2*hp->numlines*80);
910 terminx 1886
                if (!hp) goto HELPFILE_ERROR;
764 terminx 1887
                hp->numlines *= 2;
1888
            }
1889
 
1890
            // limit the line length to 78 chars and probably get rid of the CR
1891
            if (charsread>0)
1892
            {
1893
                tempbuf[charsread-1]=0;
2161 helixhorne 1894
                if (charsread>=2 && tempbuf[charsread-2]==0x0d)
1895
                    tempbuf[charsread-2]=0;
764 terminx 1896
            }
1897
 
1425 terminx 1898
            Bmemcpy(hp->line[j], tempbuf, 80);
764 terminx 1899
 
1900
            for (k=charsread; k<80; k++) hp->line[j][k]=0;
1901
 
1902
            if (skip)
1903
            {
1904
                while (fgetc(fp)!='\n' && !Bfeof(fp)) /*skip rest of line*/;
1905
                skip=0;
1906
            }
1907
 
1908
            pos = ftell(fp);
1103 terminx 1909
            if (Bfgets(tempbuf, 80, fp) == NULL) break;
764 terminx 1910
            charsread = ftell(fp)-pos;
1911
            if (charsread == 79 && tempbuf[78]!='\n') skip=1;
1912
 
1913
            j++;
1914
 
1915
        }
784 terminx 1916
        while (!newpage(tempbuf) && !Bfeof(fp) && charsread>0);
764 terminx 1917
 
3176 helixhorne 1918
        hp=(helppage_t *)Brealloc(hp, sizeof(helppage_t) + j*80);
910 terminx 1919
        if (!hp) goto HELPFILE_ERROR;
764 terminx 1920
        hp->numlines=j;
1921
 
1922
        if (i >= numallocpages)
1923
        {
3176 helixhorne 1924
            helppage = (helppage_t **)Brealloc(helppage, 2*numallocpages*sizeof(helppage_t *));
764 terminx 1925
            numallocpages *= 2;
910 terminx 1926
            if (!helppage) goto HELPFILE_ERROR;
764 terminx 1927
        }
1928
        helppage[i] = hp;
1929
        i++;
1930
    }
1931
 
3176 helixhorne 1932
    helppage =(helppage_t **) Brealloc(helppage, i*sizeof(helppage_t *));
910 terminx 1933
    if (!helppage) goto HELPFILE_ERROR;
764 terminx 1934
    numhelppages = i;
1935
 
1936
    Bfclose(fp);
1937
    return;
1938
 
910 terminx 1939
HELPFILE_ERROR:
764 terminx 1940
    Bfclose(fp);
1941
    initprintf("ReadHelpFile(): ERROR allocating memory.\n");
1942
    return;
1943
}
1944
 
1050 terminx 1945
// why can't MSVC allocate an array of variable size?!
1396 helixhorne 1946
#define IHELP_NUMDISPLINES 110 // ((overridepm16y>>4)+(overridepm16y>>5)+(overridepm16y>>7)-2)
764 terminx 1947
#define IHELP_PATLEN 45
1648 helixhorne 1948
extern int32_t overridepm16y;  // influences clearmidstatbar16()
764 terminx 1949
 
1854 helixhorne 1950
static void IntegratedHelp(void)
764 terminx 1951
{
1952
    if (!helppage) return;
1953
 
1361 terminx 1954
    overridepm16y = ydim;//3*STATUS2DSIZ;
1048 terminx 1955
 
1049 terminx 1956
    {
1644 helixhorne 1957
        int32_t i, j;
1205 terminx 1958
        static int32_t curhp=0, curline=0;
1959
        int32_t highlighthp=-1, highlightline=-1, lasthighlighttime=0;
1049 terminx 1960
        char disptext[IHELP_NUMDISPLINES][80];
1961
        char oldpattern[IHELP_PATLEN+1];
1048 terminx 1962
 
1648 helixhorne 1963
        Bmemset(oldpattern, 0, sizeof(char));
1444 terminx 1964
        //    clearmidstatbar16();
764 terminx 1965
 
1854 helixhorne 1966
        begindrawing();
1967
        CLEARLINES2D(0, ydim, 0);
1968
        enddrawing();
1969
 
1049 terminx 1970
        while (keystatus[KEYSC_ESC]==0 && keystatus[KEYSC_Q]==0 && keystatus[KEYSC_F1]==0)
764 terminx 1971
        {
1486 helixhorne 1972
            idle_waitevent();
1049 terminx 1973
            if (handleevents())
1644 helixhorne 1974
                quitevent = 0;
1975
 
1444 terminx 1976
            //        printmessage16("Help mode, press <Esc> to exit");
764 terminx 1977
 
1854 helixhorne 1978
            if (keystatus[KEYSC_S])
1048 terminx 1979
            {
1869 helixhorne 1980
                fade_editor_screen(-1);
1854 helixhorne 1981
            }
1982
            else
1983
            {
1984
                begindrawing();
1985
                CLEARLINES2D(0, ydim, 0);
1986
                enddrawing();
1987
            }
1988
 
1989
            // based on 'save as' dialog in overheadeditor()
1990
            if (keystatus[KEYSC_S])    // text search
1991
            {
1992
                char ch, bad=0, pattern[IHELP_PATLEN+1];
1993
 
1994
                for (i=0; i<IHELP_PATLEN+1; i++) pattern[i]=0;
1995
 
1996
                i=0;
1997
                bflushchars();
1998
                while (bad == 0)
1999
                {
2000
                    _printmessage16("Search: %s_", pattern);
2001
                    showframe(1);
2002
 
2003
                    idle_waitevent();
2004
 
2005
                    if (handleevents())
2006
                        quitevent = 0;
2007
 
2008
                    ch = bgetchar();
2009
 
2010
                    if (keystatus[1]) bad = 1;
2011
                    else if (ch == 13) bad = 2;
2012
                    else if (ch > 0)
2013
                    {
2014
                        if (i > 0 && (ch == 8 || ch == 127))
2015
                        {
2016
                            i--;
2017
                            pattern[i] = 0;
2018
                        }
2019
                        else if (i < IHELP_PATLEN && ch >= 32 && ch < 128)
2020
                        {
2021
                            pattern[i++] = ch;
2022
                            pattern[i] = 0;
2023
                        }
2024
                    }
2025
                }
2026
 
2027
                if (bad==1)
2028
                {
2029
                    keystatus[KEYSC_ESC] = keystatus[KEYSC_Q] = keystatus[KEYSC_F1] = 0;
2030
                }
2031
 
2032
                if (bad==2)
2033
                {
2034
                    keystatus[KEYSC_ENTER] = 0;
2035
 
2036
                    for (i=curhp; i<numhelppages; i++)
2037
                    {
2038
                        for (j = (i==curhp)?(curline+1):0; j<helppage[i]->numlines; j++)
2039
                        {
2040
                            // entering an empty pattern will search with the last used pattern
1874 helixhorne 2041
                            if (Bstrstr(helppage[i]->line[j], pattern[0]?pattern:oldpattern))
1854 helixhorne 2042
                            {
2043
                                curhp = i;
2044
 
2045
                                if ((curline=j) <= helppage[i]->numlines - 32 /*-IHELP_NUMDISPLINES*/) /**/;
2046
                                else if ((curline=helppage[i]->numlines- 32 /*-IHELP_NUMDISPLINES*/) >= 0) /**/;
2047
                                else curline=0;
2048
 
2049
                                highlighthp = i;
2050
                                highlightline = j;
2051
                                lasthighlighttime = totalclock;
2052
                                goto ENDFOR1;
2053
                            }
2054
                        }
2055
                    }
2056
ENDFOR1:
2057
                    if (pattern[0])
2058
                        Bmemcpy(oldpattern, pattern, IHELP_PATLEN+1);
2059
                }
2060
            }
2061
            else if (PRESSED_KEYSC(T))    // goto table of contents
2062
            {
1049 terminx 2063
                curhp=0;
2064
                curline=0;
1048 terminx 2065
            }
1644 helixhorne 2066
            else if (PRESSED_KEYSC(G))    // goto arbitrary page
1048 terminx 2067
            {
1644 helixhorne 2068
                curhp=getnumber16("Goto page: ", 0, numhelppages-1, 0);
1049 terminx 2069
                curline=0;
1048 terminx 2070
            }
1644 helixhorne 2071
            else if (PRESSED_KEYSC(UP))    // scroll up
1048 terminx 2072
            {
1049 terminx 2073
                if (curline>0) curline--;
1048 terminx 2074
            }
1644 helixhorne 2075
            else if (PRESSED_KEYSC(DOWN))    // scroll down
764 terminx 2076
            {
1361 terminx 2077
                if (curline + 32/*+IHELP_NUMDISPLINES*/ < helppage[curhp]->numlines) curline++;
764 terminx 2078
            }
1644 helixhorne 2079
            else if (PRESSED_KEYSC(PGUP))    // scroll one page up
764 terminx 2080
            {
1049 terminx 2081
                i=IHELP_NUMDISPLINES;
2082
                while (i>0 && curline>0) i--, curline--;
2083
            }
1644 helixhorne 2084
            else if (PRESSED_KEYSC(PGDN))    // scroll one page down
1049 terminx 2085
            {
2086
                i=IHELP_NUMDISPLINES;
1361 terminx 2087
                while (i>0 && curline + 32/*+IHELP_NUMDISPLINES*/ < helppage[curhp]->numlines) i--, curline++;
1049 terminx 2088
            }
1644 helixhorne 2089
            else if (PRESSED_KEYSC(SPACE))   // goto next paragraph
1049 terminx 2090
            {
2091
                for (i=curline, j=0; i < helppage[curhp]->numlines; i++)
2092
                {
2093
                    if (emptyline(helppage[curhp]->line[i])) { j=1; continue; }
2094
                    if (j==1 && !emptyline(helppage[curhp]->line[i])) { j=2; break; }
2095
                }
2096
                if (j==2)
2097
                {
1361 terminx 2098
                    if (i + 32 /*+IHELP_NUMDISPLINES*/ < helppage[curhp]->numlines)
1049 terminx 2099
                        curline=i;
1361 terminx 2100
                    else if (helppage[curhp]->numlines - 32/*-IHELP_NUMDISPLINES*/ > curline)
2101
                        curline = helppage[curhp]->numlines - 32/*-IHELP_NUMDISPLINES*/;
1049 terminx 2102
                }
2103
            }
1644 helixhorne 2104
            else if (PRESSED_KEYSC(BS))   // goto prev paragraph
1049 terminx 2105
            {
2106
                for (i=curline-1, j=0; i>=0; i--)
2107
                {
2108
                    if (!emptyline(helppage[curhp]->line[i])) { j=1; continue; }
2109
                    if (j==1 && emptyline(helppage[curhp]->line[i])) { j=2; break; }
2110
                }
2111
                if (j==2 || i==-1) curline=i+1;
2112
            }
1644 helixhorne 2113
            else if (PRESSED_KEYSC(HOME))    // goto beginning of page
1049 terminx 2114
            {
764 terminx 2115
                curline=0;
2116
            }
1644 helixhorne 2117
            else if (PRESSED_KEYSC(END))    // goto end of page
1049 terminx 2118
            {
1361 terminx 2119
                if ((curline=helppage[curhp]->numlines - 32/*-IHELP_NUMDISPLINES*/) >= 0) /**/;
1049 terminx 2120
                else curline=0;
2121
            }
1644 helixhorne 2122
            else if (PRESSED_KEYSC(LEFT) || PRESSED_KEYSC(LBRACK))    // prev page
1049 terminx 2123
            {
2124
                if (curhp>0)
2125
                {
2126
                    curhp--;
2127
                    curline=0;
2128
                }
2129
            }
1644 helixhorne 2130
            else if (PRESSED_KEYSC(RIGHT) || PRESSED_KEYSC(RBRACK))    // next page
1049 terminx 2131
            {
2132
                if (curhp<numhelppages-1)
2133
                {
2134
                    curhp++;
2135
                    curline=0;
2136
                }
2137
            }
2138
            else    // '1'-'0' on the upper row
764 terminx 2139
            {
1049 terminx 2140
                for (i=2; i<=11; i++)
2141
                    if (keystatus[i]) break;
2142
                if (i--<12 && i<numhelppages)
2143
                {
2144
                    curhp=i;
2145
                    curline=0;
2146
                }
764 terminx 2147
            }
2148
 
1648 helixhorne 2149
//            drawgradient();
1055 terminx 2150
 
1644 helixhorne 2151
            begindrawing();
2152
            printext16(9, ydim2d-overridepm16y+9, editorcolors[4], -1, "Help Mode", 0);
2153
            printext16(8, ydim2d-overridepm16y+8, editorcolors[12], -1, "Help Mode", 0);
1648 helixhorne 2154
            printext16(8 + 9*8 + 2*8, ydim2d-overridepm16y+8, editorcolors[15], -1, "(S:search)", 0);
1644 helixhorne 2155
            enddrawing();
1055 terminx 2156
 
1049 terminx 2157
            if (curhp < helppage[0]->numlines)
1644 helixhorne 2158
                _printmessage16("%s", helppage[0]->line[curhp]);
1049 terminx 2159
            else
1644 helixhorne 2160
                _printmessage16("%d. (Untitled page)", curhp);
764 terminx 2161
 
1049 terminx 2162
            for (i=0; j=(curhp==0)?(i+curline+1):(i+curline),
1450 terminx 2163
                    i<IHELP_NUMDISPLINES && j<helppage[curhp]->numlines; i++)
1049 terminx 2164
            {
1648 helixhorne 2165
                if (ydim-overridepm16y+28+i*9+32 >= ydim)
2166
                    break;
1049 terminx 2167
                Bmemcpy(disptext[i], helppage[curhp]->line[j], 80);
1648 helixhorne 2168
                printext16(8, ydim-overridepm16y+28+i*9, editorcolors[10],
1450 terminx 2169
                           (j==highlightline && curhp==highlighthp
1677 terminx 2170
                            && totalclock-lasthighlighttime<120*5) ?
1648 helixhorne 2171
                           editorcolors[1] : -1,
2172
                           disptext[i], 0);
1049 terminx 2173
            }
2174
 
2175
            showframe(1);
764 terminx 2176
        }
2177
 
2488 helixhorne 2178
        clearkeys();
2179
    }
1049 terminx 2180
 
2488 helixhorne 2181
    overridepm16y = -1;
764 terminx 2182
}
1247 helixhorne 2183
 
2184
#define SOUND_NUMDISPLINES IHELP_NUMDISPLINES
2185
 
1250 helixhorne 2186
static int32_t compare_sounds_s(int16_t k1, int16_t k2)
1249 helixhorne 2187
{
2188
    return (int32_t)k1 - (int32_t)k2;
2189
}
1250 helixhorne 2190
static int32_t compare_sounds_d(int16_t k1, int16_t k2)
1249 helixhorne 2191
{
2192
    sound_t *s1 = &g_sounds[k1], *s2 = &g_sounds[k2];
2193
    char *n1 = s1->definedname, *n2 = s2->definedname;
2194
 
2195
    if (!n1 && !n2) return 0;
2196
    if (!n1) return -1;
2197
    if (!n2) return 1;
1316 terminx 2198
    return Bstrcasecmp(n1, n2);
1249 helixhorne 2199
}
1250 helixhorne 2200
static int32_t compare_sounds_f(int16_t k1, int16_t k2)
1249 helixhorne 2201
{
2202
    sound_t *s1 = &g_sounds[k1], *s2 = &g_sounds[k2];
2203
    char *n1 = s1->filename, *n2 = s2->filename;
2204
 
2205
    if (!n1 && !n2) return 0;
2206
    if (!n1) return -1;
2207
    if (!n2) return 1;
1316 terminx 2208
    return Bstrcasecmp(n1, n2);
1249 helixhorne 2209
}
1250 helixhorne 2210
static int32_t compare_sounds_1(int16_t k1, int16_t k2)
1249 helixhorne 2211
{
2212
    return (g_sounds[k2].m&1) - (g_sounds[k1].m&1);
2213
}
1250 helixhorne 2214
static int32_t compare_sounds_2(int16_t k1, int16_t k2)
1249 helixhorne 2215
{
1316 terminx 2216
    return (g_sounds[k2].m&2) - (g_sounds[k1].m&2);
1249 helixhorne 2217
}
1250 helixhorne 2218
static int32_t compare_sounds_3(int16_t k1, int16_t k2)
1249 helixhorne 2219
{
2220
    return (g_sounds[k2].m&4) - (g_sounds[k1].m&4);
2221
}
1250 helixhorne 2222
static int32_t compare_sounds_4(int16_t k1, int16_t k2)
1249 helixhorne 2223
{
2224
    return (g_sounds[k2].m&8) - (g_sounds[k1].m&8);
2225
}
1250 helixhorne 2226
static int32_t compare_sounds_5(int16_t k1, int16_t k2)
1249 helixhorne 2227
{
2228
    return (g_sounds[k2].m&16) - (g_sounds[k1].m&16);
2229
}
2230
 
2231
 
2232
static int32_t sort_sounds(int32_t how)
2233
{
2234
    int32_t (*compare_sounds)(int16_t, int16_t) = NULL;
2235
 
2236
    int32_t ms, ofs, l, lb, r, rb, d, n, k1, k2;
2237
    int16_t *src, *dst, *source, *dest, *tmp;
2238
 
2239
    n = g_numsounds;
2240
    src = source = g_sndnum;
3176 helixhorne 2241
    dest = (int16_t *)Bmalloc(sizeof(int16_t) * n);
1249 helixhorne 2242
    dst = dest;
2243
    if (!dest) return -1;
2244
 
2245
    switch (how)
2246
    {
2247
    case 'g':  // restore original order
2248
        Bmemcpy(g_sndnum, g_definedsndnum, sizeof(int16_t)*n);
2249
        return 0;
2250
    case 's':
1250 helixhorne 2251
        compare_sounds = compare_sounds_s;
1249 helixhorne 2252
        break;
2253
    case 'd':
2254
        compare_sounds = compare_sounds_d;
2255
        break;
2256
    case 'f':
2257
        compare_sounds = compare_sounds_f;
2258
        break;
2259
    case '1':
2260
        compare_sounds = compare_sounds_1;
2261
        break;
2262
    case '2':
2263
        compare_sounds = compare_sounds_2;
2264
        break;
2265
    case '3':
2266
        compare_sounds = compare_sounds_3;
2267
        break;
2268
    case '4':
2269
        compare_sounds = compare_sounds_4;
2270
        break;
2271
    case '5':
2272
        compare_sounds = compare_sounds_5;
2273
        break;
2274
    default:
2275
        return -2;
2276
    }
2277
 
2278
    for (ms=1; ms<n; ms*=2)
2279
    {
2280
        for (ofs=0; ofs<n; ofs+=2*ms)
2281
        {
2282
            l = ofs;
2283
            r = ofs+ms;
2284
            d = ofs;
2285
            lb = min((l+ms), n);
2286
            rb = min((r+ms), n);
2287
            while (l < lb || r < rb)
2288
            {
2289
                if (l >= lb)
2290
                {
2291
                    dst[d++] = src[r++];
2292
                    continue;
2293
                }
2294
                if (r >= rb)
2295
                {
2296
                    dst[d++] = src[l++];
2297
                    continue;
2298
                }
2299
                k1 = src[l];
2300
                k2 = src[r];
2301
                if (compare_sounds(k1, k2) <= 0)
2302
                {
2303
                    dst[d++] = src[l++];
2304
                    continue;
1316 terminx 2305
                }
1249 helixhorne 2306
                dst[d++] = src[r++];
2307
            }
2308
        }
2309
        tmp = src;
2310
        src = dst;
2311
        dst = tmp;
2312
    }
2313
    if (src != source)
2314
        Bmemcpy(source, src, sizeof(int16_t) * n);
2315
 
2316
    Bfree(dest);
2317
    return 0;
2318
}
2319
 
1854 helixhorne 2320
static void SoundDisplay(void)
1247 helixhorne 2321
{
2322
    if (g_numsounds <= 0) return;
2323
 
1361 terminx 2324
    overridepm16y = ydim;//3*STATUS2DSIZ;
1247 helixhorne 2325
 
2326
    {
2327
        // cursnd is the first displayed line, cursnd+curofs is where the cursor is
2328
        static int32_t cursnd=0, curofs=0;
2488 helixhorne 2329
        char disptext[80];
1247 helixhorne 2330
 
2488 helixhorne 2331
        int32_t i, j;
2332
        const int32_t halfpage = (ydim-64)/(2*9);
2333
 
1251 helixhorne 2334
        while (keystatus[KEYSC_ESC]==0 && keystatus[KEYSC_Q]==0 && keystatus[KEYSC_F2]==0
1677 terminx 2335
                && keystatus[buildkeys[BK_MODE2D_3D]]==0)  // quickjump to 3d mode
1247 helixhorne 2336
        {
1648 helixhorne 2337
            begindrawing();
2338
            CLEARLINES2D(0, ydim16, 0);
2339
            enddrawing();
2340
 
1486 helixhorne 2341
            idle_waitevent();
1247 helixhorne 2342
            if (handleevents())
1644 helixhorne 2343
                quitevent = 0;
1247 helixhorne 2344
 
1648 helixhorne 2345
//            drawgradient();
1361 terminx 2346
 
1644 helixhorne 2347
            begindrawing();
2348
            printext16(9, ydim2d-overridepm16y+9, editorcolors[4], -1, "Sound Index", 0);
2349
            printext16(8, ydim2d-overridepm16y+8, editorcolors[12], -1, "Sound Index", 0);
1648 helixhorne 2350
            printext16(8 + 11*8 + 2*8, ydim2d-overridepm16y+8, editorcolors[15], -1, "(SPACE:play, S:sort)", 0);
1644 helixhorne 2351
            enddrawing();
1361 terminx 2352
 
1644 helixhorne 2353
            if (PRESSED_KEYSC(G))    // goto specified sound#
1247 helixhorne 2354
            {
1361 terminx 2355
                _printmessage16("                                                    ");
1644 helixhorne 2356
                j = getnumber16("Goto sound#: ", 0, g_numsounds-1, 0);
1247 helixhorne 2357
                for (i=0; i<g_numsounds; i++)
2358
                    if (g_sndnum[i]==j)
2359
                        break;
2360
                if (i != g_numsounds)
2361
                {
2362
                    if (i<SOUND_NUMDISPLINES)
2363
                        cursnd = 0, curofs = i;
2488 helixhorne 2364
                    else if (i>=g_numsounds-halfpage)
2365
                        cursnd = g_numsounds-halfpage, curofs = i-cursnd;
1247 helixhorne 2366
                    else
2488 helixhorne 2367
                        curofs = halfpage/2, cursnd = i-curofs;
1247 helixhorne 2368
                }
2369
            }
1644 helixhorne 2370
            else if (PRESSED_KEYSC(UP))    // scroll up
1247 helixhorne 2371
            {
2372
                if (curofs>0) curofs--;
2373
                else if (cursnd>0) cursnd--;
2374
            }
1644 helixhorne 2375
            else if (PRESSED_KEYSC(DOWN))    // scroll down
1247 helixhorne 2376
            {
2488 helixhorne 2377
                if (curofs < halfpage-1 && cursnd+curofs<g_numsounds-1)
1247 helixhorne 2378
                    curofs++;
2488 helixhorne 2379
                else if (cursnd + halfpage < g_numsounds)
1247 helixhorne 2380
                    cursnd++;
2381
            }
1644 helixhorne 2382
            else if (PRESSED_KEYSC(PGUP))    // scroll one page up
1247 helixhorne 2383
            {
2488 helixhorne 2384
                i = halfpage/2;
2385
 
1247 helixhorne 2386
                while (i>0 && curofs>0)
2387
                    i--, curofs--;
2388
                while (i>0 && cursnd>0)
2389
                    i--, cursnd--;
2390
            }
1644 helixhorne 2391
            else if (PRESSED_KEYSC(PGDN))    // scroll one page down
1247 helixhorne 2392
            {
2488 helixhorne 2393
                i = halfpage/2;
1247 helixhorne 2394
 
2488 helixhorne 2395
                while (i>0 && curofs < halfpage-1 && cursnd+curofs<g_numsounds-1)
1247 helixhorne 2396
                    i--, curofs++;
2488 helixhorne 2397
                while (i>0 && cursnd + halfpage < g_numsounds)
1247 helixhorne 2398
                    i--, cursnd++;
2399
            }
1644 helixhorne 2400
            else if (PRESSED_KEYSC(SPACE) || PRESSED_KEYSC(ENTER))   // play/stop sound
1247 helixhorne 2401
            {
2402
                int32_t j = cursnd+curofs;
2403
                int32_t k = g_sndnum[j];
1644 helixhorne 2404
 
1247 helixhorne 2405
                if (S_CheckSoundPlaying(0, k) > 0)
2406
                    S_StopSound(k);
2407
                else
2408
                    S_PlaySound(k);
2409
            }
1644 helixhorne 2410
            else if (PRESSED_KEYSC(HOME))    // goto first sound#
1247 helixhorne 2411
            {
2412
                cursnd = curofs = 0;
2413
            }
1644 helixhorne 2414
            else if (PRESSED_KEYSC(END))    // goto last sound#
1247 helixhorne 2415
            {
2488 helixhorne 2416
                if ((cursnd = g_numsounds - halfpage) >= 0)
2417
                    curofs = halfpage-1;
1247 helixhorne 2418
                else
2419
                {
2420
                    cursnd = 0;
2421
                    curofs = g_numsounds-1;
2422
                }
2423
            }
2424
 
1710 helixhorne 2425
            _printmessage16("                          FILE NAME         PITCH RANGE  PRI FLAGS VOLUME");
2426
            for (i=0; j=cursnd+i, i<SOUND_NUMDISPLINES && j<g_numsounds; i++)
1247 helixhorne 2427
            {
1710 helixhorne 2428
                int32_t l, m, k=g_sndnum[j];
2429
                sound_t *snd=&g_sounds[k];
2430
                char *cp;
1247 helixhorne 2431
 
1710 helixhorne 2432
                if (ydim-overridepm16y+28+i*9+32 >= ydim) break;
2433
 
2488 helixhorne 2434
                Bsprintf(disptext,
1710 helixhorne 2435
                         "%4d .................... ................ %6d:%-6d %3d %c%c%c%c%c %6d",
2436
                         //   5678901234567890X23456789012345678901234567
2437
                         k, snd->ps, snd->pe, snd->pr,
2438
                         snd->m&1 ? 'R':'-', snd->m&2 ? 'M':'-', snd->m&4 ? 'D':'-',
2439
                         snd->m&8 ? 'P':'-', snd->m&16 ? 'G':'-', snd->vo);
2488 helixhorne 2440
                for (l = Bsnprintf(disptext+5, 20, "%s", snd->definedname); l<20; l++)
2441
                    disptext[5+l] = ' ';
1710 helixhorne 2442
                if (snd->filename)
2443
                {
2444
                    l = Bstrlen(snd->filename);
2445
                    if (l<=16)
2446
                        cp = snd->filename;
2447
                    else
2448
                        cp = snd->filename + l-15;
2488 helixhorne 2449
                    for (m = Bsnprintf(disptext+26, 16, "%s", cp); m<16; m++)
2450
                        disptext[26+m] = ' ';
1710 helixhorne 2451
                    if (l>16)
2488 helixhorne 2452
                        disptext[26] = disptext[27] = disptext[28] = '.';
1710 helixhorne 2453
                }
2454
 
2455
                printext16(8, ydim-overridepm16y+28+i*9,
2456
                           keystatus[KEYSC_S]?editorcolors[8] : (S_CheckSoundPlaying(-1, k) ? editorcolors[2] : editorcolors[10]),
2457
                           j==cursnd+curofs ? editorcolors[1] : -1,
2488 helixhorne 2458
                           disptext, 0);
1710 helixhorne 2459
            }
2460
 
2461
            if (keystatus[KEYSC_S])    // sorting
2462
            {
2463
 
1247 helixhorne 2464
                char ch, bad=0;
2465
 
1710 helixhorne 2466
                _printmessage16("Sort by: (S)oundnum (D)ef (F)ile ori(g) or flags (12345)");
2467
                showframe(1);
2468
 
1247 helixhorne 2469
                i=0;
2470
                bflushchars(