Subversion Repositories eduke32

Rev

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

Rev Author Line No. Line
1493 helixhorne 1
//-------------------------------------------------------------------------
2
/*
1652 terminx 3
Copyright (C) 2010 EDuke32 developers and contributors
1493 helixhorne 4
 
1652 terminx 5
This file is part of EDuke32.
1493 helixhorne 6
 
7
EDuke32 is free software; you can redistribute it and/or
8
modify it under the terms of the GNU General Public License version 2
9
as published by the Free Software Foundation.
10
 
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
 
15
See the GNU General Public License for more details.
16
 
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
4541 hendricks2 19
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
1493 helixhorne 20
*/
21
//-------------------------------------------------------------------------
22
 
23
#include <time.h>
24
#include <stdlib.h>
25
 
26
#include "m32script.h"
27
#include "m32def.h"
1848 helixhorne 28
 
1538 helixhorne 29
#include "sounds_mapster32.h"
30
#include "fx_man.h"
1493 helixhorne 31
 
32
#include "osd.h"
1497 helixhorne 33
#include "keys.h"
3243 helixhorne 34
#include "common.h"
1493 helixhorne 35
 
1848 helixhorne 36
// from macros.h
37
#define rnd(X) ((krand()>>8)>=(255-(X)))
38
 
1493 helixhorne 39
vmstate_t vm;
40
vmstate_t vm_default =
41
{
1955 helixhorne 42
    -1,   // g_i
43
    0,    // g_st
44
    NULL, // g_sp
45
    0,    // flags
46
    0,    // miscflags
1493 helixhorne 47
};
48
 
49
int32_t g_errorLineNum, g_tw;
50
 
51
uint8_t aEventEnabled[MAXEVENTS];
52
 
1497 helixhorne 53
uint32_t m32_drawlinepat=0xffffffff;
1692 helixhorne 54
int32_t m32_script_expertmode = 0;
1493 helixhorne 55
 
56
instype *insptr;
1625 terminx 57
int32_t VM_Execute(int32_t once);
1499 helixhorne 58
static instype *x_sortingstateptr;
1493 helixhorne 59
 
1722 helixhorne 60
//#include "m32structures.c"
1493 helixhorne 61
 
1698 helixhorne 62
#ifdef DEBUGGINGAIDS
1500 helixhorne 63
void X_Disasm(ofstype beg, int32_t size)
64
{
65
    instype *p;
66
 
67
    if (!script) return;
68
    if (beg<0 || beg+size>g_scriptSize) return;
69
 
70
    initprintf("beg=%d, size=%d:  ", beg, size);
71
    for (p=script+beg; p<script+beg+size; p++)
72
    {
73
        if (*p>>12 && (*p&0xFFF)<CON_END)
74
            initprintf("%s ", keyw[*p&0xFFF]);
75
        else
76
            initprintf("%d ", *p);
77
    }
78
    initprintf("\n");
79
}
1644 helixhorne 80
#endif
1500 helixhorne 81
 
1625 terminx 82
void VM_ScriptInfo(void)
1493 helixhorne 83
{
84
    if (script)
85
    {
86
        instype *p;
87
        if (insptr)
88
            for (p=max(insptr-20,script); p<min(insptr+20, script+g_scriptSize); p++)
89
            {
90
                if (p==insptr) initprintf("<<");
91
 
92
                if (*p>>12 && (*p&0xFFF)<CON_END)
1791 helixhorne 93
                    initprintf("\n%5d: L%5d:  %s ",(int32_t)(p-script),(int32_t)(*p>>12),keyw[*p&0xFFF]);
1493 helixhorne 94
                else initprintf(" %d",*p);
95
 
96
                if (p==insptr) initprintf(">>");
97
            }
98
        initprintf(" \n");
1500 helixhorne 99
        if (vm.g_i >= 0)
1493 helixhorne 100
            initprintf("current sprite: %d\n",vm.g_i);
101
        if (g_tw>=0 && g_tw<CON_END)
102
            initprintf("g_errorLineNum: %d, g_tw: %s\n",g_errorLineNum,keyw[g_tw]);
103
        else
104
            initprintf("g_errorLineNum: %d, g_tw: %d\n",g_errorLineNum,g_tw);
105
    }
106
}
107
 
1955 helixhorne 108
void M32_PostScriptExec(void)
109
{
110
    if (vm.miscflags&VMFLAG_MISC_UPDATEHL)
111
    {
112
        update_highlight();
113
        vm.miscflags &= ~VMFLAG_MISC_UPDATEHL;
114
    }
115
 
116
    if (vm.miscflags&VMFLAG_MISC_UPDATEHLSECT)
117
    {
118
        update_highlightsector();
3823 helixhorne 119
        if (!in3dmode())
1955 helixhorne 120
            ovh_whiteoutgrab(1);
121
        vm.miscflags &= ~VMFLAG_MISC_UPDATEHLSECT;
122
    }
123
}
124
 
1625 terminx 125
void VM_OnEvent(register int32_t iEventID, register int32_t iActor)
1493 helixhorne 126
{
127
    if (iEventID < 0 || iEventID >= MAXEVENTS)
128
    {
1661 helixhorne 129
        M32_PRINTERROR("Invalid event ID");
1493 helixhorne 130
        return;
131
    }
132
 
133
    if (aEventOffsets[iEventID] < 0 || !aEventEnabled[iEventID])
134
    {
135
        //Bsprintf(g_szBuf,"No event found for %d",iEventID);
136
        //AddLog(g_szBuf);
137
        return;
138
    }
139
 
140
    {
4798 helixhorne 141
        instype *const oinsptr=insptr;
1493 helixhorne 142
        vmstate_t vm_backup;
4798 helixhorne 143
        void *const olocalvars = aGameArrays[M32_LOCAL_ARRAY_ID].vals;
1692 helixhorne 144
#ifdef M32_LOCALS_VARARRAY
145
        int32_t localvars[aEventNumLocals[iEventID]];
146
#else
147
        int32_t localvars[M32_LOCALS_FIXEDNUM];
148
#endif
1493 helixhorne 149
 
4357 helixhorne 150
        // Initialize 'state'-local variables to 0.
1691 helixhorne 151
        if (aEventNumLocals[iEventID] > 0)
1695 helixhorne 152
            Bmemset(localvars, 0, aEventNumLocals[iEventID]*sizeof(int32_t));
1691 helixhorne 153
 
1493 helixhorne 154
        Bmemcpy(&vm_backup, &vm, sizeof(vmstate_t));
155
 
156
        vm.g_i = iActor;    // current sprite ID
157
        if (vm.g_i >= 0)
158
            vm.g_sp = &sprite[vm.g_i];
159
 
160
        vm.g_st = 1+iEventID;
161
 
1528 helixhorne 162
        vm.flags = 0;
1493 helixhorne 163
 
164
        insptr = script + aEventOffsets[iEventID];
1691 helixhorne 165
 
166
        aGameArrays[M32_LOCAL_ARRAY_ID].vals = localvars;
1625 terminx 167
        VM_Execute(0);
1691 helixhorne 168
        aGameArrays[M32_LOCAL_ARRAY_ID].vals = olocalvars;
1493 helixhorne 169
 
1528 helixhorne 170
        if (vm.flags&VMFLAG_ERROR)
1499 helixhorne 171
        {
1493 helixhorne 172
            aEventEnabled[iEventID] = 0;
1499 helixhorne 173
            message("ERROR executing %s. Event disabled.", label+(iEventID*MAXLABELLEN));
174
        }
1493 helixhorne 175
 
1955 helixhorne 176
        M32_PostScriptExec();
1710 helixhorne 177
 
1493 helixhorne 178
        // restore old values...
179
        Bmemcpy(&vm, &vm_backup, sizeof(vmstate_t));
180
        insptr = oinsptr;
181
 
182
        //AddLog("End of Execution");
183
    }
184
}
185
 
186
static int32_t G_GetAngleDelta(int32_t a,int32_t na)
187
{
188
    a &= 2047;
189
    na &= 2047;
190
 
191
    if (klabs(a-na) < 1024)
192
    {
193
//        OSD_Printf("G_GetAngleDelta() returning %d\n",na-a);
194
        return (na-a);
195
    }
196
 
197
    if (na > 1024) na -= 2048;
198
    if (a > 1024) a -= 2048;
199
 
200
//    OSD_Printf("G_GetAngleDelta() returning %d\n",na-a);
201
    return (na-a);
202
}
203
 
1625 terminx 204
static inline void __fastcall VM_DoConditional(register int32_t condition)
1493 helixhorne 205
{
206
    if (condition)
207
    {
208
        // skip 'else' pointer.. and...
209
        insptr+=2;
1625 terminx 210
        VM_Execute(1);
1493 helixhorne 211
        return;
212
    }
213
 
214
    insptr++;
215
    insptr += *insptr;
216
    if (((*insptr)&0xFFF) == CON_ELSE)
217
    {
218
        // else...
219
        // skip 'else' and...
220
        insptr+=2;
1625 terminx 221
        VM_Execute(1);
1493 helixhorne 222
    }
223
}
224
 
4068 helixhorne 225
static int X_DoSortDefault(const void *lv, const void *rv)
1499 helixhorne 226
{
4068 helixhorne 227
    return *(int32_t *)rv - *(int32_t *)lv;
1499 helixhorne 228
}
229
 
4068 helixhorne 230
static int X_DoSort(const void *lv, const void *rv)
1499 helixhorne 231
{
4068 helixhorne 232
    m32_sortvar1 = *(int32_t *)lv;
233
    m32_sortvar2 = *(int32_t *)rv;
1499 helixhorne 234
    insptr = x_sortingstateptr;
1625 terminx 235
    VM_Execute(0);
1499 helixhorne 236
    return g_iReturnVar;
237
}
238
 
1697 helixhorne 239
// in interactive execution, allow the current sprite index to be the aimed-at sprite (in 3d mode)
1493 helixhorne 240
#define X_ERROR_INVALIDCI()                                             \
241
    if ((vm.g_i < 0 || vm.g_i>=MAXSPRITES) &&                           \
242
        (vm.g_st!=0 || searchstat!=3 || (vm.g_i=searchwall, vm.g_sp=&sprite[vm.g_i], 0))) \
243
    {                                                                   \
1877 helixhorne 244
        M32_ERROR("Current sprite index invalid!"); \
1493 helixhorne 245
        continue;                                                       \
246
    }
247
 
248
#define X_ERROR_INVALIDSPRI(dasprite)                                   \
249
    if (dasprite < 0 || dasprite>=MAXSPRITES)                           \
250
    {                                                                   \
1877 helixhorne 251
        M32_ERROR("Invalid sprite index %d!",  dasprite); \
1493 helixhorne 252
        continue;                                                       \
253
    }
254
 
255
#define X_ERROR_INVALIDSECT(dasect)                                     \
256
    if (dasect < 0 || dasect>=numsectors)                               \
257
    {                                                                   \
1877 helixhorne 258
        M32_ERROR("Invalid sector index %d!",  dasect); \
1493 helixhorne 259
        continue;                                                       \
260
    }
261
 
262
#define X_ERROR_INVALIDSP()                                             \
263
    if (!vm.g_sp && (vm.g_st!=0 || searchstat!=3 || (vm.g_sp=&sprite[searchwall], 0))) \
264
    {                                                                   \
1877 helixhorne 265
        M32_ERROR("Current sprite invalid!"); \
1493 helixhorne 266
        continue;                                                       \
267
    }
268
 
1497 helixhorne 269
#define X_ERROR_INVALIDQUOTE(q, array)                                  \
270
    if (q<0 || q>=MAXQUOTES)                                            \
271
    {                                                                   \
1877 helixhorne 272
        M32_ERROR("Invalid quote number %d!",  q); \
1497 helixhorne 273
        continue;                                                       \
274
    }                                                                   \
275
    else if (array[q] == NULL)                                          \
276
    {                                                                   \
1877 helixhorne 277
        M32_ERROR("Null quote %d!",  q); \
1497 helixhorne 278
        continue;                                                       \
279
    }                                                                   \
1691 helixhorne 280
 
281
static char *GetMaybeInlineQuote(int32_t quotei)
282
{
283
    char *quotetext;
284
    if (quotei==-1)
285
    {
286
        quotetext = (char *)insptr;
287
        while (*insptr++) /* skip the string */;
288
    }
289
    else
290
    {
291
        quotei = Gv_GetVarX(quotei);
292
        do { X_ERROR_INVALIDQUOTE(quotei, ScriptQuotes) } while (0);
293
        if (vm.flags&VMFLAG_ERROR)
294
            return NULL;
295
        quotetext = ScriptQuotes[quotei];
296
    }
297
 
298
    return quotetext;
299
}
4798 helixhorne 300
 
301
static int CheckArray(int aidx)
302
{
303
    if (!(aidx >= 0 && aidx < g_gameArrayCount))
304
        M32_ERROR("Invalid array %d!", aidx);
305
 
306
    return (vm.flags&VMFLAG_ERROR);
307
}
308
 
1625 terminx 309
int32_t VM_Execute(int32_t once)
1493 helixhorne 310
{
311
    register int32_t tw = *insptr;
312
 
313
    // jump directly into the loop, saving us from the checks during the first iteration
314
    goto skip_check;
315
 
316
    while (!once)
317
    {
1528 helixhorne 318
        if (vm.flags)
1493 helixhorne 319
            return 1;
320
 
321
        tw = *insptr;
322
 
323
skip_check:
324
        //      Bsprintf(g_szBuf,"Parsing: %d",*insptr);
325
        //      AddLog(g_szBuf);
326
 
327
        g_errorLineNum = tw>>12;
328
        g_tw = (tw &= 0xFFF);
329
 
330
        switch (tw)
331
        {
332
// *** basic commands
333
        case CON_NULLOP:
334
            insptr++;
335
            continue;
336
 
337
        case CON_STATE:
338
        {
4798 helixhorne 339
            instype *const tempscrptr = insptr+2;
340
            const int32_t stateidx = *(insptr+1), o_g_st = vm.g_st, oret=vm.flags&VMFLAG_RETURN;
341
            void *const olocalvars = aGameArrays[M32_LOCAL_ARRAY_ID].vals;
1692 helixhorne 342
#ifdef M32_LOCALS_VARARRAY
343
            int32_t localvars[statesinfo[stateidx].numlocals];
344
#else
345
            int32_t localvars[M32_LOCALS_FIXEDNUM];
346
#endif
1493 helixhorne 347
 
1691 helixhorne 348
            // needed since any read access before initialization would cause undefined behaviour
349
            if (statesinfo[stateidx].numlocals > 0)
1695 helixhorne 350
                Bmemset(localvars, 0, statesinfo[stateidx].numlocals*sizeof(int32_t));
1691 helixhorne 351
 
1493 helixhorne 352
            insptr = script + statesinfo[stateidx].ofs;
353
            vm.g_st = 1+MAXEVENTS+stateidx;
1691 helixhorne 354
            aGameArrays[M32_LOCAL_ARRAY_ID].vals = localvars;
1625 terminx 355
            VM_Execute(0);
1691 helixhorne 356
            aGameArrays[M32_LOCAL_ARRAY_ID].vals = olocalvars;
1493 helixhorne 357
            vm.g_st = o_g_st;
1528 helixhorne 358
            vm.flags &= ~VMFLAG_RETURN;
359
            vm.flags |= oret;
1493 helixhorne 360
            insptr = tempscrptr;
361
        }
362
        continue;
363
 
364
        case CON_RETURN:
1528 helixhorne 365
            vm.flags |= VMFLAG_RETURN;
366
            return 1;
1493 helixhorne 367
        case CON_BREAK:
1528 helixhorne 368
            vm.flags |= VMFLAG_BREAK;
4880 helixhorne 369
            // XXX: may not be cleared subsequently?
1493 helixhorne 370
        case CON_ENDS:
371
            return 1;
372
 
373
        case CON_ELSE:
374
            insptr++;
375
            insptr += *insptr;
376
            continue;
377
 
378
        case CON_ENDSWITCH:
1528 helixhorne 379
            vm.flags &= ~VMFLAG_BREAK;
1493 helixhorne 380
        case CON_ENDEVENT:
381
            insptr++;
382
            return 1;
383
 
384
        case CON_SWITCH:
385
            insptr++; // p-code
386
            {
387
                // command format:
388
                // variable ID to check
389
                // script offset to 'end'
390
                // count of case statements
391
                // script offset to default case (null if none)
392
                // For each case: value, ptr to code
393
                //AddLog("Processing Switch...");
394
                int32_t lValue=Gv_GetVarX(*insptr++), lEnd=*insptr++, lCases=*insptr++;
395
                instype *lpDefault=insptr++, *lpCases=insptr, *lCodeInsPtr;
396
                int32_t bMatched=0, lCheckCase;
397
                int32_t left,right;
398
 
399
                insptr += lCases*2;
400
                lCodeInsPtr = insptr;
1593 terminx 401
                //Bsprintf(g_szBuf,"lEnd= %d *lpDefault=%d",lEnd,*lpDefault); AddLog(g_szBuf);
402
                //Bsprintf(g_szBuf,"Checking %d cases for %d",lCases, lValue); AddLog(g_szBuf);
1493 helixhorne 403
                left = 0;
404
                right = lCases-1;
405
                while (!bMatched)
406
                {
1593 terminx 407
                    //Bsprintf(g_szBuf,"Checking #%d Value= %d",lCheckCase, lpCases[lCheckCase*2]); AddLog(g_szBuf);
1493 helixhorne 408
                    lCheckCase=(left+right)/2;
1593 terminx 409
                    //                initprintf("(%2d..%2d..%2d) [%2d..%2d..%2d]==%2d\n",left,lCheckCase,right,lpCases[left*2],lpCases[lCheckCase*2],lpCases[right*2],lValue);
1493 helixhorne 410
                    if (lpCases[lCheckCase*2] > lValue)
411
                        right = lCheckCase-1;
412
                    else if (lpCases[lCheckCase*2] < lValue)
413
                        left = lCheckCase+1;
414
                    else if (lpCases[lCheckCase*2] == lValue)
415
                    {
416
                        //AddLog("Found Case Match");
1593 terminx 417
                        //Bsprintf(g_szBuf,"insptr=%d. lCheckCase=%d, offset=%d, &script[0]=%d", (int32_t)insptr,(int32_t)lCheckCase,lpCases[lCheckCase*2+1],(int32_t)&script[0]); AddLog(g_szBuf);
1493 helixhorne 418
                        // fake a 2-d Array
419
                        insptr = lCodeInsPtr + lpCases[lCheckCase*2+1];
1593 terminx 420
                        //Bsprintf(g_szBuf,"insptr=%d. ",     (int32_t)insptr); AddLog(g_szBuf);
1625 terminx 421
                        VM_Execute(0);
1493 helixhorne 422
                        //AddLog("Done Executing Case");
423
                        bMatched=1;
424
                    }
1799 helixhorne 425
 
1493 helixhorne 426
                    if (right-left < 0)
427
                        break;
428
                }
1799 helixhorne 429
 
1493 helixhorne 430
                if (!bMatched)
431
                {
432
                    if (*lpDefault >= 0)
433
                    {
434
                        //AddLog("No Matching Case: Using Default");
435
                        insptr = lCodeInsPtr + *lpDefault;
1625 terminx 436
                        VM_Execute(0);
1493 helixhorne 437
                    }
438
//                    else
439
//                    {
440
//                        //AddLog("No Matching Case: No Default to use");
441
//                    }
442
                }
1499 helixhorne 443
                insptr = (instype *)(lCodeInsPtr + lEnd);
1955 helixhorne 444
                vm.flags &= ~VMFLAG_BREAK;
1593 terminx 445
                //Bsprintf(g_szBuf,"insptr=%d. ",     (int32_t)insptr); AddLog(g_szBuf);
1493 helixhorne 446
                //AddLog("Done Processing Switch");
447
                continue;
448
            }
449
 
450
        case CON_GETCURRADDRESS:
451
            insptr++;
452
            {
453
                int32_t j=*insptr++;
454
                Gv_SetVarX(j, insptr-script);
455
            }
456
            continue;
457
 
458
        case CON_JUMP:
459
            insptr++;
460
            {
461
                int32_t j = Gv_GetVarX(*insptr++);
462
                if (j<0 || j>=(g_scriptPtr-script))
463
                {
1877 helixhorne 464
                    M32_ERROR("script index out of bounds (%d)",  j);
1493 helixhorne 465
                    continue;
466
                }
467
                insptr = (instype *)(j+script);
468
            }
469
            continue;
470
 
471
        case CON_RIGHTBRACE:
472
            insptr++;
473
            return 1;
474
        case CON_LEFTBRACE:
475
            insptr++;
1625 terminx 476
            VM_Execute(0);
1493 helixhorne 477
            continue;
478
 
479
// *** arrays
480
        case CON_SETARRAY:
481
            insptr++;
482
            {
4798 helixhorne 483
                const int32_t j=*insptr++;
484
                const int32_t index = Gv_GetVarX(*insptr++);
485
                const int32_t value = Gv_GetVarX(*insptr++);
1493 helixhorne 486
 
4798 helixhorne 487
                CheckArray(j);
488
 
1493 helixhorne 489
                if (aGameArrays[j].dwFlags & GAMEARRAY_READONLY)
4798 helixhorne 490
                    M32_ERROR("Tried to set on read-only array `%s'", aGameArrays[j].szLabel);
491
 
492
                if (!(index >= 0 && index < aGameArrays[j].size))
493
                    M32_ERROR("Array index %d out of bounds", index);
494
 
495
                if (vm.flags&VMFLAG_ERROR)
496
                    continue;
497
 
498
                // NOTE: Other array types not implemented, since they're read-only.
499
                ((int32_t *)aGameArrays[j].vals)[index] = value;
1493 helixhorne 500
                continue;
501
            }
502
 
503
        case CON_GETARRAYSIZE:
504
            insptr++;
505
            {
4798 helixhorne 506
                const int32_t j=*insptr++;
507
 
508
                if (CheckArray(j))
509
                    continue;
510
 
511
                Gv_SetVarX(*insptr++, Gv_GetArraySize(j));
1493 helixhorne 512
            }
513
            continue;
514
 
515
        case CON_RESIZEARRAY:
516
            insptr++;
517
            {
4798 helixhorne 518
                const int32_t j=*insptr++;
519
                const int32_t asize = Gv_GetVarX(*insptr++);
1499 helixhorne 520
 
4798 helixhorne 521
                CheckArray(j);
522
 
523
                if (aGameArrays[j].dwFlags & GAMEARRAY_READONLY)
524
                    M32_ERROR("Tried to resize read-only array `%s'", aGameArrays[j].szLabel);
525
 
526
                if (!(asize >= 1 && asize <= 65536))
1877 helixhorne 527
                    M32_ERROR("Invalid array size %d (must be between 1 and 65536)", asize);
4798 helixhorne 528
 
529
                if (vm.flags&VMFLAG_ERROR)
1528 helixhorne 530
                    continue;
1493 helixhorne 531
 
532
//                OSD_Printf(OSDTEXT_GREEN "CON_RESIZEARRAY: resizing array %s from %d to %d\n", aGameArrays[j].szLabel, aGameArrays[j].size, asize);
4491 helixhorne 533
                aGameArrays[j].vals = Xrealloc(aGameArrays[j].vals, sizeof(int32_t) * asize);
1493 helixhorne 534
                aGameArrays[j].size = asize;
535
 
536
                continue;
537
            }
538
 
539
        case CON_COPY:
540
            insptr++;
541
            {
4798 helixhorne 542
                const int32_t si=*insptr++;
543
                int32_t sidx = Gv_GetVarX(*insptr++);
544
                const int32_t di=*insptr++;
1493 helixhorne 545
                int32_t didx = Gv_GetVarX(*insptr++);
546
                int32_t numelts = Gv_GetVarX(*insptr++);
547
 
4798 helixhorne 548
                CheckArray(si);
549
                CheckArray(di);
550
 
1493 helixhorne 551
                if (aGameArrays[di].dwFlags & GAMEARRAY_READONLY)
1877 helixhorne 552
                    M32_ERROR("Array %d is read-only!", di);
4798 helixhorne 553
                if (vm.flags&VMFLAG_ERROR)
554
                    continue;
1493 helixhorne 555
 
4798 helixhorne 556
                const int32_t ssiz = Gv_GetArraySize(si);
557
                const int32_t dsiz = Gv_GetArraySize(di);
1493 helixhorne 558
 
4799 helixhorne 559
                if ((uint32_t)sidx >= (uint32_t)ssiz)
560
                    M32_ERROR("Invalid source index %d", sidx);
561
                if ((uint32_t)didx >= (uint32_t)dsiz)
562
                    M32_ERROR("Invalid destination index %d", didx);
563
                if (vm.flags&VMFLAG_ERROR)
4798 helixhorne 564
                    continue;
4799 helixhorne 565
 
4798 helixhorne 566
                if (numelts > ssiz-sidx)
567
                    numelts = ssiz-sidx;
568
                if (numelts > dsiz-didx)
569
                    numelts = dsiz-didx;
570
 
4799 helixhorne 571
                const gamearray_t *const sar = &aGameArrays[si];
572
                gamearray_t *const dar = &aGameArrays[di];
573
 
574
                switch (sar->dwFlags & GAMEARRAY_TYPE_MASK)
1493 helixhorne 575
                {
576
                case 0:
577
                case GAMEARRAY_OFINT:
4799 helixhorne 578
                    if (sar->dwFlags & GAMEARRAY_STRIDE2)
579
                    {
580
                        for (; numelts>0; numelts--, sidx += 2)
581
                            ((int32_t *)dar->vals)[didx++] = ((int32_t *)sar->vals)[sidx];
582
                    }
583
                    else
584
                    {
585
                        Bmemcpy((int32_t *)dar->vals + didx, (int32_t *)sar->vals + sidx,
586
                                numelts * sizeof(int32_t));
587
                    }
1493 helixhorne 588
                    break;
589
                case GAMEARRAY_OFSHORT:
590
                    for (; numelts>0; numelts--)
4799 helixhorne 591
                        ((int32_t *)dar->vals)[didx++] = ((int16_t *)sar->vals)[sidx++];
1493 helixhorne 592
                    break;
593
                case GAMEARRAY_OFCHAR:
594
                    for (; numelts>0; numelts--)
4799 helixhorne 595
                        ((int32_t *)dar->vals)[didx++] = ((uint8_t *)sar->vals)[sidx++];
1493 helixhorne 596
                    break;
597
                }
598
                continue;
599
            }
600
 
601
// *** var & varvar ops
602
        case CON_RANDVAR:
603
            insptr++;
604
            Gv_SetVarX(*insptr, mulscale16(krand(), *(insptr+1)+1));
605
            insptr += 2;
606
            continue;
607
 
608
        case CON_DISPLAYRANDVAR:
609
            insptr++;
2105 helixhorne 610
            Gv_SetVarX(*insptr, mulscale15(system_15bit_rand(), *(insptr+1)+1));
1493 helixhorne 611
            insptr += 2;
612
            continue;
613
 
614
        case CON_SETVAR:
615
            insptr++;
616
            Gv_SetVarX(*insptr, *(insptr+1));
617
            insptr += 2;
618
            continue;
619
 
620
        case CON_SETVARVAR:
621
            insptr++;
622
            {
623
                int32_t j=*insptr++;
624
                Gv_SetVarX(j, Gv_GetVarX(*insptr++));
625
            }
626
            continue;
627
 
628
        case CON_MULVAR:
629
            insptr++;
630
            Gv_SetVarX(*insptr, Gv_GetVarX(*insptr) * *(insptr+1));
631
            insptr += 2;
632
            continue;
633
 
634
        case CON_DIVVAR:
635
            insptr++;
636
            if (*(insptr+1) == 0)
637
            {
1877 helixhorne 638
                M32_ERROR("Divide by zero.");
1493 helixhorne 639
                insptr += 2;
640
                continue;
641
            }
642
            Gv_SetVarX(*insptr, Gv_GetVarX(*insptr) / *(insptr+1));
643
            insptr += 2;
644
            continue;
645
 
646
        case CON_MODVAR:
647
            insptr++;
648
            if (*(insptr+1) == 0)
649
            {
1877 helixhorne 650
                M32_ERROR("Mod by zero.");
1493 helixhorne 651
                insptr += 2;
652
                continue;
653
            }
654
            Gv_SetVarX(*insptr,Gv_GetVarX(*insptr)%*(insptr+1));
655
            insptr += 2;
656
            continue;
657
 
658
        case CON_ANDVAR:
659
            insptr++;
660
            Gv_SetVarX(*insptr,Gv_GetVarX(*insptr) & *(insptr+1));
661
            insptr += 2;
662
            continue;
663
 
664
        case CON_ORVAR:
665
            insptr++;
666
            Gv_SetVarX(*insptr,Gv_GetVarX(*insptr) | *(insptr+1));
667
            insptr += 2;
668
            continue;
669
 
670
        case CON_XORVAR:
671
            insptr++;
672
            Gv_SetVarX(*insptr,Gv_GetVarX(*insptr) ^ *(insptr+1));
673
            insptr += 2;
674
            continue;
675
 
676
        case CON_RANDVARVAR:
677
            insptr++;
678
            {
679
                int32_t j=*insptr++;
2105 helixhorne 680
                Gv_SetVarX(j,mulscale16(krand(), Gv_GetVarX(*insptr++)+1));
1493 helixhorne 681
            }
682
            continue;
683
 
684
        case CON_DISPLAYRANDVARVAR:
685
            insptr++;
686
            {
687
                int32_t j=*insptr++;
2105 helixhorne 688
                Gv_SetVarX(j,mulscale15(system_15bit_rand(), Gv_GetVarX(*insptr++)+1));
1493 helixhorne 689
            }
690
            continue;
691
 
692
        case CON_MULVARVAR:
693
            insptr++;
694
            {
695
                int32_t j=*insptr++;
696
                Gv_SetVarX(j, Gv_GetVarX(j)*Gv_GetVarX(*insptr++));
697
            }
698
            continue;
699
 
700
        case CON_DIVVARVAR:
701
            insptr++;
702
            {
703
                int32_t j=*insptr++;
704
                int32_t l2=Gv_GetVarX(*insptr++);
705
 
706
                if (l2==0)
707
                {
1877 helixhorne 708
                    M32_ERROR("Divide by zero.");
1493 helixhorne 709
                    continue;
710
                }
711
                Gv_SetVarX(j, Gv_GetVarX(j)/l2);
712
                continue;
713
            }
714
 
715
        case CON_MODVARVAR:
716
            insptr++;
717
            {
718
                int32_t j=*insptr++;
719
                int32_t l2=Gv_GetVarX(*insptr++);
720
 
721
                if (l2==0)
722
                {
1877 helixhorne 723
                    M32_ERROR("Mod by zero.");
1493 helixhorne 724
                    continue;
725
                }
726
 
727
                Gv_SetVarX(j, Gv_GetVarX(j) % l2);
728
                continue;
729
            }
730
 
731
        case CON_ANDVARVAR:
732
            insptr++;
733
            {
734
                int32_t j=*insptr++;
735
                Gv_SetVarX(j, Gv_GetVarX(j) & Gv_GetVarX(*insptr++));
736
            }
737
            continue;
738
 
739
        case CON_XORVARVAR:
740
            insptr++;
741
            {
742
                int32_t j=*insptr++;
743
                Gv_SetVarX(j, Gv_GetVarX(j) ^ Gv_GetVarX(*insptr++));
744
            }
745
            continue;
746
 
747
        case CON_ORVARVAR:
748
            insptr++;
749
            {
750
                int32_t j=*insptr++;
751
                Gv_SetVarX(j, Gv_GetVarX(j) | Gv_GetVarX(*insptr++));
752
            }
753
            continue;
754
 
755
        case CON_SUBVAR:
756
            insptr++;
757
            Gv_SetVarX(*insptr, Gv_GetVarX(*insptr) - *(insptr+1));
758
            insptr += 2;
759
            continue;
760
 
761
        case CON_SUBVARVAR:
762
            insptr++;
763
            {
764
                int32_t j=*insptr++;
765
                Gv_SetVarX(j, Gv_GetVarX(j) - Gv_GetVarX(*insptr++));
766
            }
767
            continue;
768
 
769
        case CON_ADDVAR:
770
            insptr++;
771
            Gv_SetVarX(*insptr, Gv_GetVarX(*insptr) + *(insptr+1));
772
            insptr += 2;
773
            continue;
774
 
775
        case CON_ADDVARVAR:
776
            insptr++;
777
            {
778
                int32_t j=*insptr++;
779
                Gv_SetVarX(j, Gv_GetVarX(j) + Gv_GetVarX(*insptr++));
780
            }
781
            continue;
782
 
783
        case CON_SHIFTVARL:
784
            insptr++;
785
            Gv_SetVarX(*insptr, Gv_GetVarX(*insptr) << *(insptr+1));
786
            insptr += 2;
787
            continue;
788
 
1710 helixhorne 789
        case CON_SHIFTVARVARL:
790
            insptr++;
791
            {
792
                int32_t j=*insptr++;
793
                Gv_SetVarX(j, Gv_GetVarX(j) << Gv_GetVarX(*insptr++));
794
            }
795
            continue;
796
 
1493 helixhorne 797
        case CON_SHIFTVARR:
798
            insptr++;
799
            Gv_SetVarX(*insptr, Gv_GetVarX(*insptr) >> *(insptr+1));
800
            insptr += 2;
801
            continue;
802
 
1710 helixhorne 803
        case CON_SHIFTVARVARR:
804
            insptr++;
805
            {
806
                int32_t j=*insptr++;
807
                Gv_SetVarX(j, Gv_GetVarX(j) >> Gv_GetVarX(*insptr++));
808
            }
809
            continue;
810
 
1493 helixhorne 811
        case CON_SIN:
812
            insptr++;
813
            Gv_SetVarX(*insptr, sintable[Gv_GetVarX(*(insptr+1))&2047]);
814
            insptr += 2;
815
            continue;
816
 
817
        case CON_COS:
818
            insptr++;
819
            Gv_SetVarX(*insptr, sintable[(Gv_GetVarX(*(insptr+1))+512)&2047]);
820
            insptr += 2;
821
            continue;
822
 
823
        case CON_DISPLAYRAND:
824
            insptr++;
2105 helixhorne 825
            Gv_SetVarX(*insptr++, system_15bit_rand());
1493 helixhorne 826
            continue;
827
 
828
// *** other math
1644 helixhorne 829
        case CON_FTOI:
830
            insptr++;
831
            {
832
                int32_t bits=Gv_GetVarX(*insptr), scale=*(insptr+1);
1677 terminx 833
                float fval = *((float *)&bits);
1696 helixhorne 834
// rounding must absolutely be!
835
//OSD_Printf("ftoi: bits:%8x, scale=%d, fval=%f, (int32_t)(fval*scale)=%d\n", bits, scale, fval, (int32_t)(fval*scale));
4658 terminx 836
                Gv_SetVarX(*insptr, (int32_t)Blrintf(fval * scale));
1644 helixhorne 837
            }
838
            insptr += 2;
839
            continue;
840
 
841
        case CON_ITOF:
842
            insptr++;
843
            {
844
                int32_t scaled=Gv_GetVarX(*insptr), scale=*(insptr+1);
1648 helixhorne 845
                float fval = (float)scaled/(float)scale;
1644 helixhorne 846
                Gv_SetVarX(*insptr, *((int32_t *)&fval));
847
            }
848
            insptr += 2;
849
            continue;
850
 
1521 helixhorne 851
        case CON_CLAMP:
852
            insptr++;
853
            {
854
                int32_t var=*insptr++, min=Gv_GetVarX(*insptr++), max=Gv_GetVarX(*insptr++);
855
                int32_t val=Gv_GetVarX(var);
856
 
857
                if (val<min) Gv_SetVarX(var, min);
858
                else if (val>max) Gv_SetVarX(var, max);
859
            }
860
            continue;
861
 
1493 helixhorne 862
        case CON_INV:
863
            Gv_SetVarX(*(insptr+1), -Gv_GetVarX(*(insptr+1)));
864
            insptr += 2;
865
            continue;
866
 
867
        case CON_SQRT:
868
            insptr++;
869
            {
870
                // syntax sqrt <invar> <outvar>
871
                int32_t lInVarID=*insptr++, lOutVarID=*insptr++;
872
 
2791 helixhorne 873
                Gv_SetVarX(lOutVarID, ksqrt((uint32_t)Gv_GetVarX(lInVarID)));
1493 helixhorne 874
                continue;
875
            }
876
 
877
        case CON_LDIST:
878
        case CON_DIST:
879
            insptr++;
880
            {
881
                int32_t distvar = *insptr++, xvar = Gv_GetVarX(*insptr++), yvar = Gv_GetVarX(*insptr++);
882
 
883
                if (xvar < 0 || xvar >= MAXSPRITES || sprite[xvar].statnum==MAXSTATUS)
884
                {
1877 helixhorne 885
                    M32_ERROR("invalid sprite %d", xvar);
1493 helixhorne 886
                }
887
                if (yvar < 0 || yvar >= MAXSPRITES || sprite[yvar].statnum==MAXSTATUS)
888
                {
1877 helixhorne 889
                    M32_ERROR("invalid sprite %d", yvar);
1493 helixhorne 890
                }
1528 helixhorne 891
                if (vm.flags&VMFLAG_ERROR) continue;
1493 helixhorne 892
 
893
                if (tw==CON_DIST)
894
                    Gv_SetVarX(distvar, dist(&sprite[xvar],&sprite[yvar]));
895
                else
896
                    Gv_SetVarX(distvar, ldist(&sprite[xvar],&sprite[yvar]));
897
                continue;
898
            }
899
 
900
        case CON_GETANGLE:
901
            insptr++;
902
            {
903
                int32_t angvar = *insptr++;
904
                int32_t xvar = Gv_GetVarX(*insptr++);
905
                int32_t yvar = Gv_GetVarX(*insptr++);
906
 
907
                Gv_SetVarX(angvar, getangle(xvar,yvar));
908
                continue;
909
            }
910
 
911
        case CON_GETINCANGLE:
912
            insptr++;
913
            {
914
                int32_t angvar = *insptr++;
915
                int32_t xvar = Gv_GetVarX(*insptr++);
916
                int32_t yvar = Gv_GetVarX(*insptr++);
917
 
918
                Gv_SetVarX(angvar, G_GetAngleDelta(xvar,yvar));
919
                continue;
920
            }
921
 
1697 helixhorne 922
        case CON_A2XY:
923
        case CON_AH2XYZ:
924
            insptr++;
925
            {
926
                int32_t ang=Gv_GetVarX(*insptr++), horiz=(tw==CON_A2XY)?100:Gv_GetVarX(*insptr++);
927
                int32_t xvar=*insptr++, yvar=*insptr++;
928
 
929
                int32_t x = sintable[(ang+512)&2047];
930
                int32_t y = sintable[ang&2047];
931
 
932
                if (tw==CON_AH2XYZ)
933
                {
934
                    int32_t zvar=*insptr++, z=0;
935
 
936
                    horiz -= 100;
937
                    if (horiz)
938
                    {
939
                        int32_t veclen = ksqrt(200*200 + horiz*horiz);
940
                        int32_t dacos = divscale14(200, veclen);
941
 
942
                        x = mulscale14(x, dacos);
943
                        y = mulscale14(y, dacos);
1698 helixhorne 944
                        z = divscale14(-horiz, veclen);
1697 helixhorne 945
                    }
946
 
947
                    Gv_SetVarX(zvar, z);
948
                }
949
 
950
                Gv_SetVarX(xvar, x);
951
                Gv_SetVarX(yvar, y);
952
 
953
                continue;
954
            }
955
 
1493 helixhorne 956
        case CON_MULSCALE:
957
            insptr++;
958
            {
959
                int32_t var1 = *insptr++, var2 = Gv_GetVarX(*insptr++);
960
                int32_t var3 = Gv_GetVarX(*insptr++), var4 = Gv_GetVarX(*insptr++);
961
 
962
                Gv_SetVarX(var1, mulscale(var2, var3, var4));
963
                continue;
964
            }
1683 helixhorne 965
        case CON_DIVSCALE:
966
            insptr++;
967
            {
968
                int32_t var1 = *insptr++, var2 = Gv_GetVarX(*insptr++);
969
                int32_t var3 = Gv_GetVarX(*insptr++), var4 = Gv_GetVarX(*insptr++);
1493 helixhorne 970
 
1683 helixhorne 971
                Gv_SetVarX(var1, divscale(var2, var3, var4));
972
                continue;
973
            }
974
 
1493 helixhorne 975
// *** if & while
976
        case CON_IFVARVARAND:
977
            insptr++;
978
            {
979
                int32_t j = Gv_GetVarX(*insptr++);
980
                j &= Gv_GetVarX(*insptr++);
981
                insptr--;
1625 terminx 982
                VM_DoConditional(j);
1493 helixhorne 983
            }
984
            continue;
985
 
986
        case CON_IFVARVAROR:
987
            insptr++;
988
            {
989
                int32_t j = Gv_GetVarX(*insptr++);
990
                j |= Gv_GetVarX(*insptr++);
991
                insptr--;
1625 terminx 992
                VM_DoConditional(j);
1493 helixhorne 993
            }
994
            continue;
995
 
996
        case CON_IFVARVARXOR:
997
            insptr++;
998
            {
999
                int32_t j = Gv_GetVarX(*insptr++);
1000
                j ^= Gv_GetVarX(*insptr++);
1001
                insptr--;
1625 terminx 1002
                VM_DoConditional(j);
1493 helixhorne 1003
            }
1004
            continue;
1005
 
1006
        case CON_IFVARVAREITHER:
1007
            insptr++;
1008
            {
1009
                int32_t j = Gv_GetVarX(*insptr++);
1010
                int32_t l = Gv_GetVarX(*insptr++);
1011
                insptr--;
1625 terminx 1012
                VM_DoConditional(j || l);
1493 helixhorne 1013
            }
1014
            continue;
1015
 
1016
        case CON_IFVARVARBOTH:
1017
            insptr++;
1018
            {
1019
                int32_t j = Gv_GetVarX(*insptr++);
1020
                int32_t l = Gv_GetVarX(*insptr++);
1021
                insptr--;
1625 terminx 1022
                VM_DoConditional(j && l);
1493 helixhorne 1023
            }
1024
            continue;
1025
 
1026
        case CON_IFVARVARN:
1027
            insptr++;
1028
            {
1029
                int32_t j = Gv_GetVarX(*insptr++);
1030
                j = (j != Gv_GetVarX(*insptr++));
1031
                insptr--;
1625 terminx 1032
                VM_DoConditional(j);
1493 helixhorne 1033
            }
1034
            continue;
1035
 
1036
        case CON_IFVARVARE:
1037
            insptr++;
1038
            {
1039
                int32_t j = Gv_GetVarX(*insptr++);
1040
                j = (j == Gv_GetVarX(*insptr++));
1041
                insptr--;
1625 terminx 1042
                VM_DoConditional(j);
1493 helixhorne 1043
            }
1044
            continue;
1045
 
1046
        case CON_IFVARVARG:
1047
            insptr++;
1048
            {
1049
                int32_t j = Gv_GetVarX(*insptr++);
1050
                j = (j > Gv_GetVarX(*insptr++));
1051
                insptr--;
1625 terminx 1052
                VM_DoConditional(j);
1493 helixhorne 1053
            }
1054
            continue;
1055
 
1056
        case CON_IFVARVARGE:
1057
            insptr++;
1058
            {
1059
                int32_t j = Gv_GetVarX(*insptr++);
1060
                j = (j >= Gv_GetVarX(*insptr++));
1061
                insptr--;
1625 terminx 1062
                VM_DoConditional(j);
1493 helixhorne 1063
            }
1064
            continue;
1065
 
1066
        case CON_IFVARVARL:
1067
            insptr++;
1068
            {
1069
                int32_t j = Gv_GetVarX(*insptr++);
1070
                j = (j < Gv_GetVarX(*insptr++));
1071
                insptr--;
1625 terminx 1072
                VM_DoConditional(j);
1493 helixhorne 1073
            }
1074
            continue;
1075
 
1076
        case CON_IFVARVARLE:
1077
            insptr++;
1078
            {
1079
                int32_t j = Gv_GetVarX(*insptr++);
1080
                j = (j <= Gv_GetVarX(*insptr++));
1081
                insptr--;
1625 terminx 1082
                VM_DoConditional(j);
1493 helixhorne 1083
            }
1084
            continue;
1085
 
1086
        case CON_IFVARE:
1087
            insptr++;
1088
            {
1089
                int32_t j=Gv_GetVarX(*insptr++);
1625 terminx 1090
                VM_DoConditional(j == *insptr);
1493 helixhorne 1091
            }
1092
            continue;
1093
 
1094
        case CON_IFVARN:
1095
            insptr++;
1096
            {
1097
                int32_t j=Gv_GetVarX(*insptr++);
1625 terminx 1098
                VM_DoConditional(j != *insptr);
1493 helixhorne 1099
            }
1100
            continue;
1101
 
1102
        case CON_WHILEVARN:
1103
        {
1104
            instype *savedinsptr=insptr+2;
1105
            int32_t j;
1106
            do
1107
            {
1108
                insptr=savedinsptr;
1109
                j = (Gv_GetVarX(*(insptr-1)) != *insptr);
1625 terminx 1110
                VM_DoConditional(j);
1493 helixhorne 1111
            }
1528 helixhorne 1112
            while (j && !vm.flags);
1113
            vm.flags &= ~VMFLAG_BREAK;
1493 helixhorne 1114
            continue;
1115
        }
1116
 
1117
        case CON_WHILEVARL:
1118
        {
1119
            instype *savedinsptr=insptr+2;
1120
            int32_t j;
1121
            do
1122
            {
1123
                insptr=savedinsptr;
1124
                j = (Gv_GetVarX(*(insptr-1)) < *insptr);
1625 terminx 1125
                VM_DoConditional(j);
1493 helixhorne 1126
            }
1528 helixhorne 1127
            while (j && !vm.flags);
1128
            vm.flags &= ~VMFLAG_BREAK;
1493 helixhorne 1129
            continue;
1130
        }
1131
 
1132
        case CON_WHILEVARVARN:
1133
        {
1134
            int32_t j;
1135
            instype *savedinsptr=insptr+2;
1136
            do
1137
            {
1138
                insptr=savedinsptr;
1139
                j = Gv_GetVarX(*(insptr-1));
1140
                j = (j != Gv_GetVarX(*insptr++));
1141
                insptr--;
1625 terminx 1142
                VM_DoConditional(j);
1493 helixhorne 1143
            }
1528 helixhorne 1144
            while (j && !vm.flags);
1145
            vm.flags &= ~VMFLAG_BREAK;
1493 helixhorne 1146
            continue;
1147
        }
1148
 
1149
        case CON_WHILEVARVARL:
1150
        {
1151
            int32_t j;
1152
            instype *savedinsptr=insptr+2;
1153
            do
1154
            {
1155
                insptr=savedinsptr;
1156
                j = Gv_GetVarX(*(insptr-1));
1157
                j = (j < Gv_GetVarX(*insptr++));
1158
                insptr--;
1625 terminx 1159
                VM_DoConditional(j);
1493 helixhorne 1160
            }
1528 helixhorne 1161
            while (j && !vm.flags);
1162
            vm.flags &= ~VMFLAG_BREAK;
1493 helixhorne 1163
            continue;
1164
        }
1165
 
1927 helixhorne 1166
        case CON_COLLECTSECTORS:
1167
            insptr++;
1168
            {
4798 helixhorne 1169
                const int32_t aridx=*insptr++, startsectnum=Gv_GetVarX(*insptr++);
1170
                const int32_t numsectsVar=*insptr++, state=*insptr++;
1927 helixhorne 1171
 
4798 helixhorne 1172
                if (CheckArray(aridx))
1173
                    continue;
1174
 
1175
                gamearray_t *const gar = &aGameArrays[aridx];
1176
                Bassert((gar->dwFlags & (GAMEARRAY_READONLY|GAMEARRAY_VARSIZE)) == 0);
1177
 
1178
                const int32_t o_g_st=vm.g_st, arsize = gar->size;
1179
                instype *const end=insptr;
1927 helixhorne 1180
                int32_t sectcnt, numsects=0;
4798 helixhorne 1181
 
1182
                // XXX: relies on -fno-strict-aliasing
1183
                int16_t *const sectlist = (int16_t *)gar->vals;  // actually an int32_t array
1184
                int32_t *const sectlist32 = (int32_t *)sectlist;
1185
 
1927 helixhorne 1186
                int32_t j, startwall, endwall, ns;
1187
                static uint8_t sectbitmap[MAXSECTORS>>3];
1188
 
1189
                X_ERROR_INVALIDSECT(startsectnum);
1190
                if (arsize < numsectors)
1191
                {
1192
                    M32_ERROR("Array size must be at least numsectors (=%d) for collecting!",
1193
                              numsectors);
1194
                    continue;
1195
                }
1196
 
1197
                // collect!
1198
                bfirst_search_init(sectlist, sectbitmap, &numsects, MAXSECTORS, startsectnum);
1199
 
1200
                for (sectcnt=0; sectcnt<numsects; sectcnt++)
1201
                    for (WALLS_OF_SECTOR(sectlist[sectcnt], j))
1202
                        if ((ns=wall[j].nextsector) >= 0 && wall[j].nextsector<numsectors)
1203
                        {
1204
                            if (sectbitmap[ns>>3]&(1<<(ns&7)))
1205
                                continue;
1206
                            vm.g_st = 1+MAXEVENTS+state;
1207
                            insptr = script + statesinfo[state].ofs;
1208
                            g_iReturnVar = ns;
1209
                            VM_Execute(0);
1210
                            if (g_iReturnVar)
1211
                                bfirst_search_try(sectlist, sectbitmap, &numsects, wall[j].nextsector);
1212
                        }
1213
 
1214
                // short->int sector list
1215
                for (j=numsects-1; j>=0; j--)
1216
                    sectlist32[j] = sectlist[j];
1217
 
1218
                Gv_SetVarX(numsectsVar, numsects);
1219
                g_iReturnVar = 0;
1220
 
1221
                // restore some VM state
1222
                vm.g_st = o_g_st;
1223
                insptr = end;
1224
            }
1225
            continue;
1226
 
1499 helixhorne 1227
        case CON_SORT:
1228
            insptr++;
1229
            {
4798 helixhorne 1230
                const int32_t aridx=*insptr++, count=Gv_GetVarX(*insptr++), state=*insptr++;
1231
                const int32_t o_g_st = vm.g_st;
1232
                instype *const end = insptr;
1499 helixhorne 1233
 
4798 helixhorne 1234
                if (CheckArray(aridx))
1235
                    continue;
1236
 
1237
                if (count <= 0)
1238
                    continue;
1239
 
1240
                gamearray_t *const gar = &aGameArrays[aridx];
1241
                Bassert((gar->dwFlags & (GAMEARRAY_READONLY|GAMEARRAY_VARSIZE)) == 0);
1242
 
1243
                if (count > gar->size)
1499 helixhorne 1244
                {
4798 helixhorne 1245
                    M32_ERROR("Count of elements to sort (%d) exceeds array size (%d)!",
1246
                              count, gar->size);
1499 helixhorne 1247
                    continue;
1248
                }
1249
 
1250
                if (state < 0)
1251
                {
4798 helixhorne 1252
                    qsort(gar->vals, count, sizeof(int32_t), X_DoSortDefault);
1499 helixhorne 1253
                }
1254
                else
1255
                {
1256
                    x_sortingstateptr = script + statesinfo[state].ofs;
1257
                    vm.g_st = 1+MAXEVENTS+state;
4798 helixhorne 1258
                    qsort(gar->vals, count, sizeof(int32_t), X_DoSort);
1499 helixhorne 1259
                    vm.g_st = o_g_st;
1260
                    insptr = end;
1261
                }
1262
            }
1263
            continue;
1264
 
1493 helixhorne 1265
        case CON_FOR:  // special-purpose iteration
1266
            insptr++;
1267
            {
1268
                int32_t var = *insptr++, how=*insptr++, ii, jj;
1269
                int32_t parm2 = how<=ITER_DRAWNSPRITES ? 0 : Gv_GetVarX(*insptr++);
1270
                instype *end = insptr + *insptr, *beg = ++insptr;
1271
                int32_t vm_i_bak = vm.g_i;
1272
                spritetype *vm_sp_bak = vm.g_sp;
1273
                int16_t endwall;
1274
 
1528 helixhorne 1275
                if (vm.flags&VMFLAG_ERROR) continue;
1493 helixhorne 1276
 
1277
                switch (how)
1278
                {
1279
                case ITER_ALLSPRITES:
1528 helixhorne 1280
                    for (jj=0; jj<MAXSPRITES && !vm.flags; jj++)
1493 helixhorne 1281
                    {
1282
                        if (sprite[jj].statnum == MAXSTATUS)
1283
                            continue;
1284
                        Gv_SetVarX(var, jj);
1285
                        vm.g_i = jj;
1286
                        vm.g_sp = &sprite[jj];
1287
                        insptr = beg;
1625 terminx 1288
                        VM_Execute(1);
1493 helixhorne 1289
                    }
1290
                    break;
1291
                case ITER_ALLSECTORS:
1528 helixhorne 1292
                    for (jj=0; jj<numsectors && !vm.flags; jj++)
1493 helixhorne 1293
                    {
1294
                        Gv_SetVarX(var, jj);
1295
                        insptr = beg;
1625 terminx 1296
                        VM_Execute(1);
1493 helixhorne 1297
                    }
1298
                    break;
1299
                case ITER_ALLWALLS:
1528 helixhorne 1300
                    for (jj=0; jj<numwalls && !vm.flags; jj++)
1493 helixhorne 1301
                    {
1302
                        Gv_SetVarX(var, jj);
1303
                        insptr = beg;
1625 terminx 1304
                        VM_Execute(1);
1493 helixhorne 1305
                    }
1306
                    break;
1877 helixhorne 1307
                case ITER_ACTIVELIGHTS:
1308
#ifdef POLYMER
1309
                    for (jj=0; jj<PR_MAXLIGHTS; jj++)
1310
                    {
1311
                        if (!prlights[jj].flags.active)
1312
                            continue;
1313
 
1314
                        Gv_SetVarX(var, jj);
1315
                        insptr = beg;
1316
                        VM_Execute(1);
1317
                    }
1318
#else
1319
                    M32_ERROR("Polymer not compiled in, iteration over lights forbidden.");
1320
#endif
1321
                    break;
1322
 
1493 helixhorne 1323
                case ITER_SELSPRITES:
1528 helixhorne 1324
                    for (ii=0; ii<highlightcnt && !vm.flags; ii++)
1493 helixhorne 1325
                    {
1326
                        jj = highlight[ii];
1327
                        if (jj&0xc000)
1328
                        {
1329
                            jj &= (MAXSPRITES-1);
1330
                            Gv_SetVarX(var, jj);
1331
                            vm.g_i = jj;
1332
                            vm.g_sp = &sprite[jj];
1333
                            insptr = beg;
1625 terminx 1334
                            VM_Execute(1);
1493 helixhorne 1335
                        }
1336
                    }
1337
                    break;
1338
                case ITER_SELSECTORS:
1528 helixhorne 1339
                    for (ii=0; ii<highlightsectorcnt && !vm.flags; ii++)
1493 helixhorne 1340
                    {
1341
                        jj=highlightsector[ii];
1342
                        Gv_SetVarX(var, jj);
1343
                        insptr = beg;
1625 terminx 1344
                        VM_Execute(1);
1493 helixhorne 1345
                    }
1346
                    break;
1347
                case ITER_SELWALLS:
1528 helixhorne 1348
                    for (ii=0; ii<highlightcnt && !vm.flags; ii++)
1493 helixhorne 1349
                    {
1350
                        jj=highlight[ii];
1351
                        if (jj&0xc000)
1352
                            continue;
1353
                        Gv_SetVarX(var, jj);
1354
                        insptr = beg;
1625 terminx 1355
                        VM_Execute(1);
1493 helixhorne 1356
                    }
1357
                    break;
1358
                case ITER_DRAWNSPRITES:
1528 helixhorne 1359
                    for (ii=0; ii<spritesortcnt && !vm.flags; ii++)
1493 helixhorne 1360
                    {
1361
                        vm.g_sp = &tsprite[ii];
1362
                        Gv_SetVarX(var, ii);
1363
                        insptr = beg;
1625 terminx 1364
                        VM_Execute(1);
1493 helixhorne 1365
                    }
1366
                    break;
1367
                case ITER_SPRITESOFSECTOR:
1368
                    if (parm2 < 0 || parm2 >= MAXSECTORS)
1369
                        goto badindex;
1528 helixhorne 1370
                    for (jj=headspritesect[parm2]; jj>=0 && !vm.flags; jj=nextspritesect[jj])
1493 helixhorne 1371
                    {
1372
                        Gv_SetVarX(var, jj);
1373
                        vm.g_i = jj;
1374
                        vm.g_sp = &sprite[jj];
1375
                        insptr = beg;
1625 terminx 1376
                        VM_Execute(1);
1493 helixhorne 1377
                    }
1378
                    break;
1379
                case ITER_WALLSOFSECTOR:
1380
                    if (parm2 < 0 || parm2 >= MAXSECTORS)
1381
                        goto badindex;
1593 terminx 1382
                    for (jj=sector[parm2].wallptr, endwall=jj+sector[parm2].wallnum-1;
1383
                            jj<=endwall && !vm.flags; jj++)
1493 helixhorne 1384
                    {
1385
                        Gv_SetVarX(var, jj);
1386
                        insptr = beg;
1625 terminx 1387
                        VM_Execute(1);
1493 helixhorne 1388
                    }
1389
                    break;
1500 helixhorne 1390
                case ITER_LOOPOFWALL:
1391
                    if (parm2 < 0 || parm2 >= numwalls)
1392
                        goto badindex;
1519 helixhorne 1393
                    jj = parm2;
1394
                    do
1500 helixhorne 1395
                    {
1396
                        Gv_SetVarX(var, jj);
1397
                        insptr = beg;
1625 terminx 1398
                        VM_Execute(1);
1519 helixhorne 1399
                        jj = wall[jj].point2;
1593 terminx 1400
                    }
1401
                    while (jj != parm2 && !vm.flags);
1500 helixhorne 1402
                    break;
1493 helixhorne 1403
                case ITER_RANGE:
1528 helixhorne 1404
                    for (jj=0; jj<parm2 && !vm.flags; jj++)
1493 helixhorne 1405
                    {
1406
                        Gv_SetVarX(var, jj);
1407
                        insptr = beg;
1625 terminx 1408
                        VM_Execute(1);
1493 helixhorne 1409
                    }
1410
                    break;
1411
                default:
1877 helixhorne 1412
                    M32_ERROR("Unknown iteration type %d!", how);
1493 helixhorne 1413
                    continue;
1414
badindex:
1415
                    OSD_Printf(OSD_ERROR "Line %d, %s %s: index %d out of range!\n",g_errorLineNum,keyw[g_tw],
1740 helixhorne 1416
                               iter_tokens[how].token, parm2);
1528 helixhorne 1417
                    vm.flags |= VMFLAG_ERROR;
1493 helixhorne 1418
                    continue;
1419
                }
1420
                vm.g_i = vm_i_bak;
1421
                vm.g_sp = vm_sp_bak;
1528 helixhorne 1422
                vm.flags &= ~VMFLAG_BREAK;
1493 helixhorne 1423
                insptr = end;
1424
            }
1425
            continue;
1426
 
1427
        case CON_IFVARAND:
1428
            insptr++;
1429
            {
1430
                int32_t j=Gv_GetVarX(*insptr++);
1625 terminx 1431
                VM_DoConditional(j & *insptr);
1493 helixhorne 1432
            }
1433
            continue;
1434
 
1435
        case CON_IFVAROR:
1436
            insptr++;
1437
            {
1438
                int32_t j=Gv_GetVarX(*insptr++);
1625 terminx 1439
                VM_DoConditional(j | *insptr);
1493 helixhorne 1440
            }
1441
            continue;
1442
 
1443
        case CON_IFVARXOR:
1444
            insptr++;
1445
            {
1446
                int32_t j=Gv_GetVarX(*insptr++);
1625 terminx 1447
                VM_DoConditional(j ^ *insptr);
1493 helixhorne 1448
            }
1449
            continue;
1450
 
1451
        case CON_IFVAREITHER:
1452
            insptr++;
1453
            {
1454
                int32_t j=Gv_GetVarX(*insptr++);
1625 terminx 1455
                VM_DoConditional(j || *insptr);
1493 helixhorne 1456
            }
1457
            continue;
1458
 
1459
        case CON_IFVARBOTH:
1460
            insptr++;
1461
            {
1462
                int32_t j=Gv_GetVarX(*insptr++);
1625 terminx 1463
                VM_DoConditional(j && *insptr);
1493 helixhorne 1464
            }
1465
            continue;
1466
 
1467
        case CON_IFVARG:
1468
            insptr++;
1469
            {
1470
                int32_t j=Gv_GetVarX(*insptr++);
1625 terminx 1471
                VM_DoConditional(j > *insptr);
1493 helixhorne 1472
            }
1473
            continue;
1474
 
1475
        case CON_IFVARGE:
1476
            insptr++;
1477
            {
1478
                int32_t j=Gv_GetVarX(*insptr++);
1625 terminx 1479
                VM_DoConditional(j >= *insptr);
1493 helixhorne 1480
            }
1481
            continue;
1482
 
1483
        case CON_IFVARL:
1484
            insptr++;
1485
            {
1486
                int32_t j=Gv_GetVarX(*insptr++);
1625 terminx 1487
                VM_DoConditional(j < *insptr);
1493 helixhorne 1488
            }
1489
            continue;
1490
 
1491
        case CON_IFVARLE:
1492
            insptr++;
1493
            {
1494
                int32_t j=Gv_GetVarX(*insptr++);
1625 terminx 1495
                VM_DoConditional(j <= *insptr);
1493 helixhorne 1496
            }
1497
            continue;
1498
 
1499
        case CON_IFRND:
1625 terminx 1500
            VM_DoConditional(rnd(Gv_GetVarX(*(++insptr))));
1493 helixhorne 1501
            continue;
1502
 
1499 helixhorne 1503
        case CON_IFHITKEY:
1504
        case CON_IFHOLDKEY:
1521 helixhorne 1505
        case CON_RESETKEY:
2122 helixhorne 1506
        case CON_SETKEY:
1497 helixhorne 1507
            insptr++;
1508
            {
1509
                int32_t key=Gv_GetVarX(*insptr);
4385 terminx 1510
                if (key<0 || key >= (int32_t)ARRAY_SIZE(keystatus))
1497 helixhorne 1511
                {
1877 helixhorne 1512
                    M32_ERROR("Invalid key %d!", key);
1497 helixhorne 1513
                    continue;
1514
                }
1515
 
2122 helixhorne 1516
                if (tw == CON_IFHITKEY || tw == CON_IFHOLDKEY)
1625 terminx 1517
                    VM_DoConditional(keystatus[key]);
1521 helixhorne 1518
                else
1519
                    insptr++;
1520
 
1521
                if (tw != CON_IFHOLDKEY)
1499 helixhorne 1522
                {
1523
                    if (!(key==0 || key==KEYSC_ESC || key==KEYSC_TILDE || key==KEYSC_gENTER ||
1593 terminx 1524
                            key==KEYSC_LALT || key==KEYSC_RALT || key==KEYSC_LCTRL || key==KEYSC_RCTRL ||
1525
                            key==KEYSC_LSHIFT || key==KEYSC_RSHIFT))
2122 helixhorne 1526
                        keystatus[key] = (tw==CON_SETKEY);
1499 helixhorne 1527
                }
1497 helixhorne 1528
            }
1529
            continue;
1530
 
1531
        case CON_IFEITHERALT:
1625 terminx 1532
            VM_DoConditional(keystatus[KEYSC_LALT]||keystatus[KEYSC_RALT]);
1497 helixhorne 1533
            continue;
1534
 
1535
        case CON_IFEITHERCTRL:
1625 terminx 1536
            VM_DoConditional(keystatus[KEYSC_LCTRL]||keystatus[KEYSC_RCTRL]);
1497 helixhorne 1537
            continue;
1538
 
1539
        case CON_IFEITHERSHIFT:
1625 terminx 1540
            VM_DoConditional(keystatus[KEYSC_LSHIFT]||keystatus[KEYSC_RSHIFT]);
1497 helixhorne 1541
            continue;
1542
 
1493 helixhorne 1543
// vvv CURSPR
1544
        case CON_IFSPRITEPAL:
1545
            insptr++;
1546
            X_ERROR_INVALIDSP();
1625 terminx 1547
            VM_DoConditional(vm.g_sp->pal == Gv_GetVarX(*insptr));
1493 helixhorne 1548
            continue;
1549
 
1710 helixhorne 1550
        case CON_IFHIGHLIGHTED:
1551
            insptr++;
1552
            {
1553
                int32_t id=*insptr++, index=Gv_GetVarX(*insptr);
1554
 
1555
                if (index<0 || (id==M32_SPRITE_VAR_ID && index>=MAXSPRITES) || (id==M32_WALL_VAR_ID && index>=numwalls))
1556
                {
1877 helixhorne 1557
                    M32_ERROR("%s index %d out of range!", id==M32_SPRITE_VAR_ID?"Sprite":"Wall", index);
1710 helixhorne 1558
                    continue;
1559
                }
1560
 
1561
                if (id==M32_SPRITE_VAR_ID)
1562
                    VM_DoConditional(show2dsprite[index>>3]&(1<<(index&7)));
1563
                else
1564
                    VM_DoConditional(show2dwall[index>>3]&(1<<(index&7)));
1565
            }
1566
            continue;
1567
 
1493 helixhorne 1568
        case CON_IFANGDIFFL:
1569
            insptr++;
1570
            {
1571
                int32_t j;
1572
                X_ERROR_INVALIDSP();
1573
                j = klabs(G_GetAngleDelta(ang, vm.g_sp->ang));
1625 terminx 1574
                VM_DoConditional(j <= Gv_GetVarX(*insptr));
1493 helixhorne 1575
            }
1576
            continue;
1577
 
1578
        case CON_IFAWAYFROMWALL:
1579
        {
1580
            int16_t s1;
1581
            int32_t j = 0;
1582
 
1583
            X_ERROR_INVALIDSP();
1584
            s1 = vm.g_sp->sectnum;
1585
            updatesector(vm.g_sp->x+108,vm.g_sp->y+108,&s1);
1586
            if (s1 == vm.g_sp->sectnum)
1587
            {
1588
                updatesector(vm.g_sp->x-108,vm.g_sp->y-108,&s1);
1589
                if (s1 == vm.g_sp->sectnum)
1590
                {
1591
                    updatesector(vm.g_sp->x+108,vm.g_sp->y-108,&s1);
1592
                    if (s1 == vm.g_sp->sectnum)
1593
                    {
1594
                        updatesector(vm.g_sp->x-108,vm.g_sp->y+108,&s1);
1595
                        if (s1 == vm.g_sp->sectnum)
1596
                            j = 1;
1597
                    }
1598
                }
1599
            }
1625 terminx 1600
            VM_DoConditional(j);
1493 helixhorne 1601
        }
1602
        continue;
1603
 
1604
        case CON_IFCANSEE:
1605
        {
1606
            int32_t j;
1607
 
1608
            X_ERROR_INVALIDSP();
1609
            j = cansee(vm.g_sp->x,vm.g_sp->y,vm.g_sp->z/*-((krand()&41)<<8)*/,vm.g_sp->sectnum,
1593 terminx 1610
                       pos.x, pos.y, pos.z /*-((krand()&41)<<8)*/, cursectnum);
1625 terminx 1611
            VM_DoConditional(j);
1493 helixhorne 1612
        }
1613
        continue;
1614
 
1615
        case CON_IFONWATER:
1616
            X_ERROR_INVALIDSP();
1625 terminx 1617
            VM_DoConditional(sector[vm.g_sp->sectnum].lotag == 1 && klabs(vm.g_sp->z-sector[vm.g_sp->sectnum].floorz) < (32<<8));
1493 helixhorne 1618
            continue;
1619
 
1620
        case CON_IFINWATER:
1621
            X_ERROR_INVALIDSP();
1625 terminx 1622
            VM_DoConditional(sector[vm.g_sp->sectnum].lotag == 2);
1493 helixhorne 1623
            continue;
1624
 
1625
        case CON_IFACTOR:
1626
            insptr++;
1627
            X_ERROR_INVALIDSP();
1625 terminx 1628
            VM_DoConditional(vm.g_sp->picnum == Gv_GetVarX(*insptr));
1493 helixhorne 1629
            continue;
1630
 
1631
        case CON_IFINSIDE:
1632
            insptr++;
1633
            {
1634
                int32_t x=Gv_GetVarX(*insptr++), y=Gv_GetVarX(*insptr++), sectnum=Gv_GetVarX(*insptr++), res;
1635
 
1636
                res = inside(x, y, sectnum);
1637
                if (res == -1)
1638
                {
1877 helixhorne 1639
                    M32_ERROR("Sector index %d out of range!", sectnum);
1493 helixhorne 1640
                    continue;
1641
                }
1642
                insptr--;
1625 terminx 1643
                VM_DoConditional(res);
1493 helixhorne 1644
            }
1645
            continue;
1646
 
1647
        case CON_IFOUTSIDE:
1648
            X_ERROR_INVALIDSP();
1625 terminx 1649
            VM_DoConditional(sector[vm.g_sp->sectnum].ceilingstat&1);
1493 helixhorne 1650
            continue;
1651
 
1652
        case CON_IFPDISTL:
1653
            insptr++;
1654
            {
1655
                X_ERROR_INVALIDSP();
1625 terminx 1656
                VM_DoConditional(dist((spritetype *)&pos, vm.g_sp) < Gv_GetVarX(*insptr));
1493 helixhorne 1657
            }
1658
            continue;
1659
 
1660
        case CON_IFPDISTG:
1661
            insptr++;
1662
            {
1663
                X_ERROR_INVALIDSP();
1625 terminx 1664
                VM_DoConditional(dist((spritetype *)&pos, vm.g_sp) > Gv_GetVarX(*insptr));
1493 helixhorne 1665
            }
1666
            continue;
1667
// ^^^
1668
 
1669
// *** BUILD functions
1670
        case CON_INSERTSPRITE:
1671
            insptr++;
1672
            {
1673
                int32_t dasectnum = Gv_GetVarX(*insptr++), ret;
1674
 
1675
                X_ERROR_INVALIDSECT(dasectnum);
2478 helixhorne 1676
                if (Numsprites >= MAXSPRITES)
1493 helixhorne 1677
                {
1877 helixhorne 1678
                    M32_ERROR("Maximum number of sprites reached.");
1493 helixhorne 1679
                    continue;
1680
                }
1681
 
1682
                ret = insertsprite(dasectnum, 0);
1683
                vm.g_i = ret;
1684
                vm.g_sp = &sprite[ret];
1685
            }
1686
            continue;
1687
 
1688
        case CON_DUPSPRITE:
1536 helixhorne 1689
        case CON_TDUPSPRITE:
1493 helixhorne 1690
            insptr++;
1691
            {
1692
                int32_t ospritenum = Gv_GetVarX(*insptr++), nspritenum;
1693
 
1694
                if (ospritenum<0 || ospritenum>=MAXSPRITES || sprite[ospritenum].statnum==MAXSTATUS)
1695
                {
1877 helixhorne 1696
                    M32_ERROR("Tried to duplicate nonexistent sprite %d", ospritenum);
1493 helixhorne 1697
                }
2478 helixhorne 1698
                if ((tw==CON_DUPSPRITE && Numsprites >= MAXSPRITES) ||
1593 terminx 1699
                        (tw==CON_DUPSPRITE && spritesortcnt >= MAXSPRITESONSCREEN))
1493 helixhorne 1700
                {
1877 helixhorne 1701
                    M32_ERROR("Maximum number of sprites reached.");
1493 helixhorne 1702
                }
1703
 
2501 helixhorne 1704
                if (vm.flags&VMFLAG_ERROR)
1705
                    continue;
1706
 
1536 helixhorne 1707
                if (tw==CON_DUPSPRITE)
1708
                {
1709
                    nspritenum = insertsprite(sprite[ospritenum].sectnum, sprite[ospritenum].statnum);
1493 helixhorne 1710
 
1536 helixhorne 1711
                    if (nspritenum < 0)
1712
                    {
1877 helixhorne 1713
                        M32_ERROR("Internal error.");
1536 helixhorne 1714
                        continue;
1715
                    }
1716
 
1717
                    Bmemcpy(&sprite[nspritenum], &sprite[ospritenum], sizeof(spritetype));
1718
                    vm.g_i = nspritenum;
1719
                    vm.g_sp = &sprite[nspritenum];
1720
                }
1721
                else
1493 helixhorne 1722
                {
1536 helixhorne 1723
                    Bmemcpy(&tsprite[spritesortcnt], &sprite[ospritenum], sizeof(spritetype));
1724
                    tsprite[spritesortcnt].owner = ospritenum;
1725
                    vm.g_i = -1;
1726
                    vm.g_sp = &tsprite[spritesortcnt];
1727
                    spritesortcnt++;
1493 helixhorne 1728
                }
1729
            }
1730
            continue;
1731
 
1732
        case CON_DELETESPRITE:
1733
            insptr++;
1734
            {
1735
                int32_t daspritenum = Gv_GetVarX(*insptr++), ret;
1736
 
1737
                X_ERROR_INVALIDSPRI(daspritenum);
1738
                ret = deletesprite(daspritenum);
1501 helixhorne 1739
                g_iReturnVar = ret;
1493 helixhorne 1740
            }
1741
            continue;
1742
 
2590 helixhorne 1743
        case CON_GETSPRITELINKTYPE:
1744
            insptr++;
1745
            {
1746
                int32_t spritenum=Gv_GetVarX(*insptr++), resvar = *insptr++;
1747
 
1748
                X_ERROR_INVALIDSPRI(spritenum);
1749
                Gv_SetVarX(resvar, taglab_linktags(1, spritenum));
1750
            }
1751
            continue;
1752
 
1493 helixhorne 1753
        case CON_LASTWALL:
1754
            insptr++;
1755
            {
1756
                int32_t dapoint = Gv_GetVarX(*insptr++), resvar=*insptr++;
1757
 
1758
                if (dapoint<0 || dapoint>=numwalls)
1759
                {
1877 helixhorne 1760
                    M32_ERROR("Invalid wall %d", dapoint);
1493 helixhorne 1761
                    continue;
1762
                }
1763
 
1764
                Gv_SetVarX(resvar, lastwall(dapoint));
1765
            }
1766
            continue;
1767
 
1768
        case CON_GETZRANGE:
1769
            insptr++;
1770
            {
1771
                vec3_t vect;
1772
 
1773
                vect.x = Gv_GetVarX(*insptr++);
1774
                vect.y = Gv_GetVarX(*insptr++);
1775
                vect.z = Gv_GetVarX(*insptr++);
1776
 
1777
                {
1778
                    int32_t sectnum=Gv_GetVarX(*insptr++);
1779
                    int32_t ceilzvar=*insptr++, ceilhitvar=*insptr++, florzvar=*insptr++, florhitvar=*insptr++;
1780
                    int32_t walldist=Gv_GetVarX(*insptr++), clipmask=Gv_GetVarX(*insptr++);
1781
                    int32_t ceilz, ceilhit, florz, florhit;
1782
 
1783
                    X_ERROR_INVALIDSECT(sectnum);
1784
                    getzrange(&vect, sectnum, &ceilz, &ceilhit, &florz, &florhit, walldist, clipmask);
1785
                    Gv_SetVarX(ceilzvar, ceilz);
1786
                    Gv_SetVarX(ceilhitvar, ceilhit);
1787
                    Gv_SetVarX(florzvar, florz);
1788
                    Gv_SetVarX(florhitvar, florhit);
1789
                }
1790
                continue;
1791
            }
1792
 
1708 helixhorne 1793
        case CON_CALCHYPOTENUSE:
1794
            insptr++;
1795
            {
1796
                int32_t retvar=*insptr++;
1797
                int64_t dax=Gv_GetVarX(*insptr++), day=Gv_GetVarX(*insptr++);
1798
                int64_t hypsq = dax*dax + day*day;
1799
 
1955 helixhorne 1800
                if (hypsq > (int64_t)INT32_MAX)
1708 helixhorne 1801
                    Gv_SetVarX(retvar, (int32_t)sqrt((double)hypsq));
1802
                else
2791 helixhorne 1803
                    Gv_SetVarX(retvar, ksqrt((uint32_t)hypsq));
1708 helixhorne 1804
 
1805
                continue;
1806
            }
1807
 
1808
        case CON_LINEINTERSECT:
1809
        case CON_RAYINTERSECT:
1810
            insptr++;
1811
            {
1812
                int32_t x1=Gv_GetVarX(*insptr++), y1=Gv_GetVarX(*insptr++), z1=Gv_GetVarX(*insptr++);
1813
                int32_t x2=Gv_GetVarX(*insptr++), y2=Gv_GetVarX(*insptr++), z2=Gv_GetVarX(*insptr++);
1814
                int32_t x3=Gv_GetVarX(*insptr++), y3=Gv_GetVarX(*insptr++), x4=Gv_GetVarX(*insptr++), y4=Gv_GetVarX(*insptr++);
1815
                int32_t intxvar=*insptr++, intyvar=*insptr++, intzvar=*insptr++, retvar=*insptr++;
1816
                int32_t intx, inty, intz, ret;
1817
 
1818
                if (tw==CON_LINEINTERSECT)
1819
                    ret = lineintersect(x1, y1, z1, x2, y2, z2, x3, y3, x4, y4, &intx, &inty, &intz);
1820
                else
1821
                    ret = rayintersect(x1, y1, z1, x2, y2, z2, x3, y3, x4, y4, &intx, &inty, &intz);
1822
 
1823
                Gv_SetVarX(retvar, ret);
1824
                if (ret)
1825
                {
1826
                    Gv_SetVarX(intxvar, intx);
1827
                    Gv_SetVarX(intyvar, inty);
1828
                    Gv_SetVarX(intzvar, intz);
1829
                }
1830
 
1831
                continue;
1832
            }
1833
 
1834
        case CON_CLIPMOVE:
1835
            insptr++;
1836
            {
1837
                vec3_t vect;
1838
                int32_t retvar=*insptr++, xvar=*insptr++, yvar=*insptr++, z=Gv_GetVarX(*insptr++), sectnumvar=*insptr++;
1839
                int32_t xvect=Gv_GetVarX(*insptr++), yvect=Gv_GetVarX(*insptr++);
1840
                int32_t walldist=Gv_GetVarX(*insptr++), floordist=Gv_GetVarX(*insptr++), ceildist=Gv_GetVarX(*insptr++);
1841
                int32_t clipmask=Gv_GetVarX(*insptr++);
1842
                int16_t sectnum;
1843
 
1844
                vect.x = Gv_GetVarX(xvar);
1845
                vect.y = Gv_GetVarX(yvar);
1846
                vect.z = z;
1847
                sectnum = Gv_GetVarX(sectnumvar);
1848
 
1849
                X_ERROR_INVALIDSECT(sectnum);
1850
 
1851
                Gv_SetVarX(retvar, clipmove(&vect, &sectnum, xvect, yvect, walldist, floordist, ceildist, clipmask));
1852
                Gv_SetVarX(sectnumvar, sectnum);
1853
                Gv_SetVarX(xvar, vect.x);
1854
                Gv_SetVarX(yvar, vect.y);
1855
 
1856
                continue;
1857
            }
1858
 
1493 helixhorne 1859
        case CON_HITSCAN:
1860
            insptr++;
1861
            {
1862
                vec3_t vect;
2877 helixhorne 1863
                hitdata_t hit;
1493 helixhorne 1864
 
1865
                vect.x = Gv_GetVarX(*insptr++);
1866
                vect.y = Gv_GetVarX(*insptr++);
1867
                vect.z = Gv_GetVarX(*insptr++);
1868
 
1869
                {
1870
                    int32_t sectnum=Gv_GetVarX(*insptr++);
1871
                    int32_t vx=Gv_GetVarX(*insptr++), vy=Gv_GetVarX(*insptr++), vz=Gv_GetVarX(*insptr++);
1872
                    int32_t hitsectvar=*insptr++, hitwallvar=*insptr++, hitspritevar=*insptr++;
1873
                    int32_t hitxvar=*insptr++, hityvar=*insptr++, hitzvar=*insptr++, cliptype=Gv_GetVarX(*insptr++);
1874
 
1875
                    X_ERROR_INVALIDSECT(sectnum);
2877 helixhorne 1876
                    hitscan((const vec3_t *)&vect, sectnum, vx, vy, vz, &hit, cliptype);
1877
                    Gv_SetVarX(hitsectvar, hit.sect);
1878
                    Gv_SetVarX(hitwallvar, hit.wall);
1879
                    Gv_SetVarX(hitspritevar, hit.sprite);
1880
                    Gv_SetVarX(hitxvar, hit.pos.x);
1881
                    Gv_SetVarX(hityvar, hit.pos.y);
1882
                    Gv_SetVarX(hitzvar, hit.pos.z);
1493 helixhorne 1883
                }
1884
                continue;
1885
            }
1886
 
1887
        case CON_CANSEE:
1888
            insptr++;
1889
            {
1890
                int32_t x1=Gv_GetVarX(*insptr++), y1=Gv_GetVarX(*insptr++), z1=Gv_GetVarX(*insptr++);
1891
                int32_t sect1=Gv_GetVarX(*insptr++);
1892
                int32_t x2=Gv_GetVarX(*insptr++), y2=Gv_GetVarX(*insptr++), z2=Gv_GetVarX(*insptr++);
1893
                int32_t sect2=Gv_GetVarX(*insptr++), rvar=*insptr++;
1894
 
1895
                X_ERROR_INVALIDSECT(sect1);
1896
                X_ERROR_INVALIDSECT(sect2);
1897
 
1898
                Gv_SetVarX(rvar, cansee(x1,y1,z1,sect1,x2,y2,z2,sect2));
1899
                continue;
1900
            }
1901
 
1902
        case CON_ROTATEPOINT:
1903
            insptr++;
1904
            {
1905
                int32_t xpivot=Gv_GetVarX(*insptr++), ypivot=Gv_GetVarX(*insptr++);
1906
                int32_t x=Gv_GetVarX(*insptr++), y=Gv_GetVarX(*insptr++), daang=Gv_GetVarX(*insptr++);
1907
                int32_t x2var=*insptr++, y2var=*insptr++;
1908
                int32_t x2, y2;
1909
 
1910
                rotatepoint(xpivot,ypivot,x,y,daang,&x2,&y2);
1911
                Gv_SetVarX(x2var, x2);
1912
                Gv_SetVarX(y2var, y2);
1913
                continue;
1914
            }
1915
 
1916
        case CON_NEARTAG:
1917
            insptr++;
1918
            {
1919
                // neartag(int32_t x, int32_t y, int32_t z, short sectnum, short ang,  //Starting position & angle
1920
                //         short *neartagsector,    //Returns near sector if sector[].tag != 0
1921
                //         short *neartagwall,      //Returns near wall if wall[].tag != 0
1922
                //         short *neartagsprite,    //Returns near sprite if sprite[].tag != 0
1923
                //         int32_t *neartaghitdist, //Returns actual distance to object (scale: 1024=largest grid size)
1924
                //         int32_t neartagrange,    //Choose maximum distance to scan (scale: 1024=largest grid size)
1925
                //         char tagsearch)          //1-lotag only, 2-hitag only, 3-lotag&hitag
1926
 
1927
                int32_t x=Gv_GetVarX(*insptr++), y=Gv_GetVarX(*insptr++), z=Gv_GetVarX(*insptr++);
1928
                int32_t sectnum=Gv_GetVarX(*insptr++), ang=Gv_GetVarX(*insptr++);
1929
                int32_t neartagsectorvar=*insptr++, neartagwallvar=*insptr++, neartagspritevar=*insptr++, neartaghitdistvar=*insptr++;
1930
                int32_t neartagrange=Gv_GetVarX(*insptr++), tagsearch=Gv_GetVarX(*insptr++);
1931
 
1497 helixhorne 1932
                int16_t neartagsector, neartagwall, neartagsprite;
1933
                int32_t neartaghitdist;
1934
 
1493 helixhorne 1935
                X_ERROR_INVALIDSECT(sectnum);
2373 helixhorne 1936
                neartag(x, y, z, sectnum, ang, &neartagsector, &neartagwall, &neartagsprite,
1937
                        &neartaghitdist, neartagrange, tagsearch, NULL);
1493 helixhorne 1938
 
1939
                Gv_SetVarX(neartagsectorvar, neartagsector);
1940
                Gv_SetVarX(neartagwallvar, neartagwall);
1941
                Gv_SetVarX(neartagspritevar, neartagsprite);
1942
                Gv_SetVarX(neartaghitdistvar, neartaghitdist);
1943
                continue;
1944
            }
1945
 
1946
        case CON_BSETSPRITE:  // was CON_SETSPRITE
1947
            insptr++;
1948
            {
1949
                int32_t spritenum = Gv_GetVarX(*insptr++);
1950
                vec3_t davector;
1951
 
1952
                davector.x = Gv_GetVarX(*insptr++);
1953
                davector.y = Gv_GetVarX(*insptr++);
1954
                davector.z = Gv_GetVarX(*insptr++);
1955
 
1956
                X_ERROR_INVALIDSPRI(spritenum);
1957
                setsprite(spritenum, &davector);
1958
                continue;
1959
            }
1960
 
1961
        case CON_GETFLORZOFSLOPE:
1962
        case CON_GETCEILZOFSLOPE:
1963
            insptr++;
1964
            {
1965
                int32_t sectnum = Gv_GetVarX(*insptr++), x = Gv_GetVarX(*insptr++), y = Gv_GetVarX(*insptr++);
1500 helixhorne 1966
                int32_t var=*insptr++;
1493 helixhorne 1967
 
1500 helixhorne 1968
                X_ERROR_INVALIDSECT(sectnum);
1493 helixhorne 1969
                if (tw == CON_GETFLORZOFSLOPE)
1500 helixhorne 1970
                    Gv_SetVarX(var, getflorzofslope(sectnum,x,y));
1971
                else
1972
                    Gv_SetVarX(var, getceilzofslope(sectnum,x,y));
1493 helixhorne 1973
                continue;
1974
            }
1975
 
1500 helixhorne 1976
        case CON_ALIGNFLORSLOPE:
1977
        case CON_ALIGNCEILSLOPE:
1978
            insptr++;
1979
            {
1980
                int32_t sectnum = Gv_GetVarX(*insptr++), x = Gv_GetVarX(*insptr++), y = Gv_GetVarX(*insptr++);
1981
                int32_t z=Gv_GetVarX(*insptr++);
1982
 
1983
                X_ERROR_INVALIDSECT(sectnum);
1984
                if (tw == CON_ALIGNFLORSLOPE)
1985
                    alignflorslope(sectnum, x,y,z);
1986
                else
1987
                    alignceilslope(sectnum, x,y,z);
1988
                continue;
1989
            }
1990
 
1493 helixhorne 1991
// CURSPR
1499 helixhorne 1992
        case CON_SETFIRSTWALL:
1993
            insptr++;
1994
            {
1995
                int32_t sect=Gv_GetVarX(*insptr++), wal=Gv_GetVarX(*insptr++);
1996
 
1997
                X_ERROR_INVALIDSECT(sect);
1998
                setfirstwall(sect, wal);
1999
            }
2000
            continue;
2001
 
2002
        case CON_UPDATECURSECTNUM:
2003
            insptr++;
2004
            updatesectorz(pos.x, pos.y, pos.z, &cursectnum);
2005
            continue;
2006
 
1493 helixhorne 2007
        case CON_UPDATESECTOR:
2008
        case CON_UPDATESECTORZ:
2009
            insptr++;
2010
            {
2011
                int32_t x=Gv_GetVarX(*insptr++), y=Gv_GetVarX(*insptr++);
2012
                int32_t z=(tw==CON_UPDATESECTORZ)?Gv_GetVarX(*insptr++):0;
2013
                int32_t var=*insptr++;
2014
                int16_t w;
2015
 
2016
                X_ERROR_INVALIDCI();
2017
                w=sprite[vm.g_i].sectnum;
2018
 
2019
                if (tw==CON_UPDATESECTOR) updatesector(x,y,&w);
2020
                else updatesectorz(x,y,z,&w);
2021
 
2022
                Gv_SetVarX(var, w);
2023
                continue;
2024
            }
2025
 
2026
        case CON_HEADSPRITESTAT:
2027
            insptr++;
2028
            {
2029
                int32_t i=*insptr++;
2030
                int32_t j=Gv_GetVarX(*insptr++);
2031
                if (j < 0 || j > MAXSTATUS)
2032
                {
1877 helixhorne 2033
                    M32_ERROR("invalid status list %d", j);
1493 helixhorne 2034
                    continue;
2035
                }
2036
                Gv_SetVarX(i,headspritestat[j]);
2037
                continue;
2038
            }
2039
 
2040
        case CON_PREVSPRITESTAT:
2041
            insptr++;
2042
            {
2043
                int32_t i=*insptr++;
2044
                int32_t j=Gv_GetVarX(*insptr++);
2045
 
2046
                X_ERROR_INVALIDSPRI(j);
2047
                Gv_SetVarX(i,prevspritestat[j]);
2048
                continue;
2049
            }
2050
 
2051
        case CON_NEXTSPRITESTAT:
2052
            insptr++;
2053
            {
2054
                int32_t i=*insptr++;
2055
                int32_t j=Gv_GetVarX(*insptr++);
2056
 
2057
                X_ERROR_INVALIDSPRI(j);
2058
                Gv_SetVarX(i,nextspritestat[j]);
2059
                continue;
2060
            }
2061
 
2062
        case CON_HEADSPRITESECT:
2063
            insptr++;
2064
            {
2065
                int32_t i=*insptr++;
2066
                int32_t j=Gv_GetVarX(*insptr++);
2067
 
2068
                X_ERROR_INVALIDSECT(j);
2069
                Gv_SetVarX(i,headspritesect[j]);
2070
                continue;
2071
            }
2072
 
2073
        case CON_PREVSPRITESECT:
2074
            insptr++;
2075
            {
2076
                int32_t i=*insptr++;
2077
                int32_t j=Gv_GetVarX(*insptr++);
2078
 
2079
                X_ERROR_INVALIDSPRI(j);
2080
                Gv_SetVarX(i,prevspritesect[j]);
2081
                continue;
2082
            }
2083
 
2084
        case CON_NEXTSPRITESECT:
2085
            insptr++;
2086
            {
2087
                int32_t i=*insptr++;
2088
                int32_t j=Gv_GetVarX(*insptr++);
2089
 
2090
                X_ERROR_INVALIDSPRI(j);
2091
                Gv_SetVarX(i,nextspritesect[j]);
2092
                continue;
2093
            }
2094
 
2095
        case CON_CANSEESPR:
2096
            insptr++;
2097
            {
2098
                int32_t lVar1 = Gv_GetVarX(*insptr++), lVar2 = Gv_GetVarX(*insptr++), res;
2099
 
2100
                if (lVar1<0 || lVar1>=MAXSPRITES || sprite[lVar1].statnum==MAXSTATUS)
2101
                {
1877 helixhorne 2102
                    M32_ERROR("Invalid sprite %d", lVar1);
1493 helixhorne 2103
                }
2104
                if (lVar2<0 || lVar2>=MAXSPRITES || sprite[lVar2].statnum==MAXSTATUS)
2105
                {
1877 helixhorne 2106
                    M32_ERROR("Invalid sprite %d", lVar2);
1493 helixhorne 2107
                }
2108
 
1528 helixhorne 2109
                if (vm.flags&VMFLAG_ERROR) res=0;
1493 helixhorne 2110
                else res=cansee(sprite[lVar1].x,sprite[lVar1].y,sprite[lVar1].z,sprite[lVar1].sectnum,
2111
                                    sprite[lVar2].x,sprite[lVar2].y,sprite[lVar2].z,sprite[lVar2].sectnum);
2112
 
2113
                Gv_SetVarX(*insptr++, res);
2114
                continue;
2115
            }
2116
 
2117
        case CON_CHANGESPRITESTAT:
2118
        case CON_CHANGESPRITESECT:
2119
            insptr++;
2120
            {
2121
                int32_t i = Gv_GetVarX(*insptr++);
2122
                int32_t j = Gv_GetVarX(*insptr++);
2123
 
2124
                X_ERROR_INVALIDSPRI(i);
2125
                if (j<0 || j >= (tw==CON_CHANGESPRITESTAT?MAXSTATUS:numsectors))
2126
                {
1877 helixhorne 2127
                    M32_ERROR("Invalid %s: %d", tw==CON_CHANGESPRITESTAT?"statnum":"sector", j);
1493 helixhorne 2128
                    continue;
2129
                }
2130
 
2131
                if (tw == CON_CHANGESPRITESTAT)
2132
                {
2133
                    if (sprite[i].statnum == j) continue;
2134
                    changespritestat(i,j);
2135
                }
2136
                else
2137
                {
2138
                    if (sprite[i].sectnum == j) continue;
2139
                    changespritesect(i,j);
2140
                }
2141
                continue;
2142
            }
2143
 
2144
        case CON_DRAGPOINT:
2145
            insptr++;
2146
            {
2147
                int32_t wallnum = Gv_GetVarX(*insptr++), newx = Gv_GetVarX(*insptr++), newy = Gv_GetVarX(*insptr++);
2148
 
2149
                if (wallnum<0 || wallnum>=numwalls)
2150
                {
1877 helixhorne 2151
                    M32_ERROR("Invalid wall %d", wallnum);
1493 helixhorne 2152
                    continue;
2153
                }
3394 helixhorne 2154
                dragpoint(wallnum,newx,newy,0);
1493 helixhorne 2155
                continue;
2156
            }
2157
 
2158
        case CON_SECTOROFWALL:
2159
            insptr++;
2160
            {
2161
                int32_t j = *insptr++;
2162
                Gv_SetVarX(j, sectorofwall(Gv_GetVarX(*insptr++)));
2163
            }
2164
            continue;
2165
 
1579 helixhorne 2166
        case CON_FIXREPEATS:
2167
            insptr++;
1886 helixhorne 2168
            fixrepeats(Gv_GetVarX(*insptr++));
1579 helixhorne 2169
            continue;
2170
 
1683 helixhorne 2171
        case CON_GETCLOSESTCOL:
2172
            insptr++;
2173
            {
2174
                int32_t r = Gv_GetVarX(*insptr++), g = Gv_GetVarX(*insptr++), b = Gv_GetVarX(*insptr++);
2175
                Gv_SetVarX(*insptr++, getclosestcol((r>>2)&63, (g>>2)&63, (b>>2)&63));
2176
                continue;
2177
            }
1710 helixhorne 2178
 
1493 helixhorne 2179
// *** stuff
1710 helixhorne 2180
        case CON_UPDATEHIGHLIGHT:
2181
            insptr++;
2182
            update_highlight();
2183
            continue;
2184
 
1927 helixhorne 2185
        case CON_UPDATEHIGHLIGHTSECTOR:
2186
            insptr++;
2187
            update_highlightsector();
2188
            continue;
2189
 
1710 helixhorne 2190
        case CON_SETHIGHLIGHT:
2191
            insptr++;
2192
            {
2193
                int32_t what=Gv_GetVarX(*insptr++), index=Gv_GetVarX(*insptr++), doset = Gv_GetVarX(*insptr++);
2194
 
1927 helixhorne 2195
                if (highlightsectorcnt >= 0)
2196
                {
2197
                    M32_ERROR("sector highlight active or pending, cannot highlight sprites/walls");
2198
                    continue;
2199
                }
2200
 
1710 helixhorne 2201
                if (what&16384)
2202
                {
2203
                    index &= ~16384;
2204
                    if (index < 0 || index>=MAXSPRITES || sprite[index].statnum==MAXSTATUS)
2205
                    {
1877 helixhorne 2206
                        M32_ERROR("Invalid sprite index %d", index);
1710 helixhorne 2207
                        continue;
2208
                    }
2209
 
2210
                    if (doset)
2211
                        show2dsprite[index>>3] |= (1<<(index&7));
2212
                    else
2213
                        show2dsprite[index>>3] &= ~(1<<(index&7));
2214
                }
1927 helixhorne 2215
                else
1710 helixhorne 2216
                {
1927 helixhorne 2217
                    if (index < 0 || index>=numwalls)
2218
                    {
2219
                        M32_ERROR("Invalid wall index %d", index);
2220
                        continue;
2221
                    }
1710 helixhorne 2222
 
2223
                    if (doset)
2224
                        show2dwall[index>>3] |= (1<<(index&7));
2225
                    else
2226
                        show2dwall[index>>3] &= ~(1<<(index&7));
2227
                }
2228
 
1955 helixhorne 2229
                vm.miscflags |= VMFLAG_MISC_UPDATEHL;
1710 helixhorne 2230
 
2231
                continue;
2232
            }
2233
 
1927 helixhorne 2234
        case CON_SETHIGHLIGHTSECTOR:
2235
            insptr++;
2236
            {
2237
                int32_t index=Gv_GetVarX(*insptr++), doset = Gv_GetVarX(*insptr++);
2238
 
2239
                if (highlightcnt >= 0)
2240
                {
2241
                    M32_ERROR("sprite/wall highlight active or pending, cannot highlight sectors");
2242
                    continue;
2243
                }
2244
 
2245
                X_ERROR_INVALIDSECT(index);
2246
 
2247
                if (doset)
2248
                    hlsectorbitmap[index>>3] |= (1<<(index&7));
2249
                else
2250
                    hlsectorbitmap[index>>3] &= ~(1<<(index&7));
2251
 
1955 helixhorne 2252
                vm.miscflags |= VMFLAG_MISC_UPDATEHLSECT;
1927 helixhorne 2253
 
2254
                continue;
2255
            }
2256
 
1493 helixhorne 2257
        case CON_GETTIMEDATE:
2258
            insptr++;
2259
            {
2260
                int32_t v1=*insptr++,v2=*insptr++,v3=*insptr++,v4=*insptr++,v5=*insptr++,v6=*insptr++,v7=*insptr++,v8=*insptr++;
2261
                time_t rawtime;
1677 terminx 2262
                struct tm *ti;
1493 helixhorne 2263
 
2264
                time(&rawtime);
2265
                ti = localtime(&rawtime);
2266
                // initprintf("Time&date: %s\n",asctime (ti));
2267
 
2268
                Gv_SetVarX(v1, ti->tm_sec);
2269
                Gv_SetVarX(v2, ti->tm_min);
2270
                Gv_SetVarX(v3, ti->tm_hour);
2271
                Gv_SetVarX(v4, ti->tm_mday);
2272
                Gv_SetVarX(v5, ti->tm_mon);
2273
                Gv_SetVarX(v6, ti->tm_year+1900);
2274
                Gv_SetVarX(v7, ti->tm_wday);
2275
                Gv_SetVarX(v8, ti->tm_yday);
2276
                continue;
2277
            }
2278
 
2279
        case CON_ADDLOG:
2280
        {
2281
            insptr++;
2282
 
2283
            OSD_Printf("L=%d\n", g_errorLineNum);
2284
            continue;
2285
        }
2286
 
2287
        case CON_ADDLOGVAR:
2288
            insptr++;
2289
            {
2290
                char buf[80] = "", buf2[80] = "";
2291
                int32_t code = (int32_t)*insptr, val = Gv_GetVarX(code);
1649 helixhorne 2292
                int32_t negate=code&M32_FLAG_NEGATE;
1493 helixhorne 2293
 
2294
                if (code & (0xFFFFFFFF-(MAXGAMEVARS-1)))
2295
                {
1691 helixhorne 2296
                    if ((code&M32_VARTYPE_MASK)==M32_FLAG_ARRAY || (code&M32_VARTYPE_MASK)==M32_FLAG_STRUCT)
1493 helixhorne 2297
                    {
1691 helixhorne 2298
                        if (code&M32_FLAG_CONSTANT)
1493 helixhorne 2299
                            Bsprintf(buf2, "%d", (code>>16)&0xffff);
2300
                        else
1691 helixhorne 2301
                        {
2302
                            char *label = aGameVars[(code>>16)&(MAXGAMEVARS-1)].szLabel;
2303
                            Bsprintf(buf2, "%s", label?label:"???");
2304
                        }
1493 helixhorne 2305
                    }
1691 helixhorne 2306
                    else if ((code&M32_VARTYPE_MASK)==M32_FLAG_LOCAL)
2307
                        Bsprintf(buf2, "%d", code&(MAXGAMEVARS-1));
1493 helixhorne 2308
 
1691 helixhorne 2309
                    if ((code&0x0000FFFC) == M32_FLAG_CONSTANT) // addlogvar for a constant.. why not? :P
1496 helixhorne 2310
                    {
2311
                        switch (code&3)
2312
                        {
2313
                        case 0: Bsprintf(buf, "(immediate constant)"); break;
2314
                        case 1: Bsprintf(buf, "(indirect constant)"); break;
2315
                        case 2: Bsprintf(buf, "(label constant)"); break;
2316
                        default: Bsprintf(buf, "(??? constant)"); break;
2317
                        }
2318
                    }
1493 helixhorne 2319
                    else
1691 helixhorne 2320
                    {
2321
                        switch (code&M32_VARTYPE_MASK)
2322
                        {
2323
                        case M32_FLAG_ARRAY:
2324
                            Bsprintf(buf, "%s[%s]", aGameArrays[code&(MAXGAMEARRAYS-1)].szLabel?
2325
                                     aGameArrays[code&(MAXGAMEARRAYS-1)].szLabel:"???", buf2);
2326
                            break;
2327
                        case M32_FLAG_STRUCT:
1877 helixhorne 2328
                        {
2329
                            int32_t memberid=(code>>2)&63, lightp = (memberid >= LIGHT_X);
2330
                            const char *pp1[4] = {"sprite","sector","wall","tsprite"};
2331
                            const memberlabel_t *pp2[4] = {SpriteLabels, SectorLabels, WallLabels, SpriteLabels};
2332
                            if (lightp)
2333
                            {
2334
                                pp1[3] = "light";
2335
                                pp2[3] = LightLabels;
2336
                                memberid -= LIGHT_X;
2337
                            }
2338
 
2339
                            Bsprintf(buf, "%s[%s].%s", pp1[code&3], buf2, pp2[code&3][memberid].name);
2340
                        }
2341
                        break;
1691 helixhorne 2342
                        case M32_FLAG_VAR:
2343
                            Bsprintf(buf, "???");
2344
                            break;
2345
                        case M32_FLAG_LOCAL:
2346
                            Bsprintf(buf, ".local[%s]", buf2);
2347
                            break;
2348
                        }
2349
                    }
1493 helixhorne 2350
                }
2351
                else
2352
                {
2353
                    if (aGameVars[code].dwFlags & GAMEVAR_PERBLOCK)
2354
                    {
2355
                        Bsprintf(buf2, "(%s", vm.g_st==0? "top-level) " : vm.g_st<=MAXEVENTS? "event" : "state");
2356
                        if (vm.g_st >= 1+MAXEVENTS && vm.g_st <1+MAXEVENTS+g_stateCount)
2357
                            Bsprintf(buf, " `%s') ", statesinfo[vm.g_st-1-MAXEVENTS].name);
2358
                        else if (vm.g_st > 0)
2359
                            Bsprintf(buf, " %d) ", vm.g_st-1);
2360
                        Bstrcat(buf2, buf);
2361
                    }
2362
 
2363
                    Bsprintf(buf, "%s%s", buf2, aGameVars[code].szLabel ? aGameVars[code].szLabel : "???");
2364
                }
2365
 
2366
                OSD_Printf("L%d: %s%s=%d\n", g_errorLineNum, negate?"-":"", buf, val);
2367
 
2368
                insptr++;
2369
                continue;
2370
            }
2371
 
2372
        case CON_DEBUG:
2373
            insptr++;
2374
            initprintf("%d\n",*insptr++);
2375
            continue;
2376
 
2377
// *** strings
2378
        case CON_REDEFINEQUOTE:
2379
            insptr++;
2380
            {
2381
                int32_t q = *insptr++, i = *insptr++;
1497 helixhorne 2382
                X_ERROR_INVALIDQUOTE(q, ScriptQuotes);
2383
                X_ERROR_INVALIDQUOTE(i, ScriptQuoteRedefinitions);
1493 helixhorne 2384
                Bstrcpy(ScriptQuotes[q],ScriptQuoteRedefinitions[i]);
2385
                continue;
2386
            }
2387
 
2388
            insptr++;
1497 helixhorne 2389
            X_ERROR_INVALIDQUOTE(*insptr, ScriptQuotes);
2390
            OSD_Printf("%s", ScriptQuotes[*insptr++]);
2391
            continue;
1493 helixhorne 2392
 
1955 helixhorne 2393
        case CON_GETNUMBER16:  /* deprecated */
2394
        case CON_GETNUMBER256:  /* deprecated */
2395
        case CON_GETNUMBERFROMUSER:
1497 helixhorne 2396
            insptr++;
1493 helixhorne 2397
            {
1691 helixhorne 2398
                int32_t var=*insptr++, quote=*insptr++;
2399
                const char *quotetext = GetMaybeInlineQuote(quote);
2400
                if (vm.flags&VMFLAG_ERROR)
2401
                    continue;
1497 helixhorne 2402
 
1691 helixhorne 2403
                {
1955 helixhorne 2404
                    int32_t max=Gv_GetVarX(*insptr++);
2405
                    int32_t sign = (tw==CON_GETNUMBERFROMUSER) ? Gv_GetVarX(*insptr++) : (max<=0);
1691 helixhorne 2406
                    char buf[64];  // buffers in getnumber* are 80 bytes long
1497 helixhorne 2407
 
2559 helixhorne 2408
                    Bstrncpyz(buf, quotetext, sizeof(buf));
1691 helixhorne 2409
 
1696 helixhorne 2410
                    if (max==0)
1955 helixhorne 2411
                        max = INT32_MAX;
4196 helixhorne 2412
                    else
2413
                        max = klabs(max);
1696 helixhorne 2414
 
1710 helixhorne 2415
//OSD_Printf("max:%d, sign:%d\n", max, sign);
1955 helixhorne 2416
                    if (tw==CON_GETNUMBERFROMUSER)
2417
                    {
3823 helixhorne 2418
                        Gv_SetVarX(var, in3dmode() ?
1955 helixhorne 2419
                                   getnumber256(quotetext, Gv_GetVarX(var), max, sign) :
2420
                                   getnumber16(quotetext, Gv_GetVarX(var), max, sign));
2421
                    }
2422
                    else if (tw==CON_GETNUMBER16)
1691 helixhorne 2423
                        Gv_SetVarX(var, getnumber16(quotetext, Gv_GetVarX(var), max, sign));
2424
                    else
2425
                        Gv_SetVarX(var, getnumber256(quotetext, Gv_GetVarX(var), max, sign));
2426
                }
1493 helixhorne 2427
            }
2428
            continue;
2429
 
1521 helixhorne 2430
        case CON_PRINT:
1493 helixhorne 2431
        case CON_QUOTE:
2432
        case CON_ERRORINS:
2433
        case CON_PRINTMESSAGE16:
2434
        case CON_PRINTMESSAGE256:
2435
        case CON_PRINTEXT256:
1497 helixhorne 2436
        case CON_PRINTEXT16:
1832 helixhorne 2437
        case CON_DRAWLABEL:
1493 helixhorne 2438
            insptr++;
2439
            {
1691 helixhorne 2440
                int32_t i=*insptr++;
2441
                const char *quotetext = GetMaybeInlineQuote(i);
2442
                if (vm.flags&VMFLAG_ERROR)
2443
                    continue;
1493 helixhorne 2444
 
1691 helixhorne 2445
                {
2446
                    int32_t x=(tw>=CON_PRINTMESSAGE256)?Gv_GetVarX(*insptr++):0;
2447
                    int32_t y=(tw>=CON_PRINTMESSAGE256)?Gv_GetVarX(*insptr++):0;
1832 helixhorne 2448
 
1691 helixhorne 2449
                    int32_t col=(tw>=CON_PRINTEXT256)?Gv_GetVarX(*insptr++):0;
2450
                    int32_t backcol=(tw>=CON_PRINTEXT256)?Gv_GetVarX(*insptr++):0;
2451
                    int32_t fontsize=(tw>=CON_PRINTEXT256)?Gv_GetVarX(*insptr++):0;
1493 helixhorne 2452
 
1691 helixhorne 2453
                    if (tw==CON_PRINT || tw==CON_ERRORINS)
1832 helixhorne 2454
                    {
1691 helixhorne 2455
                        OSD_Printf("%s\n", quotetext);
1832 helixhorne 2456
                        if (tw==CON_ERRORINS)
2457
                            vm.flags |= VMFLAG_ERROR;
2458
                    }
1691 helixhorne 2459
                    else if (tw==CON_QUOTE)
1832 helixhorne 2460
                    {
1691 helixhorne 2461
                        message("%s", quotetext);
1832 helixhorne 2462
                    }
1691 helixhorne 2463
                    else if (tw==CON_PRINTMESSAGE16)
1832 helixhorne 2464
                    {
3823 helixhorne 2465
                        if (!in3dmode())
1832 helixhorne 2466
                            printmessage16("%s", quotetext);
2467
                    }
1691 helixhorne 2468
                    else if (tw==CON_PRINTMESSAGE256)
1832 helixhorne 2469
                    {
3823 helixhorne 2470
                        if (in3dmode())
1832 helixhorne 2471
                            printmessage256(x, y, quotetext);
2472
                    }
1691 helixhorne 2473
                    else if (tw==CON_PRINTEXT256)
2474
                    {
3823 helixhorne 2475
                        if (in3dmode())
1832 helixhorne 2476
                        {
2816 helixhorne 2477
                            if (col>=256)
2478
                                col=0;
2479
                            else if (col < 0 && col >= -255)
2480
                                col = editorcolors[-col];
2481
 
2482
                            if (backcol<0 || backcol>=256)
2483
                                backcol=-1;
2484
 
1832 helixhorne 2485
                            printext256(x, y, col, backcol, quotetext, fontsize);
2486
                        }
1691 helixhorne 2487
                    }
2488
                    else if (tw==CON_PRINTEXT16)
2489
                    {
3823 helixhorne 2490
                        if (!in3dmode())
1832 helixhorne 2491
                            printext16(x, y, editorcolors[col&255], backcol<0 ? -1 : editorcolors[backcol&255],
2492
                                       quotetext, fontsize);
1691 helixhorne 2493
                    }
1832 helixhorne 2494
                    else if (tw==CON_DRAWLABEL)
2495
                    {
3823 helixhorne 2496
                        if (!in3dmode())
1832 helixhorne 2497
                        {
2498
                            drawsmallabel(quotetext,
2499
                                          editorcolors[backcol&255],  // col
2500
                                          fontsize < 0 ? -1 : editorcolors[fontsize&255],  // backcol
2501
                                          x, y, col);  // x y z
2502
                        }
2503
                    }
1493 helixhorne 2504
                }
2505
            }
2506
            continue;
2507
 
2508
        case CON_QSTRLEN:
2509
            insptr++;
2510
            {
1691 helixhorne 2511
                int32_t i=*insptr++, quote=*insptr++;
2512
                const char *quotetext = GetMaybeInlineQuote(quote);
2513
                if (vm.flags&VMFLAG_ERROR)
2514
                    continue;
1497 helixhorne 2515
 
1691 helixhorne 2516
                Gv_SetVarX(i, Bstrlen(quotetext));
1493 helixhorne 2517
                continue;
2518
            }
2519
 
2520
        case CON_QSUBSTR:
2521
            insptr++;
2522
            {
2523
                int32_t q1 = Gv_GetVarX(*insptr++);
1691 helixhorne 2524
                int32_t q2 = *insptr++;
2525
                const char *q2text = GetMaybeInlineQuote(q2);
2526
                if (vm.flags&VMFLAG_ERROR)
2527
                    continue;
1493 helixhorne 2528
 
1497 helixhorne 2529
                X_ERROR_INVALIDQUOTE(q1, ScriptQuotes);
1493 helixhorne 2530
 
2531
                {
1691 helixhorne 2532
                    int32_t st = Gv_GetVarX(*insptr++);
2533
                    int32_t ln = Gv_GetVarX(*insptr++);
1493 helixhorne 2534
                    char *s1 = ScriptQuotes[q1];
1691 helixhorne 2535
                    const char *s2 = q2text;
1493 helixhorne 2536
 
2537
                    while (*s2 && st--) s2++;
2538
                    while ((*s1 = *s2) && ln--)
2539
                    {
2540
                        s1++;
2541
                        s2++;
2542
                    }
2543
                    *s1=0;
2544
                }
2545
                continue;
2546
            }
2547
 
2548
        case CON_QSTRNCAT:
2549
        case CON_QSTRCAT:
2550
        case CON_QSTRCPY: