ref: 0a94c0f99d6c34b30d2ac6fd7d5e516bd14dffb5
dir: /src/hexen/p_acs.c/
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 1993-2008 Raven Software
// Copyright(C) 2008 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// 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.
//
//-----------------------------------------------------------------------------
// HEADER FILES ------------------------------------------------------------
#include "h2def.h"
#include "m_random.h"
#include "s_sound.h"
#include "i_swap.h"
#include "i_system.h"
#include "p_local.h"
// MACROS ------------------------------------------------------------------
#define SCRIPT_CONTINUE 0
#define SCRIPT_STOP 1
#define SCRIPT_TERMINATE 2
#define OPEN_SCRIPTS_BASE 1000
#define PRINT_BUFFER_SIZE 256
#define GAME_SINGLE_PLAYER 0
#define GAME_NET_COOPERATIVE 1
#define GAME_NET_DEATHMATCH 2
#define TEXTURE_TOP 0
#define TEXTURE_MIDDLE 1
#define TEXTURE_BOTTOM 2
#define S_DROP ACScript->stackPtr--
#define S_POP ACScript->stack[--ACScript->stackPtr]
#define S_PUSH(x) ACScript->stack[ACScript->stackPtr++] = x
// TYPES -------------------------------------------------------------------
typedef struct
{
int marker;
int infoOffset;
int code;
} PACKEDATTR acsHeader_t;
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static void StartOpenACS(int number, int infoIndex, int *address);
static void ScriptFinished(int number);
static boolean TagBusy(int tag);
static boolean AddToACSStore(int map, int number, byte * args);
static int GetACSIndex(int number);
static void Push(int value);
static int Pop(void);
static int Top(void);
static void Drop(void);
static int CmdNOP(void);
static int CmdTerminate(void);
static int CmdSuspend(void);
static int CmdPushNumber(void);
static int CmdLSpec1(void);
static int CmdLSpec2(void);
static int CmdLSpec3(void);
static int CmdLSpec4(void);
static int CmdLSpec5(void);
static int CmdLSpec1Direct(void);
static int CmdLSpec2Direct(void);
static int CmdLSpec3Direct(void);
static int CmdLSpec4Direct(void);
static int CmdLSpec5Direct(void);
static int CmdAdd(void);
static int CmdSubtract(void);
static int CmdMultiply(void);
static int CmdDivide(void);
static int CmdModulus(void);
static int CmdEQ(void);
static int CmdNE(void);
static int CmdLT(void);
static int CmdGT(void);
static int CmdLE(void);
static int CmdGE(void);
static int CmdAssignScriptVar(void);
static int CmdAssignMapVar(void);
static int CmdAssignWorldVar(void);
static int CmdPushScriptVar(void);
static int CmdPushMapVar(void);
static int CmdPushWorldVar(void);
static int CmdAddScriptVar(void);
static int CmdAddMapVar(void);
static int CmdAddWorldVar(void);
static int CmdSubScriptVar(void);
static int CmdSubMapVar(void);
static int CmdSubWorldVar(void);
static int CmdMulScriptVar(void);
static int CmdMulMapVar(void);
static int CmdMulWorldVar(void);
static int CmdDivScriptVar(void);
static int CmdDivMapVar(void);
static int CmdDivWorldVar(void);
static int CmdModScriptVar(void);
static int CmdModMapVar(void);
static int CmdModWorldVar(void);
static int CmdIncScriptVar(void);
static int CmdIncMapVar(void);
static int CmdIncWorldVar(void);
static int CmdDecScriptVar(void);
static int CmdDecMapVar(void);
static int CmdDecWorldVar(void);
static int CmdGoto(void);
static int CmdIfGoto(void);
static int CmdDrop(void);
static int CmdDelay(void);
static int CmdDelayDirect(void);
static int CmdRandom(void);
static int CmdRandomDirect(void);
static int CmdThingCount(void);
static int CmdThingCountDirect(void);
static int CmdTagWait(void);
static int CmdTagWaitDirect(void);
static int CmdPolyWait(void);
static int CmdPolyWaitDirect(void);
static int CmdChangeFloor(void);
static int CmdChangeFloorDirect(void);
static int CmdChangeCeiling(void);
static int CmdChangeCeilingDirect(void);
static int CmdRestart(void);
static int CmdAndLogical(void);
static int CmdOrLogical(void);
static int CmdAndBitwise(void);
static int CmdOrBitwise(void);
static int CmdEorBitwise(void);
static int CmdNegateLogical(void);
static int CmdLShift(void);
static int CmdRShift(void);
static int CmdUnaryMinus(void);
static int CmdIfNotGoto(void);
static int CmdLineSide(void);
static int CmdScriptWait(void);
static int CmdScriptWaitDirect(void);
static int CmdClearLineSpecial(void);
static int CmdCaseGoto(void);
static int CmdBeginPrint(void);
static int CmdEndPrint(void);
static int CmdPrintString(void);
static int CmdPrintNumber(void);
static int CmdPrintCharacter(void);
static int CmdPlayerCount(void);
static int CmdGameType(void);
static int CmdGameSkill(void);
static int CmdTimer(void);
static int CmdSectorSound(void);
static int CmdAmbientSound(void);
static int CmdSoundSequence(void);
static int CmdSetLineTexture(void);
static int CmdSetLineBlocking(void);
static int CmdSetLineSpecial(void);
static int CmdThingSound(void);
static int CmdEndPrintBold(void);
static void ThingCount(int type, int tid);
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
// PUBLIC DATA DEFINITIONS -------------------------------------------------
int ACScriptCount;
byte *ActionCodeBase;
acsInfo_t *ACSInfo;
int MapVars[MAX_ACS_MAP_VARS];
int WorldVars[MAX_ACS_WORLD_VARS];
acsstore_t ACSStore[MAX_ACS_STORE + 1]; // +1 for termination marker
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static acs_t *ACScript;
static int *PCodePtr;
static byte SpecArgs[8];
static int ACStringCount;
static char **ACStrings;
static char PrintBuffer[PRINT_BUFFER_SIZE];
static acs_t *NewScript;
static int (*PCodeCmds[]) (void) =
{
CmdNOP,
CmdTerminate,
CmdSuspend,
CmdPushNumber,
CmdLSpec1,
CmdLSpec2,
CmdLSpec3,
CmdLSpec4,
CmdLSpec5,
CmdLSpec1Direct,
CmdLSpec2Direct,
CmdLSpec3Direct,
CmdLSpec4Direct,
CmdLSpec5Direct,
CmdAdd,
CmdSubtract,
CmdMultiply,
CmdDivide,
CmdModulus,
CmdEQ,
CmdNE,
CmdLT,
CmdGT,
CmdLE,
CmdGE,
CmdAssignScriptVar,
CmdAssignMapVar,
CmdAssignWorldVar,
CmdPushScriptVar,
CmdPushMapVar,
CmdPushWorldVar,
CmdAddScriptVar,
CmdAddMapVar,
CmdAddWorldVar,
CmdSubScriptVar,
CmdSubMapVar,
CmdSubWorldVar,
CmdMulScriptVar,
CmdMulMapVar,
CmdMulWorldVar,
CmdDivScriptVar,
CmdDivMapVar,
CmdDivWorldVar,
CmdModScriptVar,
CmdModMapVar,
CmdModWorldVar,
CmdIncScriptVar,
CmdIncMapVar,
CmdIncWorldVar,
CmdDecScriptVar,
CmdDecMapVar,
CmdDecWorldVar,
CmdGoto,
CmdIfGoto,
CmdDrop,
CmdDelay,
CmdDelayDirect,
CmdRandom,
CmdRandomDirect,
CmdThingCount,
CmdThingCountDirect,
CmdTagWait,
CmdTagWaitDirect,
CmdPolyWait,
CmdPolyWaitDirect,
CmdChangeFloor,
CmdChangeFloorDirect,
CmdChangeCeiling,
CmdChangeCeilingDirect,
CmdRestart,
CmdAndLogical,
CmdOrLogical,
CmdAndBitwise,
CmdOrBitwise,
CmdEorBitwise,
CmdNegateLogical,
CmdLShift,
CmdRShift,
CmdUnaryMinus,
CmdIfNotGoto,
CmdLineSide,
CmdScriptWait,
CmdScriptWaitDirect,
CmdClearLineSpecial,
CmdCaseGoto,
CmdBeginPrint,
CmdEndPrint,
CmdPrintString,
CmdPrintNumber,
CmdPrintCharacter,
CmdPlayerCount,
CmdGameType,
CmdGameSkill,
CmdTimer,
CmdSectorSound,
CmdAmbientSound,
CmdSoundSequence,
CmdSetLineTexture,
CmdSetLineBlocking,
CmdSetLineSpecial, CmdThingSound, CmdEndPrintBold};
// CODE --------------------------------------------------------------------
//==========================================================================
//
// P_LoadACScripts
//
//==========================================================================
void P_LoadACScripts(int lump)
{
int i;
int *buffer;
acsHeader_t *header;
acsInfo_t *info;
header = W_CacheLumpNum(lump, PU_LEVEL);
ActionCodeBase = (byte *) header;
buffer = (int *) ((byte *) header + LONG(header->infoOffset));
ACScriptCount = LONG(*buffer);
++buffer;
if (ACScriptCount == 0)
{ // Empty behavior lump
return;
}
ACSInfo = Z_Malloc(ACScriptCount * sizeof(acsInfo_t), PU_LEVEL, 0);
memset(ACSInfo, 0, ACScriptCount * sizeof(acsInfo_t));
for (i = 0, info = ACSInfo; i < ACScriptCount; i++, info++)
{
info->number = LONG(*buffer);
++buffer;
info->address = (int *) ((byte *) ActionCodeBase + LONG(*buffer));
++buffer;
info->argCount = LONG(*buffer);
++buffer;
if (info->number >= OPEN_SCRIPTS_BASE)
{ // Auto-activate
info->number -= OPEN_SCRIPTS_BASE;
StartOpenACS(info->number, i, info->address);
info->state = ASTE_RUNNING;
}
else
{
info->state = ASTE_INACTIVE;
}
}
ACStringCount = LONG(*buffer);
++buffer;
ACStrings = Z_Malloc(ACStringCount * sizeof(char *), PU_LEVEL, NULL);
for (i=0; i<ACStringCount; ++i)
{
ACStrings[i] = (char *) ActionCodeBase + LONG(buffer[i]);
}
memset(MapVars, 0, sizeof(MapVars));
}
//==========================================================================
//
// StartOpenACS
//
//==========================================================================
static void StartOpenACS(int number, int infoIndex, int *address)
{
acs_t *script;
script = Z_Malloc(sizeof(acs_t), PU_LEVSPEC, 0);
memset(script, 0, sizeof(acs_t));
script->number = number;
// World objects are allotted 1 second for initialization
script->delayCount = 35;
script->infoIndex = infoIndex;
script->ip = address;
script->thinker.function = T_InterpretACS;
P_AddThinker(&script->thinker);
}
//==========================================================================
//
// P_CheckACSStore
//
// Scans the ACS store and executes all scripts belonging to the current
// map.
//
//==========================================================================
void P_CheckACSStore(void)
{
acsstore_t *store;
for (store = ACSStore; store->map != 0; store++)
{
if (store->map == gamemap)
{
P_StartACS(store->script, 0, store->args, NULL, NULL, 0);
if (NewScript)
{
NewScript->delayCount = 35;
}
store->map = -1;
}
}
}
//==========================================================================
//
// P_StartACS
//
//==========================================================================
static char ErrorMsg[128];
boolean P_StartACS(int number, int map, byte * args, mobj_t * activator,
line_t * line, int side)
{
int i;
acs_t *script;
int infoIndex;
aste_t *statePtr;
NewScript = NULL;
if (map && map != gamemap)
{ // Add to the script store
return AddToACSStore(map, number, args);
}
infoIndex = GetACSIndex(number);
if (infoIndex == -1)
{ // Script not found
//I_Error("P_StartACS: Unknown script number %d", number);
sprintf(ErrorMsg, "P_STARTACS ERROR: UNKNOWN SCRIPT %d", number);
P_SetMessage(&players[consoleplayer], ErrorMsg, true);
}
statePtr = &ACSInfo[infoIndex].state;
if (*statePtr == ASTE_SUSPENDED)
{ // Resume a suspended script
*statePtr = ASTE_RUNNING;
return true;
}
if (*statePtr != ASTE_INACTIVE)
{ // Script is already executing
return false;
}
script = Z_Malloc(sizeof(acs_t), PU_LEVSPEC, 0);
memset(script, 0, sizeof(acs_t));
script->number = number;
script->infoIndex = infoIndex;
script->activator = activator;
script->line = line;
script->side = side;
script->ip = ACSInfo[infoIndex].address;
script->thinker.function = T_InterpretACS;
for (i = 0; i < ACSInfo[infoIndex].argCount; i++)
{
script->vars[i] = args[i];
}
*statePtr = ASTE_RUNNING;
P_AddThinker(&script->thinker);
NewScript = script;
return true;
}
//==========================================================================
//
// AddToACSStore
//
//==========================================================================
static boolean AddToACSStore(int map, int number, byte * args)
{
int i;
int index;
index = -1;
for (i = 0; ACSStore[i].map != 0; i++)
{
if (ACSStore[i].script == number && ACSStore[i].map == map)
{ // Don't allow duplicates
return false;
}
if (index == -1 && ACSStore[i].map == -1)
{ // Remember first empty slot
index = i;
}
}
if (index == -1)
{ // Append required
if (i == MAX_ACS_STORE)
{
I_Error("AddToACSStore: MAX_ACS_STORE (%d) exceeded.",
MAX_ACS_STORE);
}
index = i;
ACSStore[index + 1].map = 0;
}
ACSStore[index].map = map;
ACSStore[index].script = number;
memcpy(ACSStore[index].args, args, sizeof(int));
return true;
}
//==========================================================================
//
// P_StartLockedACS
//
//==========================================================================
boolean P_StartLockedACS(line_t * line, byte * args, mobj_t * mo, int side)
{
int i;
int lock;
byte newArgs[5];
char LockedBuffer[80];
extern char *TextKeyMessages[11];
lock = args[4];
if (!mo->player)
{
return false;
}
if (lock)
{
if (!(mo->player->keys & (1 << (lock - 1))))
{
sprintf(LockedBuffer, "YOU NEED THE %s\n",
TextKeyMessages[lock - 1]);
P_SetMessage(mo->player, LockedBuffer, true);
S_StartSound(mo, SFX_DOOR_LOCKED);
return false;
}
}
for (i = 0; i < 4; i++)
{
newArgs[i] = args[i];
}
newArgs[4] = 0;
return P_StartACS(newArgs[0], newArgs[1], &newArgs[2], mo, line, side);
}
//==========================================================================
//
// P_TerminateACS
//
//==========================================================================
boolean P_TerminateACS(int number, int map)
{
int infoIndex;
infoIndex = GetACSIndex(number);
if (infoIndex == -1)
{ // Script not found
return false;
}
if (ACSInfo[infoIndex].state == ASTE_INACTIVE
|| ACSInfo[infoIndex].state == ASTE_TERMINATING)
{ // States that disallow termination
return false;
}
ACSInfo[infoIndex].state = ASTE_TERMINATING;
return true;
}
//==========================================================================
//
// P_SuspendACS
//
//==========================================================================
boolean P_SuspendACS(int number, int map)
{
int infoIndex;
infoIndex = GetACSIndex(number);
if (infoIndex == -1)
{ // Script not found
return false;
}
if (ACSInfo[infoIndex].state == ASTE_INACTIVE
|| ACSInfo[infoIndex].state == ASTE_SUSPENDED
|| ACSInfo[infoIndex].state == ASTE_TERMINATING)
{ // States that disallow suspension
return false;
}
ACSInfo[infoIndex].state = ASTE_SUSPENDED;
return true;
}
//==========================================================================
//
// P_Init
//
//==========================================================================
void P_ACSInitNewGame(void)
{
memset(WorldVars, 0, sizeof(WorldVars));
memset(ACSStore, 0, sizeof(ACSStore));
}
//==========================================================================
//
// T_InterpretACS
//
//==========================================================================
void T_InterpretACS(acs_t * script)
{
int cmd;
int action;
if (ACSInfo[script->infoIndex].state == ASTE_TERMINATING)
{
ACSInfo[script->infoIndex].state = ASTE_INACTIVE;
ScriptFinished(ACScript->number);
P_RemoveThinker(&ACScript->thinker);
return;
}
if (ACSInfo[script->infoIndex].state != ASTE_RUNNING)
{
return;
}
if (script->delayCount)
{
script->delayCount--;
return;
}
ACScript = script;
PCodePtr = ACScript->ip;
do
{
cmd = LONG(*PCodePtr);
++PCodePtr;
action = PCodeCmds[cmd] ();
} while (action == SCRIPT_CONTINUE);
ACScript->ip = PCodePtr;
if (action == SCRIPT_TERMINATE)
{
ACSInfo[script->infoIndex].state = ASTE_INACTIVE;
ScriptFinished(ACScript->number);
P_RemoveThinker(&ACScript->thinker);
}
}
//==========================================================================
//
// P_TagFinished
//
//==========================================================================
void P_TagFinished(int tag)
{
int i;
if (TagBusy(tag) == true)
{
return;
}
for (i = 0; i < ACScriptCount; i++)
{
if (ACSInfo[i].state == ASTE_WAITINGFORTAG
&& ACSInfo[i].waitValue == tag)
{
ACSInfo[i].state = ASTE_RUNNING;
}
}
}
//==========================================================================
//
// P_PolyobjFinished
//
//==========================================================================
void P_PolyobjFinished(int po)
{
int i;
if (PO_Busy(po) == true)
{
return;
}
for (i = 0; i < ACScriptCount; i++)
{
if (ACSInfo[i].state == ASTE_WAITINGFORPOLY
&& ACSInfo[i].waitValue == po)
{
ACSInfo[i].state = ASTE_RUNNING;
}
}
}
//==========================================================================
//
// ScriptFinished
//
//==========================================================================
static void ScriptFinished(int number)
{
int i;
for (i = 0; i < ACScriptCount; i++)
{
if (ACSInfo[i].state == ASTE_WAITINGFORSCRIPT
&& ACSInfo[i].waitValue == number)
{
ACSInfo[i].state = ASTE_RUNNING;
}
}
}
//==========================================================================
//
// TagBusy
//
//==========================================================================
static boolean TagBusy(int tag)
{
int sectorIndex;
sectorIndex = -1;
while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
{
if (sectors[sectorIndex].specialdata)
{
return true;
}
}
return false;
}
//==========================================================================
//
// GetACSIndex
//
// Returns the index of a script number. Returns -1 if the script number
// is not found.
//
//==========================================================================
static int GetACSIndex(int number)
{
int i;
for (i = 0; i < ACScriptCount; i++)
{
if (ACSInfo[i].number == number)
{
return i;
}
}
return -1;
}
//==========================================================================
//
// Push
//
//==========================================================================
static void Push(int value)
{
ACScript->stack[ACScript->stackPtr++] = value;
}
//==========================================================================
//
// Pop
//
//==========================================================================
static int Pop(void)
{
return ACScript->stack[--ACScript->stackPtr];
}
//==========================================================================
//
// Top
//
//==========================================================================
static int Top(void)
{
return ACScript->stack[ACScript->stackPtr - 1];
}
//==========================================================================
//
// Drop
//
//==========================================================================
static void Drop(void)
{
ACScript->stackPtr--;
}
//==========================================================================
//
// P-Code Commands
//
//==========================================================================
static int CmdNOP(void)
{
return SCRIPT_CONTINUE;
}
static int CmdTerminate(void)
{
return SCRIPT_TERMINATE;
}
static int CmdSuspend(void)
{
ACSInfo[ACScript->infoIndex].state = ASTE_SUSPENDED;
return SCRIPT_STOP;
}
static int CmdPushNumber(void)
{
Push(LONG(*PCodePtr));
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdLSpec1(void)
{
int special;
special = LONG(*PCodePtr);
++PCodePtr;
SpecArgs[0] = Pop();
P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
ACScript->side, ACScript->activator);
return SCRIPT_CONTINUE;
}
static int CmdLSpec2(void)
{
int special;
special = LONG(*PCodePtr);
++PCodePtr;
SpecArgs[1] = Pop();
SpecArgs[0] = Pop();
P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
ACScript->side, ACScript->activator);
return SCRIPT_CONTINUE;
}
static int CmdLSpec3(void)
{
int special;
special = LONG(*PCodePtr);
++PCodePtr;
SpecArgs[2] = Pop();
SpecArgs[1] = Pop();
SpecArgs[0] = Pop();
P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
ACScript->side, ACScript->activator);
return SCRIPT_CONTINUE;
}
static int CmdLSpec4(void)
{
int special;
special = LONG(*PCodePtr);
++PCodePtr;
SpecArgs[3] = Pop();
SpecArgs[2] = Pop();
SpecArgs[1] = Pop();
SpecArgs[0] = Pop();
P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
ACScript->side, ACScript->activator);
return SCRIPT_CONTINUE;
}
static int CmdLSpec5(void)
{
int special;
special = LONG(*PCodePtr);
++PCodePtr;
SpecArgs[4] = Pop();
SpecArgs[3] = Pop();
SpecArgs[2] = Pop();
SpecArgs[1] = Pop();
SpecArgs[0] = Pop();
P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
ACScript->side, ACScript->activator);
return SCRIPT_CONTINUE;
}
static int CmdLSpec1Direct(void)
{
int special;
special = LONG(*PCodePtr);
++PCodePtr;
SpecArgs[0] = LONG(*PCodePtr);
++PCodePtr;
P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
ACScript->side, ACScript->activator);
return SCRIPT_CONTINUE;
}
static int CmdLSpec2Direct(void)
{
int special;
special = LONG(*PCodePtr);
++PCodePtr;
SpecArgs[0] = LONG(*PCodePtr);
++PCodePtr;
SpecArgs[1] = LONG(*PCodePtr);
++PCodePtr;
P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
ACScript->side, ACScript->activator);
return SCRIPT_CONTINUE;
}
static int CmdLSpec3Direct(void)
{
int special;
special = LONG(*PCodePtr);
++PCodePtr;
SpecArgs[0] = LONG(*PCodePtr);
++PCodePtr;
SpecArgs[1] = LONG(*PCodePtr);
++PCodePtr;
SpecArgs[2] = LONG(*PCodePtr);
++PCodePtr;
P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
ACScript->side, ACScript->activator);
return SCRIPT_CONTINUE;
}
static int CmdLSpec4Direct(void)
{
int special;
special = LONG(*PCodePtr);
++PCodePtr;
SpecArgs[0] = LONG(*PCodePtr);
++PCodePtr;
SpecArgs[1] = LONG(*PCodePtr);
++PCodePtr;
SpecArgs[2] = LONG(*PCodePtr);
++PCodePtr;
SpecArgs[3] = LONG(*PCodePtr);
++PCodePtr;
P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
ACScript->side, ACScript->activator);
return SCRIPT_CONTINUE;
}
static int CmdLSpec5Direct(void)
{
int special;
special = LONG(*PCodePtr);
++PCodePtr;
SpecArgs[0] = LONG(*PCodePtr);
++PCodePtr;
SpecArgs[1] = LONG(*PCodePtr);
++PCodePtr;
SpecArgs[2] = LONG(*PCodePtr);
++PCodePtr;
SpecArgs[3] = LONG(*PCodePtr);
++PCodePtr;
SpecArgs[4] = LONG(*PCodePtr);
++PCodePtr;
P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
ACScript->side, ACScript->activator);
return SCRIPT_CONTINUE;
}
static int CmdAdd(void)
{
Push(Pop() + Pop());
return SCRIPT_CONTINUE;
}
static int CmdSubtract(void)
{
int operand2;
operand2 = Pop();
Push(Pop() - operand2);
return SCRIPT_CONTINUE;
}
static int CmdMultiply(void)
{
Push(Pop() * Pop());
return SCRIPT_CONTINUE;
}
static int CmdDivide(void)
{
int operand2;
operand2 = Pop();
Push(Pop() / operand2);
return SCRIPT_CONTINUE;
}
static int CmdModulus(void)
{
int operand2;
operand2 = Pop();
Push(Pop() % operand2);
return SCRIPT_CONTINUE;
}
static int CmdEQ(void)
{
Push(Pop() == Pop());
return SCRIPT_CONTINUE;
}
static int CmdNE(void)
{
Push(Pop() != Pop());
return SCRIPT_CONTINUE;
}
static int CmdLT(void)
{
int operand2;
operand2 = Pop();
Push(Pop() < operand2);
return SCRIPT_CONTINUE;
}
static int CmdGT(void)
{
int operand2;
operand2 = Pop();
Push(Pop() > operand2);
return SCRIPT_CONTINUE;
}
static int CmdLE(void)
{
int operand2;
operand2 = Pop();
Push(Pop() <= operand2);
return SCRIPT_CONTINUE;
}
static int CmdGE(void)
{
int operand2;
operand2 = Pop();
Push(Pop() >= operand2);
return SCRIPT_CONTINUE;
}
static int CmdAssignScriptVar(void)
{
ACScript->vars[LONG(*PCodePtr)] = Pop();
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdAssignMapVar(void)
{
MapVars[LONG(*PCodePtr)] = Pop();
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdAssignWorldVar(void)
{
WorldVars[LONG(*PCodePtr)] = Pop();
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdPushScriptVar(void)
{
Push(ACScript->vars[LONG(*PCodePtr)]);
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdPushMapVar(void)
{
Push(MapVars[LONG(*PCodePtr)]);
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdPushWorldVar(void)
{
Push(WorldVars[LONG(*PCodePtr)]);
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdAddScriptVar(void)
{
ACScript->vars[LONG(*PCodePtr)] += Pop();
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdAddMapVar(void)
{
MapVars[LONG(*PCodePtr)] += Pop();
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdAddWorldVar(void)
{
WorldVars[LONG(*PCodePtr)] += Pop();
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdSubScriptVar(void)
{
ACScript->vars[LONG(*PCodePtr)] -= Pop();
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdSubMapVar(void)
{
MapVars[LONG(*PCodePtr)] -= Pop();
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdSubWorldVar(void)
{
WorldVars[LONG(*PCodePtr)] -= Pop();
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdMulScriptVar(void)
{
ACScript->vars[LONG(*PCodePtr)] *= Pop();
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdMulMapVar(void)
{
MapVars[LONG(*PCodePtr)] *= Pop();
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdMulWorldVar(void)
{
WorldVars[LONG(*PCodePtr)] *= Pop();
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdDivScriptVar(void)
{
ACScript->vars[LONG(*PCodePtr)] /= Pop();
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdDivMapVar(void)
{
MapVars[LONG(*PCodePtr)] /= Pop();
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdDivWorldVar(void)
{
WorldVars[LONG(*PCodePtr)] /= Pop();
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdModScriptVar(void)
{
ACScript->vars[LONG(*PCodePtr)] %= Pop();
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdModMapVar(void)
{
MapVars[LONG(*PCodePtr)] %= Pop();
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdModWorldVar(void)
{
WorldVars[LONG(*PCodePtr)] %= Pop();
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdIncScriptVar(void)
{
++ACScript->vars[LONG(*PCodePtr)];
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdIncMapVar(void)
{
++MapVars[LONG(*PCodePtr)];
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdIncWorldVar(void)
{
++WorldVars[LONG(*PCodePtr)];
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdDecScriptVar(void)
{
--ACScript->vars[LONG(*PCodePtr)];
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdDecMapVar(void)
{
--MapVars[LONG(*PCodePtr)];
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdDecWorldVar(void)
{
--WorldVars[LONG(*PCodePtr)];
++PCodePtr;
return SCRIPT_CONTINUE;
}
static int CmdGoto(void)
{
PCodePtr = (int *) (ActionCodeBase + LONG(*PCodePtr));
return SCRIPT_CONTINUE;
}
static int CmdIfGoto(void)
{
if (Pop() != 0)
{
PCodePtr = (int *) (ActionCodeBase + LONG(*PCodePtr));
}
else
{
++PCodePtr;
}
return SCRIPT_CONTINUE;
}
static int CmdDrop(void)
{
Drop();
return SCRIPT_CONTINUE;
}
static int CmdDelay(void)
{
ACScript->delayCount = Pop();
return SCRIPT_STOP;
}
static int CmdDelayDirect(void)
{
ACScript->delayCount = LONG(*PCodePtr);
++PCodePtr;
return SCRIPT_STOP;
}
static int CmdRandom(void)
{
int low;
int high;
high = Pop();
low = Pop();
Push(low + (P_Random() % (high - low + 1)));
return SCRIPT_CONTINUE;
}
static int CmdRandomDirect(void)
{
int low;
int high;
low = LONG(*PCodePtr);
++PCodePtr;
high = LONG(*PCodePtr);
++PCodePtr;
Push(low + (P_Random() % (high - low + 1)));
return SCRIPT_CONTINUE;
}
static int CmdThingCount(void)
{
int tid;
tid = Pop();
ThingCount(Pop(), tid);
return SCRIPT_CONTINUE;
}
static int CmdThingCountDirect(void)
{
int type;
type = LONG(*PCodePtr);
++PCodePtr;
ThingCount(type, LONG(*PCodePtr));
++PCodePtr;
return SCRIPT_CONTINUE;
}
static void ThingCount(int type, int tid)
{
int count;
int searcher;
mobj_t *mobj;
mobjtype_t moType;
thinker_t *think;
if (!(type + tid))
{ // Nothing to count
return;
}
moType = TranslateThingType[type];
count = 0;
searcher = -1;
if (tid)
{ // Count TID things
while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
{
if (type == 0)
{ // Just count TIDs
count++;
}
else if (moType == mobj->type)
{
if (mobj->flags & MF_COUNTKILL && mobj->health <= 0)
{ // Don't count dead monsters
continue;
}
count++;
}
}
}
else
{ // Count only types
for (think = thinkercap.next; think != &thinkercap;
think = think->next)
{
if (think->function != P_MobjThinker)
{ // Not a mobj thinker
continue;
}
mobj = (mobj_t *) think;
if (mobj->type != moType)
{ // Doesn't match
continue;
}
if (mobj->flags & MF_COUNTKILL && mobj->health <= 0)
{ // Don't count dead monsters
continue;
}
count++;
}
}
Push(count);
}
static int CmdTagWait(void)
{
ACSInfo[ACScript->infoIndex].waitValue = Pop();
ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORTAG;
return SCRIPT_STOP;
}
static int CmdTagWaitDirect(void)
{
ACSInfo[ACScript->infoIndex].waitValue = LONG(*PCodePtr);
++PCodePtr;
ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORTAG;
return SCRIPT_STOP;
}
static int CmdPolyWait(void)
{
ACSInfo[ACScript->infoIndex].waitValue = Pop();
ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORPOLY;
return SCRIPT_STOP;
}
static int CmdPolyWaitDirect(void)
{
ACSInfo[ACScript->infoIndex].waitValue = LONG(*PCodePtr);
++PCodePtr;
ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORPOLY;
return SCRIPT_STOP;
}
static int CmdChangeFloor(void)
{
int tag;
int flat;
int sectorIndex;
flat = R_FlatNumForName(ACStrings[Pop()]);
tag = Pop();
sectorIndex = -1;
while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
{
sectors[sectorIndex].floorpic = flat;
}
return SCRIPT_CONTINUE;
}
static int CmdChangeFloorDirect(void)
{
int tag;
int flat;
int sectorIndex;
tag = LONG(*PCodePtr);
++PCodePtr;
flat = R_FlatNumForName(ACStrings[LONG(*PCodePtr)]);
++PCodePtr;
sectorIndex = -1;
while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
{
sectors[sectorIndex].floorpic = flat;
}
return SCRIPT_CONTINUE;
}
static int CmdChangeCeiling(void)
{
int tag;
int flat;
int sectorIndex;
flat = R_FlatNumForName(ACStrings[Pop()]);
tag = Pop();
sectorIndex = -1;
while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
{
sectors[sectorIndex].ceilingpic = flat;
}
return SCRIPT_CONTINUE;
}
static int CmdChangeCeilingDirect(void)
{
int tag;
int flat;
int sectorIndex;
tag = LONG(*PCodePtr);
++PCodePtr;
flat = R_FlatNumForName(ACStrings[LONG(*PCodePtr)]);
++PCodePtr;
sectorIndex = -1;
while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
{
sectors[sectorIndex].ceilingpic = flat;
}
return SCRIPT_CONTINUE;
}
static int CmdRestart(void)
{
PCodePtr = ACSInfo[ACScript->infoIndex].address;
return SCRIPT_CONTINUE;
}
static int CmdAndLogical(void)
{
Push(Pop() && Pop());
return SCRIPT_CONTINUE;
}
static int CmdOrLogical(void)
{
Push(Pop() || Pop());
return SCRIPT_CONTINUE;
}
static int CmdAndBitwise(void)
{
Push(Pop() & Pop());
return SCRIPT_CONTINUE;
}
static int CmdOrBitwise(void)
{
Push(Pop() | Pop());
return SCRIPT_CONTINUE;
}
static int CmdEorBitwise(void)
{
Push(Pop() ^ Pop());
return SCRIPT_CONTINUE;
}
static int CmdNegateLogical(void)
{
Push(!Pop());
return SCRIPT_CONTINUE;
}
static int CmdLShift(void)
{
int operand2;
operand2 = Pop();
Push(Pop() << operand2);
return SCRIPT_CONTINUE;
}
static int CmdRShift(void)
{
int operand2;
operand2 = Pop();
Push(Pop() >> operand2);
return SCRIPT_CONTINUE;
}
static int CmdUnaryMinus(void)
{
Push(-Pop());
return SCRIPT_CONTINUE;
}
static int CmdIfNotGoto(void)
{
if (Pop() != 0)
{
++PCodePtr;
}
else
{
PCodePtr = (int *) (ActionCodeBase + LONG(*PCodePtr));
}
return SCRIPT_CONTINUE;
}
static int CmdLineSide(void)
{
Push(ACScript->side);
return SCRIPT_CONTINUE;
}
static int CmdScriptWait(void)
{
ACSInfo[ACScript->infoIndex].waitValue = Pop();
ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORSCRIPT;
return SCRIPT_STOP;
}
static int CmdScriptWaitDirect(void)
{
ACSInfo[ACScript->infoIndex].waitValue = LONG(*PCodePtr);
++PCodePtr;
ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORSCRIPT;
return SCRIPT_STOP;
}
static int CmdClearLineSpecial(void)
{
if (ACScript->line)
{
ACScript->line->special = 0;
}
return SCRIPT_CONTINUE;
}
static int CmdCaseGoto(void)
{
int value;
value = LONG(*PCodePtr);
++PCodePtr;
if (Top() == value)
{
PCodePtr = (int *) (ActionCodeBase + LONG(*PCodePtr));
Drop();
}
else
{
++PCodePtr;
}
return SCRIPT_CONTINUE;
}
static int CmdBeginPrint(void)
{
*PrintBuffer = 0;
return SCRIPT_CONTINUE;
}
static int CmdEndPrint(void)
{
player_t *player;
if (ACScript->activator && ACScript->activator->player)
{
player = ACScript->activator->player;
}
else
{
player = &players[consoleplayer];
}
P_SetMessage(player, PrintBuffer, true);
return SCRIPT_CONTINUE;
}
static int CmdEndPrintBold(void)
{
int i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i])
{
P_SetYellowMessage(&players[i], PrintBuffer, true);
}
}
return SCRIPT_CONTINUE;
}
static int CmdPrintString(void)
{
strcat(PrintBuffer, ACStrings[Pop()]);
return SCRIPT_CONTINUE;
}
static int CmdPrintNumber(void)
{
char tempStr[16];
sprintf(tempStr, "%d", Pop());
strcat(PrintBuffer, tempStr);
return SCRIPT_CONTINUE;
}
static int CmdPrintCharacter(void)
{
char *bufferEnd;
bufferEnd = PrintBuffer + strlen(PrintBuffer);
*bufferEnd++ = Pop();
*bufferEnd = 0;
return SCRIPT_CONTINUE;
}
static int CmdPlayerCount(void)
{
int i;
int count;
count = 0;
for (i = 0; i < MAXPLAYERS; i++)
{
count += playeringame[i];
}
Push(count);
return SCRIPT_CONTINUE;
}
static int CmdGameType(void)
{
int gametype;
if (netgame == false)
{
gametype = GAME_SINGLE_PLAYER;
}
else if (deathmatch)
{
gametype = GAME_NET_DEATHMATCH;
}
else
{
gametype = GAME_NET_COOPERATIVE;
}
Push(gametype);
return SCRIPT_CONTINUE;
}
static int CmdGameSkill(void)
{
Push(gameskill);
return SCRIPT_CONTINUE;
}
static int CmdTimer(void)
{
Push(leveltime);
return SCRIPT_CONTINUE;
}
static int CmdSectorSound(void)
{
int volume;
mobj_t *mobj;
mobj = NULL;
if (ACScript->line)
{
mobj = (mobj_t *) & ACScript->line->frontsector->soundorg;
}
volume = Pop();
S_StartSoundAtVolume(mobj, S_GetSoundID(ACStrings[Pop()]), volume);
return SCRIPT_CONTINUE;
}
static int CmdThingSound(void)
{
int tid;
int sound;
int volume;
mobj_t *mobj;
int searcher;
volume = Pop();
sound = S_GetSoundID(ACStrings[Pop()]);
tid = Pop();
searcher = -1;
while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
{
S_StartSoundAtVolume(mobj, sound, volume);
}
return SCRIPT_CONTINUE;
}
static int CmdAmbientSound(void)
{
int volume;
volume = Pop();
S_StartSoundAtVolume(NULL, S_GetSoundID(ACStrings[Pop()]), volume);
return SCRIPT_CONTINUE;
}
static int CmdSoundSequence(void)
{
mobj_t *mobj;
mobj = NULL;
if (ACScript->line)
{
mobj = (mobj_t *) & ACScript->line->frontsector->soundorg;
}
SN_StartSequenceName(mobj, ACStrings[Pop()]);
return SCRIPT_CONTINUE;
}
static int CmdSetLineTexture(void)
{
line_t *line;
int lineTag;
int side;
int position;
int texture;
int searcher;
texture = R_TextureNumForName(ACStrings[Pop()]);
position = Pop();
side = Pop();
lineTag = Pop();
searcher = -1;
while ((line = P_FindLine(lineTag, &searcher)) != NULL)
{
if (position == TEXTURE_MIDDLE)
{
sides[line->sidenum[side]].midtexture = texture;
}
else if (position == TEXTURE_BOTTOM)
{
sides[line->sidenum[side]].bottomtexture = texture;
}
else
{ // TEXTURE_TOP
sides[line->sidenum[side]].toptexture = texture;
}
}
return SCRIPT_CONTINUE;
}
static int CmdSetLineBlocking(void)
{
line_t *line;
int lineTag;
boolean blocking;
int searcher;
blocking = Pop()? ML_BLOCKING : 0;
lineTag = Pop();
searcher = -1;
while ((line = P_FindLine(lineTag, &searcher)) != NULL)
{
line->flags = (line->flags & ~ML_BLOCKING) | blocking;
}
return SCRIPT_CONTINUE;
}
static int CmdSetLineSpecial(void)
{
line_t *line;
int lineTag;
int special, arg1, arg2, arg3, arg4, arg5;
int searcher;
arg5 = Pop();
arg4 = Pop();
arg3 = Pop();
arg2 = Pop();
arg1 = Pop();
special = Pop();
lineTag = Pop();
searcher = -1;
while ((line = P_FindLine(lineTag, &searcher)) != NULL)
{
line->special = special;
line->arg1 = arg1;
line->arg2 = arg2;
line->arg3 = arg3;
line->arg4 = arg4;
line->arg5 = arg5;
}
return SCRIPT_CONTINUE;
}