matejcik Posted February 11, 2009 Share Posted February 11, 2009 (edited) This script changes the way Message Boxes, Inputs and Dialogs work in a cartridge. terminology: MessageBox means "show a message to the player" - the thing where you can specify names of buttons and add callback scripts Dialog means "show a series of dialog messages to the player" - you can write multiple messages at once, but can't rename buttons and add scripts for the buttons GetInput means "get input from player" - the function that puts an Input that you created on the screen. Usually, if you call any of those, the previous one is automatically cancelled. That means that if you do the following in a script: MessageBox ("hello and welcome to this zone!") MessageBox ("i hope your journey went well.") GetInput (zinputHowWasYourJourney) then the player won't see the first two MessageBoxes, because they will be immediately cancelled - the first one by the second one, and the second one by the GetInput. If you want to show a long series of messages ("do some talking") and then ask a question, your only choice would be to put only one MessageBox in the original script, and put every other MessageBox into the button script of the previous one. Which is a pain to do. The following Author Script changes the behavior. When you put a Dialog in the script, it's contents will not be shown immediately. Instead, the contents will be stored internally ("buffered"). Then, when you put a stand-alone MessageBox or GetInput into the script, the Dialog will be started. Example: Dialog ("hello and welcome to this zone!" .... "i hope your journey went well.") GetInput (zinputHowWasYourJourney) In unmodified cartridge, this would mean that the GetInput cancels the Dialog and the player won't see it. When using the author script, this code will do exactly what you want - show two messages, and after the player reads them, ask a question. You can stack as many Dialogs as you want in a single script. For example, you can use one Dialog to start the "conversation", use two more in an if-then-else clause (one for each branch), and finish it with a common ending in another Dialog. Then, when you want to show the contents of that Dialog, you have to do one of the following: a) finish the sequence with a MessageBox or a GetInput put one more "dialog message" into the last dialog and leave it empty. the author script just copy&paste the following code into your Author Script editor in the Builder. it is self-contained, so you should be able to put any other author script above or below it. originalFns = {Dialog = Wherigo.Dialog, MessageBox = Wherigo.MessageBox, GetInput = Wherigo.GetInput} dialogStrings = {} require "table" function rundialog () local ds = dialogStrings dialogStrings = {} local cb = {} cb = function(thing) if thing ~= nil then local item = table.remove(ds,1) if item ~= nil then if item.Callback == nil then item.Callback = cb end originalFns.MessageBox(item) end end end cb(1) end function Wherigo.Dialog (tbl) for k,v in ipairs(tbl) do table.insert(dialogStrings, v) end if #dialogStrings > 0 and dialogStrings[#dialogStrings].Text == nil and dialogStrings[#dialogStrings].Media == nil then table.remove(dialogStrings) rundialog() end end function Wherigo.MessageBox(tbl) table.insert(dialogStrings, tbl) rundialog() end function Wherigo.GetInput (input) if #dialogStrings == 0 then originalFns.GetInput(input) else dialogStrings[#dialogStrings].Callback = function(thing) originalFns.GetInput(input) end rundialog() end end Edited by Ranger Fox per request. Edited December 3, 2009 by Ranger Fox Quote Link to comment
+charlenni Posted February 11, 2009 Share Posted February 11, 2009 I found the function a few days before and I like it. I looked at the code and think, if you could change the Dialog function, you need not a MessageBox. function Wherigo.Dialog (tbl) if tbl ~= nil and tbl[1] ~= nil and tbl[1].Text ~= nil then for k,v in ipairs(tbl) do table.insert(dialogStrings, v) end else if dialogStrings ~= nil and #dialogStrings > 0 then tbl = {Text = table.remove(dialogStrings).Text,Buttons = {"Ok",}} Wherigo.MessageBox(tbl) end end end You could start displaying the messages with an empty Dialog (No Text). In code it would be Wherigo.Dialog{{},} . Best regards. Dirk Quote Link to comment
matejcik Posted February 11, 2009 Author Share Posted February 11, 2009 sure, but there's no point in doing that, it doesn't increase the amount of "sense" the builder code would make. however, it might be good to allow an empty messagebox to start the sequence. idea being that you don't have to specialcase the last message of the dialog, and still retain the logic where "dialog stores, messagebox runs" i was also thinking of automatically building wrappers ... something along the lines of: function wrapper(func) return function() enableBuffering() func() replayBuffer() end end and then have a loop automatically wrap all event handlers. but that just might fail spectacularly if the user tried to do something weird (for example, launch two messageboxes with callbacks) Quote Link to comment
+charlenni Posted February 12, 2009 Share Posted February 12, 2009 After a night of sleep I found a better way for my problem. If you want only make a series of dialogs this wouldn't work with your aproach. You should make a MessageBox at the end. If you would us the following code function Wherigo.Dialog (tbl) for k,v in ipairs(tbl) do table.insert(dialogStrings, v) end if dialogStrings ~= nil and #dialogStrings > 0 and dialogStrings[#dialogStrings].Text == nil then table.remove(dialogStrings) if #dialogStrings > 0 then tbl = {Text = table.remove(dialogStrings).Text,Buttons = {"Ok",}} Wherigo.MessageBox(tbl) end end end You could make a series of dialogs with the builder and the last line leave empty. In the builder you would see [[No Text]] and in the cartridge the dialogs want be shown. There is no need of an extra MessageBox. Better? Quote Link to comment
+charlenni Posted February 12, 2009 Share Posted February 12, 2009 I have another idea for this functions: if you have all text of Dialogs, MessageBox and Input you could replace text. I expanded the function, so you can write for exapmle "Hello [Player.Name], how are you?" will expanded on screen to "Hello Builder, how are you?". All varaibles which are standing between "[" and "]" are expanded. Even all functions. You could write "The result is [25*2]." and it will expanded to "The result is 50." Or if you have timer ztimerTest you could show a dialog with text "You have [ztimerTest.Remaining] seconds left. Hurry up". Or you can even call your one functions if the result is a string. And the best: you must not leave the builder, all could be done inside normal Dialogs, MessageBoxes and Inputs. I didn't test the input function (time is to short ;-). Here is the code function Wherigo.Dialog (tbl) for k,v in ipairs(tbl) do table.insert(dialogStrings, v) end if dialogStrings ~= nil and #dialogStrings > 0 and dialogStrings[#dialogStrings].Text == nil then table.remove(dialogStrings) if #dialogStrings > 0 then tbl = {Text = table.remove(dialogStrings).Text,Buttons = {"Ok",}} Wherigo.MessageBox(tbl) end end end function Wherigo.MessageBox(tbl) local ds = dialogStrings dialogStrings = {} local cb = {} cb = function(thing) if thing ~= [[Button1]] then if tbl.Callback ~= nil then tbl.Callback(thing) end else local item = table.remove(ds,1) if item == nil then tbl = MessageBoxReplace(tbl) originalFns.MessageBox(tbl) else item.Callback = cb item = MessageBoxReplace(item) originalFns.MessageBox(item) end end end cb([[Button1]]) end function Wherigo.GetInput (input) local item = table.remove(dialogStrings) input = MessageBoxReplace(input) item.Callback = function(thing) originalFns.GetInput(input) end item = MessageBoxReplace(item) Wherigo.MessageBox(item) end function MessageBoxReplace(tbl) if tbl.Text ~= nil then tbl.Text = string.gsub(tbl.Text, "(%b[])", function (x) x = "return " .. string.sub(x, 2, -2) local f = loadstring(x) return f() end) end return tbl end Quote Link to comment
matejcik Posted February 12, 2009 Author Share Posted February 12, 2009 After a night of sleep I found a better way for my problem. (snip) You could make a series of dialogs with the builder and the last line leave empty. In the builder you would see [[No Text]] and in the cartridge the dialogs want be shown. There is no need of an extra MessageBox. Better? yes, much better.i'll put something like that into the script listing, i can still edit it now :e) I expanded the function, so you can write for exapmle "Hello [Player.Name], how are you?" (snip) this is not necessary. you can write: [[Hello, ]] .. Player.Name .. [[, how are you?]] in the builder and it will use that as code, not as string. go check it out ;e) Quote Link to comment
matejcik Posted February 12, 2009 Author Share Posted February 12, 2009 new version is up; it also fixes a bug where the GetInput would fail if it was started without a Dialog Quote Link to comment
+charlenni Posted February 12, 2009 Share Posted February 12, 2009 (edited) matejcik, you are right. You could use each variable or function you want in the builder if you use [[]].. ..[[]]. I didn't know this. Thanks. But couldn't we use it for a translation on the fly? You could have for each language an own textfile wie the translations. In the builder you use only say "[text01]" and the functions read the text for "text01" from the textfile? For Dialogs and so one it is no problem, but for Names and Descriptions. I try this in the next days. Best regards. Edited February 12, 2009 by charlenni Quote Link to comment
matejcik Posted February 13, 2009 Author Share Posted February 13, 2009 But couldn't we use it for a translation on the fly? You could have for each language an own textfile wie the translations. In the builder you use only say "[text01]" and the functions read the text for "text01" from the textfile? For Dialogs and so one it is no problem, but for Names and Descriptions. I try this in the next days. this is another thing i've been wondering about ... do you have proof that you can open files that aren't "media" from the cartridge? in emulator, it might work, because its working directory can be the same as the source directory, but unless i'm mistaken, you can't put separate files (Lua includes, translation files etc) into the cartridge itself. and if you can, i'd love to see such cartridge in its compiled form Quote Link to comment
+charlenni Posted February 13, 2009 Share Posted February 13, 2009 You are right! We couldn't use extern files. It's terrible. You couldn't work with extern files. Now I have rewriten the code, so the files with the translations are medias. You have to medias with name say langEnglish and langDeutsch. Each of that medias contain one resource which ist a textfile in the format"Ident=Text" for all text you want translate. At each point you would be translated you write "{Ident}" (works for all objects defined in builder and all Dialog and MessageBoxes). At start you call a function which looks for all languages in the medias and than show a input, which will to be used. Now this media will be read which you choose. After that, all text in objects will be transfered. Dialogs and MessageBoxes will be transfered on the fly. All text is embedded in the gwc file. Now the problemes: 1. Normal input problem (should be the last call in Cartridge:OnStart()) 2. I didn't get the choice of the input. The variable is empty. I need help in programaticaly create an input. 3. On the Colorado the access to the textfile didn't work (I get a memorycard error) I think, Garmin didn't have implemented the io-library I will only need io.open, io.lines and io.close. But if they implement it, we can also make a library for making images on the fly ;-) If you like to see the code, I could send it to you. But there are no comments in the code ;-) Quote Link to comment
matejcik Posted February 13, 2009 Author Share Posted February 13, 2009 yup, send me the code :e) sorry to disappoint you, but i still don't think that it will work. if i understand it correctly, the io library accesses the -external- filesystem, you'd have to find and parse the gwc file from lua. i'd love to be mistaken on this, though :e) i'll write a more detailed answer later, unless somebody beats me to it. for now, why don't you write translations into the lua code as a table? Quote Link to comment
+sTeamTraen Posted February 13, 2009 Share Posted February 13, 2009 My builder "Earwigo" (someone please think of a better name...) supports multilingual cartridges in a way which is simpler than this, but probably less powerful. You just pick a separator string (I use '@@') and when you enter a text into the builder, you write it in each language, separated by that string. So for example a message text might be "Hello@@Bonjour@@Guten Tag". Then when you generate the Lua file (which is a separate step), you tell it to make language version 0 or 1 or 2. If you don't provide a translation for a given string for language N, it defaults to language 0, so "Hello@@Bonjour" would give "Hello" for language 2, and a text with no translation separator string is the same in every language. The on-the-fly approach is how Earwigo works for its internal multilingual capability (ie, the Javascript/PHP code of the builder has no text, only tags which are looked up at runtime). Maybe a future version will implement this for cartridges too, but the current approach is perhaps easier to understand, and doesn't need a separate data structure to be maintained. Quote Link to comment
+charlenni Posted February 13, 2009 Share Posted February 13, 2009 Here is the code. It works all fine except the io functions on the colorado and the input of the first screen (selection of the language). It is hardwired to "english.txt". If you want to change it to "deutsch.txt" you hade to change line 181. It works also in the emulator without the text-files in the same directory. You only need the gwc-file. I think, garmin "forgot" to implement the io functions ;-) DialogTest.zip Quote Link to comment
matejcik Posted February 13, 2009 Author Share Posted February 13, 2009 now this is very very interesting. but if the io library operates on files contained within the cartridge, there's no reason garmin would "forget to implement" it, they would just take Groundspeak's implementation ... very weird indeed. let me do some tests with this. Quote Link to comment
+charlenni Posted February 13, 2009 Share Posted February 13, 2009 The disadvantage of my approch is: it didn't work. The advantage is: you could select with the frist screen of the cartridge which language you want. And, if it's work (io on colorado), you could also make images on the fly (assumed you have a Lua jpg-library). Also in larger projects sometimes it is better, if you could give all text to someone, who could translate it. You could name your builder "WherIBuild" as against "WherISwear" for the original one ;-) Quote Link to comment
matejcik Posted February 13, 2009 Author Share Posted February 13, 2009 The disadvantage of my approch is: it didn't work. so, if you put your object library as a lua file inside the cartridge and "require" it, that does work on colorado? Quote Link to comment
+charlenni Posted February 13, 2009 Share Posted February 13, 2009 The disadvantage of my approch is: it didn't work. so, if you put your object library as a lua file inside the cartridge and "require" it, that does work on colorado? No, it didn't work. I get an "memorycard reading error". With the emulator extern *.lua-files work. If I put the modul in the author script section, I get an error, if I try an io-operation. And the problem with the selfmade input are further exists. Quote Link to comment
+charlenni Posted February 13, 2009 Share Posted February 13, 2009 now this is very very interesting. but if the io library operates on files contained within the cartridge, there's no reason garmin would "forget to implement" it, they would just take Groundspeak's implementation ... very weird indeed. let me do some tests with this. I have made a small Lua-file for testing. It has only one media (txt-file). If you start the cartridge with the emulator, you should see the abc in a MessageBox and in the Lua debug of the emulator. If you start it on the garmin, you will get an "Unexpected error / Closing cartridge". IOTest.zip Quote Link to comment
+charlenni Posted February 14, 2009 Share Posted February 14, 2009 Now I have a solution for one of my two problems: the input of the language. Also I have added the translation of text for EmptyYouSeeListText, EmptyTasksListText and EmptyInventoryListText. So you could choose your language at the begining of the cartridge. So the translate modul works fine except it would not run on colorados (and on oregons as well) because of the io problem. If this is solved, it is ready to use. DialogTest.zip Quote Link to comment
matejcik Posted February 14, 2009 Author Share Posted February 14, 2009 now is maybe a good time to start your own thread ;e) Quote Link to comment
Ranger Fox Posted February 19, 2009 Share Posted February 19, 2009 Now I have a solution for one of my two problems: the input of the language. Also I have added the translation of text for EmptyYouSeeListText, EmptyTasksListText and EmptyInventoryListText. So you could choose your language at the begining of the cartridge. So the translate modul works fine except it would not run on colorados (and on oregons as well) because of the io problem. If this is solved, it is ready to use. That's an innovative way to do things. I don't know, though, if Garmin will ever allow IO. They'd need a heck of a push for that and perhaps a promising return on investment. Were I translating my cartridge to different languages, I may have elected to create several arrays, one array each to hold all translations for one text string. Quote Link to comment
+me2d09 Posted March 19, 2009 Share Posted March 19, 2009 I have done some research in Wherigo input output. Because this is matejcik's thread about something different, I started a new thread. Quote Link to comment
mutle Posted November 30, 2009 Share Posted November 30, 2009 Thanks a lot for this excellent Author Script. I have a problem when showing several dialog boxes and a message box (or only a message box). If the player doesn't confirm the windows by clicking on "ok" and the next dialog and/or message boxes appear, the cartridge crashes. This happens in the Emulator as well as with the Oregon. Example: the player enters a zone - a message box appears - the player is sleeping and doing nothing - he is leaving the zone (for example by mistake) - the next message box appears --- that's the end - the cartridge crashes: "Lua Error ... :934: attempt to index global 'tbl' (a nil value)". Any idea? Thanks, mutle Quote Link to comment
matejcik Posted November 30, 2009 Author Share Posted November 30, 2009 which line is number 934 in your cartridge? Quote Link to comment
mutle Posted December 1, 2009 Share Posted December 1, 2009 The line 934 is " if tbl.Callback ~= nil then". Its part of the author script, in the function rundialog the 6th line. Best regards mutle Quote Link to comment
matejcik Posted December 1, 2009 Author Share Posted December 1, 2009 right, that makes sense. and the original code didn't. how i came up with it, i'll never know... try to replace rundialog function with this: function rundialog () local ds = dialogStrings dialogStrings = {} local cb = {} cb = function(thing) if thing ~= nil then local item = table.remove(ds,1) if item ~= nil then if item.Callback == nil then item.Callback = cb end originalFns.MessageBox(item) end end end cb(1) end i didn't test it, but unless i did a syntax error, it should fix your issue. if it does, please report back and i'll try to convince RangerFox to edit my original post ;e) Quote Link to comment
mutle Posted December 2, 2009 Share Posted December 2, 2009 First tests in the emulator worked very well - many many thanks to matejcik!!! This helps a lot and it will make the cartridge much more stable. The behaviour is like that: when there is a message or dialog box displayed and not yet confirmed (ok-button) and a new dialog or message box appears (for example "When the player enters a zone"), then the new one will be shown and the fist ones are canceled. Best regards mutle Quote Link to comment
matejcik Posted December 2, 2009 Author Share Posted December 2, 2009 great. that is the desired behavior. RangerFox, would you be so kind and update my original post with the new code? Quote Link to comment
Ranger Fox Posted December 3, 2009 Share Posted December 3, 2009 great. that is the desired behavior. RangerFox, would you be so kind and update my original post with the new code? Done. I edited the code with the function you included in post #26. Quote Link to comment
matejcik Posted December 3, 2009 Author Share Posted December 3, 2009 yes, this should do the trick. thanks. Quote Link to comment
+wunnibald Posted June 7, 2010 Share Posted June 7, 2010 function zitemThing:OnHelpMe() Dialog("Erste Dialogmessage", "Zweite Dialogmessage") MessageBox("Und hier die letzte Message") end In emulator I'm getting the following error message: 'attempt to call global 'Dialog' (a nil value)' Of course i pasted the author script at the right place in the lua file. How is the correct usage of this cool code? Thx for answering. Quote Link to comment
matejcik Posted June 7, 2010 Author Share Posted June 7, 2010 (edited) you have to use the "Wherigo" prefix: function zitemThing:OnHelpMe() Wherigo.Dialog("Erste Dialogmessage", "Zweite Dialogmessage") Wherigo.MessageBox("Und hier die letzte Message") end This is how Builder generates the code. Or you can add these two lines to your author script: Dialog = Wherigo.Dialog MessageBox = Wherigo.MessageBox then your code will work unchanged Edited June 7, 2010 by matejcik Quote Link to comment
matejcik Posted June 7, 2010 Author Share Posted June 7, 2010 also, the way you are calling it, it will not work. you need to do it this way: Wherigo.Dialog{ {Text="Erste message"}, {Text = "Zweite message"} } Wherigo.MessageBox{Text="Letzte message"} or if you just need simple things like this one, do not write the code in AuthorScript and just use Builder's "message box" and "series of messages" commands. Quote Link to comment
+wunnibald Posted June 7, 2010 Share Posted June 7, 2010 (edited) If I do it this way just the message 'Generic MessageBox' ist displayed. Both on GPS and Emulator. Edited June 7, 2010 by wunnibald Quote Link to comment
matejcik Posted June 7, 2010 Author Share Posted June 7, 2010 see what i said in my other comment Quote Link to comment
+wunnibald Posted June 8, 2010 Share Posted June 8, 2010 Sorry, I don't get what you want to say. Quote Link to comment
matejcik Posted June 8, 2010 Author Share Posted June 8, 2010 okay. first of all: do you really need to write this in an Author Script? Quote Link to comment
+wunnibald Posted June 8, 2010 Share Posted June 8, 2010 I'm trying to build dialogs out of if-then-else structures (sometimes with a question to answer at the end), so I think the answer is yes. Quote Link to comment
matejcik Posted June 8, 2010 Author Share Posted June 8, 2010 no, i'm afraid you think wrong. can you give an example in pseudo-code? something like: 1. say "Hello and welcome to this zone."2. if (you are here for the first time) say "I see this is your first time here." else say "I see you've been here before, glad to have you back." 3. say "Do you want to buy a nice woolen sweater?" 4. ask question: "Buy sweater? yes/no" something like this? if that is what you are trying to do, you don't have to write this in author script. you only copy-paste my author script into your cartridge, and then you create this code in the builder normally Quote Link to comment
+wunnibald Posted June 8, 2010 Share Posted June 8, 2010 The pattern of your example is perfect. That's what I'm intending to do. Sorry if I'm nerding around here. Just for my understanding: If I paste your code in the author script part of the file and i use MessageBox etc. in the builder like I always used to, your code will already come to effect without any further change in code (can't give it a try at moment)? Quote Link to comment
matejcik Posted June 8, 2010 Author Share Posted June 8, 2010 If I paste your code in the author script part of the file and i use MessageBox etc. in the builder like I always used to, your code will already come to effect without any further change in code (can't give it a try at moment)?exactly Quote Link to comment
+wunnibald Posted June 8, 2010 Share Posted June 8, 2010 LOL - and your Wherigo.Messagbox function overrides the generic one? Quote Link to comment
matejcik Posted June 8, 2010 Author Share Posted June 8, 2010 yes, that's the point Quote Link to comment
+wunnibald Posted June 8, 2010 Share Posted June 8, 2010 OK. Thx very much for patience and for the code of course. Quote Link to comment
+austriaka Posted September 30, 2011 Share Posted September 30, 2011 Is this Author function from above already part of the Urwigo Builder or should I place it within the User functions section? Quote Link to comment
+jgda Posted November 2, 2013 Share Posted November 2, 2013 Hi, am also using Urwigo, does this work in this builder I am having troubles getting the screen sequencing right: introduction text question if yes another question if yes messages else action can you help? Best regards, Gotthard (jGda) Quote Link to comment
+Y6GST Posted November 10, 2014 Share Posted November 10, 2014 I have used this code for the first time today and all went well using the both the Groundspeak emulator, and the WebWigo emulator, it also worked fine in the field on a Garmin Oregon 450, however the iPhone 5 running the Wherigo app only showed the last message in the sequence, none of the dialog messages were shown. Has an update to the iPhone app meant this script no longer works within it? Quote Link to comment
+Mzebonga Posted October 24, 2015 Share Posted October 24, 2015 I have used this code for the first time today and all went well using the both the Groundspeak emulator, and the WebWigo emulator, it also worked fine in the field on a Garmin Oregon 450, however the iPhone 5 running the Wherigo app only showed the last message in the sequence, none of the dialog messages were shown. Has an update to the iPhone app meant this script no longer works within it? Is there any further information on what might be stopping this script working with iPhone? Is it still a problem or have subsequent software updates resolved the issue? I only have Android so I'm not able to test on iPhone and wondered if I needed to account for this. Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.