I've been working on some incarnation of some sort of board/card game for about six months now, and it's finally to the point where I want to start talking about it. I've done a few playtests of it with friends, plenty with myself, and thought I would start blarghing about it and have a place where people can download the in-development print'n'play PDFs.
The theme of the game is that the players are a group of siblings who have to convince their parents that the thing they're being accused of (which, if the first player wants to come up with it, can most certainly do!) was not their fault, since they were actually deaing with a series of escalating lies...er...events, each one getting more fantastical than the last! You can embellish those lies a little to make them sound better, but talk fast, because if your siblings finish their stories before you do, you get trash duty for a month!
The game has the following mechanics:
The primary one is a number-based press your luck card stacking scoring mechanic like Lost Cities.
There are multiple possible chainable actions that cards allow you to perform, much like Dominion if you could chain Buys and Actions out of order.
There are card modifier cards, like Gloom, but playing them isn't the whole focus of game, like it is in Gloom.
First player selection is not arbitrary ("oldest player", "last one to ride on a train", etc.). The first player is the one who starts the game by revealing the highest value card out of anyone else. This makes it more difficult for them to complete that stack of cards, but lets them go first, potentially gaining a lead over others. This is similar to how the start player in Innovation is selected.
In the first expansion, there is a card "tucking" mechanism, like tucking under splayed cards in Innovation.
There's a little bit of "gotcha" player attacking through the removal of cards from other player's stacks, or taking a card from other players' hands, but it's not the focus of the game (so no Munchkin level 9 grinds, but it can get pretty brutal, as we've found in playtesting).
Theoretically, if the players wanted to, they can roleplay a story a bit, like in Gloom. :)
I have one expansion already designed and somewhat playtested, but not thoroughly. It's more of an idea at this point. It adds more cards and a new action one can take. It's all in the rules. :) You can check out the rules in this Google Doc and download the latest version of the game from this Dropbox link. I'll be posting stuff in /r/tabletopgamedesign as well as here. Feedback should go to Reddit or Twitter.
So I needed a JavaScript-y component for a Rails application I was working on, and I didn't want to build it in Backbone because I'm sick of making a ton of JavaScript templates, and I wasn't going to rewrite this entire Active Admin-based application as a JavaScript app for this one component, so I decided to give AngularJS a spin. All I wanted was an easy-to-build component that would read in and dump JSON data to/from the app for this particular field, to be processed with a form object on the backend. Here's what I learned:
It's seemingly easier than I thought
The tutorials and documentation make this seem really nutty and complex. If all you're doing is reading/writing some POJO (Plain Old JavaScript Object, the JS equivalent of my good friend PORO) in your controller, this is all you basically need on your page (assume it's already wrapped in a <form> tag, since it lives in an Active Admin Formtastic call):
Then in your JavaScript...well, CoffeeScript (outside of a jQuery.ready block):
app = angular.module('myapp')
app.controller 'ThingsController', ($scope) ->
$scope.things = [ { name: 'hi', subthings: [ { name: 'bye' } } } ]
$scope.$watch(
'things',
->
# look! an u-u-u-u-u-u-pdate
console.log($scope.things)
# that true below means "deep dirty check", and $watch will not execute
# your callback if you don't set it. normally $watch only checks the
# object properties to see if they have changed, and won't look at
# nested properties. slower, yes, but whatever.
, true
)
$scope.addThing = ->
$scope.things.push($scope.thing)
$scope.thing = {}
That's basically it for something simple.
Simple controller/model nesting is easy and barely documented
Yeah, this works as expected, but good luck finding an example of it anywhere:
I had upgraded Apache on a server a while back, and one of the sites on there still uses Server Side Includes. Whatever. Anyway, the upgraded site's SSI directives stopped working. I neglected to check the included module list first, thinking that if I had missed the module, then the Includes Option and the server-parsed handlers would have just exploded. Nope, they just failed silently with the module not loaded. Added the module back in and it all worked swimmingly. Color me confused.
I have a spam trainer script in Ruby that goes through the messages on my Citadel server, picks the ones in the spam folder, trans SpamAssassin with them, then deletes them. It hasn't been working for a while, so I decided to dig in and find out why.
Net::IMAP was throwing a ton of parse errors at me. One of the spam messages was being a jerk, and it was tough to find out which one. So for now, I decided to make my Net::IMAP use more robust.
Net::IMAP does a few things when it can't parse a message:
It closes your connection to the IMAP server
It raises a Net::IMAP::ResponseParseError
After a little experimentation, and liberal use of Net::IMAP.debug, I found that it's possible to recover from these errors and proceed to the next message. All you need is a Net::IMAP factory. My code is roughly something like this:
def make_imap
imap = Net::IMAP.new(*args)
imap.authenticate(*sugarpuck)
imap
end
imap = make_imap
imap.select("Spam")
imap.each do |message_id|
begin
message = imap.fetch(message_id, "BODY[TEXT] ENVELOPE").first
do_stuff_to message
rescue Net::IMAP::ResponseParseError
# imap won't work anymore at this point, so reconnect and reset the source folder.
# the original enumerator above seems to continue to work
imap = make_imap
imap.select("Spam")
end
end
In my final code, I wrapped Net::IMAP in a SimpleDelegator, had it remember what was last selected, then added a reconnect! method to reconnect to IMAP and (potentially) reselect the same folder.
I just discovered ActiveRecord::Relation#merge. Being able to reuse and factor out all those well-tested finders for database data is really going to make my life easier:
class ThingWithRelation < ActiveRecord::Base
def self.a_finder
where(cats: 'Dogs')
end
def self.another_finder
where(rats: 'hiss').group(:cats)
end
end
OtherThing.joins(:thing_with_relations)
.merge(ThingWithRelation.a_finder)
.merge(ThingWithRelation.another_finder)
There's a bunch of guides for this already, this is for my own purposes. Make a Plain Old Ruby Object look and act like an ActiveRecord one enough to let Rails use it for things like forms and collection rendering and the like:
class MyPoro
include Virtus
extend ActiveModel::Naming
include ActiveModel::Conversion
def persisted?
false
end
end
Yeah, I wasn't updating this, so I'm just going to cancel it. It was basically a good rigorous test of publishing features of this new system anyway, so it served its purpose. On to other things!