alexbatalov / fallout2-ce

Fallout 2 for modern operating systems
Other
1.79k stars 123 forks source link

[sfall] Basic Hook Script support #375

Open phobos2077 opened 6 months ago

phobos2077 commented 6 months ago

Parent issue: #29

To support modern mods CE needs hook scripts implementation. To get started with them there needs to be some basic structure.

I recommend to study sfall code and use the same basic concepts. The basic implementation is very old, but it evolved over the years.

Sfall docs on hook scripts and related opcodes can be found here: https://sfall-team.github.io/sfall/hooks/

Here is some basic introduction.


What are hook scripts?

Hook Programs

Hook Global scripts

Hook Procedures

Basic principles

xparaly commented 1 month ago

I've started some work on this on another fork. I'm trying to figure out if I need to use Sfall's ScriptProgram structure. I couldn't find anything similar in fallout2-ce. But fallout2-ce's Program is a little different from sfall's Program, so maybe I'm missing something. Any thoughts?

sfall:

typedef struct {
    fo::Program* ptr = nullptr;
    int procLookup[fo::Scripts::ScriptProc::count];
    bool initialized;
} ScriptProgram;

// Script run-time data
struct Program {
    const char* fileName; // path and file name of the script "scripts\*.int"
    long *codeStackPtr;
    long field_8;
    long field_C;
    long codePosition;  // position in the code stack when reading script opcodes
    long field_14;      // unused?
    long field_18;      // unused?
    long *dStackPtr;
    long *aStackPtr;
    long *dStackOffs;
    long *aStackOffs;
    long field_2C;
    long *stringRefPtr;
    long *procTablePtr;
    long *codeStack;    // same as codeStackPtr
    long savedEnv[12];  // saved register values
    long field_6C;      // unused?
    long field_70;      // unused?
    long field_74;      // unused?
    long timerTick;     // unused?
    long func_7C;       // always null?
    short flags;
    short fetchOpcode;
    long currentScriptWin; // current window for executing script
    long shouldRemove;
};

fallout2-ce:

// It's size in original code is 144 (0x8C) bytes due to the different
// size of `jmp_buf`.
typedef struct Program {
    char* name;
    unsigned char* data;
    struct Program* parent;
    struct Program* child;
    int instructionPointer; // current pos in data
    int framePointer; // saved stack 1 pos - probably beginning of local variables - probably called base
    int basePointer; // saved stack 1 pos - probably beginning of global variables
    unsigned char* staticStrings; // static strings table
    unsigned char* dynamicStrings; // dynamic strings table
    unsigned char* identifiers;
    unsigned char* procedures;
    jmp_buf env;
    unsigned int waitEnd; // end time of timer (field_74 + wait time)
    unsigned int waitStart; // time when wait was called
    int field_78; // time when program begin execution (for the first time)?, -1 - program never executed
    InterpretCheckWaitFunc* checkWaitFunc;
    int flags; // flags
    int windowId;
    bool exited;
    ProgramStack* stackValues;
    ProgramStack* returnStackValues;
} Program;
phobos2077 commented 1 month ago

IIRC ScriptProgram is sfall wrapper structure. And Program looks identical based on this code, if you analyze fields more closely. What exactly you think is different?

xparaly commented 1 month ago

As I started to writing this, I think I convinced myself that I should just copy over the ScriptProgram wrapper. I don't think the details of the Program struct will really have an impact on what should be done with hookscripts.

For what its worth, here's what I noticed.

  1. Sfall program is 140 bytes. FO2CE is 144 bytes.
  2. Sfall has 25 member. F02CE has 21 members.
  3. savedEnv is 12 bytes. jmp_buf is 16 bytes.
  4. I'm not sure how dStackPtr, aStackPtr, dStackOffs, and aStackOffs map to FO2CE.
  5. It looks like procTablePtr maps to procedures.
  6. not sure about *stringRefPtr.
  7. sfall has fetchOpcode. FO2CE has stackValues and returnStackValues.