mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-24 10:40:46 +00:00
ee4d060b1f
- sethighlightsector <sectnum> <on?> - updatehighlightsector - collectsectors <<array_to_collect_sectnums>> <initial_sector> <<num_collected_sectors>> <sector_filtering_state> The latter does a breadth-first search starting from an initial sector and collects nextsectors only when the filtering state, given a sectnum as RETURN input, writes a nonzero value into RETURN. As a usage example, a.m32 includes the state 'collect_teleporting_sectors', that collects all sectors containing an SE7 and highlights them afterwards. This way, it should be possible to retrofit old maps with TROR by distributing small scripts that do most of the work (right now, joining has to be done by hand, though). * corruption checker: for the 'nextwall inconsistent with nextsector' corruption, suggest an alternative fix by searching fitting nextwalls and changing the nextwall of the corrupt wall (as opposed to the nextsector). It will display with a leading '?' in the listing, and can be demanded by suffixing 'corruptcheck tryfix' with it. For example, corruptcheck tryfix 9-21 ? would fix some corruptions in Billy Boy's cranium.map without introducing drawing errors. * fix demo playback (tueidj figured this out) git-svn-id: https://svn.eduke32.com/eduke32@1927 1a8010ca-5511-0410-912e-c29ae57300e0
3066 lines
100 KiB
C
3066 lines
100 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,
|
|
0,
|
|
NULL,
|
|
0,
|
|
0,
|
|
0
|
|
};
|
|
|
|
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 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));
|
|
}
|
|
|
|
if (vm.updatehighlight)
|
|
{
|
|
update_highlight();
|
|
vm.updatehighlight = 0;
|
|
}
|
|
|
|
if (vm.updatehighlightsector)
|
|
{
|
|
update_highlightsector();
|
|
ovh_whiteoutgrab(1);
|
|
vm.updatehighlightsector = 0;
|
|
}
|
|
|
|
// 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);
|
|
//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)INT_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.updatehighlight = 1;
|
|
|
|
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.updatehighlightsector = 1;
|
|
|
|
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:
|
|
case CON_GETNUMBER256:
|
|
insptr++;
|
|
{
|
|
int32_t var=*insptr++, quote=*insptr++;
|
|
const char *quotetext = GetMaybeInlineQuote(quote);
|
|
if (vm.flags&VMFLAG_ERROR)
|
|
continue;
|
|
|
|
{
|
|
int32_t max=Gv_GetVarX(*insptr++), sign=(max<=0);
|
|
char buf[64]; // buffers in getnumber* are 80 bytes long
|
|
|
|
// no danger of accessing unallocated memory since we took care in C_SetScriptSize()
|
|
Bmemcpy(buf, quotetext, sizeof(buf));
|
|
buf[sizeof(buf)-1]='\0';
|
|
|
|
if (max==0)
|
|
max = INT_MAX;
|
|
|
|
//OSD_Printf("max:%d, sign:%d\n", max, sign);
|
|
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_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;
|
|
}
|