Hi.
So earlier I was imaginating a mail system and how it should work. It works properly (https://github.com/MetalES/Project-Zelda/issues/4), but I am in need of help.
The mail's text content is stored in another file (see bellow), this is to ensure that translators will not be lost and also to keep string.dat clean (Only mail names are part of string.dat)
Everything works fine, except that I need to ignore a chunk of line in order to display the right page.
This is how a mail file looks like (of course, this is a test)
$ = Tell the engine to go to another line
- [/0] = Tell the engine that this page start and ends there (Is there a way to do it like so ?)
[reward]heart_piece
[0]
Line0$
Line1$
Line2$
Line3$
Line4$
Line5$
Line6$
[/0]
[1]
Line0$
Line1$
Line2$
Line3$
Line4$
Line5$
Line6$
[/1]
[2]
Line0$
Line1$
Line2$
Line3$
Line4$
Line5$
Line6$
[/2]
This is the code
local submenu = require("scripts/menus/pause_submenu")
local mail_submenu = submenu:new()
function mail_submenu:on_started()
submenu.on_started(self)
self.game:set_custom_command_effect("attack", "return")
self.game:set_custom_command_effect("action", "open")
self.cursor_sprite = sol.sprite.create("menus/pause_cursor")
self.cursor_sprite:set_animation("letter")
self.displaying_mail = false
local font, font_size = sol.language.get_menu_font()
local width, height = sol.video.get_quest_size()
self.mail_name_surface = sol.surface.create(320,800)
-- Todo, this is a test, rezise this to fit the page bitmap
self.text_display_surface = sol.surface.create(320, 240)
self.mail_highest_visible = 1
self.mail_visible_y = 0
self.mail_names = {}
-- This handle the whole mail page
self.mail_content = sol.text_surface.create{
horizontal_alignment = "left",
vertical_alignment = "top",
font = "lttp",
font_size = 14,
text = text_lines,
}
--Todo
self.page_number = sol.text_surface.create({
horizontal_alignment = "left",
vertical_alignment = "top",
font = "lttp",
font_size = 14,
text = "0 /" .. self.game:get_value("total_mail") / 5,
})
--
for i = 1, 100 do
if self.game:get_value("mail_" .. i .. "_obtained") then
self.mail_names[i] = sol.text_surface.create{
horizontal_alignment = "left",
vertical_alignment = "top",
font = "lttp",
font_size = 14,
text_key = "quest_status_mail.mail." .. self.game:get_value("mail_" .. i .. "_name"),
}
end
end
self.up_arrow_sprite = sol.sprite.create("menus/arrow")
self.up_arrow_sprite:set_direction(1)
self.up_arrow_sprite:set_xy(58, 48)
self.down_arrow_sprite = sol.sprite.create("menus/arrow")
self.down_arrow_sprite:set_direction(3)
self.down_arrow_sprite:set_xy(58,212)
self.cursor_position = nil
self:set_cursor_position(1)
self:load_extra()
end
function mail_submenu:load_extra()
self.mail_name_surface:clear()
local misc_img = sol.surface.create("menus/quest_status_mail_system.png")
-- misc_img:draw_region(0, 37, 182, 172, self.mail_surface, 129, 55)
for i = 1, 100 do
local y = 7 + (i - 1) * 32
local x = 18
if self.game:get_value("mail_" .. i .. "_obtained") then
misc_img:draw_region(0, 22, 310, 32, self.mail_name_surface, 5, 0 + (33 * (i - 1)) - (i - 1))
self.mail_names[i]:draw(self.mail_name_surface, 47, y + 2)
if self.game:get_value("mail_" .. i .. "_opened") then
misc_img:draw_region(0, 0, 27, 19, self.mail_name_surface, x, y - 1)
elseif self.game:get_value("mail_" .. i .. "_highlighted") then
misc_img:draw_region(26, 1, 27, 18, self.mail_name_surface, x, y)
else
misc_img:draw_region(52, 1, 27, 18, self.mail_name_surface, x, y)
end
end
end
end
function mail_submenu:set_cursor_position(position)
if position ~= self.cursor_position then
local width, height = sol.video.get_quest_size()
self.cursor_position = position
while position <= self.mail_highest_visible do
self.mail_highest_visible = self.mail_highest_visible - 1
self.mail_visible_y = self.mail_visible_y - 32
end
while position > self.mail_highest_visible + 5 do
self.mail_highest_visible = self.mail_highest_visible + 1
self.mail_visible_y = self.mail_visible_y + 32
end
self.cursor_sprite.x = 10
self.cursor_sprite.y = 40 + 32 * (position - self.mail_highest_visible)
end
end
function mail_submenu:on_draw(dst_surface)
-- Text.
self.mail_name_surface:draw_region(0, self.mail_visible_y + 32, 320, 160, dst_surface, 0, 53) -- (0, self.mail_visible_y + 27, 320, 169, dst_surface, 17, 49
-- Arrows.
if self.game:get_value("total_mail") > 5 then
if self.mail_visible_y > 0 then
self.up_arrow_sprite:draw(dst_surface)
end
if self.mail_visible_y < 60 then
self.down_arrow_sprite:draw(dst_surface)
end
end
self.text_display_surface:draw(dst_surface, 0, 0)
-- Cursor.
self.cursor_sprite:draw(dst_surface, self.cursor_sprite.x, self.cursor_sprite.y)
self:draw_save_dialog_if_any(dst_surface)
end
function mail_submenu:on_command_pressed(command)
local handled = submenu.on_command_pressed(self, command)
if not handled then
if command == "left" then -- maybe use this for page ?
handled = true
elseif command == "right" then
handled = true
elseif command == "up" then
if self.game:get_value("unread_mail_amount") > 1 then
sol.audio.play_sound("menu/cursor")
if self.cursor_position == 1 then
self:set_cursor_position(self.game:get_value("unread_mail_amount"))
else
self:set_cursor_position(self.cursor_position - 1)
end
end
handled = true
elseif command == "down" then
if self.game:get_value("unread_mail_amount") > 1 then
sol.audio.play_sound("menu/cursor")
if self.cursor_position >= self.game:get_value("unread_mail_amount") then
self:set_cursor_position(1)
else
self:set_cursor_position(self.cursor_position + 1)
end
end
handled = true
elseif command == "pause" then
submenu.avoid_can_save_from_qsmenu = false
self.display_mail = false
sol.menu.stop(self)
elseif command == "action" then
--todo
if self.is_reading then
self:display_mail(nil)
self.is_reading = false
else
self:display_mail(self.cursor_position)
self.is_reading = true
if not self.game:get_value("mail_" .. self.cursor_position .. "_opened") then
self.game:set_value("mail_" .. self.cursor_position .. "_opened", true)
end
end
sol.audio.play_sound("danger")
handled = true
elseif command == "attack" then
if not self.displaying_mail then
self.game:set_custom_command_effect("action", "open")
self.game:set_custom_command_effect("attack", "save")
submenu.secondary_menu_started = false
sol.timer.start(1, function()
submenu.avoid_can_save_from_qsmenu = false
end)
sol.menu.stop(self)
else
-- if it is displaying a letter, just clear the message, it is very simple.
self.displaying_mail = false -- that's it.
end
handled = true
end
end
if not self.game:get_value("mail_" .. self.cursor_position .. "_highlighted") then
self.game:set_value("mail_" .. self.cursor_position .. "_highlighted", true)
end
self:load_extra()
return handled
end
function mail_submenu:display_mail(index)
local mail_text
self.current_page = 0
if index ~= nil then
-- Load the target file, only in read mode, the file name is the name of the letter, given by it's savegame variable.
-- These files are part of dialogs, so they need to be part of the language system. So mails can be translated with ease.
-- Luckily, savegame variable for this is ("mail_" next_mail_pointer_non_allowed "_" name), so you just have to get the cursor position in order to get that file
mail_text = sol.file.open("languages/".. sol.language.get_language() .. "/text/mail/" .. self.game:get_value("mail_".. self.cursor_position .. "_name") .. ".dat", "r")
-- Read the file, and store all of it's content in self.text.
self.text = mail_text:read("*all")
-- We get all of the file's text stored in self.text, the host file isn't interesting anymore, unload it.
mail_text:close()
-- Parse the text.
self:parse_text()
-- We are reading the mail, on_command_pressed need an alternate command mapping
self.reading_mail = true
else
-- We are on the mail, and player pressed "close", he closed the mail, clear everything that regards this mail.
self.text_display_surface:clear()
-- The surface handling the text has been cleared, but not the text
self.mail_content:set_text("")
mail_text = nil
self.text = nil
end
end
function mail_submenu:parse_text()
local line = 0
-- Start some wizzard stuffs here
-- $ = pass line, works
for text in string.gmatch(self.text, "[^$]+") do
line = line + 1
self.mail_content:set_text(text)
self.mail_content:draw(self.text_display_surface, 0, 0 + (line * 15))
end
end
return mail_submenu
The problem is, when opening a mail, I want to ignore all things that doesn't regard the current page , and I am not really good when it comes to string modification, I don't know how to do it, I mostly want the engine to analyse and draw texts that are between [page] and [/page].
Any help would be welcome
Hi! I think this can be done using some of the Lua functions for strings. Probably the best option will be just using "string.match" (the function "string.find" could be useful too, but maybe worse). (I think "string.gmatch" is similar, but it gives an iterator to find patterns instead, if I am not wrong.) It should not be too hard (but I agree these things are annoying and too easy to forget). Fortunately there are good tutorials explaining how to get the patterns. Check the following links in the given order:
A very nice tutorial which I used once and found it greatly useful:
http://lua-users.org/wiki/PatternsTutorial
A manual about patterns which may help too:
http://www.lua.org/manual/5.2/manual.html#6.4.1
A list of Lua string functions (you do not need this now, but it may help for other purposes):
http://lua-users.org/wiki/StringLibraryTutorial
I cannot help you more since I have forgotten how to use the patterns, so I would need to study the tutorials again.
EDIT: you may also find some examples of uses of the "string.match" function in your dialog box script.
EDIT2: be careful because some of the characters you use (like "[" and "]") have special uses for the pattern syntax (they are called magic characters in the second link), as you can read in the tutorials. You can match them using "%" before them, i.e., with "%[" and "%]".
Thanks Diarandor for the help, indeed, it is useful, but I might have find a easier way to do it using require instead of sol.load (and it just use the "$" formatting instead of a huge and long process of string manipulation
something like this also work, this is almost the same thing, but instead it use a Lua table to get the text, and it is still understandable for translators (plus, coms can be added to gave them hints since the format is lua)
This is how the mail file now looks like
local text = {
-- [0] represent the page
[0] = (
"Header$" ..
"Line1$" ..
"Line2$" ..
"Line3$" ..
"Line4$" ..
"Line5$" ..
"Line6$" ..
"Line7$" ..
"Line8$"),
["reward"] = "heart_piece",
}
return text
It does work in game, I'm quite surprised
(http://i.imgur.com/ux4hngY.png)