OAX6 Source Code Released, Instructions to create a game.

The source code for OAX6 can now be checked out by campaign backers as defined in their perk level.

It is still early, but even at this stage, a simple game could be created! I hope some of them get to play around with it and come back with suggestions. Of course, as development continues it will become easier (ultimately providing editing tools for this) and more complex games will be able to be created.

Below are the current, 0.1 instructions to create a game using OAX6:


How to Create a Game Using OAX6

Disclaimer

This guide applies for v0.1, first version publicly available to backers. We are in a very early stage still, the engine is limited both in what it can do and on how easy it can be used.

This build is provided for the following reasons:

  • So you can fulfill your curiosity on how the game works.
  • So you can start having an idea of the capabilities and format of the engine for your future projects using it.
  • So that more people (who cares about the project) has access to the source in case something terrible happens.

Setup

After cloning the repository

The default scenario should show up in the browser.

Maps

Tiled maps are saved on scenarios/wod6/maps.

Make sure you are using uncompressed JSON format.

The maps should have the following layers:

  • Solid Tiles: Any tile in this layer is considered as solid when loaded on the engine
  • Mobs: Tiles placed here should have at least an ‘id’ custom property, pointing to a valid MobType. It can additionally have a type, which can be ‘mob’ or ‘npc’, if the type is npc, then it should have a NPC id instead of a MobType id
  • Buildings: This and the following 4 layers don’t have any logical effect, use them to make cool maps.
  • Vegetation
  • Objects
  • Terrain

Scenario Data

Set your scenario data in scenarios/wod6/Info.js

startingState

  • minuteOfDay: Determines the stating time
  • map: Points to the list of maps below (name)
  • x: Starting player position
  • y: Starting player position
  • party: List of NPCs in the starting party, id, x and y
  • scene: Points to the list of scenes below

maps

  • name: Identifies the map
  • filename: Filename in scenario/wod6/maps/

scenes

Key is the scene key, each scene is a list of string which are shown in succession

Appearances

Defined in src/js/data/Appearances.js

  • The numbers refer to indexes on the tileset
  • The mob appearances include 4 frames for each direction

Items

Defined in src/js/data/Items.js Each item can have the following attributes:

  • id: Identifies the item
  • name: Description of the item
  • appearance: Referencing an item appearance on Appearances.js
  • flyAppearance: Used when the item is “flying” (for example when thrown)
  • throwable: Whether the item can be thrown
  • range: Max distance for throwing the item
  • flyType: ‘rotate’ or ‘straight’ animation to use when throwing the item
  • damage: Points of damage caused

MobTypes

Defined in src/js/data/MobTypes.js

  • id
  • name
  • appearance: Points to Appearances
  • hp
  • damage
  • defense
  • speed: Determines the order in the queue for combat mode
  • corpse: References Items.js, item placed on the floor when the mob dies
  • intent: ‘seekPlayer’, ‘waitCommand’, ‘wander’, ‘combat’

NPCs – Basic Data

Defined in src/js/data/NPCs.js

  • id
  • name
  • type: Points to MobTypes
  • alignment: ‘b’ for friendly, ‘a’ for enemy, ‘c’ for neutral. Likely to be revised
  • weapon: Points to Items
  • firstTalk: Number, will talk to player first if he gets closer than this.
  • intent: Same options as MobTypes

NPCs – Conversations

The conversation trees are defined in the “dialog” attribute of each NPC.

They are a list of objects, each object is a dialog fragment, tied to a keyword.

Each dialog fragment can have either

  • A list of dialog pieces (see below)
  • A list of dialog variants (see below)
  • A synonym keyword

A dialog variant contains a condition with a flag name and value, and a list of dialog pieces. If the condition is met the conversation will follow these dialog pieces.

A dialog piece can be either

  • A string of text
  • An object with the following types:
  • “event” is similar to a normal text, except it describes something happening instead of something the NPC is saying.
  • “dialogInterruption” is similar to a normal text, except another NPC is talking
  • “endConversation” finishes the current conversation
  • “joinParty” makes the NPC join the party
  • “setFlag” sets a global flag to a given value

There is a special dialog fragment marked as “unknown” which is used when the keyword input by the player doesn’t match any dialog fragment or variant.

Assembling a build

Once you have all data set, you can execute the build.sh script, then the game package will be available in the build directory (open the index.html file using a web server)

Trailer for the Roguelike Celebration 2018

The Roguelike Celebration is happening again this year, October 6 and 7. I will be flying to SanFran to assist and also give a talk about the History of Roguelikes.

Had an idea running on my head for a while to make a “trailer” for the event (no one asked me for it). At first, I thought of creating a playable classic roguelike using my JSRL roguelike template. I actually did create the foundations for it (as in walk in a predefined map), but it lacked the cinematic potential for a short trailer. In any case, I integrated the “torch” effect from the unicodetiles.js example into JSRL, which may be useful. You can check out the integration here.

Screen Shot 2018-08-10 at 7.30.17 AM

Then I had another idea and I just couldn’t be at peace until I implemented it. I think it occurred to me a day while driving and listening to the Mega Man III OST. I thought I had found the perfect tune for it. So, even in a busy week with lots of work, I just had to do it.

The trailer features the awesome speakers’ lineup in a “robot-masters” NES Megaman stage selected style.

I implemented it using JavaScript and Phaser, you can check the source code here and the demo running live here

Of course, there’s little structure to the project since it was meant to be a quick job (and is also pretty simple). Most of the relevant logic can be found in a single Object, the Game state. I set up a stage with a black background and the gray strip, as well a Sprite object for the character and 4 text fields. I used a Megaman 10 font (I had found another one for Megaman 2 but for some reason, it could not be loaded as a web font), I performed a simple centering function based on each line’s character count to keep the characters as sprites in the grid (thus getting a bit close to being a NES “background sprite”?).

There was also a simple “particle” animation in the background, instead of stars they were small @ signs because, you know, roguelike. I used the same color palette used on the Roguelike Celebration logo for them.

Of course, the most fun part was doing the pixel art for the speakers. I used a bunch of Mega Man 2 robot masters as a base and then I proceeded on tweaking them for each speaker. The ones I know in person where easier, for the others I had to do a bit of stalki Internet research, I hope I managed to capture their likeness.

Finally, I reused the “Retro TV with scanlines” from Cat Cafe.

 

OpenArthurianX6 – Pushing dev for Milestone 1

Still not there but it’s been a lot of work. As I worked towards the goals for Milestone 1 I found quite a bit of work was needed on the dialogs and the mobs AI.

Screen Shot 2018-08-04 at 10.20.31 PM

Changes

  • “The Law of Virtue” scenario
    • New test map (Forest clearing)
    • Cutscenes
    • Asteroth conversation
    • Shamino conversation
  • Scenario setup
    • Read starting map, starting time of day and starting player position from Scenario Info
    • Allow placing NPCs and Mobs on the tiled map
  • Added support for simple “Cutscenes”, that is sequences of text dialogs to tell the story.
  • Dialogs
    • Support multiple fragments of dialog per keyword
    • Add variants per keyword based on player flags
    • Add support for “triggers” executed inside the conversation
    • Add triggers to join the party, end conversation and set player flag
    • Fall back to “unknown” dialog if no match on variant
    • Merge triggers into the dialog as objects so they happen sequentially
    • Add support for dialog qualifiers (in addition to normal dialog lines)
      • Dialog interruption: for other NPCs to participate in.
      • Event: For event descriptions
    • Add support for keyword synonyms
    • Allow NPCs to start a dialog when getting closer
  • AI
    • Make friendly mobs act differently than party members
    • Make unfriendly NPCs have a minimum range before chasing
    • Implement intents for mobs
      • seekPlayer: Do nothing waiting for the player to be on sight
      • waitCommand: Do nothing.
    • Implement subintent logic based on intent.
    • Use direct LOS to define if can track player.
  • Combat
    • Speed up combat
  •  Art
    • Added Shamino and Soldier Mob appearances

Source Code

Funders with early source access privileges will be given access to the source code repository on request starting now!

Dev Streams!

Note that some work was done offline, of course.

 

The history of “Ultimate Collector”, Garriott’s stab at social gaming

In 2018, Portalarium is mostly associated with Shroud of the Avatar, the controversial multi-million dollars crowdfunded MMO / Single Player computer RPG. With all the noise it has caused, it’s easy to assume this game was Garriott’s comeback project after his long post-Tabula-Rasa hiatus.

However, before diving into the first new millennium iteration of his “Ultimate RPG” dream, Richard was strong on taking his newly founded company, “Portalarium“, into something completely different: games in social networks, and their efforts ultimately led them to partner with one of the biggest names on the scene: Zynga.

UC3

As you might have guessed, the game is now long gone. It actually never managed to have a broad public launch (although a couple of videos in youtube about hacking the game indicate it might have been shortly available to the public). Portalarium removed all information about the game from their website and killed all of its presence in social media, and it seemingly never made it past the threshold to be included on Zynga’s social games portfolio.

Still, the history of the development of this game is intertwined with Richard plans for the “Ultimate RPG”, which makes it interesting to imagine what Shroud of the Avatar could have been.

CLICK HERE TO READ THE FULL ARTICLE!

Hulk-Bobble-Head

ProcJam Summer 2018 – Pokemon Building Generator – Part 1

Procjam Summer 2018 has started so here I go. This will be a small project to create classic Pokemon style houses. (Guess what I might end up using it for)

This will be a two steps generator, the first thing to do is defining a logical model for the houses. We start by examining some examples to extract the structure and an initial set of variations:

Screen Shot 2018-06-20 at 3.23.33 PM

Structure

  • Blocks of 4 tiles
  • Windows and walls can be placed at tiles, having one tile for padding at every side (available tiles = blocks – 1) * 2, this padding is used to project the shadows of the building.
  • Doors can be placed at blocks, having one block for padding at every side.
  • Distorted perspective, the “depth” of the building is represented as blocks of the ceiling.
  • The last floor gets 2 less available tiles due to roof slant

Attributes:

  • Structure
    • Width: 6 blocks
    • Height: 2 blocks
    • Depth: 2 blocks
  • Front
    • 1st floor
      • Windows: Tiles 1, 2, 3, 6, 7, 8, 9 and 10
      • A door at block 3
      • Wooden wall (1 to 10)
    • 2nd floor
      • Windows: Tiles 2, 3, 4, 7, 8 and 9
      • Wooden wall (1 to 3)
      • Brick wall (4 to 10)
  • Roof
    • Slanted
    • Tiled

Next example:

Screen Shot 2018-06-20 at 3.34.38 PM

Front

  • 2nd floor
    • Bar border

Next Example:

Screen Shot 2018-06-20 at 3.43.19 PM

Structure: The last floor gets all available tiles if the roof is flat

  • Front, First floor
    • Poke sign at block 3
  •  Roof
    • Flat

Let’s confirm our model covers all wanted cases

Screen Shot 2018-06-20 at 3.52.51 PM

  • Structure
    • Width: 8 blocks
    • Height: 6 blocks
    • Depth: 2 blocks
  • Front
    • 1st floor
      • Windows: Tiles 6, 7, 10, 11
      • Doors at blocks 2 and 4
      • Mart sign at block 6
      • Brick wall
    • 2nd floor (…)
  • Roof
    • Flat
    • Tiled

Having this, we can start thinking on our higher level generator, its input will be the type of building and its size. Following are the types of buildings we’ll support: House, Gym, Mart. As for the sizes, they will be: Tiny, Small, Large, Huge.

The output of the high-level generator is a logical model of the building, which is used by the lower-level generator to produce a map of tiles. An example of the 1st output for a Large House would be:

Screen Shot 2018-06-20 at 3.34.38 PM

{
  width: 4,
  height: 2,
  depth: 2,
  floors: [
    {
      wall: 'wood',
      windows: [4, 5],
      doors: [1]
    },
    {
      wall: 'wood',
      windows: [2, 4, 5],
      border: true
    }
  ],
  roof: {
    type: 'slanted',
    material: 'tiles'
  }
}

Let’sa go! We fire subl and produce this:

const Random = {
  chance(c) {
    return this.range(0, 100) <= c;
  },
  range(min, max) {
    return Math.floor(Math.random() * (max - min + 1) + min);
  }
};


const SIZE_RANGES = {
  tiny: {
    minw: 3,
    maxw: 4,
    minh: 1,
    maxh: 1,
    mind: 1,
    maxd: 1
  },
  small: {
    minw: 4,
    maxw: 5,
    minh: 1,
    maxh: 2,
    mind: 1,
    maxd: 1
  },
  large: {
    minw: 5,
    maxw: 6,
    minh: 2,
    maxh: 3,
    mind: 1,
    maxd: 2
  },
  huge: {
    minw: 5,
    maxw: 8,
    minh: 3,
    maxh: 5,
    mind: 2,
    maxd: 4
  }
};

const SLANTED_ROOF_CHANCES = {
  house: 90,
  gym: 20,
  mart: 10
};

const WINDOW_CHANCES = {
  house: 50,
  gym: 20,
  mart: 50
};

// https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
function shuffle(array) {
  var currentIndex = array.length, temporaryValue, randomIndex;

  // While there remain elements to shuffle...
  while (0 !== currentIndex) {

    // Pick a remaining element...
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;

    // And swap it with the current element.
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }

  return array;
}

const generator = {
  generate(type, size) {
    const model = {
      width: 0,
      height: 0,
      depth: 0,
      floors: [],
      roof: {},
      type,
      size
    }
    // Size of the building
    const sizeRanges = SIZE_RANGES[size];
    model.width = Random.range(sizeRanges.minw, sizeRanges.maxw);
    model.height = Random.range(sizeRanges.minh, sizeRanges.maxh);
    model.depth = Random.range(sizeRanges.mind, sizeRanges.maxd);
    // Type of roof
    model.roof.type = Random.chance(SLANTED_ROOF_CHANCES[type]) ? 'slanted' : 'flat';

    for (let i = 0; i < model.height; i++) {
      model.floors[i] = this.generateFloor(model, i);
    }
    return model;
  },

  generateFloor(model, floorNumber) {
    const floorModel = {
      wall: '',
      windows: [],
      features: []
    }
    const useableBlocks = [];
    for (let i = 0; i < model.width - 2; i++){
      useableBlocks[i] = true;
    }
    const useableTiles = [];
    for (let i = 0; i  {
      if (!t) {
        return;
      }
      if (Random.chance(WINDOW_CHANCES[model.type])) {
        floorModel.windows.push(i);
      }
    });
    return floorModel;
  },

  getRandomSpace(array) {
    const availables = array.find(x => x === true);
    if (!availables) {
      return undefined;
    }
    const spaces = array.map((x, i) => ({x, i})).filter(x => x.x === true);
    return shuffle(spaces)[0].i;
  }
}

const model = generator.generate('mart', 'huge');

console.log(JSON.stringify(model));

Running it with nodejs gives us a variety of models already:

{
  "width":6,
  "height":2,
  "depth":2,
  "floors":[
    {
      "wall":"",
      "windows":[
        4,
        7
      ],
      "features":[
        {
          "x":1,
          "type":"door"
        },
        {
          "x":3,
          "type":"gymSign"
        }
      ]
    },
    {
      "wall":"",
      "windows":[
        3,
        9
      ],
      "features":[

      ]
    }
  ],
  "roof":{
    "type":"flat"
  },
  "type":"gym",
  "size":"large"
}

 

{
  "width":8,
  "height":5,
  "depth":3,
  "floors":[
    {
      "wall":"",
      "windows":[
        0,
        4,
        5,
        13
      ],
      "features":[
        {
          "x":3,
          "type":"door"
        },
        {
          "x":0,
          "type":"martSign"
        }
      ]
    },
    {
      "wall":"",
      "windows":[
        1,
        3,
        5,
        6,
        7,
        9,
        10,
        11,
        12,
        13
      ],
      "features":[

      ]
    },
    {
      "wall":"",
      "windows":[
        0,
        1,
        3,
        4,
        5,
        7,
        10,
        12,
        13
      ],
      "features":[

      ]
    },
    {
      "wall":"",
      "windows":[
        0,
        1,
        5,
        7,
        8,
        9,
        11,
        13
      ],
      "features":[

      ]
    },
    {
      "wall":"",
      "windows":[
        0,
        1,
        4,
        5,
        8,
        9
      ],
      "features":[

      ]
    }
  ],
  "roof":{
    "type":"flat"
  },
  "type":"mart",
  "size":"huge"
}

Next step is using these models to create the maps of tiles.

OpenArthurianX6 – Plans for the first public release

Almost one year ago, I lay down a general plan for the development of the engine, lots of things happened since the campaign was funded, and there has been progress, but not at the pace I expected.

But now, I have much greater control of my work schedule, and it’s time to get serious. I also spoke with my friend Exodus Destiny Dragon, and he’s up to continue pushing the development

I still believe the original model, based on “capabilities” and “engine aspects”, is the way to go to get to the first release. I will include an additional facet: a plotline, for a game using the engine.

You may wonder, why is this important? and I believe it comes down to… motivation. It is hard to keep a constant influx of motivation when working on an engine, it’s cool to see things come together, but it’s too easy to lose direction if there isn’t something tying everything together.

From that initial plan, we have covered the following:

Capabilities

World

  • Move around the map
  • Pick up an item from the map

Dialogs

  • Talk with a NPC

Inventory

  • Check the inventory of a party member (Some progress)
  • Drop an item on the map

Combat

  • Enter and leave combat mode
  • Attack an enemy within melee distance
  • Attack a far away enemy

Engine Aspects

Maps

  • Day and Night Cycle: Some progress

Mobs

  • Follow player

How does the plotline affect this plan? all the items will be steered towards the construction of the scenario supporting it.

When the game starts the intro is displayed as follows:

  • The Avatar has been summoned back into Britannia, arriving during the night in a forest near Yew.
  • He finds Shamino and talks with him, learning about what has happened on Britannia.
  • They decide to head back into a safe place but are suddenly attacked by a group of soldiers led by Lord Asteroth of Empath Abbey.

The game starts in a forest clearing at night in combat mode (Similar to Ultima VI)

  • The Day/Night skyline indicator is visible, showing night.
  • The party is the Avatar and Shamino, they take turns to attack the enemy.
  • While in combat, the party members can move around
  • The Avatar is armed with a sword so he can do melee attacks
  • Shamino is armed with a bow so he can do ranged attacks
  • The enemy soldiers attack the party members using melee and ranged attacks

After 2 turns, Shamino is shot by a magic bolt by Lord Asteroth and is taken out of combat. Cutscene unfolds:

  • Out of nowhere, Iolo appears along with a band of resistance members
  • He shots Lord Asteroth with his crossbow and forces the soldiers to flee.
  • Then they disband leaving the party alone.
  • Iolo says they must seek refuge on his hut to the west.
  • Party is transported to Iolo’s hut.

Inside Iolo’s hut, the Avatar can:

  • Save the Game, Exit and Restore
  • Examine Iolo
  • Talk to Iolo using keywords
  • Ask Iolo to join the party
  • Open and close its main door
  • Read a book containing Iolo’s notes during the Quest of the Avatar
  • Get a key and use it to open an inside door going into his workshop
  • Go to the second floor
  • Examine a wall finding a secret lever (Revealed by Iolo in conversation)
  • Use the lever to open a hidden door into a room with a mystic sword.
  • Switch main character to Iolo
  • Get Mystic Sword
  • Examine Mystic Sword (in Inventory)
  • Get Magic Axe
  • Get a bag
  • Switch main character to Avatar
  • Check Avatar’s inventory
  • Check Iolo’s inventory
  • Put Mystic Sword into bag
  • Put Magic Axe into bag
  • Take Mystic Sword out of bag
  • Give Mystic Sword to Avatar
  • Make Avatar Use Mystic Sword (Wear)
  • Get yellow and blue potion
  • Drink Yellow potion, recover 5 HP
  • Drink Blue potion, recover 5 MP
  • Get lute
  • Use lute (go into instrument mode, can play using numbers)
  • Exit instrument mode
  • Use torch in the wall (put it off)
  • Use torch again (light it)
  • Get torch

In the area surrounding the hut, the Avatar can

  • Move around, having the party members follow him.
  • Examine the trees around
  • Examine a rock laying around
  • Get the rock
  • Drop the rock
  • Examine crate (Has some corn inside)
  • Move rock into crate
  • Examine crate, pick corn from crate
  • Use corn, be less hungry
  • Read a gravestone
  • Check the status of Shamino
  • Talk with Shamino, ask him to leave the party.
  • Talk with Shamino, ask him to join the party.
  • Get bucket, drop next to cow.
  • Use Cow (bucket gets filled with milk)
  • Attack Cow (Switch to combat mode)
  • Cow flees (peaceful animal AI)
  • Switch off combat mode
  • There are two friendly NPCs around (resistance members). They are hiding at Iolo’s
  • The friendly NPCs sleep at night in the barn, go to the fields during the morning, and have lunch at home at noon.

The party travels south

  • Smooth transition into another map segment (forest)
  • Time goes on into dawn and morning.
  • Party attacked by headlesses group. (Switch into combat mode)
  • Cannot switch out of combat mode.
  • When a headless is killed, he drops a corpse
  • After killing all headless, combat mode is automatically turned off
  • Corpses of headless can be examined as containers, they can have a club or not.

Or the party can be defeated…

  • If the headlesses or the soldiers kill the party, it’s game over

While implementing this flow doesn’t ensure the engine is completed, I believe iterating over it making it progressively better and more flexible every time will push forward the development of the engine.

Now comes the question about the dates. The idea is to produce biweekly builds and the plan is to have a working version of this flow within 20 work weeks, as detailed here.