Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - llamazing

#166
Development / Re: About color text dialogs
April 14, 2017, 07:51:56 AM
My suggestion for syntax is to keep it simple and just use a dollar sign followed by a single letter to specify the command name, e.g. $c{red} for red text. For changing fonts it could be $f{courier} and $s{12} for font size.

I like the idea for having additional options too, such as specifying a color code, e.g. $c{255,0,170}. It might be easier to parse if a hex color code were used, like $c{ff00aa} because then there would always be exactly 6 characters and the commas would not be necessary.

I'd even go a step farther and allow for a third option where up to 9 preset values can be used, as hard-coded somewhere in the script, e.g. $c1 thru $c9. $c0 could be used as shorthand for $c{default}. This has the advantage of being very few characters.

I'd recommend against using the \ character in the syntax. It would make the parsing more difficult for separating out special characters like \n or \t. I also don't see any reason to include a second closing dollar sign. Adds one more character everywhere and potentially confusing for translators.
#167
Development / Re: About color text dialogs
April 14, 2017, 01:04:11 AM
Quote from: Diarandor on April 13, 2017, 06:32:45 PM
@llamazing: You said that you made a script that allows to change colors for any type of font (even non-monospaced fonts) and also working with special characters (multi-byte characters, like accents, Japanese characters, etc). Would it be possible for you to share it here? It may help others, including me, to improve our dialog box scripts.

This script parses the text of dialogs.dat and processes player inputs:
https://github.com/llamaizing/cythera-tech-demo/blob/master/data/scripts/menus/dialogs/conversation_dialog.lua

> Note: dialog_box.text_areas contains the text from dialogs.dat

I wrote a library of UI elements, and this one is for multi-line text, used by the script above for the dialog box. This script handles the drawing to the screen, including making the "hyperlink" text a different color:
https://github.com/llamaizing/cythera-tech-demo/blob/master/data/scripts/lib/uix/controls/multiline.lua

> See lines 151-166 for keeping track of the position(s) of the hyperlink text to be colored differently
> See the ml:refresh() function for drawing of the text (especially lines 301-321)

I provided some details about the syntax I use for the dialogs here (I'm not suggesting syntax to use for this topic, just to be able to make sense of my scripts):
http://forum.solarus-games.org/index.php/topic,873.msg4864.html#msg4864




FYI-- don't be confused by the way I named my scripts. I used 3 types of dialogs in my project:

  • scrips/menus/dialogs/conversation_dialog.lua - to display a text box for when talking with an NPC (this is the one relevant for this topic)
  • scrips/menus/dialogs/question_dialog.lua - for displaying system level pop-up dialogs with buttons (e.g. "Do you want to save?")
  • scrips/menus/dialogs/sleep_dialog.lua - to display a dialog to select how long to sleep when using a bed.

/scripts/dialog_manager.lua - manages the 3 types of dialogs above and processes keyboard/mouse inputs from the player. Ignore this one, it's not relevant to this topic.
/scripts/conversation_manager.lua - maps out the conversation, deciding which text to display next. It has nothing to do with drawing the dialog box and can be ignored for the purposes of this topic.
#168
Your projects / Re: Zelda: Book of Mudora
April 12, 2017, 02:19:33 PM
In my Cythera project I was able to colorize words that the player can click on to advance the dialog with no problems, and I was using a ttf font that was not monospaced. My dialog script is pretty complicated, but it probably wouldn't be too hard to extract just the part where I colorized the text.

My method was to write all the text to text surfaces, one text surface per line of text. I kept track of the starting and ending position of each word to colorize using text_surface:get_text(), querying it as I added each word to the text_surface. Then I had one regular surface to draw the text on, and moving left to right for each text_surface I redrew the text_surface onto the surface up until the point where the color changed, then changed the color of the text_surface and redrew the next text onto the main surface until the next color change, etc.
#169
Development / Re: How do I make a circle movement?
April 03, 2017, 03:00:57 PM
I don't think that script is going to do what you want it to do.

Code (lua) Select
circle:set_center(chest1,248,357)

You are setting the center point of the circle 248 pixels horizontally and 357 pixels vertically away from the chest (i.e. 434 pixels away from the chest in total).

With a radius of 360 pixels, your NPC will not be circling the chest. My guess is the reason the script is not working is because the path you've given the NPC takes it beyond the borders of the map? Hard to say without actually seeing your map.

Have you tried just this?
Code (lua) Select
circle:set_center(chest1)
#170
You can use a custom sort function to arrange things however you want. The following example assumes that the date is some number that increases over time.

Code (lua) Select
local function sort_by_date(a, b)
return a.date > b.date --descending order
--return a.date < b.date --ascending order
end

local example_data = {
{ date = 56, name = "second" },
{ date = 99, name = "first" },
{ date = 21, name = "third" },
}

print"Original Order:"
for i,data in ipairs(example_data) do
print(string.format("%i - date: %f, name: %s", i, data.date or 0, data.name))
end

table.sort(example_data, sort_by_date)

print"\nSorted by Date:"
for i,data in ipairs(example_data) do
print(string.format("%i - date: %f, name: %s", i, data.date or 0, data.name))
end
#171
Am I correct in assuming that the only reason you are "loading" the savegame files is to get access to the state of the savegame variables?

If so, perhaps what is needed is some sort of quick load feature that only gives read access to savegame variables but doesn't do any of the other loading of resources needed to actually start the game and therefor would be faster for checking multiple files.
#172
I don't know if this is related to the problems you are having, but on quick inspection of your code, I see two problems.

Lines 71 - 97
Code (lua) Select
local function create_drop_splash(map, x, y) --line 71
  --skip
  local drop_properties = {direction = 0, x = 0, y = 0, layer = max_layer,
    width = 16, height = 16, sprite = drop_sprite_id}
  -- Initialize parameters.
  local x = x or cx + cw * math.random() --these x & y are not used anywhere
  local y = y or cy + ch * math.random()
  local layer = max_layer
  --skip
  local ground = map:get_ground(x, y, layer) --these x & y override the previously defined locals
  if ground ~= "hole" and ground ~= "lava" then
    drop_properties.x = x --these x & y are defined by map:get_ground(x,y,layer)
    drop_properties.y = y
    drop_properties.layer = layer
    --skip
  end


EDIT: Disregard second problem
#173
I've updated the 3rd post to describe the implementation of the major features and provide insight to how some of the scripts work.
#174
Script features and how to use them

Interactive Dialogs

The interactive dialogs are the primary feature of this quest. The dialog window has 4 sections arranged vertically. The top one is for the NPC the player is talking to. The second one is for an additional NPC who can be involved in the discussion (like in Majora's Mask, where Link could be having a conversation with Anju in the Stock Pot Inn and in walks the postman, who interjects himself into the conversation -- my quest does not make use of this feature). The third section is for dialog from the player. This usually involves one-word responses that the player types in to continue the conversation, but it can also include pre-written paragraphs of text. The fourth and bottom section is for narrative text that can describe the setting or actions that characters take during the conversation.

dialogs.dat contains the dialog text content for ease of translation. Each section of the dialog window can contain up to 4 lines of text (except for the bottom section, which can only have up to 2 lines). Which section of the dialog the text gets added to is designated by using the $1 through $4 characters at the beginning of a paragraph, where omitting the special characters is the same as $1 and beginning a paragraph with # is the same as $4. If the paragraph has more text than will fit, it gets continued once the player clicks with the mouse or presses a key. Empty lines are used for paragraph breaks.

$s and $v are used for placeholder text that can change dynamically. $s is for strings (usually from strings.dat) that would need to be translated if a different language were used. $v is for number values, and thus don't require translation.

topic_rules.lua is what maps out the different dialog entries into a coherent conversation. Every NPC with spoken dialog has an entry in topic_rules.lua, along with a list that links words submitted by the player with the dialogs.dat entry to display in response. Note that the words listed in topic_rules.lua are not the exact text the player types into the dialog, but are a key to lookup the text from strings.dat so that it can be translated to the player's native language. There are also special entries for GREETING, which corresponds to the dialog to start the conversation off when the player first interacts with an NPC, as well as the special entry UNKNOWN for when the player enters text for which the NPC does not have a set response.

The script offers quite a bit of flexibility in setting up various conditions for determining which dialog to show. The dice game that can be played with the bartender at the inn is a good example of what can be achieved with the use of custom functions. Note that the dice game comes directly from Cythera, as does nearly all of the NPC dialog used in the quest.

Finally, the player can preserve a record of what is said by NPCs in the journal sidebar window for review at a later time. The journal text gets saved to a separate text file in the same directory as the save game data. I did not include a mechanism to remove journal entries (which didn't seem necessary given how short the quest is). The game_manager.lua script manages the loading and saving of the journal records.

Passage of time/NPC Movements/Night and Day cycle

The flow of time is essential for both NPC movements and the night overlay which darkens the screen at night. game_clock.lua manages the flow of time, which works by modifying the map metatable so that whenever a map gets loaded, the game clock is started (and updates every in-game minute) using a looping timer. Whenever a map is finished, the game clock is stopped with the current time saved in memory for when the next map is loaded, resuming the clock again.

The rate of time is set for 12 minutes real-time per in-game day, or 0.5 seconds real-time per in-game minute. I probably would have made an in-game day take twice as long for a real quest, but I didn't want the player to have to sit around too long for the purposes of this demo quest.

NPCs have a movement speed of 8 pixels per in-game minute, which works out to 1 tile (16 pixels) every second. NPC movements are scripted using path movements, which works out nicely since each in-game minute corresponds to one entry (step) in the path table associated with the path movement.

NPC movements are defined in the events directory, where each NPC has a file in that directory. The file lists a schedule for the NPC throughout the day, where at any given time the NPC is either stationary at some location, or moving from one location to another. The file also defines where on the map each of these locations can be found, as well as the path movements needed to get from one location to another.

One of the interesting things about the script is that an NPC can move from one map to another. Theoretically the NPC could even exist on multiple maps at the same time, but for this quest I hide the NPC at all other maps while present on a given map so that the NPC is only ever on one map at a given time.

game_events.lua manages NPC movements. The way that the implementation works is that whenever a map is loaded, the locations of all NPCs have to be adjusted in accordance with the current time. For the case where an NPC is standing stationary at some location, this is easy. Otherwise the script has to calculate where in the middle of a path movement the NPC should be, move the NPC to the corresponding map location, and then assign a path movement for the remainder of the movement. Finally, every in-game minute the schedule for an NPC is checked to see if a new path movement should be started for the NPC.

With the current implementation, NPCs follow the exact same schedule every day (which was all that was necessary for the purposes of this quest). Eventually I would like the expand on this script allowing for schedules that change based on what day of the week it is, as well as allowing for randomized special events that can alter an NPC's schedule.

Another feature borrowed from Cythera is that the player can sleep in a bed to skip ahead in time quickly. The sleep dialog that pops up when the player interacts with a bed comes straight from Cythera, as does the feature that NPCs will kick the player out of their bed during the night.

night_overlay.lua is what darkens the screen at night. This works by creating one overlay to darken the screen using the multiply blend mode and another overlay for light sources using the add blend mode. The color to use for the darkening overlay (which corresponds to the ambient light level or how much to darken the screen), is defined in night_overlay.dat at hour increments during the twilight hours. Then every in-game minute the ambient light level is updated, smoothly transitioning between the defined colors.

The number of light sources present on a map also affects the ambient light level. This can be seen on the first floor of the inn. It will start to get darker at the start of the evening, then eventually the 3 braziers turn on, at which point there is a sudden increase in the ambient light level, which then continues to get darker and darker as the night progresses.

Also note that the sequence of colors used for the night overlay varies depending on the map, as defined by the custom map.lighting variable with possible values of "outside", "inside", "dim", and "dark". Outside maps have a slightly blueish hue on account of the moonlight, whereas inside maps use pure shades of grey for the transition to night. Dim and Dark would be used for a dungeon or underground cavern where the ambient is always dark and does not change from day to night (these are not used in my quest).

Similarly, it is possible have different music playing between day and night where the custom variables map.music.day and map.music.night call out the music file to use respectively. Note that in order to get this feature to work, I set the music to be played from the quest editor as <Same as before>. This ensures that the music won't get restarted when changing maps, flowing seamlessly.

UI Elements

I created a library of scripts solely for the purpose of creating UI elements (clickable buttons, text fields, scrollbars, frame images, etc.). They can be found in the scripts/lib/uix directory. The name UIX is short for UI Express, which is what I was calling the master script to load the individual scripts for each UI subelement. Originally I was using require to load all of the UI subelement scripts needed in a given script. So if I had a script that created a window with buttons, it would require both buttons.lua and frame.lua, for example. This became quite cumbersome as I not only had to keep track of which UI subelements were used in a given script, but also the list of require statements would grow to be quite long. So instead, any script that uses any UI subelements now simply requires the ui_express.lua script, which in turn requires all of the UI subelement scripts.

The UI subelement scripts currently make use of images from Cythera in order to replicate the look of Cythera's dialogs and menus. I intend to someday release the UIX library separately using public domain images instead, making it more suitable for use in other quests.
#175
reserved
#176
I'm not expecting anyone to have heard of the game Cythera, which is a mac exclusive tile from the late 90s. It had an interesting dialog system where certain words said by NPCs would be highlighted, and the player could ask about them go into more depth on that topic. I've discussed this type of dialog system previously in this topic.

I've put together a quick little sample quest that tries to replicate the dialog system used by Cythera. It replicates the dialog text of three characters from the game (one of which is fairly complicated and a good testbed to push my dialog script to its limits).

When talking to NPCs, pretty much all of them respond to the key words "name", "job" and "bye" (to close the dialog). Beyond that, certain key words are highlighted in blue denoting that the player can take the conversation further by asking about those topics. The player can either type the keyword into a text box or select them from a running list by using the mouse.

A little quirk to be aware of is that only the first 5 letters of whatever the player types in are considered (it can be less than 5 letters too, depending on the word). This makes it easy for "fish", "fishing" or "fisherman" to all give the same response. Note that while Cythera only ever considered the first 4 letters entered, I decided to bump the limit up to 5 for a little more versatility. I don't think that it would ever be necessary to use more than 5 letters, though.

See if you can figure out how to complete this short little quest. I will say that there are two possible solutions. No items are required, and there are not any enemies.

Installation instructions:
The Solarus ALTTP resource pack is required for this quest. Confirmed to work with version 1.5.6, which can be found here. Download and extract the ALTTP resource pack. Then download my quest and extract it to the the same directory as the resource pack. For any duplicate files between the two, the ones from my quest should overwrite the ones from the resource pack.

Feel free to borrow and or modify the scripts for your own usage. Note that most of the images and sounds included in the quest actually come from Cythera and should not be used. If I end up going further with this project, it will ultimately not use any Cythera assets or text.

This demo quest has the following features:
  • Interactive dialog system
    • NPC portraits
    • clickable hyperlink text
    • text input
    • dynamic dialog content that depends on a multitude of factors
  • Preserve a log of NPC dialog for later reference
  • Objective tracking
  • Day/night cycle that darkens the map at night
    • lluminating light sources at night
    • Different music between night & day
    • NPC movements synchronized with the time
    • sleep in a bed to advance time
  • Read-only console that prints notifications for the player
  • Various UI elements with mouse/keyboard interaction

The quest can be downloaded from its github project page
#177
Development / Re: Pickable Item with No Shadow
December 26, 2016, 09:31:20 PM
Interesting. Thanks for the info, Christopho!
#178
Development / Re: Pickable Item with No Shadow
December 26, 2016, 08:32:13 PM
Quote from: Christopho on December 26, 2016, 07:57:36 PM
nil is a value of the special type "nil", but no value is just no value passed to the function call. Some functions use as a convention that these are equivalent, some other don't.

Is it a true statement that what you said only applies to functions written in C++?

When working purely in lua, there is no way to distinguish between "a value of special type nil" and "no value", correct?
#179
Development / Re: Pickable Item with No Shadow
December 26, 2016, 07:40:10 PM
Does anyone have an explanation for why item:set_shadow(nil) has a different behavior than item:set_shadow()? My understanding was that the two would be equivalent. Is it because the set_shadow function is written in C++?
#180
Development / Re: Pickable Item with No Shadow
December 25, 2016, 03:12:09 AM
Interesting, item:set_shadow(nil) does work, but item:set_shadow() does not. I thought those two expressions were equivalent.