New Game. James Mallard.

30 April, 2015

So, I have rejoined the crew at Good Games for the new season, which I think is up to 11 or so. Everyone has lost count.

As Wizards have so sadly and unnaccountably put a pillow over 4th ed and shot it in the head, the new campaign is 13th Age, which bills itself as a more lighthearted story-centric game system. I’m sure the group will have no trouble playing the game in this spirit, and not dragging perverted sex, drugs, or senseless murder into the game. Our adventuring group will definitely and most certainly not be burning down any orphanages this time.

I’m actually quite pleased to be playing a straight-up hero, which is kinda what the idea is, and taking a break from Mr Emo Azroth and Mr not-a-nice-man Korgul – to play Superman rather than Batman for a bit.

(Not to mention Mr Inquisitor of Yog-Sothoth the Eater Of Souls need I say more. Although he is violent good fun and we intend to whack a dragon Sunday.)


(I have lost my notes of the session. Damn.)

As something of a powergamer, for me cheese comes before story. Yes – I’m a bad person. Chat on the mailing list and week before last seemed to indicate that there was a spot in the party for an arcane caster. I haven’t played a Wizard down at GG, so “sweet!”. Andy suggested that I could go for something interesting from the 13 true ways splatbook – Occultist or a hybrid. Occultist didn’t really appeal. I really liked Commander, and thought it would be nice to resurrect Baharash. Wizard seemed a bit – dunno – you get the chance to do one cool thing, whereas Commander involves buffing the other party members every round, which I like because it makes the game more of a team thing.

Then I realised that these two classes – mechanically – would work really well together. Drop your Wizard Color Spray when the escalation dice is even, other rounds do your commander thing to build up command points. The commander commands are immediate actions that won’t stop the wizard casting spells.

EDIT: the Occultist has a similar mechaninc, but the rules state that doing things related to other classes makes you “lose focus”, which means you can’t do the occultist immediate actions. A Commander accumulates command points as the fight progresses and I don’t see anything to the effect that you lose them by doing other things.

For stats, I initially took “Strategist” which makes your commander powers Int instead of Cha based, and dumped Charisma. But on a closer re-reading of the rules, these game features don’t bypass the hybrid class “key ability” table. You have to pump Int and Cha both. The 13th age rules for calculating your defenses savagely penalise minmaxing. In the end, I wrote a program to run through the permutations of the 28-point buy and class/race ability bounses, and found the best one for my purposes. it’s 10, 14, 14, 14, 10, 14, with a +2 bonus on Int and Cha to bring them up to 16. Yes, anything less than that flat means you are taking some (to me) unacceptable penalties.

All that remained, then, was to justify this in story.


I felt that “Commander” class meant that my dude has a military background. But Wizard? Well – any army in a fantasy setting is going to have some battlemages! I felt that a commander needed to be an experienced noncom or maybe a green young officer. I went officer-technically-but-not-actually-having-any-authority. “Oh right,” commented Drewf at the table, “so he’s basically an officer cadet”. I can live with that.

How did he become an officer? Well – his family bought a commission.

So James Mallard comes from a well-off family, maybe even very minor noblity, and pretty much everyone is a Wizard. James is a second (maybe third) son, and father – not wanting to put all his eggs in the one basket – decided to put James in the Army.

“But father! I wanted to be a wizard!”
“Well, son, you’ll be an army wizard, and that’s the end of it.”

Rather than skills, 13th Age has you put points in “backgrounds”. When you need to make a skill check, you argue with the DM that one of your backgrounds is relevant.

James has done some of his officer training. Mainly book knowledge at this point. He knows a fair bit about the geography of the empire, he could – I dunno – hazard a guess at how long a march is likely to take, have a fair idea how to set up camp, might even be able to operate a ballista (by which I mean, order dudes with muscles to operate it), or just know that it would be dumb to try. I’m calling this “military stuff”. Four points.

Because he is a specialist wizard, he also has magecraft, magical studies – that kind of thing. Four points.

And two points of “being bought up as very minor nobility”. He could probably go to a posh dinner without making an ass of himself, ballroom dance passably although not well, and has some idea of whose coats of arms are whose.

That’s ten points – I took the “extra backgrounding” feat.

Job done. But how did he wind up in an adventuring party?


The 13th Age system bases its roleplay and story hooks around a system of 13 “icons” – great powers of the world, and around your character’s “one unique thing”. It’s just one of those paradoxes that a roleplay-oriented game system has a mechanical means of generating roleplay.

My “one unique thing” is:

My character doesn’t really remember this, but once when he was about seven his family was in the castle in Horizon, and he got separated. He wandered about and wound up in a library. There was a gentleman there, dressed in plain wizard’s robes. My character got to talking, and told this man that he was going grow up to be a wizard, a good wizard, and he was going to do missions for The Priestess and help people. And he told the man about the three types of magic circles, and drew the first ten runes of magic – explaining that it was very important that they be drawn right, and that you had to practise until you could draw them perfectly without stopping.

The man told my character that it was good to be a wizard, but it took a long time and was a lot of work, but that if that’s what he wanted to be then he should stick with it and not give up, and that he should always try to be a good wizard and help people and serve the emperor. Then that anonymous gentleman cast a spell – attempting to conceal the casting of it. But my character saw it, and said “Oh! I don’t know that one! What does it do?” Which somewhat took the gentleman back a bit. Startled him a little.

After that – meh: the gentleman left, my character found his family again, or more likely was found and was returned to them. No probs. A minor incident, forgotten in the rush of all the other things that come with seeing Horizon as a child.

There’s plenty of people that The Archmage and the other icons (or their staff) keep tabs on. That’s not unique. But there’s only one who, at the age of seven, caught him out at magic.

The idea being that if we choose to go there, we can go that the Archmage sealed off some of James’ magical potential. Of course, everyone else in the group has got their special too.

Our game is being set on the frontier. The idea is: frontier town, someone puts out a call for adventurers. I’m thinking wood palisade fort. Old west style. We decided that the game would be at a more established coastal town, but outskirts of the empire.

I’m feeling that the Archmage is testing James – not helping (much), not hindering (much), and it’s his machinations that got James assigned out out here. In game terms, that’s a 2-point “conflicted” relationship with the Archmage, and I gave him a 1-point “positive” relationship with the emperor (’cause army). What I think this means is that if a public servant or someone in the hierarchy should have cause to pull James’ file, they’d come away with the general impression that James was a young man of good character from a respectable family.

Now according to Andrew, this famous dude puts out a call for noble adventurers. HOw does my guy wind up in that group? Well, we decided that the local commander has no need for a half-trained arcanr corps officer cadet, and that this dude putting out the call was a respected – even somewhat famous – campaigner of the emperor. So the local CO has simply assigned James to him.

Job done.

And that’s how it rolls. Make up an excuse and retcon it. Collaborative fiction at its finest.


All that really remains is a personality for James. With a Cha of 16, I can’t make him withdrawn. It’d be fun to make him a bit of an upper-class-twit, but all I really know of the type is Hugh Laurie playing Princey on BlackAdder, and I don’t really think I can pull it off.

I’ll just have to wing it.

It’s even money as to whether we descend into senseless mayhem immediately or leave it a week while people get used to the game system. The guys have been playing drow for a few months – they might find it difficult to switch gears. 🙂


#FacesOfProstitution

25 April, 2015

Had a look over at https://twitter.com/hashtag/FacesOfProstitution, via Maggie McNeill . A few posts there memorialising hookers who were murdered by Johns. https://twitter.com/SexindustryK

Reminded me of something.

I used to frequent Alice’s Bookshop in the Churches Center in Belconnen. Alice once told me a story about a person she was speaking to about shoplifting. “Gee, that’s awful!”, said the person, “That your customers steal your books!”

Alice replied to that person: “Customers don’t steal my books. Thieves steal my books.”

By definition.

Let’s remove the SexindustryK stories that are simply lies: attention-grabbing, Münchausen-by-proxy lies.
Let’s remove the ones where someone moved on without notice, or died from an overdose, and the people simply made up stories.
Let’s remove the ones where a worker was killed not by a John, but by her drug dealer.
Let’s remove the ones where a worker was killed by her insane thug boyfriend.

After that, do any stories remain? Sure – lots of them. The world is a big place.

And so these women (mostly) were killed by johns?

No – they were killed by murderers. Murderers perhaps pretending to be johns, just as all of Alice’s shoplifters pretended to be customers, but not at all the same thing.

Murderers. How many of them murdered because they saw hookers as a blight on the community? How many of them murdered to make the world a safer, cleaner place (For the children!)? And how many of them murdered – here’s a thought – because God told ’em to do it? You and I both know: more than a few.

How many of them, in summary, murdered for reasons very, very similar to the ones that motivate the anti-sex-industry crowd?


Catenary

20 April, 2015

Some unpainted dudes face some other unpainted dudes on a 50′ bridge which sags 5′ in the middle and whose glue is not yet dry.

Each “step” is 1/3 of an inch, which is the thickness of a dwarven forge floor tile. The shape is a catenary, of course. I’m thinking of doing a 50′ bridge where one end is 10′ higher than the other end, now that my spreadsheet is cooking and correctly calculating the shape.

Once the glue is dry, I’ll stain the wood with ink, then bind the wood to the wire with some twine – hiopefully it will look like rope. The ends of the wire will just sit on the tiles. Maybe I can decorate them to look like posts or stakes driven into the ground.


Machine

3 April, 2015

Well – here’s the code for my “open the blinds when it’s daylight” project. It features time slicing – while the motor is winding the blinds, you can hit a button at any time to stop it.

Inputs:
PIN_UP, PIN_DN, PIN_ARM – buttons on my little control stick.
PIN_LDR – light sensor.

Outputs:
pin 13, of course. And pins A, A_, B and B_ which are the coils of the stepper.

A down on any button stops the motor.

A hold on PIN_UP/PIN_DN moves the motor until you release the button.

A hold on PIN_ARM arms and disarms the device.

A double-click on any button moves the blinds to the preset position for that button.

A triple-click sets the preset position for that button. This means that when setting, the motor will briefly activate (as if you had double-clicked), but meh.

Finally, the daylight sensor. If the device is armed, and A0 goes over the threshhold and stays over the threshold for a given time, then the motor moves the blinds to the position set on the ARM button.

The basic design is that each object has a loop() method which is called each time the main loop() runs. A boolean is returned to indicate if anything interesting happened. If nothing interesting happens for a while, then it would be reasonable to put the board to sleep, but meh – haven’t done this bit.

To set up:
Click and hold one of the UP/DN buttons to close the blinds. Triple-click to remember the closed position.
Click and hold the other UP/DN button to open the blinds. Triple-click to remember the open position, and also triple-click the ARM button.

At bedtime:
double-click the ‘close the blinds’ button to block out the light from that damn streetlight right outside my bedroom window. (If it isn’t already closed, which it will be due to privacy.)
click and hold the ‘arm’ button. The LED will flash once.

At dawn(ish), the blinds will open to let in the glorious morning sun and hopefully my circadian rhythm will finally get the message that it’s ok to wake up in the morning.

const byte INFO_LED = 13; // blue wire - also dives on-board LED

const byte A = 2;
const byte A_ = 3;
const byte B = 4;
const byte B_ = 5;

#define STEPPER_PINS(v) for(int v=2;v<=5;v++)
#define STEPPER_OFF STEPPER_PINS(stepperOut) digitalWrite(stepperOut, LOW);

const byte PIN_UP = 12; // red or black wire
const byte PIN_DN = 11; // red or black wire
const byte PIN_ARM = 10; // white wire

const byte  PIN_LDR = 0; // analog 0

const int LDR_THRESHHOLD = 300; // seems to be about right.
const int DAYLIGHT_TIME_MS = 1000 * 60 * 10; // 10 minutes

//#define DEBUG true

#ifdef DEBUG
#define info(x) _info(x)
#else
#define info(x)
#endif


// first - library code (in effect)

// An object that knows how to listen for button presses and releases
// and to invoke callbacks in response
// call loop() to make it go.

class Button {
  protected:

    byte pin;

#ifdef DEBUG
    void _info(const char *s) {
      Serial.print(name);
      Serial.print(": ");
      Serial.println(s);
    }
#endif

    virtual void dn() {
      info("DOWN");
      if (dn_callback) {
        dn_callback();
      }
    }

    virtual void up() {
      info("UP");
      if (up_callback) {
        up_callback();
      }
    }

  public:

    void (*dn_callback)() = NULL;
    void (*up_callback)() = NULL;
    char *name = "A Button";

    boolean buttonDown = false;

    void setup(byte _pin) {
      pin = _pin;
      pinMode(pin, INPUT_PULLUP);
      buttonDown = !digitalRead(pin);
    }

    boolean loop() {
      boolean newState = !digitalRead(pin);
      if (newState == buttonDown) return false;
      buttonDown = newState;
      if (buttonDown) dn(); else up();
      return true;
    }

};

// An object that knows how to listen for clicks, double-clicks, and holds
// and to invoke callbacks in response
// call loop() to make it go.

class Clicker: public Button {
  public:

    const int DOUBLE_CLICK_MS = 1000;
    const int HOLD_MS = 500;

    void (*click_callback)(int);
    void (*startHold_callback)(int);
    void (*hold_callback)();
    void (*endHold_callback)();

    boolean loop() {
      Button::loop();

      if (buttonDown) {
        if (holding) {
          hold();
        }
        else if (timeExceeded(HOLD_MS)) {
          startHold(clickCount);
          holding = true;
          clickCount = 0;
          hold(); // an initial hold to produce consistent behaviour
        }
        return true;
      }
      else {
        if (clickCount > 0 && timeExceeded(DOUBLE_CLICK_MS)) {
          clickCount = 0;
        }

        // if clickcount is greater than zero, we are in a possible double-click situation
        // so we want the loop to be running fast.
        return clickCount > 0;
      }
    }

  protected:

#ifdef DEBUG
    void _info(const char *s) {
      Serial.print(name);
      Serial.print(": ");
      Serial.println(s);
    }
#endif

    unsigned long dnMillis = 0L;
    boolean holding = false;
    int clickCount = 0;

    boolean timeExceeded(int t) {
      // millis may wrap, but the math works out
      return (millis() - dnMillis) >= t;
    }

    void dn() {
      Button::dn();
      dnMillis = millis();
      clickCount ++;
    }

    void up() {
      Button::up();
      if (holding) {
        holding = false;
        endHold();
      }
      else {
        click(clickCount);
      }
    }

    virtual void click(int clickCount) {
      info("CLICK");
      if (click_callback) {
        click_callback(clickCount);
      }
    }

    virtual void startHold(int clickCount) {
      info("HOLD ON");
      if (startHold_callback) {
        startHold_callback(clickCount);
      }
    }

    virtual void hold() {
      if (hold_callback) {
        hold_callback();
      }
    }

    virtual void endHold() {
      info("HOLD OFF");
      if (endHold_callback) {
        endHold_callback();
      }
    }
};

// A stepper motor that keeps track of location. It can move the motor to a target, or just start and stop.
// it will only do 5 minutes max of movement before stopping unconditionally
// call loop() to make it go.

class MyStepper {
  public:

    int location = 0;
    char *name = "Stepper";

    void setup() {
      STEPPER_PINS(v) pinMode(v, OUTPUT);
    }

    boolean loop() {
      // it's ok to leave lastMove uninitialized, because it's unsigned

      // 4ms = 250/s = 10/s turns = 600rpm, which is about the maximum

      if (millis() - lastMove < 5) return movingUp || movingDown || moveToTarget;

      lastMove = millis();

      if (movingUp) {
        location++;
      }
      else if (movingDown) {
        location--;
      }
      else if (moveToTarget) {
        if (location == target) {
          stopMoving();
          return true;
        }

        location += target > location ? 1 : -1;
      }
      else {
        return false;
      }

      if (tripFailsafe()) return true;

      // this code may cause both A and A_ to be turned on at the same time, but meh -
      // it's only for a microsecond or so. It isn't going to break anything.
      digitalWrite(A,   (location & 2) ? HIGH : LOW);
      digitalWrite(A_, !(location & 2) ? HIGH : LOW);
      digitalWrite(B,   ((location ^ (location >> 1)) & 1) ? HIGH : LOW);
      digitalWrite(B_, !((location ^ (location >> 1)) & 1) ? HIGH : LOW);

      return true;
    }

    void moveUp() {
      info("moveUp()");
      stopMoving();
      setFailSafe();
      movingUp = true;
    }

    void moveDown() {
      info("moveDown()");
      stopMoving();
      setFailSafe();
      movingDown = true;
    }

    void moveTo(int _target) {
      info("moveTo(_)");
      stopMoving();
      setFailSafe();
      moveToTarget = true;
      target = _target;
    }

    void stopMoving() {
      info("stopMoving()");
      movingUp = false;
      movingDown = false;
      moveToTarget = false;
      STEPPER_OFF;
    }


  protected:
    const unsigned long FAILSAFE_MS = 1000 * 60 * 5; // 5 minutes max time running the motor

    unsigned long failsafe = 0;
    unsigned long lastMove = 0;
    boolean movingUp = false;
    boolean movingDown = false;
    boolean moveToTarget = false;
    int target = 0;

#ifdef DEBUG
    void _info(const char *s) {
      Serial.print(name);
      Serial.print(": ");
      Serial.println(s);
    }
#endif

    void setFailSafe() {
      failsafe = millis();
    }

    boolean tripFailsafe() {
      if (millis() - failsafe < FAILSAFE_MS) return false;
      if (!movingUp && !movingDown && !moveToTarget) return false;
      stopMoving();
      return true;
    }

};

// the control objects and their event handlers.
// the control schema is:
// if the 'set' button is on, then a click on up/down/arm will set the corresponding setpoint
// it the 'set' button is not down
// buttons up and dn will move the motor on a hold and move to the setpunt on a dclick
// single-click does nothing. It's just an 'oops'.
// arm button moves to the arm setpoint on a dclick, and arms/disarms on a hold.
// on an arm, the onboard led is flashed once. on a disarm, it's flashed three times.

MyStepper stepper;
Clicker buttonUp;
Clicker buttonDn;
Clicker buttonArm;

boolean armed = false;
int upSetpoint;
int dnSetpoint;
int armSetpoint;
boolean daylight = false;
unsigned long daylight_t = 0;


#ifdef DEBUG
void _info(const char *s) {
  Serial.print(": ");
  Serial.println(s);
}
#endif

void buttonUp_click(int clickCount) {
  info("click");
  if (clickCount == 2) {
    info("2 clicks. moving up");
    stepper.moveTo(upSetpoint);
  }
  else if (clickCount == 3) {
    info("3 clicks. Setting up");
    upSetpoint = stepper.location;
  }
}

void buttonUp_startHold(int clickCount) {
  stepper.moveUp();
}

void buttonUp_endHold() {
  info("stop moving the stepper");
  stepper.stopMoving();
}

void buttonDn_click(int clickCount) {
  if (clickCount == 2) {
    stepper.moveTo(dnSetpoint);
    info("2 clicks. movto dn.");
  }
  else if (clickCount == 3) {
    dnSetpoint = stepper.location;
    info("3 clicks. Setting dn");
  }
}

void buttonDn_startHold(int clickCount) {
  stepper.moveDown();
}

void buttonDn_endHold() {
  stepper.stopMoving();
}

void buttonArm_click(int clickCount) {
  if (clickCount == 2) {
    stepper.moveTo(armSetpoint);
  }
  else if (clickCount == 3) {
    armSetpoint = stepper.location;
  }
}

void buttonArm_endHold() {
  armed = !armed;
  info_flash(armed ? 1 : 3);
}

void stopStepper() {
  stepper.stopMoving();
}

void setup() {
  pinMode(INFO_LED, OUTPUT);

#ifdef DEBUG
  Serial.begin(9600);
#endif


  buttonUp.setup(PIN_UP);
  buttonDn.setup(PIN_DN);
  buttonArm.setup(PIN_ARM);
  stepper.setup();

  buttonUp.name = "BtnUp";
  buttonUp.click_callback = buttonUp_click;
  buttonUp.startHold_callback = buttonUp_startHold;
  buttonUp.endHold_callback = buttonUp_endHold;

  buttonDn.name = "BtnDn";
  buttonDn.click_callback = buttonDn_click;
  buttonDn.startHold_callback = buttonDn_startHold;
  buttonDn.endHold_callback = buttonDn_endHold;

  buttonArm.name = "BtnArm";
  buttonArm.click_callback = buttonArm_click;
  buttonArm.endHold_callback = buttonArm_endHold;

  // all buttons, irrespective of anything else they do, stop
  // the stepper when they are hit.

  buttonUp.dn_callback = stopStepper;
  buttonDn.dn_callback = stopStepper;
  buttonArm.dn_callback = stopStepper;

}

// don't need a class to encapsulate this: it's pretty simple
boolean checkLightSensor() {
  if (!armed) return false; // nothing to see, here.

  boolean _daylight = analogRead(PIN_LDR) > LDR_THRESHHOLD;

  if (!_daylight) {
    if (!daylight) {
      // still naptime
      return false;
    }
    else {
      info("Just a passing car");
      // just a passing car.
      daylight = false;
      return true;
    }
  }
  else {
    // ok. it's daylight now, and we are armed.

    if (!daylight) {
      info("Daylight sensed");
      // this was the first sensing
      daylight = true;
      daylight_t = millis();
      return true;
    }
    else if (millis() - daylight_t < DAYLIGHT_TIME_MS ) {
      // waiting to see if the sun remains out for a bit
      return false;
    }
    else {
      info("It's daytime. Moving.");
      // we are armed, it's daylight, and it's been daylight for some time
      info_flash(10);
      armed = false;
      stepper.moveTo(armSetpoint);
      return true;
    }
  }

}

void loop() {
  // put your main code here, to run repeatedly:

  boolean somethingHappened = false;

  somethingHappened = buttonUp.loop() || somethingHappened;
  somethingHappened = buttonDn.loop() || somethingHappened;
  somethingHappened = buttonArm.loop() || somethingHappened;
  somethingHappened = stepper.loop() || somethingHappened;
  somethingHappened = checkLightSensor() || somethingHappened;

  if (!somethingHappened) {
    // TODO! Put the arduino to sleep, wake on interrupt.
    // for now - meh. It's ok to run a tight loop.
  }

}

void info_flash(int n) {
  while (n--) {
    digitalWrite(INFO_LED, HIGH);
    delay(200);
    digitalWrite(INFO_LED, LOW);
    delay(200);
  }
  delay(200); // to demarcate the phrase
}