Warhammer Dark Omen Forum

Warhammer Dark Omen => Singleplayer => Topic started by: Ghabry on March 27, 2012, 07:59:45 PM



Title: Further CTL investigation
Post by: Ghabry on March 27, 2012, 07:59:45 PM
Because this would be really faaaar to off-topic, to post in Enemy units in campaign (http://forum.dark-omen.org/singleplayer/enemy-units-in-campaign-t1094.0.html):

#4c is nop/no operation (go to next instruction)

:)

When you figure out sth that is not directly related to enemies I suggest you post it here (and when enough progress is made lets update the wiki and ctldis).

So far we have:
#9d spell: Allows an enemy unit to cast spell with id spell (untested for magic items)
#99 66, 32768, 1: Casts dispell on the caller. Arguments are unknown. Must be called from an event handler
#d7 n (used in B5_01 and B5_01B, thats black pyramide) checks your game if you defeated Carstein (n = 1), Hand of Nagash (n = 2) or Black Grail (n = 3). (Thats used to disable these units, but n = 1 is not used)
#94 n Adds n magic points to the enemies global magic pool
#93 n Checks if the enemy has at least n magic points

Horses need teleport_to2 for proper initialisation, infantry needs teleport_to

This is somehow connected to artillery converting to infantry on retreat (artillery gets destroyed)

on_event 23
    clear_unit_flag2 1
    #bd 8
    set_event_handler 24
    test_unit_flag1 8192


Tests the Unit Id of the unit:
test_unit_r_eq_i -278, n
n is the Unit Id you want to check.


Title: Re: Further CTL investigation
Post by: cuthalion on March 27, 2012, 08:05:51 PM

Horses need teleport_to2 for proper initialisation, infantry needs teleport_to


It's not exactly cavalry vs infantry, because 2 similar infantries are sometimes 'incompatible' as well.

I have a grounded guess that issue is connected to sprites, or rather sprite types, but I haven't investigated it thoroughly, nor I am fully familiar with sprites format.


Title: Re: Further CTL investigation
Post by: cuthalion on April 01, 2012, 07:32:36 PM
#98 66, 16384, 1
Necromancer in B4_05 uses this to cast doombolt on the stone. Before this there goes instruction
set_unit_flag2 16

I tried to force another unit cast it but it crashed - I may have missed something, will try again when I have chance.
That other unit had the spell with #9d, had necromancer's handler but it didn't avail.


Title: Re: Further CTL investigation
Post by: cuthalion on April 02, 2012, 10:35:43 AM
#54 46

This is also a teleport like teleport_to2. Is used for instance in B4_06 (mission with a mere in the centre) in Func 1, Func 2.

I have a general feeling that different campaign parts were written by different people :) The same results are achieved by somewhat different script techniques. Any particular handwriting can be distinguished by B1, B2, B3, B4 - 4 parts of the campaign :)


Title: Re: Further CTL investigation
Post by: Ghabry on April 02, 2012, 11:11:05 AM
Yeah you can also see that there was no real conversation between the devs when you look at the script languages: CTL and WHMTG have nothing in common. :)


Title: Re: Further CTL investigation
Post by: Ghabry on April 06, 2012, 02:02:49 PM
There are 8 regiment registers (for unit_r-commands) and 8 global registers (for global_r-commands)

sleep2 is actually sleep if prev statement was true.


Title: Re: Further CTL investigation
Post by: Ghabry on April 08, 2012, 12:51:23 AM
About #bd 8 (used to transform the artillery):
At first: The first 3 bits are ignored

It checks if the unit has unittype 8 (that's infantry here). If the unittype is the same it sets the false flag.
If not it sets the unittype to 8 (the first 3 bits survive) and sets the true flag.
Because the flags are set you can use a conditonal like iftrue to check the result.

Trivia:
The buildings have there own CTL-Structure (or better Regiment-In-Battle-structure) during the battle but don't execute a script function. They have regiment alignment value 0x20 (dec 32).


Title: Re: Further CTL investigation
Post by: Ghabry on April 08, 2012, 04:25:57 PM
Added CTLdis (http://en.dark-omen.org/downloads/view-details/1.-modding-tools/4.-miscellaneous-tools/ctldis.html) to the download section (thats the same version I posted in the forum a while ago).

I'm also updating the wikis CTL article (http://wiki.dark-omen.org/do/DO/CTL). All brainstorming stuff was moved to Talk and some general information were added.
I will also (slowly) update the documentation of the opcodes. For now all known codes up to 0x25 have been added (more will follow). So check this out periodically. Worked together with Rob and we figured out some new opcodes.
When the wiki is up-to-date it's also time for a new CTLdis-version.


Title: Re: Further CTL investigation
Post by: cuthalion on April 08, 2012, 04:32:17 PM
Very cool indeed :)


Title: Re: Further CTL investigation
Post by: olly on April 08, 2012, 07:24:14 PM
Agreed

:)



Title: Re: Further CTL investigation
Post by: cuthalion on April 09, 2012, 09:31:12 AM
I don't know if it's known already..
If I write .func 99 and call it from .func 100, the game crashes. I have to append it to the end, as say .func 149 and call it, then it works fine.

The other note is about that randomizer. I seem to have made it work, the problem now is to pick up correct values.

I inserted its call in .func 100 right after set_timer_100, wait_for_timer in the main do-always cycle.

Out of 20 attempts it returned:
7,8 - 6 times
5 - 5 times
6 - 1 time
1 - 1 time
1 time nothing happened, I wonder if the value was outside the range 1-10.
I didn't cover all possible values with my 'if-else', but only 1-10.

It's ok that the values are these, though I am not sure why it returned 6 much less than it did 5 or 7. Maybe it's just a not large enough selection thing.


Title: Re: Further CTL investigation
Post by: cuthalion on April 16, 2012, 07:46:02 AM
As far as I understand, unit level isn't stored as a separate byte but is calculated based on a unit experience.

I'd like to be able to set up CTL logic based on a unit's level.
I didn't find any functions that would compare values  with >, <

Can there be a roundabout way to achieve what I want?


Title: Re: Further CTL investigation
Post by: Ghabry on April 16, 2012, 08:47:38 AM
I don't even know of a value that stores the experience. But it would make sense if there is a value in the CTL-block that handles experience because its needed during battle.

And no there is no way to check for something else then (In)equality in CTL.
The basic functions are all very limited. No <, > compare, no substract command, no way to assign the value of a register to another register.


Title: Re: Further CTL investigation
Post by: cuthalion on May 03, 2012, 03:19:19 PM
    do
        set_timer 50
        wait_for_timer
        #d5 128, 5
    whilenot

This piece of code is used to prevent an enemy regiment pop on the battlefield until an event occurs.
The unit tends to appear as another unit dies. I've a suspicion #d5 checks the amount of alive enemies on the battlefield. But maybe I am wrong: unclear parameter 128 - maybe a flag but I am not sure...


Title: Re: Further CTL investigation
Post by: Ghabry on May 03, 2012, 06:43:59 PM
#d5 does the following:
arg1: alignment
arg2: compared against the counted units.
if (counted >= arg2) false flag is set, true otherwise.

It counts the unit if it is active (unitflag1 & 1), the alignment (128 = evil) matches and unitFlag2 & 2048 is not set updateand it has at least one alive unit/update. If the unit was counted unitflag2 & 0x100 is set.
The alignment check only works for 0x80 (enemy), 0x40 (peasants) and 0x20 (furniture, but this is not counted ^^). Good units have 0x0 so you cant use this to check how many units are deployed by the player -.-

And I would say we can make an assumption: If a argument is 128 its probably the alignment.

So your guess is completly correct. It returns false until the number of enemy units falls under 5.


Title: Re: Further CTL investigation
Post by: Ghabry on May 03, 2012, 10:04:06 PM
#cd checks if an unit attribute (http://wiki.dark-omen.org/do/DO/ARM/Regiment_attributes) is set. (true if it is)
#ce sets an attribute (temporary)
#cf clears it (temporary)
(to get the bit just count in Wh32Edit from Block 1 to Block 4, every checkbox is a bit)

#bf is likely to spawn a regiment
arg1: 1: Fanatics, 2: Zombie (same as spell)
arg2: CTL Function to execute
arg3: unknown
arg4: looks like some offset

#c0
Returns true if the number of arg1 < aliveUnits

Via these opcodes we can figure out:
.func 121
event 78 spawns one fanatics when:
aliveUnits >= 5, aliveUnits >= 11 and aliveUnits >= 17.
Fanatics execute Function 140.
After this it clears the fanatics flag.
Same for .func 125 but the code looks unreached (there is a return between).

#69 is send event to self
arg1: event id

#8d: Checks leader missile weapon.
If arg1 is -1 return true if there is any missile weapon.
If arg1 is not -1 return true if missile is same as arg1.

Used in .func 100:
If unit class is monster:
  If has missile weapon
    event handler 105 (archer)
  else
    event handler 102 (basic unit)
  endif
endif

Used in .func 112 and .func 113 to check for crossbow

#b7: Sends a message to the sender (use in event handler after get_event was called)
arg1 of the received message must be a sender id, otherwise this will fail.
arg1: Event id
arg1 of the message gets set to the id of the current unit
Target is the sender of the last message.

#c9: Clears the last event (got with get_event)

#f0: Replaces the unit name of the current unit with the name id if some other unknown var is 1. o_O (wtf???, purpose???)
The opcode is nonsense, but thanks to this: I think I found the function that replaces the unit name with the string referenced by the name id. The game replaces Goblin with Fanatics with Goblins btw, have you ever noticed this? (nameId is changed) ;). If it is the function I will provide a patch via my Mod Selector DLL then you can provide the enemies unit name via the unit name field of the regiment.


Title: Re: Further CTL investigation
Post by: olly on May 04, 2012, 12:21:20 AM
Outstanding!

:)


Title: Re: Further CTL investigation
Post by: cuthalion on May 04, 2012, 06:25:30 AM
Nice finds! I got 1-2 ideas how to use it though I need a better insight of how the main enemy units cycle works - that 'search_and_attack' and other stuff around there. Because now it's not clear where exactly to place in CTL file those ideas I got :p

BTW yes, I noticed Goblins with Fanatics are always just Goblins on the battle field, when I tried to use GwF name slots in EngRel for my renamed units. A patch that picks up unit name on the battlefield from regiment name would be handy indeed.


Title: Re: Further CTL investigation
Post by: cuthalion on May 04, 2012, 10:33:18 AM
One more comment-question

#c0 seems to crash if called outside Event Handler. (I think many other functions behave the same way)
So my question about this.

I want an enemy infantry tank (that protects artillery from my Xbows) move forward as it suffers casualties.
#c0 inside do-while crashes mission on start.
Instead, I use

send_event_to_this 93 (93 is an unused event Id for Infantry units)

And in event handler I write
on_event 93
 #c0 10
 iftrue
  blablabla
 endif
 end_event


This piece seems to work properly. So the question: Is it OK to use any unused event Id for my purposes or may it cause troubles? I know that certain events have predefined Ids even though they may be absent from infantry event handler on a particular mission.


Title: Re: Further CTL investigation
Post by: Ghabry on May 04, 2012, 10:44:13 AM
#c0 crashes? That sounds impossible because the only thing it does is really comparing a number against another one :D.
I have no idea if the game internally uses event id 93. But if the events are really only used by the CTL script it should be save to use.


Title: Re: Further CTL investigation
Post by: cuthalion on May 04, 2012, 10:52:56 AM
Yep, tested #c0 again and it didn't crash...Maybe that crash was due to another reason, and I didn't investigate further.


Title: Re: Further CTL investigation
Post by: Ghabry on May 04, 2012, 10:54:44 AM
#A2 (search_and_shoot_enemy)
up to
#AC (search_and_attack_enemy)
Are all doing similiar stuff, would be cool to figure this out, but is a bit complicated ^^

The only things I know about these yet:
if arg1 != -1 then arg1 is the event (with id arg1) the caller will receive when something was found. About the source I have no idea yet but it could be the id of the unit found.

For search_and_attack: arg3 is the attribute that should not be set (4096 is steam tank, makes sense).

gah so many opcodes. Guess updating wiki and ctldis slowly becomes high priority now ;).


#86 and #9f are the same (unknown) opcodes


Title: Re: Further CTL investigation
Post by: cuthalion on May 04, 2012, 11:06:25 AM
Well, I dunno about priorities :) but in general - yes I have a problem that I forgot those opcodes I remembered before, and when I encounter them again in different CTL parts I need to recall everything anew. If ctldis were updated I would appreciate. At least in 1 mission I will have to write all enemy CTL behaviour from scratch :p - the Fortress Map.

Also, a valid topic about Steam Tank. In all 3 missions where Steam Tank is present, all enemy CTL scripts have special attitude to it. I wonder what exactly is there, though probably now it's almost enough information to figure it out.
Just a point for all campaign creators who don't (didn't) edit CTL. The tank is identified by Unit Id = 14, but not by Unit attribute 'steam tank'. Maybe, there is no function that checks other units attributes anyway...
So if to place tank in the Army under a different Id, enemy will treat him as an ordinary unit and thus will misbehave.
And vice versa, if another unit is placed under Id=14, enemy will treat it as steam tank and again, will misbehave.


Title: Re: Further CTL investigation
Post by: Ghabry on May 05, 2012, 01:27:43 PM
CTLDis (http://en.dark-omen.org/downloads/view-details/1.-modding-tools/4.-miscellaneous-tools/ctldis.html) has been updated.
You have to dissasemble all CTL files again because you cant assemble script files that are written in the old ctldis format (commands were renamed). So all line comments will be lost, sorry.

Wiki is updated (http://wiki.dark-omen.org/do/DO/CTL/OpCodes), too. Its not so clean like the first items but I wanted to finish this fast and its better to have a bad documentation then none ;).


Title: Re: Further CTL investigation
Post by: cuthalion on May 05, 2012, 01:36:53 PM
Great!
Thank you very much :)


Title: Re: Further CTL investigation
Post by: olly on May 06, 2012, 01:12:12 AM
Brilliant progress discovering 37 new ones and revising many existing functions with better descriptions

:)



Title: Re: Further CTL investigation
Post by: Ghabry on May 16, 2012, 10:14:11 AM
Check for spell book (everything is 32bit so will always work):
test_unit_r_eq_i 70, n
n = -1 (none), 22 (bright), 23 (ice), 24 (waagh), 25 (dark)

Number of magic items:
test_unit_r_eq_i 71, n (n = count)

Magic Item 1:
test_unit_r_eq_i 72, n (n = item id, not sure if 0 or -1 is none)

Magic Item 2:
test_unit_r_eq_i 75, n (n = item id, not sure if 0 or -1 is none)

Magic Item 3:
test_unit_r_eq_i 78, n (n = item id, not sure if 0 or -1 is none)

Spells directly follow, summed up there are 12 slots.

Items >= 57 (treasures) are handled in a different way, you cant check them with these commands.

If this doenst work I calculated the offset wrong.

The level of the unit is at -277, but thats unreliable because its only 2 byte and other data follows... (test if it works for you)


Title: Re: Further CTL investigation
Post by: cuthalion on May 16, 2012, 10:47:00 AM
Interesting,

so what's in byte equal to reg-71 - amount of magic items or first magic item?


Title: Re: Further CTL investigation
Post by: Ghabry on May 16, 2012, 11:21:01 AM
Typo fixed, thx.


Title: Re: Further CTL investigation
Post by: cuthalion on May 24, 2015, 05:10:44 PM
A reminder to myself or to anyone who edits ctl.

Argument X for function that Ghabry calls 'move_rand_in_radius X' is not a btb subrecord's sequence number or something.
It is a subrecord that includes
<INT type="11"> X </INT>.
Also, it teleports as a regular teleport if need be. Just regular teleport uses subrecord sequence number instead of this parameter.


Title: Re: Further CTL investigation
Post by: cuthalion on May 24, 2015, 09:20:25 PM
Another reminder.

test_units_alive_le_i 128, 4
iftrue
 blablabla (for example set register to 0 and throw self in battle)
endif

This function, as the name hints, returns TRUE if there are <4 units left under AI control. Hard to say whether <4 or <=4, and also if neutral units count. I am not sure what 128 means. Probably it indicates enemy side. The function in bundle with set_timer/wait_for_timer helps to organise enemy units flow non-stop rather than a number of waves.


Title: Re: Further CTL investigation
Post by: Ghabry on June 20, 2015, 03:17:53 PM
I made a minor update to ctldis. This renames all the regiment_search functions.

Important update instructions because keywords changed:

1. Use the old ctldis in assembling mode (mode=0) to create a CTL.
2. Replace the _orig.ctl file in the directory with your CTL file.
3. Use the new ctldis in dissambling mode (mode=1) to create new script.txt
4. Use new ctldis in assembling mode (mode=0) to create the CTL

The first argument of all search functions is the event_id that is sent to the callee from the found regiment (Except if -1). The 2nd and 3rd argument vary depending on the search function.

Difference between the search functions from a low level point of view:


                               distfunc unittype unk nth  dist uflag1 attribs
search_regiment_uflag_attrib   0        0        0   1    100  arg2   arg3
search_regiment                0        0        1   1    100  0      0
search_regiment_2              1        0        0   1    100  0      0
search_regiment_3              1        0        1   1    100  0      0
search_regiment_unittype       0        arg2     0   1    100  0      0
search_regiment_unittype_2     0        arg2     0   1    100  0      0
search_regiment_nth            0        0        0   arg2 100  0      0
search_regiment_nth_2          0        0        1   arg2 100  0      0
search_regiment_unittype_nth   0        arg2     0   arg3 100  0      0
search_regiment_unittype_nth_2 0        arg2     0   arg3 100  0      0
search_regiment_distance_uflag 4        0        0   1    arg2 arg3   0



- distfunc: Distance function used, no idea what the difference is
- unittype: Unittype that the searched unit MUST have.
- unk: When 1 does something I couldn't figure out
- nth: Not completly sure, my guess is the list of found regiments is sorted and then the n-th regiment is picked (where 1 = the closest)
- distance: Search distance (not sure how big a 100-circle is)
- uflag1_xtra: Unit Flag 1 bits that searched unit most NOT have, inactive/retreating and similiar units are never found
- attribute: Attributes that the searched unit must NOT have, e.g. 4096 = engine of war

As you can see search_regiment_nth and search_regiment_nth_2 are the same... same for search_regiment_unittype_nth and search_regiment_unittype_nth2


Title: Re: Further CTL investigation
Post by: olly on June 20, 2015, 05:58:28 PM
Great Thanks!

:)


Title: Re: Further CTL investigation
Post by: cuthalion on June 21, 2015, 08:44:20 PM
Ghabry, could you give us a few examples of where these functions are used and how you interpret the logic?


Title: Re: Further CTL investigation
Post by: Ghabry on June 21, 2015, 10:14:55 PM
Isn't the table clear?
Code:
search_regiment_uflag_attrib 4, 0, 4096
Send event 4 to callee when a unit (flags is 0 = don't matter except retreat) that isn't a steamtank (4096) is in normal (100) distance.

More interesting:
Code:
test_self_at_node 9
iftrue
    ; When at node 9 do a normal distance (100) search
    ; for units that are not in close combat (UnitFlag1 = 512)
    ; and send event 58 to callee if found
    search_regiment_distance_uflag 58, 100, 512
else
    ; When we are not at node 9 still search for enemies at close distance (50)
    search_regiment_distance_uflag 58, 50, 512
    iffalse
        ; When we are not moving (UnitFlag1 = 16) then continue moving to node 9
        test_unit_flag1 16
        iftrue
            move_to_node 9
        endif
    else
        ; Unit was found, guess event 58 will handle the attack
        block_movement
        sleep
    endif
endif

And in the event handler you have
Code:
on_event 58
    #86
I guess #86 sets the event source as a target


Title: Re: Further CTL investigation
Post by: cuthalion on June 22, 2015, 08:12:50 AM
A few things/questions

1. Distance is usually measured in battle map coordinates. It is so for BTB blocks: range of node etc. It is so for ranged weapons: maximum range seems to be battle map coordinates. BTW 100 circle distance is less than shortbow range.
My guess is: if this is really a distance, then this is distance measured in percents, and 100% = ranged weapon maximum range.

 I always thought 50/75/100 to be a kind of probability rather than distance. In B101 and a lot of other missions enemy archers have the argument = 50 when they are not at main target point, and have argument 100 when they are.
And in B101, when second goblin archers regiment appears in the north: if you stand still, sometimes they come to shooting distance and fire at once - from maximum range that shortbow allows. And sometimes they come very close to your unit before they start sooting. This is why I interpreted 50 as probability: even if they see you in range, they do not always shoot at once.

2. All those flags: "in close combat", "steam tank", "fleeing" and all others - where can I get the list of them? or at least a list of known flags?



Title: Re: Further CTL investigation
Post by: Ghabry on June 22, 2015, 12:55:19 PM
I think the only public list is here:
http://wiki.dark-omen.org/do/DO/CTL/Flags (http://wiki.dark-omen.org/do/DO/CTL/Flags)

But looks incomplete, guess I never published mine which is still filled with lots of guesses/assumptions/unknowns.


Title: Re: Further CTL investigation
Post by: cuthalion on July 13, 2016, 07:31:06 PM
In wood elf campaign, it was always disappointing for me when my rider archers did not chase retreating enemy: In the midst of battle automatic trample helps a lot. So I decided to figure out how I can force archers to 'CRUSH THEM!'.
The answer seems to be as follows ('seems' because I have not tested it properly yet)

func 125 is archers event handler.
Event 15 is when enemy breaks. I just copy-pasted code of event 15 from function 122 (event handler for cavalry and infantry) to function 125 and archers started chasing.
What I need to do now is to overwrite this part only for rider archers. Probably again, unit_id is the an only option.
Also, would be nice to test many_vs_many melee fights. Hope nothing is buggy there.


Title: Re: Further CTL investigation
Post by: olly on July 13, 2016, 08:41:01 PM
Sounds great, let me know if you need any tests. Does this behave differently from Always Pursue?

[attachment=1]


Title: Re: Further CTL investigation
Post by: cuthalion on July 14, 2016, 05:31:33 PM
It does. 'always pursue' prevents chasing troops from stop. They run after victim to the bitter end. By the way, the flag seems to crash the game when is set to archer regiments.

I wanted to make my cavalry archers trample enemies who break instead of standing still waiting for a command. For that I found a difference in event handlers for cavalry and archers which seems to be responsible for this very moment. And replaced.


Title: Re: Further CTL investigation
Post by: olly on July 14, 2016, 06:13:20 PM
Cool!

:)



Title: Re: Further CTL investigation
Post by: Leilond on April 23, 2017, 10:49:41 AM
Last days I had several intense CTL/EVENTS testing sessions. Chaged the code forward and backward, adding “play_self” and “play_other” OpCodes here and there; commented, changed handlers, added and removed undocumented code a lot of time. It was hard and fun, sometimes frustrating.
I undestands things a bit better now, and I add my consideration for the good of the community. Feel free to correct, comment and eventually use any part of this in the way you think it's better.
This is a VERY long post, thus take your time if you're interested in deep CTL analysis

EVENTS HANDLING
All units use the same way to handle events.
There is a “base” function (.func 121) that handles some events (66, 68, 69, 61, 65, 78, 48, 54, 1, 25, 57, 26, 9, 14, 22, 24, 48, 2, 5, 11, 10, 8, 16, 28, 29, 17) in the same way for all units.
There is a “specialized” function for each unit type (Ground units 122, Artillery 123, Wizards 124, Archers 125... didn't verified it there are other functions like “monster” or the like) that handles other events in a different way for for each unit type. The specialized function always call the “.func 121” base function after doing his event handling.
Each unit has his “personal” event handler, that can “override or complete” events controlled by “base” and “specialized” functions (or handle events unhandled) and then simply “call” the specialized function
An example of event handler for an infantry or cavalry is
Code:
.func 14
clear_ctrl_flag 8
do
get_event
on_event 4
#44
set_return_func_iftrue 127
end_event 6844
call 122
@0xABC
test_more_events
while
return_from_event_handler
In this simple handler example, we want the troup to do something different from “standard” for event 4 (the event generated by “search_and_attack_enemy 4, 0, 4096”) and then “call 122” to make the rest of the events to be handled in “standard way”.
If you use “end_event 6844”, this particular event (in our example “event 4”) will not be handled by other handlers, the script will jump to the 0xABC label and the next event will be handled. If you use “end_event 3567”,  the event will be eventually handled by other “on_event 4” statements in “base” and “specialized” functions.

This is the way events for enemy troups are handled in all  maps and thus the way we can do for our campaigns. Make an handler to manage some events, using “ end_event 6844” to completely ovveride en event or “ end_event 3567” to make some things happens before standard handling, and then call the correct specialized function (122, 123, 124, 125) to handle “standard” event actions.

I looked for event understanding since I started to make my personal campaign, because I felt immediatley that is the place where the secret of the perfect AI live.
This were all my “discoveries”

EVENTS
 - 61. Hit by ranged attack (spell too). The event seems to fire only if at least one shot landed (no matter if no casuality done because the unit is saved by armor or shield of plotos). Thus if a unit is under fire but for that round not a single hit reach the target, the event isn'f fired.
 - 5. Event fired when unit is being charged, in the moment the charge start (before the actual fight start, but after the “Charge!” cry is sent)
 - 10. The actual hand to hand fight started (no matter who was the charger)
 - 12. “Lost a hand to hand fight round or charged in the flank/rear” AND “failed the leadership test”. Usually this send back to “.func 126” (Artillery) or “.func 132” (all other unit type) that contains istruction to make the unit rout.
 - 22. Friendly unit completely destroyed
 - 52. Some heavy damage sustained by ranged attacks. I cannot say the correct value, but if a unit loses something around 25% of its alive members, this event fire up.
 - 79. Hit by a spell (fired before event 61).
 - 15. Enemy flee the hand to hand combat (rout)
 - 16. Unit succesfully regroup after routing
 - 25. Regroup after pursuing an enemy.
 
CTL OPCODES
 - #5b and #5d. This codes send the unit routing no matter what (I tried immune to fear and will never rout, but the code still send the unit retreating. I will try to update my “ctldis.py” and call this cod “unit_always_rout1” and “unit_always_rout1”.
 - test_self_afraid. First I thought this was a “test if the unit fail a fear test”, while it simply means that the unit is “vulnerable to fear”. Unit with “Will never rout” and/or “immune to fear”, always pass this test, while all other units always fail the test
 - search_and_attack_enemy. Big issue here. This opcode, diffently from what I thought and undestood at first read, DO NOT make the unit really start to go to the fight, but only verify if there is some possible enemy in sight, set the conditional flag to true and fire the arg1 event for the unit. Thus “search_and_attack_enemy 4, 0, 4096” will fire event 4 for this unit if there is an enemy in sight to fight, but the unit will stand still and go on doing what it was doing.  The event handler, for event “4”, usually contains “#44” and “set_return_func_iftrue 127”. In this “.func 127” there are these opcodes: “#14 4, -1”, “#48”, and finally “#4f”. This three codes will make the unit move versus the designed enemy and fight if they “contact”. To make the unit “charge” when at range, it is first tested that the enemy unit is at the right range to be charged (#58) and then (if true) the charge action is launched (#59). A better name for “search_and_attack_enemy” could be "test_enemy_to_attack_in_sight".
All this, in B101.CTL, this is performed by this code.
In “.func 0” there is this:
Code:
search_and_attack_enemy 4, 0, 4096
that fire the event “4” that is handled by “.func 14” with this code:
Code:
            on_event 4
                #44
                set_return_func_iftrue 127
                end_event 6844
And then all the functions called starting from ".func 127"
Code:
.func 127
    #14 4, -1
    send_event_to_stored_unit 20
    wait_unit_flag1_clear 16392
    play_self 1
    #48
    #4f
   ;now the unit start to walk toward the enemy
    do
        for 2
            set_timer 10
            #58
            ;#58 => test if the enemy is in range for charging
            goto_iftrue 129
            wait_for_timer
            test_unit_flag1 16
            iftrue
                restore_ip
            endif
        next
        #49
    always


.func 129
    #59
    ; #59 => Charge
    iftrue
        play_self 2
        #14 19, -1
        do
            sleep
            #b0 0
            test_unit_flag1 16
        whilenot
    endif
    goto 134


.func 134
    hold
    sleep
    wait_unit_flag1_clear 8
    #50
    restore_ip
   “.func 134” seems to be the end of the battle and is fired if the charge failed (#59 returned false) or the “unit_flag1 16” is 0 (I think this mean the unit is still fighting, pursuing or locked to attack an enemy).
 - search_and_shot_enemy. Apply the same consideration made on "search_and_attack_enemy". A better name could be "test_enemy_to_shot_in_sight"
 - #44. It's used to make some test and always followed by some sort of “set_return_func” statement to make the unit start a fight (usually .func 127). I'm sure the test is failed if the unit is routing. I can reasonably suppose that “#44” is a test for being sure the unit is “able to fight” (unit alive and not routing/fleeing/paralyzed/pursuing). I will try to update my “ctldis.py” and call this opcode “test_unit_can_fight”
 - #14. This is probably the not-documented opcode most used out there... being able to understand what this damn code do, could be an big improvement of CTL understanding
 - return. What's the meaning of any istruction after a “return” statement? It look like “wasted code”, isn't it? As an example, in B101, you find in “.func 122” a “return” statement followed by some othere statemens that I do not see how they can be executed and thus I cannot see their pourpose.
 - #58. Verify if the enmy unit is at the right range to be charged. I will try to update my “ctldis.py” and call this opcode “test_charge_range”
 - #59. Charge. I will try to update my “ctldis.py” and call this opcode “charge2” (because there still is another “charge” OpCode)
UNIT FLAGS
I find that a lot of “test_unit_flagX n” and “wait_unit_flagX_clear n” are made without apparently being any “set_unit_flagX n” (or clear) being anywhere. Is it possible that some of these flag are set/cleared by default in some situations?
There are “wait_unit_flag3_clear, wait_unit_flag3_set, test_unit_flag3”, but there isn't any “set” or “clear” for flag3... What does this mean? In B101.CTL there is “wait_unit_flag3_clear 8192”... this means that flag3 update is hardcoded in the game. This make manipulation of flags a bit dangerous if not perfectly understood, and thus I suggest to use “unit registers” instead of “unit_flags”, unless you know what you're doing

Hope this hepls someone to improve in CTL understanding


Title: Re: Further CTL investigation
Post by: olly on April 23, 2017, 01:03:20 PM
Fantastic! There's loads of useful info for the wiki and to put into Dark Omen 2

many thanks

:)


Title: Re: Further CTL investigation
Post by: Ghabry on April 23, 2017, 07:31:03 PM
Thanks for your observations. About search and attack enemy did you see my post in this thread from 2 years ago? Based on my latest findings I'm updating the table:

Code:
                             distfunc unittype vision nth  dist uflag1 attribs op
find_enemy_uflag_attrib      0        0        0      1    100  arg2   arg3    a2
find_enemy_visible           0        0        1      1    100  0      0       a3
find_enemy_simple            1        0        0      1    100  0      0       a4
find_enemy_simple_visible    1        0        1      1    100  0      0       a5
find_enemy_unittype          0        arg2     0      1    100  0      0       a6
find_enemy_unittype_2        0        arg2     0      1    100  0      0       a7
find_enemy_nth               0        0        0      arg2 100  0      0       a8
find_enemy_nth_visible       0        0        1      arg2 100  0      0       a9
find_enemy_unittype_nth      0        arg2     0      arg3 100  0      0       aa
find_enemy_unittype_nth_2    0        arg2     0      arg3 100  0      0       ab
find_enemy_distance_uflag    4        0        0      1    arg2 arg3   0       ac

All of them generate arg1 as an event.

- distfunc: Looks like 0 is the direct (diagonal) distance, 1 just considers x or y (bounding box I guess), 4 is some smart thing that considers terrain e.g. (probably useful for archers).
- unittype: Unittype that the searched unit MUST have.
- vision: When 1 the vision of the caller is considered (worse when walking or fighting), except if you have 360° vision (spider) they always find everything
- nth: Not completly sure, my guess is the list of found regiments is sorted and then the n-th regiment is picked (where 1 = the closest)
- distance: Search distance used for the distfunc (not sure how big a 100 is)
- uflag1_xtra: Unit Flag 1 bits that searched unit most NOT have, inactive/retreating and similiar units are never found
- attribute: Attributes that the searched unit must NOT have, e.g. 4096 = engine of war

Also want to clarify other opcodes:
test_event_from_close_combat
This is slightly incorrect. That field is already populated when you select the enemy as a attack target.
Also archers/artillery use the same field to mark the target
so more correct is maybe "test_event_from_target"?

#5c: General purpose retreat
#5b: Same as #5b, considers the target (probably to invert the direction)
#5d: Same as #5c, inverts the retreat dir (needs test if forward or backward)

#86: This one is extremely similiar to #44. I would call this one "test_unit_can_fight" because #44 has an extra feature:
#44: Same as #88 but also checks if the sender of the last event is retreating (and returns false in that case)
#9f: Same as #86 (yeah, really)

#5a: General purpose charge (already named OP_charge)
You said #58 is a test if the enemy is in charge range. This seems legit.
#59: This sends event 7 to the unit being charged

According to my notes wait_unit_flag3_clear 8192 is "Walks to magic item", your question helped me to investigate the op-codes that are around it:

#d0: find_and_collect_item. arg1 is item to find (in the trading post they collect treasure 100)
#d1: only used when d4 is true: Takes the distance (func arg1) of magic item event-arg2. And returns TRUE and collects it when close enough.
#d2: Check if the unit currently collects an item and if the item matches event-arg2
#d3. This is already called test_event_arg3. Could be renamed: This checks if event-arg3 of the last event matches arg1 but this is in the magic item opcode group, so: It is only used in event 69. So 69 is very likely item dropped.
#d4: Only used with event 71, whatever that is. #d4 checks if any regiment in our party is already collecting the magic item specified in event-arg2 (which is an index in some struct) (TRUE if any)

everything after a "return" is dead code

#14: This is some multi-purpose crap. Depending on arg1 it can do 16 (!) different things. The 2nd argument is an event id. And the field of the regiment structure it works on is not documented by me yet. But because you said it is related to fighting I will trigger a fight and check in the debugger to see what it contains, maybe the ref to the enemy being fighted...

#3e registers a timer function for invoking #14 >.<
arg 1: arg to pass to 14
arg 2: run every nth script update

It is worth playing around with "#3c 240, 0" because the 1st arg is used as some distance for most of #14.

BACK TO #14:

I see 10, 12, 13. 12 for peasants. 13 for enemy. 10 for friends.

10 is related to fanatic releasing and generates event 78 which is obviously fanatic spawning.

12 is a mess. Could be related to screaming and running when enemy is close?

13. When the enemy is idling it searches for a unit to move to (basic attack logic?), if there is none it searches for a magic item and generates event 71 (aaah! That's how 71 is generated)

When non-idling:
Fanatics handling (event 78).
When it found a target it can shoot magic (items) through event 66.
Also permanently rescans for closer enemies and magic items. I guess attacking works over event 3. Event 3 invokes #43 which has branching for Steam tank (event 85) and everything else (event 7). Meh check this later again, because this gets worse...

So to want a completely stupid unit: Get rid of #3e.

Terminology for the next text: There are basicly two different types of "targets".
The Player can specify a target by clicking on the banner. The target is overwritten when in Close combat (CC) with somebody.
The other target is the 14h-target. Which is for the Player only populated when a regiment starts following a retreating regiment.

The enemy uses the 14h-target more: E.g. when moving to an enemy, 14h-target is set to this (havn't checked if target is also populated but would make sense - but at least in CC it is)

So will use 14h-target and target for the remaining text:

-----
Usages of #14 in B1_01:
Code:
on_event 19
#14 8, 4
end_event 6844
Sends event 4 to the caller (event source is sender of last event) when:
 - the sender of last event has a target
 - a distance check between caller and sender passes
 - caller has no target.

Note: Event 4 is:
Code:
on_event 4
#44 ; test can fight
set_return_func_iftrue 127
end_event 6844

Code:
on_event 20
#14 8, 4
end_event 6844

Code:
on_event 21
#14 9, 4
end_event 6844
Sends event 4 to the caller (event source is sender of last event) when:
 - The sender of the last event has a 14h-target
 - caller has a target
 - a distance check between 14h-target of sender and caller passes  

Code:
on_event 5
#14 5, -1
iftrue
send_event_to_stored_unit 21
endif
end_event 6844

Looks like this checks if the sender is a better candidate (distance-wise) then the 14h-target and sets 14h-target to sender if this is the case (sets TRUE)

send_event_to_stored_unit: E.g. for spawned zombies the stored unit is the wizard who spawned them. Field could have more purposes.

The event arg of #14 is ignored.

Code:
on_event 14
#14 18, -1
end_event 6844

When sender matches 14h-target the 14h-target is cleared.
When sender matches "stored unit" (see above) the "stored unit" is cleared.

When sender matches the target, then:
 - Makes no sense to me :)
 - Unsure: sourceless event 25 is sent to the caller when not in CC I think.
 - Sound effect 31 is played

event arg of #14 is ignored. Hardcoded to 25 (srsly).

Code:
on_event 22
#14 17, -1
end_event 6844

Same as 18, see above

Code:
on_event 11
#14 7, -1
end_event 6844

Also too chaotic for me.
One part of this is generating enemy sighted events.

The one who encountered something gets event 28 (source is the enemy who was sighted)
The one who was sighted gets event 29 (source is the one who saw him)

Event arg of #14 is ignored.

Code:
on_event 65
test_event_from_target
iftrue
test_unit_flag2 4
iftrue
play_self 22
endif
test_unit_flag1 512
iftrue
#14 17, -1
else
send_event_to_self 25
endif
endif
end_event 6844

17 was already explained above.

Code:
.func 106
reset_call_stack
#14 4, -1
wait_unit_flag1_clear 16392
play_self 1
#48
sleep
#4f
do
for 2
set_timer 10
#58
goto_iftrue 129
wait_for_timer
test_unit_flag1 16
iftrue
restore_ip
endif
next
#49
always

This sends event 5 to the current target. source is the caller.

The event of #14 is ignored, hardcoded to 5 (srsly).

Code:
.func 107
    reset_call_stack
    charge
    play_self 2
    #14 19, -1
    do
        sleep
        #b0 0
        test_unit_flag1 16
    whilenot
    goto 134

No idea. Result depends on the race. Does not generate events.

Code:
.func 116
    #62
    #50
    play_self 3
    #14 1, -1
    #4a
    send_event_to_self_iftrue 3
    sleep_iftrue
    clear_unit_flag1 17842328
    clear_unit_flag2 16
    goto 110

Called when a regiment starts retreating. The one following it sets the 14h-target to the one it follows.

No event generated.

Code:
.func 127
    #14 4, -1
    send_event_to_stored_unit 20
    wait_unit_flag1_clear 16392
    play_self 1
    #48
    #4f
    do
        for 2
            set_timer 10
            #58
            goto_iftrue 129
            wait_for_timer
            test_unit_flag1 16
            iftrue
                restore_ip
            endif
        next
        #49
    always

Already explained.

Code:
.func 130
    #14 6, -1
    block_movement
    do
        sleep
        #c6
    while
    do
        set_timer 20
        wait_for_timer
    always

Code:
.func 140
    set_event_handler 141
    #3c 64, 0
    do
        set_timer 10
        wait_for_timer
        #14 16, -1
    always

No idea.

Code:
.func 141
    clear_ctrl_flag 8
    do
        get_event
            on_event 52
                #14 15, -1
                end_event 6844
            @0xABC
        test_more_events
    while
    return_from_event_handler

Seems to be related to random movement. Adds a random number to the direction.

More possibilities for #14 not in the CTL:

2: Searches for a regiment using the normal find_regiment function (distance 100).

Sends event 4 (#14 evt arg ignored, yeah!) to the caller (source is the found regiment)

10: Standard handler for friends. Explained at the top.

11: No idea.

12: Standard handler for Peasants

13: Standard handler for AI

---

Objective L (12): The unit with this unit id will never get a white flag. Bernhardt has this on the Black Pyramide map.

---

I have a (quite incorrect) list of unit flags if you are interested.

Maybe is also worth to update ctldis so that it dissasembles unit flags into something more readable (or at least in hex so you don't need a calc to convert them ;))


Title: Re: Further CTL investigation
Post by: Ghabry on April 25, 2017, 07:05:55 PM
I'm currently in the process of updating ctldis with the latest investigations and some prettifiers to get better output: https://github.com/Ghabry/ctldis

Also added Python 3 compatibility :)

e.g.:

clear_attribute ContainFanatics
instead of
clear_attribute 2097152

or

test_unit_flag1 Retreat | 0x8000
instead of
test_unit_flag1 40960


Title: Re: Further CTL investigation
Post by: olly on April 25, 2017, 08:54:47 PM
Fantastic thanks

:)


Title: Re: Further CTL investigation
Post by: Leilond on April 26, 2017, 08:37:39 AM
AWESOME
Thanks everyone... I'll study it better


Title: Re: Further CTL investigation
Post by: Leilond on April 26, 2017, 08:54:31 AM
This new ctldis.py do not work for me
I tryed to decompile B102 and recived this

Code:
 File "C:\Users\rcoletta\Desktop\ctldis\ctldis-master\ctldis-master\ctldis.py", line 531
    decompiledFunc.lines.append([opName, *newLine])
                                         ^
SyntaxError: invalid syntax


Title: Re: Further CTL investigation
Post by: olly on April 26, 2017, 08:55:44 AM
I had the same using Python 2.6 & 2.7 and Ghabry advised using Python 3 as it recognises the *newline

Works fine with Python 3.6.1
[attachment=1]


Title: Re: Further CTL investigation
Post by: Leilond on April 26, 2017, 09:19:36 AM
Perfect, thanks


Title: Re: Further CTL investigation
Post by: Ghabry on April 26, 2017, 11:28:03 AM
The script is now python 2 compatible. Fixed two issues in it.

Leilond: In case you want to do some prettifying and you know Python take a look at line 326 where the prettifier-dict starts.

The mapping is basicly: opcodename -> [dissasembler, assembler] (so list of 2 elements)

Ignore the assembler for now, they are unused and stubs.

The API is basicly:
The dissasembler and assembler are functions that except as many arguments as the opcode arguments has (so for all prettifiers by now it's only one arg) and the return value is a list of strings with as many list elements as the opcode argument has. So quite simple API to extend.

And Prettifier.flag_prettifier(flag, Prettifier.unit_flag_1) is a helper function which takes an op-code argument as 1st argument and a lookup-dict (see Prettifier.unit_flag_1 for an example) and returns a String with all bits (if posible substituted) and delimited by "|".

Oh and the OpCodes are not up-to-date yet. I have to sync them with the latest observations of the latest days first.

More stuff I want to prettify which doesn't need BTB/ARM parsing so is faster to implement and to make the "data types" of CTL arguments more clear:

  • play (sound effects)
  • spells
  • unit types
  • btb node arguments (e.g. n1 instead of 1)
  • event arguments (e.g. e1 instead of 1, for events that are clear this could be also changed to e.g. E_Charge)
  • function arguments (e.g. f1 instead of 1)
  • control flag (though there is almost nothing known about it)
  • label resolving (should work because every enemy only has one label)
  • end_event 6844 and 3567
  • that @0xABC event marker
  • Nice to have: Annotate functions with the enemy that executes them (needs BTB & ARM parsing)

Maybe should also provide some constant for "registers", e.g. that "-278" register cuthalion uses in his code to read the unit id of a regiment :D (awful hack I told him because the register functions don't do range checks. But you can only read 32bit values with this)

Shame that there is no function to write registers in registers. This way you could do arbitrary loads and abuse unit_flags for bit operations. :D


Title: Re: Further CTL investigation
Post by: Leilond on April 26, 2017, 01:45:09 PM
I don't know python language
I only understood that the translation hex=>opcode and back is done reading the "opNames" array and thus I undestood that simply adding a line like "0x5b:"unit_rout," in that array will make the code translation.

Thanks anyway


Title: Re: Further CTL investigation
Post by: Leilond on April 26, 2017, 01:49:15 PM
Thanks for your observations. About search and attack enemy did you see my post in this thread from 2 years ago? Based on my latest findings I'm updating the table:

Code:
                             distfunc unittype vision nth  dist uflag1 attribs op
find_enemy_uflag_attrib      0        0        0      1    100  arg2   arg3    a2
find_enemy_visible           0        0        1      1    100  0      0       a3
find_enemy_simple            1        0        0      1    100  0      0       a4
find_enemy_simple_visible    1        0        1      1    100  0      0       a5
find_enemy_unittype          0        arg2     0      1    100  0      0       a6
find_enemy_unittype_2        0        arg2     0      1    100  0      0       a7
find_enemy_nth               0        0        0      arg2 100  0      0       a8
find_enemy_nth_visible       0        0        1      arg2 100  0      0       a9
find_enemy_unittype_nth      0        arg2     0      arg3 100  0      0       aa
find_enemy_unittype_nth_2    0        arg2     0      arg3 100  0      0       ab
find_enemy_distance_uflag    4        0        0      1    arg2 arg3   0       ac

All of them generate arg1 as an event.

- distfunc: Looks like 0 is the direct (diagonal) distance, 1 just considers x or y (bounding box I guess), 4 is some smart thing that considers terrain e.g. (probably useful for archers).
- unittype: Unittype that the searched unit MUST have.
- vision: When 1 the vision of the caller is considered (worse when walking or fighting), except if you have 360° vision (spider) they always find everything
- nth: Not completly sure, my guess is the list of found regiments is sorted and then the n-th regiment is picked (where 1 = the closest)
- distance: Search distance used for the distfunc (not sure how big a 100 is)
- uflag1_xtra: Unit Flag 1 bits that searched unit most NOT have, inactive/retreating and similiar units are never found
- attribute: Attributes that the searched unit must NOT have, e.g. 4096 = engine of war
This is absolutely GREAT
This improve my chance of create smarter units A LOT

Going on studying the rest of the post


Title: Re: Further CTL investigation
Post by: Ghabry on April 27, 2017, 12:26:35 AM
Added now all known OpCodes to ctldis and type annotated all OpCodes (still without assembler, I add the assembling during the next days). Feel free to make suggestions.

Annotation is still incomplete, more to come.

What is already in:

X() means the argument is unused
E() means the argument is an event
F() means the argument is a function

Example output:

on_event E(71)
   event_test_any_friend_collects_this_item
   iffalse
      event_test_distance_and_collect_this_item 240
      set_return_func_iftrue F(137)
   endif
   end_event Filter



.func 0
    init_unit X(128)
    clear_ctrl_flag 0x8000
    set_label 0xabc0
    #3c 240, X(0)
    set_event_handler F(14)
    set_callback 13, 29
    set_global_r_i 0, 0
    set_global_r_i 1, 0
    wait_for_deploy
    save_ip
    find_and_collect_item Treasure_Chest_100gc
    set_timer 25
    wait_for_timer
    play_self 64
    reset_call_stack
    save_ip
    do
        wait_unit_flag3_clear CollectingItem
        find_and_collect_item Treasure_Chest_100gc
        iffalse
            find_enemy_uflag_attrib E(4), 0, EngineOfWar
            iffalse
                test_unit_flag3 0x400
                iffalse
                    add_waypoint 99
                endif
            endif
        endif
        set_timer 10
        wait_for_timer
    always



on_event E(69)
   event_test_item Treasure_Chest_100gc
   iftrue
      test_event_from_enemy
      iffalse
         test_global_r_eq_i 1, 1
         iffalse
            play_self 66
            set_global_r_i 1, 1
         endif
      endif
      broadcast_event_to_friends E(17)
   endif
   event_test_unit_collects_this_item
   iftrue
      test_event_from_enemy
      iftrue
         test_can_fight_and_sender_does_not_retreat
         set_return_func_with_restart_iftrue F(127)
      else
         set_return_func F(134)
      endif
   endif
   end_event Filter


That "can fight and sender doesn't retreat" appears to make sense because 127 contains:


.func 127
    #14 4, E(-1)
    send_event_to_stored_unit E(20)
    wait_unit_flag1_clear 0x8 | 0x4000
    play_self 1
    #48
    #4f
    do
        for 2
            set_timer 10
            test_target_in_charge_range
            goto_iftrue F(129)
            wait_for_timer
            test_unit_flag1 0x10
            iftrue
                restore_ip
            endif
        next
        #49
    always

.func 129
    charge_and_send_event_to_target ; event 7
    iftrue
        play_self 2
        #14 19, E(-1)
        do
            sleep
            #b0 0
            test_unit_flag1 0x10
        whilenot ; I guess this loop tests if the charge is finished.
    endif
    goto F(134)


Title: Re: Further CTL investigation
Post by: olly on April 27, 2017, 08:19:47 AM
Much more easy to use and follow

:)


Title: Re: Further CTL investigation
Post by: Leilond on April 27, 2017, 08:38:42 AM
Added now all known OpCodes to ctldis and type annotated all OpCodes (still without assembler, I add the assembling during the next days). Feel free to make suggestions.
...
Looking forward to use the new ctldis.py!!! It will make things a lot easyer!!!


Title: Re: Further CTL investigation
Post by: Ghabry on April 29, 2017, 03:02:25 AM
Assembling works now.

Annotating should be mostly complete. There are still some empty dicts (e.g. "Voice" for all the audio stuff) or almost empty (e.g. events) dicts. Feel free to fill them and to post them here so I can add them to the script.

You find this at line 460+.

Ignore game_status and alignment, I fill them later.

Please also take a look at the new scripts and try to figure out what some Unit and Control Flags could be. I have notes about them but most of them are uncertain, so want to see others opinion before I add my flawed data.

Edit: Have to recheck arguments of type "ID. Some of them actually check the UnitID, not an incrementing number (enemy+ally). But thats just a visual issue, doesn't impact the functionality


Title: Re: Further CTL investigation
Post by: olly on April 29, 2017, 01:57:03 PM
Awesome

:)


Title: Re: Further CTL investigation
Post by: Ghabry on April 30, 2017, 04:44:16 PM
Updated ctldis again. Together with the latest version of the Mod selector (released today) you get the new opcode

set_deployment_limit n. Where n is obviously a number of how many units are allowed to be deployed.

Put it in .func 100 anywhere before "wait_for_deploy" obviously.


Title: Re: Further CTL investigation
Post by: olly on April 30, 2017, 05:55:29 PM
In the future it will be great to have predefined named scripts that fans can copy and paste such as archer unit retreat after number of hits like on mission 1.


Title: Re: Further CTL investigation
Post by: olly on June 28, 2017, 05:46:10 PM
I've added all of the voices that Leilond kindly identified http://forum.dark-omen.org/campaigns/new-campaigns-questions-and-suggestions-t1429.0.html;msg14079#msg14079 (http://forum.dark-omen.org/campaigns/new-campaigns-questions-and-suggestions-t1429.0.html;msg14079#msg14079)

and then disassembled DO/CTL/B101/

The Prettifier is fantastic
http://wiki.dark-omen.org/do/DO/CTL/B101/Disassembled (http://wiki.dark-omen.org/do/DO/CTL/B101/Disassembled)

Ideally we want to learn more about the Combat rounds and Leadership tests that Evgen has been investigating and the portrait voice of "Stand Firm Men" that is associated with the tests. It's voice 7 and appears within CTLs

test_unit_afraid   is played when Attribute NeverRetreats or WillNeverRout is set and UnitFlag1 "50% Units Lost"

So maybe we can locate it in IDA and then work out similar possible combat functions, to see it adheres to the Warhammer 4th Edition Rulebooks.

http://forum.dark-omen.org/singleplayer/sothr-game-mechanics-stats-t273.0.html;msg14251#msg14251 (http://forum.dark-omen.org/singleplayer/sothr-game-mechanics-stats-t273.0.html;msg14251#msg14251)


Title: Re: Further CTL investigation
Post by: Ghabry on February 06, 2019, 12:00:58 AM
12 years of Dark Omen Fansite! (funded 5 Feb 2007)

Interestingly the following CTL commands are never used:

Code:
#24 add_global_r_i
#26 (called automatically each time the CTL script executes)
#27 (called when #26 set the true-flag)
#31 wait_unit_flag2_clear
#32 wait_unit_flag2_set
#37 wait_unit_flag3_set
#42 send_event_to_self_if_label_exists
#56
#57
#67
#68
#6f broadcast_event_to_enemies
#8a
#90 nop_90
#91 nop_91
#9a
#9e
#a0
#a4 find_enemy_simple
#a5 find_enemy_simple_visible
#a8 find_enemy_nth
#a9 find_enemy_nth_visble
#aa find_enemy_unittype_nth
#ab find_enemy_unittype_nth_2
#bb
#be
#c8
#c9 clear_last_event
#cb
#ec test_other_unit_r_eq_i
#f0

The following are only used in the tutorial (SPARE9):

Code:
#d9 test_user_action
#da ui_indicate
#db (this seems to check if you attack the training dummies)
#dc
#dd set_unit_r_direction
#de test_unit_at_node
#df test_unit_attacking
#e1 test_other_unit_flag3
#e2 test_unit_selected
#e3 test_any_spell_selected
#e4
#e5
#e6 test_mapmode
#e8
#e9
#ea test_sound_playing
#eb test_other_unit_flag1
#ed end_mission
#ee test_event_from_unit

Which means the following used opcodes have unknown purpose:

Code:
#14
#2b
#3c
#45
#46
#47
#48
#49
#4a
#4b
#4d
#4f
#50
#51
#5e
#5f
#60
#61
#62
#63
#64
#66
#6c
#7a
#7b
#7c
#7d
#7e
#7f
#80
#81
#83
#84
#85
#87
#88
#89
#8b
#8c
#8e
#8f
#95
#96
#9b
#9c
#a1
#ad
#b0
#b1
#bc
#c5
#c6
#ca
#cc
#d6
#db
#dc
#e4
#e5
#e8
#e9
#ef

Unknown OpCodes by popularity (funcs >= 100 are only counted once because they are always the same):

This means these are useful for map scripting in general.

Code:
406 #14
374 #3c
252 #d6
157 #50
145 #2b
101 #48
 86 #47
 78 #43
 60 #7e
 59 #9b
 45 #51
 34 #89
 29 #64
 26 #80
 24 #87
 15 #7f
 10 #e8
 10 #a1
 10 #5e
  9 #62
  8 #dc
  7 #81
  6 #7d
  6 #46
(rest omited)

When counting including all funcs >= 100 in all maps (shows which unknown opcodes the standard library uses alot)

Code:
 990 #14
 813 #9b
 580 #2b
 536 #48
 461 #3c
 389 #50
 300 #5e
 282 #43
 270 #62
 252 #d6
 210 #81
 180 #7d
 180 #46
 176 #7e
 155 #a1
 150 #9c
 150 #8f
 150 #7a
 150 #6c
 150 #4d
 120 #ca
 120 #8e
 120 #8b
 120 #7b
  90 #c5
  90 #95
  90 #8c
  90 #60
  90 #4f
  90 #4a
  90 #49
  86 #47
  84 #80
  60 #bc
  60 #b0
  60 #ad
  60 #85
  60 #83
  60 #66
  60 #61
  60 #5f
  60 #4b
  60 #45
  45 #51
  34 #89
  30 #ef
  30 #cc
  30 #c6
  30 #b1
  30 #96
  30 #88
  30 #84
  30 #7c
  30 #63
  29 #64
  24 #87
  15 #7f
  10 #e8
   8 #ee
   8 #dc
   5 #db
   2 #e9
   2 #e5
   2 #e4


Title: Re: Further CTL investigation
Post by: olly on February 06, 2019, 10:22:36 PM
Excellent knowledge and yep we've certainly progressed Dark Omen along way since 2007, many thanks!