A Room With a View…of the Courtyard

After a too-long PAX-and-New Character Art-based build hiatus, I’ve updated the Early-Access Beta build 4 times in the last week or so!  It feels good to be updating the game for the beta testers again! There are a lot of small fixes and features in these builds, but the two big ones are the addition of chat rooms and a brand new map, Courtyard.


In the old days, we walked to the only map, the Ballroom, uphill, both ways, and we liked it.  Eventually, after a couple years of playtesting on that single map, I decided to test my working theory that making new and interesting maps for SpyParty wouldn’t be too terribly hard, at least relative to something like doing the AI and animations for a new mission.  In other words, I was working under the assumption that because most of the gameplay in SpyParty is based on the character behaviors and the perception and deception mechanics, doing new maps would be a relatively easy way to add new gameplay.  The maps would obviously be important and add a lot of variety to the game, but their layouts would not be as crucial to the feel of the game as they are in a shooter or a platformer.  I mean, Ballroom itself is just a box and everybody seemed to like it!

So, I tested this theory by adding the Balcony and Veranda maps, and I’d say the theory was proven to be true, since both of those maps worked well and people like playing them.   The Ballroom is still the go-to map for serious play because it’s the most tuned and balanced, but the other maps add some spice and hint at how the game will feel with lots of different settings and map topologies.

On the runup to PAX, I had an idea for a new map where the statues would be centrally located, but the Sniper couldn’t see them all at the same time.  I was wondering how that would change the Inspect Statue and Swap Statue missions, which have turned out to be two of the riskiest missions for Spies to attempt.  My original thought for this level was a single statue right in the center, but I decided that would be too hard, so I settled on three statues embedded in a central pillar, where the Sniper can only see one at a time.

I hacked this map together one night at PAX, and we playtested it the next day.  The initial tuning was way too hard for the Sniper, not to mention how hard it was to get your bearings.  After some tuning, and Wessel’s suggestion of using a statue of Alan Turing to give the Sniper an orientation reference point, the Courtyard seems to be working out well.   I think I overcorrected a bit and the statue missions are now a bit hard for the Spy again, and it needs more playtesting and tuning, but it’s definitely already interesting and fun to play for both roles.

Current stats for Courtyard look like this:

Game Type Total Games Spy Wins
 all  420 172 (41%)
Known 3 14 10 (71%)
Known 4 32 14 (44%)
Known 5 18 6 (33%)
Pick 3 of 4 63 27 (43%)
Pick 3 of 5 14 8 (57%)
Pick 4 of 5 90 28 (31%)
Any ? of 4 15 4 (27%)
Any ? of 5 174 75 (43%)

You’ll recall there there are currently three game types in SpyParty, “Known n” where the Sniper knows the n missions the Spy will try to accomplish, “Pick n of m”, where the Sniper knows the m missions available, but not which n ones the Spy picked, and “Any n of m”, where the Spy can choose which n to accomplish opportunistically during play, rather than having to pick them ahead of time.  We’ve started abbreviating these k4, p4/5, a3/4, and so on in the beta chat and forums.

As you can see from this table, the different modes have different levels of handicapping between the players.  I’ve just gathered these numbers from all the games on the Courtyard map, so this is totally ignoring skill differences, early games where players were just testing out the map, and the like.  But, it’s still interesting to see the balance.

Unfortunately, as you can see, the Any game types are missing their n parameter.  As I started gathering this data, I realized I’d screwed up and left that number out of the database for Any game types, so I can’t tell if the a?/5 games are a3/5 or a4/5, which is a bummer, because it makes a big difference in difficulty for the Spy and Sniper.  I’ll probably have to ignore old Any games when I do real ranking with this data.  I’ve since fixed it,1 and although there aren’t enough games with the new correct data yet to be statistically significant, here they are:

Game Type Total Games Spy Wins
 all  46 16 (34%)
Known 4 9 0 (0%)
Pick 3 of 4 15 9 (60%)
Pick 4 of 5 1 1 (100%)
Any 3 of 4 1 0 (0%)
Any 3 of 5 1 0 (0%)
Any 4 of 5 19 6 (31%)

Chat Rooms

Soon I will be opening up the beta, and this (hopefully) means a lot of people will be playing SpyParty simultaneously, at least towards the end of the closed beta when I send out the rest of the invitations and into the beginning of the open beta when anybody can sign up and play immediately.  The old lobby had a single room, and when 10 or 12 people were in there chatting, it got a bit hard to keep track of who was talking to who and what they were saying.

So, I did the simplest chat room design possible, with the goal of load-balancing the lobby if there were 30 or 100 simultaneous users chatting.  I basically decided to put all the room creation and multiple-join/leave commands on the chat console, and have the GUI only allow you to select a single existing chat room at a time.  This way advanced users can hang out in multiple chat rooms and make new rooms, but newbies can just join one and chat and play a match without thinking too hard about it.

The jury is still out on whether the current chat rooms work very well, and we’ll have to wait until I invite more people in to see if they solve the load balancing problem, but they’re certainly slightly confusing at the current density.  I tried to make sure joining “Headquarters” (the default room that’s always there) was easy enough that you didn’t have to think about it and it acts just like a single room lobby if there aren’t many people online, but I didn’t want to dump people automatically into a chat room for fear of causing problems when the game was scaled.  We’ll see how it works out.  I foresee a lot of changes in this code and UI as the number of simultaneous users goes up.

One change I made shortly after releasing the feature was adding a “Created by <username>” line in the chat room description.  Since users can create any rooms they like, this will at least keep people honest, or at least culpable!  Before I added this players were creating rooms that sounded official, which was funny but probably fraught with peril.  I also don’t support hidden rooms or password protected rooms or anything yet.  I’d like to keep the community from segregating as much as possible for the time being.

On the subject of chat, I really need to do something soon about my text rendering code, it is incredibly slow right now:

checker: /fps
SpyParty version v0.1.2202.0
19.869 ms/frame (fps: 50.33)  sort self - current frame
zone                                                     self     hier    count
 checkerlib::simple_font::DrawStringOrthoPixels       18.6377  18.6377    54.78
+chat_display                                          0.3964  16.6585     1.00
 SwapBuffers                                           0.2445   0.2445     1.00
+IdleFinal                                             0.2400   0.4846     1.00
+_global                                               0.0582  19.8692     0.00

Logging Performance, etc.

There were a bunch of other smaller fixes, one of which other programmers might find interesting:  I use the spypartyhelper.exe to write the log files now, rather than having the main spyparty.exe write them out.  The helper has always done the crash dump management (using a modified version of Google’s Breakpad) and the auto-updating privilege escalation, but now I also have it handle logging, using a named pipe from spyparty.exe.  The reason I made this change was some machines (like my main development machine) would happily write out the logs in the main process without affecting performance at all, even though I had commit mode turned on for the log file.  I used commit mode so if the game crashed, the log file would contain the most up-to-date log entries, so when the helper grabbed it and put it in the crash dump report and uploaded it to my server I could use it for debugging.  However, on some machines, the commit mode logging would take hundreds of times longer, and I couldn’t figure out what the difference was between fast and slow machines.  What’s worse, it became clear that a lot of beta testers were assuming the game just loaded slowly, which subtly (or not-so-subtly) affects how you feel about the game, even though all the time was being spent writing log statements.  Once I realized people were suffering with slow load times, I knew I had to fix it.

The weirdest bug I fixed involved the Spy playing the cough animation as soon as control was taken from the AI.  The cough animation is supposed to be played when the Spy bails out of a conversation too soon after saying “banana bread” to contact the Double Agent.  I added the cough because some people were cheesing out and running away from the circle before the contact animation had finished, and it was too hard for the Sniper to spot this glitch.  So, the cheesers got a big surprise a few builds back!  But, it shouldn’t be happening in a new game if you haven’t even done anything yet, and beta testers couldn’t get a good repro.  Well, after a bunch of debugging, it turned out I wasn’t clearing a timer in the Contact Double Agent situation on new game, so if somebody was shot within 2 seconds of a “banana bread”, then since they were moving at the start of the next game but the timer hadn’t expired, the situation decided they’d cheesed out of the conversation and made them cough.  Yay for cross-game bugs!  I guess it was the ghost of the previous victim making the Spy cough!

Mail Deliverability

Man, sending mail reliably on the internet today is fraught with peril.  I’ve been trying to figure out how often a beta invitation or confirmation mail simply doesn’t get delivered, or gets dumped in a spam folder.  So far, I’ve struggled with and been victorious getting SenderID and SPF working, and I’m still wrestling with DKIM, but I am confident I’ll prevail…eventually.  Of course, all the major mail clients use different standards.  I guess I could just pay a mail sending service to handle this for me, but it just seems crazy if I’m forced to do that to get mail delivered.  Then again, I’ve wasted a ton of time dealing with this, so maybe it would have been worth it.  I tend to think the learning and understanding I get from working through these problems myself is worth the time investment, but that could easily be rationalization, who knows?!

Update:  I think I have prevailed in the email war.  I’ve got all the major email providers2 verifying my DKIM and SPF records.  I had to battle php messing up newlines which confused the hash, SELinux disallowing postfix from talking to opendkim, and whole bunch of other randomness.  My only problem now is with AOL, and their postmaster just admitted the problem was on their side and they’re fixing it.  Hopefully that is the end of any spyparty.com email going into the spam folder, woohoo!  I sent out 500 invites tonight to celebrate, which brings us to  2011-05-11 06:35:21 US Central Time on the in-order invites.3

  1. I’ve tested the results with beta member “tytalus”, who was very patient! []
  2. Out of 20k beta signups: gmail 56%, hotmail+uk+live 14%, yahoo 7% aol 1% []
  3. I do 60% in-order and 40% random in each batch. []


  1. Quirken says:

    hah, statue of Alan Turing. How gosh-darn appropriate!

  2. Keith says:

    In light of practicing SpyParty, i would like to make the following observation about your picture. You are giving up one conversation circle and physically seeing two statues (only matters with swap), and only a tiny tiny bit of window spots. Other than that you know everything.

    General / Clarice ( blue dress ) / Danger P Jackson ( black, orange suit ), are all in the hidden conversation circle.

    Virginia (fat orange), is on the right statue ( she either is picking up the statue or putting down. Start counting or stop counting, either or. )

    Everyone else is clearly visible for your observational needs.

    If BB goes off exactly now, immediately exclude Flawn ( blue suit ), Sue ( chick at left statue ), and Virginia (right statue). Highlight Cybil ( red dress ), and Pembrookeberton ( yellow jacket, green pants ).

    All in all, i’d give that particular spot a 9/10. You know whenever anyone picks up a statue, you see 3 conversation circles, and if time gets added you know a butt load of people it’s not. 

    I’m more of a conversation watcher myself so i’d be in favor of dropping a view of one of the statues and seeing the 4th conversation circle instead.

    Also, isn’t there only an ‘Any 3 of 4’? There is no ‘Any 2 of 4’ or ‘any 1 of 4’, so shouldn’t ‘any ? of 4’ = 3 of 4? 

    A huge portion of any ? of 5 is most likely any 4 of 5. I know a few people who play a butt load of a4/5 on the courtyard. 

    Awesome stats though, interesting to see the balance. p3/4 is  46%! That’s pretty darn close to 50. 78 games isn’t a terrible sample, not the best but not bad.

    • checker says:

      Yeah, on some maps there are only a few modes, which would allow me to narrow down the choices, but on a significant number of games that’s not true, sadly.  Maybe I’ll try to upconvert the old records that are saveable.

  3. Scallii says:

    Ulbgh. Want.
    I’m exorbitantly looking forward to beta access, rather far forward, as my left brain won’t stop reminding me, but that hasn’t kept Buckswaggle III out of my dreams. With that said, make a SpyParty map that requires using and understanding mirrors. Or reflections in still water or something. Or music. Or shadows. Or don’t. It’s fun imagining these variants regardless. It really, really is. And no medium of any sort has ever had that power over me. (Least of all a video game that’s likely to have its movie rights sold before it’s actually released.) So for that, I thank you. Thank you, Chris Hecker, you socially mature genius.

  4. DavidR says:

    “I used commit mode so if the game crashed, the log file would contain the most up-to-date log entries”

    ^ Is commit mode actually necessary for this purpose? I was under the impression that provided you flush the buffers correctly with fflush() et al, the rest of the work (buffers->disk) took care of itself, irrespective of whether the process exited suddenly or not (because surely the buffer->disk half is an OS wide thing associated with write caching etc.?)

    • checker says:

      I have an out-of-process exception handler installed, so the buffers are not written out at the point when the program crashes, at least in my earlier tests.  I used to grab the log file and dmp when the exception happened, but now I set a flag in the helper process and wait until the main process exists, so the system buffers might have been flushed by then, but these aren’t just system buffers, I think the standard library is free to buffer as well, so who knows what state the writes will be in.  Doing logging through the pipe just eliminates all the questions, and the helper app is in control of the dmp and log.

  5. Quirken says:

    I haven’t played SpyParty in a while, but I was rather pleased to read the progress in the email (and new maps!)

    And I was tickled that you added an option to mute the screaming! Thank you!

    • checker says:

      At first I muted it completely, and it felt kinda wrong, so now I just make it really quiet so it doesn’t wake the loved ones, but you can still hear it and get the reaction, and it’s better. It’s actually in the prop file, so you can set it all the way to 0 if you really want it to mute.

    • Quirken says:

      I haven’t played with it yet, but that sounds perfect :)

    • Quirken says:

      (as-is; I don’t think I’d need to set it to 0. I don’t mind the sound, I just don’t like the reaction it gets :D )

I have temporarily disabled blog comments due to spammers, come join us on the SpyParty Discord if you have questions or comments!