The Newest Code Monkey’s Report

by Jenn Sandercock
Jan 11, 2016

Ever since I formally became part of the Thimbleweed Park team I've been half itching to write a blog post, half scared silly at the prospect and wanting to cower under my keyboard. But here I am. So, no regrets, right?

Maybe before I go on you'd like to know a bit about me so you can get where I'm coming from? I'm just going to assume you're yelling "yes" at your screen right now, ‘cause that's what you're doing, right?

Ok, since you insist... I grew up playing point-and-click adventure games in their "Golden Era". Ok, fine, Ms Picky-person, I grew up watching my siblings play point-and-click adventure games (being the youngest sucks sometimes). I never thought that I could be a game developer, since that wasn't something they told us at school and I was always a super-duper square who handed in my homework on time and actually liked school.

Hopefully, I haven't lost your interest with that, I promise I've improved and I'm now a much more well-rounded individual. Mostly because part-way through finishing my Masters thesis in Artificial Intelligence I realised that I'm a game designer who can code (rather than a pure coder) and my life has been much happier since that moment.

Over my 6+ years in game development, I've dabbled in making small adventure games using AGS and Unity. Working on these small projects gave me an appreciation for the amount of work that must be involved in the old games I loved so much. So I was and still am really excited and proud to be part of the Thimbleweed Park team, even if my official title in the budget is "Code Monkey #2".

Most of the work I'm doing at the moment is understanding the engine and wiring up rooms, I mean sewer tunnels. That's right, my first proper coding tasks have been in the sewers. It's a bit unglamorous. But it's actually perfect for my first tasks. Many of the sewer tunnels are purposely very similar so as to make players feel a bit lost and confused. This makes it much easier for me to implement stuff, because I can just copy-paste all over the place, I can just copy-paste all over the place, I can just copy-paste all over the place, I can just copy-paste all over the place.

As I was doing the copy-paste dance, I realised that there were a lot of valves in the background art for the sewers. Now the vast majority of these couldn't be truly interacted with, but they kinda looked like something that you should be able to interact with (especially because there is at least one valve you can actually turn). The valves are in different rooms and I didn't want to do more copy-paste for what to say for each valve. That is, I didn't want the characters to just say "It's a valve that doesn't move" every single time the player tries to look at it. It's boring for the player and also frustrating because the player wastes time looking at the object and hearing the same line over and over again.

I was reminded of an old GDC talk by Elan Ruskin about dynamic dialog using AI and fuzzy pattern matching. In that, they talked about having running jokes about objects so that you could build on what the player knew previously. I knew I didn't want to set up something quite so complex, but I wanted to do a little something to make looking at valves and using valves a tiny bit more interesting.

To do this I needed to create code that would be run for each of the valve objects that would set up its name, whether this specific valve had been looked at and what to do when looked at. So, to create one of these generic valves, you need to create it within a room using:

sewerTunnel2Valve1 =
{
    name = "valve"
    enter = function() { sewerValveSetup(this) }
}

The object's enter code gets called every time the player enters this room. We have to name the object with a placeholder name, but we'll allow the setup function to overwrite that value so if we decide to call those things "excessively boring valve thingamabobs" we don't need to go through every room to change their name.

The setup function is defined in a new file I created called SewerHelpers.nut, which contains all of the generic code I used for the sewers (including setting up a sewer light, spinning fans, dripping water and so on).

So here's the code to create a valve:

function sewerValveSetup(currentValve) {
    // Creates a boring valve we can look at
    currentValve.name = "valve"
     if ( ! currentValve.hasvar(has_looked_at) ) {
        currentValve.has_looked_at <- false
    }
    currentValve.verbLookAt <- function() {
        valveLookAt(this)
    }
    if ( ! currentValve.hasvar(has_used) ) {
        currentValve.has_used <- false
    }
    currentValve.verbUse <- function() {
        valveUse(this)
    }
...
}

Note that if this is the first time we're running this code, we'll set that this particular valve hasn't been looked at. It will also keep track of whether the player has attempted to use the valve.

So now if the player tries to look at a valve, they'll get something different to say based on how many valves have been looked at globally.

function valveLookAt(currentValve) {
    // For if the player looks at a valve that they can't use in the game
    if ( currentValve.has_looked_at == false ) {
        if (g.look_count_valve == 0) { sayLine("Looks like this valve has been welded into position forever.") }
        if (g.look_count_valve == 1) { sayLine("This valve has also been welded into position.") }
        if (g.look_count_valve == 2) { sayLine("Why have so many of these valves been welded up?") }
        if (g.look_count_valve == 3) { sayLine("Another welded valve.") }
        if (g.look_count_valve == 4) { sayLine("Didn't I just see this valve?") }
        if (g.look_count_valve == 5) { sayLine("Lots of valves, but no Steam.") }
        if (g.look_count_valve == 6) { sayLine("This one's rusted, not welded!") }
        if (g.look_count_valve >= 7) { sayLine("Seen one valve in the sewers, seen them all.") }
        g.look_count_valve++
        // Set that we looked at THIS valve
        currentValve. has_looked_at = true
    } else {
        sayLine("It's still a boring valve.")
    }
}

So after looking at 7 different valves we'll just keep saying the same line over and over again, but at least the player got to have a bit of value for all their hard point-and-click work.

Learning how to code in Ron's engine has been lovely and much simpler than I would have assumed after hearing the words "custom engine". It's easy to use and anytime I get stuck, I just post on the Slacks and Ron or David jump right in to help out.

I've been a newbie on many projects and I'm always nervous of those first few days and weeks (yes, and months) as you get to learn the new systems. I hate that feeling of bugging those more experienced with questions that they're probably rolling their eyes about. But it turns out Ron and David are both fantastically friendly and understanding and are really quick to help me out.

As I kept bugging Ron and David I realised one of the major flaws of a custom engine. I can't just google answers and find how everyone else has tackled the problems I'm encountering.

What this custom engine needed was some documentation!! (It also needs a proper name. I suppose technically it's called ThimbleScript, but I don't think that counts, do you? Ron... get on it!)

So I got started on my next, equally unglamorous task. Documentation is one of the tasks most coders hate doing, and I'm no exception. Still, it turns out writing the documentation is really helpful to someone getting to understand the code base (yes, I'm talking about myself, shock!).

I found a list of the command names, then I had to search for them in code, work out what they did and write about it. I'd often try to include example code, yet because I had been warned that this documentation would get released to the public, I tried to find non-spoiler examples (something that was quite tough in some special cases).

I know you're on the edges of your seats waiting to find out whether I survived these tasks, and ... (wait for it)... I did! So now if anyone else is lucky enough to join the team, they'll be able to look through all the documentation and bug me instead of Ron & David!

You can check out the documentation yourselves.

Might make some of that code I just posted above make a bit more sense too!

I'm sure that's enough Jenn for today... or is it?

Someone at my co-working space brought in little pixel stickers and I got a tad overeager and put up my Thimble-Team avatar on the wall. When I'm not at my desk, it looks like Pixel-Jenn is still hard at work putting pixels in the game.

- Jenn



vegetaman - Jan 11, 2016 at 16:12
Hello and welcome! An excellent first blog post! Also -- let me just say as a software developer (with bachelors and almost with a masters), Artificial Intelligence was the one area of the field that made (and still makes) my brain hurt. My hat is off to you for your mastery of such subject matter. And I can also appreciate that introductory period of coming up to speed on an existing software system. Once you realize you can fluently work in it though, it is a great feeling (though documentation can be a daunting, if necessary, task). Welcome aboard!

Jenn Sandercock - Jan 11, 2016 at 16:39
My AI degree was a while ago, so I don't feel very masterful of that. Also, academic coding is VERY different to commercial coding. It takes a while to get your head around that. I'm enjoying coding with other people rather than on my own.

hihp - Jan 11, 2016 at 16:19
Jenn, I can only say I am glad to have you on the project! The only thing I wonder is: Does your scripting engine not have a 'case' branch?

Jenn Sandercock - Jan 11, 2016 at 16:36
Apparently it does! But it's not used in many places. I should probably use it more!

Ron Gilbert - Jan 11, 2016 at 19:00
Squirrel does have switch statements, but I've never liked them. They take two extra lines and they compile down the the exact same thing.

Iron Curtain - Jan 11, 2016 at 20:06
Do you mean to say you've never liked switch statements at all, or that you never liked Squirrel's version of them? Because after some googling, I can't tell the difference between Squirrel's switch statements and the switch statements of any other high-level programming language (such as C++, Java, or Python).

Ron Gilbert - Jan 11, 2016 at 20:23
I've never liked switch statements. I use them, but not often, mostly when I'm switching on enums.

Diego - Jan 12, 2016 at 13:20
Hey Ron.... Don´t you like squirrels? mmm haven´t you played The Legend of Kyrandia? Malcolm the jester kills the squirrels there hehe

Benoit FOULETIER - Jan 21, 2016 at 08:41
Actually they (often) don't, they compile to jump tables, so in Jenn's example you'd (more of less) have 1 test instead of 7. But it's 2016 and power is unlimited right? so whatever rocks your boat is fine by me.

Christopher Griffin - Jan 11, 2016 at 16:22
Awesome!  We get to peer behind the curtain and see documentation while the paint is still wet!  Thanks, Jenn!

Leandro Pelorosso - Jan 11, 2016 at 16:23
Excellent job on the documentation! Thank you for sharing! :)
I see there are a methods to stop threads. May I ask how are you stopping Squirrel threads from C++? I don't see a native Squirrel API function to destroy  a running thread.
Thank you again!

Ron Gilbert - Jan 11, 2016 at 18:57
When the engine stops a thread, it just stops calling it every frame. The the thread is started, we do a sq_refadd() so it doesn't get deleted, then when it stops we do a sq_release() and it will get cleaned up. We're not using threads like Squirrel normally does, we're mangling them quite a bit to get them to work like old SCUMM threads.

Leandro Pelorosso - Jan 11, 2016 at 19:08
Thank you so much for your reply, Ron! That's good to know. I ended up doing exactly that, but I thought maybe I was missing something. Thank you for sharing the insides of the engine with us, mere mortals :)

Leandro Pelorosso - Jan 11, 2016 at 21:47
I'm sorry, may I ask one more question? How did you manage to implement something like: breakwhile(Diner.hotdogs_left > 0). Wouldn't the comparison be resolved before invoking breakwhile()? Thank you again!

Zarbulonian - Jan 12, 2016 at 14:29
How you manage threads and time is the part of the engine I'm the most curious about.

I'm eager to plow up the source once you release it.

Zarbulonian - Jan 14, 2016 at 14:32
Reading the rest of the comments, I realize that I may misremember what was said about open sourcing the engine...

I was taking it for granted, I didn't want to not-so-subtly pressure you into releasing it, provided you're not sure you'll do it.

Roberto Cano - Jan 11, 2016 at 16:25
Welcome Jenn! Great post and great documentation! Yep, software developer here, I also hate documenting. YUck! I also had to learn the hard way what means not to be able to Google things, I work for a security related company, and all code base is so secure that there's nothing out there to be searched!

Looking forward to your second post!!

Jenn Sandercock - Jan 11, 2016 at 16:49
Second post?! Oh dear! Now I'm in trouble!

A man with a tape recorder up his nose - Jan 11, 2016 at 16:32
That GIF really made me smile :-)

Andrew Hanson - Jan 11, 2016 at 16:34
So great to hear from you and awesome work! I hope to advance to such a level of expertise in problem solving some day (though most likely not AI development). I'll stick to game dev and some code.

Jenn Sandercock - Jan 11, 2016 at 16:47
Game dev & coding already requires lots of problem solving. So I'm sure you're much better than you give yourself credit.

Josejulio Martínez - Jan 11, 2016 at 17:04
Are there any plans on releasing the engine as open source software?

Mattias Cedervall - Jan 11, 2016 at 17:04
Welcome and thank you for this stimulating piece of reading, Jenn! :-) Is Shigeru Miyamoto-san your primary idol within the game design community (Ron won't read your reply so you can tell me the truth)?

Arto - Jan 11, 2016 at 17:33
The engine should be named SCUT, naturally :)

Schnee - Jan 11, 2016 at 17:34
Welcome to the blog, Jenn! Great post, A++, would read again. ;)

May I make a suggestion? Switch the lines for two and three looked-at valves around; that is, have "Another welded valve." come before "Why have so many of these valves been welded up?", not after. The lines flow more naturally that way.

As for the engine's name... how about THIMM?

Ashley Barnes - Jan 11, 2016 at 17:53
This whole post sounds like an invite to add some more Valve comments.

"I might try this valve when I feel like drowning"
"This valve probably drains the local swimming pool"
"Rusty.  Like my car, algebra and sex life"
"Oooh shiny.   ...Oh my bad!  I'll try again.  ...Oooh Rusty"
"This valve might turn on if I force it.  Ha-ha!   Oh, yeah, well I dare you to make a better pun."

Arto - Jan 11, 2016 at 18:36
"This valve probably drains the local swimming pool"

Or: "Nah, might cause a nuclear meltdown."

Droygon - Jan 26, 2016 at 11:17
Wow... I'm very late to this party (crashing) but i'm soooo game :)

"This valve just might be.....PlaceHolder 239:NOT FOUND!!! ERROR ERROR ERROR LAZY PROGRAMMING!!! PLEASE DIRECT SPAM TO RON AND GARY ASAP"
"This valve looks like it could.....PlaceHolder 627:NOT FOUND!!! ERROR ERROR ERROR!!! FORMAT C: INITIALIZED... JUST BECAUSE..."
"This valve seems... hmm... WAIT!... oh never mind..."

Now I can finally sleep soundly at nights... thank you and apologies to all

Zak Phoenix McKracken - Jan 11, 2016 at 17:53
"Real Programmers don't comment their code. If it was hard to write, it should be hard to understand."
"Real Programmers don't do documentation. Documentation is for simps who can't figure out the listing."
- Tom Van Vleck, 10/25/82

Anyway, Jenn, I think you did an enchanting (look at what kind of adjective!) documentation! Thank you for your job!

Jenn Sandercock - Jan 11, 2016 at 18:16
Way to fuel my rampant imposter syndrome! ;) I like commenting code and I think documentation is pretty important!

Seriously though. I find I like to code by writing comments of what I'd like to happen and then I add the real code. Probably not super efficient and I'll never be the whizziest coder that ever did whizz, but it helps me think out what I want to happen and when.

Zak Phoenix McKracken - Jan 12, 2016 at 02:50
Eheh, I work as a computer programmer, and I usually write code on-the-fly, from mind to keyboard, in a way that often my co-workers say: "what does this code do?!"
And I answer: "Look at it, think about it, then doc it!" :-P :-P

Jenn, do you want to be a famous novelist, and are you waiting for a big break? (Cit.)

Zarbulonian - Jan 12, 2016 at 14:56
I do both, it really depends on whether I know what I want to write or not.

When I know what I want, I can write a longish, mostly correct program without leaving the editor (well, there are often a slew of syntax errors to correct, ultimately,and a few bugs that creep in).

When the picture is not clear, I like to write a pie in the sky description of what I'd like the code to do, it helps tremendously in figuring things out.

Droygon - Jan 26, 2016 at 15:00
I have been a novice programmer for a while and although I may only be in my 2nd year at the university and may not yet fully understand "The grave errors of my coding practices" - I am totally for your way of doing it... it might be because of academia practices but it helps because:

Plus:
1) It gets all that documenting straight out of the way - very little need to backtrack your way to long forgotten code.
2) You are doing it while the code is fresh in your mind.
3) It helps you define what the piece of code is supposedly going to do - I'ts a bit (though not quite...) like the difference between learning to do something and learning doing something in order to teach someone else... it sharpens you a bit.
4) You never know what you might do with the code in the future or who might be looking at it in order to contribute.

Minus:
1) Takes a bit more time - although less time if you are going to be documenting anyway.
2) It looks quite "full"\"uglier" and perhaps a bit less readable - but only on first sight and only if you really go overboard with comments.

Welcome Jenn :) and I hope to see more inside posts from you.

peterszky - Jan 12, 2016 at 07:18
And real programmers sometimes s*cks big because of this :DDD

Carlo Valenti - Jan 11, 2016 at 18:15
I would call the scripting language J.E.N.N.:
Jeopardized Extravaganza Neural Networks :)

Matt Lacey - Jan 11, 2016 at 20:33
Off to a flying start! Seriously, I might have to steam you to do some documentation :P

Alessander - Jan 11, 2016 at 21:19
Nice post and work at the wiki, M.Sc. Jenn Sandercock! I am looking forward for the open source version of ThimbleScript (working title)!

P.S.: R.I.P. Dr. David Bowie :-(

Tom - Jan 12, 2016 at 04:04
Welcome and great stuff. It is this these little touches of polish that make a game great. I hope you guys (and gals) keep it up.
But but but (I can not leave without busting your balls):
A masters in AI and all we get is a counter and a  bunch of IF statement. You have to do better before the game is finished and blog about it.
No pressure ;-)

Keep up the good work!

Jenn Sandercock - Jan 12, 2016 at 12:41
Sometimes a bunch of IF statements are exactly what's needed. The solution didn't need anything more complex than that.

Also... There was a reason I'm not doing AI anymore. It's fun, but it's not what I'm passionate about. I love gameplay mechanics and story.

Big Red Button - Jan 14, 2016 at 13:57
On the one hand it would be an interesting idea, indeed, to put an NPC, provided with an AI, into a point & click game. It would enhance the impression of a real world. For example a monkey following you even more realistically, hoping for a banana.
On the other hand it would be extremely difficult to fit something mutable, such as an AI, into a rather programmatic game, such as a point & click game. I think it wouldn't be worth the effort. The monkey on Monkey Island was realistic enough. Furthermore, that wouldn't be 'classic', though I want the game to be classic!

Tjeerd - Jan 12, 2016 at 06:27
In line with SCUMM and GRIME,  I think the engine should be called Script Programming Interface for Thimbleweed Park (SPIT).

Daniel Wolf - Jan 12, 2016 at 07:20
+1 :-)

Carlo Valenti - Jan 12, 2016 at 09:47
Approved! :)

avanti - Jan 14, 2016 at 16:59
I am amazed. It fits perfectly.

peterszky - Jan 12, 2016 at 07:20
Thanks for the great blogpost. As a programmer (BSc) this type of stuff is my favourite!

arvenius - Jan 12, 2016 at 09:02
Nice post Jenn and good work with the docs!
You might be a team "junior" but it feels good to see you helping :)

mr. T - Jan 12, 2016 at 11:00
A most excellent post! It would be so fun to set up some basic rooms of my own and dabble with the thing, so I'm kinda envious. Or how about a rad alternative: a blog post about setting up a mini game from scratch! Like two rooms wired up with one actor blob, doing just a couple basic adventure game actions. After release perhaps? Checking out the scripting docs was very intriguing, thank you :)

AK - Jan 12, 2016 at 11:54
Hey Jenn, can you give more details about the games that you've worked on? Are they available ?

Jenn Sandercock - Jan 12, 2016 at 12:46
I've worked on a wide range of games. From AAA games like LA Noire, to casual social games like Gardens of Time and an educational game too. Last year I released a mobile game called aglimpse: friends that's about taking photos with friends. All of the games I've worked on are listed on my website in the about section: http://jennsand.com/aboutMe.php

A lot of the games I've done are free since they were personal projects. My website has more info. http://jennsand.com/index.php

The little adventure games I've done that I'm most proud of were Vet Lucie Disastrous (http://jennsand.com/vetluciedisastrous/vetLucieDisastrous.php) and The Will (http://jennsand.com/gameplayMechanicAMonth/mechanic_11.php).

Diego - Jan 12, 2016 at 13:27
Excellent profile Jenn... the important question here is... are you single? hehehe  just kidding... good work!

Michael - Jan 12, 2016 at 15:44
"Lots of valves, but no Steam"

Nice one! ^^^^

EdoBvd - Jan 12, 2016 at 16:00
Very nice, thank you!
GrumpyWiki is a really nice surprise.


Non-requested possible if-line:
"I wonder if the valves turn the other way in the south hemisphere?"

Sushi - Jan 12, 2016 at 17:39
Hi Jen,

first of all, I am so jealous of you! I would love to be even "code monkey #99",
but to paraphrase a scene from Jerry McGuire,you lost me at "enter = function() { sewerValveSetup(this) }"
So I am glad you shared the documentation at this point!

What would you suggest for someone with limited programming experience who wants to try and design a small graphic adventure: fool around with AGS or just wait a bit until Thimblescript is released? Undoubtedly, thimblescript is much better, but how do the learning curves compare vs what you can achieve with it?

My daytime job involves coding, but I consider myself more as a creative person trying to find (better/new/elegant) solutions, rather than using some obscure coding constructs no-one else can understand. I like your simple if-statements. Perhaps I would have used a case statement, but that's because I am scared to introduce a bug when the variable name changes for one reason or another
;)

Jenn Sandercock - Jan 12, 2016 at 18:01
Who knows when/if ThimbleScript will get released to the public!

So I'd definitely say don't wait, start making games right away.

In terms of comparing AGS and ThimbleScript... Well... It's a long time since I used AGS so I can't entirely remember and maybe AGS has changed. I remember it being pretty easy to get started in, but if you wanted to do something a bit out of the ordinary it was hard to make it happen. I felt like AGS was goof for people who aren't good coders. So if you're already coding for your day job... I'd probably say try out Unity and the 2D tools. Unity isn't great and you'd have to do a decent amount of work before you could have simple rooms set up. But what you get from Unity is cross-platform, which is really important these days.

Still... It depends what you want to do with your game. Are you just mucking around with ideas? Or do you want to sell your game? If you're just looking to make something for yourself or close friends, then the tool you choose might be different. Sorry I can't help you out more. Good luck!

Sushi - Jan 13, 2016 at 02:06
Hi Jen,

I would just create a small adventure game for my children, called "the great adventure of cleaning up your room" :) So nothing cross-platform or intended to be sold. I'll give AGS a go.

Thanks for your reply!

Sushi - Jan 13, 2016 at 02:19
...Turn OFF lights
...Close door

It's really educational ;)

... Including lots of Sierra-like deaths each time you step on a toy that is lingering on the floor! :D

Ron Gilbert - Jan 13, 2016 at 09:29
When I was a kid, I'd just shove all my toys under my bed. It was the first place my mom looked, so I don't know why I kept thinking I could fool her.

Zak Phoenix McKracken - Jan 13, 2016 at 13:17
Zak McKracken was educational too.
If you forgot the TV on, the faucet on, the fridge door open, Zak didn't leave the dinning room, saying:
"I forgot to turn off the TV" -> automatically walked towards the TV and turned it off
"I forgot to turn off the faucet" -> automatically walked towards the faucet and turned it off
"I forgot to close the fridge" -> automatically... etc.. etc...
Then, after leaving the room, if you entered the dinning room again and then leave it, but this time everything was OK, before leaving the room Zak looked behind him, and said:
"It looks good to me."

I Love This Game!!

Bogdan Barbu - Jan 13, 2016 at 23:31
That was probably done for memory conservation, in order to not store the state of the room once the player left it. :)

Zak Phoenix McKracken - Jan 14, 2016 at 11:15
AHAH, right, in the C64 era, where memory limitation was an issue, even 3 bytes were a little treasure!

Ron Gilbert - Jan 14, 2016 at 11:24
No, it was not done for memory reasons. There would be no savings for changing the state of an object. It was done becasue that's the way we wanted it to work.

Bogdan Barbu - Jan 15, 2016 at 13:46
I don't know how SCUMM works but I wasn't talking about changing states. My guess was that unnecessary objects are destroyed once the player leaves their respective rooms, unless there is a need to keep them around. In order for the assumption that the TV is off to hold when initializing the object again, Zakk would need to turn it off before leaving. The constraints were probably not tight enough for this to be necessary.

Amb - Jan 14, 2016 at 23:19
I've always wanted to see a single room game, where the goal is to exit the room.  You are in a garage. There are two exits - the one for humans, and the one for the car.  If you just walk to the exit, you win.  If you DO anything else, you make it harder for yourself to exit.  Nearly everything you can do forcibly adds a new puzzle that you must solve to get out.  Eg Touch a woodpile, it will collapse across both doors and block you.  Touch the lawnmower and it catches fire.  Etc.

Paulup - Jan 12, 2016 at 20:03
The hard part about naming the script is finding something with a T and a P together (for Thimbleweed Park), but I've given it my best shot -

RATPOOP
Really Awesome Thimbleweed Park Object Ordering Program

Joey - Jan 13, 2016 at 01:41
I appreciate it realy, that you wrote it with what you feel and the worries in your job.

And with a blink eye. ;O)

Thank you for sharing this, wonderful written, freshful and i can read the joy in your words, also that the job makes you fun.
Hope realy to read more entries from your side, and maybe a secret here or there from Gary and Ron. ;OP

Geoffrey Paulsen - Jan 13, 2016 at 10:03
Welcome.  Glad you're on board.  Looking forward to reading your docs someday if/when the engine is open sourced.

Big Red Button - Jan 13, 2016 at 12:30
That's an interesting blog entry!

I noticed that "It's still a boring valve." doesn't contain the information that the valve is fixed. So I suggest to make it clear. For instance: "It's still a boring valve which I can't turn."

Big Red Button - Jan 13, 2016 at 12:36
I mean there will be lots of valves as you wrote. So if the player gets confused, he would be able to get a clear information about a particular valve once again.

Zombocast - Jan 13, 2016 at 15:13
Pixel Jen is missing a spot.  Yarrg!
Now I wont be able to sleep tonight.

Grafekovic - Jan 14, 2016 at 11:27
Thanks, I haven't noticed before. Now I won't be sleeping neither.

Jenn Sandercock - Jan 14, 2016 at 12:14
Pixel Jenn is NOT missing a spot!!

The pixels I used didn't have all the colours I would have liked. The pixel I think you're talking about (just below Pixel-Jenn's nose on her right) is not the same blue as the painted wall. It was a grey, but it does look blue.

It's hard to tell in the original pixel images that were posted in the team post (http://blog.thimbleweedpark.com/teamthimbleweed), but I was copying straight from that.

Grafekovic - Jan 15, 2016 at 04:13
But it looks like a missing pixel. I can't tell you at the moment if a "wrong" color makes my insomnia better or worse, but I will tell you tomorrow morning ;-)

Bogdan Barbu - Jan 13, 2016 at 22:42
The code would be cleaner, shorter, and internationalization wouldn't require scanning the whole code base if the code were reduced to

function valveLookAt(currentValve) {
    if (!currentValve.has_looked_at)
        sayLine(g.sewer_valve_line[g.look_count_valve++]);
    else
        sayLine(g.sewer_valve_line.len() - 1); // The last entry handles the "already seen" case.
}

This is a convention I'd adopt for the whole project.

Based on snippets posted on the blog and the documentation, there are a bunch of other changes I'd make in order to improve the robustness and flexibility of the code, presuming it wouldn't require *too* much refactoring. But I will stop here because feedback of this kind is often perceived as being in bad taste (for reasons that go beyond my head).

Bogdan Barbu - Jan 13, 2016 at 23:27
Err, sayLine(g.sewer_valve_line[g.sewer_valve_line.len() - 1]); in the else branch. Sorry, I typed that comment from an iPad without a keyboard, so I lost my focus because of all the slow, boring typing. :)

Franklin - Jan 13, 2016 at 23:55
My god, you're an ass. Your entire comment is you trying to show everyone how smart you are.  Your last paragraph is the height of your pompous ego.

Bogdan Barbu - Jan 14, 2016 at 02:24
See what I mean?

I actually pay people good money to tell me I'm wrong... Praise is just empty words. I obviously appreciate their work on the game, otherwise I wouldn't be here. On the other hand, negative feedback can actually be constructive.

Matthew - Jan 14, 2016 at 07:52
Still: Don't act as if you're superior, when your GUI experiments is all you have to show for. It's common-sense, Mr. Boobies.

Bogdan Barbu - Jan 14, 2016 at 09:22
Well, I'm glad you stalked my YouTube channel but (a) I never made a claim of superiority or otherwise---sentiments and engineering don't mix, (b) that's not at all "what [I] have to show", it's just some old mini-research you happened to have stumbled across and (c) argumentig from authority makes no sense; it shouldn't matter what, if anything at all, I have to "show".

If you are interested in my actual work (not a GUI engineer, mind you), we can discuss it elsewhere. Obviously, you know how to reach me.

longuist - Jan 14, 2016 at 05:25
Readability is in the eye of the beholder. Its perfectly fine how it is, the outcome counts.
But you shouldn't take a suggestion as a personal insult. If the advised code is inappropriate you should rise an OBJECTION! indeed.

Bogdan Barbu - Jan 14, 2016 at 09:46
Precisely. An objection to something isn't like an aggressive comeback, where you're super awesome by having shamed the other person. It's like people sometimes go out of their way to get offended offended.

Regarding your other remark, I only partly agree. Even though there clearly exist differences between coders, in most respects we are more similar than we are different so common ground can be found. Sometimes it's obvious (e.g., no one will argue that indentation is a bad idea) and other times it's not but can be measured (on average, by how much did this style increase or reduce development costs by, say, leading to or avoiding bugs?).

But I mostly mentioned that because it'd help with the internationalization process, not because of aesthetics.

Ron Gilbert - Jan 15, 2016 at 15:04
I think you would have fewer objections (including mine) to your posts if you asked questions, rather than stating that your way is better without knowing why we do things the way we do.  Instead of saying we’re doing it wrong and posting your code, ask why we’re doing it the way we are? I’d be more than happy to answer your questions, but when it comes across (even if it’s not meant that way) as an attack telling me I’m doing it wrong, it’s hard to respond.

So, to answer the questions as to why we do it the way we do…

Code like you posted is exactly the kind of code you will find in the engine. The very optimized for speed, memory, reliability and testing, etc. I like code like that.

But for the game scripts, I like very readable and clear code, not clever code. A game scripter should be able to look at a section of code in isolation and completely understand that it does. Jenn’s code accomplish that. You look at it and you know exactly what it is doing, including seeing all the text. We code like that on purpose. While the code you posted is good “computer science” code, it’s not immediately obvious what it does, especially since the text is divorced from the code.

Embedded text in the game code doesn’t make translations any harder, all the text is automatically extracted from the source and put into databases, any changes to the text in the code is automatically tracked and updated. I’ve been doing translation for 20 years, it a system that works well for me and keeps the text tight with the code that uses it, which greatly increases productivity and creativity.

Zak Phoenix McKracken - Jan 15, 2016 at 17:26
So, your technique to manage text for translations is not to use a resource file or constants, but to write strings directly in the script engine, enclosed with double-quotes, then use a parser or something to extract strings and put them in a database?
Then, once the text is in a DB, you can do all what you want, export to a spreadsheet, a text file, etc...
Maybe it's easier than I thought...

Mike McP - Jan 15, 2016 at 21:02
I never thought of doing it that way, but it makes sense....you can put text directly into the code without having to worry about referencing an external file.  I guess you can write a regex around "sayLine" to pull them out with 100% accuracy.  Neat trick!

Regarding the coding efficiency, I always say "Sometimes good enough is GOOD ENOUGH".  I write business code, and if I'm writing a simple function that'll be used a couple times per day, it don't need to spend 5 minutes tweaking it...speed to market is more important to my business than efficiency.  I do agree that there are times where tweaking milliseconds off a routine is worthwhile when it's called countless times in a loop, but those are exceptions.

Ron Gilbert - Jan 15, 2016 at 21:06
Yeah, there is a single regex that pulls all the text out.  I'll do a post in a few months that talks about the whole process. Keeping text with code is extremely important for creative reasons. Game programmers are not just programmers, they have a lot of creative input and power and text really drives these games as much as puzzles.

Zak Phoenix McKracken - Jan 16, 2016 at 02:18
Ron, your heart is with the Fox! :-)

Bogdan Barbu - Jan 16, 2016 at 07:59
This is going to be one big rant and may be safely skipped. (Maybe I can get away with all the advertising.)

Apart from being kind of a hack, the regex solution won't work well for certain scenarios. Although I understand that you're purposely adopting a style that tries to avoid the non-obvious, sometimes it might be necessary to play with the string before calling sayLine. In particular, a string may sometimes need to be manipulated in some way based on something that has happened in the game. (Sure, maybe it doesn't apply for TP.)

For the record, the code snippet I wrote above isn't what I would have used either. I only suggested it because it seemed simple enough to adopt in an existing code base. Coincidentally and incidentally, I had to solve a similar (but not identical) problem once and what I came up with was a simple abstract universal language with generators dedicated to each translation. In the case of adventure games, the generators would probably have to be replaced by something else, where (human) translators are more involved (I have some ideas), since good dialog is such an important part of the experience. A generator that produces natural-sounding, interesting lines tailored to each character's personality is possible but requires an unjustified amount of work. For example, the language might be used like this: *<complement <person jimmy
*, *<joke-about <X>>*, *<offer-to-buy <X> from <Y>>* where *<X>* might evaluate to *<object wrench>* and *<Y>* might expand to *<person mark>* or *<location shop>* or whatever. At first sight, this might sound too complex to bother with but it solves the clarity problem you were talking about and gives a huge amount of flexibility with regards to dynamic scenarios. Voice recording can play into it as well but it's no use going into specifics since it's not a realistic venture for this game.

As for the other issue, telling someone they're wrong is not an attack, it's the exact opposite. If you're wrong and I don't tell you, that's when I'm causing you the most harm. If you're right, then oh well. My philosophy here is to be blunt, even if it makes me less likeable. When it comes to solving problems, I don't really see the point of pampering and I don't enjoy when people do it to me. My observation is that doing things this way usually saves time and energy, cuts costs, etc. Being blunt doesn't make you right, of course, but it can really help. I don't have a problem with being proved wrong either, since being right about something is not the point at all. When it comes to other aspects of life, sure, I'll be just as considerate as anyone else. That's not very interesting.

Bogdan Barbu - Jan 16, 2016 at 08:34
Aha, the magic of the comment section is revealed. That was a double "greater than" character that messed up the layout.

Finc - Jan 23, 2016 at 07:08
Ron gives you a fair reply.
You don't take anything on board.
Why not save everyone time and just stop commenting for a while?

longuist - Jan 17, 2016 at 05:38
The advice is true. It should be skipped.
And you are doing it again, for a reason beyond my imagination. If you had read Rons answer carefully enough AND had ACCEPTED its meaning you would have replied nothing at all.
All your points are valid, from your guessed and assumed point of view.

Phoenix would say: "Your Honor! That statement contradicts this evidence!"

Bogdan: " [..]  Sure, maybe it doesn't apply for TP. [..] "

DZ-Jay - Feb 16, 2016 at 06:29
I'm a little late to the party, but I'm just catching up with old blog entries.  I'm not even sure who will read this now, but I felt compelled to answer.

Mr. Barbu, perhaps the hardest thing to understand sometimes is that there may not be a single, One True Way of solving a problem; and that your solution is just as valid, efficient, measured, elegant, or practical, as someone else's.  In such cases, the only difference between the solutions is that only one came from your own initiative.

Accepting this fact as part of human nature -- or just life in general -- is a very hard lesson to learn, one that apparently has eluded you.  I know you will probably disagree with my comments above (just as strongly as you have disagreed with Mr. Gilbert's position), but here's my point:  that's quite alright. :)

I will leave you with a quote from Shakespeare, which seems rather a propos to aid in this lesson:

    "There are more things in Heaven and Earth, Horatio, that are dreamt of in your philosophy."
    -- Hamlet

    Best regards,
      -dZ.

Augusto - Jan 20, 2016 at 04:43
Nice way of handling text! I remember doing something similar a long time ago, but I wasn't as smart so as to keep the texts in the code. I replaced them with the calls to the function that looked them up in the dictionary, losing all the expressivity the text could give.

The only thing that I did was to add a comment above with the original text. :(

Looking forward to see how you actually handle this, because I guess that must mean you do some sort of preprocessing before compiling to actually replace those strings with the actual calls!

Thank you!

Zak Phoenix McKracken - Jan 14, 2016 at 11:21
Do you mean... this? http://i.imgur.com/d43Fd.gif

longuist - Jan 14, 2016 at 18:25
Exactly :)

Zak Phoenix McKracken - Jan 15, 2016 at 05:34
That's the reason of that "Phoenix" as the middle name in my nick :-)
Ace Attorney is the second most beautiful game I've ever played!

Jihan - Jan 14, 2016 at 09:27
Reminds me of the "empty hut" running joke from the original Monkey Island game. Very nice!

Morphez - Jan 15, 2016 at 06:09
Welcome to the project, it's good to have you.

Zombocast - Jan 15, 2016 at 14:41
RON, we need a fan art contest. And the winner gets their art "in game" as a pixel poster in ThimbleCon!

Ron Gilbert - Jan 15, 2016 at 14:50
That's a great idea!

AndreasAT - Jan 15, 2016 at 16:09
If two characters would say different things when they use the valve, is this handled in the valve code (if actor == ray: sayLine.... elif actor == reyes: ...) or do you load a new "translation" when you switch characters, that has different sentences for using the valve (language: EN_US_RAY, EN_US_REYES)?

Ron Gilbert - Jan 15, 2016 at 21:45
It would be done with IF statements, the translations need to stay exactly what the text is and it's based on language, rather then character.

Augusto - Jan 20, 2016 at 04:47
Nice post, Jen. Thank you so much for the work you're putting into the wiki, that's a great resource that already gives hints on how the engine is made.

Feeling a little bit envious :) (well... a LOT actually!) ;)

Augusto - Jan 20, 2016 at 04:48
I meant Jenn, not Jen.

Sorry!

Droygon - Jan 26, 2016 at 14:54
YES!!! (screaming at the screen... neighbors thinking... all is STILL normal with me... weirdo guy next door...)
(a bit late... sorry)

Welcome Jenn  :)

I wish you a warm stay with your new team and hope you write more and feel welcomed by all. I think posting here could be a really nice place to rest, vent and express yourself in a non-formal and friendly forum about things that are on your mind.

Hope to read more of your views... no pressure :)

Droygon - Jan 26, 2016 at 15:33
....and as for the name... just do what many have done before: Take the first letter of 4-6 people who most contributed to the writing of the engine and\or game code and mix them into the most horrible\silliest\memorable\dirtiest sounding acronym you could think of... easy

If you can't find it - consider adding\dropping people with suitable letters just to make it so... lawyer\water-boy\janitor and the likes... heck, why not call it JANITOR (Jenn-And-Notable-Important-TeamMembers-Of-Ron or Just-Another-Novel-InterNational-Team-Of-Revolutionaries)... hmmm I just kind of like the name JANITOR for an engine... especially for an old-school engine... if you don't use it I will :)

madatoman - Jan 26, 2016 at 19:18
Hi Ron

It is so great to see you working on classic point'n'click games again. The art style looks more Maniac Mansion than Monkey Island. And the interface alone is very nostalgic to see. Great post and great progress so far! Can't wait to play it for the next 25 years!

Leo - Feb 04, 2016 at 15:50
Hi, Jenn, your first post is cute. You all in the Thimbleweed team are great, I love you. :)

Amb - Feb 14, 2016 at 15:01
Another Valve comment I would really love to see

"This thing looks like it was welded by a Krogoth"

SigKILL - Aug 07, 2016 at 17:52
So, how do you get the lambda like (multiline) functions to compile in Squirrel, e.g.:

cutscene(
@()
{    // Do main cut scene commands here, like regular code.
    playObjectSound(soundHandDryer, QuickiePalBathroom.quickieDryer)
    actorPlayAnimation(currentActor, animReachMed)
    breaktime(2)
    ...
},
@()
{   // This is called if player presses ESC
    fadeOutSound(soundHandDryer, 0.5)
    ...
} )

Is there some trick? I thought it looked cool, and wanted to try it myself, but Squirrel is complaining about a missing "=" during compilation...

Ron Gilbert - Aug 07, 2016 at 18:21
I changed the compiler. @() { ...} is not standard squirrel syntax.  I think you' have to write function() { ... } for standard squirrel.

longuist - Aug 08, 2016 at 07:02
I guess this change is not only of aesthetic nature?! Mind to elaborate a bit more?

SigKILL - Aug 09, 2016 at 17:10
Yes, function() {...} seems to work perfectly :)