Thursday, June 26, 2014

Ancient evil


Things are progressing quite well, for chapter 1. Today I'd like to share with you this new NPC I created -- its a minor daemon, inhabiting Alatas' crypt:


I think it kind of looks like something out of HP lovecraft, if you squint enough. This thing is meant to summon skeletons, which look something like: 
Note skeletons are super small because of the 32x32 tile format for the game.



Saturday, June 14, 2014

Fighting Crabs by the seashore

So, you're having a stroll along the beach, when all of a sudden:


Yep, its a big mutha of a crab. That's what's going on here in this video:



This is an example of the combat engine in play for the game. Its pretty rough right now, but illustrated here is:
  • You can hit enemies
  • They can hit you
  • Its possible (but currently hard) to avoid enemy strikes
In theory there's an action element here that can get more interesting with ranged weapons, variable attack speeds, attack patterns; I am also contemplating a block move, but I'm not sure if it will make the game more fun. So more on that soon.

Thursday, June 12, 2014

Reasonable Random Hostile NPC Encounters

Here's the question I was asking myself -- how do I create random encounters with enemies, but limit the seemingly random nature of them? Here are the requirements I wanted to fulfill:


  1. The NPCs should make sense with the surrounding terrain. For example ... I shouldn't encounter beach creatures in the forest.

    Creatures following me with hostile intent should not follow me out of their normal habitat without special coercion. It shouldn't be normally allowed to lure a crab so far out of the beach that it ends up in the forest with me (unless thralled or something)
  2. I shouldn't be continuously mobbed by creatures -- the "tempo" of encounters should be somewhat regulated and related to the geography.
To this effect, there has to be something "sampling" the terrain around the player as they walk through the world. 

  1. Each tile self identifies itself as belonging to a terrain type.
  2. The sampler samples a 4x4 area around the player, and tallies the number of tiles per terrain.
  3. The area around the player is declared a terrain type if the terrain bucket exceeds 30% of the total sampled tiles.
The random encounter orchestrator piece should then decide whether or not to spawn an npc within the vicinity (but not in view) of the player, based on this information:
  1. Are there too many hostiles within the area already -- have we reached the maximum number of hostiles that should be accosting the player at any given moment, based on his level, attributes, etc.?
  2. Are there too many of the type of NPC that can be normally spawned in the terrain type already?
If the answer is "no", then we should spawn the NPC.

I plan to try to implement these algorithms into the game.

Friday, June 6, 2014

Basic conversation engine working





Yay, the basic conversation engine is in place. As an added bonus, its now possible to trigger world events based on conversation elements (dialog, responses).

Illustrated above is the ability to make the character sit down at the end of a piece of dialog.

Here's the definition for that, notice the event stanza in the triggers for the dialog:

<key>2</key>
<dict>
    <key>text</key>
    <string>I understand. But hurry! there is not much time.</string>

    <key>nextDialog</key>
    <string>_END_</string>

    <key>triggers</key>
    <array>
        <dict>
            <key>events</key>
            <array>
                <dict>
                    <key>type</key>
                    <string>entityStand</string>
                    <key>entityName</key>
                    <string>Senopati</string>
                    <key>action</key>
                    <string>sit</string>
                </dict>
            </array>
        </dict>
    </array>


</dict>

The possibilities are wide open now: set quest flags, receive items, play music, whatever I need to happen in conjunction with dialog.

Wednesday, June 4, 2014

Working on the conversation engine

This bit's tough. I've elected to try to build my own "scripting" engine, instead of integrating Lua ... because I want to see if I can design and build such a thing.

My goal isn't to build a DSL, but rather design a JSON schema which can be used to describe the world, and interpret them.

One type of scriptable world element is the conversation engine. Given an XML structure (.plist format native to IOS), that looks something like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>entityName</key>
        <string>Senopati</string>

        <key>entryPoints</key>
        <array>
            <string>1</string>
        </array>

        <key>dialog</key>
        <dict>

            <key>1</key>
            <dict>
                <key>conditions</key>
                <array>
                    <dict>
                        <key>type</key>
                        <string>flag</string>
                        <key>params</key>
                        <dict>
                            <key>operation</key>
                            <string>equals</string>
                            <key>flagName</key>
                            <string>test</string>
                            <key>flagValue</key>
                            <string>true</string>
                        </dict>
                    </dict>
                </array>

                <key>text</key>
                <string>Is your heart resolved, Putra?</string>

                <key>responses</key>
                <dict>
                    <key>1</key>
                    <dict>
                        <key>text</key>
                        <string>Yes, honored Seno. I am prepared.</string>
                        <key>ifSelected</key>
                        <dict>
                            <key>nextDialog</key>
                            <string>3</string>
                        </dict>
                    </dict>

                    <key>2</key>
                    <dict>
                        <key>text</key>
                        <string>I am not yet ready, beloved Seno. I need more time.</string>
                        <key>ifSelected</key>
                        <dict>
                            <key>nextDialog</key>
                            <string>2</string>
                        </dict>
                    </dict>
                </dict>

                <key>isEntryPoint</key>
                <string>yes</string>
            </dict>

            <key>2</key>
            <dict>
                <key>text</key>
                <string>I understand. But hurry! there is not much time.</string>

                <key>nextDialog</key>
                <string>_END_</string>
            </dict>

            <key>3</key>
            <dict>
                <key>text</key>
                <string>I am glad, as I cannot submit this sanctuary to my will much longer.</string>

                <key>nextDialog</key>
                <string>4</string>
            </dict>

            <key>4</key>
            <dict>
                <key>text</key>
                <string>My strength is waning, and I shall rejoin my brothers and sisters, lost these ten years.</string>

                <key>nextDialog</key>
                <string>_END_</string>
            </dict>

        </dict>

    </dict>
</plist>

... I want to be able to build an 'intepreter' that can setup the typical in-game dialog interface that looks like this:
The basic flow behind this is as follows:
  1. For each target NPC build a series of dialog nodes.
  2. One or more of these dialog nodes are declared as "entry points" to the conversation
    1. These are guarded by conditions
    2. The conditions check certain quest flags ("have I talked to this person before" flag; "do I have the magic doohickey" flag)
    3. The entry points should be mutually exclusive: no two entry points should be valid at any given time.
  3. Dialog nodes present their text, and
  4. An array of possible responses, whose appearance is guarded by conditions in the same way as described in (2).
  5. Clicking on a response will emit an event, which is usually going to be the event that brings you to the next node of the dialog tree, or
    1. End the conversation
    2. Trigger some other world event (maybe give you an item, set a quest flag, or something).
So far the conversation engine appears to work.
Given this test code:
[self.context.gameState.flags setObject:@"true" forKey:@"test"];

Entity *npc = [self.context.entityManager getByName:@"Senopati"];
Dialog* dialog = [self.context.dialogManager startDialog:npc.id];
NSLog(@"%@",dialog.text);

NSMutableArray *responses = [self.context.dialogManager computeAvailableResponsesFor:dialog];

Response *response = [responses objectAtIndex:1];
NSLog(@"%@",response.text);

Dialog* next = [self.context.dialogManager computeNextDialogFor:dialog :response];
NSLog(@"%@",next.text);

while ( next ) {
    next = [self.context.dialogManager computeNextDialogFor:next];
    if ( next ) {
        NSLog(@"%@",next.text);
    }
}
I'm exercising the conversation XML properly:
2014-06-04 22:05:40.689 rpg[18762:70b] Putra, is your heart prepared? 
2014-06-04 22:05:40.690 rpg[18762:70b] Not yet, beloved Seno. I am not ready.
 2014-06-04 22:05:40.690 rpg[18762:70b] I understand. But hurry! there is not much time.
Looking promising! Now to implement the UI bits.