ACS

From OdaWiki
Revision as of 22:42, 19 November 2006 by Zorro (Talk | contribs)

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 Specifications

ACS File Format


(All numbers are little-endian and 32 bits long) (Pointers are relative to the beginning of the lump)

Bytes 0 - 3 ACS\0' (0x00534341)
Bytes 4 - 7 Pointer to script and text pointers
Bytes 8 -... Varies

Pointer Table


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.