OSP Code SP [WB] Order: Weapon Type Switch

Caba`drin

Count
M&BWBWF&SNWVC
Best answers
0
After seeing a few others comment on the limits of weapon usage orders (Blunt/Any, Fire/Hold Fire) it seemed worthwhile to whip up a simple code to expand order functionality.

With this simple code, the player has three four more orders at his/her disposal, based on weapon-type, when instructing their army. With the push of a button, the player can order the currently selected combination of battle groups/divisions to equip a weapon of a certain type: one-handed; two-handed or polearm; and ranged or throwing. Also, the commander can order their troops to equip/unequip their shields (brandish and doff, respectively, in the parlance). The order going out to the troops will scroll on screen as native orders do. (This has not, however been worked into the panel with the map.)

The combination of some orders may prove fruitful. For instance, ordering "two-handers and polearms" to your Rhodok spears will have spears/spiked staffs that can be wielded one-handed still used with a shield. Following this order up with "doff your shields" will slide their board shields on to their backs, forcing the weapons to be wielded with two hands. Repeating the shield order "brandish shields" will cause those who can to pull their shields back out, while still using their polearm.

This should be compatible with most any other code bits/mods/what have you, as it does not add any slots or globals nor does it monkey with the original source code. The only compatibility issue will be to find 4 suitable, unused keys for the orders. Currently, they are set as F9=Use One-Handed Weapons; F10=Use Two-Handed Weapons and Polearms; F11=Use Ranged/Throwing Weapons. F8=Shield Toggle. To clear weapon type orders, simply give the F3-F4, "Use Weapons at Will", order built in to the command system.

Code:
  # script_order_weapon_type_switch
  # Input: Order Type    
  # Output: Nothing
  # On key depression, try to switch division to appropriate weapon
("order_weapon_type_switch", [  
     (store_script_param_1, ":ordertype"),
     (get_player_agent_no, ":player"),
     (agent_get_team, ":playerteam", ":player"),
     (try_for_agents, ":agent"),
         (agent_is_alive, ":agent"),
         (agent_is_human, ":agent"),
         (agent_is_non_player, ":agent"),
         (agent_get_team, ":team", ":agent"),
         (eq, ":team", ":playerteam"), #On Player's side?
         (agent_get_division, ":class", ":agent"),
         (try_begin), #Mark class as in battle
             (eq, ":class", 0),
             (assign, ":group0_in_battle", 1),
         (else_try),
             (eq, ":class", 1),
             (assign, ":group1_in_battle", 1),    
         (else_try),
             (eq, ":class", 2),
             (assign, ":group2_in_battle", 1),          
         (else_try),
             (eq, ":class", 3),
             (assign, ":group3_in_battle", 1),          
         (else_try),
             (eq, ":class", 4),
             (assign, ":group4_in_battle", 1),          
         (else_try),
             (eq, ":class", 5),
             (assign, ":group5_in_battle", 1),    
         (else_try),
             (eq, ":class", 6),
             (assign, ":group6_in_battle", 1),          
         (else_try),
             (eq, ":class", 7),
             (assign, ":group7_in_battle", 1),         
         (else_try),
             (eq, ":class", 8),
             (assign, ":group8_in_battle", 1),                       
         (try_end),
         (class_is_listening_order, ":team", ":class"), #Is the agent's team selected?
         (try_begin), #Mark class as selected
             (eq, ":class", 0),
             (assign, ":group0_is_selected", 1),
         (else_try),
             (eq, ":class", 1),
             (assign, ":group1_is_selected", 1),    
         (else_try),
             (eq, ":class", 2),
             (assign, ":group2_is_selected", 1),          
         (else_try),
             (eq, ":class", 3),
             (assign, ":group3_is_selected", 1),          
         (else_try),
             (eq, ":class", 4),
             (assign, ":group4_is_selected", 1),          
         (else_try),
             (eq, ":class", 5),
             (assign, ":group5_is_selected", 1),    
         (else_try),
             (eq, ":class", 6),
             (assign, ":group6_is_selected", 1),          
         (else_try),
             (eq, ":class", 7),
             (assign, ":group7_is_selected", 1),         
         (else_try),
             (eq, ":class", 8),
             (assign, ":group8_is_selected", 1),                       
         (try_end),
         (agent_get_troop_id, ":troop",":agent"),     
         (try_begin),
             (troop_is_hero, ":troop"),
             (assign, ":end", ek_head),
             (try_for_range, ":i", ek_item_0, ":end"),
                 (troop_get_inventory_slot,":item",":troop",":i"),
                 (gt, ":item", 0),
                 (item_get_type, ":weapontype", ":item"),
                 (try_begin),
                     (eq, ":ordertype", ranged),
                     (str_store_string, s1, "@ready bows and missiles"),
                     (this_or_next|eq, ":weapontype", itp_type_bow),
                     (this_or_next|eq, ":weapontype", itp_type_crossbow),
                     (eq, ":weapontype", itp_type_thrown),
                     (agent_set_wielded_item, ":agent", ":item"),
                     (assign, ":end", ek_item_0),#loop breaker
                 (else_try),
                     (eq, ":ordertype", onehand), 
                     (str_store_string, s1, "@ready side arms"),
                     (eq, ":weapontype", itp_type_one_handed_wpn),
                     (agent_set_wielded_item, ":agent", ":item"),
                     (assign, ":end", ek_item_0),#loop breaker
                 (else_try),
                     (eq, ":ordertype", bothhands),
                     (str_store_string, s1, "@ready two-handers and polearms"),
                     (this_or_next|eq, ":weapontype", itp_type_two_handed_wpn),
                     (eq, ":weapontype", itp_type_polearm),
                     (agent_set_wielded_item, ":agent", ":item"),
                     (assign, ":end", ek_item_0),#loop breaker
                 (else_try),
                     (eq, ":ordertype", shield),
                     (agent_get_wielded_item, ":shield", ":agent", 1),
                     (try_begin),
                         (gt, ":shield", 0),
                         (agent_unequip_item, ":agent", ":shield"),
                         (agent_equip_item, ":agent", ":shield"), #Moves shield to back
                         (str_store_string, s1, "@doff your shields"),
                         (assign, ":end", ek_item_0),#loop breaker
                     (else_try),
                         (eq, ":weapontype", itp_type_shield),
                         (agent_set_wielded_item, ":agent", ":item"), #Moves shield from back to hand
                         (str_store_string, s1, "@brandish shields"),
                         (assign, ":end", ek_item_0),#loop breaker
                     (try_end),        
                 (try_end),
             (try_end),
         (else_try),#regular troops
             (troop_get_inventory_capacity,":cap",":troop"),
             (try_for_range, ":i", 0, ":cap"),#(slots < 10)?
                 (troop_get_inventory_slot,":item",":troop",":i"),
                 (gt, ":item", 0),
                 (item_get_type, ":weapontype", ":item"),
                 (try_begin),
                     (eq, ":ordertype", ranged),
                     (str_store_string, s1, "@ready bows and missiles"),
                     (this_or_next|eq, ":weapontype", itp_type_bow),
                     (this_or_next|eq, ":weapontype", itp_type_crossbow),
                     (eq, ":weapontype", itp_type_thrown),
                     (agent_has_item_equipped, ":agent", ":item"),
                     (agent_set_wielded_item, ":agent", ":item"),
                     (assign, ":cap", 0),#loop breaker
                 (else_try),
                     (eq, ":ordertype", onehand), 
                     (str_store_string, s1, "@ready side arms"),
                     (eq, ":weapontype", itp_type_one_handed_wpn),
                     (agent_has_item_equipped, ":agent", ":item"),
                     (agent_set_wielded_item, ":agent", ":item"),
                     (assign, ":cap", 0),#loop breaker
                 (else_try),
                     (eq, ":ordertype", bothhands),
                     (str_store_string, s1, "@ready two-handers and polearms"),
                     (this_or_next|eq, ":weapontype", itp_type_two_handed_wpn),
                     (eq, ":weapontype", itp_type_polearm),
                     (agent_has_item_equipped, ":agent", ":item"),
                     (agent_set_wielded_item, ":agent", ":item"),
                     (assign, ":cap", 0),#loop breaker
                 (else_try),
                     (eq, ":ordertype", shield),
                     (agent_get_wielded_item, ":shield", ":agent", 1),
                     (try_begin),
                         (gt, ":shield", 0),
                         (agent_unequip_item, ":agent", ":shield"),
                         (agent_equip_item, ":agent", ":shield"), #Moves shield to back
                         (str_store_string, s1, "@doff your shields"),
                         (assign, ":cap", 0),#loop breaker
                     (else_try),
                         (eq, ":weapontype", itp_type_shield),
                         (agent_has_item_equipped, ":agent", ":item"),
                         (agent_set_wielded_item, ":agent", ":item"), #Moves shield from back to hand
                         (str_store_string, s1, "@brandish shields"),
                         (assign, ":cap", 0),#loop breaker
                     (try_end),
                 (try_end),
             (try_end),
         (try_end), #Hero v Regular Troop
     (try_end), #Agent Loop
     (str_clear, s2),
     (str_clear, s3),
     (assign, ":count_possible", 0),
     (assign, ":count_selected", 0),
     (try_begin),
         (eq, ":group0_in_battle", 1),
         (val_add, ":count_possible", 1),
         (eq, ":group0_is_selected", 1),
         (val_add, ":count_selected", 1),
         (str_store_class_name, s2, 0),
     (try_end),
     (try_begin),
          (eq, ":group1_in_battle", 1),
         (val_add, ":count_possible", 1),
         (eq, ":group1_is_selected", 1),
         (val_add, ":count_selected", 1),
         (try_begin),
             (neg|str_is_empty, s2),
             (str_store_class_name, s3, 1),
             (str_store_string, s2, "@{!}{s2}, {s3}"),
         (else_try),
             (str_store_class_name, s2, 1),
         (try_end),
     (try_end),
     (try_begin),
          (eq, ":group2_in_battle", 1),
         (val_add, ":count_possible", 1),
         (eq, ":group2_is_selected", 1),
         (val_add, ":count_selected", 1),
         (try_begin),
             (neg|str_is_empty, s2),
             (str_store_class_name, s3, 2),
             (str_store_string, s2, "@{!}{s2}, {s3}"),
         (else_try),
             (str_store_class_name, s2, 2),
         (try_end),
     (try_end),
     (try_begin),
          (eq, ":group3_in_battle", 1),
         (val_add, ":count_possible", 1),
         (eq, ":group3_is_selected", 1),
         (val_add, ":count_selected", 1),
         (try_begin),
             (neg|str_is_empty, s2),
             (str_store_class_name, s3, 3),
             (str_store_string, s2, "@{!}{s2}, {s3}"),
         (else_try),
             (str_store_class_name, s2, 3),
         (try_end),
     (try_end),
     (try_begin),
          (eq, ":group4_in_battle", 1),
         (val_add, ":count_possible", 1),
         (eq, ":group4_is_selected", 1),
         (val_add, ":count_selected", 1),
         (try_begin),
             (neg|str_is_empty, s2),
             (str_store_class_name, s3, 4),
             (str_store_string, s2, "@{!}{s2}, {s3}"),
         (else_try),
             (str_store_class_name, s2, 4),
         (try_end),
     (try_end),
     (try_begin),
          (eq, ":group5_in_battle", 1),
         (val_add, ":count_possible", 1),
         (eq, ":group5_is_selected", 1),
         (val_add, ":count_selected", 1),
         (try_begin),
             (neg|str_is_empty, s2),
             (str_store_class_name, s3, 5),
             (str_store_string, s2, "@{!}{s2}, {s3}"),
         (else_try),
             (str_store_class_name, s2, 5),
         (try_end),
     (try_end),
     (try_begin),
          (eq, ":group6_in_battle", 1),
         (val_add, ":count_possible", 1),
         (eq, ":group6_is_selected", 1),
         (val_add, ":count_selected", 1),
         (try_begin),
             (neg|str_is_empty, s2),
             (str_store_class_name, s3, 6),
             (str_store_string, s2, "@{!}{s2}, {s3}"),
         (else_try),
             (str_store_class_name, s2, 6),
         (try_end),
     (try_end),
     (try_begin),
          (eq, ":group7_in_battle", 1),
         (val_add, ":count_possible", 1),
         (eq, ":group7_is_selected", 1),
         (val_add, ":count_selected", 1),
         (try_begin),    
             (neg|str_is_empty, s2),
             (str_store_class_name, s3, 7),
             (str_store_string, s2, "@{!}{s2}, {s3}"),
         (else_try),
             (str_store_class_name, s2, 7),
         (try_end),
     (try_end),
     (try_begin),
          (eq, ":group8_in_battle", 1),
         (val_add, ":count_possible", 1),
         (eq, ":group8_is_selected", 1),
         (val_add, ":count_selected", 1),
         (try_begin),
             (neg|str_is_empty, s2),
             (str_store_class_name, s3, 8),
             (str_store_string, s2, "@{!}{s2}, {s3}"),
         (else_try),
             (str_store_class_name, s2, 8),
         (try_end),
     (try_end),
     (try_begin),
         (eq, ":count_selected", ":count_possible"),
         (str_store_string, s2, "@Everyone"),
     (try_end),
     (try_begin),
         (gt, ":count_selected", 0),
         (display_message, "@{!}{s2}, {s1}!", 0xFFDDDD66),
     (try_end),
     (str_clear, s2),
     (str_clear, s3),
    ]),
The workhorse script. Place where ever within scripts = [... The beginning works just fine.

Code:
order_weapon_type_triggers = [     
	(0, 0, 1, [(key_clicked, key_for_onehand)], [(call_script, "script_order_weapon_type_switch", onehand)]),
	(0, 0, 1, [(key_clicked, key_for_bothhands)], [(call_script, "script_order_weapon_type_switch", bothhands)]),	
	(0, 0, 1, [(key_clicked, key_for_ranged)], [(call_script, "script_order_weapon_type_switch", ranged)]),
	 (0, 0, 1, [(key_clicked, key_for_shield)], [(call_script, "script_order_weapon_type_switch", shield)]),
	 ]
Stick them in each of the actual mission templates you want to be able to give the order without the "order_weapon_type_triggers" title and brackets, or stick them toward the top of the file (I put them after the multiplayer_* and before the common_* around line 630) and then just include the "order_weapon_type_triggers" title in the mission templates. I tend to install extra triggers as follows:

Code:
(
    "lead_charge",mtf_battle_mode,charge,
    "You lead your men to battle.",
    [ 
     // bunch of stuff...all the way to the very end
          ] + order_weapon_type_triggers,
  ),

Code:
ranged    = 0
onehand   = 1
bothhands = 2
shield    = 3

from header_triggers import *
key_for_onehand   = key_f9
key_for_bothhands = key_f10
key_for_ranged    = key_f11
key_for_shield    = key_f8
Add to bottom of Constants.py, after customizing the keys used to your taste and ensuring no conflicts.


Two things that could be improved, off the bat:
1) If anyone knows the hex color code for troop orders (yellowish?), that would be helpful as the current color used is just an approximation. I was unable to find any reference to it. I believe it is the same a similar color as is used for your amount of Gold in multiplayer: 0xFFDDDD66 Script updated. The shade is too 'gold' and not yellow enough.
2) Similarly, if the string that is used by the engine to say who is receiving orders is known, it could be added so the orders follow the format of native orders more efficiently than the current code.

This has been tested and is working as described.

Comments, etc, welcome.

EDIT: Scripts.py code updated to include group names in the order text that scrolls on screen, such as "Infantry, ready polearms!" ...not particularly efficient code, but effective.

EDIT 2: All code bits updated to include new shield toggle.
 

sphere

Grandmaster Knight
M&BWB
Best answers
0
may I suggest one more option?

default

i.e. when this is chosen the system should behave just like the original i.e. the agents will pick weapons as if this mod don't exists.
 

Caba`drin

Count
M&BWBWF&SNWVC
Best answers
0
sphere said:
may I suggest one more option?

default

i.e. when this is chosen the system should behave just like the original i.e. the agents will pick weapons as if this mod don't exists.
This can be accomplished by giving the F3-F4 order "Use Weapons at Will". I didn't think it needed its own key as the functionality was built in...perhaps it does? In any case, thanks for pointing out that I didn't make that clear, I added it to the opening post.
 

leandrojas_

Squire
Best answers
0
Interesting and useful. It is, notably, a great job.

Thanks for this! This is useful for everyone! :grin:
 

Ashmond

Sergeant at Arms
WB
Best answers
0
I'm using this on a personal level.  It works great with my favorite mod and it is so easy to implement that everyone should use it. 

Thanks so much!
 

Caba`drin

Count
M&BWBWF&SNWVC
Best answers
0
I'm happy folks are finding this useful!

Lumos said:
For Warband?...
Yes. And more specifically for Warband 1.130+ as the shield feature uses the 1.130-introduced "agent_equip_item" function to "unwield" the shield. (Sheathing a wielded weapon could be coded similarly, I believe: "agent_unequip_item" followed immediately by "agent_equip_item")
 

SendMeSmile

Sergeant at Arms
Best answers
0
My dreams come true )). Very usefull.

Works cool, but problem with shields -

Infantry only remove shields and don't want to take shields again. But, i think this command is useless, because infantry take shields when used onehanded weapons.
 

Caba`drin

Count
M&BWBWF&SNWVC
Best answers
0
SendMeSmile said:
My dreams come true )). Very usefull.

Works cool, but problem with shields -

Infantry only remove shields and don't want to take shields again. But, i think this command is useless, because infantry take shields when used onehanded weapons.
First, thanks for the screenshot with your error--made it a breeze to track down, and hopefully it is as simple as I think:
The shield portion of the code requires Warband version 1.130 or higher. Have you not updated to the most recent patch?

Second, as to the utility of the shield toggle, its purpose is mainly as the OP states--to force two handers/polearms to be used with both hands. Otherwise, if you give troops that have onehanded/twohanded weapons (spiked staff, bastard sword) or polearms that can be used with shields (most spears, etc) the "Two Hander and Polearm" command, they will keep using their shield. If you were, for any reason, to want your bastard-sword wielders to use both hands or for your spears to use their polearms with both hands to better whack cavalry, then using the shield toggle after the 2Hand/Polearm command makes that possible.
 

SendMeSmile

Sergeant at Arms
Best answers
0
I have 1.31 version. I'll check it again, maybe it was my mistake.
Second - ok, i did not think about it).

UPD. My fault - not 1.31. All work, thank you.
 

Njunja

Knight
WBWF&S
Best answers
0
Indeed, awesome work... and thanks for sharing it.  :grin:
This part really needed some tweaking. 
 

StinkyMcGirk

Sergeant
WF&SWBNWVC
Best answers
0
Works very well with 1.132, as rhodoks gained some new weapons they either wouldn't use, or wouldn't use properly.

Rhodok Veteran Spearmen can now be told to lose the shields in order to use their military scythes correct.

Rhodok Sergeants can be told to use two handers/polearms in order to make use of their new warhammers and old glaives.

Swadian Knights can be ordered to make use of their two handed swords if, say, you have them in a siege situation.  Don't get me started on the power behind a dismounted Swadian Knight with a morningstar given the order to doff his shield.

The only problems are if all of your infantry is together and you use both commands, you end up with a fair amount of Rhodok sergeants using 1h military hammers and military cleavers without their shields...  so you have to increase your micro-management of said units to really get the most out of it.  I guess that's the nature of the beast when you add new A.I. and new commandos, though.

One issue I've had is that my cheatmenu seems to have been enabled by default, and its having some rather strange effects.  For one thing, all custom battles have no feedback on damage/ casualties/ etc.  Sometimes the same thing happens if I don't disable the cheatmenu right away.  Sort of annoying.  This may have come from the skirmish script or this one, though, as I added them at the same time.
 

Caba`drin

Count
M&BWBWF&SNWVC
Best answers
0
StinkyMcGirk said:
One issue I've had is that my cheatmenu seems to have been enabled by default, and its having some rather strange effects.  For one thing, all custom battles have no feedback on damage/ casualties/ etc.  Sometimes the same thing happens if I don't disable the cheatmenu right away.  Sort of annoying.  This may have come from the skirmish script or this one, though, as I added them at the same time.
I don't know why that would be happening...nothing in either of these scripts messes with the cheat mode (which is governed by the global variable $cheat_mode) or any global variables for that matter. Did you try to install the "Add cheat menu toggle to Camp menu" bit that I've posted, too? Otherwise, I can't imagine why there would be any connection between this code and the debug messages.
 

Dermeister

Veteran
Best answers
0
thats a long script is there a way to copy and past it so that it pasted exacly how you wrote it because me ity pastes it in 1 line O_O! even though i selected it all and did control C control V
 

SonKidd

Knight
Best answers
0
for single player only?
would it be possible for it to work for AI under command for multilayer by adding triggers to the appropriate mission templates?

thanks!
 

Caba`drin

Count
M&BWBWF&SNWVC
Best answers
0
Dermeister said:
thats a long script is there a way to copy and past it so that it pasted exacly how you wrote it because me ity pastes it in 1 line O_O! even though i selected it all and did control C control V
That's odd. Have you tried editing the module_*.py files with Notepad++ ? That should ease your pain.

SonKidd said:
for single player only?
would it be possible for it to work for AI under command for multilayer by adding triggers to the appropriate mission templates?
thanks!
For single player only.
I've not ever dealt with multiplayer coding...I honestly don't know what (if anything) may be required  to make this work for bots.
 

Dermeister

Veteran
Best answers
0
YEs thats what im using.... humm well for the py im using the editor that coems with python because the py files in notepad++ have weird writings in them.