DO/CTL

From Dark Omen Wiki

< DO(Difference between revisions)
Jump to: navigation, search
m (CTL Engine Control Flag)
 
(17 intermediate revisions not shown)
Line 1: Line 1:
 +
<div style="float:right; margin-left: 2em; padding: 1em; border: 1px solid black; background: rgb(225, 235, 225);">
__TOC__
__TOC__
-
== Structure ==
+
<br />
 +
<div style="">
 +
'''Sub-pages:'''
 +
:* [[DO/CTL/OpCodes|Documentation of opcodes]]
 +
:* [[DO/CTL/Flags|Unit flags in CTL code]]
 +
:* [[DO/CTL/Events|Ids used in the Unit Event Handler]]
 +
:* [[DO/CTL/Code examples|Example CTL scripts]]
 +
</div>
 +
</div>
-
Every file starts with 32 00 00 00, which we can assume to be a file version or ID number.  
+
CTL is the script executed on the battlefield. It's used to control the AI and it implements the logic of all units (also of allied ones). Use [http://en.dark-omen.org/downloads/view-details/1.-modding-tools/4.-miscellaneous-tools/ctldis.html CTLdis] to modify CTL files.
 +
== Structure ==
-
* The first INT is a version number / id.
+
A CTL file consists of many functions. On startup every regiment executes one of these functions. Functions starting from 100 are common functions used in all CTL files. Allied units always execute .func 100.
-
* The file is read as a series of signed integers.
+
-
* At the beginning of a file, there is an offset table.
+
-
* The offsets are in DWORD units, so multiply each value by 4 for the byte offset.
+
-
You can tell how big it is because it stops at the first offset listed.
+
Example of a script function:
-
* offsets divide the file into chunks.
+
.func 2
-
* The first 49 chunks of each file are the same for every CTL file, thereafter they are different.
+
    init_unit 128
 +
    clear_ctrl_flag 32768
 +
    set_label 43970
 +
    #3c 240, 0
 +
    set_event_handler 15
 +
    #3e 13, 31
 +
    wait_for_deploy
 +
    saveip
 +
    goto 7
-
This, along with the fact that there appear to be two types of integer token, those with bit 15 set and those without, leads me to believe that this is scripting code (with 49 script functions that are common to each map).
+
A line always contains an opcode name (or #xy if the function is unknown) followed by an argument list. For a documentation of the known opcodes see the [[DO/CTL/OpCodes|opcodes subarticle]].
-
The effect of moving units around is also a reasonable outcome of this hypothesis, since the areas that the units moved to are those specified in the BTB. i.e. the traders and goblins swapped and didn't move to random areas.  So the scripts may be moving units between predefined points
+
The script is connected via ARM and BTB file (Chunk <6000>):
-
== Further Actions ==
+
[[File:Armbtbctl.png‎]]
-
'''Olly''':Simple Tests using the CTL file other Maps, has shown that CTL files dictate where the starting points of enemy AI units are. Although in early testing, it appears that it may dictate where off map units are placed. For example, swapping B204.CTL with B101.CTL produced:
+
== Unit Flags ==
-
http://img156.imageshack.us/img156/3206/b204ctlex2.jpg
+
The unit flags indicate the current status of the unit, like in combat or retreating. Most flags are still unknown. See the [[DO/CTL/Flags|Flags subarticle]] for a list.
-
As can be seen, the Goblins have now started in the Village and the Peasants are now up on the Cliff. More tests to follow, as all information will contribute to the Map Editor and beyond. Therefore allowing new Single Player Campaigns to be created, where the enenmy, who can already be switched between Races will now be able to appear in different locations, that will catch even the most experienced Player out.
+
== Call Stack ==
-
:'''Mikademus''': There is another interpretation of your test. In B1_01 the second wave are actually located outside the legal map area below the ridge in the village region, and they are moved to the top of the ridge when activated. Their original position can be seen by using the BRINGEMON and LOOKLIVELY start menu codes, and holding CTRL in the game. Therefore, they may be repositioned, or simply activated.  
+
Every unit contains a call stack that can contain up to 48 elements. It's is used by call statements (to store calling function and line) and loops (to store the loop begin line).
 +
 +
== Event handling ==
-
: Nonetheless, we know, if this is script codes in some way, that the script must contain at the very least (1) enemy unit IDs, a REPOSITION command, an ACTIVATE command (unless this is implicit in positioning a unit inside or outside the legal map area), and a position definition. [[User:Mikademus|Mikademus]] 11:25, 30 August 2008 (UTC)
+
Every unit executes an event handler to allow communication between the regiments. It gets assigned with the command set_event_handler following the function. In the example above the handler would be function 15.
-
== Dump of the Script Commands ==
+
Everytime the regiment script executes it will check if new messages are pending. If yes it will call into the event handler (and store return func and position on the stack). After the event handling it will return to the old function if it was not altered with one of the set_event_handler_return_function commands (see also CTL Engine Control Flag below).
-
A dump of some script-like commands (maybe CTL-Related?):
+
All events are stored in a global message queue and have the following structure:
-
WHMTG_ReplayDotList
+
-
WHMTG_ResetDotList
+
-
WHMTG_AddBitmap
+
-
WHMTG_SetResult
+
-
WHMTG_ContinuePrompt
+
-
WHMTG_FinishDots
+
-
WHMTG_WaitForDots
+
-
WHMTG_PlayDots
+
-
WHMTG_LoadDots
+
-
WHMTG_PlaySampleNoWait
+
-
WHMTG_PlaySample
+
-
WHMTG_Wait
+
-
WHMTG_HideHead
+
-
WHMTG_ChooseOption
+
-
WHMTG_AddOption
+
-
WHMTG_Narrate
+
-
WHMTG_SpeakNoWait
+
-
WHMTG_Speak
+
-
WHMTG_ShowHead
+
-
WHMTG_LoadHeads
+
-
WHMTG_PlayAnim
+
-
WHMTG_StopAnim
+
-
WHMTG_StartAnimAsync
+
-
WHMTG_SetBackground
+
-
WHMTG_SetMusic
+
-
WHMTG_StopMusic
+
-
WHMTG_PlayMusic
+
-
WHMTG_StopAllSFX
+
-
WHMTG_StopSFX
+
-
WHMTG_PlaySFX
+
-
WHMTG_ChooseInit
+
-
WHMTG_SpotAnim
+
-
WHMTG_Voice
+
-
WHMTG_RemoveBitmap
+
-
WHMTG_DisplayBitmap
+
-
 
+
-
WH_SetObjective
+
-
WH_CheckObjective
+
-
WH_RemoveMagic
+
-
WH_AddMagic
+
-
WH_SetDeafultSaveName
+
-
WH_ShowMouse
+
-
WH_HideMouse
+
-
WH_Pause
+
-
WH_Delay
+
-
WH_Picture
+
-
WH_SaveGame
+
-
WH_Debrief
+
-
WH_InitDebrief
+
-
WH_MeetingWait
+
-
WH_Book
+
-
WH_UnitIsGoingClear
+
-
WH_UnitIsGoingSet
+
-
WH_TemporyUnitClear
+
-
WH_TemporyUnitSet
+
-
WH_IncludeUnit
+
-
WH_ExcludeUnit
+
-
WH_UnForceUnit
+
-
WH_ForceUnit
+
-
WH_ClearVariables
+
-
WH_DisableAutosave
+
-
WH_GameOver
+
-
WH_AddCash
+
-
WH_ReadVariable
+
-
WH_SetVariable
+
-
WH_ReadUnitVar
+
-
WH_SetUnitVar
+
-
WH_WriteTextToFile
+
-
WH_RemoveUnit
+
-
WH_AddUnit
+
-
WH_GetUnitHireStatus
+
-
WH_GetUnitStatus
+
-
WH_Battle
+
-
WH_Deploy
+
-
WH_TravelMap
+
-
WH_MeetingPoint
+
-
WH_Narration
+
-
WH_PlayMovie
+
-
WH_Test
+
-
 
+
-
WH_END
+
-
WH_BREAK
+
-
WH_UNTIL
+
-
WH_REPEAT
+
-
WH_LOOP
+
-
WH_SETLV
+
-
WH_POPLV
+
-
WH_PUSHLV
+
-
WH_DO
+
-
WH_RETURN
+
-
WH_GOSUB
+
-
WH_ELSE
+
-
WH_ENDIF
+
-
WH_IF
+
-
WH_GOTO
+
-
 
+
-
===Analysis===
+
-
Some of these commands come in what appears to be logical pairs. It is assumed
+
-
* that these will always match up (GOSUB and RETURN do not have to match)
+
-
* that all initiators and terminators are unique between couplets, i.e that different initiators are never closed by the same terminator and vice versa.
+
-
 
+
-
Initiator  vs. Terminator | (Nested)
+
-
--------------------------+----------------
+
-
WH_IF    <--> WH_ENDIF  | (WH_ELSE)
+
-
WH_GOSUB  <--> WH_RETURN  |
+
-
WH_REPEAT <--> WH_UNTIL  |
+
-
WH_DO    <--> WH_LOOP    | (WH_BREAK)
+
-
 
+
-
http://img297.imageshack.us/img297/5904/82998608iv3.jpg
+
-
 
+
-
Further assumptions:
+
-
* WH_GOTO is followed by wither a jump address or a label (or label reference)
+
-
* The CTL script is a stack machine that communicates arguments and return values through a global stack
+
-
 
+
-
=== Conjectured OPCODEs ===
+
-
 
+
-
====About number of parameters====
+
-
It seems of not all then quite few of the opcodes takes a variable number of arguments. Opcodes taking zero of one, one to two, and one to three arguments have been observed. Most opcodes do seem stable, but this cannot be assumed to be anything but chance or coding practice. Opcodes should be assumed to take a variable number of arguments.
+
-
 
+
-
====Opcodes taking many parameters====
+
-
There seem to be four opcodes that takes three arguments
+
-
0x808b - relatively frequent. Note that 808c takes two arguments and 808a one. Relation?
+
-
0x8098 - See f.i. common segment 18
+
-
0x8099 - Found in SPARE9 seg. 42 (note that 42 is a common argument in SPARE9 and seg 42 is
+
-
          a relatively large function. Relevant?)
+
-
0x80ec - Found in SPARE9 seg 58 (last seg)
+
-
 
+
-
There is apparently only one opcode that takes four arguments
+
-
0x80bf - quite uncommon. Found in SPARE9 seg. 25
+
-
 
+
-
====Code structure====
+
-
Flow control?
+
-
0x74 0x75 - Most frequent, IF and ENDIF?
+
-
0x76 0x78 - Also candidates for IF/ENDIF. See seg 12 and 13 in any CTL file
+
-
0x77 0x79 - If these are DO and LOOP then 0x78 could be BREAK
+
-
 
+
-
====Observations====
+
-
803c      - CTL 1  (803c opcode seems to Always have same two arguments (f0 and 0) = 240 0 (Tested Spare9, B1_01, B2_04, B5_01B)
+
-
803d      - CTL 1  (803d opcode seems to Always have same argument 66  =  102    this opcode doesnt appear in all CTL files.
+
-
: This last one isn't true - 803d has arguments 102, 103, 104, 105 in the common function 0. [[User:Rob|Rob]] 17:30, 23 January 2009 (UTC)
+
-
8030 seems to always have one huge argument, f.i. 67M, 71M etc. Bitset?
+
-
802c seems to always take 4008h or a000h as arguments. Are 4008h and a000h tokens?
+
-
802e seems to always have 2000h or nothing as argument. Is 2000h a token?
+
-
80cf seems to always take 200000h as argument.
+
-
 
+
-
====Possible special tokens====
+
-
0abc - Always follows opcodes 8011, 8012 and 8013. However, also found unbound, f.i. in seg in
+
-
        the sequence 8085 1abc 0abc. Could if be a NOP marker? The moniker for FALSE?
+
-
        Esp. see SPARE9 seg 25.
+
-
+
-
1abc - always follows on 8075. Perhaps a moniker for TRUE?
+
-
+
-
These are also sometimes found
+
-
+
-
abc0
+
-
abc1
+
-
abc
+
-
def
+
-
=== Confirmed OPCODEs ===
+
struct EventMessage {
 +
  DWORD targetId;
 +
  DWORD eventId;
 +
  DWORD arg1; // usually the source
 +
  DWORD arg2;
 +
  DWORD arg3;
 +
  DWORD arg4;
 +
  DWORD arg5;
 +
  DWORD indexLast; // -1 if the msg was handled
 +
}
-
0x80ae: This opcode controls sounds. By changing the argument, you can make Klaus say different things in the tutorial. '''Rob'''
+
Most functions set arg1 to the id of the sender. The id is an incrementing number starting with 0. At first the enemies get an id (in ARM-file order) followed by the allied units (only the ones available on the map). After the allied units the furniture (like destructable houses) follows. But the furniture does not execute a script function.
-
:The commands seemingly to do with voices above seems to be
+
For a list of common events see the [[DO/CTL/Events|Event subarticle]].
-
<div style="margin:0.5em; margin-left:2.5em;">WH_Narration<br />WHMTG_PlaySampleNoWait<br />WHMTG_PlaySample<br />WHMTG_Narrate<br />WHMTG_SpeakNoWait<br />WHMTG_Speak<br />WHMTG_Voice</div>
+
-
:I'm not certain if the "WHMTG*" commands are only used in the cutscenes, but if so then 0x80AE must be WH_Narration. [[User:Mikademus|Mikademus]] 18:33, 15 December 2009 (UTC)
+
-
:: It looks like 0x80ae uses the portrait of the unit with Script Id 0 (see BTB article). Klaus has id 0 and on Trading Post by changing id of archer from 2 to 0 (and normal gob 0 to 2) the Archer says the text (instead of Night Gobbo) --[[User:Ghabry|Ghabry]] 16:09, 16 December 2009 (UTC)
+
 +
== CTL Engine Control Flag ==
-
And the ScriptId also defines what function is called. If a unit has Id 3 "func 3" is used. I proof this theory by looking at the script Ids of the 3 peasants of the trading post. There 3 funcs are (nearly completly) equal, same for the 4 Training dummies in the Tutorial. And func 0 is extreme huge in the Tutorial because Klaus has lots of things to do.<br />Allied units have all Id 100. I'm not sure if the engine does something different with this Id for allied units.<br />The initial starting points of enemy units (outside of the map) does also have Ids that collide (are equal) to the Script Ids of the enemies. But swapping the Ids hadn't changed the spawn location, need further investigation. --[[User:Ghabry|Ghabry]] 16:16, 16 December 2009 (UTC)
+
The behaviour of the CTL-Engine can be altered by setting flags in the Control Flag. Every unit stores its own version of the control flag.
-
A Goblin Unit (Spotz UnitID = 131 in B101NME.ARM) that has its ScriptID altered to 100 in B101.BTB file block 6000 String 503 Record 13 (Indentified by Record 12 UnitID 13)but also with its Allignment set to Good in WH32Edit - Results in being able to Control the first Night Goblin Unit, as an additional Unit.  
+
{|class="wikitable"
-
http://img24.imageshack.us/img24/6372/ctlgoblincontrollable.jpg
+
! Bit !! Notes
-
http://img163.imageshack.us/img163/7996/ctlspotz2.jpg
+
|-
-
Shows Morgan (Record 12 integer 1 with Record 13 integer 100)and Spotz also made Controllable by altering script to 100.  
+
|2
-
ScriptID = 100 = Controllable by Player Script -confirmed Robs Suggested test.
+
|Indicates "true" (set by conditional commands)
-
[[Category: Modifications]]
+
|-
-
[[Category: File Formats]]
+
|3
 +
|Indicates that return_from_event_handler shall return to a different function which was set with one of the set_event_handler_return_function commands. If the new return function is the same as the old one the execution will continue at the old position (like a normal return).
 +
|-
 +
|5
 +
|Only works in combination with bit 3. If this flag is set the stack content is ignored, execution always continues at the beginning of the function.
 +
|}

Current revision as of 21:39, 8 April 2012

Contents


CTL is the script executed on the battlefield. It's used to control the AI and it implements the logic of all units (also of allied ones). Use CTLdis to modify CTL files.

Structure

A CTL file consists of many functions. On startup every regiment executes one of these functions. Functions starting from 100 are common functions used in all CTL files. Allied units always execute .func 100.

Example of a script function:

.func 2
    init_unit 128
    clear_ctrl_flag 32768
    set_label 43970
    #3c 240, 0
    set_event_handler 15
    #3e 13, 31
    wait_for_deploy 
    saveip 
    goto 7

A line always contains an opcode name (or #xy if the function is unknown) followed by an argument list. For a documentation of the known opcodes see the opcodes subarticle.

The script is connected via ARM and BTB file (Chunk <6000>):

File:Armbtbctl.png‎

Unit Flags

The unit flags indicate the current status of the unit, like in combat or retreating. Most flags are still unknown. See the Flags subarticle for a list.

Call Stack

Every unit contains a call stack that can contain up to 48 elements. It's is used by call statements (to store calling function and line) and loops (to store the loop begin line).

Event handling

Every unit executes an event handler to allow communication between the regiments. It gets assigned with the command set_event_handler following the function. In the example above the handler would be function 15.

Everytime the regiment script executes it will check if new messages are pending. If yes it will call into the event handler (and store return func and position on the stack). After the event handling it will return to the old function if it was not altered with one of the set_event_handler_return_function commands (see also CTL Engine Control Flag below).

All events are stored in a global message queue and have the following structure:

struct EventMessage {
  DWORD targetId;
  DWORD eventId;
  DWORD arg1; // usually the source
  DWORD arg2;
  DWORD arg3;
  DWORD arg4;
  DWORD arg5;
  DWORD indexLast; // -1 if the msg was handled
}

Most functions set arg1 to the id of the sender. The id is an incrementing number starting with 0. At first the enemies get an id (in ARM-file order) followed by the allied units (only the ones available on the map). After the allied units the furniture (like destructable houses) follows. But the furniture does not execute a script function.

For a list of common events see the Event subarticle.

CTL Engine Control Flag

The behaviour of the CTL-Engine can be altered by setting flags in the Control Flag. Every unit stores its own version of the control flag.

Bit Notes
2 Indicates "true" (set by conditional commands)
3 Indicates that return_from_event_handler shall return to a different function which was set with one of the set_event_handler_return_function commands. If the new return function is the same as the old one the execution will continue at the old position (like a normal return).
5 Only works in combination with bit 3. If this flag is set the stack content is ignored, execution always continues at the beginning of the function.
Personal tools
communication