Subversion Repositories eduke32

Rev

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