UI in Action

by Ron Gilbert
Feb 17, 2015

Another week and another stunning professionally produced gameplay video, this one of the first pass at the verb UI.

My goal last week was not only to get the UI working, but also the hooks from Squirrel into the engine so when verbs and objects were clicked on, everything flows correctly and wasn't just kludged up.

Astute readers will note the interface works more like Monkey Island than Maniac Mansion, and that is a good thing. Maniac Mansion was a first pass at the verb-based point & click UI and it was clunky. Monkey Island introduced (or maybe it was Last Crusade) scanning around the screen and the "sentence line" autoupdating. In Maniac Mansion, you had to select a "what is" verb. It also required a double-click to execute sentences. What were we thinking?

On the programming side, I was having some issues with how Squirrel handled classes, so I ditched the notion of rooms being classes and just made them simple tables/dictionaries. It works a lot better since I don't really need full-on classes for the rooms. There will only be one of each and they never get destroyed once created.

It also allowed me to get rid of the object { } table that enclosed all the room's objects. It was an unnecessary scope due the c code's inability to cleanly iterate through Squirrel classes. There was probably a way around it, but less is more and I like this better and it's all about me.

It could be argued you might want to create a base room class and derive from that, especially in the case of generic rooms like the forest in Monkey Island and the hotel in Thimbleweed Park, but endless class deriving and polymorphism is a pit of pain and eye poking. Object oriented programing (or OOP we pros call it) can make you feel very clever, but sometimes it feels like it's being used just because it makes you feel very clever.

I'm sure this will all change dramatically over the next few months. Stay tuned!

Here is the scripting code the runs the video above

TestStreet <-
{
    background = "TestStreet"
    enter = function()
    {
        print("Entering TestStreet")
    }
    exit = function()
    {
    }
    TestStreetToBankDoor =
    {
        name = "Bank Door"
        walkTo = function()
        {
            enterRoomFromDoor(Bank.bankToMainStreetDoor)
        }
    }
}

Bank <-
{
    background = "Bank"

    function threadTest()
    {
        while(1) {
            print("loop")
            breakhere(100)
        }
    }

    // Called when the room is entered, after objects are inited.
    enter = function()
    {
        print("Entering Bank")
        // This thread needs to be killed when leaving the room. Need to figure out a way to make that happen automatically.
        startthread(threadTest)
    }

    // Called when exiting, before new room enter code
    exit = function()
    {
    }

    bankPainting =
    {
        look_count = 0
        name = "Cheap Painting"
        lookAt = function()
        {
            if (look_count == 0) { currentActor.say("You'd think a bank could afford a better painting.") }
            if (look_count == 1) { currentActor.say("This looks like a knockoff.") }
            if (look_count == 2) { currentActor.say("I think I can see the numbers behind the paint.") }
            if (look_count >= 3) { currentActor.say("I'm done looking at this painting.") }
            look_count++
        }
    }

    bankClock =
    {
        name = "Clock"
        lookAt = function()
        {
            currentActor.say("It's who cares'o clock.")
        }
    }

    bankToMainStreetDoor =
    {
        name = "Door"
        quickExit = true    // Actor exits before fully reaching the door
        walkTo = function()
        {
            enterRoomFromDoor(TestStreet.TestStreetToBankDoor)
        }
    }
}

// All rooms must be loaded before they can be referenced.
defineRoom(Bank);
defineRoom(TestStreet);

// Create detective
detective <- Actor("DetectiveFemaleWalk")
detective.talkColors(0x45a3ff0x173450)    // text + outline colors

// Make her the selected character
selectActor(detective)

// Put her inside the Bank at the front door
enterRoomFromDoor(Bank.bankToMainStreetDoor)

One issue I have yet to solve is a simple and slick way to do different dialog for different characters.

if (look_count == 0) { currentActor.say("You'd think a bank could afford a better painting.") }
if (look_count == 1) { currentActor.say("This looks like a knockoff.") }
if (look_count == 2) { currentActor.say("I think I can see the numbers behind the paint.") }
if (look_count >= 3) { currentActor.say("I'm done looking at this painting.") }

For a lot of lines, everyone can say the same thing, but we're going to want enough variation to give the characters personality.  In reality (pro tip), you don't need that many character specific lines. The characters in Maniac Mansion basically react the same to 95% of everything the player does, but it's that 5% that stands out. That 5% feels like 75%. It's about picking and choose the custom replies and making them count.

I could so this...

if (selectedActor == DetectiveRay) {
    if (look_count == 0) { currentActor.say("You'd think a bank could afford a better painting.") }
    if (look_count == 1) { currentActor.say("This looks like a knockoff.") }
    if (look_count == 2) { currentActor.say("I think I can see the numbers behind the paint.") }
    if (look_count >= 3) { currentActor.say("I'm done looking at this painting.") }
}
if (selectedActor == Ransome) {
    // etc
}

But that's going to get real tedious real fast. I need to figure something out.

The other issue I need to deal with is fonts. Right now the C64 font is a truetype font and truetype fonts want to render smooth and antialiased. It works most of the time, but with certain sizes it looks odd. I may end up doing a true bitmap texture atlas based font once all the sizes have settled down, but that's months down the road.

And in conclusion, I leave you with a time lapse of getting the UI working...

- Ron



entropy - Feb 17, 2015 at 11:11
"I think I can see the numbers behind the paint."

Pure gold! :D

TR - Feb 17, 2015 at 11:25
Exactly what I was thinking. Could have been Guybrush saying that. :o)

pmarin - Feb 17, 2015 at 11:23
Not having the verbs tabulated like the first MI kicks my OCD. Never been more exited about a devlog since the Carmack's .plan files.

Ricardo - Feb 17, 2015 at 11:39
I must say I found weird to have delegated to a script the act of choosing which character says what to each object. I'd expect there would be a data file to handle that. Maybe a table, one line per object and one column per character? Would be much better for maintenance and tweaking. Then one table per verb.

Ron Gilbert - Feb 17, 2015 at 11:53
The problem with putting text in data files is you can't do complex logic. It works fine for simple cases like this, but what makes adventure games fun is the fun logic about when lines get said, or strange conditions about what you might have been seen or be holding.

Yes, you can do it, but I have found it to just keep the text with the logic.

I also find writing in databases or spreadsheets to completely kill my creativity. It's a silly practice that seems to be accepted as the norm these days by writers. If you're a writer, rebel against this. It's often programers who want data in clean formats forcing creative people to adjust.

Joe - Feb 17, 2015 at 12:42
Well, the text is ultimately data, and data that will be easier to localize if it has been separated. The differences in text between characters could also be treated as a specific localization.

Although writing code like...
     if (look_count == 0) { currentActor.say(TEXT_ENUM_MAGIC.BankPaintingLook1) }
...is no fun at all.

Snowman - Feb 17, 2015 at 14:24
The localization issue is usually handled by a "magic" function - gettext uses _() I think, Qt uses tr(). The string goes on the inside and becomes both key and source for the translation. A script parses the source code, finds all the calls, put the strings in a dictionary file/template that translators can fill out. The actual function call goes to some translation handler that uses the string to lookup the correct translation based on language settings. Dead simple and IMO not an onerous task at all. In addition, if necessary, the translate wrapper can have parameters to e.g. fill in values if the string is parametrized (think printf format strings), or give some context if there are clashing strings or whatever.

For reference, here is the Qt API docs for their version: http://doc-snapshot.qt-project.org/qt5-5.4/qtranslator.html

Joe - Feb 17, 2015 at 16:08
Ah yeah, makes sense that you'd use an actual English (or whatever) string as the key. I havent been able to get away with that in the past due to being tied to Windows its standard resource dlls. Those really want to tie strings to numeric ids. Not surprising that qt has a better way. Although "a script parses the source code" sounds scary, but it bet it works pretty darn well no matter what language.

I still say that magic function could treat different characters as different localizations. Dunno if that's a good way to do it, but that's what I'd try. :)

Ron Gilbert - Feb 17, 2015 at 16:18
I've never fancied hash keys for string source. It's too easy to change the text in the code and break the key. I have always favored using some kind of ID that links the text. The system I am currently using extracts the text and creates the IDs. The same script can be (safely) rerun and it will update any text. The text in the scripts is the conical text. You never edit the text in the english DB.  It's a process that I've been using since the Humongous Entertainment games and it works really well for me. Everything is fraught with downsides, so you kind of pick your poison and I've chosen this one.

5 - Feb 17, 2015 at 19:33
How do you generate the IDs? It seems like you'd have to use the relative positions of the texts if you don't want to hash them, but then everything would be offset if you inserted a new line in the middle somewhere, like if you wanted an extra line before the final one when looking at the painting.

Maybe you could use explicit IDs as well as the english text? Something like currentActor.say("bankpainting_1", "This looks like a knockoff.") ?

Ron Gilbert - Feb 17, 2015 at 20:51
There is a control file that keeps track of the next number.  For different actors, I use different ranges.  So Ransome would be 10000-19999, Delores  20000-29999, etc. These number aren't really for human consumption, so the ranges can be arbitrary. The character ranges are for printing scripts for voice acting. The program I wrote scans the DB and emits .pdf files for the actor.  The game script code will look like:

ransome.say(12478, "My makeup is starting to itch!")

Remember, there is a program that goes though in insets the 12478, so a person doesn't have to type that or keep track.

There is a lot more detail to this, like how to handle lines said by any playable character, so I should just do a full blog post about it in the future.

5 - Feb 17, 2015 at 23:10
Oh, I understand (I think)! So your program actually changes the source files, and it only adds the ID to lines that don't already have the ID? So this:

ransome.say("My makeup is starting to itch!")

Turns into what you said:

ransome.say(12478, "My makeup is starting to itch!")

I was wondering what would happen if you inserted a new line before that later on, but if I understand correctly, you'd simply keep the ID on the line from earlier, so it'd look like this:

ransome.say("Storing those fleas in my makeup container might have been short-sighted.")
ransome.say(12478, "My makeup is starting to itch!")

And you'd run your program again and it'd only touch lines that don't already have an ID:

ransome.say(12694, "Storing those fleas in my makeup container might have been short-sighted.")
ransome.say(12478, "My makeup is starting to itch!")

That's clever :)

And yes, I'd love more detailed blog post about this. Well, about everything. Thank you :)

Leo Friend - Feb 21, 2015 at 00:13
+1 to your suggestion of using localization,or localization patterns, to handle multiple characters. speech. If using squirrel, then you'd pick a unique function name to wrap all speech in, then write your own 'compiler' that takes the strings wrapped in such a function from your squirrel, and put in in a file format. Since there are really slick tools that make creating translations really nice (eg linguist/qt translator), its a good idea to use an existing file format that interoperates with existing tools. Then go in to your code, and have your implementation (of that unique function you created) read the translations at runtime and return the correct string based on the current character.

Dominik - Feb 17, 2015 at 14:24
Right you are Sir! Data tables suck. Simple as that.

But that's not a problem since the game code isn't hard coded in the engine but in a scripting language. After the game is complete (or nearing completion) it would be easy to run a script that extracts all unique strings and puts them in a data file (urgh!) for localization and another to "patch" the game code on run time with the translated replacements. For that to be efficient you could add a special prefix character in all strings that should be marked for localization like this:

if (look_count == 0) { currentActor.say("$You'd think a bank could afford a better painting.") }

This way it would be easier for a script to extract all strings starting with "$" (how doesn't love $?) while your "say" routine would simply ignore it.

Keep up the great work!

vegetaman - Feb 22, 2015 at 15:46
Programmer here -- guilty as charged on the clean formats of data. Though usually I'm nice and take care of converting the free form creative data I'm given and making a table out of it myself. The upsides of a table is that all of the information is in one place... Usually. However, the downside is that for more complex logic, the table can grow to almost an unmanageable mess (or an entire set of tables that need separate documentation to explain and easy to break if you don't add a new item properly). And when you're in the mood to go out there and "create", then setting up all those back end things is definitely counter-productive.

Jeepika - Feb 17, 2015 at 11:54
So the sentence line will be 'autoupdating'... I like that, it has to be the standard.  Guess the verbs will be accessible by keyboard shortcuts, as well.  Q= Open; W=Pick Up, and so on, maybe?

neil - Feb 17, 2015 at 11:56
10 year old me: Wow! How on earth do they make these games...
32 year old me: Wow! How on earth do they make these games...

dos - Feb 23, 2015 at 11:51
I think 22 years was plenty amount of time to learn that. Go do it now, it's never too late! ;)

TheBuzzSaw - Feb 17, 2015 at 11:57
Lookin' great so far. Can't wait for this game.

Your April Fools update should be MMO support.

Iron Curtain - Feb 17, 2015 at 18:02
Anyone who knows Ron Gilbert knows he doesn't celebrate April Fools day. And for good reason: anything legit is treated with suspicion on that day.

Edmundo - Feb 17, 2015 at 12:43
So, how do the verb buttons in the UI trigger the scripted hotspots? Is this something that happens outside the scripting level? Am I asking questions that will be answered in another blog post?

bruno - Feb 17, 2015 at 12:48
A simple way to make the dialogs differ from character is to use OOP. Something real simple and clever.
In C/C++ you don't have interfaces like in java and C#, that would be my first approach.
In C++ you can create the same funcionality extending your class (since it supports multiple inheritance).

What I am suggestion is creating a class with actions, like this (please ignore the sintax, it's only illustrative):

class DetectiveComments extends ActorComments {
int count = 0;
Room currentRoom;

// constructor
DetectiveComments (room) { currentRoom = room; }

// overrides base method
override Say() {
// calls logic for count and current room
}
}

When you enter a room, you create a new Comments class for your room and actor:
ActorComments comments = new DetectiveComments(currentRoom);

Steffen - Feb 17, 2015 at 17:23
Doing it that way would make me feel very clever. SCNR

bruno - Feb 18, 2015 at 14:38
How do you suggest to do this?

Damian - Feb 17, 2015 at 12:55
Looks nice!

Ok, now the dumb designer with barely Javascript knowledge makes the dumb question:

Why the multiple "IFs"?
Isn't there a "Switch" statement you can use?

(Please, don't kill me!) :P

Joe - Feb 17, 2015 at 13:11
I cant speak for Ron, but I favor 'if' statements. I'll start with 'if's and maybe later refactor to a 'switch' if I decide it'd be more clear. I also have a habit of messing up 'switch' statements (a missing 'break' can ruin your day) so maybe that's why. :)

Luke - Feb 17, 2015 at 13:24
Don't know about Ron, but to me, ifs look better. In this particular case, I also think the Switch statement would require more space, since you'd have to add the breaks, so you'd have two statements for each condition.

Ron Gilbert - Feb 17, 2015 at 13:59
I could use switch statements, I just like if statements for simple things.

Jammet - Feb 17, 2015 at 13:22
"It's 'who cares' o'clock!" Lovely! =^_^=

Thank you for the demonstration! I'll have to reduce the speed of the dialog text but I've greatly enjoyed watching this!

Ron Gilbert - Feb 17, 2015 at 14:02
Text speed isn't tuned at all. Right now, it's just 1.5+(len*0.025) seconds. It will be slightly more sophisticated as the project goes on. It's useful to count words rather then must character length.

Steffen - Feb 17, 2015 at 13:30
Just off the top of my hat: how about some hash maps for the descriptions? There could be one generic map containing the common lines and then a set of individual ones for the actors. Whenever the program wants a line, it first tries to find it in the hash map corresponding to the actor and, if it does not find it there, in the generic one. One would still have to think of something different for dialogues, though.

Derrick Reisdorf - Feb 17, 2015 at 13:54
As far as look_count goes, will you preserve this when the player leaves the room?  How would you add dependency between the number of times an Actor has looked at the object and the Actor itself?  Meaning if the Clock has already been looked at 5 times by one character, then a different character looks at it, how will it handle knowing the new Actor is looking at it for the first time (while possibly preserving the old look_count for the other character)?

Dominik - Feb 17, 2015 at 14:19
Wow, great update! Yesterdays post (with the delay) made me twich all day very nervously to get my fix. But all is good now. I am really looking forward to each and every one of these updates. While they are simple, sometimes short they are genuienly authentic and intresting.

Today was the first time I wanted to post: When I saw the replies to "Look at painting" I instantly though of your earlier scripts and wanted to suggest different answers for different characters. But scrolling further down I saw that OF COURSE you have though of that - stupid me :-) It's great to see that after all those years (after all I was a small boy when I first played Maniac Mansion on a friend's NES) you haven't lost your edge and it's a great pleasure to see you at work.

Thanks Ron & Gary!

Max - Feb 17, 2015 at 14:24
That high-res cursor hovering at a higher resolution over that beautiful low-res pixel art makes me cringe :(

Ron Gilbert - Feb 17, 2015 at 14:28
The cursor is the same res as the backgrounds. The video compression/reduction can make things look a little odd.

Max - Feb 17, 2015 at 14:32
This is a very comforting explanation and will definitely help me sleep at night

Jammet - Feb 17, 2015 at 23:40
Remember these very large mouse cursors Maniac Mansion had in almost every version except the PC version?

Four arrows.

I loved that. Of course it's not that important but that cursor, whenever I see it, somehow moves me ;). And on the commodore they had this cute snail mouse cursor when the game was still loading in the background! Awesome!

LogicDeLuxe - Feb 18, 2015 at 11:05
Though, loading times are things I could very well live without them.

Ron Gilbert - Feb 18, 2015 at 11:18
Maybe we'll add a "[X] Commodore 64 load times" option, complete with disk drive sound and virtual flashing drive light. Seriously, I think I'm going to add that now.

Zak Phoenix McKracken - Feb 18, 2015 at 11:47
I think you will make happy many people if you do it :-)

Stefano - Feb 18, 2015 at 12:10
Please implement that! I've just these days gotten back and started writing some C64 assembler for fun, and all the amazing memories of childhood came back :-)

LogicDeLuxe - Feb 18, 2015 at 12:52
That on the other hand, makes it interesting enough to be worth it. As long as it can be disabled anytime, go with it. And of course, there needs to be a snake pointer with this option enabled as well.
You could also give the resource file the extension .d64, just for fun.

Sushi in fishbowl - Feb 18, 2015 at 15:08
Yes , please! As long as you don't include the disk read errors, Ron.
Check out C64 quiz on iOS (which features a few lucasfilm games) for those who don't know what sound we're talking about...

Times Gone By - Feb 19, 2015 at 15:13
Can we also "Press Play on Tape" or turn to "Side 2?"

Derrick Reisdorf - Feb 20, 2015 at 14:26
Maybe include a "cracked by" loading screen or scrolling ticker on the title screen that displays (in flashing rainbow font, or otherwise): CRACKED BY EDISON SOFT?

...unless you think that encourages or condones the practice of software piracy.

Marco Lizza - Feb 19, 2015 at 17:05
Yep, I clearly remember it.

But my preferred one was the "snail cursor" that appeared when you paused the game by pressing space-bar. :)

( also I loved the load/save background images )

Robert McGovern - Feb 17, 2015 at 14:50
Crikey, you already nailed the game and look! Ship it!!

Honestly I know there is still a long way to go but it's already looking like I hoped for, and the comments about the painting were pure comedy gold.

Mario - Feb 17, 2015 at 15:15
@RON : u can make the text-display adjustable, maybe in game configuration menu, so everyone can adjust the text-display speed to his needs. i love to have a lot of configuration before i start. btw, i own a 4K monitor, so will there be any upscaling prob later?

Ron Gilbert - Feb 17, 2015 at 16:11
Yes, the text speed will be user adjustable.

Oleg - Feb 17, 2015 at 15:20
Is TP gonna be like the Lucas Arts games since Monkey Island in terms of design philosophy? Meaning no death/game losing situations and no dead ends? I apologize if you already answered that question.

Iron Curtain - Feb 17, 2015 at 17:59
Ron has repeatedly said that it will follow his rules of adventure game design that started with Monkey Island.

Michael Specht - Feb 17, 2015 at 16:19
Awesome progress! It's amazing being able to witness this creative process. Thanks a lot for this! To me, it's a dream come true, having spent lots of time myself trying to work out SCUMM-like pathfinding and dialogue trees.

I have two comments about the video:

1. The room scrolling: Why not just constant-speed scrolling with an abrupt halt at the end? The constant acceleration and deceleration draws more attention than it probably should. I guess it's one of the points where you have to make a decision about whether you want it really old school or a tad more modern.

2. A darker border color for text lines would make the lines easier to distinguish from the colorful background.

Here's another thing. Yeah, it's about the seckrit of Monkey Island. I'm sorry if this bothers you and I guess people must be asking about that all the time. You got us hooked real good! There's still lots of speculation regarding the final scenes of Le Chuck's Revenge and what would have happened afterwards.

Looking at Thimbleweed Park and your post from 2013 (http://grumpygamer.com/if_i_made_another_monkeyisland) I think it's safe to say there are some obvious connections here, like Thimbleweed Park is that dream come true after a couple of months, just with another story (I noticed how the Maniac Mansion screenshots have a Disney watermark on them, which is kind of unsettling). Anyway, please keep going in that direction, it's good! Where was I? Oh yeah, please make sure you've written down the Secret of Monkey Island _somewhere_. Put it in a time capsule maybe? Some day, someone will be happy to hear the end of the story.

mario - Feb 17, 2015 at 16:22
i like the acceleration and delay of the scrolling. looks very smooth. thats how it has to be nowadays.

Mario - Feb 17, 2015 at 16:26
for the voice actiing: could you get matthew mcconaughey for one detective?
should work in a texas-like landscape - alright alright alright

Mattias Cedervall - Feb 17, 2015 at 16:48
I think that all the characters should be able to pass the Turing test.

Uncyclopedia - Feb 17, 2015 at 16:52

Philipp - Feb 17, 2015 at 18:14
About creating variations in responses: I remember reading how the engine in Infocom adventures used to work, thought it was pretty clever, but beware I am paraphrasing from memory.
When executing an action, say "look at painting", the engine would first ask the room, then other actors, then then player and finally the direct object, in this case the painting. Technically, you ask each of those how they react to the attempt to look at the painting. Each may handle the action or not, allow the action to succeed or not and stop processing or pass it on to the next one in line.
This may sound overly complex but allows to put responses where they logically belong. For "look at painting" you could put the default responses with the painting and potential overrides with the individual characters or even allow other characters to respond to your looking at the painting. If an action should have a special effect on a room, put the code with room. If an NPC intervenes if he sees you trying to x the y,  put the code with the NPC, etc. You can probably find descriptions of the mechanism on the internet or rather likely in Graham Nelson's documentation of the Inform programming language.

Marco Lizza - Feb 19, 2015 at 15:52
Clever, but it would become quite hairy very soon. One will quickly loose track of where the phrase "XYZ" is bound...

PrinzJohnny99 - Feb 17, 2015 at 22:18
No opening and closing doors? Or will it be added later?

Ron Gilbert - Feb 17, 2015 at 22:41
There will be open and close door states, but I don't know if there will be animations, or they might be just two-frame animations. Doors animations aren't something we want to spend time and effort on. I'm not sure opening doors are the type of thing people remember. Did the doors animate in Monkey Island?

The Way it Used to Be - Feb 17, 2015 at 23:25
I just want a click or whoosh and two frame state for doors. That's classic.

Jammet - Feb 17, 2015 at 23:31
Opening doors in the classics before and after Monkey Island were just shown as open or closed completely. However they still mean a much to an adventure gamer. A closed door and no key. A challenge! Love that feeling.

Doors also had distinct opening and closing sounds even if mostly very simple.

The best part about doors is, when they're not "just" doors. Maybe there is something to read on them. Or a mail slot. Or they creak. Or you enter a doom and you'll see something that was hidden by an open door, and you can only see it if you close the door behind you.

Good times.

Jammet - Feb 17, 2015 at 23:45
Godawful typing. Sorry, I am still half asleep.

Absolutely Agree - Feb 18, 2015 at 16:22
I absolutely agree. Doors are an important part of the nostalgia for these games. Either open or closed with no animation inbetween, a distinctive sound, with various adornments such as locks, mailslots, signs, and hidden gems. So satisfying!

Peter Campbell - Feb 19, 2015 at 19:02
I'm with you on this.  Doors are mostly good, particularly for the inside entrance/exit of a building.  In addition to what you said, maybe a door requires a key to open, or can only be unlocked from the other side, or the doorknob is missing or something (I can't help but keep thinking of the old Resident Evil games).  Or maybe I don't want to keep on accidentally exiting a building because my character walked too far close to the edge of the screen where the "invisible" front door was and it automatically makes me go outside, etc. etc.

PrinzJohnny99 - Feb 18, 2015 at 04:58
Sorry, what I meant was:
"Walk to door"
"Open door"
"Walk to door"
Next screen
"Close door"

You mentioned sometime on your blog that opening and closing doors is no good game design. I think it's awesome!

Estranged - Feb 18, 2015 at 12:34
I understand the idea of skipping doors to make the game feel smooth.
Doors however can not only be part of a puzzle, but also add a feeling of a real place. NPCs can use them, which is great too.

Matt - Feb 19, 2015 at 02:29
Of course we need doors, that can be opened and closed!
I loved how lively Melee Island felt with all the pirates walking through the town, opening and closing doors.
For me, it's an important  adventure game design element, as it is to just pick up everything that is not nailed. Opening doors feels a bit like "breaking in". You're not sure, if you're allowed to do that. But hey, it's an exploration game… oh man, sound pretty stupid, huh?

Mattias Cedervall - Feb 21, 2015 at 23:05
I understand what you mean. It does not sound stupid.

chriskringel - Feb 22, 2015 at 22:02
^ this!

Benoit Fouletier - Feb 18, 2015 at 05:19
I think ditching room-as-classes for room-as-data is a good thing.
The UbiArt framework used LUA for its data (at least at the time of the Rayman games), since LUA is essentially one giant key-value table, like JSON. (Note that this was only for data, not scripting, and production-time: data was entirely binarized in the final game).
BUT, it meant we could still execute the LUA (it was not so much parsed as evaluated), and do crazy things like importing pieces of tables from various different files, or "inherit" from a base file while overriding some values, etc. So basically we had uber-polymorphism without the clutter of classes. A kind of power I've yet to find in a prefab system like Unity.
Finally, everything was unrolled and arrived "flat" (well it's still a tree, but a POD tree, not a dynamic self-aware monster), so if you had trouble with your includes etc it was only a parsing issue, not an runtime issue. Overall a surprising simple & efficient way to approach data.

Me - Feb 18, 2015 at 07:38
Can you please make this have long loading times?
And during loading include mini games like arkanoid clones.

PrinzJohnny99 - Feb 18, 2015 at 08:25
Doesn't sound like a brilliant idea to be honest.

Mattias Cedervall - Feb 18, 2015 at 11:26
:-( No! No loading times! You can pause the game and play other games if you want!

JohnnyW - Feb 18, 2015 at 08:35
Ron, it was actually Monkey Island that lost the "WHAT IS" verb. I always thought that Last Crusade (which I'm a big fan of ) would have been a ton more fun to play with the MI interface.

Alan Moore - Feb 18, 2015 at 09:38
The simple interface debuted with MI for PC CD-ROM, I think, and then appeared in MI2 and Indy 4.

Anyway, I hope you keep the 'default' verb control mechanism, where hovering over a clickable area highlights one of the verbs (say 'open' for a door) and lets you right-click to execute it. That was really handy.

Schala - Feb 18, 2015 at 19:46
That dialogue by Detective Ray reminds me an awful lot of Kyle Hyde from "Hotel Dusk." :)

Rafa Font - Feb 19, 2015 at 03:39
Here is how I see it, as a BOX.

Or in other words, a 3-dimensional array that contains all the comments made by the characters:
- First dimension is the name of the character
- Second dimension is the object they are looking at
- Third dimension is the number of times the have looked at it.

When a character looks at an object, there would be this call:...

retrieve_text(currentActor, element, look_count)

...which will retrieve the sentence to be said.

Going one step further, the 3-d array could store the cursor for each Actor, so that you don't need to count the times it has been looked at, and the call would be like this:

retrieve_next_text(currentActor, element)

When using a different language, set a global variable that would choose if the 3-d array used is the English one, or the German one, or the Chinese one. Translators would translate the box.

How does it sound?

Joost - Feb 19, 2015 at 04:48
how about making the actor specific replies a tuple
keys could be { item, actor, action, count, line } // hmmm it already feels clunky
{
{ bankpainting, detective, lookat, 1, "You'd think a bank could afford a better painting."}
{ bankpainting, detective, lookat, 2, "This looks like a knockoff." }
{ bankpainting, detective, lookat, 3, "I think I can see the numbers behind the paint."}
{ bankpainting, detective, lookat, 4, "I'm done looking at this painting."}

{ bankpainting, child, lookat, 1, "Ooh pretty colors!"}
{ bankpainting, child, lookat, 2, "My friend Denise made one just like this."}
{ bankpainting, child, lookat, 3, "My friend Denise made one just like this."}
}

with different actions instead of lookat, you could combine all dialog for the game in one place for easy editing... but tbh I think this has a lot of potential for becoming a giant cluttered mess...

Dominik - Feb 19, 2015 at 14:56
So, how about this:
Write a function "who" that takes an actor as parameter and returns said actor if it is the current one and a "dummy" actor if it's not:

function who(IsCurrentActor) {
    return(IsCurrentActor == selectedActor?currentActor:dummyActor)
}

Then make all (well only the approriate ones) methods of an actor check if they are executed on the dummy actor or not:

function say(Text) {
    if ( this==dummyActor) return;
    [...]
}

Then you can use something like this:

who(Ransome).say("I'm starting to get angry at that paintin");
who(DetectiveRay).say("PAINTING!");
who(PurpleTentacle).say("I feel like I could....");

Of course this method could work for other stuff besides talking...

who(Ransome).pickup(this);
who(Dolores).say("No way I'm touching this!");

And then you could enhance your say method to take more than one text as parameter and acces the look_counter with a variable that is called "selectedObject" or something like this:

function say( args[] ) {
    if ( this==dummyActor) return;
    if ( args.length>1) {
        if ( selectedObject.look_counter < args.length-1) selectedObject.look_counter++;
    }
    textToSay = args[selectedObject.look_counter]
    [...old code...]
}

Then you could write something like this:

who(Ransome).say("I hate paintings",
                                    "Makes me want to shoot it...",
                                    "If only this wasn't a bank.")

Which is kind of the shortest way to do it, no?
Of course the parameter array would only work for unconditional multi-answers. But if you are planning to have a lot of them, a system like this might shorten the code.

Dominik - Feb 20, 2015 at 09:30
Uuuuh! And also you could daisy-chan certain methods:

function say(...) {
    [...code...]
    return(this)
}

function pickup(...) {
    [...code...]
    return(this)
}

who(Ransome).pickup(this).say("Yup, I got it alright").delay(100).facePlayer().delay(100).say("Why the hell did I do that? That will NEVER be useful.");

Steffen - Feb 19, 2015 at 16:23
Please give us the auto-suggestion-verb, which is used by right-mouse-click, like in MI and MI2.

Tomimt - Feb 20, 2015 at 07:11
I remember the annoyance of that "What is" option, especially in Zak McKracken it was overused in many, many pitch black locations, whee you had to first locate some hotspot, remember where the hotspot is and use some item or such to turn lights on.

Kai - Feb 20, 2015 at 13:58
No need to remember where the hotspot was. Just use What Is, and when you hit something with the cursor, click once, then double-click on the verb. Voilà.

badde - Feb 20, 2015 at 15:47
to much dark side!

Peter Campbell - Feb 20, 2015 at 17:47
For anyone who missed out on the kickstarter campaign and still hoping to get a poster, boxed copy of the game, etc. etc., they have just been added to new paypal tiers now available in the "Support Us" section here on the Thimbleweed Park website.

Garchin - Feb 21, 2015 at 20:49
Thimbleweed Park Theme:
https://www.youtube.com/watch?v=37caBIZkDhI

Academy Award Nominee "Wild Tales" theme:
https://www.youtube.com/watch?v=_ueDO0HpCQw

woow....

Flowo1974 - Feb 22, 2015 at 06:44
So? Same style, different theme....

Ryan - Feb 23, 2015 at 13:32
This is getting into territory you have said you don't like (and solving for problems you don't strictly have), but is possibly still useful based on how interesting and stimulating it is:

http://assemblyrequired.crashworks.org/gdc2012-dynamic-dialog/

(It seems likely you would have seen this, but on the chance you only ever tagged it for later reading....)

I was trying to think of a way to combine the approaches there and maybe nest the dialogue in a JSON structure similar to your rooms. I think it would simplify the multiple character issue, and fits with your need to have them organized and easily-changeable (and translatable), but it gets tricky trying to marry unique numeric IDs and variable conditions more complicated than just look_count....

Keith Irvine - Feb 26, 2015 at 03:52
Put me down as another vote for the default / auto suggestion verb. Right clicking an item for the default action was great. I think from memory the default verb was a different shade than the rest in the bottom left menu when hovering over the item on screen? Pretty sure even items in the inventory had a suggestion verb (usually use item with and then a prompt to finish by clicking on another item I think), though my memory of it is  a bit hazy.

DZ-Jay - Apr 03, 2015 at 07:26
Hi, Ron,

I just caught up with this blog and I have a question regarding the dependency charts.  This may be stupid, but I'm trying to understand exactly what sort of information it is trying to convey.  When a node has, say, two connections coming from above, does it mean that there are two paths to arrive at that node, or that in order to arrive at that node you must complete two other paths?

I know you've mentioned before that it's a "dependency" chart, not a "flow" chart; but I'm having a hard time making a distinction between them.  Anyway, thanks for sharing your fantastic work--I look forward with enthusiasm to playing the game.

      -dZ.

Nor Treblig - Apr 11, 2015 at 21:05
Your question actually describes the difference between a flow chart and a dependency chart:
On a flow chart you can follow a path and you can also arrive at a node from different paths.
On a dependency chart you don't follow a path. A node is dependent from all its incoming paths and all of them need to be fulfilled.

Hope I could help.