Posted by admin on June 17, 2020
A while ago I was asked about an example of how the Worldforge rules work. The focus was especially on how a series of simple rules allows for more complex game mechanics. Since I wrote down an example of how consumption works I thought I might as well post it here, since it provides a good example of how we think about game rules.
One example could be the "bread" entity type.
Breads can be eaten, so the bread class includes a "usage" of "consume".
<string name="constraint">actor can_reach tool</string>
There's a simple constraint on the usage that the actor which performs it must be able to reach the bread. The script for the "consume" action is then handled by "world.objects.Consumable.consume", found here.
The script will check if there's a conversion property set ("_consume_mass_conversion") as well as a property specifying the kind of consumption ("consumable_type"). For the bread the consumption type is "plant". The result is that the bread is destroyed, and a "Nourish" message is sent to the actor (the one which consumed the bread). The Nourish message (or "operation" as we call them) will contain information both of the consumption type (plant) as well as how much nourishment it contains (depending on the size of the entity being consumed as well as any conversion property.
The Nourish op then needs to be handled by the entity that ate the bread. Consider if a human ate the bread. The "human" class will inherit from the "creature" class, which is defined here.
The "__scripts" property contains scripts that define the behaviour and can install "operation handlers". One of the scripts of "creature" is "world.traits.Nourishable.Nourishable", which is defined here.
This script will perform a couple of checks and apply modifications, and then increase the "nutrients" property of the entity. The "nutrients" property specifies how much nutrients an entity contains. For a creature it would be how much food it has eaten. Another script, "world.traits.Metabolizing.Metabolizing" then acts on this, and allows the entity to grow or heal if there's enough nutrients.
By default all "creatures" are omnivores, i.e. they will convert both "plant" and "meat" nourishment to nutrients. But take the wolf for example, as found here.
It has this property, which makes it not receive any nutrients from "plant" nourishments, thus making it a carnivore:
Conversely a "cow", as found here, is an herbivore as specified by
But even plants can be nourished. So plants, also use the same world.traits.Nourishable.Nourishable script. However, they obtain nourishment by consuming from the entity into which they are planted (if the are planted). Therefore they use a script at world.traits.PlantFeeding.PlantFeeding which will at a regular interval send a "Consume" operation to their parent entity, for the "soil" type of consumption.
A typical entity which then would be able to nourish a plant would be the "land". Other entities would just ignore the Consume op sent from the plant. The "land" contains the "world.traits.PlantNourishing.PlantNourishing" trait/script which allows it to send back Nourish operation to any plant.
So in this way a couple of shared scripts can be reused in many different entities, for nourishment both for entities that eat things (creatures) as well as those that suck nourishment from the ground.
It doesn't stop there though. The "fire" entity, uses the Fire.py script to at regular interval consume other entities by sending Consume operation of the "fire" type.
This kind of Consume operation will be ignored by entities, unless they implement the "Flammable.py" trait. So a rock wouldn't be consumed by fire, whereas a log would be, as the latter has the Flammable trait. The speed of fire consumption is further governed by any "_burn_speed" property.
And so on. All game play if defined by having these smaller scripts which interact with properties and send messages/operations to other entities.
Posted by admin on June 14, 2020
<string name="default">describe("Entity is planted and can't be moved.", not (entity.mode = "planted" and entity.rooted = 1))</string>
<string name="default">entity.mass = none or describe('Entity is too heavy.', entity.mass = none or entity.mass < actor._mover_mass_max)</string>
<string name="default">describe("Creature can't be moved.", false)</string>
Posted by admin on December 30, 2019
We've extended our infrastructure for building installable packages and now provide a wider variety.
On TravisCI we have a setup where we build packages for both Linux and OSX, using both GCC and Clang. While we do build for OSX we don't yet provide any installable packages. The result is a both an AppImage and a Snap package of the Ember client.
On AppVeyor we have a setup where we build Ember for Windows using MSVC. This results in an installable package.
On Snapcraft we have a setup where we build the Cyphesis server.
The end result of this is that we now automatically build our code for Linux, Windows and OSX, on both x86, amd64 and aarch64. And we use GCC, Clang and MSVC as compilers. This makes sure that we catch most code incompatibilities rather quick.
In order to make this happened we've embraced the Conan package manager. All packages that we depend on are provided as Conan packages. The process of building Ember is now as simple as just doing "conan install". The sources contain more information on how to use it.
The new binary packages can be downloaded from
Posted by admin on September 23, 2019
Recently I've performed a major refactoring of how entity interaction happens in the Worldforge system. The basis of it is the new "usages" property which declares the actions that are available for each entity. As an example of how this can be used I've implemented a simple "fishing" task. When fishing you need a "fishing rod", and you need worms (or "annelids" as they are called in the system). You get these by digging in the ground with a shovel and then sifting through the resulting piles of earth with a sieve.
The "fishing rod" type is defined here. It has a "Fish" usage, which has a constraint of "get_entity(actor.attached_hand_primary) = tool and contains(actor.contains, child instance_of types.annelid)". The constraint checks that the rod when activated is wielded by the user, and that there's at least one worm in the user's inventory.
It declares on parameter, a "target" which is of type "entity_location" (i.e. a position on another entity) with a constraint of "entity instance_of types.ocean && actor can_reach entity_location with tool". The target constraints requires that the target is of type "ocean" and that the user can reach the position with the fishing pole (the fishing rod has a reach of 5 meters, as defined in the "reach" property).
By declaring these rules using constraints we can remove a lot of boilerplate code from the actual rule, since the simulation engine will take care of checking these constraints before the rule code is invoked. It's also now possible for clients to check the constraints themselves (and disable the usage if the constraints doesn't match).
The usage defers the rule handling to the handler "world.objects.tools.FishingRod.fish". This is a reference to a Python script, to be found here.
The usage handler will immediately create a Fishing task instance, with a "tick interval" of two seconds. The task inherits from StoppableTask, which just means that it will by default have a "stop" usage attached to it. It will otherwise run indefinitely.
Every two seconds the “tick” method is called. It will do a random check to see if there’s a fish on the line. If so, an Imaginary op about this is sent to the client.
If the client stops the task while there’s a fish on the hook a new Fish entity will be spawned, and the worm entity will be consumed.
The gameplay is fairly simple, but it serves as a good example of having the Entity Filter, the Usages and the Task systems all working together to provide gameplay. Since all of the rules are handled by either Python scripts or Type properties the feature can be altered and iterated on in real time without having to restart the server.
Posted by admin on May 21, 2018
I've done some work in Cyphesis to allow for much more powerful features for live editing of the world, mainly editing rules and scripts.