Pulp Game Jam dev log: Neven & Dave's game

Here's the finished game:


Pulp-importable JSON:
I Was Dead, But.json.zip (v1.0.1, 42.8 KB)

Playdate-ready PDX:
I_Was_Dead_But.pdx.zip (v1.0.1, 115.3 KB)

And here begins our original devlog from the jam:

I'll be working on a Pulp game with my friend David Wester. His strengths include music, sound, and writing. I'm a monkey at a typewriter.

We brainstormed on the theme and retired to our corners—him, to noodle on some "scary" music; me, to code up some quick crank-mechanic prototypes. We've decided we want to create something crank-driven, and deliberately not using the "top-down player walking around rooms" approach Pulp is best suited for. Why do things the easy way, right.

Here's what I have so far:


When doing things in PulpScript based on ranges ("if the crank angle is between 45º and 90º…") there's a lot of this:

on rotateCompass do
	if angle<292 then
		if angle<247 then
			if angle<202 then
				if angle<157 then
					if angle<112 then
						if angle<67 then
							if angle<23 then
								swap "r1"
								swap "r45"
							swap "r90"

It's a little silly, but it's also simple and—with a little commenting—pretty clear.

Next, I'll see how convincing I can make rotation look in Pulp. The little compass arrow there turns within its tile, but can I do it with a larger control? Let's find out…


In our game, we sometimes want to do things based on time. There’s a global ticking clock, and also a “local” one, timing you from the moment you enter a particular room, for instance.

Here’s how I do that:


on loop do	
	time += 1	

Then, let’s say I want to do an intro sequence where text is printed line by line:


if time>10 then
	label "Malthusius Mansion" at 1,1
if time>30 then
	label "November 22, 1961" at 1,2
end :a:
if time>50 then
	label "A FULL MOON" at 1,3

(this is in a function in the [start] room; I call it from the [player] script, since labels have to be drawn there.)

The effect is:


P.S. I’m sure you can work out how the :a: is done. It responds to the [player:confirm] event, btw.

Shaun points out that Pulp already has a built-in time tracker: event.frame. Nice!

1 Like

Pulp has several ways to show dialog: say, label, menu. A specific feature I wanted in our game is an RPG-style avatar of the speaking character.

You can of course embed tiles in text, like so:

say "{embed:person} WITCH: Oh no you don't!"

which would give you something like:


This is cute, but I wanted large, expressive avatars—4 or even 9 tiles in size—plus some additional character info. Like so:


I could draw all this manually using swaps, but that’s a lot of swaps. With 5 characters in the game, I needed a more automated system. Here’s what I ended up with.

The game logic sets the currently speaking character:

dialogPerson = 5

Then this [dialog] room draws like such:

on drawDialogAvatar do	
	tell 4,10 to
		swap "p{dialogPerson}t1"
	tell 5,10 to
		swap "p{dialogPerson}t2"
	tell 6,10 to
		swap "p{dialogPerson}t3"
	tell 4,11 to
		swap "p{dialogPerson}t4"
	tell 5,11 to
		swap "p{dialogPerson}t5"
	tell 6,11 to
		swap "p{dialogPerson}t6"
	tell 4,12 to
		swap "p{dialogPerson}t7"
	tell 5,12 to
		swap "p{dialogPerson}t8"
	tell 6,12 to
		swap "p{dialogPerson}t9"

So, 9 draws for 9 tiles. It expects the tiles to be named like p1t3—person 1, tile 3.

When creating these, I make the first tile (p1t1) then hit Duplicate 8 times. Note that this automatically increments the number—Shaun made it so that tiles with numbers at the end up the number when duplicated. Super handy!

Adding a new character is now just a matter of defining them and drawing their 9 tiles. I draw those right on the canvas (to see what I’m doing), then remove them from the canvas before running the game.

P.S. The info is drawn like such:

if dialogPerson==5 then
	label "CHESTER COOKE JR." at 9,10
	label "Assoc. Account Manager" at 9,11
	label "Seeks meaning of life" at 9,12

I could also set these 3 lines to variables and have one block that draws them all, but I figured this was good enough, so why add extra variables. If the game needed to use these fields elsewhere, I’d use variables.

1 Like

Our game’s main view has five people seated around a table:

Some of them will leave. Could be anyone at any time. How to best script this?

My first idea was to simply copy the room and remove a person in each copy—that avoids the tedious work of replacing tiles that make up one person’s image here. BUT. What happens when the second person leaves? It could be any two people—#1 and #2, or #1 and #3, and so on. I can’t have a separate room copy for each permutation. So it seemed like I’d have to go back to replacing tiles…

…unless. Unless I used the dangerously seductive fill function. It draws a filled rectangle, at any pixel coordinates. Pixel-level drawing in Pulp—gasp!!

So I can do something like:

fill "black" at 12,51,29,45


There are still two tiles that need to be manually touched up, but that’s not too much work.

In the end, I created these:

on removePerson1 do
	fill "black" at 12,51,29,45
	draw "p1table1 2" at 5,9
	draw "p1table2 2" at 5,10

on removePerson2 do
	fill "black" at 43,40,33,35
	draw "black" at 6,9
	draw "p2table1 2" at 6,10
	draw "p2table2 2" at 7,9

on removePerson3 do
	fill "black" at 78,33,44,41
	draw "table top" at 10,9
	draw "table top" at 11,9
	draw "table top" at 13,9
	draw "table top" at 14,9

(I found the coordinates by pasting a screenshot in Photoshop and drawing the rectangle shape there to cover up what I wanted, then looking at its properties.)

I can now very easily remove arbitrary persons:

tell event.room to
	call "removePerson2"
	call "removePerson4"


It might not “matter,” but a Launcher card for your Pulp game will make it feel so very grown up. Here’s the first crack at ours:

(Title possibly temporary.)


Is there a way to preview the launcher card on the web player?
Or is this something which can only be done on device and the sdk simulator?

1 Like

There is not but you can see a preview in the editor on the Game mode (where you set the title, author, etc).

yeah, I’m aware of that but was just wondering if there was a way to see the launcher card when you launch the game in the browser.

I think this is a good idea for the web player. Until it’s implemented here’s a way to achieve the same thing: Move your player to your card room and in their draw handler add something like:

if event.room==“card” then

And then in their confirm handler something like:

if event.room==“card” then
    goto x,y in “start”

(Sorry about the smart quotes in the code samples, I’m on my phone :playdate_crying:)


Will give that a try!

Here’s our jam game!


Pulp-importable JSON:
I Was Dead, But.json.zip (v1.0.1, 42.8 KB)

Playdate-ready PDX:
I_Was_Dead_But.pdx.zip (v1.0.1, 115.3 KB)

If you find any showstoppers, let me know and I’ll reupload. Now, I’ll post another reply with a postmortem of my experience on the game.


This game was built by me and my friend David Wester. Our friendship dates back to our days of doing improve/sketch comedy together. I have some amount of skill with art and coding, Dave can write and compose.

There were some things we wanted to do before the jam theme was known:

  • “Indirect control” of the player/game
  • Something with a story and dialog
  • Use of the crank

After getting the theme—scary heartbreak—we brainstormed it, and felt that “scary” mapped onto “indirect control” pretty well. We didn’t want to do a romantic heartbreak, so we talked about other kinds: failed investments, dashed hopes, general disappointment.

It occurred to us that ghosts are a good candidate for “indirect control.” A poltergeist doesn’t just walk in and announce themselves; they mess with stuff around the house to get their message across. Something about the radial nature of the crank led us to a round seance table, where you choose the seance attendee to haunt.

The technical foundation

IWDB (I Was Dead, But…) has no visible player character. Instead, it presents a series of mini games with their own challenges. Your main room is that seance table:

CleanShot 2021-11-22 at 16.15.40

The pointer-finger is controlled using the crank. This works the way you might imagine:

on turnFinger do
	// remember the previous selection; it could be handy
	previousTablePerson = tablePerson
	if angle>280 then
		// seat 1
		if angle>300 then
			// seat 2
			if angle>340 then
				// seat 3
				tablePerson = 3
				tablePerson = 2
			tablePerson = 1
		if angle<80 then

This took a little bit of sketching on paper, but it was fun and not all that challenging in terms of “math.”

Probably the biggest piece of work in the game was hooking up the dialog. Instead of using simple say statements, we wanted a custom dialog view with a large avatar:

This is its own room, which looks like this:

To say a line of dialog somewhere in code, we call

dialogLine = 1
goto 1,1 in "dialog"

On entering the dialog room, it steps through a huge if-then-else chain to say the right line:

if dialogLine==101 then
	dialogPerson = 1
	call "drawDialog"
	say "Oh dear, I'm feeling faint. Would you mind if I stepped into the other room and sat for a spell?"

drawDialog is a function in the same room which draws the avatar (out of 9 tiles per character) and the character description:

tell 4,10 to
	swap "p{dialogPerson}t1"
tell 5,10 to
	swap "p{dialogPerson}t2"
tell 6,10 to
	swap "p{dialogPerson}t3"
if dialogPerson==3 then
label "PROF. MALTHUSIUS" at 9,10
label "Medium, Guru, Yogi, CPA" at 9,11
label "Seance Organizer" at 9,12

This is a little tedious, but it only had to be written once.

Another slightly slow task was drawing the “illustration”-style art, instead of sticking to 8-px mazes.

I’ve had some experience doing this in Pulp in the past, so it was fun.

Beyond this, we’d love it if you just played the game!


Players have found a number of bugs in the game—some showstoppers—so we’ll be fixing them and reposting the game :slightly_smiling_face:

Reposted at the top. Hopefully this one is stable!


This was so fun!! Loved the concept, the writing, the execution… really fun and funny and unique. Thanks for sharing :slight_smile: