Pseudo Rooms
Jan 05, 2016
Welcome to 2016. It sounds so futuristic. The other day and was joking around with Clayton and I said "Yeah, maybe in the year 2016!", just picking some random date that seemed like the far future, but ironically, it wasn't. As a kid who grew up in the 70's, the year 2000 was a future filled with marvels and space travel. It was the year we picked to say "a long time from now in a world we can't even imagine."
OK, in all honesty, I don't think I could have imagined the Internet, Twitter or the iPhone, so maybe it wasn't that far off. I write this on a computer that runs billions of times faster than what sent the astronauts to the moon and has so much memory that I will never run out.
Back as Lucasfilm, Chip Morningstar used to joke that the perfect computer would have an infinite amount of memory and an expansion slot for more.
For Thimbleweed Park, I have that. Maybe it is the year 2016 after all.
We've been blogging about the game for a year now. It's been a lot of fun, but also a lot of work. Writing one or two blog posts a week, plus recording and editing a podcast takes an amazing amount of time. Oh, and I have a game to make.
"Yeah, yeah, cry me a river Mr. Gilbert! Get on with the blog post!"
The engine has remained pretty stable for the past few months, mostly bug fixes and small features here and there. David, Jenn and I are finally getting to the point where we understand the engine enough that we can code in it without a constant fight.
Last week I added a new feature to the engine called Pseudo Rooms and I thought I'd spend our time together this week telling you about them. Grab a stool and relax while I spin a tale of mystery and deceit. A tale of adversity overcome and triumph of the good. A tale of... oh who am I kidding, it's a bunch of source code.
We used Pseudo Rooms in the SCUMM system to construct a group of rooms that were based on a single template. We used them mostly for evil maze, but not always.
In Thimbleweed Park, the Edmund Hotel is 13 floors tall, which means 11 floors of rooms once you eliminate the penthouse, the lobby and the mezzanine (ThimbleCon ‘87). Each of those 11 floors has 10 hotel rooms, so for the math impaired, that is 110 hotel rooms. We could have defined 110 hotel rooms in art and code, but that would be grueling and inflexible.
So once again, I dip back into the SCUMM pool and pull out Pseudo Rooms. Pseudo Rooms allow us to define one hotel room and then use it as a template to construct as many other rooms - all at run-time - that we need.
It's important that they are truly separate rooms so any state changes that happen in the room (turning on the TV, the bathroom sink, etc) are remembered for each room. We could write special code to track that in a single room, but that's a lot of extra work. It's much better if they are truly separate rooms. The other issue is Ray standing in room 307 and Ransome standing in room 610. If it was a single room, you'd see them both, but we need them in separate rooms without a lot of hoop-jumping.
Pseudo Rooms to the rescue.
You define a Pseudo Rooms using the (spoiler) command...
This create a new room called HotelRoom101 based on HotelRoom. You can put an actor in it and treat it like any other room.
The code to build the entire hotel is as follows...
for (local floor_id = 3; floor_id <= 12; floor_id++) {
local floor = definePseudoRoom("HotelHall"+floor_id, HotelHall)
floor.floor_number = floor_id
for (local room_id = 1; room_id <= HOTEL_ROOMS_PER_FLOOR; room_id++) {
local room = definePseudoRoom("HotelRoom"+((floor_id*100)+room_id), HotelRoom)
local door = floor["hotelHallDoor"+room_id]
door.name <- "Room "+((floor_id*100)+room_id)
door.hotel_room <- room
door.verbWalkTo <- function() {
enterRoomFromDoor(hotel_room.hotelRoomHallDoor)
}
room.hotelRoomHallDoor.hotel_floor_door <- door
room.initRoom()
}
}
And the template room code is...
{
background = "HotelRoom"
enter = function()
{
setMapLocation(CountyMap.mapHotel)
if (objectState(this.hotelRoomRadio) == ON) {
startthread(playRadio, this.hotelRoomRadio)
}
}
exit = function()
{
stopSound(soundThereminLoop)
stopSound(soundRadioMusicLoop)
}
initRoom() {
// Change the color of the bed.
objectState(this.hotelRoomBed, random(1,3))
// TODO - Change other things.
}
hotelRoomHallDoor =
{
name = "door"
flags = DOOR_BACK
hotel_floor_door = null // Door on hotel floor to come out of
verbWalkTo = function()
{
enterRoomFromDoor(hotel_floor_door)
}
}
hotelRoomPhone =
{
name = "telephone"
verbLookAt = function()
{
Phone.receiverOff = FALSE
Phone.whichPhone = this
cameraInRoom(Phone)
}
verbUse = function()
{
Phone.receiverOff = TRUE
Phone.whichPhone = this
cameraInRoom(Phone)
}
verbPickUp = function()
{
verbUse()
}
}
hotelRoomRadio =
{
name = "radio"
initState = OFF
verbLookAt = function()
{
if (objectState(this) == OFF) {
sayLine("It's turned off.")
} else {
sayLine("It's turned on, and tuned to 198.7 FM")
}
}
verbUse = function()
{
if (objectState(this) == OFF) {
objectState(this, ON)
startthread(playRadio, this)
} else {
objectState(this, OFF)
stopSound(soundThereminLoop)
stopSound(soundRadioMusicLoop)
}
}
}
hotelRoomBed =
{
name = "bed"
verbLookAt = function()
{
sayLine("It's a bed.")
}
verbUse = function()
{
sayLine("Not sleepy.")
}
}
}
We'll probably use them for evil mazes as well.
- Ron
Maybe it can be a bonus thing, like, not relevant for progress but unlocking a special ending...
How long did it take to have this template for the room up and running?
Prototypal inheritance FTW!
[half way through song]
Guybrush: "Hmm, maybe I should write this down."
At that point I paused the game, then panicked to find a pen and remember the order of the bones they'd already sung up to that point - I figured this was a cruel joke by the developers!
I didn't notice that Guybrush had written it on the 'spit-encrusted-paper' until my second play through, I guess I'd figured there was no writing implement in his inventory to write with, and it didn't occur to me to check regardless!
Thing is, looking back, I love the game all the more for it :)
Please allow me to offer a code-refactoring suggestion:
How about adding local room_postfix = ((floor_id*100)+room_id)
and then using "HotelRoom"+room_postfix and "Room "+room_postfix
Stuff like that is gonna avoid major headaches during QA ;)
Cheers,
Ralph
Thanks for the code insight, I live for that insight of elegent simplicity :)
* Go on, Google these.
One digit for the floor, and two digits for the room.
So you would have room 300 or 301 to room 309 or 310 on the 3rd floor, and so on. I don't think you'd see rooms ending with "11" or higher.
(I hate to explain a joke)
That's another thing, how are you planning to do the halls of the hotel? I at first pictured a long hall, from left to right, where all the doors to the room will be along that one side of the hall. That would surely be the easiest to do, but might seem a little weird within the game space and exterior design of the hotel. I like the aesthetics of the exterior of the hotel; will the layout of the rooms change a bit to match the exterior?
I hope there's a housekeeper with cart who seems to always talk about weird ways to remove stains from things:
http://www.hospitalitynet.org/news/4026910.html
Weird that I found the first one on the National Center on Domestic and Sexual Violence, but these inspection checklists are kind of neat reference material:
http://www.ncdsv.org/images/HOTELINSPECTIONCHECKLIST.pdf
http://www.houstontx.gov/fire/business/hotelmotelinspectionguide.pdf
Plans:
http://www.simpsonsoverseasproperty.co.uk/downloads/Dickinson%20Hotel%20Floor%20Plan.jpg
https://upload.wikimedia.org/wikipedia/commons/8/87/Floor_plan_of_hotel_rooms..jpg
I don't think I could have imagined the Internet either.
Are you also going to vary the exterior view of the hotel depending on in which rooms the light is on?
I assume that several rooms will be occupied. I'm curious about if the agents are going to disturb some hotel guests.
Or are you including the Hotel Hall as one of those rooms? Stairwell?
So, you could also use a loop to call all the DefinePsuedoRoom constructors, too..."HotelRoom"&floor_id*100+room_id?
Are you planning on putting something special in a random room? I'm sorry if you mentioned this...but it's this hotel going to be mostly vacant? Because of Thimblecon? Wait. Is this a convention of thimble collectors?
So many questions now for the next Q&A podcast.
Just don't add random scarey stuff like twins on bikes, blood out of elevators, and little boys screaming Redrum!
local door = floor["hotelHallDoor"+room_id]
Is this essentially some kind of pointer? We've already defined a local "floor". Now we're assigning some derivative value of floor to door. When I see brackets I usually think arrays, but it's weird seeing a string value in there.
I'd also like to see the HotelHall constructor (or whatever you want to call it). You'll have 8 doors (9 including stairwell doors) and an elevator. How do you put the room numbers on the rooms?
floor["foo"] is the same thing as floor.foo
There is no constructor for rooms.
Thanks, Ron!
Or just Easter eggs.
Also David was surprised in his elevator-post about how many people enjoyed the Zak bus logic. Too bad he stated that the elevator logic has been made simpler, but maybe it's for the best because if there is no puzzle where one has to switch while one is riding it to open some door etc., it might be a red herring.
"Each of those 11 floors has 10 hotel rooms" vs. "const HOTEL_ROOMS_PER_FLOOR = 8".
:-)
You've created the blueprints to the 1997 movie Cube.
Each room has a different way to die, and only by reading the markers can you tell if its safe, odd or even!
You have doomed us all!
There is something I´ve always wanted to know... what happened with SCUMM program files? Did George keep the originals? or it´s just lost?
Do you have images of how it was? any screenshot?
Happy 2016 Ron.... and keep going on! I´m learning a lot of things from your code.
<%Humourous Cynicism%>
$ExplainHowAmazeYouAre
if ($Mood <= AVERAGE) {
$AddAnHintOfCritisism
}
<%End of Humourous Cynicism%>
<%End of Pseudo-comment template%>
Also, it has been said a few times that free help often doesn't work out, because without incentive there is no accountability (or maybe reliability is a better word). To make sure that deadlines get met and that the project is a priority, it's better for all involved that they be paid for their time. Of course, nobody was suggesting that free help CAN'T work.
Think of the opportunities, Mr.Gilbert. Think.