Difference between revisions of "ACS"

From OdaWiki
 
(5 intermediate revisions by 2 users not shown)
Line 1: Line 1:
ACS (Action Coding Script?) is a compiled scripting language that works along side with the Hexen map format.  The compiled scripts are stored in a map's BEHAVIOR lump in a binary format decoded by the zdoom/hexen engines.  '''The license the ACS interpreter was released under is not GPL complaint, so there is no ACS support in Odamex.'''  Here is some info I dug which can aid in rewriting the interpreter.
+
ACS (Action Coding Script?) is a compiled scripting language that works along side with the Hexen map format.  The compiled scripts are stored in a map's BEHAVIOR lump in a binary format decoded by the zdoom/hexen engines.  Odamex supports ACS inherited from ZDoom 1.22, however what works and what does not is not documented.
  
== ACS Specifications ==
 
ACS File Format
 
---------------
 
(All numbers are little-endian and 32 bits long)
 
(Pointers are relative to the beginning of the lump)
 
  
{| border="1" width="75%"
 
!Bytes  0 - 3
 
|ACS\0' (0x00534341)
 
|-
 
!Bytes  4 - 7
 
|Pointer to script and text pointers
 
|-
 
!Bytes  8 -...
 
|Varies
 
|}
 
  
-------------
+
== Specs and Resources ==
Pointer Table
+
http://odamex.net/doc/thirdparty/acsspec.txt - Unspecified author, found in the zdoom utilities source.
-------------
+
The first dword is a count of the number of scripts in the lump. It is
+
immediately followed by an entry for each script in the lump. These
+
entries are of the format:
+
 
+
DWORD 0 This script's number
+
DWORD 1 A pointer to the start of the script
+
DWORD 2 The number of parameters the script accepts
+
 
+
These are then followed by a dword indicating how many different strings
+
are in the script. The remaining dwords contain pointers to each of the
+
strings.
+
 
+
------------
+
Script Codes
+
------------
+
Compiled ACS scripts do not distinguish between their arguments and
+
their local variables. When a script is executed, it's parameters
+
are copied to its first x local variables, where x is the number of
+
parameters the script takes. The ACC compiler will output an error
+
for any script with more than 10 local variables (including
+
parameters), so it's probably safe to allocate enough space for only
+
10 variables in an ACS interpreter.
+
 
+
There are 64 world variables available (numbered 0-63) that are
+
accessible from scripts executed from any map in a single hub. Each
+
map can also have 32 map variables accessible to all scripts in that
+
map, but not by scripts in other maps.
+
 
+
ACS's internal functions are actually opcodes. Some use arguments on
+
the stack, and others have their arguments immediately following them
+
in the code. For those that use arguments on the stack, the arguments
+
are first pushed on to the stack in sequence, and then the function's
+
opcode is stored. If the function uses a string as an argument, then
+
the string's index is pushed onto the stack as a number. Functions
+
are responsible for popping the arguments passed to them before they
+
return. The first value pushed is the function's first parameter, the
+
second value pushed is the second parameter, etc.
+
 
+
    #0: PCD_NOP
+
    #1: PCD_TERMINATE
+
    #2: PCD_SUSPEND
+
    #3: PCD_PUSHNUMBER x
+
    #4: PCD_LSPEC1 x
+
    #5: PCD_LSPEC2 x
+
    #6: PCD_LSPEC3 x
+
    #7: PCD_LSPEC4 x
+
    #8: PCD_LSPEC5 x
+
    #9: PCD_LSPEC1DIRECT x a
+
  #10: PCD_LSPEC2DIRECT x a b
+
  #11: PCD_LSPEC3DIRECT x a b c
+
  #12: PCD_LSPEC4DIRECT x a b c d
+
  #13: PCD_LSPEC5DIRECT x a b c d e
+
  #14: PCD_ADD
+
  #15: PCD_SUBTRACT
+
  #16: PCD_MULTIPLY
+
  #17: PCD_DIVIDE
+
  #18: PCD_MODULUS
+
  #19: PCD_EQ
+
  #20: PCD_NE
+
  #21: PCD_LT
+
  #22: PCD_GT
+
  #23: PCD_LE
+
  #24: PCD_GE
+
  #25: PCD_ASSIGNSCRIPTVAR x
+
  #26: PCD_ASSIGNMAPVAR x
+
  #27: PCD_ASSIGNWORLDVAR x
+
  #28: PCD_PUSHSCRIPTVAR x
+
  #29: PCD_PUSHMAPVAR x
+
  #30: PCD_PUSHWORLDVAR x
+
  #31: PCD_ADDSCRIPTVAR x
+
  #32: PCD_ADDMAPVAR x
+
  #33: PCD_ADDWORLDVAR x
+
  #34: PCD_SUBSCRIPTVAR x
+
  #35: PCD_SUBMAPVAR x
+
  #36: PCD_SUBWORLDVAR x
+
  #37: PCD_MULSCRIPTVAR x
+
  #38: PCD_MULMAPVAR x
+
  #39: PCD_MULWORLDVAR x
+
  #40: PCD_DIVSCRIPTVAR x
+
  #41: PCD_DIVMAPVAR x
+
  #42: PCD_DIVWORLDVAR x
+
  #43: PCD_MODSCRIPTVAR x
+
  #44: PCD_MODMAPVAR x
+
  #45: PCD_MODWORLDVAR x
+
  #46: PCD_INCSCRIPTVAR x
+
  #47: PCD_INCMAPVAR x
+
  #48: PCD_INCWORLDVAR x
+
  #49: PCD_DECSCRIPTVAR x
+
  #50: PCD_DECMAPVAR x
+
  #51: PCD_DECWORLDVAR x
+
  #52: PCD_GOTO x
+
  #53: PCD_IFGOTO x
+
  #54: PCD_DROP
+
  #55: PCD_DELAY
+
  #56: PCD_DELAYDIRECT x
+
  #57: PCD_RANDOM
+
  #58: PCD_RANDOMDIRECT x y
+
  #59: PCD_THINGCOUNT
+
  #60: PCD_THINGCOUNTDIRECT x y
+
  #61: PCD_TAGWAIT
+
  #62: PCD_TAGWAITDIRECT x
+
  #63: PCD_POLYWAIT
+
  #64: PCD_POLYWAITDIRECT x
+
  #65: PCD_CHANGEFLOOR
+
  #66: PCD_CHANGEFLOORDIRECT x y
+
  #67: PCD_CHANGECEILING
+
  #68: PCD_CHANGECEILINGDIRECT x y
+
  #69: PCD_RESTART
+
  #70: PCD_ANDLOGICAL
+
  #71: PCD_ORLOGICAL
+
  #72: PCD_ANDBITWISE
+
  #73: PCD_ORBITWISE
+
  #74: PCD_EORBITWISE
+
  #75: PCD_NEGATELOGICAL
+
  #76: PCD_LSHIFT
+
  #77: PCD_RSHIFT
+
  #78: PCD_UNARYMINUS
+
  #79: PCD_IFNOTGOTO x
+
  #80: PCD_LINESIDE
+
  #81: PCD_SCRIPTWAIT
+
  #82: PCD_SCRIPTWAITDIRECT x
+
  #83: PCD_CLEARLINESPECIAL
+
  #84: PCD_CASEGOTO x y
+
  #85: PCD_BEGINPRINT
+
  #86: PCD_ENDPRINT
+
  #87: PCD_PRINTSTRING
+
  #88: PCD_PRINTNUMBER
+
  #89: PCD_PRINTCHARACTER
+
  #90: PCD_PLAYERCOUNT
+
  #91: PCD_GAMETYPE
+
  #92: PCD_GAMESKILL
+
  #93: PCD_TIMER
+
  #94: PCD_SECTORSOUND
+
  #95: PCD_AMBIENTSOUND
+
  #96: PCD_SOUNDSEQUENCE
+
  #97: PCD_SETLINETEXTURE
+
  #98: PCD_SETLINEBLOCKING
+
  #99: PCD_SETLINESPECIAL
+
  #100: PCD_THINGSOUND
+
  #101: PCD_ENDPRINTBOLD
+
 
+
*1: PCD_TERMINATE
+
    Terminates script execution.
+
 
+
*3: PCD_PUSHNUMBER x
+
    Push x onto the stack.
+
 
+
*4: PCD_LSPEC1 x
+
    Execute line special x. It takes one argument on the stack.
+
 
+
*5: PCD_LSPEC2 x
+
    Execute line special x. It takes two arguments on the stack.
+
 
+
*6: PCD_LSPEC3 x
+
    Execute line special x. It takes three argument on the stack.
+
 
+
*7: PCD_LSPEC4 x
+
    Execute line special x. It takes four argument on the stack.
+
 
+
*8: PCD_LSPEC5 x
+
    Execute line special x. It takes five argument on the stack.
+
 
+
*9: PCD_LSPEC1DIRECT x a
+
    Execute line special x (a).
+
 
+
*10: PCD_LSPEC2DIRECT x a b
+
 
+
    Execute line special x (a, b).
+
 
+
*11: PCD_LSPEC3DIRECT x a b c
+
 
+
    Execute line special x (a, b, c).
+
 
+
*12: PCD_LSPEC4DIRECT x a b c d
+
 
+
    Execute line special x (a, b, c, d).
+
 
+
*13: PCD_LSPEC5DIRECT x a b c d e
+
 
+
    Execute line special x (a, b, c, d, e).
+
 
+
*14: PCD_ADD
+
 
+
    Stack before:
+
        int val1
+
        int val2
+
   
+
    Stack after:
+
        int (val1 + val2)
+
 
+
*15: PCD_SUBTRACT
+
 
+
    Stack before:
+
        int val1
+
        int val2
+
   
+
    Stack after:
+
        int (val1 - val2)
+
 
+
*16: PCD_MULTIPLY
+
 
+
    Stack before:
+
        int val1
+
        int val2
+
   
+
    Stack after:
+
        int (val1 * val2)
+
 
+
*17: PCD_DIVIDE
+
 
+
    Stack before:
+
        int val1
+
        int val2
+
   
+
    Stack after:
+
        int (val1 / val2)
+
 
+
*18: PCD_MODULUS
+
 
+
    Stack before:
+
        int val1
+
        int val2
+
   
+
    Stack after:
+
        int (val1 % val2)
+
 
+
*19: PCD_EQ
+
 
+
    Stack before:
+
        int val1
+
        int val2
+
   
+
    Stack after:
+
        (val1 == val2)
+
 
+
*20: PCD_NE
+
 
+
    Stack before:
+
        int val1
+
        int val2
+
   
+
    Stack after:
+
        (val1 != val2)
+
 
+
*21: PCD_LT
+
 
+
    Stack before:
+
        int val1
+
        int val2
+
   
+
    Stack after:
+
        (val1 < val2)
+
 
+
*22: PCD_GT
+
 
+
    Stack before:
+
        int val1
+
        int val2
+
   
+
    Stack after:
+
        (val1 > val2)
+
 
+
*23: PCD_LE
+
 
+
    Stack before:
+
        int val1
+
        int val2
+
   
+
    Stack after:
+
        (val1 <= val2)
+
 
+
*24: PCD_GE
+
 
+
    Stack before:
+
        int val1
+
        int val2
+
   
+
    Stack after:
+
        (val1 >= val2)
+
 
+
*25: PCD_ASSIGNSCRIPTVAR x
+
 
+
    Stack before:
+
        int val
+
   
+
    Store val in script var x.
+
 
+
*26: PCD_ASSIGNMAPVAR x
+
 
+
    Stack before:
+
        int val
+
   
+
    Store val in map var x.
+
 
+
*27: PCD_ASSIGNWORLDVAR x
+
 
+
    Stack before:
+
        int val
+
   
+
    Store val in world var x.
+
 
+
*28: PCD_PUSHSCRIPTVAR x
+
 
+
    Push value of script var x onto the stack.
+
 
+
*29: PCD_PUSHMAPVAR x
+
   
+
    Push value of map var x onto the stack.
+
 
+
*30: PCD_PUSHWORLDVAR x
+
 
+
    Push value of world var x onto the stack.
+
 
+
*31: PCD_ADDSCRIPTVAR x
+
 
+
    Stack before:
+
        int val
+
   
+
    script var x += val
+
 
+
*32: PCD_ADDMAPVAR x
+
 
+
    Stack before:
+
        int val
+
   
+
    map var x += val
+
 
+
*33: PCD_ADDWORLDVAR x
+
 
+
    Stack before:
+
        int val
+
   
+
    world var x += val
+
 
+
*34: PCD_SUBSCRIPTVAR x
+
 
+
    Stack before:
+
        int val
+
   
+
    script var x -= val
+
 
+
*35: PCD_SUBMAPVAR x
+
 
+
    Stack before:
+
        int val
+
   
+
    map var x -= val
+
 
+
*36: PCD_SUBWORLDVAR x
+
 
+
    Stack before:
+
        int val
+
   
+
    world var x -= val
+
 
+
*37: PCD_MULSCRIPTVAR x
+
 
+
    Stack before:
+
        int val
+
   
+
    script var x *= val
+
 
+
*38: PCD_MULMAPVAR x
+
 
+
    Stack before:
+
        int val
+
   
+
    map var x *= val
+
 
+
*39: PCD_MULWORLDVAR x
+
 
+
    Stack before:
+
        int val
+
   
+
    world var x *= val
+
 
+
*40: PCD_DIVSCRIPTVAR x
+
 
+
    Stack before:
+
        int val
+
   
+
    script var x /= val
+
 
+
*41: PCD_DIVMAPVAR x
+
 
+
    Stack before:
+
        int val
+
   
+
    map var x /= val
+
 
+
*42: PCD_DIVWORLDVAR x
+
 
+
    Stack before:
+
        int val
+
   
+
    world var x /= val
+
 
+
*43: PCD_MODSCRIPTVAR x
+
 
+
    Stack before:
+
        int val
+
   
+
    script var x %= val
+
 
+
*44: PCD_MODMAPVAR x
+
 
+
    Stack before:
+
        int val
+
   
+
    map var x %= val
+
 
+
*45: PCD_MODWORLDVAR x
+
 
+
    Stack before:
+
        int val
+
   
+
    world var x %= val
+
 
+
*46: PCD_INCSCRIPTVAR x
+
 
+
    script var x += 1
+
 
+
*47: PCD_INCMAPVAR x
+
 
+
    map var x += 1
+
 
+
*48: PCD_INCWORLDVAR x
+
 
+
    world var x += 1
+
 
+
*49: PCD_DECSCRIPTVAR x
+
 
+
    script var x -= 1
+
 
+
*50: PCD_DECMAPVAR x
+
 
+
    map var x -= 1
+
 
+
*51: PCD_DECWORLDVAR x
+
 
+
    world varx -= 1
+
 
+
*52: PCD_GOTO x
+
 
+
    Jump to offset x (relative to beginning of object file).
+
 
+
*53: PCD_IFGOTO x
+
 
+
    Stack before:
+
        int boolean
+
   
+
    If the boolean is true, jump to offset x.
+
 
+
*54: PCD_DROP
+
 
+
    Stack before:
+
        int anything
+
   
+
    Pop one number off the stack and discard it.
+
 
+
*55: PCD_DELAY
+
 
+
    Stack before:
+
        int tics
+
   
+
    Pop a number off the stick and delay for that many tics.
+
 
+
*56: PCD_DELAYDIRECT x
+
 
+
    Delay for x tics.
+
 
+
*57: PCD_RANDOM
+
 
+
    Stack before:
+
        int minval
+
        int maxval
+
   
+
    Stack after:
+
        int random(minval, maxval)
+
 
+
*58: PCD_RANDOMDIRECT x y
+
 
+
    Stack after:
+
        int random(x, y)
+
 
+
*59: PCD_THINGCOUNT
+
 
+
    Stack before:
+
        int type
+
        int tid
+
   
+
    Stack after:
+
        int thingcount(type,tid)
+
 
+
*60: PCD_THINGCOUNTDIRECT x y
+
 
+
    Stack after:
+
        int thingcount(x, y)
+
 
+
*61: PCD_TAGWAIT
+
 
+
    Stack before:
+
        int tag
+
   
+
    Pops a tag value off the stack and suspends execution of the current
+
    script until all sectors with a matching tag value are inactive.
+
 
+
*62: PCD_TAGWAITDIRECT x
+
 
+
    Waits for all sectors with tag x to become inactive before continuing
+
    execution of the current script.
+
 
+
*63: PCD_POLYWAIT
+
 
+
    Stack before:
+
        int po
+
   
+
    Suspends execution of the current script until polyobj po is inactive.
+
 
+
*64: PCD_POLYWAITDIRECT x
+
 
+
    Suspends execution of the current script until polyobj x is inactive.
+
 
+
*65: PCD_CHANGEFLOOR
+
 
+
    Stack before:
+
        int tag
+
        str flatname
+
   
+
    Sets the floor flat of all sectors tagged with tag to flatname.
+
 
+
*66: PCD_CHANGEFLOORDIRECT x y
+
 
+
    Sets the floor flat of all sectors tagged with x to y.
+
 
+
*67: PCD_CHANGECEILING
+
 
+
    Stack before:
+
        int tag
+
        str flatname
+
   
+
    Sets the ceiling flat of all sectors tagged with tag to flatname.
+
 
+
*68: PCD_CHANGECEILINGDIRECT x y
+
 
+
    Sets the ceiling flat of all sectors tagged with x to y.
+
 
+
*69: PCD_RESTART
+
 
+
    Restart execution of the current script from the beginning.
+
 
+
*70: PCD_ANDLOGICAL
+
 
+
    Stack before:
+
        int boolean1
+
        int boolean2
+
   
+
    Stack after:
+
        (boolean1 && boolean2)
+
 
+
*71: PCD_ORLOGICAL
+
 
+
    Stack before:
+
        int boolean1
+
        int boolean2
+
   
+
    Stack after:
+
        (boolean1 || boolean2)
+
 
+
*72: PCD_ANDBITWISE
+
 
+
    Stack before:
+
        int param1
+
        int param2
+
   
+
    Stack after
+
        int (param1 & param2)
+
 
+
*73: PCD_ORBITWISE
+
 
+
    Stack before:
+
        int param1
+
        int param2
+
   
+
    Stack after:
+
        int (param1 | param2)
+
 
+
*74: PCD_EORBITWISE
+
 
+
    Stack before:
+
        int param1
+
        int param2
+
   
+
    Stack after:
+
        int (param1 ^ param2)
+
 
+
*75: PCD_NEGATELOGICAL
+
 
+
    Stack before:
+
        int val
+
   
+
    Stack after:
+
        int (!val)
+
 
+
*76: PCD_LSHIFT
+
 
+
    Stack before:
+
        int a
+
        int b
+
   
+
    Stack after:
+
        int (a << b)
+
 
+
*77: PCD_RSHIFT
+
 
+
    Stack before:
+
        int a
+
        int b
+
   
+
    Stack after:
+
        int (a >> b)
+
 
+
*78: PCD_UNARYMINUS
+
 
+
    Stack before:
+
        int val
+
   
+
    Stack after:
+
        int (-val)
+
 
+
*79: PCD_IFNOTGOTO x
+
 
+
    Stack before:
+
        int boolean
+
   
+
    If boolean is false, jump to offset x.
+
 
+
*80: PCD_LINESIDE
+
 
+
    Stack after:
+
        int lineside
+
   
+
    lineside is a numerical parameter indicating which side of the line
+
    activated this script.
+
 
+
*81: PCD_SCRIPTWAIT
+
 
+
    Stack before:
+
        int scr
+
   
+
    Suspend execution of the current script until script scr has
+
    terminated.
+
 
+
*82: PCD_SCRIPTWAITDIRECT x
+
 
+
    Suspend execution of the current script until script x has
+
    terminated.
+
 
+
*83: PCD_CLEARLINESPECIAL
+
 
+
    Clears the special of the activating line.
+
 
+
*84: PCD_CASEGOTO x y
+
 
+
    Stack before:
+
        int val
+
   
+
    Stack after:
+
        int val (if not taken)
+
 
+
    If the val == x, pop it and jump to offset y.
+
 
+
*85: PCD_BEGINPRINT
+
 
+
    Prepare to build a string to output to the screen by creating a new
+
    empty working string.
+
 
+
*86: PCD_ENDPRINT
+
 
+
    Output the current working string to the local machine's screen.
+
 
+
*87: PCD_PRINTSTRING
+
 
+
    Stack before:
+
        str string
+
   
+
    Pop a string index off the stack and append it to the current
+
    working string.
+
 
+
*88: PCD_PRINTNUMBER
+
 
+
    Stack before:
+
        int num
+
   
+
    Append num to the current working string in its ASCII representation.
+
 
+
*89: PCD_PRINTCHARACTER
+
 
+
    Stack before:
+
        int char
+
   
+
    Append the ASCII character char to the current working string.
+
 
+
*90: PCD_PLAYERCOUNT
+
 
+
    Stack after:
+
        int playercount
+
   
+
    playercount is the number of players in the game.
+
 
+
*91: PCD_GAMETYPE
+
 
+
    Stack after:
+
        int gametype
+
   
+
    gametype represents the current game type.
+
 
+
*92: PCD_GAMESKILL
+
 
+
    Stack after:
+
        int gameskill
+
   
+
    gameskill is the current game skill.
+
 
+
*93: PCD_TIMER
+
 
+
    Stack after:
+
        int gametime
+
   
+
    gametime is the current level time in tics.
+
 
+
*94: PCD_SECTORSOUND
+
 
+
    Stack before:
+
        str name
+
        int volume
+
   
+
    Pops two values off the stack and plays a sound in the sector
+
    pointed at by this script's activating linedef.
+
 
+
*95: PCD_AMBIENTSOUND
+
 
+
    Stack before:
+
        str snd
+
        int vol
+
   
+
    Plays the sound snd at volume vol (0-127) on the local machine.
+
 
+
*96: PCD_SOUNDSEQUENCE
+
 
+
    Stack before:
+
        str seq
+
   
+
    Plays the sound sequence seq in the facing sector.
+
 
+
*97: PCD_SETLINETEXTURE
+
 
+
    Stack before:
+
        int line
+
        int side
+
        int position
+
        str texturename
+
 
+
*98: PCD_SETLINEBLOCKING
+
 
+
    Stack before:
+
        int line
+
        int blocking
+
 
+
*99: PCD_SETLINESPECIAL
+
 
+
    Stack before:
+
        int line
+
        int special
+
        int arg1
+
        int arg2
+
        int arg3
+
        int arg4
+
        int arg5
+
   
+
    Sets the line special and args for all matching lines.
+
 
+
*100: PCD_THINGSOUND
+
 
+
    Stack before:
+
        int tid
+
        str name
+
        int volume
+
 
+
    Plays a sound at all things marked with tid.
+
 
+
*101: PCD_ENDPRINTBOLD
+
 
+
    Print the current working string to the screen of all computers in
+
    the game.
+
 
+
== Sources ==
+
[[http://www.zdoom.org/files/utils/utils050999.zip|Zdoom utilities (text file found here)]]
+

Latest revision as of 04:45, 13 December 2013

ACS (Action Coding Script?) is a compiled scripting language that works along side with the Hexen map format. The compiled scripts are stored in a map's BEHAVIOR lump in a binary format decoded by the zdoom/hexen engines. Odamex supports ACS inherited from ZDoom 1.22, however what works and what does not is not documented.


Specs and Resources

http://odamex.net/doc/thirdparty/acsspec.txt - Unspecified author, found in the zdoom utilities source.