Skip to content

Commit

Permalink
Refactor|libcommon: Use an object-oriented model for ACScript system …
Browse files Browse the repository at this point in the history
…components

Now uses a common, OO model for all ACScript system components, in
"acs" namespace. Functionality is separated into Interpreter, Script
and System components.

Also fixed a couple of bugs that crept in during the custom episodes
implementation, through misinterpretation of vanilla behavior due to
a logic error in vanilla (which, subtly masked various bugs in the
Hexen IWAD(s)...).
  • Loading branch information
danij-deng committed Jan 29, 2015
1 parent 63939ea commit 11ef7e3
Show file tree
Hide file tree
Showing 82 changed files with 3,049 additions and 2,723 deletions.
1 change: 1 addition & 0 deletions doomsday/api/doomsday.h
Expand Up @@ -69,6 +69,7 @@
#include "api_server.h"
#include "api_sound.h"
#include "api_svg.h"
#include "api_uri.h"

#include <de/memoryzone.h>
#include <de/point.h>
Expand Down
8 changes: 7 additions & 1 deletion doomsday/plugins/common/common.pri
Expand Up @@ -9,6 +9,9 @@ INCLUDEPATH += \
$$DENG_LZSS_DIR/portable/include

HEADERS += \
$$common_inc/acs/interpreter.h \
$$common_inc/acs/script.h \
$$common_inc/acs/system.h \
$$common_inc/am_map.h \
$$common_inc/animdefs.h \
$$common_inc/common.h \
Expand Down Expand Up @@ -93,6 +96,9 @@ HEADERS += \
$$common_inc/menu/widgets/widget.h

SOURCES += \
$$common_src/acs/interpreter.cpp \
$$common_src/acs/script.cpp \
$$common_src/acs/system.cpp \
$$common_src/am_map.c \
$$common_src/animdefs.cpp \
$$common_src/common.c \
Expand Down Expand Up @@ -132,7 +138,7 @@ SOURCES += \
$$common_src/p_iterlist.c \
$$common_src/p_map.cpp \
$$common_src/p_mapsetup.cpp \
$$common_src/p_mapspec.c \
$$common_src/p_mapspec.cpp \
$$common_src/p_plat.cpp \
$$common_src/p_saveg.cpp \
$$common_src/p_saveio.cpp \
Expand Down
112 changes: 112 additions & 0 deletions doomsday/plugins/common/include/acs/interpreter.h
@@ -0,0 +1,112 @@
/** @file interpreter.h Action Code Script (ACS) interpreter.
*
* @authors Copyright © 2003-2013 Jaakko Keränen <jaakko.keranen@iki.fi>
* @authors Copyright © 2005-2015 Daniel Swanson <danij@dengine.net>
* @authors Copyright © 1999 Activision
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>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., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA</small>
*/

#ifndef LIBCOMMON_ACS_INTERPRETER_H
#define LIBCOMMON_ACS_INTERPRETER_H

#if __cplusplus
# include "acs/script.h"
# include "mapstatereader.h"
# include "mapstatewriter.h"
#endif

#define ACS_INTERPRETER_MAX_SCRIPT_ARGS 10
#define ACS_INTERPRETER_SCRIPT_STACK_DEPTH 32

#ifdef __cplusplus

namespace acs {

class System;

/**
* Action Code Script (ACS) interpreter (thinker).
*
* @ingroup playsim
*/
struct Interpreter
{
thinker_t thinker;
struct mobj_s *activator;
Line *line;
int side;
void *_script;
int delayCount;
struct Stack { // Local value stack.
int values[ACS_INTERPRETER_SCRIPT_STACK_DEPTH];
int height;

void push(int value);
int pop();
int top() const;
void drop();
} locals;
int args[ACS_INTERPRETER_MAX_SCRIPT_ARGS];
int const *pcodePtr;

acs::System &scriptSys() const;

/**
* Returns the Script data for the thinker.
*/
acs::Script &script() const;

void think();

/**
* Deserialize the thinker from the currently open save file.
*/
int read(MapStateReader *msr);

/**
* Serialize the thinker to the currently open save file.
*/
void write(MapStateWriter *msw) const;

/**
* @param script Logical ACS script-state instance.
* @param scriptArgs Args passed to the script.
* @param delayCount Delay in tics to wait before interpretation begins.
*/
static thinker_s *newThinker(acs::Script &script, acs::Script::Args const &scriptArgs,
struct mobj_s *activator = nullptr, Line *line = nullptr,
int side = 0, int delayCount = 0);
};

} // namespace acs
#endif // __cplusplus

// C wrapper API ---------------------------------------------------------------

// Opaque type for interpreter instances.
struct acs_Interpreter;

#ifdef __cplusplus
extern "C" {
#endif

void acs_Interpreter_Think(acs_Interpreter *interp);

#ifdef __cplusplus
} // extern "C"
#endif

#endif // LIBCOMMON_ACS_INTERPRETER_H
174 changes: 174 additions & 0 deletions doomsday/plugins/common/include/acs/script.h
@@ -0,0 +1,174 @@
/** @file script.h Action Code Script (ACS), script model.
*
* @authors Copyright © 2003-2013 Jaakko Keränen <jaakko.keranen@iki.fi>
* @authors Copyright © 2005-2015 Daniel Swanson <danij@dengine.net>
* @authors Copyright © 1999 Activision
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>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., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA</small>
*/

#ifndef LIBCOMMON_ACS_SCRIPT_H
#define LIBCOMMON_ACS_SCRIPT_H

#include "common.h"
#include <array>
#include <de/reader.h>
#include <de/writer.h>
#include <de/String>

namespace acs {

class System;

/**
* Models the high-level state of an Action Code Script (ACS).
*
* @ingroup playsim
*/
class Script
{
public:
/**
* Stores information about an ACS byte/p-code entry point.
*/
struct EntryPoint
{
int const *pcodePtr = nullptr;
bool startWhenMapBegins = false;
int scriptNumber = 0;
int scriptArgCount = 0;
};

/**
* Script arguments.
*/
class Args : public std::array<de::dbyte, 4>
{
public:
Args();
Args(de::dbyte const *cArr, de::dint length);
};

/**
* Logical script states.
*/
enum State {
Inactive,
Running,
Suspended,

WaitingForSector,
WaitingForPolyobj,
WaitingForScript,

Terminating
};
static de::String stateAsText(State state);

public:
Script();
Script(EntryPoint const &ep);

/**
* Composes the human-friendly, styled, textual name of the object.
*/
de::String describe() const;

/**
* Composes a human-friendly, styled, textual description of the script.
*/
de::String description() const;

/**
* Start/resume script interpretation if inactive/suspended.
*
* If currently suspended the script is instructed to resume (deferred).
*
* Otherwise instantiate a new script Interpreter and add it to the list of
* thinkers for the @em current map.
*
* @param args Script argument values.
* @param activator Mobj activator, if any (can be @c nullptr).
* @param line Line activator, if any (can be @c nullptr).
* @param side Line side number.
* @param delayTics Number of tics to wait before interpretation begins.
* (Can be used to delay processing during map startup).
*
* @return @c true if started/resumed.
*/
bool start(Args const &args, mobj_t *activator = nullptr,
Line *line = nullptr, int side = 0, int delayTics = 0);

/**
* Instruct the script to self-suspend if running (deferred).
*
* @return @c true if marked for suspension.
*/
bool suspend();

/**
* Instruct the script to self-terminate if running (deferred).
*
* @return @c true if marked for termination.
*/
bool terminate();

/**
* Returns the current logical state of the script (FYI).
*/
State state() const;

bool isRunning() const;
bool isSuspended() const;
bool isWaiting() const;

void waitForPolyobj(int tag);
void waitForScript (int number);
void waitForSector (int tag);

void polyobjFinished(int tag);
void sectorFinished (int tag);

/**
* Returns the entry point info for the script.
*/
EntryPoint const &entryPoint() const;

/**
* Reconfigure the entry point info for the script.
*/
void applyEntryPoint(EntryPoint const &epToCopy);

void read(Reader *reader);
void write(Writer *writer) const;

public: /// @todo make private:

/**
* Resume @em this script if it is waiting on @a other (which has just terminated).
*
* @param other Script to be considered.
*/
void resumeIfWaitingForScript(Script const &other);

void setState(State newState);

private:
DENG2_PRIVATE(d)
};

} // namespace acs

#endif // LIBCOMMON_ACS_SCRIPT_H

0 comments on commit 11ef7e3

Please sign in to comment.