Posts: 973
Threads: 20
Joined: Oct 2010
Hey Jtm!
Welcome back!
Jtm Wrote:I've tried to change code so that Master of Magic calls j_Move_or_attack_reaction subroutine after picking up the coordinates from external ai. This subroutine is used when player moves units with mouse pointer. So far failed. If anyone is interested, I can send the alternative code that implements the call to j_Move_or_attack_reaction.
FYI, you won't be able to make far calls (not easily anyway).
Nor should you try to change existing far calls, without being prepared to do a little more work.
The header of the exe file contains a list of all far calls and adjusts all of them when the exe file is loaded.
If you remove a far call, the corresponding code will still get adjusted.
In effect it would mean you'd have unpredictable code.
So you'd also have to adjust the list in the exe file header.
--I like ILSe
Posts: 104
Threads: 0
Joined: Oct 2010
I like Serena Wrote:FYI, you won't be able to make far calls (not easily anyway).
To be honest I don't understand how and why the 8086 architecture would limit far calls. I suppose I'll have to do my homework then. Sounds like bad news  Check below. I was planning to use following code but first test was not successful. Will look into it after a good night sleep.
Code: ; Start of Unit_strategy_exe() routine
; WIZARDS.EXE:889E4
[COLOR="YellowGreen"]55 push bp ; auto combat
8B EC mov bp, sp
83 EC 06 sub sp, 6
56 push si_casting_battle_unitID
57 push di
8B 76 06 mov si_casting_battle_unitID, [bp+casting_battleUnitID]
8B C6 mov ax, si_casting_battle_unitID
BA 6E 00 mov dx, 6Eh ; 'n'
F7 EA imul dx
C4 1E 2A 92 les bx, addr_Battle_unit
03 D8 add bx, ax
26 8A 47 43 mov al, es:[bx+43h]
98 cbw
BA 6E 00 mov dx, 6Eh ; 'n'
F7 EA imul dx
C4 1E 2A 92 les bx, addr_Battle_unit
03 D8 add bx, ax
26 8B 7F 44 mov di, es:[bx+struc_Battle_Unit.field_xPos]
26 8B 47 46 mov ax, es:[bx+struc_Battle_Unit.field_yPos]
89 7E 0A mov [bp+target_Y], di
89 46 08 mov [bp+target_X], ax
A0 97 92 mov al, [w_kyrub_dseg_9297]
08 C0 or al, al
74 1C jz loc_no_external_AI:
B0 01 mov al, 1
A2 96 92 mov [w_kyrub_dseg_9296], al
loc_wait_external_AI:
A0 96 92 mov al, [w_kyrub_dseg_9296]
08 C0 or al, al
75 F9 jnz loc_wait_external_AI
loc_move_or_attack
56 push si_casting_battle_unitID
9A 34 00 CC 34 call j_choose_next_unit_for_action
59 pop cx
FF 36 02 89 push w_kyrub_dseg_8902
FF 36 00 89 push w_kyrub_dseg_8900
56 push si_unit_id
9A 39 00 CC 34 call j_Move_or_attack_reaction
EB 21 jmp loc_92548
loc_no_external_AI:
90
56 push si_casting_battle_unitID
9A 34 00 CC 34 call j_choose_next_unit_for_action
59 pop cx[/COLOR]
Code: Replace opcodes in 0x889E4
[color=DarkOrange]558BEC83EC0656578B76068B7E080BFF754B837E0A0075458BC6BA6E00F7EAC41E2A9203D8268A474398BA6E00F7EAC41E2A9203D8268B7F448BC6BA6E00F7EAC41E2A9203D8268A474398BA6E00F7EAC41E2A9203D8268B474689460A569A3400CC3459893682C5[/color]
with
[color=YellowGreen]558BEC83EC0656578B76068BC6BA6E00F7EAC41E2A9203D8268A474398BA6E00F7EAC41E2A9203D8268B7F44268B4746897E0A894608A0979208C0741CB001A29692A0969208C075F9569A3400CC3459FF360289FF360089569A3900CC34EB2190569A3400CC3459[/color]
I like Serena Wrote:Nor should you try to change existing far calls, without being prepared to do a little more work.
The header of the exe file contains a list of all far calls and adjusts all of them when the exe file is loaded.
If you remove a far call, the corresponding code will still get adjusted.
In effect it would mean you'd have unpredictable code.
So you'd also have to adjust the list in the exe file header. Ya that wasn't in my mind. Good to know though. Thanks
By the way, I've noticed that some of the code is highly NON-optimized. Unit_strategy_exe subroutine has dozens of recalculations of memory address for battle unit. Using one simple variable or register for precalculated value would save hundreds of bytes for other stuff. That's actually the trick I used to make more space in the beginning of the subroutine (compare my code and the original). Removed one 6Eh multiplication etc.
Posts: 401
Threads: 31
Joined: May 2012
Interesting.
I tried to interpreter the code you included and I understood nothing or less.
Anyway there are AI routines that could be improved, like hunting a unit that has your speed, searching for invisible units, cracking a wall to enter a city and so on.
Only the people crazy enough to think they can change the world of Arcanus and Myrror can do it.
August 19th, 2012, 08:08
(This post was last modified: August 19th, 2012, 08:57 by I like Serena.)
Posts: 973
Threads: 20
Joined: Oct 2010
I just checked it out.
It works for me too.
I've started MoM and then your program.
When I enter combat, the game remains standing by, as expected.
Then I can specify for each AI unit which unit to attack.
My own units are under my control normally.
When exiting your program, battle resumes as normal.
So we have first step to external AI!
Good!
--I like ILSe
Posts: 973
Threads: 20
Joined: Oct 2010
FrancoK Wrote:Anyway there are AI routines that could be improved, like hunting a unit that has your speed, searching for invisible units, cracking a wall to enter a city and so on.
So we need rules, like:
[INDENT] If a unit has wallcrusher, and all enemy units are inside city walls,
then select a piece of wall and go crack it.[/INDENT]
Or perhaps:
[INDENT] Select a piece of wall and go crack it
IF the unit has an ability to damage a wall, and it's useful to crack the wall.[/INDENT]
combined with:
[INDENT] It's useful to crack the wall
IF all enemy units are inside walls and all walls are undamaged[/INDENT]
--I like ILSe
Posts: 973
Threads: 20
Joined: Oct 2010
Jtm Wrote:In addition to saving x and y to 8900 and 8902, the program also changes attacker's battle unit data at +0x43, which is the location for the target unit id.
I've taken a look at the code.
Apparently the function executes the unit strategy that has already been chosen.
This means we can change its current strategy if we want to.
This strategy is mostly determined by battleunit fields +0x43 and +0x54.
If we change them, the unit will do something else.
Code: +0x43 is the target battleunit id (0-18)
+0x54 is the chosen action (100-109)
100 melee (if unit has non-zero melee)
101 unclear??
102 shoot
103 unclear??
104 doom bolt (if unit has the special)
105 fireball (if unit has the special)
106 move??
107 cast spell
108 cast spell (difference??)
109 summon demon (if unit has the special)
--I like ILSe
Posts: 401
Threads: 31
Joined: May 2012
I like Serena Wrote:So we need rules, like:
[INDENT]If a unit has wallcrusher, and all enemy units are inside city walls,
then select a piece of wall and go crack it.[/INDENT]
Or perhaps:
[INDENT]Select a piece of wall and go crack it
IF the unit has an ability to damage a wall, and it's useful to crack the wall.[/INDENT]
combined with:
[INDENT]It's useful to crack the wall
IF all enemy units are inside walls and all walls are undamaged[/INDENT] Yes, more or less. :-)
The units able to break a wall are either very powerful (and so better used against units) or weak (like engineers) and need to be protected.
So, the first check is:
There is a wall? If no, skip to the end of the procedure.
There is a defender on the threshold? If no, skip to the end of the procedure.
Is the defender flying? If no, skip to the end of the procedure.
Can I attack it? If yes, chose if attack with all units or some and go to normal attack procedure; if not go to breakwall procedure.
:breakwall procedure
if the breakwaller has ranged attack, attack the closest tower and move the "foot" units to that tower.
if the breakwaller has not ranged attack, move the breakwaller to attack the closest tower and move the "foot" units to that tower, fast/strong units in front, slow/weak in the rear.
:attackFlyingDefender
move the flyingDown unit to attack the flying defender and move the "foot" units close to it, fast/strong units in front, slow/weak in the rear.
This is an example, of course, it can be more simple or more complex.
Only the people crazy enough to think they can change the world of Arcanus and Myrror can do it.
Posts: 525
Threads: 6
Joined: Dec 2010
I purpose a way to make Ai external.think about external file with external fixed-length commands.
It may look like:take variable from datasegment:adress,make primitive operator ,store it...
Primitive operators may be: load machine code and run it,swap block local variables to file or memory page e.t.s.
Technicaly,you may patch interrupt 3f and patch executable code in memory this way. (The segment relocation in memory have good visibility at this point.) Thus,avoid to corrupt wizards.exe,and make resident program tiny and fast and external-easy programmable. Note,you must be emulator and OS unspecific.
Also,there is bart multiplayer shell,which work right way. (I was try to make combat-extender... it work with this shell also). Dissasemble it is good idea also.but i have no time for this.
August 20th, 2012, 14:03
(This post was last modified: August 21st, 2012, 17:31 by I like Serena.)
Posts: 973
Threads: 20
Joined: Oct 2010
FrancoK Wrote:Yes, more or less. :-)
The units able to break a wall are either very powerful (and so better used against units) or weak (like engineers) and need to be protected.
That's why I put in the condition that all enemies should be within the walls.
Otherwise, it's probably better to simply attack the units outside the wall.
Quote:There is a wall? If no, skip to the end of the procedure.
Let's avoid the word "procedure".
I believe thinking in procedures tends to limit one's view.
Also, let's leave out conditions that have to be implicitly satisfied for the rule to be valid.
If a rule is not valid, for instance due to the lack of city walls, we can simply discard it.
No need to make that explicit.
Quote:There is a defender on the threshold? If no, skip to the end of the procedure.
Whether there's a defender or not at the threshold, I prefer to break the wall if I can.
The reason is that you do not want to enter the city through the threshold.
It will make 4 or more units hit you twice simultaneously, which is very disadvantageous due to the effect of suppression counters.
Quote:Is the defender flying? If no, skip to the end of the procedure.
Can I attack it? If yes, chose if attack with all units or some and go to normal attack procedure; if not go to breakwall procedure.
Same thing.
I think it's better to create options to attack from multiple directions, and also to reduce the defensive bonus of the walls.
FYI, the wall gives a +3 defense bonus, including the threshold.
A broken wall gives a +1 defense bonus at that point (for a unit outside the wall), plus the option to attack.
Quote::breakwall procedure
if the breakwaller has ranged attack, attack the closest tower and move the "foot" units to that tower.
if the breakwaller has not ranged attack, move the breakwaller to attack the closest tower and move the "foot" units to that tower, fast/strong units in front, slow/weak in the rear.
Yes, that sounds good.
When attacking through a broken tower, we have favorable odds.
I'd still also break the wall next to the tower I think.
Quote::attackFlyingDefender
move the flyingDown unit to attack the flying defender and move the "foot" units close to it, fast/strong units in front, slow/weak in the rear.
Can you explain?
Quote:This is an example, of course, it can be more simple or more complex.
I definitely prefer simple.
AI is hard enough to do well.
I want to avoid questionable rules that cause clutter.
Let's start with simple rules that are obviously valid.
Later we can always finetune and make exceptions.
--I like ILSe
Posts: 973
Threads: 20
Joined: Oct 2010
Asfex Wrote:I purpose a way to make Ai external.think about external file with external fixed-length commands.
It may look like:take variable from datasegment:adress,make primitive operator ,store it...
Primitive operators may be: load machine code and run it,swap block local variables to file or memory page e.t.s.
Technicaly,you may patch interrupt 3f and patch executable code in memory this way. (The segment relocation in memory have good visibility at this point.) Thus,avoid to corrupt wizards.exe,and make resident program tiny and fast and external-easy programmable. Note,you must be emulator and OS unspecific.
Also,there is bart multiplayer shell,which work right way. (I was try to make combat-extender... it work with this shell also). Dissasemble it is good idea also.but i have no time for this.
Yes, we need a kind of interface engine, on 2 levels I think.
One (assembly) engine to interact with MoM directly, getting information out and back in.
And a second engine (high level language) to apply high level rules (that "normal" people can understand) to high level data structures.
You appear to have a couple of ideas to refine the assembly engine...
Can you make them more explicit?
--I like ILSe
|