Recent content by Zsar

  1. Zsar

    Crossdressing in Calradia [ Battanian Edition ]

    Mmh, maybe it is time to introduce the concept of unisex clothing? Because, issue aside, the first three do not look out of place to me at all?
    (Or rather, Lamarc looks like he is "wearing casual" - it would look a little odd, if he walked about town dressed like that... last time I checked lords never do that though, so it's not effectively a problem, is it?)

    ... The last two guys make up for it, though, they their sense of fashion should definitely be fixed.
  2. Zsar

    Resolved Gang leader needs weapons quest bugged

    @elysebluemoon : Please add as a probable cause:
    - counted number of weapons in quest log is often wrong
    - when the counted number is wrong, the weapons cannot be delivered

    Here is a 1.5.3 save reproducing the issue: (Dropbox)

    Steps to reproduce:
    - load game
    - check Inventory: 4 One Handed Axes
    - check Quests: only 2 One Handed Axes
    - talk to Iliset the Viper and try to hand over your 4/4 One Handed Axes
    ... you cannot.

    Note: In this save dialog text from another quest appears, but the same behaviour occurs just as well when no other quests are active (text is then correct, but weapons cannot be handed over nevertheless).

    Only when working around this issue have I noticed other weapons (of any type, not only ranged) vanish - the game seems to count/find wrongly and then just removes whatever until it has removed <expected> number of items.
  3. Zsar

    Missing changelogs for late patch versions

    I have not been around for a while and today noted that the game version has increased from version 1.158 to 1.165 and may in fact soon climb to 1.166. Using search, I was able to find the following changelogs:1.160 1.161 1.164 1.165Unfortunately, I still lack the changelogs for 1.159, 1.162...
  4. Zsar

    [KIT] partitioned Module System source files

    MadVader said:
    It's best to stay with the Taleworlds code organization and just get used to it, separating your code as much as you can from their code.
    I accept that I probably am completely oblivious to the actual meaning, but well, this sentence appears to exactly match my motivation to split the files in the first place. Modularisation, so diff/merge can be limited to as small a file as possible - module_*.py - while all included files contain 100% second or third party code.

    If that were the case, however, the sense of everything before in your post were nullified. This seems implausible, so my matching likely be wrong. While in either case this is my fallacy alone, a helping hand in discerning the proper interpretation were most welcome.

    ... If someone could enlighten me now, how to properly include Python files in others? That would be most welcome too.
    This whole situation is not only uncomfortable but also highly demotivating.
  5. Zsar

    [KIT] partitioned Module System source files

    There are no includes in Python. As far as I am aware!
    Imports pre-interpret a file, so the imported file has to import everything necessary to be sensibly interpreted, so I need import circles and a whole bunch of useless lines in a file I created for the single one purpose to be as short as possible!

    This file:
    Code:
    scripts.extend([
      #script_get_number_with_luck:
      # INPUT : arg0 = luck, arg1 = number
      # OUTPUT: reg0 = (number + number * luck)
      ("get_number_with_luck",[
        (store_script_param_1, reg0),
        (store_script_param_2, ":num"),
    
        (val_mul, reg0, ":num"),
        (val_div, reg0, 100),
        (val_add, reg0, ":num")
      ]),
    
      #script_get_number_with_luck_from_troop:
      # INPUT : arg0 = troop_id, arg1 = number
      # OUTPUT: reg0 = (number + number * luck)
      ("get_number_with_luck_from_troop",[
        (store_script_param_1, reg0),
        (store_script_param_2, ":num"),
    
        (troop_get_slot, reg0, reg0, slot_troop_luck),
        (val_mul, reg0, ":num"),
        (val_div, reg0, 100),
        (val_add, reg0, ":num")
      ]),
    
      #script_get_number_with_luck_from_party:
      # INPUT : arg0 = party_id, arg1 = number
      # OUTPUT: reg0 = (number + number * average_luck)
      ("get_number_with_luck_from_party",[
        (store_script_param_1, reg0),
        (store_script_param_2, ":num"),
    
        (call_script, "script_calculate_average_party_luck", reg0),
        (val_mul, reg0, ":num"),
        (val_div, reg0, 100),
        (val_add, reg0, ":num")
      ]),
    
      #script_get_random_number_with_luck:
      # INPUT : arg0 = luck, arg1 = min_value, arg2 = max_value + 1
      # OUTPUT: reg0 = (random_number + random_number * luck)
      ("get_random_number_with_luck",[
        (store_script_param_1, reg0),
        (store_script_param_2, ":min"),
        (store_script_param, ":max", 3),
    
        (store_random_in_range, ":rnd", ":min", ":max"),
        (val_mul, reg0, ":rnd"),
        (val_div, reg0, 100),
        (val_add, reg0, ":rnd")
      ]),
    
      #script_get_random_number_with_luck_from_troop:
      # INPUT : arg0 = troop_id, arg1 = min_value, arg2 = max_value + 1
      # OUTPUT: reg0 = (random_number + random_number * luck)
      ("get_random_number_with_luck_from_troop",[
        (store_script_param_1, reg0),
        (store_script_param_2, ":min"),
        (store_script_param, ":max", 3),
    
        (troop_get_slot, reg0, reg0, slot_troop_luck),
        (store_random_in_range, ":rnd", ":min", ":max"),
        (val_mul, reg0, ":rnd"),
        (val_div, reg0, 100),
        (val_add, reg0, ":rnd")
      ]),
    
      #script_get_random_number_with_luck_from_party:
      # INPUT : arg0 = party_id, arg1 = min_value, arg2 = max_value + 1
      # OUTPUT: reg0 = (random_number + random_number * average_luck)
      ("get_random_number_with_luck_from_party",[
        (store_script_param_1, reg0),
        (store_script_param_2, ":min"),
        (store_script_param, ":max", 3),
    
        (call_script, "script_calculate_average_party_luck", reg0),
        (store_random_in_range, ":rnd", ":min", ":max"),
        (val_mul, reg0, ":rnd"),
        (val_div, reg0, 100),
        (val_add, reg0, ":rnd")
      ]),
    
      #script_calculate_adverse_troop_lucks:
      # INPUT : arg0 = active_troop_id, arg1 = reactive_troop_id
      # OUTPUT: reg0 = relative_active_troop_luck
      ("calculate_adverse_troop_lucks",[
        (store_script_param_1, reg0),
        (store_script_param_2, ":sub"),
    
        (troop_get_slot, reg0, reg0, slot_troop_luck),
        (troop_get_slot, ":sub", ":sub", slot_troop_luck),
        (val_sub, reg0, ":sub")
      ]),
    
      #script_calculate_adverse_party_lucks:
      # INPUT : arg0 = active_party_id, arg1 = reactive_party_id
      # OUTPUT: reg0 = relative_active_party_id
      ("calculate_adverse_party_lucks",[
        (store_script_param_1, ":dom"),
        (store_script_param_2, ":sub"),
    
        (call_script, "script_calculate_average_party_luck", ":sub"),
        (assign, ":sub", reg0),
        (call_script, "script_calculate_average_party_luck", ":dom"),
        (val_sub, reg0, ":sub")
      ]),
    
      #script_calculate_average_party_luck:
      # INPUT : arg0 = party_id
      # OUTPUT: reg0 = average_luck
      ("calculate_average_party_luck",[
        (store_script_param_1, ":party_id"),
    
        (party_get_num_companion_stacks, ":stack_count", ":party_id"),
        (assign, reg0, 0),
        (assign, ":quotient", 0),
        (try_for_range, ":stack", 0, ":stack_count"),
          (party_stack_get_troop_id, ":stack", ":stack"),
          (troop_get_slot, ":stack", ":stack", slot_troop_luck),
          (neq, ":stack", 0), # do not count no-luckers
            (val_add, reg0, slot_troop_luck),
            (val_add, ":quotient", 1),
        (try_end),
    
        (try_begin),
          (neq, ":quotient", 0), # at least one lucker
            (val_div, reg0, ":quotient"),
        (try_end)
      ])
    ])
    cannot be included via import-statement as is! The interpreter will abort on "store_script_param_1" as it is a token not defined in this file or any of its own imports.
    ... Easiest trick to achieve this was to append the file content to module_scripts.py. No imports needed, no lines wasted, no interpretation madness - and as it happens exactly what the #include-statement does for a C-file. True, indifferent inclusion.
    If I can "just include" it, then "to include" means not "to import" and it is not a technique one trivially has to stumple across when learning the language, so I missed it, and it is neither a technique easily looked up, by the proof that I could not find it.

    Damnation, did this ruffle the feathers I have not; I must be abnormally clueless to pose a problem that apparently no one else ever had!
  6. Zsar

    [KIT] partitioned Module System source files

    Well, overlapping slot definitions just might be a silent, hard to spot problem.
    Code:
    troop_slot_home = 2
    troop_slot_liege  = 2
    ... Sure, will compile, no problem.
    - Oh, then we save a party in troop_slot_home and a troop in troop_slot_liege and get arbitrary results in our code? Tsk tsk tsk.

    These have to be collision free by parent type. Without automatic detection, to keep them all in one place is the only way to ensure this.

    Now, slot definitions and slot content definitions should be in the same block for ease of reference. Slot content definitions are quite harmless and may be defined locally as you suggest - but then the slot definition should be with them... I need not continue, do I?

    I constantly (hè) employ named constants. A good way to increase maintainability.
    In my (yet unfinished) adjacency library, a node is stored in a center's party_slot.
    Here g_player_luck turned into a troop_slot for the purpose of generalising this value to all unique characters.
    In this script for the original M&B I have used an item_slot to store the factions whose traders should have access to it.

    I have on average (and indeed: exactly) required one additional slot per project.

    addendum:
    Oh wait, I just recalled something - to import a file, it must be a valid module, so I had to carry back the necessary imports to the files-to-be-imported, had I not? I recall this issue leading me to the copy-approach in the first place.

    Concise:
    Code:
    Scripts.append([
      ("example_script",[
        (store_val, ":bla", 0, 1),
      ])
    ])
    I would earn on import into module_scripts a "NameError: name 'store_val' not defined" unless I imported header_scripts therein. Same for all other sources.
  7. Zsar

    [KIT] partitioned Module System source files

    So, not worst case: I can still append at the end. Still have to use my kit, just to create import statements instead of copying the whole file content.
    Hé, that does make the world a better place.

    I will have at that. Mayhap today even. See how well it can work.
    ... You have not, by chance, hid away a collision detection for constants, slot definitions in particular? That would allow to savely partition module_constants.py, which in turn were a boon.
  8. Zsar

    [KIT] partitioned Module System source files

    Wait, wait, I think I must elaborate the requirement I have, as I find no hint towards accomplishing it in this explanation:

    Say, I have a folder Headers, the headers are in there. Fine.
    Now, I want to create a folder Scripts, wherein I store scripts, to be appended to module_scripts.py .
    Now, I want to create subfolders Graph, Luck, Adjacencies, wherein I store scripts that might reference each other.
    Example: Adjacencies uses Graph for graph-based algorithms such as finding a path. It might also invoke a script from Luck to discern, whether among fairly equal pathes a lord pick the best, the worst or one inbetween.

    My kit performs depth-first traversal through the directory structure and appends it all to module_scripts.py before processing is started.
    In other words, to drop a file into any subdirectory of Scripts suffices for its inclusion and its position relative to any other subfolder is irrelevant.
    Simple and clear.

    How do I do exactly that with swysdk?
    • Declare folder F matched to one module file.
    • Have Drag&Drop support for any subfolder of F.
    • Have full automatic access between arbitrary subfolders of arbitrary depth from F.

    If I just extended the PYTHONPATH with F, would that suffice?
    I think not: None of the code you posted concatenates these source files in any way. None of the code you posted contains a loop with dynamic range to process an arbitrary number of files sequentially.
    If it does work that way, it does so by a mechanism that completely eludes me.
  9. Zsar

    Python editor

    One never tires to campaign for Notepad++, because it is indeed that good.

    ... There are decomilers available here and there, but really, one should work and be content with raw source files wherever possible!
  10. Zsar

    Fireball problems

    Ah, I think I understand. When "add_missile" is invoked, it actually does the very same as using the item in question would do. Therefore, a hit with "itm_fe_tome_of_fire2" triggers a shot of "itm_fe_tome_of_fire2", which will hit something, which triggers a shot of "itm_fe_tome_of_fire2", which will hit something... well, and there we have that.

    ... This is a positively funky way to create a while-loop. The Module System definitely qualifies as an esoteric programming language by now.
    Who needs INTERCAL and its "COME FROM" when we can have the "DO NOT STOP SHOOTING YET"-loop!
  11. Zsar

    Recruiting manhunters from villages?

    Mmh, I think we might have a slight communication problem...
    Let us try this in the most detailed way then. See that code up there? It contains two blocks of script:
    Code:
    [
        (store_troop_gold, ":value", "trp_player"),
        (ge, ":value", 10),
        (party_get_free_companions_capacity, ":value", "p_main_party"),
        (gt, ":value", 0),
    ]
    Code:
    [
        (party_add_members, "p_main_party", "trp_manhunter", 1),
        (troop_remove_gold, "trp_player", 10),
    ]
    Both are complete code blocks, everything scriptish can be done in either, but the first one is executed before this option is shown. If it fails, either by a failing script or by an equation computed as false, the option will not be visible.
    This is the condition block, denoted by its position after the option's ID and before its label.
    Therefore, if you wish someone unable to take the option in question, you denote the conditions for that in this code block and not in the second. It accomplishes that the option never appear - unless it can be taken - and therefore saves you from dealing with any case where it would be taken despite not being valid to be.
    This also has the benefit that people would not see a lot of options and had to try and find those actually available to them.
    Only if you actually wanted them to choose an option they were not entitled to - write, to apply some form of chastisement - is there sense in not employing the condition block to check for the prerequisites which would entitle them.

    The second block then, as you have already found out, is the consequence block. It is executed when the option is chosen. Thence, it should not encompass anything that already ought to be done at the time of choosing. Not much else can be written about it...
  12. Zsar

    [KIT] partitioned Module System source files

    So there really is no manual...
    As far as I can see, pathes are included by explicit notion in build_module.bat.
    I therefore have to implement the same system I used here in Windows batch script instead of Python, build my PYTHONPATH on runtime, then edit the modules in question to include import-statements for all files found. As I cannot (at least: know not how to) append to a file anywhere but at the end, for that I have to rewrite every module file on runtime (which I would rather do in Python or even C - but then why not use the existing code that already is done).
    ... Really, that seems more trouble than it is worth. I do not mind to invent different wheels, but the same wheel multiple times!?

    - Feel free to correct me if I misjudge things. I really hope I do, in fact.
  13. Zsar

    Fireball problems

    Say... could I borrow you to solve a minor problem in my bachelor thesis?
    It involves discerning the position of a point relative to a plane on the basis of its normal vector in an n-dimensional space.
  14. Zsar

    Recruiting manhunters from villages?

    Why do you not use the condition block for your condition? Has it angered you?
    A properly telling name for an ID would be nice too, eh?
    Why check for "more than 10" denars, when "at least 10" do suffice?
    And no dots to terminate an imperative!
    Code:
      ("recruit_manhunter",[
        (store_troop_gold, ":money", "trp_player"),
        (ge, ":money", 10),
      ],"Recruit a manhunter",[
        (party_add_members, "p_main_party", "trp_manhunter", 1),
        (troop_remove_gold, "trp_player", 10),
      ]),
    Now, about that party limit:
    Code:
      ("recruit_manhunter",[
        (store_troop_gold, ":value", "trp_player"),
        (ge, ":value", 10),
        (party_get_free_companions_capacity, ":value", "p_main_party"),
        (gt, ":value", 0),
      ],"Recruit a manhunter",[
        (party_add_members, "p_main_party", "trp_manhunter", 1),
        (troop_remove_gold, "trp_player", 10),
      ]),
    A bit of initiative, I dare say, might be not unwise. Do read! Do infer! Do try!
    In short: "Do have the courage to employ your own wit!" - Immanuel Kant, "Beantwortung der Frage: Was ist Aufklärung?", 1784
    ... This citation shows: To research might be proficient as well.
  15. Zsar

    Fireball problems

    ... Mayhap... if you rotated both source and target in a way that the angle around the z-axis denoted the angle around the x-axis after reversing this rotation...

    I am horribly out of practice with angular calculations, but I have a feeling that this may be feasible. Rotating by Pi/2 around - global - x would turn the local z-axis parallel to the former y-axis, if I am not mistaken. Fetching an angle then, rotating back and applying this angle to the y-axis should be proper.
    Thereafter rinse and repeat with x and y swapped.

    ... I am reasonably sure I recall this or a similar practice from my computer graphics lecture.

    If all else fails, there are functions available to go the hard way:
    Code:
    store_sqrt = 2125  # (store_sqrt, <destination_fixed_point>, <value_fixed_point>), takes square root of the value
    store_pow  = 2126  # (store_pow, <destination_fixed_point>, <value_fixed_point>, <value_fixed_point), takes square root of the value
                       #  dest, op1, op2 :      dest = op1 ^ op2
    store_sin  = 2127  # (store_sin, <destination_fixed_point>, <value_fixed_point>), takes sine of the value that is in degrees
    store_cos  = 2128  # (store_cos, <destination_fixed_point>, <value_fixed_point>), takes cosine of the value that is in degrees
    store_tan  = 2129  # (store_tan, <destination_fixed_point>, <value_fixed_point>), takes tangent of the value that is in degrees
    Koozer said:
    what does set_fixed_point_multiplier actually do..?
    Outside of trigger intervals, the MS only handles integral numbers. Fixed point is a way to denote a real number with fixed precision by assigning to one position within the integral number the decimal point. Hence "fixed point".
    In practice, it works like this:

    One wished a real number with three decimal places. Therefore one took this integral number and multiplied it with 1000, memorising this as the neutrality factor F...
    To multiply two integral numbers A and B, one then calculated: A * B. No change.
    To divide integral numbers A through B, one calculated: (A * F) / B and gained the fixed point number C, whose first three positions were behind the decimal point.
    To multiply fixed point numbers A and B, one calculated (A * B) / F for a fixed point result and (A * B) / pow(F, 2) for an integral result.
    To divide fixed point numbers A and B, one treated them as integral numbers, (A * F) / B again, and might choose to apply correct rounding before dividing through F once more to return to integral numbers again.

    "set_fixed_point_multiplier" sets F for use in internal calculations. For your own calculations, employ "convert_to_fixed_point" and "convert_from_fixed_point" - those will grab the F set there, so you need not care about changing factors.
    Koozer said:
    This module system has given me a new-found appreciation for good code documentation.
    Hell, yes! One should make M&B-modding a mandatory lesson for Software Engineers.
Back
Top Bottom