Giter Site home page Giter Site logo

wasa's Introduction

Wasa

Wasa is a concept for a fully online board-game platform. Wasa explores how modern web technologies can enable advanced board games, such as classical chit-based war games, to be enjoyed on touch devices as well as on large-screen PCs.

Disclaimer! Wasa is not a fully working board game solution. It is a project made to explore how real time web-based touch-interface gaming could work. It is a work in process.

Demo

Latest build should be deployed to https://wasa.bitknife.se/

Run

Docker-Compose

Wasa is packaged as a Docker image based on nginx, and can be built and run using docker-compose since it uses Webdis (which uses Redis), as simple as this:

First build the Wasa image

$ cd run
$ docker-compose build

And run the whole stack like this:

$ docker-compose up

Two things happens here:

  1. The webdis server is started and exposed on port 7373

  2. An Nginx server is exposing the webapp on port 8080

Like so:

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
53e69d3c00aa        wasa_wasa-webapp    "/docker-entrypoint.…"   8 minutes ago       Up 8 minutes        0.0.0.0:8080->80/tcp     wasa-webapp
4f1720ba96db        nicolas/webdis      "/bin/sh -c '/usr/bi…"   8 minutes ago       Up 8 minutes        0.0.0.0:7379->7379/tcp   wasa-webdis

So, to acces the embedded instance of the application, surf to:

To verify everything, I suggest you open up the Wasa application and start a new game and load up a scenario. If the webdis backend is working correctly, you should be able to se the events propagating to a second browser!

imply copy the link from the first browser and open up a second. This is how your opponent would connect to your game.

Developer

If you are a developer, I would instead suggest open up ./webapp/index.html from the git-repository using your development environment (like pycharm etc.) and serve it from there.

It still connects to the webdis instance on port 7373 running inside the wasa-webdis docker instance you started above.

But from the dev-env you can make instant changes to the code (reload page) and test. Surfing to localhost:8080 will only load the application version that was built into the docker image.

Production / Internet

See the comment in docker-compose.yaml on the approach to use. Not safe, but it could work for a short test session etc.

Design / Goals

Primary goals

  • Online multiplayer games.

  • Share game by sharing a single link.

  • No files to share or no emails to send during the game.

  • Live experience if wanted (preferrably using voice or video conference as support function).

  • Full history of all game events.

  • Fast, browser based solution.

  • No client installation.

  • Generic. Focus on component movement and interactions, less on specific game rules.

Secondary goals

  • Designed with touch devices (smartphones, ipads) in mind.

France 40 GMT Games France 40, by Mark Simonitch, based on the Vassal Module.

Limitations

Wasa aims to implement games with the following characteristics at this time:

  • Complex wargames (ie. tries to handle stacks of components, component flipping, rotation etc).

  • No hidden informations right now (ie no decks of cards, no bags with chits, no hidden tokens, no block games)

Features

All features are implemented with touch support first in mind (must work great on both PCs and iPads etc.).

Features working

Below is just a take-out of what works:

  • State synchronization between multiple browsers.

  • Multiple game sessions active (even for a single game).

  • In-game chat.

  • Current game history loaded when first entering game.

  • Two-sided counters (flip by long click).

  • Component trays, grouped.

  • Draggable markers.

  • Counter move animations.

  • Rotatable markers (if enabled and useful).

  • Markers move to top when moved (ie. for stacking).

  • Stack selection (select all overlapping).

  • Highlighting of components.

  • Peek into stacks.

  • Game components can be marked using a colored border.

  • Draggable panels (Tray, game board etc.)

Features currently in development

  • Stack movement.

Ideas

  • Undo or back/forward in history.

  • Turn concept (ie. lock board of others while acting in your turn).

  • Offline mode (stack events locally until connection is made).

Tecknical

Overview

TODO: Add figure showing how stuff fits together.

Application fundamentals:

  1. webapp/index.html is the entrance, a static html page not loading an javascript. Just information and links etc.

  2. application/index.html is the actual application. This loads the javascript into the browser.

  3. from the document.ready() function nunjucks.js is configured and then createWasaBoardGame() is executed.

  4. createWasaBoardGame sets up the back-end client and check for email, session ids and stuff.

  5. after a while, the GUI is created through initWasaFront()

Front-end

A good thing to always take in mind is that Wasa, just as Vassal, works with game component as pictures and pixels and not as scalable objects. All objects are placed by absolute position. This means, that whenever a module is implemented, all components and movements are done by chaing the absolute X/Y coordinate. So, the game map can not be replaced, or re-scaled without resetting all games (or possible converting existing games to the new scale, not implemented yet).

  • HTML5

  • "Standard" Bootstrap / Jquery(UI) solution

  • Websocket event notification for instant and no page refresh experience.

Back-end

Backend is currently based on Webdis (which is based on Redis).

But should ideally instead be on authorized REST API calls in the future.

HOWTO

Convert Vassal Moule to Wasa Moule

Converting a (modern) Vassal module to a Wasa module is fairly straight forward. It can be done by a person not skilled in programming, but will probably go a lot faster if you are able to edit some simple scripts that will better match the Vassal module in question.

Follow the example below, where I convert the Holland ´44 game to a Wasa module, step by step to get the picture.

This game contain no cards, and that step is not yet explained since cards are not fully implemented yet.

Preparing the source files

  1. Download the Vassal module somwhere around here.

  2. Use your normal un-ZIP program of choice (The ".vmod"-file is actually just a zip-file), to un-zip the file at a temporary place.

  3. Open up the folder containing the un-Zipped Vassal module.

  4. Inside it you will find a sub-folder named 'images'. Open it.

  5. This directory should contain a hand-full of large files (the game map and player aids), and probably a lot more smaller files - the chits/counters and/or the cards of the game. Keep the window open until later.

Creating the new game module

Creating a new game module takes 20-30 min for the basics. But touch up the components and setting up scenarios varies a lot from game to game.

Best method is to just copy the most similar module found. Most modules are actually very similar in structure. But two good modules to use as a starting-point would be Red Winter or France 40. Lets go for France 40 since it is a game of the same series.

  1. From the wasa sources (clone using git, or just download them as a ZIP-file.

  2. If ZIP-download, unpack the sources and go to wasa/applicatin/game_modules/ and copy the france_40 folder and rename the copy to holland_44. This name also doubles as the game module ID used URLs later on.

  3. Now, we need to clean out the France 40 components. Remove everything inside "components".

  4. Copy the entire 'images' folder of the Hollad 44 vassal module to the "components" directory you just cleaned. After copying it, rename the directory 'images' to 'vassal'.

  5. Back in the 'holland_44' folder, open up the file config.js and edit the fields under "game_data" (leave everythin above unchanged for now):

It should look something like below:

var game_data = {
    //
    // Game id and directory name under "game_modules"
    'game_id': 'holland_44',
    //
    // Whatever you like
    'version': '0.1a',
    //
    // Textual tile, used to present the game
    'title': 'Holland 44',
    //
    // A sub tile is common, fill it in if applicable
    'subtitle': 'Operation Market-Garden',
    //
    // Path ot the box front. Used for presenting the game
    'box_front_img': 'components/vassal/Holland44 Cover Scaled.png',
    //
    // Leave this as default
    'component_path_prefix': 'components/vassal/',
    //
    // A custom CSS class that will be applied to all counters of this game
    //
    // This class is defined in the file style.css (more about that below)
    'component_classes': 'holland44_counter_small',
    //
    // This structure defines the "tabs" of the game. There are three classes of tabs:
    // 1) Game maps, on which game components can be dropped
    //   Note that map boards do not define their game image at this point.
    //   (it is done in the style.css file)
    'game_board_tabs': [
        {
            'title': 'Main map',
            'id': 'main_map',
            'classes': ''
        }
    ],
    // 2) Non game-maps, like tables and Player Aids
    //   At this point look inside the "components/vassal" directory and look for the few big files:
    //   Note, that you need to set the correct width in pixles for each image.
    //   If you want, you could add more tabs (images) by adding new blocks similar to the one below.
    'extra_tabs': [
        {
            'title': 'Player Aid',
            'id': 'tab2',
            'image_src': 'components/vassal/HO44-PAC-FINAL-HiRes-1 100.jpg',
            'image_style': 'width: 1100px; height: auto;'
        },
        {
            'title': 'Terrain effects',
            'id': 'tab3',
            'image_src': 'components/vassal/HO44-PAC-FINAL-HiRes-2 100.jpg',
            'image_style': 'width: 1100px; height: auto;'
        },
    ],
    // 3) Rules. This tab does not display the rules, but simply a link to the rules.
    //    you can often find a link to the game rules using Google.
    'rules_tab': {
        'id': 'rules_tab',
        'link_src': 'https://s3-us-west-2.amazonaws.com/gmtwebsiteassets/Holland44/HO44-LIVINGRULES-May2018.pdf',
        'link_title': 'Official rules by GMT'
    },
    // You will add the scenarios at a later point. You could keep the "scenarios" field empty for now.
    'scenarios': [
    ]
};

Style.js

This file contains the play board definitions as well as some custom CSS for this particular game.

The IDs of the game boards above (in config.js) must each appear here. So we need include main_map as well as normandy44_counter_small and add the correct sizes for the big map and the small counters.

You could customize the component class as well to give each component some more space in the component tray for example.

#main_title {
}
.theme_color {
    color: #b2392e;
}
.custom_game_table {
    padding: 150px;
    padding-bottom: 500px;
}
#tab_side {
    /* Most of the times, keep it to relative (large maps). Some small maps could use fixed though */
    position: relative;
}
#main_map {
    background-image: url('components/vassal/HOLLAND44_Map-nf.jpg');
    height: 6528px;
    width: 3300px;
}
.component {
    float: left;
    cursor: pointer;
    border-radius: 6px;
}
.holland44_counter_small {
    /* Custom for this game */
    background-repeat: no-repeat;
    width: 85px;
    height: 85px;
}

Creating the components.js file

The components.js file defines what usable and placeable components are available in each game.

This file can be created by hand, but can much faster be partly generated by a small python-script and then instead tidied up by hand, whatever details the script could not automatically set up.

Most game module contains a script called "generate_wasa_components_js.py". Have a look at them. The script is quite simple as it just scans through the images-directory (under "components/vassal"). It filters out the large files and possibly also very small files, or files not matching a certain naming-scheme etc.

The goal is to create a file called components.js. In its simplest form it looks like the one below:

var component_list = [
    '12VA.ex.png',
    '12VA.png',
    '13PA.ex.png',
    '13PA.png',
    '17VA.ex.png',
    '17VA.png',
    '1CT.ex.png',
    ];

However, Wasa supports a slightly more rich structure. And the generation-script of later modules (like France 40) instead generates a file that looks like this (shortened to save some space), which is much more useful, but also a bit tougher to generate. The Normandy 44-game contains over 600 different sides (300+ front and back) to pair up.

The big deal is that the script can detect the front- and back-sides of the components and create the pairs of images as seen below. But note, that some components may not be correctly detected in full, and so to make the Wasa module be correct. Some manual labour is often needed.

The script could very well be re-written in a more general and more useful manner. I did not spend much time on this part.

Also note, that the components are roughly categorized, where the first item of each list (the [] brackets) containing the header of each category:

var component_list = [
    [
        "Belgic",
        ["be-16div", {"b": "BE-16Div-Bk.png", "f": "BE-16Div.png"}],
        ["be-17div", {"b": "BE-17Div-Bk.png", "f": "BE-17Div.png"}],
        ["be-18div", {"b": "BE-18Div-Bk.png", "f": "BE-18Div.png"}],
        ["be-1cav", {"b": "BE-1Cav-Bk.png", "f": "BE-1Cav.png"}],
    ],
    [
        "British",
        ["br-12div", {"b": "BR-12Div-Bk.png", "f": "BR-12Div.png"}],
        ["br-12l-recon", {"f": "BR-12L-recon.png"}],
        ["br-1div", {"b": "BR-1DIV-Bk.png", "f": "BR-1Div.png"}],
    ],
    [
        "French",
        ["fr-101-84", {"b": "FR-101-84-Bk.png", "f": "FR-101-84.png"}],
        ["fr-101-87", {"b": "FR-101-87-Bk.png", "f": "FR-101-87.png"}],
        ["fr-102-148", {"b": "FR-102-148-Bk.png", "f": "FR-102-148.png"}],
        ["fr-102-42", {"b": "FR-102-42-Bk.png", "f": "FR-102-42.png"}],
        ["fr-tkbn-6", {"f": "FR-TkBn-6.png"}],
        ["fr-tkbn-7", {"f": "FR-TkBn-7.png"}],
        ["fr-tkbn-9", {"f": "FR-TkBn-9.png"}],
    ],
    [
        "Germans",
        ["ge-1", {"b": "GE-1-Bk.png", "f": "GE-1.png"}],
        ["ge-10", {"b": "GE-10-Bk.png", "f": "GE-10.png"}],
        ["ge-11", {"b": "GE-11-Bk.png", "f": "GE-11.png"}],
        ["ge-11sch", {"b": "GE-11Sch-B.png", "f": "GE-11Sch-F.png"}],
        ["ge-ssrem", {"b": "GE-SSREM-B.png"}],
        ["ge-ssrem-a", {"f": "GE-SSREM-A.png"}],
        ["ge-sstot", {"b": "GE-SSTot-B.png", "f": "GE-SSTot.png"}],
        ["ge-ssverf", {"b": "GE-SSVerf-B.png", "f": "GE-SSVerf.png"}],
    ],
    [
        "Misc",
        ["m-autods", {"f": "m-AutoDS.png"}],
        ["m-control-allied", {"f": "m-CONTROL-Allied.png"}],
        ["m-train", {"f": "m-Train.png"}],
        ["m-turn", {"f": "m-Turn-GE.png", "b": "m-Turn-Allied.png"}],
    ]
];

So to get started with the often small modifications needed, it is allways a good idea too look at the images directory and find out if the front- and back-sides seem to follow a common pattern. The images for the back-side of the counters are often named with a suffice like '-b' or '-back' for example. In Holland 44, the module uses '-f' for the front and '-b' for the backs.

I only modified a part of the script in the middle of the iteration over the directories:

back_suffixes = ['-r.png']
front_suffixes = ['-f.png', '.png']
c_key = get_c_key(file_name, back_suffixes)
if c_key:
    component = component_map.get(c_key, {})
    component['b'] = file_name
else:
    c_key = get_c_key(file_name, front_suffixes)
    component = component_map.get(c_key, {})
    component['f'] = file_name

And then run the script once to generate the first components.js. I then manually added a default header such as "All" to make it follow the grouped structure seen above.

Now, the manual labour takes place. But wait with this until the module loads correctly, since it is very useful to load and see all components and the errors.

Registering the new game module

Before the new game module shows up in the game directory, it needs to be registered in a separate file.

Open up wasa/application/game_modules/registered_modules.js

I now add a the new entry below somewhere close to France 40:

{
    'game_id': 'holland_44',
    'title': 'Holland \'44',
    'subtitle': 'Operation Market-Garden',
    'box_front': './game_modules/holland_44/components/vassal/Holland44 Cover Scaled.png',
    'comment': 'Partially working.'
},

I should be able to use the new module by surfing to the lobby, seeing the game box appear:

Holland 44

Testing and debugging.

At this point, chances are a few things are not fully correctly set-up. If the module does not load correctly. Make sure to keep an eye on the browser console for any errors. Common errors I have encounted are:

  • Miss-spelled paths.

  • Failed to update some fields when I copy and pasted another module.

  • Wrong format of the components.js, a missing comma for example.

Correcting generated components

Now, after the module loads correctly, you will need to look through the component tray and update the generated file with better pairs of fronts and backs. You could at this point alsow categorize the components into suitable groups, such as by faction or component types etc.

Setting up scenarios / starting positions

After the components was improved and verified. It is time for the last and most fun part before the module is ready.

This step is fairly straight forward.

  1. Reset the game by clicking on the "Session" tap of the Player Panel.

  2. Then follow the scenario set-up instructions of the game to place all components.

  3. Verify the set-up. For complex games, it is easy to make misstakes.

  4. After all components are correctly placed, go to the chat-window and type

    /dump

You will be presented with a window containing all data needed for the set-up. Something like this:

/* Events from game_id = holland_44 */
[
  {
    "event_type": "dice_roll",
    "username": "herr.eklund",
    "time": 1539725790,
    "payload": {
      "dice_rolled": "1D6",
      "result": 1
    }
  },
  {
    "event_type": "create_component",
    "username": "herr.eklund",
    "time": 1539726241,
    "payload": {
      "tray_component_id": "us-101-502-1-para-inf-bttn",
      "component_id": "blc5d2cq",
      "game_board_id": "main_map",
      "left": 458.6666564941406,
      "top": 890.0208129882812,
      "flipped": true
    }
  },

Copy and paste the contents into a new file under normandy_44/scenarios. Prepend the list of events with

var scenario_setup =

wasa's People

Watchers

Hans Eklund avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.