Happy Valentine’s Day, Belated

The ever-awesome ZeroTKA had an awesome idea for a Valentine’s Day surprise, and then my daughter gave me a cold and I couldn’t get it done for the actual day.  But hey, it’s still Valentine’s Day in Damon’s heart.

This build, v0.1.2487.0, was supposed to be a quicky, but it snowballed bigtime.  Here are the release notes from the private beta forums:

Uh, this was supposed to be a quick update.

  • add idle timestamp to invite confirmation if player is idle
  • s/In Lobby/In Room/ in lobby status
  • auto-idle state in lobby after 5 minutes of no input to SpyParty
  • display away message when playing
  • tiebreaker for both players hitting spy or sniper at the same time in match menu – kind of a hack
  • wait a bit after putting down briefcase
  • couriers never stand on a pad to pick up or put down briefcase
  • ambassador won’t put down briefcase unless it can be picked up without standing on a pad
  • display game type and level on match results screen
  • Happy Valentine’s Day (belated due to a cold) – thank zerotka for the awesome idea!
  • pointier convo arrow
  • reenable previous talker arrow
  • add concept of “important” NPCs (like green statue swapper)
  • sort important NPCs higher/lower than unknown cast
  • put a grey bar on them in the portraits on result screen
  • play microfilm failure animation if bailing on action test
  • drink events for accept, reject, offer, waiter giving up
  • okay/good/bad -> white/green/red in mission preview text
  • much more visible sniper crosshairs
  • try harder to find a spot if you’re forced to go to pedestal
  • delay forcing swapper until outside min radius and then random timer
  • finally solved the mystery of the floor pad rotations, old click-to-move ui vestige, thanks kcmmmmm!
  • round event for cast member picking up pending statue
  • handle room name escapes before eating whitespace
  • ignore escape until endgame results synced to avoid lobby kicks and disabled Spy/Sniper menu items
  • setting to not print /help on lobby entry
  • allow big lobby font, allow ellipsis in settings and lobby escape menu
  • Damon at least looks at the corpse, for god’s sake
  • arrow ui for conversation talking turns
  • version number in screenshot name
  • toby offers drink and waits until accept or refuse
  • break up too-long chat lines correctly with wrapping
  • settings in lobby escape menu uses new lobby layout
  • small timestamp font, only do time, not date (clipboard still gets full date)
  • sync up /time format
  • block actions while putting down or handing off briefcase
  • allow Toby to go more places and offer more drinks (like the back side of Balcony, which he basically was afraid to visit)
  • new walking bug tuning, midpoint, tighter radii, etc
  • display autolock animation times correctly in spy disk
  • move ambassador personal space radius in a bit so not as jumpy
  • bulge cy2 pillar out a bit more, but NPCs really hug it, better practice this or get shot by r7
  • whiter whites for your username
  • fix bug if spawn at convo center you’re going to
  • if you’re finishing convo because you’re lonely, and somebody shows up, go back to listening
  • retry look areas if your spot is taken
  • clear the customer’s queue so don’t take drinks long after waiter leaves
  • make veranda front a little wider for pathing sanity
  • walking people count as violating ambassador’s personal space, so spy can’t twitch
  • version check content package to avoid weird bugs
  • fix lobby chat crash bug
  • draw cast bars with quads, size properly
  • sort known-to-sniper cast members low, unknown (like seduction target, no-suspected double agents) high
  • splash screen works on wineskin (non-transparent)
  • expand results screen portraits on mouseover now that we have a mouse on that screen
  • fix results display for multiple consecutive time-adds
  • only push round events if playing
  • push round event on shift-m add time
  • flicker ambassador ui during leaving, not go to red (ST color)
  • grey outlines in results, not yellow

So, the briefcase/floor-pad thing is kinda huge. Having to actively reject Toby is kinda huge. New green swap is big. I don’t even remember what else. Yikes.

Chris

One Bug’s Story, or, Assume it’s a bug!

This is the story of a bug in SpyParty.  This story has a happy ending, because the SpyParty beta testers are amazing, and they are constantly helping find bugs, of course, but they are also constantly helping me reproduce bugs, and narrow down the potential causes of bugs, and triage them, and are generally providing me with incredible support so I can make the game better.

This bug also has an interesting story, because it turned out to have a very subtle cause, one that manifested itself intermittently in ways that looked almost random, and for a long time there was no “repro case”.  Getting a repro on a bug is the key to fixing it, as I discuss in the How to Report Bugs the SpyParty Way post.  It can make the difference between a 10 minute fix and a 10 day fix…or never managing to find and fix it. 

*shudder*

But let’s start at the beginning…

I first noticed the bug long before I’d invited people into the beta, but it was so rare that I didn’t prioritize finding it, and in fact I would forget about it for stretches of time.  Yes, I make notes of bugs I see, but I’ve got so much high priority stuff to do right now that I don’t go back and look at that list very often…the important bugs get fixed immediately, but a bug like this can stay in for a long time.

So, what’s the bug?  Well, let’s go to the videotape:

YouTube Preview Image

This video was from a Spy Commentary game played between buxx and dieffenbachj, two early beta testers who were some of the first to upload gameplay videos.

It turns out, in addition to just being plain awesome for games overall, the rise of videos and streams is also an amazing resource for bug finding and fixing!  The more people record their games, the more they’ll be able to point to a video of exactly what went wrong so the developers can see it almost first-hand.  The bane of a developer’s life is a bug report that says, “the game broke” with no other description.  You know something’s probably wrong, but it’s basically useless for finding a problem.  With a video, you can usually see exactly what’s going on, so that problem is eliminated, or at least massively reduced.

So, as you can see in that video, the Spy is facing the wrong way on the floor pad.  The Spy should be facing the pedestal with the statue on it in that position, but in this case the Spy is turned 90 degrees.

I watched buxx‘s videos when he posted them1 and I noticed this, and so I posted a bug in the Bugs Forum on the private beta website myself on May 6th, 2012.

Obviously, trying to repro it by replaying the steps in that video was fruitless.

Next up, bishop caught it with a screenshot and posted on May 13th, 2012:

It’s a perfect shot, but his next post is “I haven’t had much luck on the repro.”

ardonite chimes in the next day:

I got the rotation bug once at a statue.

I think I was rriiiiight in the bounding box. So maybe if it’s on a border pixel of the box then it glitches out?

Edit: no, hypothesis incorrect.

That’s how it goes: make a hypothesis, check it, repeat.

More shots every couple months over the summer from bishop and r7stuart:

Still no repro.

This entire time—in fact since I first saw it myself pre-beta—I’ve been trying to resist thinking it’s some kind of “numerical issue” with the code that handles the facing angle.  Yes, angles are finicky to deal with due to wrapping, but I’ve found programmers, including myself, tend to immediately go to vague concepts like “floating point error” for anything like this.  To fight this tendency back when we were working on physical simulation code together, Casey Muratori and I developed a mantra:  “Assume it’s a bug!”  It means that instead of assuming it’s some subtle floating point error creeping in, or anything mysterious like that, it’s almost certainly just some dumb programming bug.  That mantra has never failed me.  It’s always just a plain old bug.

Onward…

In the fall of 2012, streaming SpyParty took off bigtime, and so people were recording their games more often, and we started to get more videos, this one from r7stuart in October:

YouTube Preview Image

And tytalus in November:

YouTube Preview Image

I saw this last one live on tytalus’s stream, and grimaced when it happened, but also was happy to have more data to some day find a repro, or just have a random brainwave and fix it by intuition.2

At this point, people were reporting NPCs doing it, which at least made me happy, because it meant it wasn’t a tell.  Tells and anti-tells3 are the most serious SpyParty bugs, because they undermine the delicate balance of the game, so I proritize them highest, even above crash bugs sometimes!

A couple on New Year’s Eve from jorjon:

Then two clips from streams, the first from slappydavis, who’s Seduction Target appears to do it at the bookshelf on January 6th:

YouTube Preview Image

And then from james1221 on January 12th during the SpyParty New Years Cup Tournament:

YouTube Preview Image

Both of these are different, however.  In both cases, the NPC is being blocked by another character, and instead of repathing to a new place, they just wait until the blocking character leaves.  This is both good news and bad news.  It means it’s easy to project this bug onto other bugs, it means there are other bugs,4 and it means all the real examples of this bug so far have involved the Spy.  I don’t mention this last part in the hopes that nobody notices.  Luckly it’s rare enough that it’s not going to be a game balance changer even if it is a tell.

Finally, kcmmmmm finds a reliable repro on February 7th, two days ago, and 8 months after the first post in the Bugs thread!  These pictures are beautiful to me:

You can stand at that position, with that camera angle, and repro the bug most tries.  He also figures out that it’s very camera angle dependent, which is another clue, but once I could repro it locally, its remaining time on this earth was measured in minutes.

I had some trouble reproing it reliably here, including a couple wild-goose chases where I thought it wouldn’t repro with the debugger running5 or in my debugging modes,6 but in the end I got a case where I could catch it in the debugger, and I looked at the source, and there it was, suspiciously rotten code.

It was an old check from when I used to support click-to-move, as opposed to direct-control of the spy.  There was a case in the code that would check if you were clicking on the bookshelf itself, rather than the floor pad in front of the bookshelf, and it would helpfully direct you to the floor pad.  The position part of this got taken out long ago (I think), but the angle part remained in, so when the Spy stopped moving, if the mouse was over the bookshelf that code would return the angle for facing the bookshelf.

Wait, you say, there’s no mouse cursor in Spy mode?  Ah, yes there is, it’s just hidden and forced into the middle of the screen.  So, most of the time it hits your back, but sometimes, if you’re turning or leaning down or whatever when you stop, it’ll miss you and hit what’s behind you, and if it hits a bookshelf on the frame when you stop, you get the wrong facing angle.

Now, with this knowledge, go back and watch the videos and look a the pictures above.  Always a nearby guilty bookcase, isn’t there? 

But wait, you say again, what about the very first video, the green bookshelf is nowhere near the middle of the screen!  Ah, but buxx uses a controller,7 and the mouse gets hidden but doesn’t get centered if you’re using a controller!  It probably should, but it doesn’t.  So, buxx‘s hidden mouse pointer is probably off to the right of the window, over the green bookshelf, until he moves one pedestal pad to the left, and then the mouse pointer is no longer on the bookshelf, and he faces the right way!

Awesome, all the cases explained, and the bug was trivial to fix!

Okay, there’s actually one more case in the Bugs thread I didn’t post here, because it’s funny enough that I’m going to make an entire post about it soon.

So, just remember, always, Assume it’s a bug!


  1. …because they’re great for learning, the only thing better than video is commentated video! []
  2. This happens in programming a lot, but you don’t want to count on it if you don’t have to. []
  3. Where the NPCs can do something the Spy can’t. []
  4. duh []
  5. Sometimes this happens with an uninitialized variable, since the debugger initializes most memory to zero for you. []
  6. Could mean some debug code was correcting for the bug? []
  7. You can see the action UI in the video uses the controller icons! No detail is too small to matter in a bug! []

Full Commentated Live Casting for Tournament Finals, January 19th, 7pm PST!

Update:  Here’s the video of the finals match between  james1221 and bl00dw0lf with the full commentary!1

YouTube Preview Image

I am ludicrously excited about this!  If you follow this blog and SpyParty on Twitter or Facebook,2 you probably know I’ve been really interested in live streaming recently.  In fact, just the other day I set up the SpyParty Streams Notifier and I’m writing up a longer post about that and streaming in general, and I was recently interviewed by Chris Priestman on Indie Statik about the growth of streaming for indie games, along with Erik Svedäng who’s working on the awesome Clairvoyance, which makes great use of online replays. 

You may also know we’re at the final game of beta-tester insight’s SpyParty New Year’s Cup, which has been a really fun and exciting set of matches, most of which have been live streamed or at least recorded and posted after the match.  Watching the live streams and chatting with the other viewers during the games is incredible.

Even grizzled live streaming veterans are having a blast with the tournament streams!

So, what better to do than combine the tournament and the focus on live streaming and go all-in?

We are going to live commentate the finals match of the tournament between james1221 and bl00dw0lf, re-streaming both sides of the match to a single stream we can fade between the two views dynamically based on context, and we’ll have expert level commentary by virifaux and ky, with occasional color by me.  ky is going to play director while he casts, picking the best view from the two streams, just like the dude in the video truck at the Super Bowl!  We tested all the technical and social aspects of this today, it worked incredibly well, and you can see the results here, with a test game between james1221 and slappydavis:

YouTube Preview Image

Check out ky‘s awesome temporary name tags for this test, whipped up in mspaint while we were streaming!

Tune In

So, at 10pm EST / 7pm PST / 3am GMT,3 on Saturday, January 19th4 point your browser to the SpyParty twitch.tv channel:

http://twitch.tv/spyparty

If today’s practice session is any indication, it’s going to be totally awesome!

Assuming this goes as well as I hope, we’re going to start doing this kind of casting more often, with a rotating mix of commentators, so leave comments here on this post with feedback on what you saw and let us know if you liked it, or if there’s anything we can change to make it even better!


  1. As a youtube commentor pointed out, I shouldn’t have had the winner above the video because it ruins the surprise! []
  2. And now Google+, because the world definitely needed another social network! []
  3. sorry! []
  4. 20th if you’re GMT []

Live streamed interview tonight, January 10th, 8pm PST (GMT-8)

Sorry for the late notice here, but tonight, Thursday, January 10th at 8pm PST (GMT-8), beta tester and live streamer KY1 will interview me about SpyParty, Spore, and other topics, and in between we’ll play some matches.  We’re going to stream both sides, which is always awesome!

Edit:  this happened, and it was a ton of fun!  KY asked some great questions, Vinny showed up and asked questions about Spore, and the vinesauce crew had some great audience questions and played mass-Sniper!  KY posted the whole thing:

YouTube Preview Image

It was supposed to go 1 hour, and we went 2 hours and 41 minutes.  Oops.  Since it’s so long, here are some highlights KY picked out:

0:00:00 SpyParty Discussion
0:15:16 Match: Veranda, Courtyard
0:22:00 SpyParty Discussion
0:41:37 Match: Balcony
0:53:10 Spore Discussion (Interviewer: Vinny/Vinesauce)
1:11:43 SpyParty Discussion
1:31:05 Jedi Snipe
1:50:14 Match: Ballroom
2:18:08 Chris says “Banana Bread”
2:20:23 Promotion Replay, Closing Statements

KY streams at vinesauce.com, a fun community with hundreds of people watching the stream every night.  There were around 400 when he was streaming SpyParty last night, for example.  The chat there blazes by so fast I think I can only read 1/10th of it even when I’m paying full attention.  KY assures me I don’t have to try to read it while he’s interviewing me.

It occurs to me now as I’m writing this post I should have taken a screenshot when KY was streaming SpyParty last night, but instead, have a tank.

I’m going to stream the interview as well at the SpyParty twitch.tv account, so you can watch both sides of the games we play.  We’ll both post the archives on youtube, and I’ll link them here when they’re up.  If you’re going to listen to both sides, you probably want to mute one or the other unless you like a lot of reverb in your life.

KY has been very patient.  He’s been wanting to interview me about SpyParty since he joined the beta. His playtime is 40:15:02, he’s played 869 games, and he’s going to destroy me when we play, just to be clear. When he first asked, I told him to hold off on the interview until the beta was open, which I assured him would be sometime in October.  Last year.  Since then he’s been playing a lot of SpyParty, being a great member of the community, mentoring new players, and occasionally inquiring about that interview, always politely, until finally I felt bad typing “so close, just hold off a bit longer” for the 50th time, and we decided we’d do an interview now and then another one after the beta was finally open.2

Should be a fun time, so tune in tonight!3


  1. ky in-game because I don’t support capitals in usernames, to the perpetual chargin of ZeroTKA, who will forever be zerotka []
  2. Sooooon! []
  3. Does “tune in” work any more as a saying? []

SpyParty New Years Cup Tournament Starting Tonight!

I have a lot of bigger posts queued up, but since this is time-sensitive, I wanted to quickly post that SpyParty beta tester insight‘s New Years Cup is starting tonight, with a match between darwin and drawnonward, and will be streamed live at 1am US PST (GMT-8) at http://twitch.tv/drawnonward. You can also sign up for the SpyParty Streams Notifier to get timely notifications of streams when they go live (one of the queued up posts is about that)! Here are the brackets:

This image should be live updated. If not, click here for the updated brackets!

I hope players do lots more tournaments in the future, and I’m thinking spectation will really help with that when I get it in. Live commentated SpyParty tournaments, so awesome!

Match Schedule

I’ll post these here as they become available, and update it with archives after the games are played:

Match Time Stream? Video?
drawnonward vs darwin Jan 3 1am PST (GMT-8) archived match
slappydavis vs menelaus34 Jan 3 7pm PST (GMT-8), 2pm AEDT archived match
insight vs varanas Jan 3 4pm GMT nope, but recording for youtube
canadianbacon vs james1221 Jan 4 5pm PST archived both sides! bacon & james
charliewoo vs skrymir Jan 4 10am PST  archived match
james1221 vs tytalus Jan 6 7pm CST archived both sides! james & tytalus
charliewoo vs menelaus34 Jan 6 archived match
insight vs bl00dw0lf Jan 9 6pm EST recording, not streaming
darwin vs soolseem Jan 9 6pm PST archived match
james1221 vs darwin Jan 11 10pm EST archived match
menelaus34 vs bl00dw0lf Jan 14 10pm CST archived match
Finals!
Bronze Match: menelaus34 vs darwin Jan 17 video
1st Place Match: bl00dw0lf vs james1221 Jan 19 9pm CST full commentated live stream!

Player Stats!

tytalus has put together some stats for the players based on the leaderboard information. Eventually I’d like to make all the stats available via an API so people can do cool stuff with them.

The Tournament Rules

This is from insight‘s post on the beta forums introducing the tournament and calling for players.

All are welcome! This is in no way serious competition and players of all skill levels are encouraged to join.

The Format:
The tournament will be organized into a random single elimination style bracket. I’m going to do single elimination in order to make sure this tournament gets finished in a timely fashion. Assuming this runs smoothly I think double elimination would be ideal.

Competitors will be responsible for contacting each other to arrange a mutually agreeable time to play your match. Each group of matches will be played over a period of 3 days. Please do not sign up if there will be periods of three days where you will not be somewhat flexible to find an hour to play.

The Games:
Matches will be played as 6 rounds total. Players can decide to either alternate between spy and sniper, or one player can play 3 rounds as spy in a row, then switch. The player with the least games played plays first as either spy or sniper.

* Players will decide which map format they would like to play. *
* If players cannot decide on a format, they will default to format #1*

Format 1: All rounds are played on Ballroom. Any 3 of 4 missions.

Format 2: Each set is a different map.
- 1st Set: Ballroom. Any 3 of 4 missions.
- 2nd Set: Balcony. Any 2 of 3 missions.
- 3rd Set: Courtyard 2. Any 4 of 5 missions.

If players are tied at the end of the 6 rounds, they go into sudden death. The players play sets of games until one player loses both.

The Schedule:
Each group of matches will be three days in which time all matches must be completed and reported by 12:00am EST ( UTC -5 ). There will be one day in between each round for updating the brackets.

Semantics:
Round: A single game between two players on a single map.
Set: A pair of rounds between two players on a single map, alternating roles.
Match: A collection of sets.