OSP Code Optimisation Fix for kill-order loot dependency

Users who are viewing this thread

Tingyun

Knight at Arms
AWOIF and Viking Conquest Balance Mod have had this fix for awhile now, and I haven’t seen reports of any problems, so it seemed time to post here.

There is an issue where if a low level enemy dies first in battle, then that entire stack is looted first, and that can result in the loot buffer filling up and leaving no room for loot from the better enemies. Full details can be found here: https://www.reddit.com/r/mountandblade/comments/8p48ge/kill_order_effect_on_looting_and_mod_solutions/

The issue occurs in both solo or small party hunting, as well as more moderately outnumbered large battles. I’ve seen it start occurring at around 1 v 30, and seen players report it start happening at around 200 v 600, though obviously the exact numbers would depend on the particular mod. It only occurs if there are enemy units with low price gear (since low price gear loots at a much higher rate, sometimes more than 8 items per unit if the enemy force is mid-sized, quickly exhausting the buffer).

The fix is very simple, and consists of simply sorting the enemy party by descending level before looting. Since high level units have high priced gear with low drop rates, they don’t exhaust the buffer generally, and level is a reasonable proxy for loot desirability.

In module_scripts.py in "party_calculate_loot" at (party_get_num_companion_stacks, ":num_stacks",":enemy_party"), paste the below:

Code:
    (party_get_num_companion_stacks, ":num_stacks",":enemy_party"), 
      (assign, ":last_stack", ":num_stacks"),
      (try_for_range, ":unused", 0, ":num_stacks"),
        (assign, ":best_stack", -1),
        (assign, ":best_level", -1),
        (try_for_range, ":cur_stack", 0, ":last_stack"),
          (party_stack_get_troop_id, ":cur_troop", ":enemy_party", ":cur_stack"),
		  (neg|troop_is_hero, ":cur_troop"),
          (store_character_level, ":troop_level", ":cur_troop"),
          (gt, ":troop_level", ":best_level"),
          (assign, ":best_level", ":troop_level"),
          (assign, ":best_stack", ":cur_stack"),
        (try_end),
        (try_begin),
          (gt, ":best_stack", -1),
          (party_stack_get_troop_id, ":stack_troop", ":enemy_party", ":best_stack"),
          (party_stack_get_size, ":stack_size", ":enemy_party", ":best_stack"),
          (party_remove_members, ":enemy_party", ":stack_troop", ":stack_size"),
          (party_add_members, ":enemy_party", ":stack_troop", ":stack_size"),
          (val_sub, ":last_stack", 1),
        (try_end),
      (try_end),

Credit also goes to Rubik, as I adapted some sorting code from custom commander for this new purpose.

One much more minor (and less clearly justified) looting change is to avoid the idle soldiers in the player party getting loot shares during a raid on a bandit camp, and instead just cap the loot shares to the amount of those soldiers who participate, the player plus 6 men. It is simple to do so, just find where the loot calculation already checks whether it is a bandit lair: (party_slot_eq, "$g_enemy_party", slot_party_type, spt_bandit_lair), and add directly underneath either: (val_min, ":num_player_party_shares", 16),  (to set based on normal soldier shares) or (val_min, ":num_player_party_shares", 2:cool:, (to set based on companion x3 shares). Since a player only takes 6 men to assault a bandit lair, it seems more fair to distribute loot the same whether they happen to be in a party of 10 or 100.
 
Hi Axxoy,

The code works fine in several other mods. Are you sure you put the code in the right place? Did you use other changes to looting? If you like you can PM me your looting script and I’ll check it for you.
 
Thanks for this script. There is an exploit. When player dismisses his party before looting he will get much more items. Some mods like Prophecy of Pendor show the looting screen first and then the screen with gathering prisoners/recruites. In this case the script needs to count wound members. They will be prisoners.

(party_get_num_companion_stacks, ":num_stacks",":enemy_party"),                           
(assign, ":last_stack", ":num_stacks"),         
(try_for_range, ":unused", 0, ":num_stacks"),     
  (assign, ":best_stack", -1),                                       
  (assign, ":best_level", -1),                 
  (try_for_range, ":cur_stack", 0, ":last_stack"),
    (party_stack_get_troop_id, ":cur_troop", ":enemy_party", ":cur_stack"),
    (neg|troop_is_hero, ":cur_troop"),
    (store_character_level, ":troop_level", ":cur_troop"),       
    (gt, ":troop_level", ":best_level"),
    (assign, ":best_level", ":troop_level"),
    (assign, ":best_stack", ":cur_stack"),
  (try_end),
  (try_begin),
    (gt, ":best_stack", -1),
    (party_stack_get_troop_id, ":stack_troop", ":enemy_party", ":best_stack"),
    (party_stack_get_size, ":stack_size", ":enemy_party", ":best_stack"),
    (party_stack_get_num_wounded, ":num_wounded", ":enemy_party",  ":best_stack"),
    (party_remove_members, ":enemy_party", ":stack_troop", ":stack_size"),
    (party_add_members, ":enemy_party", ":stack_troop", ":stack_size"),
    (party_wound_members, ":enemy_party", ":stack_troop", ":num_wounded"),
    (val_sub, ":last_stack", 1),
  (try_end),
(try_end),
 
Back
Top Bottom