Friday, 31 December 2010

Still nothing much to report

Well, as promised, yesterday was a bit of a lazy day. I prodded at a Func screen for screen edit, but didn't try very hard. Watched a lot of Doctor Who, read some Stieg Larsson... Recharged my batteries a bit. Probably do the same today.

I did get a decent night's sleep last night for the first time in ages. No coughing myself awake at 3am. That's a big improvement, I can tell you.

Wednesday, 29 December 2010

Not much to report.

I took out the SQL code. I kept the Narrative class interface unchanged, but behind the scenes it just hand-rolls an ArrayList. It'll do for now. I worked out a popup dialog to let you name your new slave girl, and I'm looking at how to specify orders for the girl (and for yourself) now you have her.

It's rendered a bit tricky by the fact that you have such a limited amount of screen to work with. On a PC app I could just throw widgets at the problem. Here I need to think about it a bit. And of course, it's further complicated by the fact that I don't really know the platform yet.

My head is aching with all this. I think I'll change track for tomorrow. Maybe take a lazy day or two (to use Daisy's term...)

Tuesday, 28 December 2010

SQL details

This is mainly a reply to anonymous from the last post's comments.

The database uses Android's built-in SQLite3. It's a local database - a tad
overkill at this point, but writing a dataprovider seems to be the easiest way to send potentially large arrays of data to the apps.

So what I'm doing, or going to be doing at any rate, is building up scene/narrative lists from XML and using them to drive the plot segments.

I think the SQL itself is all right. I have three tables:

                        mk_table(db, "create table narrative ("
                                + "     " + idstring + ", "
                                + "     ev_name varchar not null"
                                + ");"
                        );
                        count_narratives(db);

                        mk_table(db, "create table narrative_string ("
                                + "     " + idstring
                                + "     , ev_name varchar not null"
                                + "     , seq integer not null"
                                + "     , text_id integer not null"
                                + ");"
                        );

                        mk_table(db, "create table narrative_image ("
                                + "     " + idstring
                                + "     , ev_name varchar not null"
                                + "     , seq integer not null"
                                + "     , image_id integer not null"
                                + ");"
                        );


Where mk_table is defined thusly:

                private void mk_table(SQLiteDatabase db, String sql)
                {
                        Log.d(TAG, "creating table: " + sql);
                        db.execSQL(sql);
                }


The count_narratives function is just to sanity check things:

                private int count_narratives(SQLiteDatabase db)
                {
                        Cursor c;
                        String sql = "select count(*) n from " + TAB_NARRATIVE;

                        c = db.rawQuery(sql, null);
                        if(c == null) {
                                Log.d(TAG, "count_narratives: can't get cursor");
                                return -1;
                        }
                        Boolean bv = c.moveToFirst();
                        if(!bv) {
                                Log.d(TAG, "count_narratives: no rows for count(*)!");
                                return -1;
                        }
                        int n = c.getInt(0);
                        c.close();
                        Log.d(TAG, "count_narratives: "+n+" narratives added!");
                        return n;
                }


So if the table creates, that should always work. After I create the narrative table it tells me the table has zero rows (and therefore that it exists). So far so good.

I then populate the database:

                        Log.d(TAG, "starting intro narrative.");
                        int seq = 1;
                        db.beginTransaction();
                        insert_narrative(db, "intro", seq++, R.string.intro1, R.drawable.alley);
                        count_narratives(db);
                        insert_narrative(db, "intro", seq++, R.string.intro2);
                        count_narratives(db);
                        insert_narrative(db, "intro", seq++, R.string.intro3);
                        count_narratives(db);
                        insert_narrative(db, "intro", seq++, R.string.intro4);
                        count_narratives(db);
                        insert_narrative(db, "intro", seq++, R.string.intro5);
                        count_narratives(db);
                        insert_narrative(db, "intro", seq++, R.string.intro6);
                        insert_narrative(db, "intro", seq++, R.string.intro7);
                        insert_narrative(db, "intro", seq++, R.string.intro8);
                        insert_narrative(db, "intro", seq++, R.string.intro9, R.drawable.girl1);
                        insert_narrative(db, "intro", seq++, R.string.intro10);
                        insert_narrative(db, "intro", seq++, R.string.intro11);
                        insert_narrative(db, "intro", seq++, R.string.intro12);
                        db.endTransaction();
                        Log.d(TAG, "final narrative count.");
                        count_narratives(db);
                        Log.d(TAG, "final narrative count done.");
                        Log.d(TAG, "end of intro narrative.");


The count_narratives calls in here show the table continuing to exist, and with the expected number of rows. Again: so far, so good.

Then I try and retrieve the data:

                String sql = ""
                        + "select\n"
                        + "     e.ev_name,\n"
                        + "     s.seq,\n"
                        + "     s.text_id,\n"
                        + "     i.image_id\n"
                        + "from\n"
                        + "     "+TAB_NARRATIVE+" e\n"
                        + "     left outer join narrative_string s on\n"
                        + "             e.ev_name = s.ev_name\n"
                        + "     left outer join narrative_image i on\n"
                        + "             e.ev_name = i.ev_name\n"
                        + "where\n"
                        + "     e.ev_name = '" + narrative_name + "'\n"
                        + "order by\n"
                        + "     1, 2\n"
                ;


And for some reason the table no longer exists. So either A) I'm accidentally dropping the data after creation (possible, but I don't know where) or B) I'm accidentally opening a non-existent database for the query and SQLite is creating a new empty database, or else C) something very weird is happening.

I'm tending toward B) myself.

I think I'll leave the SQL alone for now.

Well, I enter the data, the table exists. I check the data entered ok, and the table exists. I try to query said data just a little later, and there is no such table.

I tried wrapping it in transactions; making sure the database closed... So I've given up on it for now. I'm keeping the Narrative interface, but stubbing out the SQL behind the scenes.

Next time I try it, I think I'll start with XML

Meanwhile: alerts. I want to prompt for the girl's name, and then on to the hard part - setting orders.

Monday, 27 December 2010

Bloody SQL

Still slogging at the SQL code. I create a table. I add rows to that table. All is logged; errors there are none. Then when I come to get the data back, the table doesn't exist all of a sudden.

Not helped by me being too tired to think, and still not very well. Apparently, influenza is supposed to run its course inside two weeks, ten days ideally. This should be day eight. I will be really pleased when this is over...

Customer Suplly, Redux

Let's  tackle the notion of customer supply again. See if I get any further with it this time.


As I sid earlier, there's a lot of common ground between Clonemaster and Streets of Crossgate when it comes to working out customer interactions. They both use a fairly static customer population, from which the girls need to attract punters. The major difference is that in a Crossgate ward, there's apt to be more than five potential marks. On the other hand the Crossgate case is the same as the Clonemaster one will be, once the plot moves off the initial base and the player get to set up in more populous environments.

So. How do we go about thinning down the vast supply of potential customers in Crossgate and arrive at an interesting subset?

  1. Initially, I think we need to shrink the customer pool a little. Let's say East Sleaze in Crossgate has 100 potential punters. Obviously, there are more people than that living in the ward. But I'm going to assume that some of those people aren't interested in whoring, or don't have the disposable income to indulge, or else are loyal regulars at another establishment. Basically, we're looking for the "floating voters" here.
  2. Given our 100 initial population, how to decide who wants to play? The same criteria apply. They need to have money, they need to be horny, and the girls need to offer something the customer wants. Yes, there is an "obvious thing" in this category, and yes, it's often going to be enough.
  3. One other thing required is that the customer needs here: he needs to have heard of the PC and his business. So reputation is still going to be a big driver for customers. As a ballpark figure, maybe use the rep figure as the % chance for any given punter to show an interest. So one rep would see a base one customer turning up each ... each time period. I still need to think about the timescale here...

Sunday, 26 December 2010

Yayy!

Well, the database seems to be creating, at last. Was a bit of a needlessly long haul, but got there in the end.

Now I need to use that data to drive the narrative.

Plodding on ...

Well, it's been a hell of a week. I'm starting to feel a bit better - would be a lot better if this damn cough wasn't waking me at 4am each night, but I'll take what I can get. Still a bit tired though, and the pigs ear I made of the SQL code yesterday would stand as testament to that.

Anyway, I'm busy sorting that out now.

I also spent some time yesterday fiddling with Inkscape. As an artist, I make a damn good programmer, but I can just about muddle by as a cartoonist and I've been trying to create a splash screen for the app. Nothing ready for prime time just yet, however.

SQL and Exceptions.

OK, been trying to work out why exceptions don't appear to work as they should. Well, more accurately, i've been trying to make SQL work. The reason it isn't is that the insert func was a stub, and the reason it was still a stub was that the fatal error that should have reminded me to unstub it didn't turn out all that fatal after all.

Still a lot to learn about this platform, I guess.

Signing Apps

Android apps need to be signed before they'll install, so that's what I've been working on this morning.

Works for me - feel free to try it and comment. It doesn't do anything more than you've already seen in the screenshots at the moment, so don't expect great things. Mainly I'm after some feedback from other installs before the code gets too complex to quickly troubleshoot.

[edit]

And if the template designer ever decides to start working again, I'm going to do something about the way Awesome, Inc seems to like printing hyperlinks as black on black.  Very Hotblack Desiato and all that, but not very good when it comes to people seeing the damn things.

Meanwhile, let's migrate to a less cool (but more legible) template.

Saturday, 25 December 2010

SQL in Android

Still flailing around a bit with this, but I found a useful looking example for how to create and access a database. After a bit of messing around I ended up with code like this:

        private static class OpenHelper extends SQLiteOpenHelper {
                OpenHelper(Context context) {
                        super(context, DATABASE_NAME, null, DATABASE_VERSION);
                }

                @Override
                public void onCreate(SQLiteDatabase db) {
                        String t, sql;
                        String idstring = "_ID integer primary key "+
                                          "autoincrement  not null  UNIQUE"
                        ;

                        sql     = "create table event ("
                                + "     " + idstring + ", "
                                + "     ev_name varchar not null"
                                + ")"
                        ;
                        db.execSQL(sql);


                        sql     = "create table event_string ("
                                + "     " + idstring
                                + "     , ev_name varchar not null"
                                + "     , stage integer not null"
                                + "     , string_id integer not null"
                                + ")"
                        ;
                        db.execSQL(sql);

                        sql     = "create table event_image ("
                                + "     " + idstring
                                + "     , ev_name varchar not null"
                                + "     , stage integer not null"
                                + "     , image_id integer not null"
                                + ")"
                        ;
                        db.execSQL(sql);




OK: so far, so good. I create the tables if the database itself needed creating, and I've decoupled the images and strings so any stage can have either, or both, (or none, although I'm not sure where I'd use that.

I'm less happy with the next bit...







/*
 *                      now create the database. This is the bit that
 *                      I'm not happy with. It's still hard-coding the
 *                      event structure into the program, which defeats
 *                      the point in many ways.
 *
 *                      What the hell - learning experience. I'll do it to
 *                      more forward and maybe revisit when I better understand
 *                      the platform
 */

                        insert_event("intro", R.string.intro1, R.drawable.alley);
                        insert_event("intro", R.string.intro2);
                        insert_event("intro", R.string.intro3);
                        insert_event("intro", R.string.intro4);
                        insert_event("intro", R.string.intro5);
                        insert_event("intro", R.string.intro6);
                        insert_event("intro", R.string.intro7);
                        insert_event("intro", R.string.intro8);
                        insert_event("intro", R.string.intro9, R.drawable.girl1);
                        insert_event("intro", R.string.intro10);
                        insert_event("intro", R.string.intro11);
                        insert_event("intro", R.string.intro12);


Apat from the fact that I'm not passing a stage number through (and apart from the fact that I really need to adopt a common nomenclature for all this stuff) The big problem here is that you can't look at the code and read the flow of the text. Sure you can do that in the strings.xml file, but you still get problems. If you add an entry to the XML, you still need to come back here and update the database creation. And there's no easy way to tell if the images are attached to the correct snippets.

What I want, really is to read from XML, and then load the database in a loop. That would mean I couldn't use resource strings; not a problem. I could still use image resource numbers, and I think I would do that, in fact. Eventually I need to think about loading girlpacks ... but that can wait. More important is getting a time management screen going

Friday, 24 December 2010

Pages! Gotcha

Finally remembered where I saw the Pages feature. There's ToDo lists up now for my current projects, including the outstanding stuff for WM.

List length is not necessarily an indicator of amount of work. The WM list is a lot finer-grained than the others, for instance.

Anyways...

So, despite all my best intentions, I find myself interested in android dev, so I think I'll chase that down a bit more. I've been looking at getting the sqlite interface working, since that should let me create generic ADV loops again. Currently I'm testing a state flag for each tap of the screen

Android code samples are in Java BTW. The scriptable languages framework is neat, but I get the impression it's kind of hamstrung. There's a cool hack with the Android C compiler (which is definitely hamstrung) using the scripts for access to android classes, but I've not looked at that yet.

Anyway: bumping a state variable for each click, and then switching on the result:

        public void onClick(View v) {
                Button b = (Button) v;
                switch(++intro_count) {
                case 2:
                        b.setText(R.string.intro2);
                        break;
                case 3:
                        b.setText(R.string.intro3);
                        break;

                // ... much snippage
                }
        }

Which works, but isn't really scalable. What I want is something like this

        public void onClick(View v) {
                Button b = (Button) v;
                Scene scene("intro");
                Snippet snip;

                while(snippet = scene.next()) {
                        b.setText(snip.text_id);
                        if(snip.has_image()) {
                               set_background(snip.image_id);
                        }
                }
        }

That looks a lot easier to generalise. I can still load images from game resources, but now we start to separate data and engine from one another. And in doing so we open the door to another necessity of any WM derived game: addon girl packs


Merry Christmas, All

Seasons Greetings to one and all. I set out to do some work here, but I think I'd be better served by taking an early night. Later all.

Running Lua Under Android

Now this is interesting. Android Scripting Environment (ASE) supplies a way to run scripting languages on Android. Including Lua and Perl.

I think I need to know a bit better what I'm doing here, but this could definitely be useful. Imagine being able to run Clonemaster Scenes on Android without modification. One to watch, I think

Thursday, 23 December 2010

Light at the end of the tunnel...

Heating fixed, starting to feel better. I even managed to get some dev time in. I've been having a bit of fun with my Android phone.



That's the emulator from the Android SDK. Let's do a few more screens.


Just tap to progress...



There's eleven or twelve of these in total. I'll not post all of them, promise.



I bet people were wondering if they'd have to look at that alley all day. I know I was getting to that point.


Two more to go.







And there's the setup for a mobile WM game. Not that I'm promising to make it - right now I'm just teaching myself the basics.

Still, as long as I'm having fun...

Wednesday, 22 December 2010

Still sick as a dog...

Had the doctor round today. He says it's influenza, although probably not swine flu, which is reassuring, anyway. So not a lot going to get done over the next few days. I know where I want to go with the customer supply topic, but getting the ideas written up is like wading though tarmac

That said, I did get some bullet points down last night, so I'll see if I can turn them into sentences

Tuesday, 21 December 2010

Customer Supply III

So let's try that again: How. Do You. Want. It. To. Work?

Well, I'm not completely sure, if I'm honest. That's the point of these posts. Bear with my while I brainstorm things a little


So that's more a list of the factors involved.  I'd add a bif of explanation, but after half an hour waiting on the phone for a heating engineer I'm not sure I'm up for it.

Later, all.

Customer Supply II

So how do I want to do it?

Well, I'd like to model the customers and use that model to adjudicate their interactions with the girls. WhoreMaster started down this road, but never quite got there. There's a big array of customers, but as it turns out most important interactions are computed as on-the-fly probabilities, and/or affect temporary customers that are created and discarded in the same transaction.

So this means that if a customer leaves the premises pissed off because you're using fake plastic tentacles for the third week running, he'll be back with the same probability the next week, and every week thereafter. It means that the PC can kidnap his customers wives and children and the customer will bear him no ill will. I think it's even possible to abduct his womenfolk several weeks running, because they're created on the fly too.

And it means that if the PC tortures and enslaves half of Sleaze Street, it's going to have no impact on the customer supply, because the dead or enslaved punter was generated on the spur of the moment anyway.



 None of this is criticising necno. WM has expanded well beyond it's initial parameters, and it is manifestly unfair to expect it to do things that it was never designed to do. It's also possible that it did all these things, and a bunch of bumbling newbies like myself didn't see the intention and accidentally messed it all up. The important thing here is that it works and it works well enough.


So if it ain't broke, why fix it?

Good question. Partly it's the stuck-on-an-asteroid business. In a sizable city, you can probably afford to piss off your customers to an extent, and there are enough still out there that it doesn't touch your business. At the start of Clonemaster you're going to depend on a fairly limited number of passing ships, each with a small number of potential customers. If I was playing the game, I think I'd be disappointed if I could rob and enslave the crew of each ship that docked, and still have turn up with the frequency and the same expectations. So your history with the crew is going to matter. So is your relationship with the captain. And the girl's interaction with crewmembers is going to have an effect.

And partly, it's that I want to manage this on a much smaller scale (another thing CM is going to have in common with Otherworld) and pay more attention to they girls. It's a resource management game, so let's make it so that how well you do depends in part on how well you manage those resources. (Some people may disagree. Those I would direct towards WhoreMaster which works just fine, and is ready to play right now)
 

Customer Supply

I started thinking about this as something for an Android WM variant, but it occurs to be there's an identical problem to be solved in Clonemaster. So let's talk about that instead. It'll keep me from having too many irons in the fire.

Anyway: Customer Supply.

In the game, the player starts out in a deserted base carved into an asteroid in the Belt. He needn't stay lonely for long however as the Base's planners thoughtfully included a girl-making-machine and several tons of raw biomass. All the same, there's going to come a point where the player needs to get some  supplies from outside if he's going to supply. And give, this game traces its descent back to WhoreMaster, you can probably guess how he's going to approach the problem.

Scenario:

So let's assume that the player has some girls (I'll call them Xaviera, Yvette and Zoe) and that he's activated the base's radio beacon and persuaded a passing ship to stop and, umm "trade".

What I'd Like:

What I'd like is for passing ships to dock for a few days, while the crew release long building in-flight tensions, as it were. The simplest way to do this is to say something like:

duration_table = {
    { low =   0, high =   20, days = 0 },
    { low =  21, high =   40, days = 1 },
    { low =  41, high =   80, days = 2 },
    { low =  81, high =  100, days = 3 },
    { low = 101, high =  140, days = 4 },
    { low = 141, high =  160, days = 5 },
   # and so on as desired/
}

die_roll = d100() + ship.average_horniness - ship.captain.impaitence

length_of_stay = ship_duration[die_roll].days

It says something when even the easiest way to do a thing turns out to be somewhat complicated.

Anyway, that's the easy way. Naturally, I don't want to do it like that...

Beware the gratitude of Gods, my children...

Beware the gratitude of gods: their idea of a blessing does not always correspond to our own...

As evidence, I cite the Great God Maixioukofalot must have been pleased with the shout-out I gave him in the last message. He's bestowed his benisons upon Yours Truly and I too am now coughing and sniffling with the best of them. The  week of quiet debugging I was anticipating seems destined to be one of freezing cold (did I mention our boiler is on the blink?) and medication. On top of all that, my blog seems to be turning into a soap opera. Go figure...

Anyway, a head full of cotton wool means I'm not going to do any heavy duty debugging, so I'm going to try jumping to another part of Clonemaster where the going isn't quite so heavy and see what progress I can make there...

Monday, 20 December 2010

The Evil Aztec God Maixioukofalot...

The evil Aztec God Maixioukofalot has  bestowed his blessings upon my missus. She's holed up in the bedroom as I type, hacking and spluttering, and it looks like my nice quite pre-xmas week is going to be rather less quiet and have rather less free time than I'd planned.

I have managed to sneak some dev time in. The problems I mentioned in the last post are sorted, so that's ok. Now, however, if I add a new narrative, it junks all the options attached to choices. Probably because adding a narrative still forces a full rebuild of the tree... I bet that's something to do with it.

Also had a bit play with the Android SDK. I have a real life task coming up involving Android, so I need to give it some attention shortly. Still, I can't help getting ideas...

Options nesting correctly.

Options now appear under choices, so I created a bunch of stuff and saved it. Images aren't storing, and thumbs appear as images in the treeview. And choices aren't shuffling down when an option is moved. 

The indentation is broken in the same file as well, but I can live with that if all the needed information is preserved.

Sunday, 19 December 2010

Been a funny old day...

... flash, Android, Boo ... been all over the place really.

Choice/Option pairings are very nearly working as I want them to work. I still want the options embedded a level further down. Nearly got that sorted out, but too tired to think about it right now.

I'm going to call it a night.

Android

I should also add that one of the RL time sinks at the moment is my Android smartphone. I have to say, I think it's a wonderful piece of kit (Galaxy-S) and I'm going to have a shot at developing something for it at some point in time.

My wife on the other hand is completely in love with hers ... but she can't get iPlayer on it. So today's exercise is how to upgrade the firmware to the latest (Samsung Kies seems to be the sane way to do it).

Nothing too complex, but it's all part of the learning curve. I have no idea what I mean by that...

OK, back to work

So: scene editing app for Clonemaster: I've got choices and options on the go. Two problems with options:


First of all, the options should be in a level under the Choice tag. Not critical, I suppose. Second is that option name doesn't update when the focus leaves the "text" field. It does when the panel loses focus, but that's a little late.

Also, the Choice panel is kind of bland at the moment.



I'm tempted to add in a "prompt" field. So the Choice would have "What do you want to do now?" That would give me something to add to the panel (so you could tell it wasn't a bug) and something for the treeview label as well. The prompt would wind up as a snippet in the Lua engine, although I'd need to store the text as an XML attribute.

Update:

Hmm... OK. It's not a problem with options. They're working perfectly. It's a problem for all the narrative items. Snippets  are broken the same way.

So something about the way I'm updating the treeview, presumably ... and calling TreeView.Refresh() forces the update.  Let's add a prompt to Choice now...

More Flash

Well, I eventually resorted to running Flash on a VitualBox instance, which will do, I suppose. That was pretty much it for yesterday. Real Life had its demands, especially with Xmas looming so large. I did some fiddling SceneEdit as well but nothing substantial to report.

I did end up looking at an old flash project of mine. I kind of burned out on this one and it stalled, but I haven't given up on it just yet. In fact right at this minute I'm really tempted to blow the dust off it and see if I can take it forward.

I must be getting bored with that scene editor app. My brain keeps casting around for other things to do.

Anyway, since I'm on the subject, here's the game so far as it got: Mad Science 101. Password is "docclox"

Adult content and all that. Adult themes. Naughty words. A little bit of animated shagging. I better put the over-18 warning back up again.

Saturday, 18 December 2010

Flash CS5

I've spent most of today poking at Flash CS5 trying to get it to unstall under wine. Apparently it's possible, although I've not had much joy of it, as yet.

Personally I'm quite happy with Flash 8 which runs under wine with no problem at all. But I want to try some experiments using the Otherworld source, and for that, I need CS3 or better.

Friday, 17 December 2010

Lua.NET

Just spend some time looking at ways to run .NET assemblies from Lua or Lua from inside .NET.

There's a promising looking doodad called LuaInterface, which was goign great until I tried to run it under  mono. Uses mixed mode assemblies, so no use to me, thank you kindly.

LuaSharp looks to be more promising, in that it promises to be a pure .NET version, and so should work.

The benefits here are that I'd be able to run the lua classes from inside .NET and thus lose one potential source of errors. On the other hand, I'd probably lose all that in the time taken to get it all working, so it's not a high priority.

Still useful to know the tech is out there.

[edit]

Forgot the initial point of this diversion: can I validate lua code in the Scene Editor? Should I? It's going to be a real pain to edit the scene and then have the lua fail with a simple syntax error when it runs. On the other hand, that's what a player screen is for.

I guess the gripping hand is that the player screen isn't going to play properly without lua interpretation. And even then, not if the lua depends on Clonemaster globals that won't be set in the editor. I suppose I could have a userdata variable "editor_mode" which would allow an opening func to spoof those values...

Hmmm...

Image Panel Working

The Story So Far:

Having got a Lua based framework to correctly process an XML based narrative format, Our Hero decides to switch languages to create a GUI based editor for the format.

So far he's got as far as the Image Panel:




















That seems to work. Next should be Func, if I'm working through tabs in order.

Clonemaster.dll

Added a Clonemaster namespace to the dll. Turns out there's a BackgroundImage property to control, so I still needed to disambiguate the damn thing...

Bugger, that seems to have broken something. Buttons aren't being disabled as they should, and the narrative index isn't being set.

Snippet is broken too, so it's not just a background image thing.

Hmm... I bet its another type name switch that broke with the namespace

Update:

That's exactly the problem. Fixed version (hopefully):

                tv.AfterSelect += def(o,e as TreeViewEventArgs):
                        n = e.Node
                        print "node.index = ${e.Node.Index}"

                        ts = "${n.Tag.GetType()}"

                        if ts == "Clonemaster.Narrative":
                                NarrClick(n.Tag, n.Index)
                        if ts == "Clonemaster.Scene":
                                SceneClick(n.Tag)
                        if ts == "Clonemaster.Snippet":
                                SnipClick(n.Tag,n.Parent.Index, n.Index)
                        if ts == "Clonemaster.Thumb":
                                ThumbClick(n.Tag,n.Parent.Index, n.Index)
                        if ts == "Clonemaster.Choice":
                                ChoiceClick(n.Tag,n.Parent.Index, n.Index)


I don't know of a good OO way to get around this one. I suppose I could have wrapper func to raise the relevant event. Is it worth the trouble, I ask.

Let's see if I get any more problems from tjhis.

Thumbnail not saving, part 2

I thought I'd write a test to make sure narratives saved their thumbs correctly. This passes:

        [Test]
        def save_scene_thumb():
#
#               let's have the variables separate
#
                s_name = "scene name"
                s_desc = "scene desc"
                n_name = "narrative name"
                n_desc = "narrative desc"
                s_defl = n_desc
                t_name = "player"
                t_path = "data/images.pc.png"
                t_op = "show"
                t_loc = "left"
#
#               then we can interpolate them into the target string
#
                target = detab("""
                        <scene name="${s_name}" default="${s_defl}" desc="${s_desc}">
                         <narrative name="${n_name}" desc="${n_desc}">
                          <thumb name="${t_name}" path="${t_path}" operation="${t_op}" location="${t_loc}" />
                         </narrative>
                        </scene>
                """)
#
#               ... and use them to initialise the scene
#
                sc = Scene()
                sc.name         = s_name
                sc.default      = s_defl
                sc.desc         = s_desc
                n = sc.Add_narrative(n_name, n_desc)
                t as Thumb = n.Add(Thumb())
                t.name = t_name
                t.path = t_path
                t.operation = t_op
                t.location = t_loc
#
#               now we need a string writer
#
                using sw = StringWriter():
                        sc.save(sw)
                        assert target = "${sw}"


So we can probably rule out a bug in narrative or thumbnail. The next most likelty cause is that the thumbnail is never being added to the narrative. Investigating...


Update:

Got it: Narrative was testing the type of the narrative item and calling class specific save routines. Now that all items have a common base class, we can do this the proper OO way.

Choice at the wrong logical level?

Hmmm...

I was thinking about how to word the help screen.

"A Scene is basically a complete ADV sequence. Scenes are made up of narratives which are sequences of text and images joined by jumps and choices..."

And thinking about it, that makes more sense. Informally:

Scene         = Narrative [[ ChoiceOrJump Narrative ] ... ]
ChoiceOrJump  = Choice | Jump
Narrative     = NarrativeItem [ NarrativeItem ... ]
NarrativeItem = Snippet | Background | Thumbnail | Chapter | Func


The question is, is it worth redoing all the lua test code just to make things hang together a little more logically. I'm tending towards "no", I have to admit...

Image selection for thumbnails

OK, I can find an image with the image browser now.


















Which is cool enough. The same code will more or less copy and paste into the background panel as well, so that's some real progress. I get funcs going, and options (with embedded funcs) and this sucker is about done. (Although I might include a playback feature - thereby turning it into a self contained ADV app).

However, it doesn't save right. I save this screen above, I get this:

<scene name="NewScene" default="" desc="">
 <narrative name="NewNarrative" desc="" />
</scene>


Yes, the day just isn't complete until I've posted an XML fragment. Also, there's no thumbnail tag embedded in the narrative. I need to fix that next.

Thursday, 16 December 2010

I should have knocked on wood...

Well, I got the code conflict sorted out. Didn't get too much else done; felt dog tired and took and early night.

I'll see about getting those image panels working today. There's not a lot to do, but it all needs testing, and that slows things down. It's frustrating.

Config Panel, Stale Source

Interesting morning. I now have fully loading and saving config files. I also have a config panel which lets you use a folder browser to specify the game directory where the game should look for images.

On the downside, the thumbnail panel I have here doesn't have the picturebox in it. Which means that something went wrong updating the source files on my local copy. I can't fix that until tonight, so in the meantime I think I'll work on something else.

The background image panel sounds like a good choice - lot of the same issues there. Problems solved would directly apply to the thumbpanel, but no real danger of overwriting working code.

Wednesday, 15 December 2010

The nice thing about a blog...

... is that every time I want to beat myself up about how little I got done, I can look over the day's progress and see how far I've come.

Got the loading issue fixed, by the way. And a config class, plus load and save tests. The next up is a browse button so you can have images other than a green question mark in the thumbnail panel, and the config panel so you can tell the app where to look for images.

I don't think I'll bother with import just yet. People can either make sure the file is in the data directory, or they can navigate up out of the game folder and not have it zip up right. It's a dev tool; there's a limit to how much time I can invest in "user friendly" before it starts impacting on "game working"

Ahh, I need some sleep. Later, people.
I'm grasshoppering around like mad here. This is the thumbnail panel


















Needs an import button, a browse button under the image, and it would be nice to have a lookup between names given and images, so you could pick the names out of a dropdown box.

Thing about the last idea ... I''d need to save it, and probably make it part of the game itself. And If I'm going to have  named shorthand for thumbnail pics, I want to have another tag for mood, so I can disply emotions

So I guess I'll leave that for future expansion

Bits and Bobs

OK, a few things to do at the mo', and I don't want to forget any of them:
  • I need a ConfigPanel to set config options. Doesn't matter that there's only one of them right now.
  • I need a configuration menu option, since I'm running out of button space
  • I need a "+Option" button to add options to Choices
  • I need a "Help" menu option, since I'm going to need to explain what all the tag types mean at some point.
  • new button modes: 
    • config mode for  when config panel is up
    • choice mode for to enable adding options
  • put up a static ToDo page so I don't need to keep hunting for this post

Loading is broken

Something in all of the means the saved scenes don't load at all.  Better sort that out next

Tests all pass ... apart from load_option which isn't written yet, anyway. So it's not the load part...

Seems to work

That seems to work just fine. This is how it turned out:

#
#               common code for all the narrative item buttons
#               inserts an item afte the current one (if any)
#               and then inserts a corresponding node into the
#               tree view
#
                def insert_narrative_item(typ as System.Type):
#
#                       this should never be called unless we have a current
#                       narrative
#
                        assert narrative_index != -1
#
#                       get the narrative object
#
                        n as Narrative = scene.narratives[narrative_index]
#
#                       add one to the current item index so it points at
#                       the slot where the new item will be stored
#
                        item_index++
#
#                       create the item and add it to the narrative list
#
                        it = n.Add(typ(), item_index)
#
#                       insert a node into the treeview for the snippet
#
                        tree_panel.insert(narrative_index, item_index, it)

#
#               this fires if someone clicks the "+Snippet" button
#
                button_panel.snippet.Click += def(o,e):
                        insert_narrative_item(Snippet)

#
#               fires if someone hits +thumb
#
                button_panel.thumbnail.Click += def(o,e):
                        insert_narrative_item(Thumb)



I'm pleased with that. It's going to save a lot of time, (or at least a lot of copy/paste errors), but shouldn't be too hard to figure out when I have to change it.