Modding Q&A [For Quick Questions and Answers]

Users who are viewing this thread

Status
Not open for further replies.
Not that it's super-important, but process_line_correction.py doesn't account for #s that are inside of quoted strings. This can bork the indentation in module_scripts.

For instance, in script_get_relevant_comment_for_log_entry, about 28 lines into the script:

  ("get_relevant_comment_for_log_entry",
      ...
      (try_begin),
        (eq, "$cheat_mode", -1), #temporarily disabled
        (try_begin),
          (assign, reg5, ":log_entry_no"),
          (assign, reg6, ":entry_type"),
          (assign, reg8, ":entry_time"),
         
          (gt, "$players_kingdom", 0),
          (try_begin),
            (gt, ":troop_object_faction", 0),
            (assign, reg7, ":players_kingdom_relation"),
            (display_message, "@{!}Event #{reg5}, type {reg6}, time {reg8}: player's kingdom relation to troop object = {reg7}"), this line contains a # so process_line_correction ignores the rest of the line
            (else_try),
              (gt, ":center_object_faction", 0),
              (assign, reg7, ":players_kingdom_relation"),
              (display_message, "@{!}Event #{reg5}, type {reg6}, time {reg8}: player's kingdom relation to center object faction = {reg7}"), and here
              (else_try),
                (gt, ":faction_object", 0),
                (assign, reg7, ":players_kingdom_relation"),
                (display_message, "@{!}Event #{reg5}, type {reg6}, time {reg8}: player's kingdom relation to faction object = {reg7}"),and here
                (else_try),
                  (display_message, "@{!}Event #{reg5}, type {reg6}, time {reg8}. No relevant kingdom relation"),and here
                  (try_end),
                (else_try),
                  (display_message, "@{!}Event #{reg5}, type {reg6}, time {reg8}. Player unaffiliated"),and here
                  (try_end),
                (try_end),

Note the messed up indentation. Anyone have an easy way to account for/ignore #s inside of quoted strings?
 
CryptoCactus said:
Note the messed up indentation. Anyone have an easy way to account for/ignore #s inside of quoted strings?

The best solution is to fix your code (or Native code, or whatever mod you are using). If it has broken the rule on how to write the code,  fix it by just removing the # inside the string.

Or you can try to rewrite the entire algorithm in line_correction to accept new exceptions rules.

Which one is easier? It so happens the easy way is also the best way here


 
It's native code. And yes, that's what I did, just removed the pound signs from the relevant strings. Just thought fixing the actual process file might be a more robust way of doing it.
 
CryptoCactus said:
Just thought fixing the actual process file might be a more robust way of doing it.

That is the point. What is the broken part? The algorithm with simple rules, that results in a easy to read code (indentation), or the code in a few lines of module_scripts.py?

General rules:
1) # is used for comments. Can be used on start of line (its all a comment) or in the middle (first part is code, second part is comment)
2) Each new block increases indentation (example: (try_begin) and (try_for_range) )
3) End of a block reduces indentation (example: (try_end))
4) One line, one operation
5) Empty lines are ignored
6) Python functions should not be include on module_XXX.py files. Use header_XXX.py for that (example: def XXXX() )

Note how this rules could be applied to ALL the module_XXXX.py files. In fact, you should apply line_correction on all of them, not just scripts.

In VC you can see a example of improved line_correction that also is applied to several files (mission_templates, scripts, triggers, simple_triggers, etc).

On my mods I apply it to ALL my files (besides modules_XXX I have tons of plugins as I use WRECK). Indentation is part of my build process, it is applied in a universal and automatic way, which helps to keep my code clean, easier to read and also keeps my git history clean
 
I don't disagree - it's incredibly handy and I use it on all my module_* files as well. In general it seems like it would be a good idea to ignore quoted strings when processing lines (for any purpose, really), is all I'm saying.

Nonetheless, I cede the point.  :razz:
 
pzp2GJ.jpg

How I can give Buvran village to Rhodoks?
 
If Im not mistaken, this would fix the problem with the strings:
Code:
import sys
sys.dont_write_bytecode = True

import glob, os
os.chdir("./")
for fileName in glob.glob("module_*.py"):
	file = open(fileName,"r")
	lines = file.readlines()
	file.close()

	file = open(fileName,"w")

	level = 0
	for line in lines:
		line = line.strip()
		isString = 0
		acceptableindex = -1
		for i in xrange(len(line)):
			if(line[i]=='\"' or line[i]=='\''):
				isString = (isString+1)%2
			if(line[i]=='#' and isString == 0):
				acceptableindex = i
				break
		#acceptableindex = line.find("#")
		if (acceptableindex == -1):
			acceptableindex = len(line)
		level -= line.count("try_end", 0, acceptableindex)
		level -= line.count("end_try", 0, acceptableindex)
		level -= line.count("else_try", 0, acceptableindex)
		newlevel = level
		level_positive_change = 0
		newlevel += line.count("else_try", 0, acceptableindex)
		newlevel += line.count("(", 0, acceptableindex)
		newlevel += line.count("[", 0, acceptableindex)
		newlevel += line.count("try_begin", 0, acceptableindex)
		newlevel += line.count("try_for", 0, acceptableindex)
		level_positive_change = newlevel - level
		newlevel -= line.count(")", 0, acceptableindex)
		newlevel -= line.count("]", 0, acceptableindex)
		if (level_positive_change == 0):
			level = newlevel
		for i in xrange(level):
			file.write("	")
		level = newlevel
		file.write("%s\n"%line)
	file.close()
as Im a total noob with python, there are probably a lot of better ways to do this, but to me it seems reasonable

this wont work for multiline strings such as the credits strings in module_strings, but it should work for pretty much everything else


also, what do you guys use to make it run for all files??
just edited the code to work for all the module_*.py files in the directory
 
Ikaguia said:
If Im not mistaken, this would fix the problem with the strings:
Code:
import sys
sys.dont_write_bytecode = True

import glob, os
os.chdir("./")
for fileName in glob.glob("module_*.py"):
	file = open(fileName,"r")
	lines = file.readlines()
	file.close()

	file = open(fileName,"w")

	level = 0
	for line in lines:
		line = line.strip()
		isString = 0
		acceptableindex = -1
		for i in xrange(len(line)):
			if(line[i]=='\"' or line[i]=='\''):
				isString = (isString+1)%2
			if(line[i]=='#' and isString == 0):
				acceptableindex = i
				break
		#acceptableindex = line.find("#")
		if (acceptableindex == -1):
			acceptableindex = len(line)
		level -= line.count("try_end", 0, acceptableindex)
		level -= line.count("end_try", 0, acceptableindex)
		level -= line.count("else_try", 0, acceptableindex)
		newlevel = level
		level_positive_change = 0
		newlevel += line.count("else_try", 0, acceptableindex)
		newlevel += line.count("(", 0, acceptableindex)
		newlevel += line.count("[", 0, acceptableindex)
		newlevel += line.count("try_begin", 0, acceptableindex)
		newlevel += line.count("try_for", 0, acceptableindex)
		level_positive_change = newlevel - level
		newlevel -= line.count(")", 0, acceptableindex)
		newlevel -= line.count("]", 0, acceptableindex)
		if (level_positive_change == 0):
			level = newlevel
		for i in xrange(level):
			file.write("	")
		level = newlevel
		file.write("%s\n"%line)
	file.close()
as Im a total noob with python, there are probably a lot of better ways to do this, but to me it seems reasonable

this wont work for multiline strings such as the credits strings in module_strings, but it should work for pretty much everything else


also, what do you guys use to make it run for all files??
just edited the code to work for all the module_*.py files in the directory

Excellent! I've added another bit to check for the (simple) python bits in module_troops, as well. It won't work if you have defs within defs or anything complex like that, but for any simple python code that starts with a def and ends with a return, it should work fine. Also a nice little "processing..." output to the console, because I like being able to see it do things.

Code:
import sys
sys.dont_write_bytecode = True

def correct_lines (fileName):
  file = open(fileName,"r")
  lines = file.readlines()
  file.close()

  file = open(fileName,"w")
  print "Processing " + fileName + "..."
  level = 0
  returnFound = 0
  for line in lines:
    line = line.strip()
    isString = 0
    acceptableindex = -1
    for i in xrange(len(line)):
      if(line[i]=='\"' or line[i]=='\''):
        isString = (isString+1)%2
      if(line[i]=='#' and isString == 0):
        acceptableindex = i
        break
    #acceptableindex = line.find("#")
    if (acceptableindex == -1):
      acceptableindex = len(line)
    if line.startswith("return "):
      returnFound = 1
    level -= line.count("try_end", 0, acceptableindex)
    level -= line.count("end_try", 0, acceptableindex)
    level -= line.count("else_try", 0, acceptableindex)
    newlevel = level
    level_positive_change = 0
    newlevel += line.count("else_try", 0, acceptableindex)
    newlevel += line.count("(", 0, acceptableindex)
    newlevel += line.count("[", 0, acceptableindex)
    newlevel += line.count("try_begin", 0, acceptableindex)
    newlevel += line.count("try_for", 0, acceptableindex)
    newlevel += line.startswith("def ")
    level_positive_change = newlevel - level
    newlevel -= line.count(")", 0, acceptableindex)
    newlevel -= line.count("]", 0, acceptableindex)
    if (level_positive_change == 0):
      level = newlevel
    for i in xrange(level):
      file.write("  ")
    level = newlevel
    if (returnFound == 1):
      level -= 1
    returnFound = 0
    file.write("%s\n"%line)
  file.close()

import glob
for modfile in glob.glob('module_*.py'):
  correct_lines(modfile)

raw_input("Press Enter to continue...")
 
Is there a working way to do armor, horse, and weapon race restriction. So my minotaurs cannot wear helmets that don't fit or ride horses.
 
Leikeze said:
Is there a working way to do armor, horse, and weapon race restriction.

sure, but you need to include more details:

1) are you using skins (module_skins) for each race?
2) are any of them playable (so you would need to limit inventory usage of items too)
3) are any of them companions? Or npcs you can give gear in your game (like a vassal lord)

In short: why do you need this limitation in the first place? How is the game trying to give items your characters should not use?

With that you can elaborate a solution (or a few): limit inventory, limit looting, limit agent usage of items in a battle, and so on
 
Using 1, 2, and 3. I want to stop the player from grabbing an armor from anywhere(market, looting, or inventory) that does not fit him and putting it on. But he should still be aloud to carry the item in his inventory so he can put it on companions or sell it.

Note: my mod will contain over 5 races.
 
Got a question for all of you wizards.
So, what's the equivalent of a Python list or a C array in the Warband MS?

What I'm trying to do is make a presentation box on the right of the troop selection screen which would display some basic stats from the troop tuple. For that I need some form of 'calling' the indexes of each field(strength, HP, skills).
 
Sherlock Holmes said:
So, what's the equivalent of a Python list or a C array in the Warband MS?

you can use a troop/party slots as a array. There are some "ready to use" OSP scripts for that, I like Common Warband Array Processing
https://forums.taleworlds.com/index.php/topic,335511.0.html

I even converted his scripts to WRECK extension and included on my Sublime API, so I can do stuff like this:

Code:
		(try_begin),
			(_test_setup, "print array: npcs names"),

			(array_init_range, active_npcs_begin, active_npcs_end),
			(str_clear, s1),(str_clear, s2),
			(array_print, "script_lord_name_to_s0", s1, s2, array_1),
			(display_message, "@{s3}"),	

			(array_print, "script_lord_name_to_s0", "@  |  ", "@  |  "),
			(display_message, "@{s3}"),

			(_test_end),
		(try_end),

		(try_begin),
		    (_test_setup, "filter test: more than 6, list: 1 to 10"),
		    (array_init_range, 1, 11),
		    (assign, reg1, 6),
		    (array_filter, "script_cf_filter_more_than_reg1"),
		    (array_length),
		    (_test_equals, reg0, 4, "len"),
		    (array_get, 1),
		    (_test_equals, reg0, 7, "filtered list (>6)"),
		    (_test_end),
		(try_end),

(ignore the test_XXX stuff, its my regression testing code)
 
Leikeze said:
Using 1, 2, and 3. I want to stop the player from grabbing an armor from anywhere(market, looting, or inventory) that does not fit him and putting it on. But he should still be aloud to carry the item in his inventory so he can put it on companions or sell it.

Note: my mod will contain over 5 races.

I read you can use ti_on_item_init but that it is a really slow way  to do it.
 
HarryPham123 said:
i have this error it said incorect skeleton type when i enter horse battle .

Code:
# All of the animations are hardcoded. You can edit the individual sequences, resources or times. But each
# animation must stay at the same position, otherwise the game won't run properly. If you want to add a new animation,
# you can change both the ids and values of the animations which are named as unused_human_anim_???
# and unused_horse_anim_??? (??? = any number). You must not change used animations' ids.

1) make sure you are adding whatever animation at the correct ID.
2) make sure you are using a valid animation resource
3) open ID_animations.py and find which one is the 553. It should be "anim_horse_stand = 553"

Re-read the start of module_animations.py, as it explains how this stuff works.
 
This is more of a python question rather than a module system related one, although it is still somewhat connected to the game.

So, I want to make a variable that changes value each time a certain function is called.
Anyone knows how can I achieve that?
 
Status
Not open for further replies.
Back
Top Bottom