mirror of
https://github.com/ZDoom/acc.git
synced 2024-12-01 16:01:46 +00:00
9ae0c430ba
SVN r3889 (trunk)
1546 lines
35 KiB
C
1546 lines
35 KiB
C
|
|
//**************************************************************************
|
|
//**
|
|
//** pcode.c
|
|
//**
|
|
//**************************************************************************
|
|
|
|
// HEADER FILES ------------------------------------------------------------
|
|
|
|
#include <string.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include "pcode.h"
|
|
#include "common.h"
|
|
#include "error.h"
|
|
#include "misc.h"
|
|
#include "strlist.h"
|
|
#include "token.h"
|
|
#include "symbol.h"
|
|
#include "parse.h"
|
|
|
|
// MACROS ------------------------------------------------------------------
|
|
|
|
// TYPES -------------------------------------------------------------------
|
|
|
|
typedef struct scriptInfo_s
|
|
{
|
|
S_WORD number;
|
|
U_BYTE type;
|
|
U_BYTE argCount;
|
|
U_WORD varCount;
|
|
U_WORD flags;
|
|
int address;
|
|
int srcLine;
|
|
boolean imported;
|
|
} scriptInfo_t;
|
|
|
|
typedef struct functionInfo_s
|
|
{
|
|
U_BYTE hasReturnValue;
|
|
U_BYTE argCount;
|
|
U_BYTE localCount;
|
|
int address;
|
|
int name;
|
|
} functionInfo_t;
|
|
|
|
typedef struct mapVarInfo_s
|
|
{
|
|
int initializer;
|
|
boolean isString;
|
|
char *name;
|
|
boolean imported;
|
|
} mapVarInfo_t;
|
|
|
|
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
|
|
|
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
|
|
|
|
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
|
|
|
|
static void GrowBuffer(void);
|
|
static void Append(void *buffer, size_t size);
|
|
static void Write(void *buffer, size_t size, int address);
|
|
static void Skip(size_t size);
|
|
static void CloseOld(void);
|
|
static void CloseNew(void);
|
|
static void CreateDummyScripts(void);
|
|
static void RecordDummyScripts(void);
|
|
|
|
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
|
|
|
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
|
|
|
int pc_Address;
|
|
byte *pc_Buffer;
|
|
byte *pc_BufferPtr;
|
|
int pc_ScriptCount;
|
|
int pc_FunctionCount;
|
|
boolean pc_NoShrink;
|
|
boolean pc_HexenCase;
|
|
boolean pc_EnforceHexen;
|
|
boolean pc_WarnNotHexen;
|
|
boolean pc_WadAuthor = TRUE;
|
|
boolean pc_EncryptStrings;
|
|
int pc_LastAppendedCommand;
|
|
int pc_DummyAddress;
|
|
|
|
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
|
|
|
static size_t BufferSize;
|
|
static boolean ObjectOpened = NO;
|
|
static scriptInfo_t ScriptInfo[MAX_SCRIPT_COUNT];
|
|
static functionInfo_t FunctionInfo[MAX_FUNCTION_COUNT];
|
|
static int ArraySizes[MAX_MAP_VARIABLES];
|
|
static int *ArrayInits[MAX_MAP_VARIABLES];
|
|
static boolean ArrayOfStrings[MAX_MAP_VARIABLES];
|
|
static int NumArrays;
|
|
static mapVarInfo_t MapVariables[MAX_MAP_VARIABLES];
|
|
static boolean MapVariablesInit = NO;
|
|
static char ObjectName[MAX_FILE_NAME_LENGTH];
|
|
static int ObjectFlags;
|
|
static int PushByteAddr;
|
|
static char Imports[MAX_IMPORTS][9];
|
|
static int NumImports;
|
|
static boolean HaveExtendedScripts;
|
|
|
|
static char *PCDNames[PCODE_COMMAND_COUNT] =
|
|
{
|
|
"PCD_NOP",
|
|
"PCD_TERMINATE",
|
|
"PCD_SUSPEND",
|
|
"PCD_PUSHNUMBER",
|
|
"PCD_LSPEC1",
|
|
"PCD_LSPEC2",
|
|
"PCD_LSPEC3",
|
|
"PCD_LSPEC4",
|
|
"PCD_LSPEC5",
|
|
"PCD_LSPEC1DIRECT",
|
|
"PCD_LSPEC2DIRECT",
|
|
"PCD_LSPEC3DIRECT",
|
|
"PCD_LSPEC4DIRECT",
|
|
"PCD_LSPEC5DIRECT",
|
|
"PCD_ADD",
|
|
"PCD_SUBTRACT",
|
|
"PCD_MULTIPLY",
|
|
"PCD_DIVIDE",
|
|
"PCD_MODULUS",
|
|
"PCD_EQ",
|
|
"PCD_NE",
|
|
"PCD_LT",
|
|
"PCD_GT",
|
|
"PCD_LE",
|
|
"PCD_GE",
|
|
"PCD_ASSIGNSCRIPTVAR",
|
|
"PCD_ASSIGNMAPVAR",
|
|
"PCD_ASSIGNWORLDVAR",
|
|
"PCD_PUSHSCRIPTVAR",
|
|
"PCD_PUSHMAPVAR",
|
|
"PCD_PUSHWORLDVAR",
|
|
"PCD_ADDSCRIPTVAR",
|
|
"PCD_ADDMAPVAR",
|
|
"PCD_ADDWORLDVAR",
|
|
"PCD_SUBSCRIPTVAR",
|
|
"PCD_SUBMAPVAR",
|
|
"PCD_SUBWORLDVAR",
|
|
"PCD_MULSCRIPTVAR",
|
|
"PCD_MULMAPVAR",
|
|
"PCD_MULWORLDVAR",
|
|
"PCD_DIVSCRIPTVAR",
|
|
"PCD_DIVMAPVAR",
|
|
"PCD_DIVWORLDVAR",
|
|
"PCD_MODSCRIPTVAR",
|
|
"PCD_MODMAPVAR",
|
|
"PCD_MODWORLDVAR",
|
|
"PCD_INCSCRIPTVAR",
|
|
"PCD_INCMAPVAR",
|
|
"PCD_INCWORLDVAR",
|
|
"PCD_DECSCRIPTVAR",
|
|
"PCD_DECMAPVAR",
|
|
"PCD_DECWORLDVAR",
|
|
"PCD_GOTO",
|
|
"PCD_IFGOTO",
|
|
"PCD_DROP",
|
|
"PCD_DELAY",
|
|
"PCD_DELAYDIRECT",
|
|
"PCD_RANDOM",
|
|
"PCD_RANDOMDIRECT",
|
|
"PCD_THINGCOUNT",
|
|
"PCD_THINGCOUNTDIRECT",
|
|
"PCD_TAGWAIT",
|
|
"PCD_TAGWAITDIRECT",
|
|
"PCD_POLYWAIT",
|
|
"PCD_POLYWAITDIRECT",
|
|
"PCD_CHANGEFLOOR",
|
|
"PCD_CHANGEFLOORDIRECT",
|
|
"PCD_CHANGECEILING",
|
|
"PCD_CHANGECEILINGDIRECT",
|
|
"PCD_RESTART",
|
|
"PCD_ANDLOGICAL",
|
|
"PCD_ORLOGICAL",
|
|
"PCD_ANDBITWISE",
|
|
"PCD_ORBITWISE",
|
|
"PCD_EORBITWISE",
|
|
"PCD_NEGATELOGICAL",
|
|
"PCD_LSHIFT",
|
|
"PCD_RSHIFT",
|
|
"PCD_UNARYMINUS",
|
|
"PCD_IFNOTGOTO",
|
|
"PCD_LINESIDE",
|
|
"PCD_SCRIPTWAIT",
|
|
"PCD_SCRIPTWAITDIRECT",
|
|
"PCD_CLEARLINESPECIAL",
|
|
"PCD_CASEGOTO",
|
|
"PCD_BEGINPRINT",
|
|
"PCD_ENDPRINT",
|
|
"PCD_PRINTSTRING",
|
|
"PCD_PRINTNUMBER",
|
|
"PCD_PRINTCHARACTER",
|
|
"PCD_PLAYERCOUNT",
|
|
"PCD_GAMETYPE",
|
|
"PCD_GAMESKILL",
|
|
"PCD_TIMER",
|
|
"PCD_SECTORSOUND",
|
|
"PCD_AMBIENTSOUND",
|
|
"PCD_SOUNDSEQUENCE",
|
|
"PCD_SETLINETEXTURE",
|
|
"PCD_SETLINEBLOCKING",
|
|
"PCD_SETLINESPECIAL",
|
|
"PCD_THINGSOUND",
|
|
"PCD_ENDPRINTBOLD",
|
|
// [RH] End of Hexen p-codes
|
|
"PCD_ACTIVATORSOUND",
|
|
"PCD_LOCALAMBIENTSOUND",
|
|
"PCD_SETLINEMONSTERBLOCKING",
|
|
// [BC] Start of new pcodes
|
|
"PCD_PLAYERBLUESKULL",
|
|
"PCD_PLAYERREDSKULL",
|
|
"PCD_PLAYERYELLOWSKULL",
|
|
"PCD_PLAYERMASTERSKULL",
|
|
"PCD_PLAYERBLUECARD",
|
|
"PCD_PLAYERREDCARD",
|
|
"PCD_PLAYERYELLOWCARD",
|
|
"PCD_PLAYERMASTERCARD",
|
|
"PCD_PLAYERBLACKSKULL",
|
|
"PCD_PLAYERSILVERSKULL",
|
|
"PCD_PLAYERGOLDSKULL",
|
|
"PCD_PLAYERBLACKCARD",
|
|
"PCD_PLAYERSILVERCARD",
|
|
"PCD_PLAYERONTEAM",
|
|
"PCD_PLAYERTEAM",
|
|
"PCD_PLAYERHEALTH",
|
|
"PCD_PLAYERARMORPOINTS",
|
|
"PCD_PLAYERFRAGS",
|
|
"PCD_PLAYEREXPERT",
|
|
"PCD_BLUETEAMCOUNT",
|
|
"PCD_REDTEAMCOUNT",
|
|
"PCD_BLUETEAMSCORE",
|
|
"PCD_REDTEAMSCORE",
|
|
"PCD_ISONEFLAGCTF",
|
|
"PCD_LSPEC6",
|
|
"PCD_LSPEC6DIRECT",
|
|
"PCD_PRINTNAME",
|
|
"PCD_MUSICCHANGE",
|
|
"PCD_CONSOLECOMMANDDIRECT",
|
|
"PCD_CONSOLECOMMAND",
|
|
"PCD_SINGLEPLAYER",
|
|
// [RH] End of Skull Tag p-codes
|
|
"PCD_FIXEDMUL",
|
|
"PCD_FIXEDDIV",
|
|
"PCD_SETGRAVITY",
|
|
"PCD_SETGRAVITYDIRECT",
|
|
"PCD_SETAIRCONTROL",
|
|
"PCD_SETAIRCONTROLDIRECT",
|
|
"PCD_CLEARINVENTORY",
|
|
"PCD_GIVEINVENTORY",
|
|
"PCD_GIVEINVENTORYDIRECT",
|
|
"PCD_TAKEINVENTORY",
|
|
"PCD_TAKEINVENTORYDIRECT",
|
|
"PCD_CHECKINVENTORY",
|
|
"PCD_CHECKINVENTORYDIRECT",
|
|
"PCD_SPAWN",
|
|
"PCD_SPAWNDIRECT",
|
|
"PCD_SPAWNSPOT",
|
|
"PCD_SPAWNSPOTDIRECT",
|
|
"PCD_SETMUSIC",
|
|
"PCD_SETMUSICDIRECT",
|
|
"PCD_LOCALSETMUSIC",
|
|
"PCD_LOCALSETMUSICDIRECT",
|
|
"PCD_PRINTFIXED",
|
|
"PCD_PRINTLOCALIZED",
|
|
"PCD_MOREHUDMESSAGE",
|
|
"PCD_OPTHUDMESSAGE",
|
|
"PCD_ENDHUDMESSAGE",
|
|
"PCD_ENDHUDMESSAGEBOLD",
|
|
"PCD_SETSTYLE",
|
|
"PCD_SETSTYLEDIRECT",
|
|
"PCD_SETFONT",
|
|
"PCD_SETFONTDIRECT",
|
|
"PCD_PUSHBYTE",
|
|
"PCD_LSPEC1DIRECTB",
|
|
"PCD_LSPEC2DIRECTB",
|
|
"PCD_LSPEC3DIRECTB",
|
|
"PCD_LSPEC4DIRECTB",
|
|
"PCD_LSPEC5DIRECTB",
|
|
"PCD_DELAYDIRECTB",
|
|
"PCD_RANDOMDIRECTB",
|
|
"PCD_PUSHBYTES",
|
|
"PCD_PUSH2BYTES",
|
|
"PCD_PUSH3BYTES",
|
|
"PCD_PUSH4BYTES",
|
|
"PCD_PUSH5BYTES",
|
|
"PCD_SETTHINGSPECIAL",
|
|
"PCD_ASSIGNGLOBALVAR",
|
|
"PCD_PUSHGLOBALVAR",
|
|
"PCD_ADDGLOBALVAR",
|
|
"PCD_SUBGLOBALVAR",
|
|
"PCD_MULGLOBALVAR",
|
|
"PCD_DIVGLOBALVAR",
|
|
"PCD_MODGLOBALVAR",
|
|
"PCD_INCGLOBALVAR",
|
|
"PCD_DECGLOBALVAR",
|
|
"PCD_FADETO",
|
|
"PCD_FADERANGE",
|
|
"PCD_CANCELFADE",
|
|
"PCD_PLAYMOVIE",
|
|
"PCD_SETFLOORTRIGGER",
|
|
"PCD_SETCEILINGTRIGGER",
|
|
"PCD_GETACTORX",
|
|
"PCD_GETACTORY",
|
|
"PCD_GETACTORZ",
|
|
"PCD_STARTTRANSLATION",
|
|
"PCD_TRANSLATIONRANGE1",
|
|
"PCD_TRANSLATIONRANGE2",
|
|
"PCD_ENDTRANSLATION",
|
|
"PCD_CALL",
|
|
"PCD_CALLDISCARD",
|
|
"PCD_RETURNVOID",
|
|
"PCD_RETURNVAL",
|
|
"PCD_PUSHMAPARRAY",
|
|
"PCD_ASSIGNMAPARRAY",
|
|
"PCD_ADDMAPARRAY",
|
|
"PCD_SUBMAPARRAY",
|
|
"PCD_MULMAPARRAY",
|
|
"PCD_DIVMAPARRAY",
|
|
"PCD_MODMAPARRAY",
|
|
"PCD_INCMAPARRAY",
|
|
"PCD_DECMAPARRAY",
|
|
"PCD_DUP",
|
|
"PCD_SWAP",
|
|
"PCD_WRITETOINI",
|
|
"PCD_GETFROMINI",
|
|
"PCD_SIN",
|
|
"PCD_COS",
|
|
"PCD_VECTORANGLE",
|
|
"PCD_CHECKWEAPON",
|
|
"PCD_SETWEAPON",
|
|
"PCD_TAGSTRING",
|
|
"PCD_PUSHWORLDARRAY",
|
|
"PCD_ASSIGNWORLDARRAY",
|
|
"PCD_ADDWORLDARRAY",
|
|
"PCD_SUBWORLDARRAY",
|
|
"PCD_MULWORLDARRAY",
|
|
"PCD_DIVWORLDARRAY",
|
|
"PCD_MODWORLDARRAY",
|
|
"PCD_INCWORLDARRAY",
|
|
"PCD_DECWORLDARRAY",
|
|
"PCD_PUSHGLOBALARRAY",
|
|
"PCD_ASSIGNGLOBALARRAY",
|
|
"PCD_ADDGLOBALARRAY",
|
|
"PCD_SUBGLOBALARRAY",
|
|
"PCD_MULGLOBALARRAY",
|
|
"PCD_DIVGLOBALARRAY",
|
|
"PCD_MODGLOBALARRAY",
|
|
"PCD_INCGLOBALARRAY",
|
|
"PCD_DECGLOBALARRAY",
|
|
"PCD_SETMARINEWEAPON",
|
|
"PCD_SETACTORPROPERTY",
|
|
"PCD_GETACTORPROPERTY",
|
|
"PCD_PLAYERNUMBER",
|
|
"PCD_ACTIVATORTID",
|
|
"PCD_SETMARINESPRITE",
|
|
"PCD_GETSCREENWIDTH",
|
|
"PCD_GETSCREENHEIGHT",
|
|
"PCD_THING_PROJECTILE2",
|
|
"PCD_STRLEN",
|
|
"PCD_SETHUDSIZE",
|
|
"PCD_GETCVAR",
|
|
"PCD_CASEGOTOSORTED",
|
|
"PCD_SETRESULTVALUE",
|
|
"PCD_GETLINEROWOFFSET",
|
|
"PCD_GETACTORFLOORZ",
|
|
"PCD_GETACTORANGLE",
|
|
"PCD_GETSECTORFLOORZ",
|
|
"PCD_GETSECTORCEILINGZ",
|
|
"PCD_LSPEC5RESULT",
|
|
"PCD_GETSIGILPIECES",
|
|
"PCD_GELEVELINFO",
|
|
"PCD_CHANGESKY",
|
|
"PCD_PLAYERINGAME",
|
|
"PCD_PLAYERISBOT",
|
|
"PCD_SETCAMERATOTEXTURE",
|
|
"PCD_ENDLOG",
|
|
"PCD_GETAMMOCAPACITY",
|
|
"PCD_SETAMMOCAPACITY",
|
|
// [JB] start of new pcodes
|
|
"PCD_PRINTMAPCHARARRAY",
|
|
"PCD_PRINTWORLDCHARARRAY",
|
|
"PCD_PRINTGLOBALCHARARRAY",
|
|
// [JB] end of new pcodes
|
|
"PCD_SETACTORANGLE",
|
|
"PCD_GRABINPUT",
|
|
"PCD_SETMOUSEPOINTER",
|
|
"PCD_MOVEMOUSEPOINTER",
|
|
"PCD_SPAWNPROJECTILE",
|
|
"PCD_GETSECTORLIGHTLEVEL",
|
|
"PCD_GETACTORCEILINGZ",
|
|
"PCD_SETACTORPOSITION",
|
|
"PCD_CLEARACTORINVENTORY",
|
|
"PCD_GIVEACTORINVENTORY",
|
|
"PCD_TAKEACTORINVENTORY",
|
|
"PCD_CHECKACTORINVENTORY",
|
|
"PCD_THINGCOUNTNAME",
|
|
"PCD_SPAWNSPOTFACING",
|
|
"PCD_PLAYERCLASS",
|
|
//[MW] start my p-codes
|
|
"PCD_ANDSCRIPTVAR",
|
|
"PCD_ANDMAPVAR",
|
|
"PCD_ANDWORLDVAR",
|
|
"PCD_ANDGLOBALVAR",
|
|
"PCD_ANDMAPARRAY",
|
|
"PCD_ANDWORLDARRAY",
|
|
"PCD_ANDGLOBALARRAY",
|
|
"PCD_EORSCRIPTVAR",
|
|
"PCD_EORMAPVAR",
|
|
"PCD_EORWORLDVAR",
|
|
"PCD_EORGLOBALVAR",
|
|
"PCD_EORMAPARRAY",
|
|
"PCD_EORWORLDARRAY",
|
|
"PCD_EORGLOBALARRAY",
|
|
"PCD_ORSCRIPTVAR",
|
|
"PCD_ORMAPVAR",
|
|
"PCD_ORWORLDVAR",
|
|
"PCD_ORGLOBALVAR",
|
|
"PCD_ORMAPARRAY",
|
|
"PCD_ORWORLDARRAY",
|
|
"PCD_ORGLOBALARRAY",
|
|
"PCD_LSSCRIPTVAR",
|
|
"PCD_LSMAPVAR",
|
|
"PCD_LSWORLDVAR",
|
|
"PCD_LSGLOBALVAR",
|
|
"PCD_LSMAPARRAY",
|
|
"PCD_LSWORLDARRAY",
|
|
"PCD_LSGLOBALARRAY",
|
|
"PCD_RSSCRIPTVAR",
|
|
"PCD_RSMAPVAR",
|
|
"PCD_RSWORLDVAR",
|
|
"PCD_RSGLOBALVAR",
|
|
"PCD_RSMAPARRAY",
|
|
"PCD_RSWORLDARRAY",
|
|
"PCD_RSGLOBALARRAY",
|
|
//[MW] end my p-codes
|
|
"PCD_GETPLAYERINFO",
|
|
"PCD_CHANGELEVEL",
|
|
"PCD_SECTORDAMAGE",
|
|
"PCD_REPLACETEXTURES",
|
|
"PCD_NEGATEBINARY",
|
|
"PCD_GETACTORPITCH",
|
|
"PCD_SETACTORPITCH",
|
|
"PCD_PRINTBIND",
|
|
"PCD_SETACTORSTATE",
|
|
"PCD_THINGDAMAGE2",
|
|
"PCD_USEINVENTORY",
|
|
"PCD_USEACTORINVENTORY",
|
|
"PCD_CHECKACTORCEILINGTEXTURE",
|
|
"PCD_CHECKACTORFLOORTEXTURE",
|
|
"PCD_GETACTORLIGHTLEVEL",
|
|
"PCD_SETMUGSHOTSTATE",
|
|
"PCD_THINGCOUNTSECTOR",
|
|
"PCD_THINGCOUNTNAMESECTOR",
|
|
"PCD_CHECKPLAYERCAMERA",
|
|
"PCD_MORPHACTOR",
|
|
"PCD_UNMORPHACTOR",
|
|
"PCD_GETPLAYERINPUT",
|
|
"PCD_CLASSIFYACTOR",
|
|
"PCD_PRINTBINARY",
|
|
"PCD_PRINTHEX",
|
|
"PCD_CALLFUNC",
|
|
"PCD_SAVESTRING", // [FDARI]
|
|
"PCD_PRINTMAPCHRANGE", // [FDARI] output range
|
|
"PCD_PRINTWORLDCHRANGE",
|
|
"PCD_PRINTGLOBALCHRANGE",
|
|
"PCD_STRCPYTOMAPCHRANGE", // [FDARI] input range
|
|
"PCD_STRCPYTOWORLDCHRANGE",
|
|
"PCD_STRCPYTOGLOBALCHRANGE",
|
|
"PCD_PUSHFUNCTION", // from Eternity
|
|
"PCD_CALLSTACK", // from Eternity
|
|
"PCD_SCRIPTWAITNAMED",
|
|
"PCD_TRANSLATIONRANGE3",
|
|
};
|
|
|
|
// CODE --------------------------------------------------------------------
|
|
|
|
//==========================================================================
|
|
//
|
|
// PC_OpenObject
|
|
//
|
|
//==========================================================================
|
|
|
|
void PC_OpenObject(char *name, size_t size, int flags)
|
|
{
|
|
if(ObjectOpened == YES)
|
|
{
|
|
PC_CloseObject();
|
|
}
|
|
if(strlen(name) >= MAX_FILE_NAME_LENGTH)
|
|
{
|
|
ERR_Exit(ERR_FILE_NAME_TOO_LONG, NO, name);
|
|
}
|
|
strcpy(ObjectName, name);
|
|
pc_Buffer = MS_Alloc(size, ERR_ALLOC_PCODE_BUFFER);
|
|
pc_BufferPtr = pc_Buffer;
|
|
pc_Address = 0;
|
|
ObjectFlags = flags;
|
|
BufferSize = size;
|
|
pc_ScriptCount = 0;
|
|
ObjectOpened = YES;
|
|
PC_AppendString("ACS");
|
|
PC_SkipInt(); // Script table offset
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// PC_CloseObject
|
|
//
|
|
//==========================================================================
|
|
|
|
void PC_CloseObject(void)
|
|
{
|
|
MS_Message(MSG_DEBUG, "---- PC_CloseObject ----\n");
|
|
while (pc_Address & 3)
|
|
{
|
|
PC_AppendByte (0);
|
|
}
|
|
if(!pc_NoShrink || (NumLanguages > 1) || (NumStringLists > 0) ||
|
|
(pc_FunctionCount > 0) || MapVariablesInit || NumArrays != 0 ||
|
|
pc_EncryptStrings || NumImports != 0 || HaveExtendedScripts)
|
|
{
|
|
if(pc_EnforceHexen)
|
|
{
|
|
ERR_Exit(ERR_NOT_HEXEN, NO);
|
|
}
|
|
if(pc_WarnNotHexen)
|
|
{
|
|
fprintf(stderr, "\nThese scripts have been upgraded because they use new features.\n"
|
|
"They will not be compatible with Hexen.\n");
|
|
}
|
|
CloseNew();
|
|
}
|
|
else
|
|
{
|
|
CloseOld();
|
|
}
|
|
if(MS_SaveFile(ObjectName, pc_Buffer, pc_Address) == FALSE)
|
|
{
|
|
ERR_Exit(ERR_SAVE_OBJECT_FAILED, NO);
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// CloseOld
|
|
//
|
|
//==========================================================================
|
|
|
|
static void CloseOld(void)
|
|
{
|
|
int i;
|
|
|
|
STR_WriteStrings();
|
|
PC_WriteInt((U_INT)pc_Address, 4);
|
|
PC_AppendInt((U_INT)pc_ScriptCount);
|
|
for(i = 0; i < pc_ScriptCount; ++i)
|
|
{
|
|
scriptInfo_t *info = &ScriptInfo[i];
|
|
MS_Message(MSG_DEBUG, "Script %d, address = %d, arg count = %d\n",
|
|
info->number, info->address, info->argCount);
|
|
PC_AppendInt((U_INT)(info->number + info->type * 1000));
|
|
PC_AppendInt((U_INT)info->address);
|
|
PC_AppendInt((U_INT)info->argCount);
|
|
}
|
|
STR_WriteList();
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// CloseNew
|
|
//
|
|
// Creates a new-format ACS file. For programs that don't know any better,
|
|
// this will look just like an old ACS file with no scripts or strings but
|
|
// with some extra junk in the middle. Both WadAuthor and DeePsea will not
|
|
// accept ACS files that do not have the ACS\0 header. Worse, WadAuthor
|
|
// will hang if the file begins with ACS\0 but does not look like something
|
|
// that might have been created with Raven's ACC. Thus, the chunks live in
|
|
// the string block, and there are two 0 dwords at the end of the file.
|
|
//
|
|
//==========================================================================
|
|
|
|
static void CloseNew(void)
|
|
{
|
|
int i, j, count;
|
|
int chunkStart;
|
|
|
|
if(pc_WadAuthor)
|
|
{
|
|
CreateDummyScripts();
|
|
}
|
|
|
|
chunkStart = pc_Address;
|
|
|
|
// Only write out those scripts that this acs file actually provides.
|
|
for(i = j = 0; i < pc_ScriptCount; ++i)
|
|
{
|
|
if(!ScriptInfo[i].imported)
|
|
{
|
|
++j;
|
|
}
|
|
}
|
|
if(j > 0)
|
|
{
|
|
PC_Append("SPTR", 4);
|
|
PC_AppendInt(j * 8);
|
|
for(i = 0; i < pc_ScriptCount; i++)
|
|
{
|
|
scriptInfo_t *info = &ScriptInfo[i];
|
|
if(!info->imported)
|
|
{
|
|
MS_Message(MSG_DEBUG, "Script %d, address = %d, arg count = %d\n",
|
|
info->number, info->address, info->argCount);
|
|
PC_AppendWord(info->number);
|
|
PC_AppendByte(info->type);
|
|
PC_AppendByte(info->argCount);
|
|
PC_AppendInt((U_INT)info->address);
|
|
}
|
|
}
|
|
}
|
|
|
|
// If any scripts have more than the maximum number of arguments, output them.
|
|
for(i = j = 0; i < pc_ScriptCount; ++i)
|
|
{
|
|
if(!ScriptInfo[i].imported && ScriptInfo[i].varCount > MAX_SCRIPT_VARIABLES)
|
|
{
|
|
++j;
|
|
}
|
|
}
|
|
if(j > 0)
|
|
{
|
|
PC_Append("SVCT", 4);
|
|
PC_AppendInt(j * 4);
|
|
for(i = 0; i < pc_ScriptCount; ++i)
|
|
{
|
|
scriptInfo_t *info = &ScriptInfo[i];
|
|
if(!info->imported && info->varCount > MAX_SCRIPT_VARIABLES)
|
|
{
|
|
MS_Message(MSG_DEBUG, "Script %d, var count = %d\n",
|
|
info->number, info->varCount);
|
|
PC_AppendWord(info->number);
|
|
PC_AppendWord(info->varCount);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Write script flags in a separate chunk, so older ZDooms don't get confused
|
|
for(i = j = 0; i < pc_ScriptCount; ++i)
|
|
{
|
|
if(!ScriptInfo[i].imported && ScriptInfo[i].flags != 0)
|
|
{
|
|
++j;
|
|
}
|
|
}
|
|
if (j > 0)
|
|
{
|
|
PC_Append("SFLG", 4);
|
|
PC_AppendInt(j * 4);
|
|
for(i = 0; i < pc_ScriptCount; ++i)
|
|
{
|
|
scriptInfo_t *info = &ScriptInfo[i];
|
|
if(!info->imported && info->flags != 0)
|
|
{
|
|
PC_AppendWord(info->number);
|
|
PC_AppendWord(info->flags);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Write the string table for named scripts.
|
|
STR_WriteListChunk(STRLIST_NAMEDSCRIPTS, MAKE4CC('S','N','A','M'), NO);
|
|
|
|
if(pc_FunctionCount > 0)
|
|
{
|
|
PC_Append("FUNC", 4);
|
|
PC_AppendInt(pc_FunctionCount * 8);
|
|
for(i = 0; i < pc_FunctionCount; ++i)
|
|
{
|
|
functionInfo_t *info = &FunctionInfo[i];
|
|
MS_Message(MSG_DEBUG, "Function %d:%s, address = %d, arg count = %d, var count = %d\n",
|
|
i, STR_GetString(STRLIST_FUNCTIONS, info->name),
|
|
info->address, info->argCount, info->localCount);
|
|
PC_AppendByte(info->argCount);
|
|
PC_AppendByte(info->localCount);
|
|
PC_AppendByte((U_BYTE)(info->hasReturnValue?1:0));
|
|
PC_AppendByte(0);
|
|
PC_AppendInt((U_INT)info->address);
|
|
}
|
|
STR_WriteListChunk(STRLIST_FUNCTIONS, MAKE4CC('F','N','A','M'), NO);
|
|
}
|
|
|
|
if(NumLanguages > 1)
|
|
{
|
|
for(i = 0; i < NumLanguages; i++)
|
|
{
|
|
STR_WriteChunk(i, pc_EncryptStrings);
|
|
}
|
|
}
|
|
else if(STR_ListSize(0) > 0)
|
|
{
|
|
STR_WriteChunk(0, pc_EncryptStrings);
|
|
}
|
|
|
|
STR_WriteListChunk(STRLIST_PICS, MAKE4CC('P','I','C','S'), NO);
|
|
if(MapVariablesInit)
|
|
{
|
|
int j;
|
|
|
|
for(i = 0; i < pa_MapVarCount; ++i)
|
|
{
|
|
if(MapVariables[i].initializer != 0)
|
|
break;
|
|
}
|
|
for(j = pa_MapVarCount-1; j > i; --j)
|
|
{
|
|
if(MapVariables[j].initializer != 0)
|
|
break;
|
|
}
|
|
++j;
|
|
|
|
if (i < j)
|
|
{
|
|
PC_Append("MINI", 4);
|
|
PC_AppendInt((j-i)*4+4);
|
|
PC_AppendInt(i); // First map var defined
|
|
for(; i < j; ++i)
|
|
{
|
|
PC_AppendInt(MapVariables[i].initializer);
|
|
}
|
|
}
|
|
}
|
|
|
|
// If this is a library, record which map variables are
|
|
// initialized with strings.
|
|
if(ImportMode == IMPORT_Exporting)
|
|
{
|
|
count = 0;
|
|
|
|
for(i = 0; i < pa_MapVarCount; ++i)
|
|
{
|
|
if(MapVariables[i].isString)
|
|
{
|
|
++count;
|
|
}
|
|
}
|
|
if(count > 0)
|
|
{
|
|
PC_Append("MSTR", 4);
|
|
PC_AppendInt(count*4);
|
|
for(i = 0; i < pa_MapVarCount; ++i)
|
|
{
|
|
if(MapVariables[i].isString)
|
|
{
|
|
PC_AppendInt(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now do the same thing for arrays.
|
|
for(count = 0, i = 0; i < pa_MapVarCount; ++i)
|
|
{
|
|
if(ArrayOfStrings[i])
|
|
{
|
|
++count;
|
|
}
|
|
}
|
|
if(count > 0)
|
|
{
|
|
PC_Append("ASTR", 4);
|
|
PC_AppendInt(count*4);
|
|
for(i = 0; i < pa_MapVarCount; ++i)
|
|
{
|
|
if(ArrayOfStrings[i])
|
|
{
|
|
PC_AppendInt(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Publicize the names of map variables in a library.
|
|
if(ImportMode == IMPORT_Exporting)
|
|
{
|
|
for(i = 0; i < pa_MapVarCount; ++i)
|
|
{
|
|
if(!MapVariables[i].imported)
|
|
{
|
|
STR_AppendToList(STRLIST_MAPVARS, MapVariables[i].name);
|
|
}
|
|
else
|
|
{
|
|
STR_AppendToList(STRLIST_MAPVARS, NULL);
|
|
}
|
|
}
|
|
STR_WriteListChunk(STRLIST_MAPVARS, MAKE4CC('M','E','X','P'), NO);
|
|
}
|
|
|
|
// Record the names of imported map variables
|
|
count = 0;
|
|
for(i = 0; i < pa_MapVarCount; ++i)
|
|
{
|
|
if(MapVariables[i].imported && !ArraySizes[i])
|
|
{
|
|
count += 5 + strlen(MapVariables[i].name);
|
|
}
|
|
}
|
|
if(count > 0)
|
|
{
|
|
PC_Append("MIMP", 4);
|
|
PC_AppendInt(count);
|
|
for(i = 0; i < pa_MapVarCount; ++i)
|
|
{
|
|
if(MapVariables[i].imported && !ArraySizes[i])
|
|
{
|
|
PC_AppendInt(i);
|
|
PC_AppendString(MapVariables[i].name);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(NumArrays)
|
|
{
|
|
int count;
|
|
|
|
// Arrays defined here
|
|
for(count = 0, i = 0; i < pa_MapVarCount; ++i)
|
|
{
|
|
if(ArraySizes[i] && !MapVariables[i].imported)
|
|
{
|
|
++count;
|
|
}
|
|
}
|
|
if(count)
|
|
{
|
|
PC_Append("ARAY", 4);
|
|
PC_AppendInt(count*8);
|
|
for(i = 0; i < pa_MapVarCount; ++i)
|
|
{
|
|
if(ArraySizes[i] && !MapVariables[i].imported)
|
|
{
|
|
PC_AppendInt(i);
|
|
PC_AppendInt(ArraySizes[i]);
|
|
}
|
|
}
|
|
for(i = 0; i < pa_MapVarCount; ++i)
|
|
{
|
|
if(ArrayInits[i])
|
|
{
|
|
int j;
|
|
|
|
PC_Append("AINI", 4);
|
|
PC_AppendInt(ArraySizes[i]*4+4);
|
|
PC_AppendInt((U_INT)i);
|
|
MS_Message(MSG_DEBUG, "Writing array initializers for array %d (size %d)\n", i, ArraySizes[i]);
|
|
for(j = 0; j < ArraySizes[i]; ++j)
|
|
{
|
|
PC_AppendInt((U_INT)ArrayInits[i][j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Arrays imported from elsewhere
|
|
for(count = 0, j = i = 0; i < pa_MapVarCount; ++i)
|
|
{
|
|
if(ArraySizes[i] && MapVariables[i].imported)
|
|
{
|
|
count += 9 + strlen(MapVariables[i].name);
|
|
++j;
|
|
}
|
|
}
|
|
if(count)
|
|
{
|
|
PC_Append("AIMP", 4);
|
|
PC_AppendInt(count+4);
|
|
PC_AppendInt(j);
|
|
for(i = 0; i < pa_MapVarCount; ++i)
|
|
{
|
|
if(ArraySizes[i] && MapVariables[i].imported)
|
|
{
|
|
PC_AppendInt(i);
|
|
PC_AppendInt(ArraySizes[i]);
|
|
PC_AppendString(MapVariables[i].name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add a dummy chunk to indicate if this object is a library.
|
|
if(ImportMode == IMPORT_Exporting)
|
|
{
|
|
PC_Append("ALIB", 4);
|
|
PC_AppendInt(0);
|
|
}
|
|
|
|
// Record libraries imported by this object.
|
|
if(NumImports > 0)
|
|
{
|
|
count = 0;
|
|
for(i = 0; i < NumImports; ++i)
|
|
{
|
|
count += strlen(Imports[i]) + 1;
|
|
}
|
|
if(count > 0)
|
|
{
|
|
PC_Append("LOAD", 4);
|
|
PC_AppendInt(count);
|
|
for(i = 0; i < NumImports; ++i)
|
|
{
|
|
PC_AppendString(Imports[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
PC_AppendInt((U_INT)chunkStart);
|
|
if(pc_NoShrink)
|
|
{
|
|
PC_Append("ACSE", 4);
|
|
}
|
|
else
|
|
{
|
|
PC_Append("ACSe", 4);
|
|
}
|
|
PC_WriteInt((U_INT)pc_Address, 4);
|
|
|
|
// WadAuthor compatibility when creating a library is pointless, because
|
|
// that editor does not know anything about libraries and will never
|
|
// find their scripts ever.
|
|
if(pc_WadAuthor && ImportMode != IMPORT_Exporting)
|
|
{
|
|
RecordDummyScripts();
|
|
}
|
|
else
|
|
{
|
|
PC_AppendInt(0);
|
|
}
|
|
PC_AppendInt(0);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// CreateDummyScripts
|
|
//
|
|
//==========================================================================
|
|
|
|
static void CreateDummyScripts(void)
|
|
{
|
|
int i;
|
|
|
|
MS_Message(MSG_DEBUG, "Creating dummy scripts to make WadAuthor happy.\n");
|
|
if(pc_Address%4 != 0)
|
|
{ // Need to align
|
|
U_INT pad = 0;
|
|
PC_Append((void *)&pad, 4-(pc_Address%4));
|
|
}
|
|
pc_DummyAddress = pc_Address;
|
|
for(i = 0; i < pc_ScriptCount; ++i)
|
|
{
|
|
// Only create dummies for scripts WadAuthor could care about.
|
|
if(!ScriptInfo[i].imported && ScriptInfo[i].number >= 0 && ScriptInfo[i].number <= 255)
|
|
{
|
|
PC_AppendCmd(PCD_TERMINATE);
|
|
if(!pc_NoShrink)
|
|
{
|
|
PC_AppendCmd(PCD_NOP);
|
|
PC_AppendCmd(PCD_NOP);
|
|
PC_AppendCmd(PCD_NOP);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// RecordDummyScripts
|
|
//
|
|
//==========================================================================
|
|
|
|
static void RecordDummyScripts(void)
|
|
{
|
|
int i, j, count;
|
|
|
|
for(i = count = 0; i < pc_ScriptCount; ++i)
|
|
{
|
|
if(!ScriptInfo[i].imported && ScriptInfo[i].number >= 0 && ScriptInfo[i].number <= 255)
|
|
{
|
|
++count;
|
|
}
|
|
}
|
|
PC_AppendInt((U_INT)count);
|
|
for(i = j = 0; i < pc_ScriptCount; ++i)
|
|
{
|
|
scriptInfo_t *info = &ScriptInfo[i];
|
|
if(!info->imported && info->number >= 0 && ScriptInfo[i].number <= 255)
|
|
{
|
|
MS_Message(MSG_DEBUG, "Dummy script %d, address = %d, arg count = %d\n",
|
|
info->number, info->address, info->argCount);
|
|
PC_AppendInt((U_INT)info->number);
|
|
PC_AppendInt((U_INT)pc_DummyAddress + j*4);
|
|
PC_AppendInt((U_INT)info->argCount);
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// GrowBuffer
|
|
//
|
|
//==========================================================================
|
|
|
|
void GrowBuffer(void)
|
|
{
|
|
ptrdiff_t buffpos = pc_BufferPtr - pc_Buffer;
|
|
|
|
BufferSize *= 2;
|
|
pc_Buffer = MS_Realloc(pc_Buffer, BufferSize, ERR_PCODE_BUFFER_OVERFLOW);
|
|
pc_BufferPtr = pc_Buffer + buffpos;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// PC_Append functions
|
|
//
|
|
//==========================================================================
|
|
|
|
static void Append(void *buffer, size_t size)
|
|
{
|
|
if (ImportMode != IMPORT_Importing)
|
|
{
|
|
if(pc_Address+size > BufferSize)
|
|
{
|
|
GrowBuffer ();
|
|
}
|
|
memcpy(pc_BufferPtr, buffer, size);
|
|
pc_BufferPtr += size;
|
|
pc_Address += size;
|
|
}
|
|
}
|
|
|
|
void PC_Append(void *buffer, size_t size)
|
|
{
|
|
if (ImportMode != IMPORT_Importing)
|
|
{
|
|
MS_Message(MSG_DEBUG, "AD> %06d = (%d bytes)\n", pc_Address, size);
|
|
Append(buffer, size);
|
|
}
|
|
}
|
|
|
|
void PC_AppendByte(U_BYTE val)
|
|
{
|
|
if (ImportMode != IMPORT_Importing)
|
|
{
|
|
MS_Message(MSG_DEBUG, "AB> %06d = %d\n", pc_Address, val);
|
|
Append(&val, sizeof(U_BYTE));
|
|
}
|
|
}
|
|
|
|
void PC_AppendWord(U_WORD val)
|
|
{
|
|
if (ImportMode != IMPORT_Importing)
|
|
{
|
|
MS_Message(MSG_DEBUG, "AW> %06d = %d\n", pc_Address, val);
|
|
val = MS_LittleUWORD(val);
|
|
Append(&val, sizeof(U_WORD));
|
|
}
|
|
}
|
|
|
|
void PC_AppendInt(U_INT val)
|
|
{
|
|
if (ImportMode != IMPORT_Importing)
|
|
{
|
|
MS_Message(MSG_DEBUG, "AL> %06d = %d\n", pc_Address, val);
|
|
val = MS_LittleUINT(val);
|
|
Append(&val, sizeof(U_INT));
|
|
}
|
|
}
|
|
|
|
void PC_AppendString(char *string)
|
|
{
|
|
if (ImportMode != IMPORT_Importing)
|
|
{
|
|
int length;
|
|
|
|
length = strlen(string)+1;
|
|
MS_Message(MSG_DEBUG, "AS> %06d = \"%s\" (%d bytes)\n",
|
|
pc_Address, string, length);
|
|
Append(string, length);
|
|
}
|
|
}
|
|
|
|
void PC_AppendCmd(pcd_t command)
|
|
{
|
|
boolean dupbyte = NO;
|
|
if (ImportMode != IMPORT_Importing)
|
|
{
|
|
pc_LastAppendedCommand = command;
|
|
if (pc_NoShrink)
|
|
{
|
|
MS_Message(MSG_DEBUG, "AC> %06d = #%d:%s\n", pc_Address,
|
|
command, PCDNames[command]);
|
|
command = MS_LittleUINT(command);
|
|
Append(&command, sizeof(U_INT));
|
|
}
|
|
else
|
|
{
|
|
U_BYTE cmd;
|
|
if (command == PCD_DUP && PushByteAddr)
|
|
{ // If the last instruction was PCD_PUSHBYTE, convert this PCD_DUP to a
|
|
// duplicate PCD_PUSHBYTE, so it can be merged into a single instruction below.
|
|
command = PCD_PUSHBYTE;
|
|
dupbyte = YES;
|
|
MS_Message(MSG_DEBUG, "AC> PCD_DUP changed to PCD_PUSHBYTE\n");
|
|
}
|
|
else if (command != PCD_PUSHBYTE && PushByteAddr)
|
|
{ // Maybe shrink a PCD_PUSHBYTE sequence into PCD_PUSHBYTES
|
|
int runlen = (pc_Address - PushByteAddr) / 2;
|
|
int i;
|
|
|
|
if (runlen > 5)
|
|
{
|
|
pc_Buffer[PushByteAddr] = PCD_PUSHBYTES;
|
|
for (i = 0; i < runlen; i++)
|
|
{
|
|
pc_Buffer[PushByteAddr+i+2] = pc_Buffer[PushByteAddr+i*2+1];
|
|
}
|
|
pc_Buffer[PushByteAddr+1] = runlen;
|
|
pc_Address = PushByteAddr + runlen + 2;
|
|
pc_BufferPtr = pc_Buffer + pc_Address;
|
|
MS_Message(MSG_DEBUG, "AC> Last %d PCD_PUSHBYTEs changed to #%d:PCD_PUSHBYTES\n",
|
|
runlen, PCD_PUSHBYTES);
|
|
}
|
|
else if (runlen > 1)
|
|
{
|
|
pc_Buffer[PushByteAddr] = PCD_PUSH2BYTES + runlen - 2;
|
|
for (i = 1; i < runlen; i++)
|
|
{
|
|
pc_Buffer[PushByteAddr+1+i] = pc_Buffer[PushByteAddr+1+i*2];
|
|
}
|
|
pc_Address = PushByteAddr + runlen + 1;
|
|
pc_BufferPtr = pc_Buffer + pc_Address;
|
|
MS_Message(MSG_DEBUG, "AC> Last %d PCD_PUSHBYTEs changed to #%d:PCD_PUSH%dBYTES\n",
|
|
runlen, PCD_PUSH2BYTES+runlen-2, runlen);
|
|
}
|
|
PushByteAddr = 0;
|
|
}
|
|
else if(command == PCD_PUSHBYTE && PushByteAddr == 0)
|
|
{ // Remember the first PCD_PUSHBYTE, in case there are more
|
|
PushByteAddr = pc_Address;
|
|
}
|
|
MS_Message(MSG_DEBUG, "AC> %06d = #%d:%s\n", pc_Address,
|
|
command, PCDNames[command]);
|
|
|
|
if (command < 256-16)
|
|
{
|
|
cmd = command;
|
|
Append(&cmd, sizeof(U_BYTE));
|
|
}
|
|
else
|
|
{
|
|
// Room for expansion: The top 16 pcodes in the [0,255]
|
|
// range select a set of pcodes, and the next byte is
|
|
// the pcode in that set.
|
|
cmd = ((command - (256-16)) >> 8) + (256-16);
|
|
Append(&cmd, sizeof(U_BYTE));
|
|
cmd = (command - (256-16)) & 255;
|
|
Append(&cmd, sizeof(U_BYTE));
|
|
}
|
|
if (dupbyte)
|
|
{
|
|
PC_AppendByte(pc_Buffer[pc_Address-2]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// PC_AppendShrink
|
|
//
|
|
//==========================================================================
|
|
|
|
void PC_AppendShrink(U_BYTE val)
|
|
{
|
|
if(pc_NoShrink)
|
|
{
|
|
PC_AppendInt(val);
|
|
}
|
|
else
|
|
{
|
|
PC_AppendByte(val);
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// PC_AppendPushVal
|
|
//
|
|
//==========================================================================
|
|
|
|
void PC_AppendPushVal(U_INT val)
|
|
{
|
|
if(pc_NoShrink || val > 255)
|
|
{
|
|
PC_AppendCmd(PCD_PUSHNUMBER);
|
|
PC_AppendInt(val);
|
|
}
|
|
else
|
|
{
|
|
PC_AppendCmd(PCD_PUSHBYTE);
|
|
PC_AppendByte((U_BYTE)val);
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// PC_Write functions
|
|
//
|
|
//==========================================================================
|
|
|
|
static void Write(void *buffer, size_t size, int address)
|
|
{
|
|
if (ImportMode != IMPORT_Importing)
|
|
{
|
|
if(address+size > BufferSize)
|
|
{
|
|
GrowBuffer();
|
|
}
|
|
memcpy(pc_Buffer+address, buffer, size);
|
|
}
|
|
}
|
|
|
|
void PC_Write(void *buffer, size_t size, int address)
|
|
{
|
|
if (ImportMode != IMPORT_Importing)
|
|
{
|
|
MS_Message(MSG_DEBUG, "WD> %06d = (%d bytes)\n", address, size);
|
|
Write(buffer, size, address);
|
|
}
|
|
}
|
|
|
|
void PC_WriteByte(U_BYTE val, int address)
|
|
{
|
|
if (ImportMode != IMPORT_Importing)
|
|
{
|
|
MS_Message(MSG_DEBUG, "WB> %06d = %d\n", address, val);
|
|
Write(&val, sizeof(U_BYTE), address);
|
|
}
|
|
}
|
|
|
|
/*
|
|
void PC_WriteWord(U_WORD val, int address)
|
|
{
|
|
MS_Message(MSG_DEBUG, "WW> %06d = %d\n", address, val);
|
|
val = MS_LittleUWORD(val);
|
|
Write(&val, sizeof(U_WORD), address);
|
|
}
|
|
*/
|
|
|
|
void PC_WriteInt(U_INT val, int address)
|
|
{
|
|
if (ImportMode != IMPORT_Importing)
|
|
{
|
|
MS_Message(MSG_DEBUG, "WL> %06d = %d\n", address, val);
|
|
val = MS_LittleUINT(val);
|
|
Write(&val, sizeof(U_INT), address);
|
|
}
|
|
pc_LastAppendedCommand = PCD_NOP;
|
|
}
|
|
|
|
void PC_WriteString(char *string, int address)
|
|
{
|
|
if (ImportMode != IMPORT_Importing)
|
|
{
|
|
int length;
|
|
|
|
length = strlen(string)+1;
|
|
MS_Message(MSG_DEBUG, "WS> %06d = \"%s\" (%d bytes)\n",
|
|
address, string, length);
|
|
Write(string, length, address);
|
|
}
|
|
}
|
|
|
|
void PC_WriteCmd(pcd_t command, int address)
|
|
{
|
|
if (ImportMode != IMPORT_Importing)
|
|
{
|
|
MS_Message(MSG_DEBUG, "WC> %06d = #%d:%s\n", address,
|
|
command, PCDNames[command]);
|
|
command = MS_LittleUINT(command);
|
|
Write(&command, sizeof(U_INT), address);
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// PC_Skip functions
|
|
//
|
|
//==========================================================================
|
|
|
|
static void Skip(size_t size)
|
|
{
|
|
if (ImportMode != IMPORT_Importing)
|
|
{
|
|
if(pc_Address+size > BufferSize)
|
|
{
|
|
GrowBuffer();
|
|
}
|
|
pc_BufferPtr += size;
|
|
pc_Address += size;
|
|
}
|
|
}
|
|
|
|
void PC_Skip(size_t size)
|
|
{
|
|
if (ImportMode != IMPORT_Importing)
|
|
{
|
|
MS_Message(MSG_DEBUG, "SD> %06d (skip %d bytes)\n", pc_Address, size);
|
|
Skip(size);
|
|
}
|
|
}
|
|
|
|
/*
|
|
void PC_SkipByte(void)
|
|
{
|
|
MS_Message(MSG_DEBUG, "SB> %06d (skip byte)\n", pc_Address);
|
|
Skip(sizeof(U_BYTE));
|
|
}
|
|
*/
|
|
|
|
/*
|
|
void PC_SkipWord(void)
|
|
{
|
|
MS_Message(MSG_DEBUG, "SW> %06d (skip word)\n", pc_Address);
|
|
Skip(sizeof(U_WORD));
|
|
}
|
|
*/
|
|
|
|
void PC_SkipInt(void)
|
|
{
|
|
if (ImportMode != IMPORT_Importing)
|
|
{
|
|
MS_Message(MSG_DEBUG, "SL> %06d (skip int)\n", pc_Address);
|
|
Skip(sizeof(U_INT));
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// PC_PutMapVariable
|
|
//
|
|
//==========================================================================
|
|
|
|
void PC_PutMapVariable(int index, int value)
|
|
{
|
|
if(index < MAX_MAP_VARIABLES)
|
|
{
|
|
MapVariables[index].isString = pa_ConstExprIsString;
|
|
MapVariables[index].initializer = value;
|
|
MapVariablesInit = YES;
|
|
if(pc_EnforceHexen)
|
|
{
|
|
ERR_Error(ERR_HEXEN_COMPAT, YES);
|
|
}
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// PC_NameMapVariable
|
|
//
|
|
//==========================================================================
|
|
|
|
void PC_NameMapVariable(int index, symbolNode_t *sym)
|
|
{
|
|
if(index < MAX_MAP_VARIABLES)
|
|
{
|
|
MapVariables[index].name = sym->name;
|
|
MapVariables[index].imported = sym->imported;
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// PC_AddScript
|
|
//
|
|
//==========================================================================
|
|
|
|
void PC_AddScript(int number, int type, int flags, int argCount)
|
|
{
|
|
scriptInfo_t *script;
|
|
int i;
|
|
|
|
if (flags != 0 || number < 0 || number >= 1000)
|
|
{
|
|
HaveExtendedScripts = YES;
|
|
if(pc_EnforceHexen)
|
|
{
|
|
ERR_Error(ERR_HEXEN_COMPAT, YES);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < pc_ScriptCount; i++)
|
|
{
|
|
if (ScriptInfo[i].number == number)
|
|
{
|
|
ERR_Error(ERR_SCRIPT_ALREADY_DEFINED, YES);
|
|
}
|
|
}
|
|
if(pc_ScriptCount == MAX_SCRIPT_COUNT)
|
|
{
|
|
ERR_Error(ERR_TOO_MANY_SCRIPTS, YES);
|
|
}
|
|
else
|
|
{
|
|
script = &ScriptInfo[pc_ScriptCount];
|
|
script->number = number;
|
|
script->type = type;
|
|
script->address = (ImportMode == IMPORT_Importing) ? 0 : pc_Address;
|
|
script->argCount = argCount;
|
|
script->flags = flags;
|
|
script->srcLine = tk_Line;
|
|
script->imported = (ImportMode == IMPORT_Importing) ? YES : NO;
|
|
pc_ScriptCount++;
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// PC_SetScriptVarCount
|
|
//
|
|
// Sets the number of local variables used by a script, including
|
|
// arguments.
|
|
//
|
|
//==========================================================================
|
|
|
|
void PC_SetScriptVarCount(int number, int type, int varCount)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < pc_ScriptCount; i++)
|
|
{
|
|
if(ScriptInfo[i].number == number && ScriptInfo[i].type == type)
|
|
{
|
|
ScriptInfo[i].varCount = varCount;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// PC_AddFunction
|
|
//
|
|
//==========================================================================
|
|
|
|
void PC_AddFunction(symbolNode_t *sym)
|
|
{
|
|
functionInfo_t *function;
|
|
|
|
if(pc_FunctionCount == MAX_FUNCTION_COUNT)
|
|
{
|
|
ERR_Error(ERR_TOO_MANY_FUNCTIONS, YES, NULL);
|
|
}
|
|
else if(pc_EnforceHexen)
|
|
{
|
|
ERR_Error(ERR_HEXEN_COMPAT, YES);
|
|
}
|
|
|
|
function = &FunctionInfo[pc_FunctionCount];
|
|
function->hasReturnValue = (U_BYTE)sym->info.scriptFunc.hasReturnValue;
|
|
function->argCount = (U_BYTE)sym->info.scriptFunc.argCount;
|
|
function->localCount = (U_BYTE)sym->info.scriptFunc.varCount;
|
|
function->name = STR_AppendToList (STRLIST_FUNCTIONS, sym->name);
|
|
function->address = sym->info.scriptFunc.address;
|
|
sym->info.scriptFunc.funcNumber = pc_FunctionCount;
|
|
pc_FunctionCount++;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// PC_AddArray
|
|
//
|
|
//==========================================================================
|
|
|
|
void PC_AddArray(int index, int size)
|
|
{
|
|
NumArrays++;
|
|
ArraySizes[index] = size;
|
|
if(pc_EnforceHexen)
|
|
{
|
|
ERR_Error(ERR_HEXEN_COMPAT, YES);
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// PC_InitArray
|
|
//
|
|
//==========================================================================
|
|
|
|
void PC_InitArray(int index, int *entries, boolean hasStrings)
|
|
{
|
|
int i;
|
|
|
|
// If the array is just initialized to zeros, then we don't need to
|
|
// remember the initializer.
|
|
for(i = 0; i < ArraySizes[index]; ++i)
|
|
{
|
|
if(entries[i] != 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if(i < ArraySizes[index])
|
|
{
|
|
ArrayInits[index] = MS_Alloc(ArraySizes[index]*sizeof(int), ERR_OUT_OF_MEMORY);
|
|
memcpy(ArrayInits[index], entries, ArraySizes[index]*sizeof(int));
|
|
}
|
|
ArrayOfStrings[index] = hasStrings;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// PC_AddImport
|
|
//
|
|
//==========================================================================
|
|
|
|
int PC_AddImport(char *name)
|
|
{
|
|
if (NumImports >= MAX_IMPORTS)
|
|
{
|
|
ERR_Exit(ERR_TOO_MANY_IMPORTS, YES);
|
|
}
|
|
else if(pc_EnforceHexen)
|
|
{
|
|
ERR_Error(ERR_HEXEN_COMPAT, YES);
|
|
}
|
|
strncpy(Imports[NumImports], name, 8);
|
|
return NumImports++;
|
|
}
|