Package: paignion
PaignionPaignion is a Python-generated, JavaScript-powered game engine for text adventure
games.ContentsQuick startWhat is Paignion?How to write room descriptionsHow to write room metadataTangible and intangible itemsItem propertiesActionsHow to install PaignionQuick startIf you just want to play a game made with Paignion to see what it can do, you can clone
this repo and build the example games locally to test them:$ git clone https://github.com/kokkonisd/paignion
$ cd paignion
$ python3 -m pip install -r requirements.txt # Install dependencies
$ python3 -m paignion build examples/complete_demo # Build demo gameThis will build the complete demo atexamples/complete_demo/build. You can play it by
serving it locally, for example withhttp-server:$ cd examples/complete_demo/build
$ http-server -p 4000You can then open a browser, go tolocalhost:4000and enjoy :)What is Paignion?Paignion is a game engine fortext adventure games.
It takes a bunch of specifically formatted Markdown files written by you, the game
developer, and turns them into a JavaScript-based text adventure game, which you can
easily send to friends or serve on your site. You only need to install Paignion in
order tomakegames; the actual game runs in a browser and does not have any
dependencies you need to install.If you want to see a minimal example of a game built with Paignion to witness with your
own eyes how simple it is to create a game, you can follow theinstallation instructionsto install Paignion on your computer.
Once it is installed, you can run the following command in your terminal to create a
new game:$ paignion init my_new_gameA directory called "my_new_game" will be created, and some default files will be
generated:$ tree my_new_game/
my_new_game
└── rooms
    ├── origin.md
    └── second_room.md

1 directory, 2 filesAs you can see, a directory called "rooms" has been created inside the directory of
your game, and it contains all of the rooms of your game in the form of Markdown
(.md) files.You mustalwayshave anorigin.mdroom; this is the room in which the player
starts when they launch the game.As you can see, every room file is split into two parts: a YAML header and a Markdown
body. This is basically based onJekyll's Front Matter.The YAML header is contained in triple dashes (---); it must always come first, and
the Markdown body must always come after it.The YAML header basically contains metadata for the room (which rooms it connects to,
what items it contains, the properties of these items etc). The Markdown body contains
the description of the room, which is the text shown to the player when they enter the
room.How to write room descriptionsRoom descriptions are written in basic Markdown. You can use pretty much anything you
would use here on GitHub when writing them.Note that the player will not get a list of the items of the room as they enter it;
they will only get what you give them in the description. You can describe the items in
detail to invite them to examine them, or you can do the opposite and let the player
discover them by looking around the room.How to write room metadataRoom metadata is entirely optional. However, if all your rooms are completely empty
then your game isn't going to be much fun.Each entry of room metadata is basically one of two elements:directionsoritems.Directionsrefer to the rooms that this room links to, anditemsrefer
to the items that are found in the room and that the player can interact with.Directions are one ofnorth, east, south, west, up, down; you do not need to specify
each and every one of them, you only need to specify those you need. For example, if I
want my origin room to link to the kitchen on its north, I can write:---north:kitchen---assuming I will create akitchen.mdroom. Usually you'll want to mirror this in the
linked room, by addingsouth: origininkitchen.mdin this case, but you do not
have to; you're making a game, not working on a uni assignment! Screw coherence and
continuity, go nuts!Just to make it clear how this works, if we were to implement the twoorigin.mdandkitchen.mdroom, the player could move from the origin to the kitchen by typing
"go north" or "go to the north" or "move to the north" etc.Tangible and intangible itemsItems are split into two categories:tangibleandintangible. Tangible items are
the ones that the player can pick up and store in their inventory, like a key or a gun.
Intangible items on the other hand cannot be picked up by the player, and can instead
be examined by them, like a painting or a fireplace. Both types of items can be used
together, viaactions. Here's how you would declare that in the room files:---items:tangible:# Tangible items go hereintangible:# Intangible items go here---As with the directions, you don't need to define either of those categories if you
don't plan on using them; for example, if you don't want intangible/tangible items you
don't need to specify an empty list, and if you don't want neither the one nor the
other you can skip the items key in the YAML entirely.Item propertiesEach item, tangible or intangible, can define a few properties. For example, every item
should have at least a name and a description. Item descriptions can also contain
Markdown (just like the room descriptions).The rest of the item properties are optional, which means you only need to define them
if you want to override the defaults. The optional properties are the following:amount: the amount of instances of this item found in this room. For example, you
can have three gold coins, and let the player pick as many as they want. This is set
to 1 by default (since if you don't specify how many of it there are then you
probably mean there is just one) but can be set to any number, or "inf", which means
that there is an infinite amount of this item. This can be used for things like
grains of sand on a beach or something, I don't know.visible: is this item visible by the player or not? Basically this determines if
the item will be filtered out or not if the player asks to "look around the room".
This can be useful for things that are obviously there: for example you might want
the player to be able to, say, combine a shovel and the ground in order to dig a
hole by saying "use shovel with ground", but at the same time if they ask to look
around the room it's dumb to respond "you can see one shovel and oneground", hence
the utility of thevisibleflag.effect: the effect that is currently applied to an object. For example, if you
enchant a sword it becomessword (enchanted). If you put a cat under a running sink
it becomescat (wet). This usually starts out undefined and gets changed by an
action, either for comedic/worldbuilding purposes or for an actual action that
changes something in the game.Here are some concrete examples of items:---items:tangible:-name:rockdescription:"Arockyoucanpickupandprobablythrowatsomething."-name:bootdescription:"Anoldboot.Kindastinks."amount:2# It's a pair of boots!-name:sanddescription:"Sand.Youknowwhatsandis.Whatyouwoulddowiththis,Idonotknow.Havefunendlesslypickingupgrainsofsand."amount:"inf"effect:boringintangible- name:skyvisible:false# it would be dumb to say "there is 1 sky" to the player# also note how if it's invisible you do not need to define a# description since the player cannot say "look at the sky"# (they will get a "there is no such item" answer)-name:boatdescription:"Anold,rottingwoodenboat.Seemsitwashedupontheshorealongtimeago."---ActionsThere is another (pretty important) item property:actions. You would have a pretty
boring game if the player could not change the game world via their actions, wouldn't
you?Each time you want an item to be able to be used with another item, you must specify
theused_withproperty (and the properties that come along with it). Under this, you
must at least specify what the name of the item that this item interacts with is, and
also an effect message that is shown to the player when the action is carried out. The
last one is mandatory because not giving your players feedback isbad.The syntax of the commands is very minimal, and there are actually very few commands
for now:setandaddwhich, well, set a certain property to a certain value or
add (meaningappend) something to the current value of a specific property. Let me
explain with an example.Say we're making a very simple 2-room game. The player starts out in the origin of
course, which only contains one key (tangible) and one door (intangible) on its west
side. The goal for the player is pretty simple: pick up the key, open the door, and get
to the second room. This is how you'd implement this with actions:---# we do not define anything for the `west` direction; it will get populated# automatically by the actionitems:tangible:-name:keydescription:"Asimplekey.I'mprettysureitopensthatdooroverthere.Wannapickitup?"intangible:-name:doordescription:"Aclassicwoodendoor.It'slocked."used_with:-name:keyeffect_message:"Thedoorisnowunlocked."consumes_subject:trueactions:-set(west, "second_room", origin)-add("The door has been unlocked", description, origin)---There is a locked door to your west and a key at your feet. You know what to do.Of course, I am assuming that there is asecond_room.mdwhoseeastdirection points
toorigin. In order to advance to the second room, the player must type something
like "take the key" in order to pick up the key and then something like "use key on
door" in order to unlock the door. At that point, the action we just wrote for the door
will be applied: it will delete the key from the player's inventory (this is done
because ofconsumes_subject, more on that later), it will set thewestdirection of
the origin room tosecond_room, linking the two, and finally it will append a
paragraph saying "The door has been unlocked." to the origin's description, so that if
the player comes back later and don't remember that they already unlocked the door, the
description will remind them. Of course, in this case I'm using theaddcommand to
show how it's supposed to be used, but in this case it would be better to just change
the entire description to that paragraph. You decide.In any case, here are the available commands:set(X, Y, Z)add(Y, X, Z)sub(Y, X, Z)mul(Y, X, Z)div(Y, X, Z)Xis a property/key: something likewest, oreffect, orvisible, oramount...Zis either a room name or an item name (tangible or intangible). The engine will
look for a room first, then for an item from the player's inventory, and lastly for an
intangible item, first from the current room and then from the other rooms. Keep this
order in mind when designing; only the first item in that order will be acted upon.
As for why the engine only looks for intangible items outside the player's inventory:
if the action is meant for a tangible item, the user can pick it up and use it. There
is no need to do this without having the user pick the item up first.Finally,Yis a string containing a message or a value for the keyX. This can be
one of three things:astring, like"blablabla"aMarkdown string, likem"The _trenches_ were ~~very~~ extremely **deep**.",
which will obviously get rendered on the screen like other strings that support
Markdown in the engineaninteger, like4Thesetandaddcommands can be used either to set/append strings, or to set/add
integers. Thesub,mulanddivcommands only serve to subtract, multiply and
divide by an integer value respectively.To conclude, here is the rest of the available properties for the actions:consumes_subject: decreases the amount of the subject (meaning the itemperformingthe action) by 1, or deletes it if it was at 1.consumes_object: same thing, but for the object (meaning the itemreceivingthe
action).How to install PaignionYou can install Paignion viapip:$ pip3 install paignionYou can then directly use it from your terminal. If you don't want to install it, you
can clone this repo and use it from within the repo itself:$ git clone https://github.com/kokkonisd/paignion
$ cd paignion
$ python3 -m pip install -r requirements.txt # Install dependenciesYou can then launch it from inside the clone of the repo by running:$ python3 -m paignion init my_new_game # or build ...Developer notesTests can (and should be) run like this (after having installed the dependencies listed
inrequirements.txt):$ toxTODOs:Add conditional commands??? maybe???Add part explaining the frontend engine in README