mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-11-18 18:21:38 +00:00
aa8b2e4e05
* fix breaking out of 'switch' blocks and compilation of the 'default' case * Have a way of assigning 'special function' menu [' F] entries to script states. Writing a string literal after the state name will register the state under that name. Menu names are limited to 24 characters and it's possible to have up to 16 of them. * new branching command 'ifinteractive', true if a state runs from the menu mentioned above. * new command: getnumberfromuser <<retvar>> "query_string" <maxnum> <flags> See 'state collect_teleporting_sectors' in a.m32 for a combined usage of the new functionality. git-svn-id: https://svn.eduke32.com/eduke32@1955 1a8010ca-5511-0410-912e-c29ae57300e0
3082 lines
101 KiB
C
3082 lines
101 KiB
C
//-------------------------------------------------------------------------
|
|
/*
|
|
Copyright (C) 2010 EDuke32 developers and contributors
|
|
|
|
This file is part of EDuke32.
|
|
|
|
EDuke32 is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License version 2
|
|
as published by the Free Software Foundation.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
//-------------------------------------------------------------------------
|
|
|
|
#include <time.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "m32script.h"
|
|
#include "m32def.h"
|
|
|
|
#include "sounds_mapster32.h"
|
|
#include "fx_man.h"
|
|
|
|
#include "osd.h"
|
|
#include "keys.h"
|
|
|
|
// from macros.h
|
|
#define rnd(X) ((krand()>>8)>=(255-(X)))
|
|
|
|
vmstate_t vm;
|
|
vmstate_t vm_default =
|
|
{
|
|
-1, // g_i
|
|
0, // g_st
|
|
NULL, // g_sp
|
|
0, // flags
|
|
0, // miscflags
|
|
};
|
|
|
|
int32_t g_errorLineNum, g_tw;
|
|
|
|
uint8_t aEventEnabled[MAXEVENTS];
|
|
|
|
uint32_t m32_drawlinepat=0xffffffff;
|
|
int32_t m32_script_expertmode = 0;
|
|
|
|
instype *insptr;
|
|
int32_t VM_Execute(int32_t once);
|
|
static instype *x_sortingstateptr;
|
|
|
|
//#include "m32structures.c"
|
|
|
|
// from sector.c vvv
|
|
static int32_t ldist(const spritetype *s1, const spritetype *s2)
|
|
{
|
|
int32_t x= klabs(s1->x-s2->x);
|
|
int32_t y= klabs(s1->y-s2->y);
|
|
|
|
if (x<y) swaplong(&x,&y);
|
|
|
|
{
|
|
int32_t t = y + (y>>1);
|
|
return (x - (x>>5) - (x>>7) + (t>>2) + (t>>6));
|
|
}
|
|
}
|
|
|
|
static int32_t dist(const spritetype *s1, const spritetype *s2)
|
|
{
|
|
int32_t x= klabs(s1->x-s2->x);
|
|
int32_t y= klabs(s1->y-s2->y);
|
|
int32_t z= klabs((s1->z-s2->z)>>4);
|
|
|
|
if (x<y) swaplong(&x,&y);
|
|
if (x<z) swaplong(&x,&z);
|
|
|
|
{
|
|
int32_t t = y + z;
|
|
return (x - (x>>4) + (t>>2) + (t>>3));
|
|
}
|
|
}
|
|
///
|
|
|
|
#ifdef DEBUGGINGAIDS
|
|
void X_Disasm(ofstype beg, int32_t size)
|
|
{
|
|
instype *p;
|
|
|
|
if (!script) return;
|
|
if (beg<0 || beg+size>g_scriptSize) return;
|
|
|
|
initprintf("beg=%d, size=%d: ", beg, size);
|
|
for (p=script+beg; p<script+beg+size; p++)
|
|
{
|
|
if (*p>>12 && (*p&0xFFF)<CON_END)
|
|
initprintf("%s ", keyw[*p&0xFFF]);
|
|
else
|
|
initprintf("%d ", *p);
|
|
}
|
|
initprintf("\n");
|
|
}
|
|
#endif
|
|
|
|
void VM_ScriptInfo(void)
|
|
{
|
|
if (script)
|
|
{
|
|
instype *p;
|
|
if (insptr)
|
|
for (p=max(insptr-20,script); p<min(insptr+20, script+g_scriptSize); p++)
|
|
{
|
|
if (p==insptr) initprintf("<<");
|
|
|
|
if (*p>>12 && (*p&0xFFF)<CON_END)
|
|
initprintf("\n%5d: L%5d: %s ",(int32_t)(p-script),(int32_t)(*p>>12),keyw[*p&0xFFF]);
|
|
else initprintf(" %d",*p);
|
|
|
|
if (p==insptr) initprintf(">>");
|
|
}
|
|
initprintf(" \n");
|
|
if (vm.g_i >= 0)
|
|
initprintf("current sprite: %d\n",vm.g_i);
|
|
if (g_tw>=0 && g_tw<CON_END)
|
|
initprintf("g_errorLineNum: %d, g_tw: %s\n",g_errorLineNum,keyw[g_tw]);
|
|
else
|
|
initprintf("g_errorLineNum: %d, g_tw: %d\n",g_errorLineNum,g_tw);
|
|
}
|
|
}
|
|
|
|
void M32_PostScriptExec(void)
|
|
{
|
|
if (vm.miscflags&VMFLAG_MISC_UPDATEHL)
|
|
{
|
|
update_highlight();
|
|
vm.miscflags &= ~VMFLAG_MISC_UPDATEHL;
|
|
}
|
|
|
|
if (vm.miscflags&VMFLAG_MISC_UPDATEHLSECT)
|
|
{
|
|
update_highlightsector();
|
|
if (qsetmode != 200)
|
|
ovh_whiteoutgrab(1);
|
|
vm.miscflags &= ~VMFLAG_MISC_UPDATEHLSECT;
|
|
}
|
|
}
|
|
|
|
void VM_OnEvent(register int32_t iEventID, register int32_t iActor)
|
|
{
|
|
if (iEventID < 0 || iEventID >= MAXEVENTS)
|
|
{
|
|
M32_PRINTERROR("Invalid event ID");
|
|
return;
|
|
}
|
|
|
|
if (aEventOffsets[iEventID] < 0 || !aEventEnabled[iEventID])
|
|
{
|
|
//Bsprintf(g_szBuf,"No event found for %d",iEventID);
|
|
//AddLog(g_szBuf);
|
|
return;
|
|
}
|
|
|
|
{
|
|
instype *oinsptr=insptr;
|
|
vmstate_t vm_backup;
|
|
void *olocalvars = aGameArrays[M32_LOCAL_ARRAY_ID].vals;
|
|
#ifdef M32_LOCALS_VARARRAY
|
|
int32_t localvars[aEventNumLocals[iEventID]];
|
|
#elif defined M32_LOCALS_ALLOCA
|
|
int32_t *localvars = alloca(aEventNumLocals[iEventID] * sizeof(int32_t));
|
|
#else
|
|
int32_t localvars[M32_LOCALS_FIXEDNUM];
|
|
#endif
|
|
|
|
// needed since any read access before initialization would cause undefined behaviour
|
|
if (aEventNumLocals[iEventID] > 0)
|
|
Bmemset(localvars, 0, aEventNumLocals[iEventID]*sizeof(int32_t));
|
|
|
|
Bmemcpy(&vm_backup, &vm, sizeof(vmstate_t));
|
|
|
|
vm.g_i = iActor; // current sprite ID
|
|
if (vm.g_i >= 0)
|
|
vm.g_sp = &sprite[vm.g_i];
|
|
|
|
vm.g_st = 1+iEventID;
|
|
|
|
vm.flags = 0;
|
|
|
|
insptr = script + aEventOffsets[iEventID];
|
|
|
|
aGameArrays[M32_LOCAL_ARRAY_ID].vals = localvars;
|
|
VM_Execute(0);
|
|
aGameArrays[M32_LOCAL_ARRAY_ID].vals = olocalvars;
|
|
|
|
if (vm.flags&VMFLAG_ERROR)
|
|
{
|
|
aEventEnabled[iEventID] = 0;
|
|
message("ERROR executing %s. Event disabled.", label+(iEventID*MAXLABELLEN));
|
|
}
|
|
|
|
M32_PostScriptExec();
|
|
|
|
// restore old values...
|
|
Bmemcpy(&vm, &vm_backup, sizeof(vmstate_t));
|
|
insptr = oinsptr;
|
|
|
|
//AddLog("End of Execution");
|
|
}
|
|
}
|
|
|
|
static int32_t G_GetAngleDelta(int32_t a,int32_t na)
|
|
{
|
|
a &= 2047;
|
|
na &= 2047;
|
|
|
|
if (klabs(a-na) < 1024)
|
|
{
|
|
// OSD_Printf("G_GetAngleDelta() returning %d\n",na-a);
|
|
return (na-a);
|
|
}
|
|
|
|
if (na > 1024) na -= 2048;
|
|
if (a > 1024) a -= 2048;
|
|
|
|
// OSD_Printf("G_GetAngleDelta() returning %d\n",na-a);
|
|
return (na-a);
|
|
}
|
|
|
|
static inline void __fastcall VM_DoConditional(register int32_t condition)
|
|
{
|
|
if (condition)
|
|
{
|
|
// skip 'else' pointer.. and...
|
|
insptr+=2;
|
|
VM_Execute(1);
|
|
return;
|
|
}
|
|
|
|
insptr++;
|
|
insptr += *insptr;
|
|
if (((*insptr)&0xFFF) == CON_ELSE)
|
|
{
|
|
// else...
|
|
// skip 'else' and...
|
|
insptr+=2;
|
|
VM_Execute(1);
|
|
}
|
|
}
|
|
|
|
static int32_t X_DoSortDefault(const int32_t *lv, const int32_t *rv)
|
|
{
|
|
return (*rv - *lv);
|
|
}
|
|
|
|
static int32_t X_DoSort(const int32_t *lv, const int32_t *rv)
|
|
{
|
|
m32_sortvar1 = *lv;
|
|
m32_sortvar2 = *rv;
|
|
insptr = x_sortingstateptr;
|
|
VM_Execute(0);
|
|
return g_iReturnVar;
|
|
}
|
|
|
|
// in interactive execution, allow the current sprite index to be the aimed-at sprite (in 3d mode)
|
|
#define X_ERROR_INVALIDCI() \
|
|
if ((vm.g_i < 0 || vm.g_i>=MAXSPRITES) && \
|
|
(vm.g_st!=0 || searchstat!=3 || (vm.g_i=searchwall, vm.g_sp=&sprite[vm.g_i], 0))) \
|
|
{ \
|
|
M32_ERROR("Current sprite index invalid!"); \
|
|
continue; \
|
|
}
|
|
|
|
#define X_ERROR_INVALIDSPRI(dasprite) \
|
|
if (dasprite < 0 || dasprite>=MAXSPRITES) \
|
|
{ \
|
|
M32_ERROR("Invalid sprite index %d!", dasprite); \
|
|
continue; \
|
|
}
|
|
|
|
#define X_ERROR_INVALIDSECT(dasect) \
|
|
if (dasect < 0 || dasect>=numsectors) \
|
|
{ \
|
|
M32_ERROR("Invalid sector index %d!", dasect); \
|
|
continue; \
|
|
}
|
|
|
|
#define X_ERROR_INVALIDSP() \
|
|
if (!vm.g_sp && (vm.g_st!=0 || searchstat!=3 || (vm.g_sp=&sprite[searchwall], 0))) \
|
|
{ \
|
|
M32_ERROR("Current sprite invalid!"); \
|
|
continue; \
|
|
}
|
|
|
|
#define X_ERROR_INVALIDQUOTE(q, array) \
|
|
if (q<0 || q>=MAXQUOTES) \
|
|
{ \
|
|
M32_ERROR("Invalid quote number %d!", q); \
|
|
continue; \
|
|
} \
|
|
else if (array[q] == NULL) \
|
|
{ \
|
|
M32_ERROR("Null quote %d!", q); \
|
|
continue; \
|
|
} \
|
|
|
|
static char *GetMaybeInlineQuote(int32_t quotei)
|
|
{
|
|
char *quotetext;
|
|
if (quotei==-1)
|
|
{
|
|
quotetext = (char *)insptr;
|
|
while (*insptr++) /* skip the string */;
|
|
}
|
|
else
|
|
{
|
|
quotei = Gv_GetVarX(quotei);
|
|
do { X_ERROR_INVALIDQUOTE(quotei, ScriptQuotes) } while (0);
|
|
if (vm.flags&VMFLAG_ERROR)
|
|
return NULL;
|
|
quotetext = ScriptQuotes[quotei];
|
|
}
|
|
|
|
return quotetext;
|
|
}
|
|
|
|
int32_t VM_Execute(int32_t once)
|
|
{
|
|
register int32_t tw = *insptr;
|
|
|
|
// jump directly into the loop, saving us from the checks during the first iteration
|
|
goto skip_check;
|
|
|
|
while (!once)
|
|
{
|
|
if (vm.flags)
|
|
return 1;
|
|
|
|
tw = *insptr;
|
|
|
|
skip_check:
|
|
// Bsprintf(g_szBuf,"Parsing: %d",*insptr);
|
|
// AddLog(g_szBuf);
|
|
|
|
g_errorLineNum = tw>>12;
|
|
g_tw = (tw &= 0xFFF);
|
|
|
|
switch (tw)
|
|
{
|
|
// *** basic commands
|
|
case CON_NULLOP:
|
|
insptr++;
|
|
continue;
|
|
|
|
case CON_STATE:
|
|
{
|
|
instype *tempscrptr = insptr+2;
|
|
int32_t stateidx = *(insptr+1), o_g_st = vm.g_st, oret=vm.flags&VMFLAG_RETURN;
|
|
void *olocalvars = aGameArrays[M32_LOCAL_ARRAY_ID].vals;
|
|
#ifdef M32_LOCALS_VARARRAY
|
|
int32_t localvars[statesinfo[stateidx].numlocals];
|
|
#elif defined M32_LOCALS_ALLOCA
|
|
int32_t *localvars = alloca(statesinfo[stateidx].numlocals * sizeof(int32_t));
|
|
#else
|
|
int32_t localvars[M32_LOCALS_FIXEDNUM];
|
|
#endif
|
|
|
|
// needed since any read access before initialization would cause undefined behaviour
|
|
if (statesinfo[stateidx].numlocals > 0)
|
|
Bmemset(localvars, 0, statesinfo[stateidx].numlocals*sizeof(int32_t));
|
|
|
|
insptr = script + statesinfo[stateidx].ofs;
|
|
vm.g_st = 1+MAXEVENTS+stateidx;
|
|
aGameArrays[M32_LOCAL_ARRAY_ID].vals = localvars;
|
|
VM_Execute(0);
|
|
aGameArrays[M32_LOCAL_ARRAY_ID].vals = olocalvars;
|
|
vm.g_st = o_g_st;
|
|
vm.flags &= ~VMFLAG_RETURN;
|
|
vm.flags |= oret;
|
|
insptr = tempscrptr;
|
|
}
|
|
continue;
|
|
|
|
case CON_RETURN:
|
|
vm.flags |= VMFLAG_RETURN;
|
|
return 1;
|
|
case CON_BREAK:
|
|
vm.flags |= VMFLAG_BREAK;
|
|
case CON_ENDS:
|
|
return 1;
|
|
|
|
case CON_ELSE:
|
|
insptr++;
|
|
insptr += *insptr;
|
|
continue;
|
|
|
|
case CON_ENDSWITCH:
|
|
vm.flags &= ~VMFLAG_BREAK;
|
|
case CON_ENDEVENT:
|
|
insptr++;
|
|
return 1;
|
|
|
|
case CON_SWITCH:
|
|
insptr++; // p-code
|
|
{
|
|
// command format:
|
|
// variable ID to check
|
|
// script offset to 'end'
|
|
// count of case statements
|
|
// script offset to default case (null if none)
|
|
// For each case: value, ptr to code
|
|
//AddLog("Processing Switch...");
|
|
int32_t lValue=Gv_GetVarX(*insptr++), lEnd=*insptr++, lCases=*insptr++;
|
|
instype *lpDefault=insptr++, *lpCases=insptr, *lCodeInsPtr;
|
|
int32_t bMatched=0, lCheckCase;
|
|
int32_t left,right;
|
|
|
|
insptr += lCases*2;
|
|
lCodeInsPtr = insptr;
|
|
//Bsprintf(g_szBuf,"lEnd= %d *lpDefault=%d",lEnd,*lpDefault); AddLog(g_szBuf);
|
|
//Bsprintf(g_szBuf,"Checking %d cases for %d",lCases, lValue); AddLog(g_szBuf);
|
|
left = 0;
|
|
right = lCases-1;
|
|
while (!bMatched)
|
|
{
|
|
//Bsprintf(g_szBuf,"Checking #%d Value= %d",lCheckCase, lpCases[lCheckCase*2]); AddLog(g_szBuf);
|
|
lCheckCase=(left+right)/2;
|
|
// initprintf("(%2d..%2d..%2d) [%2d..%2d..%2d]==%2d\n",left,lCheckCase,right,lpCases[left*2],lpCases[lCheckCase*2],lpCases[right*2],lValue);
|
|
if (lpCases[lCheckCase*2] > lValue)
|
|
right = lCheckCase-1;
|
|
else if (lpCases[lCheckCase*2] < lValue)
|
|
left = lCheckCase+1;
|
|
else if (lpCases[lCheckCase*2] == lValue)
|
|
{
|
|
//AddLog("Found Case Match");
|
|
//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);
|
|
// fake a 2-d Array
|
|
insptr = lCodeInsPtr + lpCases[lCheckCase*2+1];
|
|
//Bsprintf(g_szBuf,"insptr=%d. ", (int32_t)insptr); AddLog(g_szBuf);
|
|
VM_Execute(0);
|
|
//AddLog("Done Executing Case");
|
|
bMatched=1;
|
|
}
|
|
|
|
if (right-left < 0)
|
|
break;
|
|
}
|
|
|
|
if (!bMatched)
|
|
{
|
|
if (*lpDefault >= 0)
|
|
{
|
|
//AddLog("No Matching Case: Using Default");
|
|
insptr = lCodeInsPtr + *lpDefault;
|
|
VM_Execute(0);
|
|
}
|
|
// else
|
|
// {
|
|
// //AddLog("No Matching Case: No Default to use");
|
|
// }
|
|
}
|
|
insptr = (instype *)(lCodeInsPtr + lEnd);
|
|
vm.flags &= ~VMFLAG_BREAK;
|
|
//Bsprintf(g_szBuf,"insptr=%d. ", (int32_t)insptr); AddLog(g_szBuf);
|
|
//AddLog("Done Processing Switch");
|
|
continue;
|
|
}
|
|
|
|
case CON_GETCURRADDRESS:
|
|
insptr++;
|
|
{
|
|
int32_t j=*insptr++;
|
|
Gv_SetVarX(j, insptr-script);
|
|
}
|
|
continue;
|
|
|
|
case CON_JUMP:
|
|
insptr++;
|
|
{
|
|
int32_t j = Gv_GetVarX(*insptr++);
|
|
if (j<0 || j>=(g_scriptPtr-script))
|
|
{
|
|
M32_ERROR("script index out of bounds (%d)", j);
|
|
continue;
|
|
}
|
|
insptr = (instype *)(j+script);
|
|
}
|
|
continue;
|
|
|
|
case CON_RIGHTBRACE:
|
|
insptr++;
|
|
return 1;
|
|
case CON_LEFTBRACE:
|
|
insptr++;
|
|
VM_Execute(0);
|
|
continue;
|
|
|
|
// *** arrays
|
|
case CON_SETARRAY:
|
|
insptr++;
|
|
{
|
|
int32_t j=*insptr++;
|
|
int32_t index = Gv_GetVarX(*insptr++);
|
|
int32_t value = Gv_GetVarX(*insptr++);
|
|
|
|
if (j<0 || j >= g_gameArrayCount)
|
|
{
|
|
M32_ERROR("Tried to set invalid array ID (%d)", j);
|
|
}
|
|
if (aGameArrays[j].dwFlags & GAMEARRAY_READONLY)
|
|
{
|
|
M32_ERROR("Tried to set on read-only array `%s'", aGameArrays[j].szLabel);
|
|
}
|
|
if (index >= aGameArrays[j].size || index < 0)
|
|
{
|
|
M32_ERROR("Array index %d out of bounds", index);
|
|
}
|
|
if (vm.flags&VMFLAG_ERROR) continue;
|
|
((int32_t *)aGameArrays[j].vals)[index]=value; // REM: other array types not implemented, since they're read-only
|
|
continue;
|
|
}
|
|
|
|
case CON_GETARRAYSIZE:
|
|
insptr++;
|
|
{
|
|
int32_t j=*insptr++;
|
|
Gv_SetVarX(*insptr++, (aGameArrays[j].dwFlags&GAMEARRAY_VARSIZE) ?
|
|
Gv_GetVarN(aGameArrays[j].size) : aGameArrays[j].size);
|
|
}
|
|
continue;
|
|
|
|
case CON_RESIZEARRAY:
|
|
insptr++;
|
|
{
|
|
int32_t j=*insptr++;
|
|
int32_t asize = Gv_GetVarX(*insptr++);
|
|
|
|
if (asize<=0 || asize>65536)
|
|
{
|
|
M32_ERROR("Invalid array size %d (must be between 1 and 65536)", asize);
|
|
continue;
|
|
}
|
|
|
|
// OSD_Printf(OSDTEXT_GREEN "CON_RESIZEARRAY: resizing array %s from %d to %d\n", aGameArrays[j].szLabel, aGameArrays[j].size, asize);
|
|
aGameArrays[j].vals = Brealloc(aGameArrays[j].vals, sizeof(int32_t) * asize);
|
|
if (aGameArrays[j].vals == NULL)
|
|
{
|
|
aGameArrays[j].size = 0;
|
|
M32_ERROR("Out of memory!");
|
|
return 1;
|
|
}
|
|
aGameArrays[j].size = asize;
|
|
|
|
continue;
|
|
}
|
|
|
|
case CON_COPY:
|
|
insptr++;
|
|
{
|
|
int32_t si=*insptr++, ssiz;
|
|
int32_t sidx = Gv_GetVarX(*insptr++); //, vm.g_i, vm.g_p);
|
|
int32_t di=*insptr++, dsiz;
|
|
int32_t didx = Gv_GetVarX(*insptr++);
|
|
int32_t numelts = Gv_GetVarX(*insptr++);
|
|
|
|
if (si<0 || si>=g_gameArrayCount)
|
|
{
|
|
M32_ERROR("Invalid array %d!", si);
|
|
}
|
|
if (di<0 || di>=g_gameArrayCount)
|
|
{
|
|
M32_ERROR("Invalid array %d!", di);
|
|
}
|
|
if (aGameArrays[di].dwFlags & GAMEARRAY_READONLY)
|
|
{
|
|
M32_ERROR("Array %d is read-only!", di);
|
|
}
|
|
if (vm.flags&VMFLAG_ERROR) continue;
|
|
|
|
ssiz = (aGameArrays[si].dwFlags&GAMEARRAY_VARSIZE) ?
|
|
Gv_GetVarN(aGameArrays[si].size) : aGameArrays[si].size;
|
|
dsiz = (aGameArrays[di].dwFlags&GAMEARRAY_VARSIZE) ?
|
|
Gv_GetVarN(aGameArrays[si].size) : aGameArrays[di].size;
|
|
|
|
if (sidx > ssiz || didx > dsiz) continue;
|
|
if ((sidx+numelts) > ssiz) numelts = ssiz-sidx;
|
|
if ((didx+numelts) > dsiz) numelts = dsiz-didx;
|
|
|
|
switch (aGameArrays[si].dwFlags & GAMEARRAY_TYPE_MASK)
|
|
{
|
|
case 0:
|
|
case GAMEARRAY_OFINT:
|
|
Bmemcpy((int32_t *)aGameArrays[di].vals + didx, (int32_t *)aGameArrays[si].vals + sidx, numelts * sizeof(int32_t));
|
|
break;
|
|
case GAMEARRAY_OFSHORT:
|
|
for (; numelts>0; numelts--)
|
|
((int32_t *)aGameArrays[di].vals)[didx++] = ((int16_t *)aGameArrays[si].vals)[sidx++];
|
|
break;
|
|
case GAMEARRAY_OFCHAR:
|
|
for (; numelts>0; numelts--)
|
|
((int32_t *)aGameArrays[di].vals)[didx++] = ((uint8_t *)aGameArrays[si].vals)[sidx++];
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// *** var & varvar ops
|
|
case CON_RANDVAR:
|
|
insptr++;
|
|
Gv_SetVarX(*insptr, mulscale16(krand(), *(insptr+1)+1));
|
|
insptr += 2;
|
|
continue;
|
|
|
|
case CON_DISPLAYRANDVAR:
|
|
insptr++;
|
|
Gv_SetVarX(*insptr, mulscale15((uint16_t)rand(), *(insptr+1)+1));
|
|
insptr += 2;
|
|
continue;
|
|
|
|
case CON_SETVAR:
|
|
insptr++;
|
|
Gv_SetVarX(*insptr, *(insptr+1));
|
|
insptr += 2;
|
|
continue;
|
|
|
|
case CON_SETVARVAR:
|
|
insptr++;
|
|
{
|
|
int32_t j=*insptr++;
|
|
Gv_SetVarX(j, Gv_GetVarX(*insptr++));
|
|
}
|
|
continue;
|
|
|
|
case CON_MULVAR:
|
|
insptr++;
|
|
Gv_SetVarX(*insptr, Gv_GetVarX(*insptr) * *(insptr+1));
|
|
insptr += 2;
|
|
continue;
|
|
|
|
case CON_DIVVAR:
|
|
insptr++;
|
|
if (*(insptr+1) == 0)
|
|
{
|
|
M32_ERROR("Divide by zero.");
|
|
insptr += 2;
|
|
continue;
|
|
}
|
|
Gv_SetVarX(*insptr, Gv_GetVarX(*insptr) / *(insptr+1));
|
|
insptr += 2;
|
|
continue;
|
|
|
|
case CON_MODVAR:
|
|
insptr++;
|
|
if (*(insptr+1) == 0)
|
|
{
|
|
M32_ERROR("Mod by zero.");
|
|
insptr += 2;
|
|
continue;
|
|
}
|
|
Gv_SetVarX(*insptr,Gv_GetVarX(*insptr)%*(insptr+1));
|
|
insptr += 2;
|
|
continue;
|
|
|
|
case CON_ANDVAR:
|
|
insptr++;
|
|
Gv_SetVarX(*insptr,Gv_GetVarX(*insptr) & *(insptr+1));
|
|
insptr += 2;
|
|
continue;
|
|
|
|
case CON_ORVAR:
|
|
insptr++;
|
|
Gv_SetVarX(*insptr,Gv_GetVarX(*insptr) | *(insptr+1));
|
|
insptr += 2;
|
|
continue;
|
|
|
|
case CON_XORVAR:
|
|
insptr++;
|
|
Gv_SetVarX(*insptr,Gv_GetVarX(*insptr) ^ *(insptr+1));
|
|
insptr += 2;
|
|
continue;
|
|
|
|
case CON_RANDVARVAR:
|
|
insptr++;
|
|
{
|
|
int32_t j=*insptr++;
|
|
Gv_SetVarX(j,mulscale(krand(), Gv_GetVarX(*insptr++)+1, 16));
|
|
}
|
|
continue;
|
|
|
|
case CON_DISPLAYRANDVARVAR:
|
|
insptr++;
|
|
{
|
|
int32_t j=*insptr++;
|
|
Gv_SetVarX(j,mulscale((uint16_t)rand(), Gv_GetVarX(*insptr++)+1, 15));
|
|
}
|
|
continue;
|
|
|
|
case CON_MULVARVAR:
|
|
insptr++;
|
|
{
|
|
int32_t j=*insptr++;
|
|
Gv_SetVarX(j, Gv_GetVarX(j)*Gv_GetVarX(*insptr++));
|
|
}
|
|
continue;
|
|
|
|
case CON_DIVVARVAR:
|
|
insptr++;
|
|
{
|
|
int32_t j=*insptr++;
|
|
int32_t l2=Gv_GetVarX(*insptr++);
|
|
|
|
if (l2==0)
|
|
{
|
|
M32_ERROR("Divide by zero.");
|
|
continue;
|
|
}
|
|
Gv_SetVarX(j, Gv_GetVarX(j)/l2);
|
|
continue;
|
|
}
|
|
|
|
case CON_MODVARVAR:
|
|
insptr++;
|
|
{
|
|
int32_t j=*insptr++;
|
|
int32_t l2=Gv_GetVarX(*insptr++);
|
|
|
|
if (l2==0)
|
|
{
|
|
M32_ERROR("Mod by zero.");
|
|
continue;
|
|
}
|
|
|
|
Gv_SetVarX(j, Gv_GetVarX(j) % l2);
|
|
continue;
|
|
}
|
|
|
|
case CON_ANDVARVAR:
|
|
insptr++;
|
|
{
|
|
int32_t j=*insptr++;
|
|
Gv_SetVarX(j, Gv_GetVarX(j) & Gv_GetVarX(*insptr++));
|
|
}
|
|
continue;
|
|
|
|
case CON_XORVARVAR:
|
|
insptr++;
|
|
{
|
|
int32_t j=*insptr++;
|
|
Gv_SetVarX(j, Gv_GetVarX(j) ^ Gv_GetVarX(*insptr++));
|
|
}
|
|
continue;
|
|
|
|
case CON_ORVARVAR:
|
|
insptr++;
|
|
{
|
|
int32_t j=*insptr++;
|
|
Gv_SetVarX(j, Gv_GetVarX(j) | Gv_GetVarX(*insptr++));
|
|
}
|
|
continue;
|
|
|
|
case CON_SUBVAR:
|
|
insptr++;
|
|
Gv_SetVarX(*insptr, Gv_GetVarX(*insptr) - *(insptr+1));
|
|
insptr += 2;
|
|
continue;
|
|
|
|
case CON_SUBVARVAR:
|
|
insptr++;
|
|
{
|
|
int32_t j=*insptr++;
|
|
Gv_SetVarX(j, Gv_GetVarX(j) - Gv_GetVarX(*insptr++));
|
|
}
|
|
continue;
|
|
|
|
case CON_ADDVAR:
|
|
insptr++;
|
|
Gv_SetVarX(*insptr, Gv_GetVarX(*insptr) + *(insptr+1));
|
|
insptr += 2;
|
|
continue;
|
|
|
|
case CON_ADDVARVAR:
|
|
insptr++;
|
|
{
|
|
int32_t j=*insptr++;
|
|
Gv_SetVarX(j, Gv_GetVarX(j) + Gv_GetVarX(*insptr++));
|
|
}
|
|
continue;
|
|
|
|
case CON_SHIFTVARL:
|
|
insptr++;
|
|
Gv_SetVarX(*insptr, Gv_GetVarX(*insptr) << *(insptr+1));
|
|
insptr += 2;
|
|
continue;
|
|
|
|
case CON_SHIFTVARVARL:
|
|
insptr++;
|
|
{
|
|
int32_t j=*insptr++;
|
|
Gv_SetVarX(j, Gv_GetVarX(j) << Gv_GetVarX(*insptr++));
|
|
}
|
|
continue;
|
|
|
|
case CON_SHIFTVARR:
|
|
insptr++;
|
|
Gv_SetVarX(*insptr, Gv_GetVarX(*insptr) >> *(insptr+1));
|
|
insptr += 2;
|
|
continue;
|
|
|
|
case CON_SHIFTVARVARR:
|
|
insptr++;
|
|
{
|
|
int32_t j=*insptr++;
|
|
Gv_SetVarX(j, Gv_GetVarX(j) >> Gv_GetVarX(*insptr++));
|
|
}
|
|
continue;
|
|
|
|
case CON_SIN:
|
|
insptr++;
|
|
Gv_SetVarX(*insptr, sintable[Gv_GetVarX(*(insptr+1))&2047]);
|
|
insptr += 2;
|
|
continue;
|
|
|
|
case CON_COS:
|
|
insptr++;
|
|
Gv_SetVarX(*insptr, sintable[(Gv_GetVarX(*(insptr+1))+512)&2047]);
|
|
insptr += 2;
|
|
continue;
|
|
|
|
case CON_DISPLAYRAND:
|
|
insptr++;
|
|
Gv_SetVarX(*insptr++, rand());
|
|
continue;
|
|
|
|
// *** other math
|
|
case CON_FTOI:
|
|
insptr++;
|
|
{
|
|
int32_t bits=Gv_GetVarX(*insptr), scale=*(insptr+1);
|
|
float fval = *((float *)&bits);
|
|
// rounding must absolutely be!
|
|
//OSD_Printf("ftoi: bits:%8x, scale=%d, fval=%f, (int32_t)(fval*scale)=%d\n", bits, scale, fval, (int32_t)(fval*scale));
|
|
Gv_SetVarX(*insptr, (int32_t)nearbyintf(fval * scale));
|
|
}
|
|
insptr += 2;
|
|
continue;
|
|
|
|
case CON_ITOF:
|
|
insptr++;
|
|
{
|
|
int32_t scaled=Gv_GetVarX(*insptr), scale=*(insptr+1);
|
|
float fval = (float)scaled/(float)scale;
|
|
Gv_SetVarX(*insptr, *((int32_t *)&fval));
|
|
}
|
|
insptr += 2;
|
|
continue;
|
|
|
|
case CON_CLAMP:
|
|
insptr++;
|
|
{
|
|
int32_t var=*insptr++, min=Gv_GetVarX(*insptr++), max=Gv_GetVarX(*insptr++);
|
|
int32_t val=Gv_GetVarX(var);
|
|
|
|
if (val<min) Gv_SetVarX(var, min);
|
|
else if (val>max) Gv_SetVarX(var, max);
|
|
}
|
|
continue;
|
|
|
|
case CON_INV:
|
|
Gv_SetVarX(*(insptr+1), -Gv_GetVarX(*(insptr+1)));
|
|
insptr += 2;
|
|
continue;
|
|
|
|
case CON_SQRT:
|
|
insptr++;
|
|
{
|
|
// syntax sqrt <invar> <outvar>
|
|
int32_t lInVarID=*insptr++, lOutVarID=*insptr++;
|
|
|
|
Gv_SetVarX(lOutVarID, ksqrt(Gv_GetVarX(lInVarID)));
|
|
continue;
|
|
}
|
|
|
|
case CON_LDIST:
|
|
case CON_DIST:
|
|
insptr++;
|
|
{
|
|
int32_t distvar = *insptr++, xvar = Gv_GetVarX(*insptr++), yvar = Gv_GetVarX(*insptr++);
|
|
|
|
if (xvar < 0 || xvar >= MAXSPRITES || sprite[xvar].statnum==MAXSTATUS)
|
|
{
|
|
M32_ERROR("invalid sprite %d", xvar);
|
|
}
|
|
if (yvar < 0 || yvar >= MAXSPRITES || sprite[yvar].statnum==MAXSTATUS)
|
|
{
|
|
M32_ERROR("invalid sprite %d", yvar);
|
|
}
|
|
if (vm.flags&VMFLAG_ERROR) continue;
|
|
|
|
if (tw==CON_DIST)
|
|
Gv_SetVarX(distvar, dist(&sprite[xvar],&sprite[yvar]));
|
|
else
|
|
Gv_SetVarX(distvar, ldist(&sprite[xvar],&sprite[yvar]));
|
|
continue;
|
|
}
|
|
|
|
case CON_GETANGLE:
|
|
insptr++;
|
|
{
|
|
int32_t angvar = *insptr++;
|
|
int32_t xvar = Gv_GetVarX(*insptr++);
|
|
int32_t yvar = Gv_GetVarX(*insptr++);
|
|
|
|
Gv_SetVarX(angvar, getangle(xvar,yvar));
|
|
continue;
|
|
}
|
|
|
|
case CON_GETINCANGLE:
|
|
insptr++;
|
|
{
|
|
int32_t angvar = *insptr++;
|
|
int32_t xvar = Gv_GetVarX(*insptr++);
|
|
int32_t yvar = Gv_GetVarX(*insptr++);
|
|
|
|
Gv_SetVarX(angvar, G_GetAngleDelta(xvar,yvar));
|
|
continue;
|
|
}
|
|
|
|
case CON_A2XY:
|
|
case CON_AH2XYZ:
|
|
insptr++;
|
|
{
|
|
int32_t ang=Gv_GetVarX(*insptr++), horiz=(tw==CON_A2XY)?100:Gv_GetVarX(*insptr++);
|
|
int32_t xvar=*insptr++, yvar=*insptr++;
|
|
|
|
int32_t x = sintable[(ang+512)&2047];
|
|
int32_t y = sintable[ang&2047];
|
|
|
|
if (tw==CON_AH2XYZ)
|
|
{
|
|
int32_t zvar=*insptr++, z=0;
|
|
|
|
horiz -= 100;
|
|
if (horiz)
|
|
{
|
|
int32_t veclen = ksqrt(200*200 + horiz*horiz);
|
|
int32_t dacos = divscale14(200, veclen);
|
|
|
|
x = mulscale14(x, dacos);
|
|
y = mulscale14(y, dacos);
|
|
z = divscale14(-horiz, veclen);
|
|
}
|
|
|
|
Gv_SetVarX(zvar, z);
|
|
}
|
|
|
|
Gv_SetVarX(xvar, x);
|
|
Gv_SetVarX(yvar, y);
|
|
|
|
continue;
|
|
}
|
|
|
|
case CON_MULSCALE:
|
|
insptr++;
|
|
{
|
|
int32_t var1 = *insptr++, var2 = Gv_GetVarX(*insptr++);
|
|
int32_t var3 = Gv_GetVarX(*insptr++), var4 = Gv_GetVarX(*insptr++);
|
|
|
|
Gv_SetVarX(var1, mulscale(var2, var3, var4));
|
|
continue;
|
|
}
|
|
case CON_DIVSCALE:
|
|
insptr++;
|
|
{
|
|
int32_t var1 = *insptr++, var2 = Gv_GetVarX(*insptr++);
|
|
int32_t var3 = Gv_GetVarX(*insptr++), var4 = Gv_GetVarX(*insptr++);
|
|
|
|
Gv_SetVarX(var1, divscale(var2, var3, var4));
|
|
continue;
|
|
}
|
|
|
|
// *** if & while
|
|
case CON_IFVARVARAND:
|
|
insptr++;
|
|
{
|
|
int32_t j = Gv_GetVarX(*insptr++);
|
|
j &= Gv_GetVarX(*insptr++);
|
|
insptr--;
|
|
VM_DoConditional(j);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFVARVAROR:
|
|
insptr++;
|
|
{
|
|
int32_t j = Gv_GetVarX(*insptr++);
|
|
j |= Gv_GetVarX(*insptr++);
|
|
insptr--;
|
|
VM_DoConditional(j);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFVARVARXOR:
|
|
insptr++;
|
|
{
|
|
int32_t j = Gv_GetVarX(*insptr++);
|
|
j ^= Gv_GetVarX(*insptr++);
|
|
insptr--;
|
|
VM_DoConditional(j);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFVARVAREITHER:
|
|
insptr++;
|
|
{
|
|
int32_t j = Gv_GetVarX(*insptr++);
|
|
int32_t l = Gv_GetVarX(*insptr++);
|
|
insptr--;
|
|
VM_DoConditional(j || l);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFVARVARBOTH:
|
|
insptr++;
|
|
{
|
|
int32_t j = Gv_GetVarX(*insptr++);
|
|
int32_t l = Gv_GetVarX(*insptr++);
|
|
insptr--;
|
|
VM_DoConditional(j && l);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFVARVARN:
|
|
insptr++;
|
|
{
|
|
int32_t j = Gv_GetVarX(*insptr++);
|
|
j = (j != Gv_GetVarX(*insptr++));
|
|
insptr--;
|
|
VM_DoConditional(j);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFVARVARE:
|
|
insptr++;
|
|
{
|
|
int32_t j = Gv_GetVarX(*insptr++);
|
|
j = (j == Gv_GetVarX(*insptr++));
|
|
insptr--;
|
|
VM_DoConditional(j);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFVARVARG:
|
|
insptr++;
|
|
{
|
|
int32_t j = Gv_GetVarX(*insptr++);
|
|
j = (j > Gv_GetVarX(*insptr++));
|
|
insptr--;
|
|
VM_DoConditional(j);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFVARVARGE:
|
|
insptr++;
|
|
{
|
|
int32_t j = Gv_GetVarX(*insptr++);
|
|
j = (j >= Gv_GetVarX(*insptr++));
|
|
insptr--;
|
|
VM_DoConditional(j);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFVARVARL:
|
|
insptr++;
|
|
{
|
|
int32_t j = Gv_GetVarX(*insptr++);
|
|
j = (j < Gv_GetVarX(*insptr++));
|
|
insptr--;
|
|
VM_DoConditional(j);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFVARVARLE:
|
|
insptr++;
|
|
{
|
|
int32_t j = Gv_GetVarX(*insptr++);
|
|
j = (j <= Gv_GetVarX(*insptr++));
|
|
insptr--;
|
|
VM_DoConditional(j);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFVARE:
|
|
insptr++;
|
|
{
|
|
int32_t j=Gv_GetVarX(*insptr++);
|
|
VM_DoConditional(j == *insptr);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFVARN:
|
|
insptr++;
|
|
{
|
|
int32_t j=Gv_GetVarX(*insptr++);
|
|
VM_DoConditional(j != *insptr);
|
|
}
|
|
continue;
|
|
|
|
case CON_WHILEVARN:
|
|
{
|
|
instype *savedinsptr=insptr+2;
|
|
int32_t j;
|
|
do
|
|
{
|
|
insptr=savedinsptr;
|
|
j = (Gv_GetVarX(*(insptr-1)) != *insptr);
|
|
VM_DoConditional(j);
|
|
}
|
|
while (j && !vm.flags);
|
|
vm.flags &= ~VMFLAG_BREAK;
|
|
continue;
|
|
}
|
|
|
|
case CON_WHILEVARL:
|
|
{
|
|
instype *savedinsptr=insptr+2;
|
|
int32_t j;
|
|
do
|
|
{
|
|
insptr=savedinsptr;
|
|
j = (Gv_GetVarX(*(insptr-1)) < *insptr);
|
|
VM_DoConditional(j);
|
|
}
|
|
while (j && !vm.flags);
|
|
vm.flags &= ~VMFLAG_BREAK;
|
|
continue;
|
|
}
|
|
|
|
case CON_WHILEVARVARN:
|
|
{
|
|
int32_t j;
|
|
instype *savedinsptr=insptr+2;
|
|
do
|
|
{
|
|
insptr=savedinsptr;
|
|
j = Gv_GetVarX(*(insptr-1));
|
|
j = (j != Gv_GetVarX(*insptr++));
|
|
insptr--;
|
|
VM_DoConditional(j);
|
|
}
|
|
while (j && !vm.flags);
|
|
vm.flags &= ~VMFLAG_BREAK;
|
|
continue;
|
|
}
|
|
|
|
case CON_WHILEVARVARL:
|
|
{
|
|
int32_t j;
|
|
instype *savedinsptr=insptr+2;
|
|
do
|
|
{
|
|
insptr=savedinsptr;
|
|
j = Gv_GetVarX(*(insptr-1));
|
|
j = (j < Gv_GetVarX(*insptr++));
|
|
insptr--;
|
|
VM_DoConditional(j);
|
|
}
|
|
while (j && !vm.flags);
|
|
vm.flags &= ~VMFLAG_BREAK;
|
|
continue;
|
|
}
|
|
|
|
case CON_COLLECTSECTORS:
|
|
insptr++;
|
|
{
|
|
int32_t aridx=*insptr++, startsectnum=Gv_GetVarX(*insptr++);
|
|
int32_t numsectsVar=*insptr++, state=*insptr++;
|
|
|
|
int32_t o_g_st=vm.g_st, arsize = aGameArrays[aridx].size;
|
|
instype *end=insptr;
|
|
int32_t sectcnt, numsects=0;
|
|
int16_t *sectlist = aGameArrays[aridx].vals; // actually an int32_t array
|
|
int32_t *sectlist32 = (int32_t *)sectlist;
|
|
int32_t j, startwall, endwall, ns;
|
|
static uint8_t sectbitmap[MAXSECTORS>>3];
|
|
|
|
X_ERROR_INVALIDSECT(startsectnum);
|
|
if (arsize < numsectors)
|
|
{
|
|
M32_ERROR("Array size must be at least numsectors (=%d) for collecting!",
|
|
numsectors);
|
|
continue;
|
|
}
|
|
|
|
// collect!
|
|
bfirst_search_init(sectlist, sectbitmap, &numsects, MAXSECTORS, startsectnum);
|
|
|
|
for (sectcnt=0; sectcnt<numsects; sectcnt++)
|
|
for (WALLS_OF_SECTOR(sectlist[sectcnt], j))
|
|
if ((ns=wall[j].nextsector) >= 0 && wall[j].nextsector<numsectors)
|
|
{
|
|
if (sectbitmap[ns>>3]&(1<<(ns&7)))
|
|
continue;
|
|
vm.g_st = 1+MAXEVENTS+state;
|
|
insptr = script + statesinfo[state].ofs;
|
|
g_iReturnVar = ns;
|
|
VM_Execute(0);
|
|
if (g_iReturnVar)
|
|
bfirst_search_try(sectlist, sectbitmap, &numsects, wall[j].nextsector);
|
|
}
|
|
|
|
// short->int sector list
|
|
for (j=numsects-1; j>=0; j--)
|
|
sectlist32[j] = sectlist[j];
|
|
|
|
Gv_SetVarX(numsectsVar, numsects);
|
|
g_iReturnVar = 0;
|
|
|
|
// restore some VM state
|
|
vm.g_st = o_g_st;
|
|
insptr = end;
|
|
}
|
|
continue;
|
|
|
|
case CON_SORT:
|
|
insptr++;
|
|
{
|
|
int32_t aridx=*insptr++, count=Gv_GetVarX(*insptr++), state=*insptr++;
|
|
int32_t o_g_st=vm.g_st;
|
|
instype *end=insptr;
|
|
|
|
if (count<=0) continue;
|
|
if (count > aGameArrays[aridx].size)
|
|
{
|
|
M32_ERROR("Count of elements to sort (%d) exceeds array size (%d)!", count,aGameArrays[aridx].size);
|
|
continue;
|
|
}
|
|
|
|
if (state < 0)
|
|
{
|
|
qsort(aGameArrays[aridx].vals, count, sizeof(int32_t), (int32_t(*)(const void *,const void *))X_DoSortDefault);
|
|
}
|
|
else
|
|
{
|
|
x_sortingstateptr = script + statesinfo[state].ofs;
|
|
vm.g_st = 1+MAXEVENTS+state;
|
|
qsort(aGameArrays[aridx].vals, count, sizeof(int32_t), (int32_t(*)(const void *,const void *))X_DoSort);
|
|
vm.g_st = o_g_st;
|
|
insptr = end;
|
|
}
|
|
}
|
|
continue;
|
|
|
|
case CON_FOR: // special-purpose iteration
|
|
insptr++;
|
|
{
|
|
int32_t var = *insptr++, how=*insptr++, ii, jj;
|
|
int32_t parm2 = how<=ITER_DRAWNSPRITES ? 0 : Gv_GetVarX(*insptr++);
|
|
instype *end = insptr + *insptr, *beg = ++insptr;
|
|
int32_t vm_i_bak = vm.g_i;
|
|
spritetype *vm_sp_bak = vm.g_sp;
|
|
int16_t endwall;
|
|
|
|
if (vm.flags&VMFLAG_ERROR) continue;
|
|
|
|
switch (how)
|
|
{
|
|
case ITER_ALLSPRITES:
|
|
for (jj=0; jj<MAXSPRITES && !vm.flags; jj++)
|
|
{
|
|
if (sprite[jj].statnum == MAXSTATUS)
|
|
continue;
|
|
Gv_SetVarX(var, jj);
|
|
vm.g_i = jj;
|
|
vm.g_sp = &sprite[jj];
|
|
insptr = beg;
|
|
VM_Execute(1);
|
|
}
|
|
break;
|
|
case ITER_ALLSECTORS:
|
|
for (jj=0; jj<numsectors && !vm.flags; jj++)
|
|
{
|
|
Gv_SetVarX(var, jj);
|
|
insptr = beg;
|
|
VM_Execute(1);
|
|
}
|
|
break;
|
|
case ITER_ALLWALLS:
|
|
for (jj=0; jj<numwalls && !vm.flags; jj++)
|
|
{
|
|
Gv_SetVarX(var, jj);
|
|
insptr = beg;
|
|
VM_Execute(1);
|
|
}
|
|
break;
|
|
case ITER_ACTIVELIGHTS:
|
|
#ifdef POLYMER
|
|
for (jj=0; jj<PR_MAXLIGHTS; jj++)
|
|
{
|
|
if (!prlights[jj].flags.active)
|
|
continue;
|
|
|
|
Gv_SetVarX(var, jj);
|
|
insptr = beg;
|
|
VM_Execute(1);
|
|
}
|
|
#else
|
|
M32_ERROR("Polymer not compiled in, iteration over lights forbidden.");
|
|
#endif
|
|
break;
|
|
|
|
case ITER_SELSPRITES:
|
|
for (ii=0; ii<highlightcnt && !vm.flags; ii++)
|
|
{
|
|
jj = highlight[ii];
|
|
if (jj&0xc000)
|
|
{
|
|
jj &= (MAXSPRITES-1);
|
|
Gv_SetVarX(var, jj);
|
|
vm.g_i = jj;
|
|
vm.g_sp = &sprite[jj];
|
|
insptr = beg;
|
|
VM_Execute(1);
|
|
}
|
|
}
|
|
break;
|
|
case ITER_SELSECTORS:
|
|
for (ii=0; ii<highlightsectorcnt && !vm.flags; ii++)
|
|
{
|
|
jj=highlightsector[ii];
|
|
Gv_SetVarX(var, jj);
|
|
insptr = beg;
|
|
VM_Execute(1);
|
|
}
|
|
break;
|
|
case ITER_SELWALLS:
|
|
for (ii=0; ii<highlightcnt && !vm.flags; ii++)
|
|
{
|
|
jj=highlight[ii];
|
|
if (jj&0xc000)
|
|
continue;
|
|
Gv_SetVarX(var, jj);
|
|
insptr = beg;
|
|
VM_Execute(1);
|
|
}
|
|
break;
|
|
case ITER_DRAWNSPRITES:
|
|
for (ii=0; ii<spritesortcnt && !vm.flags; ii++)
|
|
{
|
|
vm.g_sp = &tsprite[ii];
|
|
Gv_SetVarX(var, ii);
|
|
insptr = beg;
|
|
VM_Execute(1);
|
|
}
|
|
break;
|
|
case ITER_SPRITESOFSECTOR:
|
|
if (parm2 < 0 || parm2 >= MAXSECTORS)
|
|
goto badindex;
|
|
for (jj=headspritesect[parm2]; jj>=0 && !vm.flags; jj=nextspritesect[jj])
|
|
{
|
|
Gv_SetVarX(var, jj);
|
|
vm.g_i = jj;
|
|
vm.g_sp = &sprite[jj];
|
|
insptr = beg;
|
|
VM_Execute(1);
|
|
}
|
|
break;
|
|
case ITER_WALLSOFSECTOR:
|
|
if (parm2 < 0 || parm2 >= MAXSECTORS)
|
|
goto badindex;
|
|
for (jj=sector[parm2].wallptr, endwall=jj+sector[parm2].wallnum-1;
|
|
jj<=endwall && !vm.flags; jj++)
|
|
{
|
|
Gv_SetVarX(var, jj);
|
|
insptr = beg;
|
|
VM_Execute(1);
|
|
}
|
|
break;
|
|
case ITER_LOOPOFWALL:
|
|
if (parm2 < 0 || parm2 >= numwalls)
|
|
goto badindex;
|
|
jj = parm2;
|
|
do
|
|
{
|
|
Gv_SetVarX(var, jj);
|
|
insptr = beg;
|
|
VM_Execute(1);
|
|
jj = wall[jj].point2;
|
|
}
|
|
while (jj != parm2 && !vm.flags);
|
|
break;
|
|
case ITER_RANGE:
|
|
for (jj=0; jj<parm2 && !vm.flags; jj++)
|
|
{
|
|
Gv_SetVarX(var, jj);
|
|
insptr = beg;
|
|
VM_Execute(1);
|
|
}
|
|
break;
|
|
default:
|
|
M32_ERROR("Unknown iteration type %d!", how);
|
|
continue;
|
|
badindex:
|
|
OSD_Printf(OSD_ERROR "Line %d, %s %s: index %d out of range!\n",g_errorLineNum,keyw[g_tw],
|
|
iter_tokens[how].token, parm2);
|
|
vm.flags |= VMFLAG_ERROR;
|
|
continue;
|
|
}
|
|
vm.g_i = vm_i_bak;
|
|
vm.g_sp = vm_sp_bak;
|
|
vm.flags &= ~VMFLAG_BREAK;
|
|
insptr = end;
|
|
}
|
|
continue;
|
|
|
|
case CON_IFVARAND:
|
|
insptr++;
|
|
{
|
|
int32_t j=Gv_GetVarX(*insptr++);
|
|
VM_DoConditional(j & *insptr);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFVAROR:
|
|
insptr++;
|
|
{
|
|
int32_t j=Gv_GetVarX(*insptr++);
|
|
VM_DoConditional(j | *insptr);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFVARXOR:
|
|
insptr++;
|
|
{
|
|
int32_t j=Gv_GetVarX(*insptr++);
|
|
VM_DoConditional(j ^ *insptr);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFVAREITHER:
|
|
insptr++;
|
|
{
|
|
int32_t j=Gv_GetVarX(*insptr++);
|
|
VM_DoConditional(j || *insptr);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFVARBOTH:
|
|
insptr++;
|
|
{
|
|
int32_t j=Gv_GetVarX(*insptr++);
|
|
VM_DoConditional(j && *insptr);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFVARG:
|
|
insptr++;
|
|
{
|
|
int32_t j=Gv_GetVarX(*insptr++);
|
|
VM_DoConditional(j > *insptr);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFVARGE:
|
|
insptr++;
|
|
{
|
|
int32_t j=Gv_GetVarX(*insptr++);
|
|
VM_DoConditional(j >= *insptr);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFVARL:
|
|
insptr++;
|
|
{
|
|
int32_t j=Gv_GetVarX(*insptr++);
|
|
VM_DoConditional(j < *insptr);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFVARLE:
|
|
insptr++;
|
|
{
|
|
int32_t j=Gv_GetVarX(*insptr++);
|
|
VM_DoConditional(j <= *insptr);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFRND:
|
|
VM_DoConditional(rnd(Gv_GetVarX(*(++insptr))));
|
|
continue;
|
|
|
|
case CON_IFHITKEY:
|
|
case CON_IFHOLDKEY:
|
|
case CON_RESETKEY:
|
|
insptr++;
|
|
{
|
|
int32_t key=Gv_GetVarX(*insptr);
|
|
if (key<0 || key >= (int32_t)(sizeof(keystatus)/sizeof(keystatus[0])))
|
|
{
|
|
M32_ERROR("Invalid key %d!", key);
|
|
continue;
|
|
}
|
|
|
|
if (tw != CON_RESETKEY)
|
|
VM_DoConditional(keystatus[key]);
|
|
else
|
|
insptr++;
|
|
|
|
if (tw != CON_IFHOLDKEY)
|
|
{
|
|
if (!(key==0 || key==KEYSC_ESC || key==KEYSC_TILDE || key==KEYSC_gENTER ||
|
|
key==KEYSC_LALT || key==KEYSC_RALT || key==KEYSC_LCTRL || key==KEYSC_RCTRL ||
|
|
key==KEYSC_LSHIFT || key==KEYSC_RSHIFT))
|
|
keystatus[key] = 0;
|
|
}
|
|
}
|
|
continue;
|
|
|
|
case CON_IFEITHERALT:
|
|
VM_DoConditional(keystatus[KEYSC_LALT]||keystatus[KEYSC_RALT]);
|
|
continue;
|
|
|
|
case CON_IFEITHERCTRL:
|
|
VM_DoConditional(keystatus[KEYSC_LCTRL]||keystatus[KEYSC_RCTRL]);
|
|
continue;
|
|
|
|
case CON_IFEITHERSHIFT:
|
|
VM_DoConditional(keystatus[KEYSC_LSHIFT]||keystatus[KEYSC_RSHIFT]);
|
|
continue;
|
|
|
|
// vvv CURSPR
|
|
case CON_IFSPRITEPAL:
|
|
insptr++;
|
|
X_ERROR_INVALIDSP();
|
|
VM_DoConditional(vm.g_sp->pal == Gv_GetVarX(*insptr));
|
|
continue;
|
|
|
|
case CON_IFHIGHLIGHTED:
|
|
insptr++;
|
|
{
|
|
int32_t id=*insptr++, index=Gv_GetVarX(*insptr);
|
|
|
|
if (index<0 || (id==M32_SPRITE_VAR_ID && index>=MAXSPRITES) || (id==M32_WALL_VAR_ID && index>=numwalls))
|
|
{
|
|
M32_ERROR("%s index %d out of range!", id==M32_SPRITE_VAR_ID?"Sprite":"Wall", index);
|
|
continue;
|
|
}
|
|
|
|
if (id==M32_SPRITE_VAR_ID)
|
|
VM_DoConditional(show2dsprite[index>>3]&(1<<(index&7)));
|
|
else
|
|
VM_DoConditional(show2dwall[index>>3]&(1<<(index&7)));
|
|
}
|
|
continue;
|
|
|
|
case CON_IFANGDIFFL:
|
|
insptr++;
|
|
{
|
|
int32_t j;
|
|
X_ERROR_INVALIDSP();
|
|
j = klabs(G_GetAngleDelta(ang, vm.g_sp->ang));
|
|
VM_DoConditional(j <= Gv_GetVarX(*insptr));
|
|
}
|
|
continue;
|
|
|
|
case CON_IFAWAYFROMWALL:
|
|
{
|
|
int16_t s1;
|
|
int32_t j = 0;
|
|
|
|
X_ERROR_INVALIDSP();
|
|
s1 = vm.g_sp->sectnum;
|
|
updatesector(vm.g_sp->x+108,vm.g_sp->y+108,&s1);
|
|
if (s1 == vm.g_sp->sectnum)
|
|
{
|
|
updatesector(vm.g_sp->x-108,vm.g_sp->y-108,&s1);
|
|
if (s1 == vm.g_sp->sectnum)
|
|
{
|
|
updatesector(vm.g_sp->x+108,vm.g_sp->y-108,&s1);
|
|
if (s1 == vm.g_sp->sectnum)
|
|
{
|
|
updatesector(vm.g_sp->x-108,vm.g_sp->y+108,&s1);
|
|
if (s1 == vm.g_sp->sectnum)
|
|
j = 1;
|
|
}
|
|
}
|
|
}
|
|
VM_DoConditional(j);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFCANSEE:
|
|
{
|
|
int32_t j;
|
|
|
|
X_ERROR_INVALIDSP();
|
|
j = cansee(vm.g_sp->x,vm.g_sp->y,vm.g_sp->z/*-((krand()&41)<<8)*/,vm.g_sp->sectnum,
|
|
pos.x, pos.y, pos.z /*-((krand()&41)<<8)*/, cursectnum);
|
|
VM_DoConditional(j);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFONWATER:
|
|
X_ERROR_INVALIDSP();
|
|
VM_DoConditional(sector[vm.g_sp->sectnum].lotag == 1 && klabs(vm.g_sp->z-sector[vm.g_sp->sectnum].floorz) < (32<<8));
|
|
continue;
|
|
|
|
case CON_IFINWATER:
|
|
X_ERROR_INVALIDSP();
|
|
VM_DoConditional(sector[vm.g_sp->sectnum].lotag == 2);
|
|
continue;
|
|
|
|
case CON_IFACTOR:
|
|
insptr++;
|
|
X_ERROR_INVALIDSP();
|
|
VM_DoConditional(vm.g_sp->picnum == Gv_GetVarX(*insptr));
|
|
continue;
|
|
|
|
case CON_IFINSIDE:
|
|
insptr++;
|
|
{
|
|
int32_t x=Gv_GetVarX(*insptr++), y=Gv_GetVarX(*insptr++), sectnum=Gv_GetVarX(*insptr++), res;
|
|
|
|
res = inside(x, y, sectnum);
|
|
if (res == -1)
|
|
{
|
|
M32_ERROR("Sector index %d out of range!", sectnum);
|
|
continue;
|
|
}
|
|
insptr--;
|
|
VM_DoConditional(res);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFOUTSIDE:
|
|
X_ERROR_INVALIDSP();
|
|
VM_DoConditional(sector[vm.g_sp->sectnum].ceilingstat&1);
|
|
continue;
|
|
|
|
case CON_IFPDISTL:
|
|
insptr++;
|
|
{
|
|
X_ERROR_INVALIDSP();
|
|
VM_DoConditional(dist((spritetype *)&pos, vm.g_sp) < Gv_GetVarX(*insptr));
|
|
}
|
|
continue;
|
|
|
|
case CON_IFPDISTG:
|
|
insptr++;
|
|
{
|
|
X_ERROR_INVALIDSP();
|
|
VM_DoConditional(dist((spritetype *)&pos, vm.g_sp) > Gv_GetVarX(*insptr));
|
|
}
|
|
continue;
|
|
// ^^^
|
|
|
|
// *** BUILD functions
|
|
case CON_INSERTSPRITE:
|
|
insptr++;
|
|
{
|
|
int32_t dasectnum = Gv_GetVarX(*insptr++), ret;
|
|
|
|
X_ERROR_INVALIDSECT(dasectnum);
|
|
if (numsprites >= MAXSPRITES)
|
|
{
|
|
M32_ERROR("Maximum number of sprites reached.");
|
|
continue;
|
|
}
|
|
|
|
ret = insertsprite(dasectnum, 0);
|
|
vm.g_i = ret;
|
|
vm.g_sp = &sprite[ret];
|
|
numsprites++;
|
|
}
|
|
continue;
|
|
|
|
case CON_DUPSPRITE:
|
|
case CON_TDUPSPRITE:
|
|
insptr++;
|
|
{
|
|
int32_t ospritenum = Gv_GetVarX(*insptr++), nspritenum;
|
|
|
|
if (ospritenum<0 || ospritenum>=MAXSPRITES || sprite[ospritenum].statnum==MAXSTATUS)
|
|
{
|
|
M32_ERROR("Tried to duplicate nonexistent sprite %d", ospritenum);
|
|
}
|
|
if ((tw==CON_DUPSPRITE && numsprites >= MAXSPRITES) ||
|
|
(tw==CON_DUPSPRITE && spritesortcnt >= MAXSPRITESONSCREEN))
|
|
{
|
|
M32_ERROR("Maximum number of sprites reached.");
|
|
}
|
|
if (vm.flags&VMFLAG_ERROR) continue;
|
|
|
|
if (tw==CON_DUPSPRITE)
|
|
{
|
|
nspritenum = insertsprite(sprite[ospritenum].sectnum, sprite[ospritenum].statnum);
|
|
|
|
if (nspritenum < 0)
|
|
{
|
|
M32_ERROR("Internal error.");
|
|
continue;
|
|
}
|
|
|
|
Bmemcpy(&sprite[nspritenum], &sprite[ospritenum], sizeof(spritetype));
|
|
vm.g_i = nspritenum;
|
|
vm.g_sp = &sprite[nspritenum];
|
|
numsprites++;
|
|
}
|
|
else
|
|
{
|
|
Bmemcpy(&tsprite[spritesortcnt], &sprite[ospritenum], sizeof(spritetype));
|
|
tsprite[spritesortcnt].owner = ospritenum;
|
|
vm.g_i = -1;
|
|
vm.g_sp = &tsprite[spritesortcnt];
|
|
spritesortcnt++;
|
|
}
|
|
}
|
|
continue;
|
|
|
|
case CON_DELETESPRITE:
|
|
insptr++;
|
|
{
|
|
int32_t daspritenum = Gv_GetVarX(*insptr++), ret;
|
|
|
|
X_ERROR_INVALIDSPRI(daspritenum);
|
|
ret = deletesprite(daspritenum);
|
|
g_iReturnVar = ret;
|
|
if (ret==0)
|
|
numsprites--;
|
|
}
|
|
continue;
|
|
|
|
case CON_LASTWALL:
|
|
insptr++;
|
|
{
|
|
int32_t dapoint = Gv_GetVarX(*insptr++), resvar=*insptr++;
|
|
|
|
if (dapoint<0 || dapoint>=numwalls)
|
|
{
|
|
M32_ERROR("Invalid wall %d", dapoint);
|
|
continue;
|
|
}
|
|
|
|
Gv_SetVarX(resvar, lastwall(dapoint));
|
|
}
|
|
continue;
|
|
|
|
case CON_GETZRANGE:
|
|
insptr++;
|
|
{
|
|
vec3_t vect;
|
|
|
|
vect.x = Gv_GetVarX(*insptr++);
|
|
vect.y = Gv_GetVarX(*insptr++);
|
|
vect.z = Gv_GetVarX(*insptr++);
|
|
|
|
{
|
|
int32_t sectnum=Gv_GetVarX(*insptr++);
|
|
int32_t ceilzvar=*insptr++, ceilhitvar=*insptr++, florzvar=*insptr++, florhitvar=*insptr++;
|
|
int32_t walldist=Gv_GetVarX(*insptr++), clipmask=Gv_GetVarX(*insptr++);
|
|
int32_t ceilz, ceilhit, florz, florhit;
|
|
|
|
X_ERROR_INVALIDSECT(sectnum);
|
|
getzrange(&vect, sectnum, &ceilz, &ceilhit, &florz, &florhit, walldist, clipmask);
|
|
Gv_SetVarX(ceilzvar, ceilz);
|
|
Gv_SetVarX(ceilhitvar, ceilhit);
|
|
Gv_SetVarX(florzvar, florz);
|
|
Gv_SetVarX(florhitvar, florhit);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
case CON_CALCHYPOTENUSE:
|
|
insptr++;
|
|
{
|
|
int32_t retvar=*insptr++;
|
|
int64_t dax=Gv_GetVarX(*insptr++), day=Gv_GetVarX(*insptr++);
|
|
int64_t hypsq = dax*dax + day*day;
|
|
|
|
if (hypsq > (int64_t)INT32_MAX)
|
|
Gv_SetVarX(retvar, (int32_t)sqrt((double)hypsq));
|
|
else
|
|
Gv_SetVarX(retvar, ksqrt((int32_t)hypsq));
|
|
|
|
continue;
|
|
}
|
|
|
|
case CON_LINEINTERSECT:
|
|
case CON_RAYINTERSECT:
|
|
insptr++;
|
|
{
|
|
int32_t x1=Gv_GetVarX(*insptr++), y1=Gv_GetVarX(*insptr++), z1=Gv_GetVarX(*insptr++);
|
|
int32_t x2=Gv_GetVarX(*insptr++), y2=Gv_GetVarX(*insptr++), z2=Gv_GetVarX(*insptr++);
|
|
int32_t x3=Gv_GetVarX(*insptr++), y3=Gv_GetVarX(*insptr++), x4=Gv_GetVarX(*insptr++), y4=Gv_GetVarX(*insptr++);
|
|
int32_t intxvar=*insptr++, intyvar=*insptr++, intzvar=*insptr++, retvar=*insptr++;
|
|
int32_t intx, inty, intz, ret;
|
|
|
|
if (tw==CON_LINEINTERSECT)
|
|
ret = lineintersect(x1, y1, z1, x2, y2, z2, x3, y3, x4, y4, &intx, &inty, &intz);
|
|
else
|
|
ret = rayintersect(x1, y1, z1, x2, y2, z2, x3, y3, x4, y4, &intx, &inty, &intz);
|
|
|
|
Gv_SetVarX(retvar, ret);
|
|
if (ret)
|
|
{
|
|
Gv_SetVarX(intxvar, intx);
|
|
Gv_SetVarX(intyvar, inty);
|
|
Gv_SetVarX(intzvar, intz);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
case CON_CLIPMOVE:
|
|
insptr++;
|
|
{
|
|
vec3_t vect;
|
|
int32_t retvar=*insptr++, xvar=*insptr++, yvar=*insptr++, z=Gv_GetVarX(*insptr++), sectnumvar=*insptr++;
|
|
int32_t xvect=Gv_GetVarX(*insptr++), yvect=Gv_GetVarX(*insptr++);
|
|
int32_t walldist=Gv_GetVarX(*insptr++), floordist=Gv_GetVarX(*insptr++), ceildist=Gv_GetVarX(*insptr++);
|
|
int32_t clipmask=Gv_GetVarX(*insptr++);
|
|
int16_t sectnum;
|
|
|
|
vect.x = Gv_GetVarX(xvar);
|
|
vect.y = Gv_GetVarX(yvar);
|
|
vect.z = z;
|
|
sectnum = Gv_GetVarX(sectnumvar);
|
|
|
|
X_ERROR_INVALIDSECT(sectnum);
|
|
|
|
Gv_SetVarX(retvar, clipmove(&vect, §num, xvect, yvect, walldist, floordist, ceildist, clipmask));
|
|
Gv_SetVarX(sectnumvar, sectnum);
|
|
Gv_SetVarX(xvar, vect.x);
|
|
Gv_SetVarX(yvar, vect.y);
|
|
|
|
continue;
|
|
}
|
|
|
|
case CON_HITSCAN:
|
|
insptr++;
|
|
{
|
|
vec3_t vect;
|
|
hitdata_t hitinfo;
|
|
|
|
vect.x = Gv_GetVarX(*insptr++);
|
|
vect.y = Gv_GetVarX(*insptr++);
|
|
vect.z = Gv_GetVarX(*insptr++);
|
|
|
|
{
|
|
int32_t sectnum=Gv_GetVarX(*insptr++);
|
|
int32_t vx=Gv_GetVarX(*insptr++), vy=Gv_GetVarX(*insptr++), vz=Gv_GetVarX(*insptr++);
|
|
int32_t hitsectvar=*insptr++, hitwallvar=*insptr++, hitspritevar=*insptr++;
|
|
int32_t hitxvar=*insptr++, hityvar=*insptr++, hitzvar=*insptr++, cliptype=Gv_GetVarX(*insptr++);
|
|
|
|
X_ERROR_INVALIDSECT(sectnum);
|
|
hitscan((const vec3_t *)&vect, sectnum, vx, vy, vz, &hitinfo, cliptype);
|
|
Gv_SetVarX(hitsectvar, hitinfo.hitsect);
|
|
Gv_SetVarX(hitwallvar, hitinfo.hitwall);
|
|
Gv_SetVarX(hitspritevar, hitinfo.hitsprite);
|
|
Gv_SetVarX(hitxvar, hitinfo.pos.x);
|
|
Gv_SetVarX(hityvar, hitinfo.pos.y);
|
|
Gv_SetVarX(hitzvar, hitinfo.pos.z);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
case CON_CANSEE:
|
|
insptr++;
|
|
{
|
|
int32_t x1=Gv_GetVarX(*insptr++), y1=Gv_GetVarX(*insptr++), z1=Gv_GetVarX(*insptr++);
|
|
int32_t sect1=Gv_GetVarX(*insptr++);
|
|
int32_t x2=Gv_GetVarX(*insptr++), y2=Gv_GetVarX(*insptr++), z2=Gv_GetVarX(*insptr++);
|
|
int32_t sect2=Gv_GetVarX(*insptr++), rvar=*insptr++;
|
|
|
|
X_ERROR_INVALIDSECT(sect1);
|
|
X_ERROR_INVALIDSECT(sect2);
|
|
|
|
Gv_SetVarX(rvar, cansee(x1,y1,z1,sect1,x2,y2,z2,sect2));
|
|
continue;
|
|
}
|
|
|
|
case CON_ROTATEPOINT:
|
|
insptr++;
|
|
{
|
|
int32_t xpivot=Gv_GetVarX(*insptr++), ypivot=Gv_GetVarX(*insptr++);
|
|
int32_t x=Gv_GetVarX(*insptr++), y=Gv_GetVarX(*insptr++), daang=Gv_GetVarX(*insptr++);
|
|
int32_t x2var=*insptr++, y2var=*insptr++;
|
|
int32_t x2, y2;
|
|
|
|
rotatepoint(xpivot,ypivot,x,y,daang,&x2,&y2);
|
|
Gv_SetVarX(x2var, x2);
|
|
Gv_SetVarX(y2var, y2);
|
|
continue;
|
|
}
|
|
|
|
case CON_NEARTAG:
|
|
insptr++;
|
|
{
|
|
// neartag(int32_t x, int32_t y, int32_t z, short sectnum, short ang, //Starting position & angle
|
|
// short *neartagsector, //Returns near sector if sector[].tag != 0
|
|
// short *neartagwall, //Returns near wall if wall[].tag != 0
|
|
// short *neartagsprite, //Returns near sprite if sprite[].tag != 0
|
|
// int32_t *neartaghitdist, //Returns actual distance to object (scale: 1024=largest grid size)
|
|
// int32_t neartagrange, //Choose maximum distance to scan (scale: 1024=largest grid size)
|
|
// char tagsearch) //1-lotag only, 2-hitag only, 3-lotag&hitag
|
|
|
|
int32_t x=Gv_GetVarX(*insptr++), y=Gv_GetVarX(*insptr++), z=Gv_GetVarX(*insptr++);
|
|
int32_t sectnum=Gv_GetVarX(*insptr++), ang=Gv_GetVarX(*insptr++);
|
|
int32_t neartagsectorvar=*insptr++, neartagwallvar=*insptr++, neartagspritevar=*insptr++, neartaghitdistvar=*insptr++;
|
|
int32_t neartagrange=Gv_GetVarX(*insptr++), tagsearch=Gv_GetVarX(*insptr++);
|
|
|
|
int16_t neartagsector, neartagwall, neartagsprite;
|
|
int32_t neartaghitdist;
|
|
|
|
X_ERROR_INVALIDSECT(sectnum);
|
|
neartag(x, y, z, sectnum, ang, &neartagsector, &neartagwall, &neartagsprite, &neartaghitdist, neartagrange, tagsearch);
|
|
|
|
Gv_SetVarX(neartagsectorvar, neartagsector);
|
|
Gv_SetVarX(neartagwallvar, neartagwall);
|
|
Gv_SetVarX(neartagspritevar, neartagsprite);
|
|
Gv_SetVarX(neartaghitdistvar, neartaghitdist);
|
|
continue;
|
|
}
|
|
|
|
case CON_BSETSPRITE: // was CON_SETSPRITE
|
|
insptr++;
|
|
{
|
|
int32_t spritenum = Gv_GetVarX(*insptr++);
|
|
vec3_t davector;
|
|
|
|
davector.x = Gv_GetVarX(*insptr++);
|
|
davector.y = Gv_GetVarX(*insptr++);
|
|
davector.z = Gv_GetVarX(*insptr++);
|
|
|
|
X_ERROR_INVALIDSPRI(spritenum);
|
|
setsprite(spritenum, &davector);
|
|
continue;
|
|
}
|
|
|
|
case CON_GETFLORZOFSLOPE:
|
|
case CON_GETCEILZOFSLOPE:
|
|
insptr++;
|
|
{
|
|
int32_t sectnum = Gv_GetVarX(*insptr++), x = Gv_GetVarX(*insptr++), y = Gv_GetVarX(*insptr++);
|
|
int32_t var=*insptr++;
|
|
|
|
X_ERROR_INVALIDSECT(sectnum);
|
|
if (tw == CON_GETFLORZOFSLOPE)
|
|
Gv_SetVarX(var, getflorzofslope(sectnum,x,y));
|
|
else
|
|
Gv_SetVarX(var, getceilzofslope(sectnum,x,y));
|
|
continue;
|
|
}
|
|
|
|
case CON_ALIGNFLORSLOPE:
|
|
case CON_ALIGNCEILSLOPE:
|
|
insptr++;
|
|
{
|
|
int32_t sectnum = Gv_GetVarX(*insptr++), x = Gv_GetVarX(*insptr++), y = Gv_GetVarX(*insptr++);
|
|
int32_t z=Gv_GetVarX(*insptr++);
|
|
|
|
X_ERROR_INVALIDSECT(sectnum);
|
|
if (tw == CON_ALIGNFLORSLOPE)
|
|
alignflorslope(sectnum, x,y,z);
|
|
else
|
|
alignceilslope(sectnum, x,y,z);
|
|
continue;
|
|
}
|
|
|
|
// CURSPR
|
|
case CON_SETFIRSTWALL:
|
|
insptr++;
|
|
{
|
|
int32_t sect=Gv_GetVarX(*insptr++), wal=Gv_GetVarX(*insptr++);
|
|
|
|
X_ERROR_INVALIDSECT(sect);
|
|
setfirstwall(sect, wal);
|
|
}
|
|
continue;
|
|
|
|
case CON_UPDATECURSECTNUM:
|
|
insptr++;
|
|
updatesectorz(pos.x, pos.y, pos.z, &cursectnum);
|
|
continue;
|
|
|
|
case CON_UPDATESECTOR:
|
|
case CON_UPDATESECTORZ:
|
|
insptr++;
|
|
{
|
|
int32_t x=Gv_GetVarX(*insptr++), y=Gv_GetVarX(*insptr++);
|
|
int32_t z=(tw==CON_UPDATESECTORZ)?Gv_GetVarX(*insptr++):0;
|
|
int32_t var=*insptr++;
|
|
int16_t w;
|
|
|
|
X_ERROR_INVALIDCI();
|
|
w=sprite[vm.g_i].sectnum;
|
|
|
|
if (tw==CON_UPDATESECTOR) updatesector(x,y,&w);
|
|
else updatesectorz(x,y,z,&w);
|
|
|
|
Gv_SetVarX(var, w);
|
|
continue;
|
|
}
|
|
|
|
case CON_HEADSPRITESTAT:
|
|
insptr++;
|
|
{
|
|
int32_t i=*insptr++;
|
|
int32_t j=Gv_GetVarX(*insptr++);
|
|
if (j < 0 || j > MAXSTATUS)
|
|
{
|
|
M32_ERROR("invalid status list %d", j);
|
|
continue;
|
|
}
|
|
Gv_SetVarX(i,headspritestat[j]);
|
|
continue;
|
|
}
|
|
|
|
case CON_PREVSPRITESTAT:
|
|
insptr++;
|
|
{
|
|
int32_t i=*insptr++;
|
|
int32_t j=Gv_GetVarX(*insptr++);
|
|
|
|
X_ERROR_INVALIDSPRI(j);
|
|
Gv_SetVarX(i,prevspritestat[j]);
|
|
continue;
|
|
}
|
|
|
|
case CON_NEXTSPRITESTAT:
|
|
insptr++;
|
|
{
|
|
int32_t i=*insptr++;
|
|
int32_t j=Gv_GetVarX(*insptr++);
|
|
|
|
X_ERROR_INVALIDSPRI(j);
|
|
Gv_SetVarX(i,nextspritestat[j]);
|
|
continue;
|
|
}
|
|
|
|
case CON_HEADSPRITESECT:
|
|
insptr++;
|
|
{
|
|
int32_t i=*insptr++;
|
|
int32_t j=Gv_GetVarX(*insptr++);
|
|
|
|
X_ERROR_INVALIDSECT(j);
|
|
Gv_SetVarX(i,headspritesect[j]);
|
|
continue;
|
|
}
|
|
|
|
case CON_PREVSPRITESECT:
|
|
insptr++;
|
|
{
|
|
int32_t i=*insptr++;
|
|
int32_t j=Gv_GetVarX(*insptr++);
|
|
|
|
X_ERROR_INVALIDSPRI(j);
|
|
Gv_SetVarX(i,prevspritesect[j]);
|
|
continue;
|
|
}
|
|
|
|
case CON_NEXTSPRITESECT:
|
|
insptr++;
|
|
{
|
|
int32_t i=*insptr++;
|
|
int32_t j=Gv_GetVarX(*insptr++);
|
|
|
|
X_ERROR_INVALIDSPRI(j);
|
|
Gv_SetVarX(i,nextspritesect[j]);
|
|
continue;
|
|
}
|
|
|
|
case CON_CANSEESPR:
|
|
insptr++;
|
|
{
|
|
int32_t lVar1 = Gv_GetVarX(*insptr++), lVar2 = Gv_GetVarX(*insptr++), res;
|
|
|
|
if (lVar1<0 || lVar1>=MAXSPRITES || sprite[lVar1].statnum==MAXSTATUS)
|
|
{
|
|
M32_ERROR("Invalid sprite %d", lVar1);
|
|
}
|
|
if (lVar2<0 || lVar2>=MAXSPRITES || sprite[lVar2].statnum==MAXSTATUS)
|
|
{
|
|
M32_ERROR("Invalid sprite %d", lVar2);
|
|
}
|
|
|
|
if (vm.flags&VMFLAG_ERROR) res=0;
|
|
else res=cansee(sprite[lVar1].x,sprite[lVar1].y,sprite[lVar1].z,sprite[lVar1].sectnum,
|
|
sprite[lVar2].x,sprite[lVar2].y,sprite[lVar2].z,sprite[lVar2].sectnum);
|
|
|
|
Gv_SetVarX(*insptr++, res);
|
|
continue;
|
|
}
|
|
|
|
case CON_CHANGESPRITESTAT:
|
|
case CON_CHANGESPRITESECT:
|
|
insptr++;
|
|
{
|
|
int32_t i = Gv_GetVarX(*insptr++);
|
|
int32_t j = Gv_GetVarX(*insptr++);
|
|
|
|
X_ERROR_INVALIDSPRI(i);
|
|
if (j<0 || j >= (tw==CON_CHANGESPRITESTAT?MAXSTATUS:numsectors))
|
|
{
|
|
M32_ERROR("Invalid %s: %d", tw==CON_CHANGESPRITESTAT?"statnum":"sector", j);
|
|
continue;
|
|
}
|
|
|
|
if (tw == CON_CHANGESPRITESTAT)
|
|
{
|
|
if (sprite[i].statnum == j) continue;
|
|
changespritestat(i,j);
|
|
}
|
|
else
|
|
{
|
|
if (sprite[i].sectnum == j) continue;
|
|
changespritesect(i,j);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
case CON_DRAGPOINT:
|
|
insptr++;
|
|
{
|
|
int32_t wallnum = Gv_GetVarX(*insptr++), newx = Gv_GetVarX(*insptr++), newy = Gv_GetVarX(*insptr++);
|
|
|
|
if (wallnum<0 || wallnum>=numwalls)
|
|
{
|
|
M32_ERROR("Invalid wall %d", wallnum);
|
|
continue;
|
|
}
|
|
dragpoint(wallnum,newx,newy);
|
|
continue;
|
|
}
|
|
|
|
case CON_SECTOROFWALL:
|
|
insptr++;
|
|
{
|
|
int32_t j = *insptr++;
|
|
Gv_SetVarX(j, sectorofwall(Gv_GetVarX(*insptr++)));
|
|
}
|
|
continue;
|
|
|
|
case CON_FIXREPEATS:
|
|
insptr++;
|
|
fixrepeats(Gv_GetVarX(*insptr++));
|
|
continue;
|
|
|
|
case CON_GETCLOSESTCOL:
|
|
insptr++;
|
|
{
|
|
int32_t r = Gv_GetVarX(*insptr++), g = Gv_GetVarX(*insptr++), b = Gv_GetVarX(*insptr++);
|
|
Gv_SetVarX(*insptr++, getclosestcol((r>>2)&63, (g>>2)&63, (b>>2)&63));
|
|
continue;
|
|
}
|
|
|
|
// *** stuff
|
|
case CON_UPDATEHIGHLIGHT:
|
|
insptr++;
|
|
update_highlight();
|
|
continue;
|
|
|
|
case CON_UPDATEHIGHLIGHTSECTOR:
|
|
insptr++;
|
|
update_highlightsector();
|
|
continue;
|
|
|
|
case CON_SETHIGHLIGHT:
|
|
insptr++;
|
|
{
|
|
int32_t what=Gv_GetVarX(*insptr++), index=Gv_GetVarX(*insptr++), doset = Gv_GetVarX(*insptr++);
|
|
|
|
if (highlightsectorcnt >= 0)
|
|
{
|
|
M32_ERROR("sector highlight active or pending, cannot highlight sprites/walls");
|
|
continue;
|
|
}
|
|
|
|
if (what&16384)
|
|
{
|
|
index &= ~16384;
|
|
if (index < 0 || index>=MAXSPRITES || sprite[index].statnum==MAXSTATUS)
|
|
{
|
|
M32_ERROR("Invalid sprite index %d", index);
|
|
continue;
|
|
}
|
|
|
|
if (doset)
|
|
show2dsprite[index>>3] |= (1<<(index&7));
|
|
else
|
|
show2dsprite[index>>3] &= ~(1<<(index&7));
|
|
}
|
|
else
|
|
{
|
|
if (index < 0 || index>=numwalls)
|
|
{
|
|
M32_ERROR("Invalid wall index %d", index);
|
|
continue;
|
|
}
|
|
|
|
if (doset)
|
|
show2dwall[index>>3] |= (1<<(index&7));
|
|
else
|
|
show2dwall[index>>3] &= ~(1<<(index&7));
|
|
}
|
|
|
|
vm.miscflags |= VMFLAG_MISC_UPDATEHL;
|
|
|
|
continue;
|
|
}
|
|
|
|
case CON_SETHIGHLIGHTSECTOR:
|
|
insptr++;
|
|
{
|
|
int32_t index=Gv_GetVarX(*insptr++), doset = Gv_GetVarX(*insptr++);
|
|
|
|
if (highlightcnt >= 0)
|
|
{
|
|
M32_ERROR("sprite/wall highlight active or pending, cannot highlight sectors");
|
|
continue;
|
|
}
|
|
|
|
X_ERROR_INVALIDSECT(index);
|
|
|
|
if (doset)
|
|
hlsectorbitmap[index>>3] |= (1<<(index&7));
|
|
else
|
|
hlsectorbitmap[index>>3] &= ~(1<<(index&7));
|
|
|
|
vm.miscflags |= VMFLAG_MISC_UPDATEHLSECT;
|
|
|
|
continue;
|
|
}
|
|
|
|
case CON_GETTIMEDATE:
|
|
insptr++;
|
|
{
|
|
int32_t v1=*insptr++,v2=*insptr++,v3=*insptr++,v4=*insptr++,v5=*insptr++,v6=*insptr++,v7=*insptr++,v8=*insptr++;
|
|
time_t rawtime;
|
|
struct tm *ti;
|
|
|
|
time(&rawtime);
|
|
ti = localtime(&rawtime);
|
|
// initprintf("Time&date: %s\n",asctime (ti));
|
|
|
|
Gv_SetVarX(v1, ti->tm_sec);
|
|
Gv_SetVarX(v2, ti->tm_min);
|
|
Gv_SetVarX(v3, ti->tm_hour);
|
|
Gv_SetVarX(v4, ti->tm_mday);
|
|
Gv_SetVarX(v5, ti->tm_mon);
|
|
Gv_SetVarX(v6, ti->tm_year+1900);
|
|
Gv_SetVarX(v7, ti->tm_wday);
|
|
Gv_SetVarX(v8, ti->tm_yday);
|
|
continue;
|
|
}
|
|
|
|
case CON_ADDLOG:
|
|
{
|
|
insptr++;
|
|
|
|
OSD_Printf("L=%d\n", g_errorLineNum);
|
|
continue;
|
|
}
|
|
|
|
case CON_ADDLOGVAR:
|
|
insptr++;
|
|
{
|
|
char buf[80] = "", buf2[80] = "";
|
|
int32_t code = (int32_t)*insptr, val = Gv_GetVarX(code);
|
|
int32_t negate=code&M32_FLAG_NEGATE;
|
|
|
|
if (code & (0xFFFFFFFF-(MAXGAMEVARS-1)))
|
|
{
|
|
if ((code&M32_VARTYPE_MASK)==M32_FLAG_ARRAY || (code&M32_VARTYPE_MASK)==M32_FLAG_STRUCT)
|
|
{
|
|
if (code&M32_FLAG_CONSTANT)
|
|
Bsprintf(buf2, "%d", (code>>16)&0xffff);
|
|
else
|
|
{
|
|
char *label = aGameVars[(code>>16)&(MAXGAMEVARS-1)].szLabel;
|
|
Bsprintf(buf2, "%s", label?label:"???");
|
|
}
|
|
}
|
|
else if ((code&M32_VARTYPE_MASK)==M32_FLAG_LOCAL)
|
|
Bsprintf(buf2, "%d", code&(MAXGAMEVARS-1));
|
|
|
|
if ((code&0x0000FFFC) == M32_FLAG_CONSTANT) // addlogvar for a constant.. why not? :P
|
|
{
|
|
switch (code&3)
|
|
{
|
|
case 0: Bsprintf(buf, "(immediate constant)"); break;
|
|
case 1: Bsprintf(buf, "(indirect constant)"); break;
|
|
case 2: Bsprintf(buf, "(label constant)"); break;
|
|
default: Bsprintf(buf, "(??? constant)"); break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (code&M32_VARTYPE_MASK)
|
|
{
|
|
case M32_FLAG_ARRAY:
|
|
Bsprintf(buf, "%s[%s]", aGameArrays[code&(MAXGAMEARRAYS-1)].szLabel?
|
|
aGameArrays[code&(MAXGAMEARRAYS-1)].szLabel:"???", buf2);
|
|
break;
|
|
case M32_FLAG_STRUCT:
|
|
{
|
|
int32_t memberid=(code>>2)&63, lightp = (memberid >= LIGHT_X);
|
|
const char *pp1[4] = {"sprite","sector","wall","tsprite"};
|
|
const memberlabel_t *pp2[4] = {SpriteLabels, SectorLabels, WallLabels, SpriteLabels};
|
|
if (lightp)
|
|
{
|
|
pp1[3] = "light";
|
|
pp2[3] = LightLabels;
|
|
memberid -= LIGHT_X;
|
|
}
|
|
|
|
Bsprintf(buf, "%s[%s].%s", pp1[code&3], buf2, pp2[code&3][memberid].name);
|
|
}
|
|
break;
|
|
case M32_FLAG_VAR:
|
|
Bsprintf(buf, "???");
|
|
break;
|
|
case M32_FLAG_LOCAL:
|
|
Bsprintf(buf, ".local[%s]", buf2);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (aGameVars[code].dwFlags & GAMEVAR_PERBLOCK)
|
|
{
|
|
Bsprintf(buf2, "(%s", vm.g_st==0? "top-level) " : vm.g_st<=MAXEVENTS? "event" : "state");
|
|
if (vm.g_st >= 1+MAXEVENTS && vm.g_st <1+MAXEVENTS+g_stateCount)
|
|
Bsprintf(buf, " `%s') ", statesinfo[vm.g_st-1-MAXEVENTS].name);
|
|
else if (vm.g_st > 0)
|
|
Bsprintf(buf, " %d) ", vm.g_st-1);
|
|
Bstrcat(buf2, buf);
|
|
}
|
|
|
|
Bsprintf(buf, "%s%s", buf2, aGameVars[code].szLabel ? aGameVars[code].szLabel : "???");
|
|
}
|
|
|
|
OSD_Printf("L%d: %s%s=%d\n", g_errorLineNum, negate?"-":"", buf, val);
|
|
|
|
insptr++;
|
|
continue;
|
|
}
|
|
|
|
case CON_DEBUG:
|
|
insptr++;
|
|
initprintf("%d\n",*insptr++);
|
|
continue;
|
|
|
|
// *** strings
|
|
case CON_REDEFINEQUOTE:
|
|
insptr++;
|
|
{
|
|
int32_t q = *insptr++, i = *insptr++;
|
|
X_ERROR_INVALIDQUOTE(q, ScriptQuotes);
|
|
X_ERROR_INVALIDQUOTE(i, ScriptQuoteRedefinitions);
|
|
Bstrcpy(ScriptQuotes[q],ScriptQuoteRedefinitions[i]);
|
|
continue;
|
|
}
|
|
|
|
insptr++;
|
|
X_ERROR_INVALIDQUOTE(*insptr, ScriptQuotes);
|
|
OSD_Printf("%s", ScriptQuotes[*insptr++]);
|
|
continue;
|
|
|
|
case CON_GETNUMBER16: /* deprecated */
|
|
case CON_GETNUMBER256: /* deprecated */
|
|
case CON_GETNUMBERFROMUSER:
|
|
insptr++;
|
|
{
|
|
int32_t var=*insptr++, quote=*insptr++;
|
|
const char *quotetext = GetMaybeInlineQuote(quote);
|
|
if (vm.flags&VMFLAG_ERROR)
|
|
continue;
|
|
|
|
{
|
|
int32_t max=Gv_GetVarX(*insptr++);
|
|
int32_t sign = (tw==CON_GETNUMBERFROMUSER) ? Gv_GetVarX(*insptr++) : (max<=0);
|
|
char buf[64]; // buffers in getnumber* are 80 bytes long
|
|
|
|
Bstrncpy(buf, quotetext, sizeof(buf));
|
|
buf[sizeof(buf)-1]='\0';
|
|
|
|
if (max==0)
|
|
max = INT32_MAX;
|
|
|
|
//OSD_Printf("max:%d, sign:%d\n", max, sign);
|
|
if (tw==CON_GETNUMBERFROMUSER)
|
|
{
|
|
Gv_SetVarX(var, (qsetmode==200) ?
|
|
getnumber256(quotetext, Gv_GetVarX(var), max, sign) :
|
|
getnumber16(quotetext, Gv_GetVarX(var), max, sign));
|
|
}
|
|
else if (tw==CON_GETNUMBER16)
|
|
Gv_SetVarX(var, getnumber16(quotetext, Gv_GetVarX(var), max, sign));
|
|
else
|
|
Gv_SetVarX(var, getnumber256(quotetext, Gv_GetVarX(var), max, sign));
|
|
}
|
|
}
|
|
continue;
|
|
|
|
case CON_PRINT:
|
|
case CON_QUOTE:
|
|
case CON_ERRORINS:
|
|
case CON_PRINTMESSAGE16:
|
|
case CON_PRINTMESSAGE256:
|
|
case CON_PRINTEXT256:
|
|
case CON_PRINTEXT16:
|
|
case CON_DRAWLABEL:
|
|
insptr++;
|
|
{
|
|
int32_t i=*insptr++;
|
|
const char *quotetext = GetMaybeInlineQuote(i);
|
|
if (vm.flags&VMFLAG_ERROR)
|
|
continue;
|
|
|
|
{
|
|
int32_t x=(tw>=CON_PRINTMESSAGE256)?Gv_GetVarX(*insptr++):0;
|
|
int32_t y=(tw>=CON_PRINTMESSAGE256)?Gv_GetVarX(*insptr++):0;
|
|
|
|
int32_t col=(tw>=CON_PRINTEXT256)?Gv_GetVarX(*insptr++):0;
|
|
int32_t backcol=(tw>=CON_PRINTEXT256)?Gv_GetVarX(*insptr++):0;
|
|
int32_t fontsize=(tw>=CON_PRINTEXT256)?Gv_GetVarX(*insptr++):0;
|
|
|
|
if (tw==CON_PRINT || tw==CON_ERRORINS)
|
|
{
|
|
OSD_Printf("%s\n", quotetext);
|
|
if (tw==CON_ERRORINS)
|
|
vm.flags |= VMFLAG_ERROR;
|
|
}
|
|
else if (tw==CON_QUOTE)
|
|
{
|
|
message("%s", quotetext);
|
|
}
|
|
else if (tw==CON_PRINTMESSAGE16)
|
|
{
|
|
if (qsetmode != 200)
|
|
printmessage16("%s", quotetext);
|
|
}
|
|
else if (tw==CON_PRINTMESSAGE256)
|
|
{
|
|
if (qsetmode == 200)
|
|
printmessage256(x, y, quotetext);
|
|
}
|
|
else if (tw==CON_PRINTEXT256)
|
|
{
|
|
if (qsetmode == 200)
|
|
{
|
|
if (col<0 || col>=256) col=0;
|
|
if (backcol<0 || backcol>=256) backcol=-1;
|
|
printext256(x, y, col, backcol, quotetext, fontsize);
|
|
}
|
|
}
|
|
else if (tw==CON_PRINTEXT16)
|
|
{
|
|
if (qsetmode != 200)
|
|
printext16(x, y, editorcolors[col&255], backcol<0 ? -1 : editorcolors[backcol&255],
|
|
quotetext, fontsize);
|
|
}
|
|
else if (tw==CON_DRAWLABEL)
|
|
{
|
|
if (qsetmode != 200)
|
|
{
|
|
drawsmallabel(quotetext,
|
|
editorcolors[backcol&255], // col
|
|
fontsize < 0 ? -1 : editorcolors[fontsize&255], // backcol
|
|
x, y, col); // x y z
|
|
}
|
|
}
|
|
}
|
|
}
|
|
continue;
|
|
|
|
case CON_QSTRLEN:
|
|
insptr++;
|
|
{
|
|
int32_t i=*insptr++, quote=*insptr++;
|
|
const char *quotetext = GetMaybeInlineQuote(quote);
|
|
if (vm.flags&VMFLAG_ERROR)
|
|
continue;
|
|
|
|
Gv_SetVarX(i, Bstrlen(quotetext));
|
|
continue;
|
|
}
|
|
|
|
case CON_QSUBSTR:
|
|
insptr++;
|
|
{
|
|
int32_t q1 = Gv_GetVarX(*insptr++);
|
|
int32_t q2 = *insptr++;
|
|
const char *q2text = GetMaybeInlineQuote(q2);
|
|
if (vm.flags&VMFLAG_ERROR)
|
|
continue;
|
|
|
|
X_ERROR_INVALIDQUOTE(q1, ScriptQuotes);
|
|
|
|
{
|
|
int32_t st = Gv_GetVarX(*insptr++);
|
|
int32_t ln = Gv_GetVarX(*insptr++);
|
|
char *s1 = ScriptQuotes[q1];
|
|
const char *s2 = q2text;
|
|
|
|
while (*s2 && st--) s2++;
|
|
while ((*s1 = *s2) && ln--)
|
|
{
|
|
s1++;
|
|
s2++;
|
|
}
|
|
*s1=0;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
case CON_QSTRNCAT:
|
|
case CON_QSTRCAT:
|
|
case CON_QSTRCPY:
|
|
/// case CON_QGETSYSSTR:
|
|
insptr++;
|
|
{
|
|
int32_t i = Gv_GetVarX(*insptr++);
|
|
int32_t j = *insptr++;
|
|
|
|
const char *quotetext = GetMaybeInlineQuote(j);
|
|
if (vm.flags&VMFLAG_ERROR)
|
|
continue;
|
|
|
|
X_ERROR_INVALIDQUOTE(i, ScriptQuotes);
|
|
|
|
switch (tw)
|
|
{
|
|
#if 0
|
|
case CON_QGETSYSSTR:
|
|
if (ScriptQuotes[i] == NULL)
|
|
{
|
|
M32_ERROR("null quote %d %d", i,j);
|
|
break;
|
|
}
|
|
switch (j)
|
|
{
|
|
case STR_MAPFILENAME:
|
|
Bstrcpy(ScriptQuotes[i], boardfilename);
|
|
break;
|
|
case STR_VERSION:
|
|
Bstrcpy(ScriptQuotes[i], "Mapster32"VERSION BUILDDATE);
|
|
break;
|
|
default:
|
|
M32_ERROR("unknown str ID %d %d", i,j);
|
|
}
|
|
break;
|
|
#endif
|
|
case CON_QSTRCAT:
|
|
Bstrncat(ScriptQuotes[i], quotetext, (MAXQUOTELEN-1)-Bstrlen(ScriptQuotes[i]));
|
|
break;
|
|
case CON_QSTRNCAT:
|
|
Bstrncat(ScriptQuotes[i], quotetext, Gv_GetVarX(*insptr++));
|
|
break;
|
|
case CON_QSTRCPY:
|
|
Bstrcpy(ScriptQuotes[i], quotetext);
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
case CON_QSPRINTF:
|
|
insptr++;
|
|
{
|
|
int32_t dq=Gv_GetVarX(*insptr++), sq=*insptr++;
|
|
const char *sourcetext = GetMaybeInlineQuote(sq);
|
|
if (vm.flags&VMFLAG_ERROR)
|
|
continue;
|
|
|
|
X_ERROR_INVALIDQUOTE(dq, ScriptQuotes);
|
|
|
|
{
|
|
int32_t arg[32], numvals=0, i=0, j=0, k=0;
|
|
int32_t len = Bstrlen(sourcetext);
|
|
char tmpbuf[MAXQUOTELEN<<1];
|
|
|
|
while (*insptr != -1 && numvals < 32)
|
|
arg[numvals++] = Gv_GetVarX(*insptr++);
|
|
|
|
insptr++; // skip the NOP
|
|
|
|
i = 0;
|
|
do
|
|
{
|
|
while (k < len && j < MAXQUOTELEN && sourcetext[k] != '%')
|
|
tmpbuf[j++] = sourcetext[k++];
|
|
|
|
if (sourcetext[k] == '%')
|
|
{
|
|
k++;
|
|
|
|
if (i>=numvals) goto dodefault;
|
|
|
|
switch (sourcetext[k])
|
|
{
|
|
case 'l':
|
|
if (sourcetext[k+1] != 'd')
|
|
{
|
|
// write the % and l
|
|
tmpbuf[j++] = sourcetext[k-1];
|
|
tmpbuf[j++] = sourcetext[k++];
|
|
break;
|
|
}
|
|
k++;
|
|
case 'd':
|
|
{
|
|
char buf[16];
|
|
int32_t ii = 0;
|
|
|
|
Bsprintf(buf, "%d", arg[i++]);
|
|
|
|
ii = Bstrlen(buf);
|
|
Bmemcpy(&tmpbuf[j], buf, ii);
|
|
j += ii;
|
|
k++;
|
|
}
|
|
break;
|
|
|
|
case 'f':
|
|
{
|
|
char buf[64];
|
|
int32_t ii = 0;
|
|
|
|
Bsprintf(buf, "%f", *((float *)&arg[i++]));
|
|
|
|
ii = Bstrlen(buf);
|
|
Bmemcpy(&tmpbuf[j], buf, ii);
|
|
j += ii;
|
|
k++;
|
|
}
|
|
break;
|
|
|
|
case 's':
|
|
{
|
|
if (arg[i]>=0 && arg[i]<MAXQUOTES && ScriptQuotes[arg[i]])
|
|
{
|
|
int32_t ii = Bstrlen(ScriptQuotes[arg[i]]);
|
|
Bmemcpy(&tmpbuf[j], ScriptQuotes[arg[i]], ii);
|
|
j += ii;
|
|
}
|
|
k++;
|
|
}
|
|
break;
|
|
|
|
dodefault:
|
|
default:
|
|
tmpbuf[j++] = sourcetext[k-1];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
while (k < len && j < MAXQUOTELEN);
|
|
|
|
tmpbuf[j] = '\0';
|
|
Bmemcpy(ScriptQuotes[dq], tmpbuf, MAXQUOTELEN);
|
|
ScriptQuotes[dq][MAXQUOTELEN-1] = '\0';
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// *** findnear*
|
|
// CURSPR vvv
|
|
case CON_FINDNEARSPRITE:
|
|
case CON_FINDNEARSPRITE3D:
|
|
case CON_FINDNEARSPRITEVAR:
|
|
case CON_FINDNEARSPRITE3DVAR:
|
|
insptr++;
|
|
{
|
|
// syntax findnearactor(var) <type> <maxdist(var)> <getvar>
|
|
// gets the sprite ID of the nearest actor within max dist
|
|
// that is of <type> into <getvar>
|
|
// -1 for none found
|
|
// <type> <maxdist(varid)> <varid>
|
|
int32_t lType=*insptr++;
|
|
int32_t lMaxDist = (tw==CON_FINDNEARSPRITE || tw==CON_FINDNEARSPRITE3D)?
|
|
*insptr++ : Gv_GetVarX(*insptr++);
|
|
int32_t lVarID=*insptr++;
|
|
int32_t lFound=-1, j, k = MAXSTATUS-1;
|
|
|
|
X_ERROR_INVALIDCI();
|
|
do
|
|
{
|
|
j=headspritestat[k]; // all sprites
|
|
if (tw==CON_FINDNEARSPRITE3D || tw==CON_FINDNEARSPRITE3DVAR)
|
|
{
|
|
while (j>=0)
|
|
{
|
|
if (sprite[j].picnum == lType && j != vm.g_i && dist(&sprite[vm.g_i], &sprite[j]) < lMaxDist)
|
|
{
|
|
lFound=j;
|
|
j = MAXSPRITES;
|
|
break;
|
|
}
|
|
j = nextspritestat[j];
|
|
}
|
|
if (j == MAXSPRITES)
|
|
break;
|
|
continue;
|
|
}
|
|
|
|
while (j>=0)
|
|
{
|
|
if (sprite[j].picnum == lType && j != vm.g_i && ldist(&sprite[vm.g_i], &sprite[j]) < lMaxDist)
|
|
{
|
|
lFound=j;
|
|
j = MAXSPRITES;
|
|
break;
|
|
}
|
|
j = nextspritestat[j];
|
|
}
|
|
|
|
if (j == MAXSPRITES)
|
|
break;
|
|
}
|
|
while (k--);
|
|
Gv_SetVarX(lVarID, lFound);
|
|
continue;
|
|
}
|
|
|
|
case CON_FINDNEARSPRITEZVAR:
|
|
case CON_FINDNEARSPRITEZ:
|
|
insptr++;
|
|
{
|
|
// syntax findnearactor(var) <type> <maxdist(var)> <getvar>
|
|
// gets the sprite ID of the nearest actor within max dist
|
|
// that is of <type> into <getvar>
|
|
// -1 for none found
|
|
// <type> <maxdist(varid)> <varid>
|
|
int32_t lType=*insptr++;
|
|
int32_t lMaxDist = (tw==CON_FINDNEARSPRITEZVAR) ? Gv_GetVarX(*insptr++) : *insptr++;
|
|
int32_t lMaxZDist = (tw==CON_FINDNEARSPRITEZVAR) ? Gv_GetVarX(*insptr++) : *insptr++;
|
|
int32_t lVarID=*insptr++;
|
|
int32_t lFound=-1, lTemp, lTemp2, j, k=MAXSTATUS-1;
|
|
|
|
X_ERROR_INVALIDCI();
|
|
do
|
|
{
|
|
j=headspritestat[k]; // all sprites
|
|
if (j == -1) continue;
|
|
do
|
|
{
|
|
if (sprite[j].picnum == lType && j != vm.g_i)
|
|
{
|
|
lTemp=ldist(&sprite[vm.g_i], &sprite[j]);
|
|
if (lTemp < lMaxDist)
|
|
{
|
|
lTemp2=klabs(sprite[vm.g_i].z-sprite[j].z);
|
|
if (lTemp2 < lMaxZDist)
|
|
{
|
|
lFound=j;
|
|
j = MAXSPRITES;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
j = nextspritestat[j];
|
|
}
|
|
while (j>=0);
|
|
if (j == MAXSPRITES)
|
|
break;
|
|
}
|
|
while (k--);
|
|
Gv_SetVarX(lVarID, lFound);
|
|
|
|
continue;
|
|
}
|
|
// ^^^
|
|
|
|
case CON_GETTICKS:
|
|
insptr++;
|
|
{
|
|
int32_t j=*insptr++;
|
|
Gv_SetVarX(j, getticks());
|
|
}
|
|
continue;
|
|
|
|
case CON_SETASPECT:
|
|
insptr++;
|
|
{
|
|
int32_t daxrange = Gv_GetVarX(*insptr++), dayxaspect = Gv_GetVarX(*insptr++);
|
|
if (daxrange < (1<<12)) daxrange = (1<<12);
|
|
if (daxrange > (1<<20)) daxrange = (1<<20);
|
|
if (dayxaspect < (1<<12)) dayxaspect = (1<<12);
|
|
if (dayxaspect > (1<<20)) dayxaspect = (1<<20);
|
|
setaspect(daxrange, dayxaspect);
|
|
continue;
|
|
}
|
|
|
|
// vvv CURSPR
|
|
case CON_SETI:
|
|
insptr++;
|
|
vm.g_i = Gv_GetVarX(*insptr++);
|
|
X_ERROR_INVALIDCI();
|
|
vm.g_sp = &sprite[vm.g_i];
|
|
continue;
|
|
|
|
case CON_SIZEAT:
|
|
insptr++;
|
|
X_ERROR_INVALIDSP();
|
|
vm.g_sp->xrepeat = (uint8_t) Gv_GetVarX(*insptr++);
|
|
vm.g_sp->yrepeat = (uint8_t) Gv_GetVarX(*insptr++);
|
|
continue;
|
|
|
|
case CON_CSTAT:
|
|
insptr++;
|
|
X_ERROR_INVALIDSP();
|
|
vm.g_sp->cstat = (int16_t) *insptr++;
|
|
continue;
|
|
|
|
case CON_CSTATOR:
|
|
insptr++;
|
|
X_ERROR_INVALIDSP();
|
|
vm.g_sp->cstat |= (int16_t) Gv_GetVarX(*insptr++);
|
|
continue;
|
|
|
|
case CON_CLIPDIST:
|
|
insptr++;
|
|
X_ERROR_INVALIDSP();
|
|
vm.g_sp->clipdist = (int16_t) Gv_GetVarX(*insptr++);
|
|
continue;
|
|
|
|
case CON_SPRITEPAL:
|
|
insptr++;
|
|
X_ERROR_INVALIDSP();
|
|
vm.g_sp->pal = Gv_GetVarX(*insptr++);
|
|
continue;
|
|
|
|
case CON_CACTOR:
|
|
insptr++;
|
|
X_ERROR_INVALIDSP();
|
|
vm.g_sp->picnum = Gv_GetVarX(*insptr++);
|
|
continue;
|
|
|
|
case CON_SPGETLOTAG:
|
|
insptr++;
|
|
X_ERROR_INVALIDSP();
|
|
Gv_SetVarX(M32_LOTAG_VAR_ID, vm.g_sp->lotag);
|
|
continue;
|
|
|
|
case CON_SPGETHITAG:
|
|
insptr++;
|
|
X_ERROR_INVALIDSP();
|
|
Gv_SetVarX(M32_HITAG_VAR_ID, vm.g_sp->hitag);
|
|
continue;
|
|
|
|
case CON_SECTGETLOTAG:
|
|
insptr++;
|
|
X_ERROR_INVALIDSP();
|
|
Gv_SetVarX(M32_LOTAG_VAR_ID, sector[vm.g_sp->sectnum].lotag);
|
|
continue;
|
|
|
|
case CON_SECTGETHITAG:
|
|
insptr++;
|
|
X_ERROR_INVALIDSP();
|
|
Gv_SetVarX(M32_HITAG_VAR_ID, sector[vm.g_sp->sectnum].hitag);
|
|
continue;
|
|
|
|
case CON_GETTEXTUREFLOOR:
|
|
insptr++;
|
|
X_ERROR_INVALIDSP();
|
|
Gv_SetVarX(M32_TEXTURE_VAR_ID, sector[vm.g_sp->sectnum].floorpicnum);
|
|
continue;
|
|
|
|
case CON_GETTEXTURECEILING:
|
|
insptr++;
|
|
X_ERROR_INVALIDSP();
|
|
Gv_SetVarX(M32_TEXTURE_VAR_ID, sector[vm.g_sp->sectnum].ceilingpicnum);
|
|
continue;
|
|
// ^^^
|
|
case CON_DRAWLINE16:
|
|
case CON_DRAWLINE16B:
|
|
case CON_DRAWLINE16Z:
|
|
insptr++;
|
|
{
|
|
int32_t x1=Gv_GetVarX(*insptr++), y1=Gv_GetVarX(*insptr++);
|
|
int32_t z1=tw==CON_DRAWLINE16Z?Gv_GetVarX(*insptr++):0;
|
|
int32_t x2=Gv_GetVarX(*insptr++), y2=Gv_GetVarX(*insptr++);
|
|
int32_t z2=tw==CON_DRAWLINE16Z?Gv_GetVarX(*insptr++):0;
|
|
int32_t col=Gv_GetVarX(*insptr++), odrawlinepat=drawlinepat;
|
|
int32_t xofs=0, yofs=0;
|
|
|
|
if (tw==CON_DRAWLINE16B || tw==CON_DRAWLINE16Z)
|
|
{
|
|
screencoords(&x1,&y1, x1-pos.x,y1-pos.y, zoom);
|
|
screencoords(&x2,&y2, x2-pos.x,y2-pos.y, zoom);
|
|
|
|
if (tw==CON_DRAWLINE16Z && m32_sideview)
|
|
{
|
|
y1 += getscreenvdisp(z1-pos.z,zoom);
|
|
y2 += getscreenvdisp(z2-pos.z,zoom);
|
|
}
|
|
|
|
xofs = halfxdim16;
|
|
yofs = midydim16;
|
|
}
|
|
|
|
drawlinepat = m32_drawlinepat;
|
|
drawline16(xofs+x1,yofs+y1, xofs+x2,yofs+y2, col>=0?editorcolors[col&15]:(-col&255));
|
|
drawlinepat = odrawlinepat;
|
|
continue;
|
|
}
|
|
|
|
case CON_DRAWCIRCLE16:
|
|
case CON_DRAWCIRCLE16B:
|
|
case CON_DRAWCIRCLE16Z:
|
|
insptr++;
|
|
{
|
|
int32_t x1=Gv_GetVarX(*insptr++), y1=Gv_GetVarX(*insptr++);
|
|
int32_t z1 = tw==CON_DRAWCIRCLE16Z ? Gv_GetVarX(*insptr++) : 0;
|
|
int32_t r=Gv_GetVarX(*insptr++);
|
|
int32_t col=Gv_GetVarX(*insptr++), odrawlinepat=drawlinepat;
|
|
int32_t xofs=0, yofs=0, eccen=16384;
|
|
|
|
if (tw==CON_DRAWCIRCLE16B || tw==CON_DRAWCIRCLE16Z)
|
|
{
|
|
screencoords(&x1,&y1, x1-pos.x,y1-pos.y, zoom);
|
|
if (m32_sideview)
|
|
y1 += getscreenvdisp(z1-pos.z, zoom);
|
|
r = mulscale14(r,zoom);
|
|
eccen = scalescreeny(eccen);
|
|
xofs = halfxdim16;
|
|
yofs = midydim16;
|
|
}
|
|
|
|
drawlinepat = m32_drawlinepat;
|
|
drawcircle16(xofs+x1, yofs+y1, r, eccen, col>=0?editorcolors[col&15]:(-col&255));
|
|
drawlinepat = odrawlinepat;
|
|
continue;
|
|
}
|
|
|
|
case CON_ROTATESPRITE16:
|
|
case CON_ROTATESPRITE:
|
|
insptr++;
|
|
{
|
|
int32_t x=Gv_GetVarX(*insptr++), y=Gv_GetVarX(*insptr++), z=Gv_GetVarX(*insptr++);
|
|
int32_t a=Gv_GetVarX(*insptr++), tilenum=Gv_GetVarX(*insptr++), shade=Gv_GetVarX(*insptr++);
|
|
int32_t pal=Gv_GetVarX(*insptr++), orientation=Gv_GetVarX(*insptr++);
|
|
int32_t x1=Gv_GetVarX(*insptr++), y1=Gv_GetVarX(*insptr++);
|
|
int32_t x2=Gv_GetVarX(*insptr++), y2=Gv_GetVarX(*insptr++);
|
|
|
|
if (tw == CON_ROTATESPRITE && !(orientation & 256)) {x<<=16; y<<=16;}
|
|
rotatesprite(x,y,z,a,tilenum,shade,pal,2|orientation,x1,y1,x2,y2);
|
|
continue;
|
|
}
|
|
|
|
case CON_SETGAMEPALETTE:
|
|
insptr++;
|
|
switch (Gv_GetVarX(*insptr++))
|
|
{
|
|
default:
|
|
case 0: SetGAMEPalette(); break;
|
|
case 1: SetWATERPalette(); break;
|
|
case 2: SetSLIMEPalette(); break;
|
|
case 3: SetBOSS1Palette(); break;
|
|
}
|
|
continue;
|
|
|
|
// *** sounds
|
|
case CON_IFSOUND:
|
|
insptr++;
|
|
{
|
|
int32_t j=Gv_GetVarX(*insptr);
|
|
if (j<0 || j>=MAXSOUNDS)
|
|
{
|
|
M32_ERROR("Invalid sound %d", j);
|
|
insptr++;
|
|
continue;
|
|
}
|
|
VM_DoConditional(S_CheckSoundPlaying(vm.g_i,j));
|
|
}
|
|
continue;
|
|
|
|
case CON_IFNOSOUNDS:
|
|
{
|
|
int32_t j = MAXSOUNDS-1;
|
|
for (; j>=0; j--)
|
|
if (g_sounds[j].SoundOwner[0].i == vm.g_i)
|
|
break;
|
|
|
|
VM_DoConditional(j < 0);
|
|
}
|
|
continue;
|
|
|
|
case CON_IFIN3DMODE:
|
|
VM_DoConditional(qsetmode==200);
|
|
continue;
|
|
|
|
// ifaimingsprite and -wall also work in 2d mode, but you must "and" with 16383 yourself
|
|
case CON_IFAIMINGSPRITE:
|
|
VM_DoConditional(AIMING_AT_SPRITE || (qsetmode!=200 && pointhighlight>=16384));
|
|
continue;
|
|
case CON_IFAIMINGWALL:
|
|
VM_DoConditional(AIMING_AT_WALL_OR_MASK || (qsetmode!=200 && linehighlight>=0));
|
|
continue;
|
|
case CON_IFAIMINGSECTOR:
|
|
VM_DoConditional(AIMING_AT_CEILING_OR_FLOOR);
|
|
continue;
|
|
case CON_IFINTERACTIVE:
|
|
VM_DoConditional(vm.miscflags&VMFLAG_MISC_INTERACTIVE);
|
|
continue;
|
|
|
|
case CON_GETSOUNDFLAGS:
|
|
insptr++;
|
|
{
|
|
int32_t j=Gv_GetVarX(*insptr++), var=*insptr++;
|
|
if (j<0 || j>=MAXSOUNDS)
|
|
{
|
|
M32_ERROR("Invalid sound %d", j);
|
|
insptr++;
|
|
continue;
|
|
}
|
|
|
|
Gv_SetVarX(var, g_sounds[j].m);
|
|
}
|
|
continue;
|
|
|
|
case CON_SOUNDVAR:
|
|
case CON_STOPSOUNDVAR:
|
|
case CON_SOUNDONCEVAR:
|
|
case CON_GLOBALSOUNDVAR:
|
|
insptr++;
|
|
{
|
|
int32_t j=Gv_GetVarX(*insptr++);
|
|
|
|
if (j<0 || j>=MAXSOUNDS)
|
|
{
|
|
M32_ERROR("Invalid sound %d", j);
|
|
continue;
|
|
}
|
|
|
|
switch (tw)
|
|
{
|
|
case CON_SOUNDONCEVAR:
|
|
if (!S_CheckSoundPlaying(vm.g_i,j))
|
|
A_PlaySound((int16_t)j,vm.g_i);
|
|
break;
|
|
case CON_GLOBALSOUNDVAR:
|
|
A_PlaySound((int16_t)j,-1);
|
|
break;
|
|
case CON_STOPSOUNDVAR:
|
|
if (S_CheckSoundPlaying(vm.g_i,j))
|
|
S_StopSound((int16_t)j);
|
|
break;
|
|
case CON_SOUNDVAR:
|
|
A_PlaySound((int16_t)j,vm.g_i);
|
|
break;
|
|
}
|
|
}
|
|
continue;
|
|
|
|
case CON_STOPALLSOUNDS:
|
|
insptr++;
|
|
FX_StopAllSounds();
|
|
continue;
|
|
|
|
default:
|
|
VM_ScriptInfo();
|
|
|
|
OSD_Printf("\nAn error has occurred in the Mapster32 virtual machine.\n\n"
|
|
"Please e-mail the file mapster32.log along with every M32 file\n"
|
|
"you're using and instructions how to reproduce this error to\n"
|
|
"helixhorned@gmail.com.\n\n"
|
|
"Thank you!");
|
|
vm.flags |= VMFLAG_ERROR;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|