Getting all strings in strings.dat?

Started by llamazing, September 04, 2016, 06:22:04 PM

Previous topic - Next topic
It there a good way to either get all key/value entries in strings.dat for a given language or just the ones with keys beginning with a certain pattern?

Or do I have to parse strings.dat in my own script to extract the info myself?

I was trying to manually keep a list of strings.dat keys I'm interested in, but there's too many and it's becoming too much of a hassle.

I think there is not a direct/clean way to get the keys/values, so yes, you would need to do that with some script that looks for them in the strings.dat file.

By the way, why do you need to get these values?
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

I'm working on implementing an interactive dialog system for talking to NPCs where the player types single word responses (in their native language), which in turn trigger additional dialog with that NPC. So basically, given a value from an entry in strings.dat (text the player types in), I need to find the associated strings.dat key for that value. And I know that the strings.dat key begins with "topic.(NPC_name)." -- I just need to find out what the last part of the key is.

Then I have a script to associate the strings.dat key with a dialogs.dat id. It's actually a bit more complicated than that since one strings.dat key can be linked with multiple dialogs.dat ids, and depending on the current state of the game, the script chooses which one of those dialogs it's going to display.

But since I've been working on the problem some more, I think I've come up with a better solution by doing things in the reverse order that I was originally envisioning, and doing things that way doesn't require parsing the strings.dat file.

In case you aren't following all that, here is an example:
Quote> hello

"Hello, my name is Greg. I'd stay and chat, but I'm busy looking for my hat."

> hat

"My hat was a gift from my wife. I lost it when a gust of wind blew it off my head
as I was exiting the church. I know it is around here somewhere..."

> wife

"My wife Sally runs the inn where you can get a bed to rest for the night."

> inn

"The inn is located at the northwest corner of the town, just past the blacksmith."

The english strings.dat file would contain:
text{ key = "topic.Greg.hello", value = "hello" }
text{ key = "topic.Greg.hat", value = "hat" }
text{ key = "topic.Greg.wife", value = "wife" }
text{ key = "topic.Greg.inn", value = "inn" }


The english dialogs.dat file would contain:
dialog{ id="Greg.greeting", text = "\nHello, my name is Greg. I'd stay and chat, but I'm busy looking for my @hat.\n"}
dialog{ id="Greg.hat_lost", text = "\nMy hat was a gift from my @wife. I lost it when a gust of wind blew it off my head\nas I was exiting the @church. I know it is around here somewhere...\n"}
dialog{ id="Greg.hat_found", text = "\nThank you for finding my hat!\n"}
dialog{ id="Greg.wife", text = "\nMy wife Sally runs the @inn where you can get a bed to rest for the night.\n"}
dialog{ id="Greg.inn_directions", text = "\nThe inn is located at the northwest corner of the town, just past the blacksmith.\n"}


A custom script would then link the string key "topic.Greg.hello" with the dialog id "Greg.greeting"

Cool idea! Why do you even need the custom script though? Couldn't the strings.dat key just match the dialogs.dat id exactly?

My understanding is that both of these files are valid lua, so you should be able to use sol.main.load_file() or require() to load the entire file into a table and parse the table. I don't know the specifics enough to help you with that though, sorry.

One day there will be a function to just get all elements from strings.dat and dialogs.dat. In the meantime, parsing the files is indeed the good approach. As suggested by wrightmat, you can parse the files with Lua itself because the syntax is valid Lua. This can be done with sol.main.load_file() and setfenv().
require() is to include code of another script in your script, here you just want to parse a file, this is more lowlevel. This is actually one of the rare examples where sol.main.load_file() should be used rather than require() ;)

Quote from: wrightmat on September 05, 2016, 05:10:05 PM
Cool idea! Why do you even need the custom script though? Couldn't the strings.dat key just match the dialogs.dat id exactly?

The explanation I gave is the simplified version, and the workings of my conversation manager script to link the strings with the dialogs are fairly complex. The reason they cannot match one-to-one is because one strings.dat key can be linked with multiple dialogs and the conversation manager script decides which dialog to use based on saved game values, the current map, etc.

If you look closely at the dialogs.dat example I gave, you'll see that I defined "Greg.hat_lost" and "Greg.hat_found". So Greg's response to the keyword "hat" initially is the "oh no, I lost my hat" dialog, but if the player finds and returns his hat, then his response becomes the "thanks for finding my hat" dialog.

Another example is if there ends up being multiple dialogs that have all their conditions met, then the conversation manager picks one of them at random. Just a way of mixing things up a little.

Quote from: Christopho on September 05, 2016, 05:31:03 PM
As suggested by wrightmat, you can parse the files with Lua itself because the syntax is valid Lua. This can be done with sol.main.load_file() and setfenv().

I tried it and it was easier than I thought to parse. Thanks!

Okay, so, require() is faster then load_file if I understand ?

loadfile("my_script.lua") or sol.main.load_file("my_script.lua") opens a Lua file, parses it and returns its code as a function value.
-> Very basic and low level. Quite slow since it involves loading a file. You almost never need it.

require("my_module") returns a module, which is usually a table. The first time require() is called with a module name, attempts to find the module in various paths (system paths, current directory, Solarus quest directory...) as a Lua file (.lua or .luac) or as a C shared library (.dll or .so). Loads it, executes its, remembers its return value for next times and finally returns that value. The next times it is called with the same module name, does nothing and directly returns the return value that was memorized the first time.
-> This is the common way to include scripts from other scripts. Very fast except the first time. You need it every day.