B Info Module System How to use some simple PYTHON functions in MNB Module System.

Users who are viewing this thread

rubik

Squire
For example:

def set_item_difficulty():
  item_difficulty = []    # create an empty list: item_difficulty
  for i_item in xrange(len(items)):  # do a loop in the list items
    item_difficulty.append((item_set_slot, i_item, slot_item_difficulty, get_difficulty(items[i_item][6]))) # append Module System sentences to the list
  return item_difficulty[:]  # return the whole list with all MS sentences above

# the function get_difficulty is already defined in header_items.py, I just call it here.

It was used to set items' difficulties. Then we can use (item_get_slot,<destination>, <item_id>, slot_item_difficulty) to get items' difficulties easily.
Of course we also need to write some codes to call this PYTHON function.

First we need to add the flowing script to call it.
("init_item_difficulties", set_item_difficulty()), 

Then add the flowing to the script of game_start to call the script of init_item_difficulties.
(call_script, "script_init_item_difficulties"),

I almost forget that, you must define slot_item_difficulty in module_constants.py before you use it.

Now, you can get any static data in Module System and assign it to a slot, not only items' difficulties.

Another example:
Judge whether an item can use on horseback or not.

def judge_item_cant_use_on_horseback():
  cant_use_on_horseback = []    # create an empty list: cant_use_on_horseback
  for i_item in xrange(len(items)):  # do a loop in the list items
    if items[i_item][3] & itp_cant_use_on_horseback ==  itp_cant_use_on_horseback:  # if can't use
      cant_use_on_horseback.append((item_set_slot, i_item, slot_cant_use_on_horseback, 1)) # append Module System sentences to the list
  return cant_use_on_horseback[:]  # return the whole list with all MS sentences above

In the same way, you can Judge whether an item is itp_unique or not, can reload on horseback or not, penalty with shield or not and so on.


What's more, I want to point out that the following in module_items.py is only a list. You can creat a new list and do some related operation yourself.

items = [
# item_name, mesh_name, item_properties, item_capabilities, slot_no, cost, bonus_flags, weapon_flags, scale, view_dir, pos_offset
["no_item","INVALID ITEM", [("practice_sword",0)], itp_type_one_handed_wpn|itp_primary|itp_secondary, itc_longsword, 3,weight(1.5)|spd_rtng(103)|weapon_length(90)|swing_damage(16,blunt)|thrust_damage(10,blunt),imodbits_none],
["horse_meat","Horse Meat", [("raw_meat",0)], itp_type_goods|itp_consumable|itp_food, 0, 12,weight(40)|food_quality(30)|max_ammo(40),imodbits_none],
# Items before this point are hardwired and their order should not be changed!
["practice_sword","Practice Sword", [("practice_sword",0)], itp_type_one_handed_wpn|itp_primary|itp_secondary|itp_wooden_parry|itp_wooden_attack, itc_longsword, 3,weight(1.5)|spd_rtng(103)|weapon_length(90)|swing_damage(16,blunt)|thrust_damage(10,blunt),imodbits_none],

.................................
.................................
.................................
.................................

["rabati", "Rabati", [("rabati",0)], itp_type_head_armor  ,0, 278 , weight(2)|abundance(100)|head_armor(20)|body_armor(0)|leg_armor(0) ,imodbits_cloth ],

]

Such as the following list I wrote:

modifiers = [
  (imod_plain, 100, 0),
  (imod_cracked, 50, -1),
  (imod_rusty, 55, -1),
  (imod_bent, 65, -1),
  (imod_chipped, 72, -1),
  (imod_battered, 75, -1),
  (imod_poor, 80, -1),
  (imod_crude, 83, -1),
  (imod_old, 86, -1),
  (imod_cheap, 90, -1),
  (imod_fine, 190, 1),
  (imod_well_made, 250, 1),
  (imod_sharp, 160, 1),
  (imod_balanced, 350, 1),
  (imod_tempered, 670, 1),
  (imod_deadly, 850, 1),
  (imod_exquisite, 1450, 1),
  (imod_masterwork, 1750, 1),
  (imod_heavy, 190, 1),
  (imod_strong, 490, 1),
  (imod_powerful, 320, 1),
  (imod_tattered, 50, -1),
  (imod_ragged, 70, -1),
  (imod_rough, 60, -1),
  (imod_sturdy, 170, 1),
  (imod_thick, 260, 1),
  (imod_hardened, 390, 1),
  (imod_reinforced, 650, 1),
  (imod_superb, 250, 1),
  (imod_lordly, 1150, 1),
  (imod_lame, 40, -1),
  (imod_swaybacked, 60, -1),
  (imod_stubborn, 90, 1),
  (imod_timid, 180, -1),
  (imod_meek, 180, -1),
  (imod_spirited, 650, 1),
  (imod_champion, 1450, 1),
  (imod_fresh, 100, 1),
  (imod_day_old, 100, -1),
  (imod_two_day_old, 90, -1),
  (imod_smelling, 40, -1),
  (imod_rotten, 5, -1),
  (imod_large_bag, 190, 1)
]

This is a new list I created to record something about every modifier. The first one in every tuple is the ID of the modifier, the second one is the price multiplier(need to divide 100 at last), the third one is the quality of the modifier(1 for good modifier, -1 for bad modifier).

You may have a question that how to use the new list?
Just use it like the list items.

Look at the folowing PYTHON function.

def set_item_modifier_multiplier():
  modifier_multiplier = []
  for i_modifier in xrange(len(modifiers)):
    modifier_multiplier.append((item_set_slot, i_modifier, slot_item_modifier_multiplier, modifiers[i_modifier][1]))
  return modifier_multiplier[:]

This function assign the price multiplier to slot_item_modifier_multiplier for every modifier.

Some related code:
("init_item_modifier_quality", set_item_modifier_quality()),
(call_script, "script_init_item_modifier_quality"),

Now, the script of get_item_value_with_imod in autoloot can be rewrited as following:

("get_item_value_with_imod",
  [# returns the sell price based on the item's money value and its imod
    (store_script_param, ":item", 1),
    (store_script_param, ":imod", 2),
   
    (store_item_value, ":score", ":item"),
    (item_get_slot, ":imod_multiplier", ":imod", slot_item_modifier_multiplier),
    (val_mul, ":score", ":imod_multiplier"),
    (assign, reg0, ":score"),
  ]),

At last, all above are only examples. You should open your mind to create more things.
 
Since slots are zero by default - we'll want the above to write out a 1 (or -1) to that slot when they can't be used on horseback (or better, write a 1 to the slot if it can be used, and leave it at zero otherwise).

Really looking forward to coding this evening :grin:  Thanks rubik.
 
I have change it to cant use. It's more better now.

Edit: I am sorry that I forgot to add a colon at the end of "if items[i_item][3] & itp_cant_use_on_horseback ==  itp_cant_use_on_horseback" just now. 
 
I'd probably just use an array for the imod thing, that looks pretty clunky and I think I see some bugs, but in general the idea is good for encoding general item properties into slots. Just that imod code, I think there are some indexing problems with making each imod an item.
 
Perhaps something more along the lines of:

    (item_get_slot, ":value", ":item", ":imod_slot"),

which in most cases would translate in real code to:

    (item_slot_eq, ":item", slot_item_not_on_horseback, 1),
or
    (item_slot_eq, ":item", slot_item_not_with_shield, 1),
or
    (item_slot_eq, ":item", slot_item_penalty_with_shield, 1),
etc....

Just use multiple slots - one per imodbit or type flag, so that you can tell exactly what an item is and isn't.  Requires quite a few slots... but slots seem to be massive or unlimited, so no biggie.:wink:
 
fisheye said:
I'd probably just use an array for the imod thing, that looks pretty clunky and I think I see some bugs, but in general the idea is good for encoding general item properties into slots. Just that imod code, I think there are some indexing problems with making each imod an item.

Item slots are not only for items. Some objects have no relative operations on slots. Such as item modifiers, weapon proficiencies and so on.
In this situation, we can make these objects items and use operations on item slots. The most important thing is to make sure that the new item slot won't be used on the actual items.
 
rubik said:
fisheye said:
I'd probably just use an array for the imod thing, that looks pretty clunky and I think I see some bugs, but in general the idea is good for encoding general item properties into slots. Just that imod code, I think there are some indexing problems with making each imod an item.

Item slots are not only for items. Some objects have no relative operations on slots. Such as item modifiers, weapon proficiencies and so on.
In this situation, we can make these objects items and use operations on item slots. The most important thing is to make sure that the new item slot won't be used on the actual items.

Well, that's exactly the same as just hijacking the slot on the actual item, then. E.g.

itm_practice_sword is item #1, I use slot 5 to store its difficulty (e.g. 10)
imod_rusty is imod #1, I use slot 6 to store its price multiplier (e.g. 100)

If I retrieve slot 6 on itm_practice_sword, I get 100
If I retrieve slot 5 on imod_rusty, I get 10

I mean, it's the same, since they're both numerically number 1, it's the same memory object (it's an item object). It's pretty weird programming practice to overlap slots like that, but if you keep them separate, it should be ok.
 
fisheye said:
Well, that's exactly the same as just hijacking the slot on the actual item, then. E.g.

itm_practice_sword is item #1, I use slot 5 to store its difficulty (e.g. 10)
imod_rusty is imod #1, I use slot 6 to store its price multiplier (e.g. 100)

If I retrieve slot 6 on itm_practice_sword, I get 100
If I retrieve slot 5 on imod_rusty, I get 10

I mean, it's the same, since they're both numerically number 1, it's the same memory object (it's an item object). It's pretty weird programming practice to overlap slots like that, but if you keep them separate, it should be ok.

Sorry to be dense...

But why would one ever use code intended for items on something that is just a number, such as an imodbit?

I thought imodbits were... bit flags... that add or modify the attributes of that item.  I did not think that an imod was an object, like a troop, party, or item is.

So I would have thought that asking the question: "what is in slot #4 on this imodbit" was a completely meaningless and incorrect question.  imodbits aren't objects, and don't have slots, hence bad question.

I thought that the correct question would have been: "what imodbits are attributed to this item".  That question holds that the item is an object, and each such object has its own set of slots, which can be used for anything, including storing 1 or 0 to indicate if a given attribute is associated with that item.  Such as "Can't be used on horseback" either is or is not attributed to "Great Lance".

But are you saying that imodbits ARE somehow an object?  Because you indicate that asking for slot #5 in your example above would return the value for the item with the matching item ID as the imodbit in question, which to me underscores my understanding that this would just be flat wrong: imodbits aren't objects.

??? sorry to be thique ???
 
I can think of a use for slots on pretty much anything, which is rubik's point.

Suppose you wanted an extra text to appear on rusty and bent items telling you that you can get it repaired. And extra text on the crude and inferior stuff to say it's not repairable. And extra text on balanced and lordly stuff saying it's totally bloody awesome. Then, I'd want to set a slot on an imodbit, that is set to "str_repair_this" for rusty and bent, "str_cant_repair" for crude, and "str_you_lucky_****er" for lordly. Then when grabbing item extra text, I just grab the slot of the imod, and display the text, without having to do a massive case-by-case chunk of script.
 
Okay - that's freakin' cool - but what primitive would you use?  presumably, item_get_slot - which means you're really looking at an item's slot, and just overloading it to store imod info in the same space - meaning that you need to be careful what slots you use - since they're effectively item_slots.

Am I following you two this time?

So one might define a range of such slots:

item_slot_imod_pre_text
item_slot_imod_post_text
item_slot_imod_fix_text
item_slot_imod_can_be_fixed
item_slot_imod_<whatever>

And then all you need to do is to ensure that (1) for every imod that you want to use as an argument, you've got an item with that same ID, and (2) for every item, you ensure that you don't define any of the same slot indexes as something else (since they're both using item slots, even though they're not quite the same thing really).


--- Which brings me to some questions:

If you're querying the attributes of an imodbit, then you need some way to get from an item to its "list" of imodbits.  Since SM has no bit manipulation primitives, short of doing some odd-ball math, wouldn't you need to have a whole set of item slots setup for use as 1 or 0 to indicate if a given bit-flag is associated with that item?

item_slot_has_no_horse_flag
item_slot_has_no_shield_flag
item_slot_has_shield_penalty_flag

...

--- 

Okay - I think I have part of my confusion figured out: I was incorrectly thinking that imods were bit flags.  But they're not, are they?  They're just a unique value, and only one is associated with any given item at run-time, modifying its underlying nature.  But you don't get "rusty" + "large" at the same time  - its either rusty, or large, not both?

If that's the case, then overloading the item-slots to store imod slot-data makes perfect sense.  You ask an item for its imod, and then you ask for the slot X of the item ID the same-as the imod ID you're trying to query, and viola, you now have one or more integers associated with an imod, as long as you don't overlap slots for true items and imod data (slot #5 will be the same value whether one uses an imod or item_no to do the lookup).

However, for item types - they are bit-flags, and they are or'd together, which means you do want the python MS compiler to break that data out for you either into separate slots (as in my examples), or into a value that you then use multiple divide by 2 and mod 2 in order to see if a given bit index was set or not.
 
Ok - so I got something built - using both of your ideas and I felt I should share since it might be useful to you two and likely others.

First: disclaimer: this is new raw code.  I will be testing it over the next week to find & fix bugs.

Second: This is really just both of your ideas combined, and implemented.  Very little new is in here by way of my own ingenuity (my code is mostly about improving the interface - dialogs & menus).  There's a few tid-bits, like trying to compute a weighted damage value taking into account the type of damage - blunt vs. pierce vs. cut.  And there's a tiny bit by way of expanding everything so that more data is available from the MS code - and some minor bug fixes that I found, etc.

Last: I'll be posting my updated system, with smarter pick-weapons logic that is based on all this new info later in the week.  I need to build that logic and build the user interface for it, so this is just the foundation.

I expanded on rubiks idea to have an explicit imod table to try to record and make available the data that the ms engine fails to provide:
Code:
###############################################ITEM MODIFIERS#######################################################
#  Each imod_attributes contains the following elements
#  0) imod
#  1) cost % multiplier for the base item if it has this imod.             (item_get_slot, <dest>, <imod>, slot_imod_cost)
#  2) difficulty (skill) adjustment that this imod requires.               (item_get_slot, <dest>, <imod>, slot_imod_require)
#  3) imod use effect speed (effects horse speed as well).                 (item_get_slot, <dest>, <imod>, slot_imod_speed)
#  4) imod use effect armor rating (effects sheilds & barding too).        (item_get_slot, <dest>, <imod>, slot_imod_armor)
#  5) imod use effect weapon damage.                                       (item_get_slot, <dest>, <imod>, slot_imod_damage)
#
# These values are stuffed into item slots, via the script_init_auto_loot
# You can then access these values using code such as (item_get_slot, ":cost_multiplier", ":imod", slot_imod_cost),
# See module_constants.py for a list of slot_imod_xxx slot definitions
#
# NOTE: modifying the values here is to allow the module code to access this information that the module system fails
#       to provide.  chaning these values won't actually cause the game to change its understanding of what the imod
#       does - it will only change *your* code's understanding - making it effectively *WRONG*.
#       Only add new values (columns of data) that the game exe doesn't use.  The ones I've provided should be
#       considered constant / read-only / etc.
####################################################################################################################
imod_effects = [
  #    ID                COST   DFCLT SPD  ARMR DMG
  (imod_plain,           100,     0,   0,   0,   0),
  (imod_cracked,          50,     0,   0,  -4,  -5),
  (imod_rusty,            55,     0,   0,  -3,  -3),
  (imod_bent,             65,     0,  -3,   0,  -3),
  (imod_chipped,          72,     0,   0,   0,  -1),
  (imod_battered,         75,     0,   0,  -2,   0),
  (imod_poor,             80,     0,   0,   0,   0),
  (imod_crude,            83,     0,   0,  -1,   0),
  (imod_old,              86,     0,   0,   0,   0),
  (imod_cheap,            90,     0,   0,   0,   0),
  (imod_fine,            190,     0,   0,   0,   0),
  (imod_well_made,       250,     0,   0,   0,   0),
  (imod_sharp,           160,     0,   0,   0,   0),
  (imod_balanced,        350,     0,   3,   0,   3),
  (imod_tempered,        670,     0,  -1,   0,   4),
  (imod_deadly,          850,     0,   0,   0,   0),
  (imod_exquisite,      1450,     0,   0,   0,   0),
  (imod_masterwork,     1750,     4,   1,   0,   5),
  (imod_heavy,           190,     1,  -2,   3,   2),
  (imod_strong,          490,     2,  -3,   0,   3),
  (imod_powerful,        320,     0,   0,   0,   0),
  (imod_tattered,         50,     0,   0,  -3,   0),
  (imod_ragged,           70,     0,   0,  -2,   0),
  (imod_rough,            60,     0,   0,   0,   0),
  (imod_sturdy,          170,     0,   0,   1,   0),
  (imod_thick,           260,     0,   0,   2,   0),
  (imod_hardened,        390,     0,   0,   3,   0),
  (imod_reinforced,      650,     0,   0,   4,   0),
  (imod_superb,          250,     0,   0,   0,   0),
  (imod_lordly,         1150,     0,   0,   6,   0),
  (imod_lame,             40,     0,  -5,   0,   0),
  (imod_swaybacked,       60,     0,  -2,   0,   0),
  (imod_stubborn,         90,     1,   0,   0,   0),
  (imod_timid,           180,     1,   0,   0,   0),
  (imod_meek,            180,     0,   0,   0,   0),
  (imod_spirited,        650,     0,   1,   0,   0),
  (imod_champion,       1450,     0,   2,   0,   0),
  (imod_fresh,           100,     0,   0,   0,   0),
  (imod_day_old,         100,     0,   0,   0,   0),
  (imod_two_day_old,      90,     0,   0,   0,   0),
  (imod_smelling,         40,     0,   0,   0,   0),
  (imod_rotten,            5,     0,   0,   0,   0),
  (imod_large_bag,       190,     0,   0,   0,   0)
]
I expanded the amount of data we record for items:
Code:
def get_swing_damage_type(y):
  return (y >> (iwf_damage_type_bits+iwf_swing_damage_bits)) & 0x03

def get_thrust_damage_type(y):
  return (y >> (iwf_damage_type_bits+iwf_thrust_damage_bits)) & 0x03

def set_item_base_score():
  item_base_score = []
  for i_item in xrange(len(items)):
    # get the base type without its bitflag attributes
    type = items[i_item][3] & ibf_item_type_mask

    if type >= itp_type_head_armor and type <= itp_type_hand_armor:

      # store armor attributes
      item_base_score.append((item_set_slot, i_item, slot_item_head_armor, get_head_armor(items[i_item][6])))
      item_base_score.append((item_set_slot, i_item, slot_item_body_armor, get_body_armor(items[i_item][6])))
      item_base_score.append((item_set_slot, i_item, slot_item_leg_armor, get_leg_armor(items[i_item][6])))

    elif type >= itp_type_one_handed_wpn and type <= itp_type_thrown and type != itp_type_shield:

      # store weapon attributes
      item_base_score.append((item_set_slot, i_item, slot_item_thrust_damage, get_thrust_damage(items[i_item][6])&0xff))
      item_base_score.append((item_set_slot, i_item, slot_item_swing_damage, get_swing_damage(items[i_item][6])&0xff))
      item_base_score.append((item_set_slot, i_item, slot_item_thrust_damage_type, get_thrust_damage_type(items[i_item][6])))
      item_base_score.append((item_set_slot, i_item, slot_item_swing_damage_type, get_swing_damage_type(items[i_item][6])))
      item_base_score.append((item_set_slot, i_item, slot_item_weapon_speed, get_speed_rating(items[i_item][6])))
      if items[i_item][3] & itp_cant_use_on_horseback == itp_cant_use_on_horseback:
        item_base_score.append((item_set_slot, i_item, slot_item_cant_use_on_horseback, 1))
      else:
        item_base_score.append((item_set_slot, i_item, slot_item_cant_use_on_horseback, 0))

    elif type == itp_type_shield:

      # store shield attributes
      item_base_score.append((item_set_slot, i_item, slot_item_shield_size, get_weapon_length(items[i_item][6])))
      item_base_score.append((item_set_slot, i_item, slot_item_shield_armor, get_body_armor(items[i_item][6])))
      if items[i_item][3] & itp_cant_use_on_horseback == itp_cant_use_on_horseback:
        item_base_score.append((item_set_slot, i_item, slot_item_cant_use_on_horseback, 1))
      else:
        item_base_score.append((item_set_slot, i_item, slot_item_cant_use_on_horseback, 0))

    elif type == itp_type_horse:

      # store horse attributes
      item_base_score.append((item_set_slot, i_item, slot_item_horse_speed, get_missile_speed(items[i_item][6])))
      item_base_score.append((item_set_slot, i_item, slot_item_horse_armor, get_body_armor(items[i_item][6])))
      item_base_score.append((item_set_slot, i_item, slot_item_horse_charge, get_thrust_damage(items[i_item][6])&0xff))


  return item_base_score[:]

Which fills out these slots (defined in constants.py):
Code:
# armor
slot_item_head_armor      = 6
slot_item_body_armor      = 7
slot_item_leg_armor       = 8

# weapons
slot_item_cant_use_on_horseback = 6
slot_item_thrust_damage   = 7
slot_item_swing_damage    = 8
slot_item_thrust_damage_type = 9
slot_item_swing_damage_type = 10
slot_item_weapon_speed    = 11

# shields
#slot_item_cant_use_on_horseback = 6  # we use this for shields too
slot_item_shield_size     = 7
slot_item_shield_armor    = 8

# horses
slot_item_horse_speed     = 6
slot_item_horse_armor     = 7
slot_item_horse_charge    = 8

# MORDACHAI - further extensions to Autoloot

# damage types
idt_cut      = 0
idt_pierce   = 1
idt_blunt    = 2

And finally this function to retrieve the lovely imod_effectg table we added to items.py:
Code:
def set_imod_effects():
  effects = []
  for i_effect in xrange(len(imod_effects)):
    imod_id = imod_effects[i_effect][0]
    effects.append((item_set_slot, imod_id, slot_imod_cost,    imod_effects[i_effect][1]))
    effects.append((item_set_slot, imod_id, slot_imod_require, imod_effects[i_effect][2]))
    effects.append((item_set_slot, imod_id, slot_imod_speed,   imod_effects[i_effect][3]))
    effects.append((item_set_slot, imod_id, slot_imod_armor,   imod_effects[i_effect][4]))
    effects.append((item_set_slot, imod_id, slot_imod_damage,  imod_effects[i_effect][5]))
  return effects[:]
Which fills out these slots:
Code:
# imod slots are really item slots!!!
# WARNING: do not let them overlap with any slot_item_xxx definition, or you will be sorry!
slot_imod_cost          =   100
slot_imod_require       =   101
slot_imod_speed         =   102
slot_imod_armor         =   103
slot_imod_damage        =   104

And here's the affected autoloot scripts:
Code:
####################################################################################
#
# Autoloot Scripts begin
# ---------------------------------------------------
# Original credit to Fisheye
# Autoloot improved by rubik
# User-interface enchancements by Mordachai
####################################################################################

  ("init_item_difficulties", set_item_difficulty()),
  ("init_item_base_score", set_item_base_score()),
  ("init_imod_effects", set_imod_effects()),

  ###################################
  # MORDACHAI - tie all of the autoloot initialization into a single function
  # script_init_auto_loot
  # Input: arg1: 1 if called from game_start, 0 otherwise
  # Onput: none
  # Effect: initializes the item slots used by auto loot if it hasn't been performed yet for this version of autoloot
  ###################################
  ("init_auto_loot",
    [
      # we pass this in so that we can distinguish creating a new game vs. updating an old one
      (store_script_param, ":game_start", 1),
      (assign, reg0, ":game_start"), # avoid unused variable error

      (try_begin),
        # only do the initialization if it hasn't been done for this version of autoloot yet
        (lt, "$g_auto_loot_version", auto_loot_version),
        # reinitialize autoloot if we've installed a newer version of it (update a saved game automatically)
        # NOTE: if the system changes radically enough - we'll need to clear out the old troop slots and ask the player to reassign them from scratch

        # initialize the difficulty slots
        (call_script, "script_init_item_difficulties"),

        # initialize additional item slots
        (call_script, "script_init_item_base_score"),

        # initialize the imod slot data
        (call_script, "script_init_imod_effects"),

        # record the version of autoloot that we've initialized for
        (assign, "$g_auto_loot_version", auto_loot_version),
      (try_end),
    ]
  ),

  ###################################
  # script_troop_can_use_item
  # Can a troop qualify to use this item?
  # arg1: troop
  # arg2: item
  # arg3: imod
  # Returns 1 = yes, 0 = no.
  ###################################
  ("troop_can_use_item",
    [
      (store_script_param, ":troop", 1),
      (store_script_param, ":item", 2),
      (store_script_param, ":imod", 3),

      (item_get_slot, ":difficulty", ":item", slot_item_difficulty),

      (try_begin),

        # anyone can use this item
        (eq, ":difficulty", 0),
        (assign, reg0, 1),

      (else_try),

        # adjust for imod
        (item_get_slot, ":adj", ":imod", slot_imod_require),
        (val_add, ":difficulty", ":adj"),

        # determine which skill or attribute the difficulty rating applies to
        (item_get_type, ":type", ":item"),
        (try_begin),
          # horse (skl_riding)
          (eq, ":type", itp_type_horse),
          (store_skill_level, ":skill", skl_riding, ":troop"),
        (else_try),
          # melee weapon or armor (strength)
          (this_or_next|eq, ":type", itp_type_crossbow),
          (this_or_next|eq, ":type", itp_type_one_handed_wpn),
          (this_or_next|eq, ":type", itp_type_two_handed_wpn),
          (this_or_next|eq, ":type", itp_type_polearm),
          (this_or_next|eq, ":type", itp_type_head_armor),
          (this_or_next|eq, ":type", itp_type_body_armor),
          (this_or_next|eq, ":type", itp_type_foot_armor),
          (             eq, ":type", itp_type_hand_armor),
          (store_attribute_level, ":skill", ":troop", ca_strength),
        (else_try),
          # shield (skl_shield)
          (eq, ":type", itp_type_shield),
          (store_skill_level, ":skill", skl_shield, ":troop"),
        (else_try),
          # bow (power draw)
          (eq, ":type", itp_type_bow),
          (store_skill_level, ":skill", skl_power_draw, ":troop"),
        (else_try),
          # thrown weapon (power throw)
          (eq, ":type", itp_type_thrown),
          (store_skill_level, ":skill", skl_power_throw, ":troop"),
        (try_end),

        (try_begin),
          # check if the troop has enough skill to equip this item
          (ge, ":skill", ":difficulty"),
          (assign, reg0, 1),
        (else_try),
          (assign, reg0, 0),
        (try_end),
      (try_end),
    ]
  ),

  #####################################################################
  # script_get_item_cost_with_imod
  # Param1: item ID
  # Param2: item modifier
  # returns the sell price for the item adjusted by its imod
  #####################################################################
  ("get_item_cost_with_imod",
    [
      (store_script_param, ":item", 1),
      (store_script_param, ":imod", 2),

      (store_item_value, ":cost", ":item"),
      (item_get_slot, ":multiplier", ":imod", slot_imod_cost),
      (val_mul, ":cost", ":multiplier"),
      (store_div, reg0, ":cost", 100),
    ]
  ),

  #####################################################################
  # script_get_item_difficulty_with_imod
  # Param1: item ID
  # Param2: item modifier
  # returns the difficulty requirement for the item adjusted by its imod
  #####################################################################
  ("get_item_difficulty_with_imod",
    [
      (store_script_param, ":item", 1),
      (store_script_param, ":imod", 2),

      (item_get_slot, ":base", ":item", slot_item_difficulty),
      (try_begin),
        (neq, ":base", 0),
        (item_get_slot, ":adj", ":imod", slot_imod_require),
        (store_add, reg0, ":base", ":adj"),
      (else_try),
        (assign, reg0, ":base"),
      (try_end),
    ]
  ),

  #####################################################################
  # script_get_damage_adjusted_for_type
  # Param1: base damage
  # Param2: damage type
  # returns the effective damage rating
  #####################################################################
  ("get_damage_adjusted_for_type",
    [
      (store_script_param, ":damage", 1),
      (store_script_param, ":type", 2),

      #NOTE: this function must be adjusted if you mess with the soak & reduction factors in module.ini
      # NOTE: I have no idea how to really generate these numbers - wtf does soak and reduction actually mean?
      (try_begin),
        (eq, ":type", idt_cut),
        (assign, reg0, ":damage"),
      (else_try),
        (eq, ":type", idt_pierce),
        (store_mul, reg0, ":damage", 130),
        (val_div, reg0, 100),
      (else_try),
        (eq, ":type", idt_blunt),
        (store_mul, reg0, ":damage", 135),
        (val_div, reg0, 100),
      (try_end),
    ]
  ),

  #####################################################################
  # script_get_item_score_with_imod
  # Param1: item ID
  # Param2: item modifier
  # returns the desirability score for the item adjusted by its imod
  #####################################################################
  ("get_item_score_with_imod",
    [
      (store_script_param, ":item", 1),
      (store_script_param, ":imod", 2),

      (item_get_type, ":type", ":item"),
      (try_begin),

        # horse score = (horse_armor + imod) * (speed + imod)
        (eq, ":type", itp_type_horse),

        (item_get_slot, ":horse_armor", ":item", slot_item_horse_armor),
        (item_get_slot, ":imod_armor", ":imod", slot_imod_armor),
        (val_add, ":horse_armor", ":imod_armor"),

        (item_get_slot, ":speed", ":item", slot_item_horse_speed),
        (item_get_slot, ":imod_speed", ":imod", slot_imod_speed),
        (val_add, ":speed", ":imod_speed"),

        (store_mul, ":i_score", ":horse_armor", ":speed"),

      (else_try),

        # shield score = shield_size * (shield_armor + imod)
        (eq, ":type", itp_type_shield),
        (item_get_slot, ":shield_size", ":item", slot_item_shield_size),
        (item_get_slot, ":shield_armor", ":item", slot_item_shield_armor),
        (item_get_slot, ":imod_armor", ":imod", slot_imod_armor),
        (val_add, ":shield_armor", ":imod_armor"),
        (store_mul, ":i_score", ":shield_size", ":shield_armor"),

      (else_try),

        # armor score = (head_armor + imod) + (body_armor + imod) + (foot_armor + imod)
        (this_or_next|eq, ":type", itp_type_head_armor),
        (this_or_next|eq, ":type", itp_type_body_armor),
        (this_or_next|eq, ":type", itp_type_foot_armor),
        (             eq, ":type", itp_type_hand_armor),

        # get the imod effect on armor
        (item_get_slot, ":imod_armor", ":imod", slot_imod_armor),

        # get the adjusted armor value of each aspect of this armor
        (item_get_slot, ":head_armor", ":item", slot_item_head_armor),
        (try_begin),
          (gt, ":head_armor", 0),
          (val_add, ":head_armor", ":imod_armor"),
        (try_end),

        (item_get_slot, ":body_armor", ":item", slot_item_body_armor),
        (try_begin),
          (gt, ":body_armor", 0),
          (val_add, ":body_armor", ":imod_armor"),
        (try_end),

        (item_get_slot, ":leg_armor", ":item", slot_item_leg_armor),
        (try_begin),
          (gt, ":leg_armor", 0),
          (val_add, ":leg_armor", ":imod_armor"),
        (try_end),

        # add all of the adjusted armors together
        (store_add, ":i_score", ":head_armor", ":body_armor"),
        (val_add, ":i_score", ":leg_armor"),

      (else_try),

        # weapon score = max((swing_damage * dmg_type_adj_factor), (thrust_damage * dmg_type_adj_factor))
        (this_or_next|eq, ":type", itp_type_one_handed_wpn),
        (this_or_next|eq, ":type", itp_type_two_handed_wpn),
        (this_or_next|eq, ":type", itp_type_bow),
        (this_or_next|eq, ":type", itp_type_crossbow),
        (             eq, ":type", itp_type_polearm),

        # get the imod first - it adjusts the base damage value
        (item_get_slot, ":imod_damage", ":imod", slot_imod_damage),

        # get actual damage values adjusted for damage type
        (item_get_slot, ":swing_damage", ":item", slot_item_swing_damage),
        (val_add, ":swing_damage", ":imod_damage"),
        (item_get_slot, ":swing_damage_type", ":item", slot_item_swing_damage_type),
        (call_script, "script_get_damage_adjusted_for_type", ":swing_damage", ":swing_damage_type"),
        (assign, ":swing_damage", reg0),

        (item_get_slot, ":thrust_damage", ":item", slot_item_thrust_damage),
        (val_add, ":thrust_damage", ":imod_damage"),
        (item_get_slot, ":thrust_damage_type", ":item", slot_item_thrust_damage_type),
        (call_script, "script_get_damage_adjusted_for_type", ":thrust_damage", ":thrust_damage_type"),
        (assign, ":thrust_damage", reg0),

        # use the better of the two as the basis for choosing to upgrade to this weapon
        (assign, ":i_score", ":swing_damage"),
        (val_max, ":i_score", ":thrust_damage"),

      (else_try),

         # thrown score = (thrust damage + imod_damage)
        (eq, ":type", itp_type_thrown),

        (item_get_slot, ":thrust_damage", ":item", slot_item_thrust_damage),
        (item_get_slot, ":imod_damage", ":imod", slot_imod_damage),
        (store_add, ":i_score", ":thrust_damage", ":imod_damage"),

      (else_try),

        # bolts & arrows score = thrust_damage*2 (+1 if large bag)
        (this_or_next|eq, ":type", itp_type_arrows),
        (             eq, ":type", itp_type_bolts),

        (item_get_slot, ":thrust_damage", ":item", slot_item_thrust_damage),
        (store_mul, ":i_score", ":thrust_damage", 2),

        # a_large_bag will add 1 to score to discriminate the same ammo with the plain modifier
        (try_begin),
          (eq, ":imod", imod_large_bag),
          (val_add, ":i_score", 1),
        (try_end),

      (try_end),

      (assign, reg0, ":i_score"),
    ]
  ),
  #### Autoloot improved by rubik end
 
These is no need to get damage type and damage value separately with PYTHON functions and create a new slot for damage type.
The function get_thrust_damage(items[i_item][6]) will return a value which contains the information on both damage type and damage value.

We can use (store_div, ":damage_type",":damage", 256), to get its damage type and (store_mod, ":damage_value",":damage", 256), to get its damage value. 
 
rubik said:
These is no need to get damage type and damage value separately with PYTHON functions and create a new slot for damage type.
The function get_thrust_damage(items[i_item][6]) will return a value which contains the information on both damage type and damage value.

We can use (store_div, ":damage_type",":damage", 256), to get its damage type and (store_mod, ":damage_value",":damage", 256), to get its damage value.

I changed the extractors to mask against 0xFF for the damage field.  So damage-type is not stored in the damage slots, but since I placed those in their own slots, its easy(er) to access.  I just prefer it as two separate slots, that one doesn't have to mod or div by anything to use it - direct access - direct use. :wink:

...after all, the full value of the item type could be stored and we could mod/div to tease out all of the bit-ranges... but that would be cumbersome, eh?
 
Got this to work, yepee!

Code:
get_improvement_details = CScript("get_improvement_details")
encountered_party = CGlobalVar("encountered_party")
cur_improvement = CLocalVar("cur_improvement")
assign( CReg(6), 0 )
with If():	
	partyGetSlot( cur_improvement, encountered_party, slot_center_current_improvement ) > 0
	get_improvement_details( cur_improvement )
	strStoreString( s7, s0 )
	assign( CReg(6), 1 )
	CReg(9).assign( valMax_( (partyGetSlot_( encountered_party, slot_center_improvement_end_hour ) - storeCurrentHours_()) / 24, 1 ) - 1 )

Code:
cf_enter_center_location_bandit_check = CScript("cf_enter_center_location_bandit_check")
check_quest_active = CScript("check_quest_active")
init_town_walkers = CScript("init_town_walkers")
with If():	
	cf_enter_center_location_bandit_check()
	with Else():
		modifyVisitorsAtSite( partyGetSlot_("$current_town",slot_town_elder) )
		resetVisitors()
		setVisitor( 11, partyGetSlot_("$current_town", slot_town_elder) )
		with If():
			check_quest_active("qst_hunt_down_fugitive")
			emit(_neg|_is_currently_night)
			questSlotEq("qst_hunt_down_fugitive", slot_quest_target_center, "$current_town")
	                emit(_neg|_check_quest_succeeded, "qst_hunt_down_fugitive")
        	        emit(_neg|_check_quest_failed, "qst_hunt_down_fugitive")
        	        setVisitor( 45, "trp_fugitive" )
		init_town_walkers()
		setJumpMission("mt_village_center")
		changeScreenMission()
 
Agrippa, are you using some kind of add-on, or did you write all those python wrappers for modsys code yourself?
 
Actually that's today's work inpired by this thread. Right now that's ~400 lines of horrible code, and i don't know how it's working, it actually shouldn't )
 
Holy crap. I hope you know what you're doing, it looks like you're actually rewriting the whole modsys.
 
agrippa said:
Actually that's today's work inpired by this thread. Right now that's ~400 lines of horrible code, and i don't know how it's working, it actually shouldn't )

Although its cool from a purely "I can do this" perspective (programming nerd) - why?  Do you have a larger purpose in mind?

One thing that would be a nice enhancement of Rubik's idea is a way to inline his python functions.

His implementation generates a list of tuples - which is precisely what is associated with a script, so that works.  And one can use that technique to replace any entity that expects a list of MS code tuples (such as the condition block for a dialog or menu, or a consequence block for either one).  But if we could have the python function emit the tuples inline, then we could invoke multiple ones, such as:

("init_auto_loot",
[
  some_python_function(),
  another_python_function(),
  (eq, ":local", value),
  yet_another_python_function(),
  (assign, reg0, 5),
  ]
),

Currently, the MS compiler will barf on the above because some_python_fuction() generates a list - and instead of a list we would need an inline expansion of that list - the individual tuples placed into the code-stream.  Does that make sense to you?
 
Back
Top Bottom