PYTHON SCRIPT/SCHEME EXCHANGE

Users who are viewing this thread

Sure, why not?

And as for working it out, the above is extremely similar to what I've done for my "enchanting vat" during alchemical-potion item enhancement.  Except that rather than being triggered from dialogue, it's triggered from the potion-use menu when you select an item enchanting potion.  So you could say I cheated - I'd already fiddled with it and come up with the best way I could find, and your question happened to be almost identical (but simpler).
 
Ok, this is not exactly a script, but it is a usefull tool in the module system. Below is the coding for a prop which is destructable, but can be as tough or weak as you want it to be. See below:

("dummy_a",0,"arena_archery_target_b","bo_arena_archery_target_b",  [
  (ti_on_init_scene_prop,
  [
      (assign, "$dummy_damaged", 0),
     
  ]),
  (ti_on_scene_prop_hit,
  [
      (play_sound,"snd_shield_hit_cut"),  #change this depending on what is being hit
      (store_trigger_param_1, ":instance_no"),
      (store_trigger_param_2, ":damage"),
      (assign, reg60, ":damage"),
      (val_add, "$dummy_damaged", 1),
      (val_add, ":damage", 10),
      (prop_instance_get_position, 2, ":instance_no"),
      (get_player_agent_no, ":player_agent"),
      (agent_get_position, 3, ":player_agent"),
      (prop_instance_animate_to_position, ":instance_no", 2, 30), #animate to position 1 in 0.3 second
      (try_begin),
          (ge, "$dummy_damaged", 5),    #5=number of hits the prop can withstand, change as you wish
          (store_trigger_param_1, ":instance_no"),
          (prop_instance_get_starting_position, 1, ":instance_no"),
          (assign, ":rotate_side", 80),
          (position_rotate_x, 1, ":rotate_side"),
          (prop_instance_animate_to_position, ":instance_no", 1, 70), #animate to position 1 in 0.7 second
          (val_add, "$num_total_dummies_destroyed", 1),
          (play_sound,"snd_shield_broken"),    #makes this noise when destroyed, put any noise here
          (assign, "$dummy_damaged", 0),      #resets the damage
      (try_end),
     
  ]),
]),

$dummy_damaged will have to be added to module variables. There are several problems with this method, one of which is that hits given to a wall in a previous battle will apply to a wall in a new battle if the wall is not thouroughly destroyed, and since all props use the same variable, if your men have been banging on the walls, and have hit them quite a lot, you can knock out a gatehouse with one blow. On the whole though, this problem tends to actually give the feeling that some walls/gates/whatever are tougher than others, and some hits more powerful, and even with its problems, this code is ceartainly more realistic than simply using the original dummy script.
 
Highlander said:
Sorry, Colt, for for breaking your monopoly.
The formation code:

!Don't change the distance to less than 70 in a line formation, less than 100 otherwise! The guys will build the formation after weapon attack on your right hand site. The max. number of agents is 40 right now.

What happens if you change it to less than 70?

edit: Tried it...I see. They can't move past each other to get into position if you set the amount too low.
 
Amman de Stazia said:
I use ti_on_init_item for mine, and have experimented with different ways of having the enemy parties use the commands too....  It's not hugely successful yet...

Could you elaborate on this? What did you try? What happened?

I also tried, just playing around with it despite knowing almost nothing about M&B scripting. It only worked properly once...and I think that was just a fluke.
 
The Formation code.

I've looked at this script and found a solution to avoid repeating "(call_script,"script_formation_repeat")". Let's have a look :

("formation_start",
[(get_player_agent_no,reg(10)),
(agent_get_position,1,reg(10)),
(assign,"$agents",0),  #initialization of the agents counter
  (try_for_range,reg(20),1,100), #reset of the player dummy-slots
  (agent_set_slot,reg(10),reg(20),0),
  (try_end),
          (try_for_agents,reg(5)),
            (assign,reg(0),0),
            #Not the player
            (neq, reg(5), reg(10)),
            #Not Dead
            (agent_is_alive, reg(5)),
            #Not a Horse?
            (agent_is_human, reg(5)),
            #If the Selected Troop is an Ally
            (agent_is_ally,reg(5)),
            (val_add,"$agents",1),    #increment the counter
          (assign,reg(1),1),
          (try_begin),
            (assign,reg(20),1), #reg(20) is the agent number to use every position only once
            (agent_get_slot,reg(21),reg(10),reg(20)), #player agent used as a dummy not to make several agent use one position
            (eq,reg(21),0), #number isn't used, yet
            (assign,reg(1),reg(20)),
            (assign,reg(3),reg(1)),
            (val_mul,reg(3),100),
            (copy_position,reg(1),1),
            (position_move_x,reg(1),reg(3)), #number 1 = 100 metres right to the player agent 2= 200 etc...
            (agent_set_scripted_destination,reg(5),reg(1)), #tells the agent to run there
            (agent_set_slot,reg(5),1,reg(1)), #tells the agent which position he has - only important if you want to do somethink else with the script, it would work without it right now.
            (agent_set_slot,reg(10),reg(20),1), #tells the game that the number is used, by using the player slots.
          (else_try),
            (try_for_range,reg(1),1,"$agents"),    #loop call !  :razz:
              (call_script,"script_formation_repeat"),
            (try_end),
          (try_end),         
          (try_end),
  ]),
("formation_repeat",
[            (val_add,reg(20),1), # adds 1 to the agent number
            (agent_get_slot,reg(21),reg(10),reg(20)),
            (eq,reg(21),0), # again, is the number already used?
            (assign,reg(1),reg(20)), #just copying the number to use it somewhere else...
            (assign,reg(3),reg(1)), #again copying
            (assign,reg(4),0), #assigns the row of this agent to 0
#-#-#-#-#-#-#-#-#-#
            (try_for_range,reg(15),1,100), #this try-code assigns the right row.
            (assign,reg(17),reg(15)),
            (assign,reg(16),reg(15)),
            (val_mul,reg(15),5), #number of troops in one line
            (val_mul,reg(16),5), #has to be the same as above
            (val_add,reg(16),5), #has to be the same as above
            (gt,reg(3),reg(15)),
            (le,reg(3),reg(16)),
            (assign,reg(15),reg(17)),
            (val_mul,reg(15),6), #number of troops in one line + 1
            (val_sub,reg(3),reg(15)),
            (assign,reg(4),reg(17)),
            (try_end),
#delete these lines to get a 1 line formation
#-#-#-#-#-#-#-#-#-#
            (val_mul,reg(3),100),
            (val_mul,reg(4),200),
            (copy_position,reg(1),1),
            (position_move_x,reg(1),reg(3)),
            (position_move_y,reg(1),reg(4)),
            (agent_set_scripted_destination,reg(5),reg(1)),
            (agent_set_slot,reg(5),1,reg(1)),
            (agent_set_slot,reg(10),reg(20),1),
]),


The agents number has no importance. "formation_start" simply count them and call "formation_repeat" as many times as needed.

Edit : corrected some syntax errors. Thanks Dwinny !
 
Actually, I'm trying to make a routine which calculate the number of lines relatively to the agents number. I've done the routine, but I can't find the right place...

Edit : Grummpff... Doesn't want to be functional...
 
That's great Andre, but I tested it, and it doesn't work. Only one troop goes into formation.

A question: what exactly does try_for_agents do? What information does it store?
 
:oops: Syntax error : I wrote (val_add,"$agent",1) instead of (val_add,"$agents",1). Edited ! Try it and tell if it is functional. Thanks.

The "try_for_agents" operation is a loop. It doesn't store any information. It only proceed operations written after (and before its corresponding "try_end"). I can be wrong, because I didn't find any doc about...
 
Ah, so it looks at all the operations within the try_for_agents and try_end, and goes through all agents and does those operations?

Okay, so my first guess was wrong.  :oops: Thanks.

Oh, you're also missing a comma at the end of that operation as well. I'm going to go test it now...

edit: Works! Good job!

Unfortunately, there's a limit to the number of agents that will build a formation, both in this one and the original. What also coincided with that was a series of error messages. I don't remember exactly what it was, since the messages were faint and scrolled by very quickly, but I think it was OPCODE #, invalid register ID or something like that. I'll go back and take a screenshot if I can.

edit: SCRIPT ERROR ON OPCODE ###: Invalid Register ID: ##

 
How many agents ?

Can you have the OPCODE name and the REGISTER ID ? Would be useful to fix the problem (and I must say that I don't want to try myself  :mrgreen: )
 
I don't know how many exactly...around 70, I'd say.

As for the opcode and register, there were a whole bunch of them, and the numbers varied for each. Here's part of what appeared on my screen though:

SCRIPT ERROR ON OPCODE 700: Invalid Register ID: 65
SCRIPT ERROR ON OPCODE 720: Invalid Register ID: 65
SCRIPT ERROR ON OPCODE 721: Invalid Register ID: 65
SCRIPT ERROR ON OPCODE 10730: Invalid Register ID: 65
SCRIPT ERROR ON OPCODE 700: Invalid Register ID: 66
SCRIPT ERROR ON OPCODE 720: Invalid Register ID: 66
SCRIPT ERROR ON OPCODE 721: Invalid Register ID: 66
SCRIPT ERROR ON OPCODE 10730: Invalid Register ID: 66
SCRIPT ERROR ON OPCODE 700: Invalid Register ID: 67
SCRIPT ERROR ON OPCODE 720: Invalid Register ID: 67
SCRIPT ERROR ON OPCODE 721: Invalid Register ID: 67
SCRIPT ERROR ON OPCODE 10730: Invalid Register ID: 67

There was more, and this was the second time I initiated the formation. The first time, the register IDs were higher, going down from 80. I'm guessing that number has something to do with the number of agents, since I had 80 troops on the field.
 
OPCODE 700 = copy_position
OPCODE 720 = move_to_x
OPCODE 721 = move_to_y
OPCODE 10730 = agent_set_scripted_destination

The error is localised in "formation_repeat", and should come from the loop call I've written.

Localise this line :

            (try_for_range,reg(1),1,"$agents"),    #loop call !

and change the "reg(1)" :

            (try_for_range,"$temp_var",1,"$agents"),    #loop call !

Should be better...

P.S. : sorry, my own computer is not connected to the web and is upstairs in an asleep house...

Edit : there are 63 registers hardcoded in the Native Module System. I guess that the first Invalid Register ID error you got was the 64th...
 
Okay, I'll try that. Also, the first invalid register ID was actualy 70-something, I believe, though I'm not sure.

Also, I counted the number of troops that didn't make a formation. Of 79, 14 didn't.

edit: Nope, didn't work.  :sad:
 
Yes, still got the errors, and still some troops didn't join the formation. I don't think the error occurs when all troops can enter the formation. Try it with 80.
 
Concerning errors, the game core limits the battle size to 40. Over this number (and it's said in the battle sizer doc) the game can crash, or generate errors.

Concerning the troops which don't join the formation, I've found something, maybe... I need to test it a bit more.

André de Cuyne said:
Actually, I'm trying to make a routine which calculate the number of lines relatively to the agents number. I've done the routine, but I can't find the right place...

Edit : Grummpff... Doesn't want to be functional...

I'll try to test again this routine. Should be better to have three lines of ten soldiers instead of six lines of five...
 
Dwinny said:
Amman de Stazia said:
I use ti_on_init_item for mine, and have experimented with different ways of having the enemy parties use the commands too....   It's not hugely successful yet...

Could you elaborate on this? What did you try? What happened?

I also tried, just playing around with it despite knowing almost nothing about M&B scripting. It only worked properly once...and I think that was just a fluke.

What I did, was create four unique items, one each for swadian, vaegir dark hunter and player.  These items triggered formations scripts.  However, I found it hard to check on the function, because I could never be sure, during a battle, whether one of those items was equipped by an enemy or ally.
When I used the items myself, formations did form, but it was a very low rate of success.
 
With all the talk about formations, I reckon this is the right time for this. Since Highlander's code is long, somewhat buggy, and slow to act, I made my own formation script. It supports as many men in formation at once as m+b can handle, they react quicker, and will never give any error messages, in addition to being somewhat more user friendly. Best of all, it can even be used to make a wedge. The wedge will not be usefull for now, but with cavalry being scriptable in the new version, it will be soon.

The efficient, improved formation code:

  ("formation",
  [(get_player_agent_no,reg(10)),
    (agent_get_position,1,reg(10)),
    (assign,":collumn",1),
    (position_move_x,1,100),
    (try_for_agents,reg(5)),
      (agent_is_ally,reg(5)),
      (agent_is_alive,reg(5)),
      (agent_is_human,reg(5)),
      (agent_set_scripted_destination,reg(5),1),
      (position_move_x,1,100),
      (try_begin),
          (eq,":collumn",10),
          (position_move_x,1,-10*100),
          (position_move_y,1,-100),
          (assign,":collumn",1),
      (else_try),
          (val_add,":collumn",1),
      (end_try),
    (end_try)]),

Red: distance between agents left and right.
Blue: distance between agents front and back.
Green: number of men in one row.

Screenie with more men than the current formation code supports:


The wedge formation code:

  ("formation_wedge",
  [(get_player_agent_no,reg(10)),
    (agent_get_position,1,reg(10)),
    (assign,":collumn",1),
    (assign,":nc",3),
    (position_move_x,1,-100),
    (position_move_y,1,-100),
    (try_for_agents,reg(5)),
      (agent_is_ally,reg(5)),
      (agent_is_alive,reg(5)),
      (agent_is_human,reg(5)),
      (agent_set_scripted_destination,reg(5),1),
      (try_begin),
          (eq,":collumn",":nc"),
          (val_mul,":nc",-100),
          (position_move_x,1,":nc"),
          (position_move_y,1,-100),
          (assign,":collumn",1),
          (val_div,":nc",-100),
          (val_add,":nc",2),
      (else_try),
          (position_move_x,1,100),
          (val_add,":collumn",1),
      (end_try),
    (end_try)]),

Red: distance side to side.
Blue: distance front to back.
This will need to be modified for cavalry with the new version. To use this, set up a trigger in module_mission_templates.py under the "lead_charge" mission which will call this script every tenth of a second when the conditions are right, thus moving the formation according to the player. It becomes a bit rough when moving, but its really not all that bad.

Screenie:


To get enemies to form a line:

  ("ai_formation",
  [(assign,"$formed",1),(try_for_agents,reg(5)),
    (agent_is_alive, reg(5)),
    (neg|agent_is_ally,reg(5)),
    (agent_is_human, reg(5)),
    (agent_get_position,1,reg(5)),
    (try_end),
    (assign,":collumn",1),
    (position_move_x,1,75),
    (try_for_agents,reg(5)),
      (neg|agent_is_ally,reg(5)),
      (agent_is_alive,reg(5)),
      (agent_is_human,reg(5)),
      (agent_set_scripted_destination,reg(5),1),
      (position_move_x,1,75),
      (try_begin),
          (eq,":collumn",10),
          (position_move_x,1,-10*75),
          (position_move_y,1,-50),
          (assign,":collumn",1),
      (else_try),
          (val_add,":collumn",1),
      (end_try),
    (end_try)]),

Give the enemies a weapon which will call this script. The distances are slightly different from the formation above, but works the same way. It picks a random enemy infantryman and uses him as the starting point for the formation.

When formations clash :twisted: :
 
Back
Top Bottom