Thursday, 22 September 2011

Crass Commercialism

I've decided to bite the bullet and try my luck in the indie game market.

Not without a degree of trepidation, I must admit. But, I'm beginning to think that the only way I'll see stable employment from this point forward is to be my own boss. And if I'm going to spend all day sitting around writing software anyway, I might as well try and make it pay the bills.

So, the plan currently is to keep coding, but look at a commercial release of something. Probably still aim at the adult game market.I've got the coding skills; maybe some commercial incentive will get me to see a project through to completion for a change. Certainly it'll be nice to be able to work full time on something.

I'll also probably end up with adwords and a tip jar box on here at some point.

Plan A was "get a job", and that's pretty much failed. This is Plan B.

More details to come.

Saturday, 17 September 2011

People Are Hard

Damn, but Inform gets frustrating when you try and do interactions with people.

A simple thing like fastening a collar around a slavegirl's neck falls foul of several rules.

In other news, I've decided to go professional with the games dev. Not sure of the details yet - I have a meeting which might make some funding available, so no hard and fast decisions until get done with that. Dangerous Game is one of the possible projects I might commercialise. Or it might end up being something completely new.

Meanwhile, I'm still working on The Doghouse. The story so far: You (as PC) have been summoned by your cousin Vinny and lumbered with looking after his new nightclub, "The Doghouse" while Vinny travels abroad for health reasons that are completely unrelated to the amount of money he owes to the Mob.

Of course with all that money owing, various extremely violent people will be displeased if you just walk out of the nightclub and get on with your life. So the sensible thing is to look around, work out the business plan, and get the club operational as soon as possible so you can get out before someone decides to put a contract on you too. Now if you could only work out why he put bedrooms adjoining the dance floor. Or jail cells in the basement...

You're aided in this (if that is indeed the correct word) by Einstein, the biggest and dumbest bouncer in the world. Einstein has had the plan explained to him by Vinny, but can't really remember much more than the "package is due today", although with the right questions, you might manage to jog his memory. And the arrival of the package will certainly answer a lot of questions.

So far I've coded up to the package arriving, (which has been great fun) and then hit a bit of a wall. So I hived off the "package" into it's own inform game with a view towards recombining the two when it's working.

I don't really want to release another "no-sex but loads of setup" file, so I'm going to keep plugging at the sexslave interactions, and hopefully release when there's something more to do than wander around and make wisecracks.

Monday, 12 September 2011

The Doghouse

Inspired by Nuku's Flexible Society, I've been playing with Inform 7 again. I seem to be afflicted with more than my usual share of "Grasshopper Mind" at the moment.

Here's a start for something called The Doghouse. It's just a start at the moment, really. You'll need an Inform interpreter to play it. If you don't already have one, WindowsFrotz seems to work well enough.

Themes are going to be more or less my usual ones. There's not a lot of naughtiness in this yet, but you can get some idea of how it's going to develop...

Thursday, 8 September 2011

Action and Action_Sleep

The action base class is pretty trivial
class Action
        attr_accessor :name
        attr_accessor :resistance

        def initialize(args)
                @name = args[:name]
                @resistance = args[:resistance] || 100
        end
end
That's a name, and a resistance value. In general if obedience exceeds resistance.

Of course, doing this in ruby, we don't really need a base class. So all this does is set a default resistance.

So, we have our first (and so far only) subclass Action_Sleep

class Action_Sleep < Action
        def initialize(args=nil)
                args = {} unless args
                args[:name] = "Sleep" unless args[:name]
                args[:resistance] = 35 unless args[:resistance]
                super(args)
        end
end

That defauts the name and changes the default resistance. I've left the args in so we can either have custom sleep actions for girls with strange sleep patterns, or else subclass it for something sleeplike later on.

What's missing here is the perform method. And this is where I get in a tangle.




#
#       two factors: obedience and tiredness
#
#       five outcomes:
#
#       disobedient and alert: will stay awake
#       disobedient and a bit tired: will try to stay awake
#       disobedient and very tired: fall asleep, mumbling defiance
#       obedient and tired: will go to sleep
#       obedient and alert: will try to sleep and pretend if need be
#
#       how to define "tired" then?
#       what do I want from tiredness?
#
#       I want to impose some limit on how long people can work
#       I want to be able to exceed that limit
#       I want to use sleep-dep to compel obedience
#
        def perform(actor)
                tiredness = 100 - actor.alertness
                obeidient = (actor.obedience > @resistance)
                tired = (tiredness > 40)
#
#               now, the simplest case is the obedient one
#
                if obedient
                        if tired
                                print "#{} sleeps soundly"
                        else
                                print "#{} lies still and pretends to sleep"
                        end
                        return
                end

#               so, these are the disobedient cases
#               simplest of which is if she's at zero alertness
#               in which case she falls asleep anyway
#
                if actor.alertness == 0
                        print "#{} mutters in her sleep"
                        return
                end

#
#               if she's not tired, she refuses to pretend to sleep
#
                if !tired
                        print "#{} makes rude gestures at the CCTV camera"
                        return
                end

#
#               now then: being tired will make her more inclined to
#               obey than she would be otherwise. Let's have a bonus #               from 1-20
#
                if actor.obedience + tiredness / 5 >= @resistance
                        print "#{} dozes, restlessly"
                else
                        print "#{} stares bleary-eyed at the camera"
                end
        end
That's still not got any changes to stats. Tiredness, obedience, resistance, none of them are moving at this point.

Next thing is to make it all compile and see how it runs.
 OK, Girl class now,
class Girl
        attr_accessor :name         # girl's name
        attr_accessor :obedience    # 100 == perfect obedience
        attr_accessor :alertness    # 0 == asleep, 100 == hyper
        attr_accessor :energy       # 0 == sick, 100 == fighting fit
        attr_accessor :actions      # action tabs - all possible actions
        attr_accessor :current      # currently selected action

#
#       set name from params, defaults for other stats
#       only one action (sleep) for now
#
        def initialize(args)
                @name           = args[:name]
                @obedience      = args[:obedience]      || 10
                @alertness      = args[:alertness]      || 100
                @energy         = args[:energy]         || 100
                @actions = {
                        :sleep => Action_Sleep.new({})
                }
                @current = @actions[:sleep]
        end
       
#      
#       call perform on the current action
#
        def do_shift(shift_id)
                @current.perform(self)
        end
end
Stats are 1 - 100 in range.
 That was simple too. Never mind, next one makes up for it

Wednesday, 7 September 2011

Code: GirlList

(I'm breaking these up by class to try and avoid Blogger lagging like it did yesterday)

It seems to me that everything I describe in this blog turns out at least three times as complicated when I write it all down than it was when it was in my head. For this reason, I'm reluctant to say that GirlList is simple and straight forward. I mean, I think it is, but I'm afraid if I say so, I'll invoke Murphy.

Anyway....
class GirlList

    def initialize
        @list = Array.new
    end

    def add(actor)
        @list.push(actor)
    end

    def do_shift(shift_id)
        @list.each { |x|
            x.do_shift(shift_id)
        }
    end
end

It's basically a wrapper around an array. Method to initialise the array, one to add girls, and one to evaluate each girl's performance in a shift.  I changed do_turn to do_shift at this level, as mentioned earlier, and I may yet lower the granularity further. But this'll do for now.

Why not just have an array? I'm not sure I have a good reason, except that I often find it's good to have an explicit list class. It gives me room to add processing when a girl is added or removed, for instance.

mmm... looks like this one really was that simple.

Code: TrainingCamp

A first cut of the TrainingCamp class looks like this:

class TrainingCamp
    def initialize
        @girls = GirlList.new
    end
  
    def do_turn
    #
    #    part of me wants to break this down, hour by hour
    #    I can see good things from that. Staggering
    #    changeovers for instance, means never risking
    #    having three girls gang up on you...
    #
        @girls.do_shift(Shift::Morning)
        @girls.do_shift(Shift::Afternoon)
        @girls.do_shift(Shift::Evening)
        @girls.do_shift(Shift::Night)
    end

    def add_girl(girl)
        @girls.add(girl)
    end
end
Again, nothing surprising there. I've added a method to add girls to the camp. The calling code looks like this this:
camp = TrainingCamp.new
camp.add_girl(Girl.new( :name => "Anne", :obedience => 51))
camp.add_girl(Girl.new( :name => "Betty" ))

while true
    camp.do_turn
    sleep 1
end
That'll let me run tests with one turn a second when the rest of the classes are working.

I also added a Shift class. Since that's just a holder for the shift constants, I'll we can deal with it here:
class Shift
    Morning        = "Morning"
    Afternoon     = "Afternoon"
    Evening        = "Evening"
    Night            = "Night"
end

I could just use the strings, but this way they get syntax checked and I can spot typos. I also had the impression that Ruby stored all strings as single instances, so passing strings around was no worse than passing ints, and that using strings was the preferred Ruby idiom for constants. But now I think on it, I may be getting that mixed up with Lua. Never mind, in any event, it saves me having a lookup table to convert int constants into strings

Tuesday, 6 September 2011

Let's throw some UML at that...

So, let's look at how some of that breaks down into classes.

 

Nothing particularly earth shattering there. We have TrainingCamp as a top level class (at least as far as training is concerned) which contains a GirlList which abstracts a list of Girls in training. Eventually TrainingCamp is going to have a bit more to it, since it will need to manage available training equipment, training schedules and the like. But for now, it just keeps a list of girls.

The do_turn method in TrainingCamp executes one turn (which is to say one day) of training. That gets passed down to GirlList, which passes it on to each of the girls in the list. Thinking about it, I think I'll probably change to do_turn to do_shift or do_hour in Girl and GirlList. There are places we'll want to manage simultaneous actions - like two girls competing for the same resource, or sparring, or sex training for that matter. And the PC needs to be in the TrainingCamp as well, thinking about it ... but that can wait.


Anyway...





You'll note I'm not addressing mood state at all here. This is in the interests of starting simple. For now, I'm going to have a default, neutral mood and a single task - sleeping.

Some things to note

Each Action has a resistance. The basic rule is that if Girl.obedience > Action.resistance then the thing gets done. Every time a girl performs an action on demand, there's a chance that her resistance to that action will go down. And if she successfully refuses, it should probably have a chance to go up

I had thought of using the resistance value to model a girl's like or dislike of an action, but that's not going to work. Over time, resistance is going to drop to zero for everything she does, but I'd quite like there still to be things she liked and disliked. I'll need to think about that a bit.

The possible actions are stored in a hash called actions_list. Each girl will probably have the same actions (assuming no mutants, monstergirls or whatever) but they each get their own copy of the action table so we they can have their own resistance value. If the Action object gets too bit we'll need to split it to a global action table, and smaller one containing the girl-specific data. For now we'll just copy it.

Next thing, we'll try some code.

I'll finish this up tomorrow. I'm getting tired and Blogger is giving me a ten second lag on keyboard input at the moment. Ajax for the win.

Emotion Modelling

The heart of any training game is getting the girls to react believably to the training stimulus. However our simulation of the training process hasn't really changed since Pooolka write the first draft of Slavemaker.

In this post I'm going to talk a bit about the current state of that art, and what I see as good and bad about it. Then I want to explain what I want to do that's different, why I think that would be better, and some ideas on how I hope to get it done.

OK: State of the art. Basically all the games I'm familiar with work by  having different activities add points to some statistics, and subtract them from others. On balance, more points get added than subtracted, so it's possible to max out the girl's stats, while at the same time, the subtractions keep the game from becoming overly linear.

There's a lot that's good about that approach. It's simple, it's easy for the player to understand what's happening, and it gives a pretty good impression of a training process. It's simple, and it's Good Enough. These are strong points in favour.

As for drawbacks, there are two that spring to mind. One is that the system offers few surprises once you master the basics. You don't ever see a girl fly into a huff, and then slowly warm back out if it, for instance. You never see resistance suddenly crumble. You never see sullen obedience or apologetic defiance.

The other drawback is that it's very much a single trainee model. It doesn't allow for interaction with any other girls. Even in games like Whoremaster or Otherworld  that have multiple girls designed in from the start, they're still just running multiple parallel single player training.

So, then: What I want to achieve. I want to keep the keep the good parts of the original system so far as I can, while adding room for the girls to have emotional states that can change, usually predictably, sometimes not. I want to model relationships as well. Not the girl's relationship with her trainer, but also how she feels about each of the other slaves, her feelings for other masters and mistresses, and her feelings about the various tasks used in her training.

The hard part in this is going to be maintaining the simplicity and understandability of pooolka's model. In programming terms, it's a dead loss. We're going to need a lot of code and classes to manage these relationships. In terms of player interface, I think we can keep it more or less unchanged. As for understanding why the girls are behaving as they are, that's harder.

If a girl does unexpected things too often, then the game seems arbitrary and unfair. We can mitigate that a lot by making information available so the player can work out why in reterospect. But at the same time if we make too much information available, we lose the surprise when something unexpected does happen.

How to do it: I'll go into more detail in the next post, but basically I want to
have a state machine for different mental states, and to have that emotional state colour the way a girl reacts to a task. So if she's Defiant, then even if she obeys, she'll do it spitting curses at you. Or we might have an Submissive state where she does pretty much as she's told, and if for any reason she can't bring herself to obey, it'll be with apologies and pleas for mercy. Run either of them for too long and they'll transition to Tired, and not say anything apart from "need .. to ... sleep ..." or some such thing. Let them sleep and they'll jump back to their previous state.

Transitions are all going to be based on rules, and those rules will take account of  environmental and situational circumstances as well as attributes. So, for instance, you could have girl busy falling in love with their trainer, who has a bad day and ends up tired and hungry and gets given all the tasks she hates. If she gets enough negatives from all that, it's possible she might spike to an Angry state. She probably won't stay there long, because her stats are still ones for "falling-in-love". So the trainer gets an unexpected earful the next time he talks to her, followed by a fairly rapid cooling off afterward.

There are other things I'd like to do, too. Make effective training rely on rewards and punishment as well as simple repetition of a task, and allow the player to use things like hunger and sex drive as leverage to get obedience. But there's probably enough to be going on with here.

So, to summarise: I want to extend the basic pooolka model for training by adding emotional states that transition by well defined rules, but which are still capable of unexpected spikes, and I want to model relationships with people and with activities to provide extra variables to drive those state transitions. All of this with a user interface little different from the one
in slavemaker.

Next post I'll do some UML and maybe some code showing how I'm thinking of implementing all this.