<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>openage dev updates</title><link href="https://blog.openage.dev/" rel="alternate"></link><link href="https://blog.openage.dev/feeds/all.atom.xml" rel="self"></link><id>https://blog.openage.dev/</id><updated>2025-07-14T00:00:00+02:00</updated><entry><title>Openage Development News: June 2025 (and before)</title><link href="https://blog.openage.dev/openage-development-news-june-2025-and-before.html" rel="alternate"></link><published>2025-07-14T00:00:00+02:00</published><updated>2025-07-14T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2025-07-14:/openage-development-news-june-2025-and-before.html</id><summary type="html">&lt;p&gt;Devlog for everything until June 2025&lt;/p&gt;</summary><content type="html">&lt;p&gt;Hello everyone and welcome to the newest update on openage development. This time we are going
to take a look at all the things that happened since &lt;a href="https://blog.openage.dev/openage-development-news-august-2024.html"&gt;August&lt;/a&gt;
and also other stuff that might be interesting. So without further ado, let's bring you up to date!&lt;/p&gt;
&lt;h2&gt;Game entity interaction&lt;/h2&gt;
&lt;p&gt;We'll start with the features that enable &lt;em&gt;interaction&lt;/em&gt; between game entities, i.e. attacking, converting
and all other things that game entities can do to each other. I'm happy to say that this milestone
has now been completed (yay!) and also works pretty nicely with everything else we've implemented so far.
Check out this recording to see how it looks:&lt;/p&gt;
&lt;video width="800" height="600" controls&gt;
  &lt;source src="./images/news/2025-06/interaction_game_entities.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;p&gt;To recap the initial problem description for game entity interaction: The challenge in letting game
entities interact is not the triggering of a single action, e.g. an attack. That's actually the easy
part. Instead, the major challenge arises from modelling the complex gameplay patterns in RTS that combine
multiple actions. What do we mean by that? Well, take these types of gameplay as examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;looping actions&lt;/strong&gt;, e.g. attacking until a target is dead&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;chained actions&lt;/strong&gt;, e.g. moving closer to another unit before attacking&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;combinations of the above&lt;/strong&gt;, e.g. chasing a moving target&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can probably find more examples if you think about your last gaming session. RTS and especially AoE2
are full of those patterns.&lt;/p&gt;
&lt;h3&gt;Agent Behavior in the openage Activity System&lt;/h3&gt;
&lt;p&gt;Another way to think about how these gameplay patterns work is to see game entities as &lt;em&gt;agents&lt;/em&gt; for the
player. Unlike in a first-person game, where a player's inputs directly control the character, agent
control is usually more indirect. Agents may be given commands that then trigger specific behavior and
might set up a complex chain of events. They also may act completely on their own, e.g. units using the
aggressive/defensive/passive stances system in AoE2.&lt;/p&gt;
&lt;p&gt;openage implements this agent behavior in a place called the activity system, which we already talked about
&lt;a href="https://blog.openage.dev/openage-development-news-november-2023.html"&gt;before&lt;/a&gt;. The idea is that game entity behavior is modeled via a
node graph that acts like a state machine for the individual game entity. Traversing the graph happens
when the game entity receives events, e.g. a player command. Visiting nodes then executes actions or
checks conditions to branch on different paths in the graph. You could also say that the activity graph
represents the decisions a game entity can make.&lt;/p&gt;
&lt;p&gt;Most of the work for game entity interaction went into making the activity system fit for interactive
agent behavior. For example, we implemented new decision node types to evaluate the state of the game
entities that interact, e.g. for checking if one game entity is in range of the other's attack radius.
We also had to design an activity graph that matches the unit behavior in games like AoE2, so that gameplay
feels the same. You can see the resulting graph below:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Activity Graph for units" src="https://blog.openage.dev/images/news/2025-06/units_activity_graph.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Follow the graph from the &lt;code&gt;Start&lt;/code&gt; node on the left. The behavior for attacking is located in the&lt;/em&gt;
&lt;em&gt;top right portion of the graph. You can see the basic loop for checking whether the target is in range&lt;/em&gt;
&lt;em&gt;as well as the application of an effect (like attacking) via the &lt;code&gt;ApplyEffect&lt;/code&gt; node.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Additionally, we wanted to make the whole node graph configurable, ensuring that game entity behavior is
changeable instead of relying on hardcoded behavior. This actually worked pretty nicely. We managed to expose
all node types, decision functions, and actions via the game data files, so almost everything can be
configured without changing the code. Currently, there are no failsafes for checking if a graph is "correct"
(i.e. it doesn't crash the whole engine), but that will hopefully be added in the near future.&lt;/p&gt;
&lt;h3&gt;Targeting game entities (with your mouse)&lt;/h3&gt;
&lt;p&gt;So far we've only mentioned how agent behavior may be triggered by commands and conveniently left out
how these commands end up in the game. We want to specifically look at the implementation of
&lt;em&gt;targeting&lt;/em&gt; game entities, i.e. finding out which game entity a player "right-clicked" on.&lt;/p&gt;
&lt;p&gt;Player inputs like right-clicking are routed through openage's input system. A minor "problem" for
interaction is that this input system knows almost nothing about what's going on in the simulation.
This design allows us to run the input system in a separate thread, making the handling of inputs
faster and easier, so we ideally don't want to change it. However, it raises the question: How do we
get to know what game entity a player right-clicked on? After all, we should be able to give the
selected game entities a hint on what they should interact with.&lt;/p&gt;
&lt;p&gt;openage's current solution is a bit janky, but it currently gets the job done. For this, we consult
the openage renderer - another engine subsystem. The idea is that the renderer creates an additional
texture, a so-called &lt;em&gt;ID&lt;/em&gt; texture, that writes the value of the game entity ID to the pixel location
of sprites belonging to said game entity. Essentially, this texture lets us look up which game entity
is occupying each pixel on the screen.&lt;/p&gt;
&lt;p&gt;The ID texture is directly passed to the input system which then uses the (x, y) coordinates of the
click event to look up the game entity ID at that position. Unlike the color textures created by the
renderer, the ID texture is never shown on screen. Here is what it would look like if it would be drawn:&lt;/p&gt;
&lt;p&gt;&lt;img alt="ID texture colored" src="https://blog.openage.dev/images/news/2025-06/id_texture.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Black pixels match no game entity. Colored pixels represent locations of game entities.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Side Tangents&lt;/h2&gt;
&lt;p&gt;Aside from game entity interactions, there were a bunch of features that were implemented on the side.
These features are probably only "cool" if you are a giant nerd (like &lt;a href="https://github.com/heinezen"&gt;@heinezen&lt;/a&gt;),
but he writes these posts and decides what gets discussed, so...&lt;/p&gt;
&lt;h3&gt;Curve Compression&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/SFTtech/openage/blob/master/doc/code/curves.md"&gt;Curves&lt;/a&gt; are openage's internal data
structure for storing value changes &lt;em&gt;over time&lt;/em&gt; in the game simulation.
In other words, they store past, present, and predicted values of game entity data used during the game,
e.g. HP or unit position, as time-value keyframes. Values for the time between keyframes can also be
interpolated.&lt;/p&gt;
&lt;p&gt;In most situations in the simulation, keyframes are inserted lazily, which means that the simulation
doesn't check whether the keyframe is redundant or not. This is usually fine and also desired, since
this makes operating on curves much faster.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Curve without compression" src="https://blog.openage.dev/images/news/2025-06/continuous_curve_uncompressed.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Curve without compression. Keyframes B, D, E, H, and K are redundant and don't change the&lt;/em&gt;
&lt;em&gt;interpolated values.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;However, there are cases where we don't want duplicate keyframes. An example of this is the usage
of curves for storing the animations of objects in the renderer. To which frame index to use for
the current animation, the renderer checks the animation's keyframe time to determine when the
animation started. The frame index is then roughly calculated using this formula:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;frame_idx = (current_time - keyframe_time) / time_per_frame
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Problems can occur when the animation is triggered by a looping action, e.g. attacking a game entity
until it's dead. Currently, the animation is requested for every "iteration" of this loop, i.e.
every time the action is done, a new animation keyframe is inserted. However, if the loop time
for the action does not match the loop time of the animation, then the animation gets abruptly
cut off whenever a new keyframe is inserted.&lt;/p&gt;
&lt;p&gt;Curve compression solves this nicely by only adding keyframes is they don't change the interpolated
value. This is what the curve looks like when compressed:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Curve with compression" src="https://blog.openage.dev/images/news/2025-06/continuous_curve_compressed.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Curve with compression. Only the necessary keyframes remain.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This not only solves the jittering animations in the renderer, but it's also useful for other use case
where we want the data to be compact. Examples for this are curves that are sent over the network
or recordings written to disk.&lt;/p&gt;
&lt;h3&gt;Converter Cleanups&lt;/h3&gt;
&lt;p&gt;Transforming the game data from AoE2 and other games to openage formats is handled by the openage
converter. The code for this conversion is actually pretty complex and rivals the actual engine
code in size. However, it's also been infamous for containing a bunch of files that are pretty
much unreadable as they contain up to 10,000 lines.&lt;/p&gt;
&lt;p&gt;Having huge files is not a really a problem for running the scripts, but rather developing on them.
Turns out parsing giant files doesn't make the job of IDE indexers very easy. That alone was enough
motivation to finally split up the converter files more. Increasing the readability is also
a nice plus and makes the converter more maintainable.&lt;/p&gt;
&lt;p&gt;As a side goal, we've also been working on making the converter less error-prone and more forgiving
in some cases. This was necessary due to the constant changes to the game data format in the new
expansions for AoE2:DE. Updates to AoE2:DE should hopefully not crash the converter as much anymore,
although we still have to keep pace with the data format changes.&lt;/p&gt;
&lt;h2&gt;Outside Contributions&lt;/h2&gt;
&lt;p&gt;Since our last update, openage has received a number of outside contributions that we want
to honorably mention here. These add a few significant improvements to the engine :)&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/jere8184"&gt;@jere8184&lt;/a&gt; and &lt;a href="https://github.com/dmwever"&gt;@dmwever&lt;/a&gt; improved
the openage pathfinder. Most notably are the &lt;a href="https://github.com/SFTtech/openage/pull/1713"&gt;increased the pairing heap performance&lt;/a&gt;,
the &lt;a href="https://github.com/SFTtech/openage/pull/1725"&gt;introduction of the &lt;code&gt;dirty&lt;/code&gt; flag for integration&lt;/a&gt;
as well as the addition of an &lt;a href="https://github.com/SFTtech/openage/pull/1724"&gt;array curve datastructure&lt;/a&gt;
for use in the field types.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/jere8184"&gt;@jere8184&lt;/a&gt; also added fixes for the
&lt;a href="https://github.com/SFTtech/openage/pull/1746"&gt;Windows builds&lt;/a&gt; and
&lt;a href="https://github.com/SFTtech/openage/pull/1733"&gt;CI pipeline&lt;/a&gt;. They also introduced fused
types to the &lt;a href="https://github.com/SFTtech/openage/pull/1735"&gt;SLP/SMP/SMX/SLD image conversion&lt;/a&gt; in our converter.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/ZzzhHe"&gt;@ZzzhHe&lt;/a&gt; has made added several new features to the renderer:
- &lt;a href="https://github.com/SFTtech/openage/pull/1718"&gt;Completeness checks for uniform initialization&lt;/a&gt;
- &lt;a href="https://github.com/SFTtech/openage/pull/1734"&gt;Binding empty vertex array objects&lt;/a&gt;
- &lt;a href="https://github.com/SFTtech/openage/pull/1738"&gt;Configurable shader templates&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/haytham918"&gt;@haytham918&lt;/a&gt; had added &lt;a href="https://github.com/SFTtech/openage/pull/1710"&gt;optional &lt;code&gt;clang-tidy&lt;/code&gt; checks&lt;/a&gt; to our buildsystem.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/bytegrrrl"&gt;@bytegrrrl&lt;/a&gt; added &lt;a href="https://github.com/SFTtech/openage/pull/1770"&gt;a few operations to our &lt;code&gt;FixedPoint&lt;/code&gt; class&lt;/a&gt;
that enable us to use pure fixed-point calculations in more places. &lt;code&gt;FixedPoint&lt;/code&gt; can now
also &lt;a href="https://github.com/SFTtech/openage/pull/1758"&gt;use an intermediary type&lt;/a&gt; useful for operations on large numbers, thanks to the
contribution of &lt;a href="https://github.com/Eeelco"&gt;@Eeelco&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We hope we didn't forget anybody who made important changes :) More external contributions are also open
in the GitHub repository.&lt;/p&gt;
&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;A better first question might be: When does the next blogpost release after this one? Will it also
take almost a year? That's a good question, although the answer is that sadly it will probably take a
while to write the next update. Writing the devlogs takes a lot of time, especially when they
should be understandable for newbies. Also, when the choice is between writing devlogs and coding,
coding is still much more fun... So coding will take priority for a while. However, I (@heinezen)
still like creating the devlogs, so maybe they will pop up more frequently again sooner or later :D&lt;/p&gt;
&lt;p&gt;As for openage, we now have opened a loooot of possibilities with the completition of game entity
interaction. We can now go the boring route and add more interaction types that are not handled
fully yet (like building construction). There's also the possibility for a more exciting route
which leads us even deeper into topic of state transitions, e.g. proper handling of unit deaths.
Or we might do something entirely different depending on who has better ideas. I guess you'll find out
next time ;)&lt;/p&gt;
&lt;p&gt;Take care!&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any remaining questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="simulation"></category><category term="renderer"></category></entry><entry><title>Openage Development News: August 2024</title><link href="https://blog.openage.dev/openage-development-news-august-2024.html" rel="alternate"></link><published>2024-09-09T00:00:00+02:00</published><updated>2024-09-09T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2024-09-09:/openage-development-news-august-2024.html</id><summary type="html">&lt;p&gt;Devlog for August 2024&lt;/p&gt;</summary><content type="html">&lt;p&gt;Hello everyone and welcome to another update on openage. For this month, our priorities
have mostly been getting release 0.6.0 ready to ship and thinking about something
to start on for the subsequent 0.7 milestone. While release 0.6.0 is currently stuck in
review for a bit, milestone 0.7 is already starting to take shape, so we can already
tell you a few details about it. So without further ado, let's get started.&lt;/p&gt;
&lt;h2&gt;Game entity interaction&lt;/h2&gt;
&lt;p&gt;As our major focus for milestone 0.7, we have decided on &lt;strong&gt;interaction between game entities&lt;/strong&gt;.
This includes all ingame mechanics that let units do things to each other. The most common
example of this would probably be &lt;em&gt;attacking&lt;/em&gt;, although conversion, construction or resource gathering
also fall under this definition.&lt;/p&gt;
&lt;p&gt;openage (mostly) encapsulates all interactions inside one ability type: &lt;code&gt;ApplyEffect&lt;/code&gt;.
As the name suggests, &lt;code&gt;ApplyEffect&lt;/code&gt; hold a batch of &lt;code&gt;Effect&lt;/code&gt; objects that define what
interactions are done when the ability is used. The concrete type of the &lt;code&gt;Effect&lt;/code&gt; object
determines the type of interaction. For example, attack damage is modeled by the &lt;code&gt;Effect&lt;/code&gt;
type with the (somewhat bulky) name &lt;code&gt;FlatAttributeChange&lt;/code&gt;. Different effect types can be
mixed in a batch, so an &lt;code&gt;ApplyEffect&lt;/code&gt; ability could theoretically do damage and simultaneously
try converting a unit.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Effect types" src="https://blog.openage.dev/images/news/2024-08/apply_effect.svg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Structure of ability and effect types in the API.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Our implementation is still in a very basic work in progress stage, so there are not
many interesting stories to tell yet. We are currently focusing on getting attack interactions
to work with the game entities in the AoE2 modpack with some example code. Here you
can see part of the result:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Knight attack" src="https://blog.openage.dev/images/news/2024-08/knight_apply_effect.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A knight game entity, currently attacking itself due to an absence of other targets.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Implementing more interaction will get more and more complex as other systems get involved such as
attack stances, line of sight, state changes, and so on. You can expect to read more on that over
the next months.&lt;/p&gt;
&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;When we are satisfied with the basic interactions, we will gradually expand the capabilties of
the engine to support more interaction features. An obvious choice for the next improvement would
be the introduction of a collision system, which we need so that game entities can compute when
they are close enough to each other for interactions.&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="simulation"></category><category term="pathfinding"></category></entry><entry><title>Openage Development News: July 2024</title><link href="https://blog.openage.dev/openage-development-news-july-2024.html" rel="alternate"></link><published>2024-08-04T00:00:00+02:00</published><updated>2024-08-04T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2024-08-04:/openage-development-news-july-2024.html</id><summary type="html">&lt;p&gt;Devlog for July 2024&lt;/p&gt;</summary><content type="html">&lt;p&gt;Hello everyone and welcome to another openage monthly devlog. For this month, we are
looking at a new renderer feature that adds a common optimization strategy to our rendering
pipeline. We will also talk a little bit about the imminent release of the openage version 0.6.0.&lt;/p&gt;
&lt;h2&gt;Frustum Culling&lt;/h2&gt;
&lt;p&gt;We are going to start with &lt;em&gt;frustum culling&lt;/em&gt;, a &lt;a href="https://github.com/SFTtech/openage/pull/1642"&gt;feature&lt;/a&gt; added by 
outside contributor &lt;a href="https://github.com/nikhilghosh75"&gt;@nikhilghosh75&lt;/a&gt; that has finally landed
in the main repository.&lt;/p&gt;
&lt;p&gt;A &lt;em&gt;frustum&lt;/em&gt; in this context is referring to a camera frustum, which basically represents
the view cone of our camera in the 3D scene. Objects that are outside of this view cone would
not be visible in a rendered frame, even if we told the GPU to draw the object. However, requesting
the GPU to draw these objects and letting it figure out where and if they would be on screen
can still take a great amount of time. Only once the GPU notices that the object
would be drawn outside the viewport, it can skip further calculations.&lt;/p&gt;
&lt;p&gt;With frustum &lt;em&gt;culling&lt;/em&gt;, we are trying to exclude the objects that are not visible as early as
possible, so that they don't even result in a draw call to the GPU. Ideally, we can also skip
shader uniforms updates (done on the CPU side) while the object stays invisible.
The potential for time saves here can be huge. Imagine a game scene that has 10,000 objects in total
but only 500 are visible in the camera view. In this case, the number of draw calls and shader updates
would be reduced by 95%!&lt;/p&gt;
&lt;p&gt;openage currently supports 2D frustums (for sprite animations) and 3D frustums (for objects like
terrain). Since most of our rendered objects are sprite animations, the 2D frustum is the
type that would be used most frequently. You can see how the culling works in this small demo: &lt;/p&gt;
&lt;p&gt;&lt;img alt="Frustum Culling Demo" src="https://blog.openage.dev/images/news/2024-07/frustum_culling.png"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Red rectangle&lt;/em&gt;: Frustum bounding box&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Blue rectangles&lt;/em&gt;: Animation boundary box of an object&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you can see, objects (blue rectangles) outside the frustum boundaries (red rectangle)
are not included the render pass. To make the culling effect visible in this demo, the frustum's size is smaller
than the actual camera viewport. In a normal game, the frustum would be slightly larger than
the camera viewport to ensure that all objects that are visible are displayed. Notice also that
frustum culling is not pixel perfect for the animations (e.g. for the leftmost object). Instead,
the maximum boundary of all animation sprites are used, so an object may still be drawn if one of its
current animation's sprites &lt;em&gt;could&lt;/em&gt; be visible during a rendered frame.&lt;/p&gt;
&lt;h2&gt;Preparing for the Next Release&lt;/h2&gt;
&lt;p&gt;We have decided that after the last pathfinding improvements have been merged, we want to release
the latest state of the project as &lt;strong&gt;version 0.6&lt;/strong&gt;. The engine has improved a lot since
the last release, so in our mind it makes sense to publish a minor feature milestone to reflect what
we have achieved so far.&lt;/p&gt;
&lt;p&gt;Most additions for the next release should already be known to avid readers of our devlogs, so
we won't repeat them in detail here. Our major personal highlights are the new flow field
pathfinder as well as the massive performance improvements we accomplished. Of course, there
are also a bunch of small and big fixes, like getting the engine to work on Windows and macOS
again, that are pretty nice.&lt;/p&gt;
&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;When the release is done, we will focus more on game simulation, specifically game entity
interactions. There are also long-term improvements planned for the GUI and audio systems,
so maybe we also start on that in the near future.&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="renderer"></category><category term="release"></category></entry><entry><title>Openage Development News: June 2024</title><link href="https://blog.openage.dev/openage-development-news-june-2024.html" rel="alternate"></link><published>2024-07-10T00:00:00+02:00</published><updated>2024-07-10T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2024-07-10:/openage-development-news-june-2024.html</id><summary type="html">&lt;p&gt;Devlog for June 2024&lt;/p&gt;</summary><content type="html">&lt;p&gt;Hello and welcome to another openage devlog. This month, we have introduced a few more
pathfinder updates that make it work better with the game simulation. We are now getting
to the point where the pathfinding looks and performs okay enough that we can include
it in the next release version!&lt;/p&gt;
&lt;h2&gt;Propagating Line-of-sight through Portals&lt;/h2&gt;
&lt;p&gt;As described in our &lt;a href="https://blog.openage.dev/openage-development-news-april-2024.html"&gt;April devlog&lt;/a&gt;, the pathfinder uses line-of-sight (LOS) optimization
to improve pathing close to the target cell. To put it simply: When a cell on the grid is flagged as LOS,
there exist a direct (non-obstructed) path from this cell to the target. In practice, this
means that any game entity at the position of this cell can move to the target position in
a straight line. This makes pathing look much more natural and &lt;em&gt;smooth&lt;/em&gt;. If we would
only use the direction vectors of the flow field right until the end, we would
be limited to their 8 possible directions.&lt;/p&gt;
&lt;p&gt;In our initial implementation, LOS optimization was confined to the target sector, i.e.
cells outside the target sector were never flagged as LOS. However, this meant that a lot
of paths that could have been a straight line but crossed a sector boundary looked
noticeably weird. Instead of bee-lining straight towards the target when there are
no obstructions, game entities would have to move to the edge of the target sector first
before they would reach an LOS cell:&lt;/p&gt;
&lt;video width="640" height="480" controls&gt;
  &lt;source src="./images/news/2024-06/openage_path_gameplay3.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;p&gt;&lt;em&gt;You can almost see where the sector boundary is as the game entity is turning very sharply towards the target as it reaches the first LOS flagged cell in the target sector.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This behaviour has been fixed by propagating the LOS integration through sector portals.
Essentially, LOS flags are passed from one side of the portal (in the entry sector) to the
other (in the exit sector). LOS integration then continues in the exit sector using the passed LOS flagged
cells as the starting point. As a result, paths look much better when they cross multiple sectors:&lt;/p&gt;
&lt;video width="640" height="480" controls&gt;
  &lt;source src="./images/news/2024-06/openage_path_gameplay4.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;h2&gt;Optimizing Field Generation&lt;/h2&gt;
&lt;p&gt;The topic of performance came up in a Reddit comment before, so we thought it might be interesting to pick it up
again. Performance is big factor in the feasibility of flow fields, since pathfinding should not
stall gameplay operations. Flow fields do have some benefits for the quality of paths, but the added
complexity can come with a hefty performance price tag. Thus, we have to ensure that the pathfinding
is still as performant as possible.&lt;/p&gt;
&lt;p&gt;Over the last month, we have applied several optimization strategies:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Simplified Code&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We removed a lot of redundant code from the design phase of the pathfinder. This includes things
like redundant sanity checks, debug code, or flags that were only relevant for the pathfinding
demos that you've seen in our monthly devlogs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CPU-friendly datastructures&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To increase throughput for field generation on the CPU, we replaced most occurences of datastructures
that are known to be slow (e.g. &lt;code&gt;std::unordered_map&lt;/code&gt;, &lt;code&gt;std::deque&lt;/code&gt;, &lt;code&gt;std::unordered_set&lt;/code&gt;) with
vectorized data types (&lt;code&gt;std::vector&lt;/code&gt; and &lt;code&gt;std::array&lt;/code&gt;). These data types utilize the CPU's L1-L3 caches
much better, which means that the CPU has to spend less time on fetching data from RAM and has more
time for running calculations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Flow Field Caching&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Generated flow fields are now cached and reused for subsequent path requests if possible.
In practice, chaching can be done for all flow fields on the high-level path where the target
is a portal cell (i.e. any sector that is not the target sector). Since field
generation is deterministic, building two flow fields with the same target cell results
in them being equal. Therefore, if a high-level paths uses the same portal as a previous
path request, the previously generated flow field can be reused.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;The overall result of our optimizations is that pathfinding is now about 2x-4x faster than
in our first iteration. Technically, there are no benchmarks yet, so you have to trust our numbers
for now. On our test machines, a path request can take between &lt;code&gt;0.3ms&lt;/code&gt; and &lt;code&gt;2ms&lt;/code&gt; for paths
of roughly the same length, depending on the number of fields that have to be built and
how many obtructions there are per sector. Flow field and integration field generation
in the low-level pathfinding stage is now so fast that the A* calculations of the
high-level pathfinder are becoming the bottleneck with ~50% runtime usage.&lt;/p&gt;
&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;That was definitely enough pathfinding for a while. There is a probably still lot to improve,
but other parts of the engine need attention too.&lt;/p&gt;
&lt;p&gt;Next month, we will focus more on game entity &lt;em&gt;interactions&lt;/em&gt;. That means we will make them do
things to each other, like damage or healing or whatever we can think about that's fun (and
not too complicated).&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="pathfinding"></category></entry><entry><title>Openage Development News: May 2024</title><link href="https://blog.openage.dev/openage-development-news-may-2024.html" rel="alternate"></link><published>2024-06-04T00:00:00+02:00</published><updated>2024-06-04T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2024-06-04:/openage-development-news-may-2024.html</id><summary type="html">&lt;p&gt;Devlog for May 2024&lt;/p&gt;</summary><content type="html">&lt;p&gt;We have a few more pathfinding updates for you this month. These are mostly about
integrating pathfinding into the game simulation to test it under real gameplay conditions.&lt;/p&gt;
&lt;h2&gt;Pathfinding in Game Simulation&lt;/h2&gt;
&lt;p&gt;We finally got flow field pathfinding implemented in the game simulation!
You can see the result below:&lt;/p&gt;
&lt;video width="640" height="480" controls&gt;
  &lt;source src="./images/news/2024-05/openage_path_gameplay1.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;p&gt;In the game simulation, not that much is being done beyond initializing
the flow field grids when loading a modpack (as discussed in &lt;a href="https://blog.openage.dev/openage-development-news-april-2024.html"&gt;last month's&lt;/a&gt;
post) and sending path requests from the movement system to the pathfinding
subcomponent. In the movement system, we only have to create the path request
consisting of grid ID (extracted from the moving game entity's &lt;code&gt;Move&lt;/code&gt; ability),
start location (current position of the game entity), and target location
(position of the movement target). The request is forwarded to the
&lt;code&gt;Pathfinder&lt;/code&gt; object referenced in the game state which acts as an
interface to the pathfinding subcomponent. After the pathfinding is finished,
the movement system gets back a list of waypoints which can then be
inserted into the game entity's movement curve.&lt;/p&gt;
&lt;p&gt;While all of this sounds pretty simple &lt;em&gt;now&lt;/em&gt;, there were still a bunch of
fixes necessary to the main pathfinding algorithms to make it work
properly. We will quickly go over the major problems that we faced
in the next sections.&lt;/p&gt;
&lt;h3&gt;Diagonal Paths Blocking&lt;/h3&gt;
&lt;p&gt;When building a flow field, we want to point the vectors of each cell
in the direction of the path with the minimum movement cost. The naive
way of computing a direction vector for a cell in a flow field
is pretty simple: For each cell, we check the integration values for
the 8 surrounding neighbor cells and let the direction vector point
in the direction of the neighbor with the lowest value. Do that for all
the cells and the flow field is ready.&lt;/p&gt;
&lt;p&gt;However, this solution is flawed in that it does not account for a specific
edge case concerning diagonal movement. You may be able to spot the problem
by looking at the example grid below.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Naive cell comparison" src="https://blog.openage.dev/images/news/2024-05/naive_diagonal.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Hint: Check the direction vectors in the top corner.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As you can see above, the problem here is that some diagonal paths at the top
should not be possible. It's as if the path would literally slips through
the cracks of the impassable cells. This behavior is cause by the naive
implementation considering all neighbor cells individually. However, logically
(or in AoE2 at least), a diagonal path should only be able to exist if an adjacent
horizontal &lt;em&gt;or&lt;/em&gt; vertical cell are passable. If neither of them are, then the corresponding
diagonal cell should be considered "blocked".&lt;/p&gt;
&lt;p&gt;The solution to this problem is actually pretty simple. We can find out which
neighbor cells should be considered "blocked" by processing the 4 cardinal
neighbor cells' integration values first and add an additional check that sets a flag
if they are impassable. Afterwards, we process the 4 diagonal cells where we now also
check whether their adjacent horizontal/vertical cells are impassable. If they both are
impassable, the diagonal cell is considered "blocked" and the integration value
comparison is skipped over.&lt;/p&gt;
&lt;p&gt;The result then looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Improved cell comparison" src="https://blog.openage.dev/images/news/2024-05/improved_diagonal.png"&gt;&lt;/p&gt;
&lt;h3&gt;Start/Target Sector Refinements&lt;/h3&gt;
&lt;p&gt;As previously explained in an &lt;a href="https://blog.openage.dev/openage-development-news-march-2024.html"&gt;older devlog&lt;/a&gt;, the pathfinder executes in three stages:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;High-level search: Search for a path on the &lt;em&gt;sector&lt;/em&gt; level with A* using the portals connecting each sector.&lt;/li&gt;
&lt;li&gt;Low-level search: Build flow fields for all sectors in the sector path found by the high-level search.&lt;/li&gt;
&lt;li&gt;Waypoint creation: Follow the direction vectors in the flow fields from start to target cell.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The reason we do stage 1 is to save computation time by only creating and building flow fields
for the sectors that are visited by the path.&lt;/p&gt;
&lt;p&gt;In the inital implementation of stage 1, there were a few bugs that have to be ironed out. For example,
one (wrong) assumption we made was that a start or target cell would automatically have access to all
portals in their sector. There are some obvious counterexamples, e.g. when the start is on an island:&lt;/p&gt;
&lt;video width="640" height="480" controls&gt;
  &lt;source src="./images/news/2024-05/openage_path_gameplay2.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;p&gt;&lt;em&gt;Ingame example of how such an island could look like. Note that terrain is only one way of creating this situation. Sorrounding the game entity with buildings would have the same effect.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In the situation shown above, we cannot even exit the sector and are confined to the island. Another
example would be a situation where only partial access to portals exist:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Naive grid" src="https://blog.openage.dev/images/news/2024-05/naive_grid.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Start cell (green) and target cell (orange) have access to different portals, even though they are in the same sector. The only way to reach the target from the start is to path through the portals to the neighboring sector on the left.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To avoid these problems, the pathfinder is now doing a preliminary check before the high-level search
that determines which portals are accessible by the start cell and the target cell, respectively. This
is done by calculating their sectors' integration fields and checking which portals are passable
in said integration fields¹. When the A* algorithm in the high-level search is started, we use the
portals reachable from the start sector as the starting nodes. The portals reachable by the target
cell become possible end nodes.&lt;/p&gt;
&lt;p&gt;¹ We can reuse these fields in stage 2 (low-level search) when building the flow fields for
these sectors. Thus, it isn't even much of an overhead.&lt;/p&gt;
&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;You can be excited for more pathfinding updates next month, but then that's probably it. We
promise! Other than pathfinding, we also have updates for the renderer pipeline queues up,
so tune in if you are interested in more graphics-related progress.&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="pathfinding"></category><category term="simulation"></category></entry><entry><title>Openage Development News: April 2024</title><link href="https://blog.openage.dev/openage-development-news-april-2024.html" rel="alternate"></link><published>2024-05-05T00:00:00+02:00</published><updated>2024-05-05T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2024-05-05:/openage-development-news-april-2024.html</id><summary type="html">&lt;p&gt;Devlog for April 2024&lt;/p&gt;</summary><content type="html">&lt;p&gt;Hello everyone, we are happy to have you here for yet another openage update. For the latter half of
the month, we have taken a small break from pathfinding to work on other small internal projects that have been
piling up, e.g. some leftover tasks in the renderer. That also means that, unlike last month, this update won't
be 100% pathfinding exclusive, so those of you who enjoy more variety have something to look forward to!&lt;/p&gt;
&lt;h2&gt;Pathfinding in nyan API&lt;/h2&gt;
&lt;p&gt;Since the pathfinding system in the engine is mostly finished, we have been making efforts to officially use
it into the movement systems of the game simulation and build it into our rudimentary map generation.
The first major step in this direction is the integration of new pathfinding-related objects into
our &lt;a href="https://github.com/SFTtech/openage/blob/master/doc/nyan/openage-lib.md"&gt;nyan modding API&lt;/a&gt;. This allows
game objects to utilize the pathfinding functionality in several ways.&lt;/p&gt;
&lt;p&gt;&lt;img alt="nyan API objects" src="https://blog.openage.dev/images/news/2024-04/nyan_api_pathfinding.svg"&gt;&lt;/p&gt;
&lt;p&gt;The new API object &lt;code&gt;PathType&lt;/code&gt; can be used to define grids in the pathfinder. Usually, there exists more than
one pathfinding grid per game. For example, AoE2 has two grids, one for land-based units and one for ships.
If you are very generous, you could additionally consider that there is a third "air" grid as the ambient birds flying
all over the map have separate pathfinding rules. A unique air grid is also used for flying units in
&lt;em&gt;Star Wars: Galactic Battlegrounds&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PathType&lt;/code&gt; objects can be referenced by other API objects to reference a specific grid, e.g. by the &lt;code&gt;Move&lt;/code&gt; ability with its
new member &lt;code&gt;path_type&lt;/code&gt;. This tells the engine which grid to search for pathfinding when the ability is used
by a game entity. For dynamically influencing the cost of the grid, there is now a &lt;code&gt;Pathable&lt;/code&gt; ability which changes the
cost of grid cells for one or multiple grids at its location when it is active. The latter
ability may for example be used by buildings to make parts of the grid impassable as long as the
building exists.&lt;/p&gt;
&lt;p&gt;For map generation, the &lt;code&gt;Terrain&lt;/code&gt; API object now allows defining the pathing costs associated with each terrain
via the &lt;code&gt;path_costs&lt;/code&gt; member. This member simply assigns a cost value to each grid defined with &lt;code&gt;PathType&lt;/code&gt;.
When the map is created, the terrain generator used these values to initialize the cost fields for the grid in
the pathfinder.&lt;/p&gt;
&lt;h2&gt;Rendering Multi-textured Objects&lt;/h2&gt;
&lt;p&gt;After adding all the relevant pathfinding types to our API, we are finally able to put all pieces together and make
units move with proper pathfinding. However, there was one minor problem that we wanted to resolve first: While
the gamestate has supported tiling with terrains for a while, the terrain &lt;em&gt;renderer&lt;/em&gt; couldn't display them properly
yet. In fact, the renderer would only use the texture of the first tile for texturing a whole 10x10 chunk, so all
chunks looked like they only contained a single terrain type. Given that this is rather distracting when we want to
test whether pathfinding based on specific terrain costs works, we took a slight detour to extend the renderer first.
You can see the result in the screenshot below.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Multi-terrain/layer support" src="https://blog.openage.dev/images/news/2024-04/openage_multi_mesh.png"&gt;&lt;/p&gt;
&lt;p&gt;Previously, each terrain chunk in the renderer was handled as a single mesh that would be drawn with one texture
in the shader. In the new implementation, the chunk is split up so that all tiles with matching terrain
textures get their own mesh. For example, if there are 6 different terrain textures, then there would be
6 meshes created for the chunk. All of the meshes are drawn individually, but this is practically unnoticeable
as the meshes border each other seamlessly. You may have also noticed the lack of terrain blending which
currently make the tile edges very distinct.&lt;/p&gt;
&lt;p&gt;After we updated the terrain renderer, we also applied similar changes to the world renderer (which draws unit
sprites). Here, we added support for rendering animations with multiple layers. In the above screenshot,
you can see this in action when you look at the castle, which consists of a &lt;em&gt;main&lt;/em&gt; layer and a &lt;em&gt;shadow&lt;/em&gt; layer.
The main layer is the building sprite, whereas the shadow layer is the semi-transparent grayscale sprite
to the left of the building. Previously, the renderer would only draw whatever layer was defined first.&lt;/p&gt;
&lt;p&gt;The principle is roughly the same as for the terrain chunks: Every layer gets its own mesh which is drawn
individually. Draw order is a bit more important in this context because animations of different units are
more likely to overlap each other than tiles in the terrain renderer. Therefore, we added the possibility
to insert renderable objects by priority into the rendering pipeline. As a result, all animation parts
should now be displayed properly in the game.&lt;/p&gt;
&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;Now that the terrain renderer actually displays what's happening in the gamestate, we can start working
on integrating the pathfinder again. In theory, this is pretty trivial to add, but we'll have to see if we
encounter some errors in the implementation.&lt;/p&gt;
&lt;p&gt;The next obvious step for the terrain renderer is blending support. This could be much harder as we would
have to find a strategy that can handle the blending styles of all the old and new releases (AoE1, Conquerors,
and the Definitive Editions all have different approaches). We will probably try to tackle the classic Conquerors
blending first and then iterate and adjust gradually for other styles.&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="pathfinding"></category><category term="renderer"></category></entry><entry><title>Openage Development News: March 2024</title><link href="https://blog.openage.dev/openage-development-news-march-2024.html" rel="alternate"></link><published>2024-03-31T00:00:00+01:00</published><updated>2024-03-31T00:00:00+01:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2024-03-31:/openage-development-news-march-2024.html</id><summary type="html">&lt;p&gt;Devlog for February/March 2024&lt;/p&gt;</summary><content type="html">&lt;p&gt;Hello everyone and welcome to another round of openage updates. If you enjoyed the pathfinding
explanations from our last devlog, you can probably start getting excited because this month's
post will be &lt;em&gt;all about&lt;/em&gt; even more fun pathfinding features. However, we hope that those of
you who are not avid pathfinding aficionados can have some fun too. So let's get to it.&lt;/p&gt;
&lt;h2&gt;Line of Sight Optimization&lt;/h2&gt;
&lt;p&gt;In &lt;a href="https://blog.openage.dev/openage-development-news-january-2024.html"&gt;last month's update&lt;/a&gt;, we showed off the flow fields that
are created by our new pathfinder implementation. Essentially, the idea behind flow fields is
that instead of computing a single path from start A to target B, we generate a vector field
for the whole grid where every cell gets assigned a vector that points towards the next cheapest
cell for reaching B. As a result, units anywhere on the grid can follow (or &lt;em&gt;flow&lt;/em&gt;) along these vectors to
eventually arrive at the target (see below).&lt;/p&gt;
&lt;p&gt;&lt;img alt="Flow field example" src="https://blog.openage.dev/images/news/2024-03/flow_field_example.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;target cell == (7,7); origin is left corner&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;yellow == less expensive&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;purple == more expensive&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;black == impassible&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this example, you can see that the flow field vectors only support 8 directions. A side
effect of this is that paths become diamond-shaped, i.e. they have turns of at least 45 degrees.
While this may not be as noticeable when you are just looking at the static flow field, it can be very annoying
when observing units in motion. When controlling units, most players would expect them to go in a straight line
if there are no obstacles between start and target (and not take detour into a castle's line of fire).
For this reason, we have to do some low-level optimization that smoothes out short-distance
paths in these situations.&lt;/p&gt;
&lt;p&gt;One of these optimizations is a so-called &lt;em&gt;line-of-sight pass&lt;/em&gt;. In this preliminary step,
we flag every cell that can be reached from the target in a straight line with an "line-of-sight" flag.
Units in these cells can then be pathed directly towards the target in a straight line
without having to use the vector field. You can see the results of doing such a line-of-sight
pass in the image below.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Line-of-sight pass" src="https://blog.openage.dev/images/news/2024-03/los_pass_demo.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;target cell == (1,4); origin is left corner&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;white == line-of-sight flag&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;light grey == blocked flag&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;dark grey == passable, but no line-of-sight&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;black == impassible&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Impassable cells or cells with more than minimum cost are considered line-of-sight &lt;em&gt;blockers&lt;/em&gt;
and are assigned a separate "blocked" flag. The same goes for cells that are only partially
in line-of-sight, e.g. cells that are on the line between the blocker cells' outer corners
and the edge of the grid. The cells marked as "blocked" form the boundaries of a line-of-sight
vision cones that span across the grid.&lt;/p&gt;
&lt;p&gt;For cells with a "line-of-sight" flag, we can skip calculating flow field vectors as they are
no longer necessary for finding a path.&lt;/p&gt;
&lt;h2&gt;Travelling with Portals&lt;/h2&gt;
&lt;p&gt;One advantage of flow fields is that the generated field may be reused for multiple
path requests to the same target, e.g. group movement of units. While reusing the fields
can save computation time in this context, the complexity of flow field calculations
make the initial cost of building the flow field much higher than for other pathfinding
methods. On larger grids, this can make individual path requests incredibly slow.&lt;/p&gt;
&lt;p&gt;To solve this problem, we can utilize a simple trick: We split the pathfinding grid
into smaller &lt;em&gt;sectors&lt;/em&gt;, e.g. with size 16x16, and search for a high-level path through
these sectors first. Afterwards, we only calculate flow fields for the sectors
that are visited and ignore the rest of the grid.&lt;/p&gt;
&lt;p&gt;To accomplish this, sectors are connected via so-called &lt;em&gt;portals&lt;/em&gt;. Portal are created on
the pathable edges between two sectors. Additionally, portals in the same sector are connected
to each other if they are mutually reachable. The result is a mesh of portal nodes that can be
searched with a high-level pathfinder. For the high-level pathfinder, we can use a node-based approach
intead of flow fields, e.g. the A* algorithm, to search the mesh. Finding the high-level path
should usually be pretty fast as it only depends on the number of portals on the grid.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Grid with portals" src="https://blog.openage.dev/images/news/2024-03/portal_demo.png"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;white == passable&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;grey == portal tiles&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;black == impassible&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;The only major step left in the pathfinder integration is to include it into the actual game simulation, i.e.
building it into map/terrain generation. This should be easier than the implementation the pathfinder itself,
but will take some effort to get right. If pathfinding becomes too tedious, we might switch
things up and work on something else for a short while. In any case, you will find out what
we decided to do in next month's update!&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="pathfinding"></category></entry><entry><title>Openage Development News: January 2024</title><link href="https://blog.openage.dev/openage-development-news-january-2024.html" rel="alternate"></link><published>2024-02-18T00:00:00+01:00</published><updated>2024-02-18T00:00:00+01:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2024-02-18:/openage-development-news-january-2024.html</id><summary type="html">&lt;p&gt;Devlog for January 2024&lt;/p&gt;</summary><content type="html">&lt;p&gt;Hello everyone and welcome to another (very delayed) update to the current openage development
progress. This time, we have a lot to talk about a new larger feature implementation (and a few
other cool things that are interesting for you nerds). So without further ado, let's look at the
changes.&lt;/p&gt;
&lt;h2&gt;Pathfinding with Flow Fields&lt;/h2&gt;
&lt;p&gt;In mid-January, we started working on a new pathfinding algorithm based on &lt;em&gt;flow fields&lt;/em&gt;. It is
set to enhance our previous pathfinding logic which so far is a pure &lt;em&gt;A*&lt;/em&gt; implementation.&lt;/p&gt;
&lt;p&gt;For those unfamiliar with flow fields, here is a quick introduction: Flow field pathfinding is
a technique that's specifically intended for large &lt;strong&gt;crowd&lt;/strong&gt; movements, which is exactly
what we are doing in most RTS games. In these games, you often have situations where a) multiple
units are controlled at the same time and b) moved as a group to the same goal location.
The key idea behind flow field pathfinding is that instead of finding the best path for every individual
unit, as done in A*, we calculate the best paths for the whole grid as direction vectors. These vectors
then steer units around obstacles and towards the goal. As a result, all units with the same goal
can "flow" across the grid using these vectors, no matter where their starting positions are.&lt;/p&gt;
&lt;p&gt;Explaining every detail about flow fields could warrant its own blogpost, so we will stop here
and direct everyone interested enough to &lt;a href="http://www.gameaipro.com/GameAIPro/GameAIPro_Chapter23_Crowd_Pathfinding_and_Steering_Using_Flow_Field_Tiles.pdf"&gt;read the article&lt;/a&gt; that our implementation
is based on. Currently, we are still demoing our flow field pathfinder to tweak it before we build it into
the actual game simulation. The demo shows just the basic flow field functionality, but you
should already be able to see where we are going with it.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Cost field" src="https://blog.openage.dev/images/news/2024-01/cost_field.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;green == less expensive, red == more expensive, black == impassible&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Every flow field pathing request starts with a &lt;em&gt;cost field&lt;/em&gt; that assigns each cell in the grid
a cost value. This cost determines how expensive it is to move to a cell on the grid. The cost field
changes infrequently during gameplay, e.g. when a building is placed.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Integration field" src="https://blog.openage.dev/images/news/2024-01/integration_field.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;target cell == (7,7); origin is left corner&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;yellow == less expensive, purple == more expensive, black == impassible&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;When we get a pathing request to a specific goal, another field called &lt;em&gt;integration field&lt;/em&gt; is
computed. The integrated costs of each cell contain the minimum movement cost required to reach
the goal from the cell. To do this, we integrate outward starting with the target cell by
checking each cell's direct neighbors and setting the cells integrated cost to &lt;code&gt;own_cost + cheapest_neighbor_cost&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Flow field" src="https://blog.openage.dev/images/news/2024-01/flow_field.png"&gt;&lt;/p&gt;
&lt;p&gt;As a final step, we create the &lt;em&gt;flow field&lt;/em&gt; that calculates steering vectors for each cell.
The steering vectors point towards the neighbor cell with the lowest &lt;em&gt;integrated&lt;/em&gt; cost. This way,
units following the vectors should always take the path with the cheapest movement cost to
the goal. This in independent from where their initial position is on the grid.&lt;/p&gt;
&lt;h2&gt;Optimizations&lt;/h2&gt;
&lt;p&gt;Since the beginning of this year, we have started optimizing some parts of the code in Python and
C++ that were in need of a speedup. On the C++-side, this is mostly addressed by making our internal
data structures more cache-friendly. This is especially relevant for our renderer, where cache-friendly
data means more throughput and, as a consequence, more objects that can be shown on screen.&lt;/p&gt;
&lt;p&gt;In our Python code, we have added multi-threading support to the final media export step in the
conversion process. Previously, conversion of graphics data took a significant amount of time,
especially for the newer game releases which require processing gigabytes of graphics files. Converting
this data would often take up at least 30 minutes.&lt;/p&gt;
&lt;p&gt;The new implementation of the media converter now parallelizes the conversion of graphics data
using Python's &lt;code&gt;multiprocessing&lt;/code&gt; module. This drastically speeds up the overall conversion
process by utilizing all available CPU threads. Conversion should now take no longer
than 5 minutes for any AoE release.&lt;/p&gt;
&lt;p&gt;&lt;img alt="CPU utilization" src="https://blog.openage.dev/images/news/2024-01/cpu_util.png"&gt;&lt;/p&gt;
&lt;p&gt;The table below shows conversion times before and after multi-threading was introduced. As you
can see, the great beneficiaries are DE1 and DE2. The other games also profit, although not as much
because some files convert so fast that the converter cannot spawn threads fast enough to keep up.
This is also the reason why AoE1 is slightly slower now, although the difference is negligable.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Release&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AoE1 (1997)&lt;/td&gt;
&lt;td&gt;28.410s&lt;/td&gt;
&lt;td&gt;33.39s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AoE2 (1999)&lt;/td&gt;
&lt;td&gt;81.186s&lt;/td&gt;
&lt;td&gt;51.01s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SWGB&lt;/td&gt;
&lt;td&gt;109.620s&lt;/td&gt;
&lt;td&gt;62.07s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HD Edition&lt;/td&gt;
&lt;td&gt;67.717s&lt;/td&gt;
&lt;td&gt;53.23s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DE1&lt;/td&gt;
&lt;td&gt;216.225s&lt;/td&gt;
&lt;td&gt;66.48s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DE2&lt;/td&gt;
&lt;td&gt;959.706s&lt;/td&gt;
&lt;td&gt;250.63s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;We are going to put more effort into pathfinding, so that we can use it in the actual game
simulation soon. That would also require us to properly design collision detection, so the
feature might stay in a "work in progress" stage for a while.&lt;/p&gt;
&lt;p&gt;Besides the new pathfinding, we also want to integrate more GUI and HUD features as that will
become more relavant once we add more gameplay features.&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="nyan"></category><category term="simulation"></category></entry><entry><title>Openage Development News: December 2023</title><link href="https://blog.openage.dev/openage-development-news-december-2023.html" rel="alternate"></link><published>2024-01-03T00:00:00+01:00</published><updated>2024-01-03T00:00:00+01:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2024-01-03:/openage-development-news-december-2023.html</id><summary type="html">&lt;p&gt;Devlog for December 2023&lt;/p&gt;</summary><content type="html">&lt;p&gt;Hello everyone and welcome to yet another openage development update. As 2023 is wrapping up, we can look back on a huge amount of features, fixes, and restructerings that made it into the engine this year. Basically, we transformed openage from an unmaintanable monolith into a usable, albeit still work-in-progress, engine prototype. All of the newly designed subsystems were finally integrated into the engine core. This means we can start 2024 without worrying as much about the engine's stability and architecture as before :)&lt;/p&gt;
&lt;p&gt;During the holiday season, openage development also took a small break, so this blogpost is slightly more brief than usual. We will get back to the usual format next month.&lt;/p&gt;
&lt;h2&gt;Configurable Activities - Part 2&lt;/h2&gt;
&lt;p&gt;Our new &lt;em&gt;activity system&lt;/em&gt;, which we introduced in &lt;a href="https://blog.openage.dev/openage-development-news-november-2023.html"&gt;last month's new post&lt;/a&gt;, has now been finalized and published in the new openage nyan API &lt;code&gt;v0.4.1&lt;/code&gt; specification (see &lt;a href="https://github.com/SFTtech/openage/pull/1608"&gt;PR#1608&lt;/a&gt;). In comparison to the progress we showed last month, there are a few minor changes. Most notably, there are now dedicated, built-in conditions for the &lt;code&gt;XORGate&lt;/code&gt; nodes. Some of the other objects were also renamed for extra clarity:&lt;/p&gt;
&lt;p&gt;&lt;img alt="nyan API changes" src="https://blog.openage.dev/images/news/2023-12/activity_nyan_api.svg"&gt;&lt;/p&gt;
&lt;p&gt;Support for the new activity system nyan objects has been added to the engine and the converter. In the converter, there are now two default activity graphs built using the new API objects. One is a very simple graph for buildings that just consists of a basic &lt;code&gt;Start&lt;/code&gt; -&amp;gt; &lt;code&gt;Idle&lt;/code&gt; -&amp;gt; &lt;code&gt;End&lt;/code&gt; flow that essentially only makes sure that the building gets properly drawn on screen. However, the activity graph for units is more complex and makee full use of the event-based node transitions. It is an extension of the hardcoded actvity graph that we previously used in examples, with the notable improvement that game entities can now "break out" of a movement action when they receive a new command.&lt;/p&gt;
&lt;p&gt;&lt;img alt="unit graph" src="https://blog.openage.dev/images/news/2023-12/activity_graph_units.svg"&gt;&lt;/p&gt;
&lt;p&gt;Game entities created during modpack conversion will automatically be assigned an &lt;code&gt;Activity&lt;/code&gt; ability that references one of the default graphs. Ingame, the end results looks like this:&lt;/p&gt;
&lt;video width="640" height="480" controls&gt;
  &lt;source src="./images/news/2023-12/openage_activity_improved.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;p&gt;The current implementation should support most of the simple action flows found in AoE games. We will keep testing and extend the nyan API definition as we add more and more features that utilizing the activity graph.&lt;/p&gt;
&lt;h2&gt;Did you do a 37C3 lightning talk?&lt;/h2&gt;
&lt;p&gt;As some of you who are following the prject for longer than a year may know, we usually try to organize a lightning talk at the annual Chaos Communication Congress (see the &lt;a href="https://www.youtube.com/playlist?list=PLT1iU74zbvGhLaWE8XnXXfA18-gvGtUzd"&gt;YouTube recordings&lt;/a&gt; of our previous attendences). Unfortunately, we couldn't organize an update on the big stage at the 37C3 this year due to scheduling problems, so there will be no regular annual status report video for 2023. We will try to record an alternative status update in either January or February to make up for that and show off some of the recent developments. Until then, you can find our &lt;a href="https://www.youtube.com/watch?v=s-TzT_KoaII"&gt;status update for release 0.5.0&lt;/a&gt; on YouTube which also covers a large portion of the significant improvements we added last year.&lt;/p&gt;
&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;There are no concrete milestone for 2024 yet, but we are still working on improving our internal demos and adding more gameplay features.&lt;/p&gt;
&lt;p&gt;For next month, we will start implementing more complex mechanics such as collision detection and pathfinding to the engine. These will likely take more than a month to be usable, so there will also be updates in-between that add small stuff like configurable hotkeys or a better display of game entity data in the viewport.&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="nyan"></category><category term="simulation"></category></entry><entry><title>Openage Development News: November 2023</title><link href="https://blog.openage.dev/openage-development-news-november-2023.html" rel="alternate"></link><published>2023-12-08T00:00:00+01:00</published><updated>2023-12-08T00:00:00+01:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2023-12-08:/openage-development-news-november-2023.html</id><summary type="html">&lt;p&gt;Devlog from November 2023&lt;/p&gt;</summary><content type="html">&lt;p&gt;Hello and welcome to another one of our monthly openage devlogs! This month was all about adding
usability features to the engine as well as making the nyan data API easier to use. Well, &lt;em&gt;easier&lt;/em&gt;
for us developers at least. Without further ado, let's start with our most interesting new feature.&lt;/p&gt;
&lt;h2&gt;Drag Selection&lt;/h2&gt;
&lt;p&gt;Selecting units with drag selection on screen is something you see in every RTS game since the
90s and I'm sure everyone reading this has used it before. For the player, the process is pretty simple:
They draw a rectangle on screen by holding the mouse button down and everything visible in the rectangle
is then put into their selection queue. In openage it now looks like this:&lt;/p&gt;
&lt;video width="640" height="480" controls&gt;
  &lt;source src="./images/news/2023-11/openage_drag_select2_short.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;p&gt;While this looks like a small feature, the implementation a bit more challenging than what we have done before.
Most of this is because drag selection requires multiple subsystems to work together to get the desired
result. First of all, we need the input system to handle not just one event but a sequence of three
mouse actions (&lt;code&gt;MouseDown&lt;/code&gt; -&amp;gt; &lt;code&gt;MouseMove&lt;/code&gt; -&amp;gt; &lt;code&gt;MouseUp&lt;/code&gt;). For the selection itself, we also
need to figure out which units inside the rectangle are selectable by the player, so we don't end
up with a bunch of trees in our selection queue. Last but not least, the rectangle also has to be drawn
on screen, so the player can see what they are actually going to select.&lt;/p&gt;
&lt;p&gt;In our old engine architecture, the implementation of this feature was a hot garbled mess that massively
tanked performance (also visible in our &lt;a href="https://www.youtube.com/watch?v=4GujF6YGSBY&amp;amp;t=28s"&gt;YouTube demo&lt;/a&gt;),
partly because it was basically taking control of the renderer which stalled all other draw commands.
This is where our new engine architecture with decoupled subsystems finally pays off big time. In comparison to
the previous implementation, the new drag selection is communicated via sane interfaces from the input system
to the other subsystems of the engine.&lt;/p&gt;
&lt;p&gt;Here is how the input events are handled now:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;MouseDown&lt;/code&gt;: The input system detects the drag selection sequence initialization and switches into a drag selection context&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MouseMove&lt;/code&gt;: Inputs are forwarded to two different places&lt;ol&gt;
&lt;li&gt;A HUD controller that tells the renderer to draw/resize the rectangle on screen&lt;/li&gt;
&lt;li&gt;A game controller for the player that keeps track of the rectangle position and size&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MouseUp&lt;/code&gt;: The input system finalizes the selection&lt;ol&gt;
&lt;li&gt;The HUD controller tells the renderer to delete the drawn rectangle&lt;/li&gt;
&lt;li&gt;The game controller sends the final rectangle position size as a drag select event to the game simulation&lt;/li&gt;
&lt;li&gt;The game simulation handles the drag select event by&lt;ol&gt;
&lt;li&gt;Checking which units are inside the rectangle&lt;/li&gt;
&lt;li&gt;Checking which units are selectable by the player&lt;/li&gt;
&lt;li&gt;Finally, sending the list of unit IDs back to the controller&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Configurable Activities&lt;/h2&gt;
&lt;p&gt;Way back in &lt;a href="https://blog.openage.dev/openage-development-news-june-2023.html"&gt;June&lt;/a&gt;, we added configurable game entity behaviour in the
form of the &lt;em&gt;activity system&lt;/em&gt; into the engine. However, for the last months the "configurable" part only
existed in theory, since all game entities were assigned a hardcoded activity by default. This month. we
have been making efforts to add support for activities both to our nyan data API and the openage converter.
This will eventually allow us to define the whole behaviour in the modpack itself, which in turn
also allows modders to change game entity behaviour with a simple data mod.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Activity graph" src="https://blog.openage.dev/images/news/2023-06/activity_graph.svg"&gt;&lt;/p&gt;
&lt;p&gt;Currently, the nyan API changes look like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt="nyan API changes" src="https://blog.openage.dev/images/news/2023-11/activity_nyan_api.svg"&gt;&lt;/p&gt;
&lt;p&gt;Since activities are simple directed node graphs, we can model all node types as nyan objects which
point to successor nodes via the &lt;code&gt;next&lt;/code&gt; member. Internal events are handled the same
way, using nyan objects that have members for the event payload. When the modpack is loaded, the engine
builds the activity graph from using the node definitions.&lt;/p&gt;
&lt;p&gt;Activities are assigned to game entities with a new ability (also called &lt;code&gt;Activity&lt;/code&gt;) which
references the node graph. This means that every game entity can potentially have its own
unique behaviour (which can also be changed at runtime).&lt;/p&gt;
&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;During next month, we will put more work into the configurable activities and release a new data API
specification when we are done. If there is enough time, we will also improve the HUD a bit to
display more useful information for players on screen.&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="nyan"></category><category term="renderer"></category><category term="input"></category></entry><entry><title>Openage Development News: October 2023</title><link href="https://blog.openage.dev/openage-development-news-october-2023.html" rel="alternate"></link><published>2023-11-09T00:00:00+01:00</published><updated>2023-11-09T00:00:00+01:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2023-11-09:/openage-development-news-october-2023.html</id><summary type="html">&lt;p&gt;Devlog from October 2023&lt;/p&gt;</summary><content type="html">&lt;p&gt;Hello everyone and welcome to another update to the openage project. October has been a rather slow month,
with us mostly focusing on getting the code base cleaned up. As part of the cleanup, we also ported a few
rendering features of the old engine core to the new renderer. But more on that further below.&lt;/p&gt;
&lt;h2&gt;Legacy Code Cleanup&lt;/h2&gt;
&lt;p&gt;Our legacy code cleanup continues with the refactoring of the old GUI interface which is now completely
decoupled from the game simulation. The old GUI directly interfaced with gameplay features, which was
not necessarily bad but kind of slow. In comparison to this, the new GUI will not communicate
with the game simulation directly, but rather send input signals through our regular input system that
is also used for keyboard and mouse inputs. Communicating in the other direction (simulation to GUI) will
be a little bit more complicated but that is a story for a future News update.&lt;/p&gt;
&lt;p&gt;We've additionally removed the last remnants of SDL related code. As a result, SDL2 will be removed as a dependency
in the next release as all window system functionality is now handled by Qt. Furthermore, we have also
resolved a few nasty crashing issues and memory leaks in the renderer and fixed display bugs when
using the Wayland compositor.&lt;/p&gt;
&lt;h2&gt;Terrain Chunks&lt;/h2&gt;
&lt;p&gt;openage can now properly handle terrain assets from modpacks and display them ingame. Our previous
terrain implementation used a hardcoded test texture - which you should be familiar with from all the
screenshots we've published. Not only can the renderer use "real" terrain assets now, it can also display more
than one of them at once! As a result, openage looks almost like a real game:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Terrain rendering" src="https://blog.openage.dev/images/news/2023-10/openage_terrain_chunks.png"&gt;&lt;/p&gt;
&lt;p&gt;Internally, both the terrain data in the game simulation and the terrain render objects are now
organized in &lt;em&gt;chunks&lt;/em&gt;. Chunks are collections of 16x16 tiles that can be updated individually.
This allows us to utilize better runtime optimization, since we don't have to update the whole terrain
grid at once if there is a change.&lt;/p&gt;
&lt;p&gt;The current implementation is nowhere near feature complete yet. For example, there's no blending
and only one texture can be displayed per chunk. Gameplay-wise, terrain has also no effect as
pathfinding and collision are not implemented right now.&lt;/p&gt;
&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;Code cleanup will probably be finalized in November and published as a new release. Afterwards, we
will start adding proper unit selection to the engine and find a way to display the selected units
on the screen.&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="renderer"></category></entry><entry><title>Openage Development News: September 2023</title><link href="https://blog.openage.dev/openage-development-news-september-2023.html" rel="alternate"></link><published>2023-10-07T00:00:00+02:00</published><updated>2023-10-07T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2023-10-07:/openage-development-news-september-2023.html</id><summary type="html">&lt;p&gt;Devlog from September 2023&lt;/p&gt;</summary><content type="html">&lt;p&gt;Hello and welcome to our monthly openage recap. This month involved a significant amount of work reviewing, fixing
pre-release code, and then preparing the publishing of said release. Even if there's currently not much
going on feature-wise, there's a lot happening in the development process.&lt;/p&gt;
&lt;h2&gt;Version 0.5.0 Release&lt;/h2&gt;
&lt;p&gt;As some of you may have noticed, openage 0.5.0 has been released on &lt;a href="https://github.com/SFTtech/openage/releases/tag/v0.5.0"&gt;GitHub&lt;/a&gt;.
It's the first major release in a while and we are very proud of what we pulled off. 0.5.0 introduces the new architecture
and is something that we can easily improve and build on. Avid readers of the News posts should already know what's in the release,
so we'll spare you the details. For everyone else, take a look at the release highlights.&lt;/p&gt;
&lt;p&gt;Let's just hope the next release won't take as long ;) &lt;em&gt;ahem&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;What's coming for 0.6.0?&lt;/h2&gt;
&lt;p&gt;We are not totally sure yet where to start with 0.6.0 and what exactly will be part of the next release. Right now, the
consensus is that we try to improve on 0.5.0 and add more features that directly support gameplay, e.g.:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HUD rendering (or parts of it)&lt;/li&gt;
&lt;li&gt;Proper unit selection&lt;/li&gt;
&lt;li&gt;Collision &amp;amp; Pathfinding&lt;/li&gt;
&lt;li&gt;Configurable inputs&lt;/li&gt;
&lt;li&gt;Audio Support&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While implementing these, new gameplay features will probably be added in parallel depending on what we think is doable.&lt;/p&gt;
&lt;p&gt;Before we start thinking about new features though, we also have some project maintainance work to take care of.
On our GitHub, we've already introduced new &lt;a href="https://github.com/SFTtech/openage/projects?query=is%3Aopen"&gt;project boards&lt;/a&gt;
to track the development progress. We're additionally planning to add a bunch of new beginner issues for new contributors,
which also have their own &lt;a href="https://github.com/orgs/SFTtech/projects/15"&gt;board&lt;/a&gt;. Furthermore, the should be a bugfix release
coming soon that addresses a few compilation errors and engine startup problems.&lt;/p&gt;
&lt;h2&gt;Legacy Code Cleanup&lt;/h2&gt;
&lt;p&gt;While 0.5.0 in practice only uses the new architecture flow, most pre-0.5.0 legacy code has so far remained in the code base.
We couldn't remove it previously because there were a giant amount of interdependencies in the legacy subsystems and removing
them while also working on other parts of the engine would have been a nightmare. Now that 0.5.0 is out and running without
relying on the old legacy subsystems, we can clean up what's left.&lt;/p&gt;
&lt;p&gt;Since release 0.5.0, we have started the process of removing the legacy code subsystem by subsystem (see &lt;a href="https://github.com/SFTtech/openage/pull/1550"&gt;PR#1556&lt;/a&gt;).
Currently, it looks like about ~40,000 lines will eventually be removed (compared to ~65,000 lines added for
the new architecture). We have also identified some parts that are still salvagable and can be transferred to the
new architecture such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Audio Manager (has to be ported from SDL to Qt)&lt;/li&gt;
&lt;li&gt;Parts of the GUI (only needs new engine interface)&lt;/li&gt;
&lt;li&gt;Some Game Logic (terrain generation, score calculation)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;We will focus on cleanup tasks publishing fixes for the current release first. After that is done, we will pick a new feature
to work on, probably something "simple" like unit selection. As always, you will learn about it next month at the latest!&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="release"></category></entry><entry><title>Openage Development News: August 2023</title><link href="https://blog.openage.dev/openage-development-news-august-2023.html" rel="alternate"></link><published>2023-09-04T00:00:00+02:00</published><updated>2023-09-04T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2023-09-04:/openage-development-news-august-2023.html</id><summary type="html">&lt;p&gt;Devlog from August 2023&lt;/p&gt;</summary><content type="html">&lt;p&gt;Welcome to our monthly openage update. As we wrap up for release &lt;code&gt;v0.5.0&lt;/code&gt;, we can talk about a few quality-of-life
and speed improvements that happened over the last weeks.&lt;/p&gt;
&lt;h2&gt;Tales of Renderer Troubles&lt;/h2&gt;
&lt;p&gt;In last month's update, we announced the implementation of a stresstest for the renderer. This has now
been added in form of a simple render demo that incrementally adds renderable objects to the render
loop and logs the current FPS. It's very bare bones, but it gets the job done:&lt;/p&gt;
&lt;video width="640" height="480" controls&gt;
  &lt;source src="./images/news/2023-08/openage_stresstest.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;p&gt;However, while playing around with the first few stresstest runs, we noticed that the renderer performance
was extremely bad (not to say abysmal). It barely managed handling 400 objects with 30 FPS and there were
massive slowdowns after only 100 rendered objects. Keep in mind that the &lt;em&gt;objects&lt;/em&gt; in question are not just
units. They are everything that needs to be displayed in the game world: buildings, trees, birds,
cacti... If 400 objects were the limit, we would run out of frames pretty quickly in a real game.&lt;/p&gt;
&lt;p&gt;So we set out to investigate and fix the bottleneck. It turns out that there was a call to the Python API
in the objects' frame update. Every frame the renderer would check its asset cache to see if the texture
required for a render object was already loaded from disk. The cache lookup would resolve the texture path,
initiating a Python call and introducing a massive overhead. We have since removed the calls to Python and
the stresstest now easily manages &amp;gt;3500 objects at 30 FPS - almost 9x as much as before.&lt;/p&gt;
&lt;h2&gt;New Startup Flow&lt;/h2&gt;
&lt;p&gt;In the new release, we want to make the initial startup more user-friendly, so that it's easier to
get the engine running. Well, maybe you should imagine large quotation marks around "user-friendly"
because the engine is very much not ready to be used by the general public. However, we wanted to make
sure that at least the people who get as far as successfully compiling everything are not greated with crashes.&lt;/p&gt;
&lt;p&gt;To accomplish this, there is a new CLI startup flow that guide users through the initial setup phase
and the conversion process. Common installation folders for games can be automatically searched,
so that it should be easier to create usable modpacks no matter which AoE game or release you have.
Even if no installation is available, the converter is now able to download the
&lt;a href="https://archive.org/details/AgeOfEmpiresIiTheConquerorsDemo"&gt;AoC Trial Version&lt;/a&gt;
as a fallback. We also made sure that the engine works with all game releases.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Units from all games" src="https://blog.openage.dev/images/news/2023-08/openage_modpack_units.png"&gt;&lt;/p&gt;
&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;After release &lt;code&gt;v0.5.0&lt;/code&gt; is done, we will do a brief planning session to set the milestones for the next
months. It's possible that we will prioritize removing legacy code in the next minor release
and take a step back from adding new features until that's done.&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="renderer"></category><category term="converter"></category><category term="release"></category></entry><entry><title>Openage Development News: July 2023</title><link href="https://blog.openage.dev/openage-development-news-july-2023.html" rel="alternate"></link><published>2023-08-06T00:00:00+02:00</published><updated>2023-08-06T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2023-08-06:/openage-development-news-july-2023.html</id><summary type="html">&lt;p&gt;Devlog from July 2023&lt;/p&gt;</summary><content type="html">&lt;p&gt;Welcome to another monthly update for openage. This month's progress does not involve a lot of code changes
as we are preparing for the next release. Nevertheless there is a bunch of new stuff that's not code that we can
tell you about.&lt;/p&gt;
&lt;h2&gt;Architecture Documentation&lt;/h2&gt;
&lt;p&gt;A lot of work has gone into cleaning up the architecture documentation to include all new/rewritten engine subsystems.
If you have followed our monthly News posts in the last months, you have basically already seen an abridged version
of the contents. The documentation just adds &lt;em&gt;a lot&lt;/em&gt; more technical details and fancy diagrams. Overall, the &lt;a href="https://github.com/SFTtech/openage/pull/1525"&gt;documentation PR&lt;/a&gt;
probably contain about 20 pages of new text.&lt;/p&gt;
&lt;p&gt;In summary, there are completely new docs for the following subsystems:
- Event System
- Game simulation and all its sub-components:
    - Components
    - Systems
    - Event-based game logic
- Time management
- Curves&lt;/p&gt;
&lt;p&gt;We also removed a bunch of old stuff for code that is now removed or deprecated and updated outdated information.
The only thing remaining to be reworked is our &lt;a href="https://openage.dev"&gt;website&lt;/a&gt;, although this shouldn't take much effort.&lt;/p&gt;
&lt;h2&gt;Next Release Plan&lt;/h2&gt;
&lt;p&gt;We are currently preparing for a new release &lt;code&gt;v0.5.0&lt;/code&gt; that will happen soon-ish, maybe even in August. This release
will still not really be a "usable" release for casual users. However, it is an important milestone since it will
be the first release where all new engine subsystems work together and the basic architecture outline is clear.
In theory, this should also make outside contributions easier but we will have to see about that. There is
a lot of legacy code that has to remain part of &lt;code&gt;v0.5.0&lt;/code&gt;, so jumping into the code might not be that pleasent yet.
We will use subsequent &lt;code&gt;v0.5.X&lt;/code&gt; releases to refactor and clean up the legacy parts of the codebase.&lt;/p&gt;
&lt;p&gt;Release &lt;code&gt;v0.5.0&lt;/code&gt; will add a few more interactable demos that show off what the engine is capable of. Basically,
this will be similar to the things you've seen in previous news posts but a bit larger in scope. It should work as a minimal
example on how to use the engine for someone that wants to contribute. There will also be a stresstest demo
that checks overall engine performance and could help us to locate bottlenecks in the code.&lt;/p&gt;
&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;Preparartion for the next release will be our major focus. Apart from merging the docs and implementing the demos
mentioned above, there also are a few minor bugs and annoyances left to fix.&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="docs"></category><category term="release"></category></entry><entry><title>Openage Development News: June 2023</title><link href="https://blog.openage.dev/openage-development-news-june-2023.html" rel="alternate"></link><published>2023-07-03T00:00:00+02:00</published><updated>2023-07-03T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2023-07-03:/openage-development-news-june-2023.html</id><summary type="html">&lt;p&gt;Devlog from June 2023&lt;/p&gt;</summary><content type="html">&lt;p&gt;Welcome to another monthly openage update. This month there's been a lot of progress inside the gamestate, so
there is much to show and even more to discuss.&lt;/p&gt;
&lt;h2&gt;Modpack Loading - Part 2&lt;/h2&gt;
&lt;p&gt;Since our previous update, modpack loading and game data handling inside the engine's gamestate have been greatly
extended. The biggest advancement in this regard is that the engine can now create actual units - or &lt;em&gt;game entities&lt;/em&gt;
as we call them - from the information in the &lt;code&gt;nyan&lt;/code&gt; database. Additionally, the available game data from the modpacks
can now be used in the game simulation routines. Right now, game entities can do very little and therefore still use
a very limited amount of the data, but it's a step forward from having hardcoded test entities.&lt;/p&gt;
&lt;p&gt;Here you can see how different entities from the AoE1, AoE2 and SWGB modpacks are created and displayed from modpack
data:&lt;/p&gt;
&lt;video width="640" height="498" controls&gt;
  &lt;source src="./images/news/2023-06/spawn_entity.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;p&gt;Note that this example contains both buildings and units as game entities. Internally, openage doesn't differentiate
between different unit types and instead uses composition to define what each game entity can do. This means that when
a game entity is spawned, the engine essentially "assembles" its capabilities by assigning properties and abilities
(e.g. &lt;code&gt;Move&lt;/code&gt;, &lt;code&gt;Turn&lt;/code&gt;, &lt;code&gt;Idle&lt;/code&gt;, &lt;code&gt;Live&lt;/code&gt;, etc.) based on what is defined for the game entity in the modpack.&lt;/p&gt;
&lt;h2&gt;Rudimentary Game Logic&lt;/h2&gt;
&lt;p&gt;Now that we can get game entities into the game world, we can start playing around with them. Currently, there are
only two things a game entity can do: Idle or Move. This doesn't sound like much, but more stuff will soon be added
to the gamestate one by one. Most of this months work went into the architecture to support more complex action
states of game entities.&lt;/p&gt;
&lt;p&gt;In openage, the action state of a unit is not directly driven by commands from the input system but by a node-based
flow graph with task nodes, branching paths, and wait states for events. Commands mainly signal where to go next
in the graph. We do things this way because commands in RTS usually do not trigger one specific action but start
entire action chains. For example, a &lt;code&gt;Gather&lt;/code&gt; command in AoE2 does not just involve the process of slurping up
resources; it also requires moving to the resource, automatically finding a dropoff place and actually depositing
the resources in the player's storage.&lt;/p&gt;
&lt;p&gt;Below you can see an example of what such a flow graph looks like. The example flow graph is currently hardcoded in
the engine and assigned to every game entity. In the future, we want these flow graphs to be configurable per
game entity (or game entity type), so that every unit could display different behaviour.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Activity flow graph" src="https://blog.openage.dev/images/news/2023-06/activity_graph.svg"&gt;&lt;/p&gt;
&lt;p&gt;Operating on the flow graph in the engine then looks like this:&lt;/p&gt;
&lt;video width="640" height="498" controls&gt;
  &lt;source src="./images/news/2023-06/activity_move.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;The flow graph logic in the gamestate was the last major component missing in the new engine architecture. Since
that is almost done, we will probably prepare a new release soon containing all the changes made over the last months.
Before that, we have to clean up all the rough edges in the code and make the features more "presentable" to
those who haven't followed the update posts.&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="mods"></category><category term="gamestate"></category></entry><entry><title>Openage Development News: May 2023</title><link href="https://blog.openage.dev/openage-development-news-may-2023.html" rel="alternate"></link><published>2023-06-01T00:00:00+02:00</published><updated>2023-06-01T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2023-06-01:/openage-development-news-may-2023.html</id><summary type="html">&lt;p&gt;Devlog from May 2023&lt;/p&gt;</summary><content type="html">&lt;p&gt;Welcome to another monthly update to the openage development. This month's progress consisted
of a lot of cleanup and bug fixing tasks but there were also a variety of small features
added to the engine. So without further ado, let's jump right in.&lt;/p&gt;
&lt;h3&gt;Modpack Loading&lt;/h3&gt;
&lt;p&gt;While the openage converter could already generate modpacks from the original game assets for
a long time, the engine couldn't really understand them yet (except for loading/showing
single animations for testing). This has been changed now with the addition of a simple
internal mod manager as well as loaders for getting game data into the gamestate's &lt;a href="https://github.com/SFTtech/nyan"&gt;nyan&lt;/a&gt;
database. At this point, the gamestate still doesn't have any logic that can do something
meaningful with the data. However, it gets us one step closer to testing features with "real"
data instead of the more generic tests and demos that we've shown before. This also means
that you might see more AoE2 or SWGB visuals in future news posts!&lt;/p&gt;
&lt;p&gt;The engine's configuration is now also loaded as a modpack which is simply called &lt;code&gt;engine&lt;/code&gt;.
Currently, it contains the bindings for the openage data/modding API referenced by other modpacks.
Later, it will probably include other bindings for scripting and GUI. &lt;code&gt;engine&lt;/code&gt;
is always implicitely available to other modpacks and can be used to interface with the
engine API. Storing the engine confguration as a modpack could also allow basic modding of
the low-level engine internals, although we'll have to see how well that works in the future.&lt;/p&gt;
&lt;h3&gt;Renderer Features&lt;/h3&gt;
&lt;p&gt;Our renderer can now properly handle drawing directions (or angles, respectively) of unit
sprites. Depending on the direction a unit is facing in the scene, the renderer will now
select the correct subtexture coordinates from the animation's sprite sheet and pass it
the the shaders. You can see here how the result looks for one of our test assets
(taken from &lt;a href="https://jimhatama.itch.io/german-ww2-pixel-tanks"&gt;here&lt;/a&gt; under CC-BY 4.0):&lt;/p&gt;
&lt;video width="400" height="318" controls&gt;
  &lt;source src="./images/news/2023-05/openage_angles.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;p&gt;Of course, it also works for animations from AoE2:&lt;/p&gt;
&lt;video width="400" height="318" controls&gt;
  &lt;source src="./images/news/2023-05/openage_angles_aoe2.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;p&gt;What's probably less noticeable in the videos is that the renderer is additionally able to
handled &lt;em&gt;mirroring&lt;/em&gt; of sprites, i.e. flipping sprites alongside their X or Y axis. The
feature is implemented directly in the display shader and using it should therefore produce
very little overhead.&lt;/p&gt;
&lt;p&gt;Mirroring is commonly used to save space since the sprite sheet only has to contain
sprites for half the available directions. The sprites for the remaining directions
can then be inferred from the vertically opposite direction. For example, assets in
the original AoE2 release only contained sprites for 5 out of 8 directions. and mirrored
the remaining 3.&lt;/p&gt;
&lt;h3&gt;What's next?&lt;/h3&gt;
&lt;p&gt;Since the engine now supports modpack loading, we can start working on the gamestate
internals using actual game data from the converted assets. The first step will
be to initialize the various abilities of a game entity in the engine with
information from the nyan database. We will probably start with very simple
abilities like &lt;code&gt;Idle&lt;/code&gt;, &lt;code&gt;Position&lt;/code&gt;, &lt;code&gt;Live&lt;/code&gt;, and maybe &lt;code&gt;Move&lt;/code&gt; and work our way to
the more complex abilities later.&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="mods"></category><category term="renderer"></category></entry><entry><title>Openage Development News: April 2023</title><link href="https://blog.openage.dev/openage-development-news-april-2023.html" rel="alternate"></link><published>2023-05-02T00:00:00+02:00</published><updated>2023-05-02T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2023-05-02:/openage-development-news-april-2023.html</id><summary type="html">&lt;p&gt;Devlog from April 2023&lt;/p&gt;</summary><content type="html">&lt;p&gt;Welcome to the April 2023 update for openage&lt;/p&gt;
&lt;p&gt;This month we had progress in several subsystems of the engine, most of which we built in the previous
months: the event system, the renderer, and the gamestate. These systems already worked together,
but previously consisted more of hardcoded "duct tape" code to make it all work. In the past weeks,
we replaced many of these code paths with something that is closer to the final architecture
targeted by the engine.&lt;/p&gt;
&lt;h3&gt;Spawning Entities Reloaded&lt;/h3&gt;
&lt;p&gt;We already showed off a spawn event last month which created a &lt;em&gt;Gaben&lt;/em&gt; entity on mouse click.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Gaben Spawns" src="https://blog.openage.dev/images/news/2023-03/gaben_entity.png"&gt;&lt;/p&gt;
&lt;p&gt;Previously, this just placed &lt;em&gt;Gaben&lt;/em&gt; at a hardcoded position at the origin point of the 3D scene &lt;code&gt;(0,0,0)&lt;/code&gt;.
With the new changes from this month, &lt;em&gt;Gaben&lt;/em&gt; is able to spawn where the player clicks on the screen.&lt;/p&gt;
&lt;video width="400" height="318" controls&gt;
  &lt;source src="./images/news/2023-04/openage_raycasting.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;p&gt;To achive this mouse spawning feature, we rewrote parts of the engine's old &lt;strong&gt;coordinate system&lt;/strong&gt; and
added a &lt;strong&gt;raycasting&lt;/strong&gt; algorithm that can point at objects in the 3D scene.&lt;/p&gt;
&lt;p&gt;The coordinate system is necessary to convert between the different coordinate types used by the
engine's subsystems. For example, the input system mainly receives 2D pixel coordinates from
the window management that represent the position of the mouse inside the window. The game world
on the other hand uses 3D coordinates for positions of objects in the game world. A different kind of
3D coordinates are also used in the renderer to draw animations and terrain.&lt;/p&gt;
&lt;p&gt;To place &lt;em&gt;Gaben&lt;/em&gt; at the correct position inside the 3D game world, we have to convert the 2D pixel coordinates
from the input system to a 3D coordinate in the scene. We achieve this with
a very straightforward technique called "raycasting". Basically, we cast a ray from the position of the
camera using its direction vector as the direction of the ray. Then, we check for a point where this
ray intersects with an object in the 3D scene, e.g. the terrain mesh. The resulting intersection point
is placement position we are looking for (as 3D scene coordinates). Since the 3D scene coordinates
use a different axis orientation than 3D game world coordinates, we have to make one final conversion
to get the correct values for the gamestate.&lt;/p&gt;
&lt;h3&gt;Moving Entities&lt;/h3&gt;
&lt;p&gt;Spawning entities at the mouse position is pretty cool by itself, but we are not done yet. With
the power of the coordinate system, we can also make objects move!&lt;/p&gt;
&lt;p&gt;To effectively explain how objects in the gamestate move, you have to understand &lt;strong&gt;curves&lt;/strong&gt; - the
data containers that openage uses to store its runtime data. They are described in more detail in
an &lt;a href="https://blog.openage.dev/t1-curves-logic.html"&gt;older blogpost&lt;/a&gt;, but here's the gist of it: Instead of calculating the current position of
an object every frame (like many other engines do), curves store only changes to the position
as &lt;em&gt;keyframes&lt;/em&gt;, containing the new position and a timestamp. Basically, the keyframes represent
waypoints of the objects where each waypoint also is assigned a timestamp that signifies when
the object reached the waypoint. To get the position at a specific point in time &lt;code&gt;t&lt;/code&gt;, the curve
interpolate between the two keyframes before and after &lt;code&gt;t&lt;/code&gt;. In case of positions, this means
that it calculates the position between the two waypoints defined by keyframes.&lt;/p&gt;
&lt;p&gt;Curves may sound complicated and internally they definitely are. However, they also make internal
gamestate calculations and testing much easier because we can just insert a bunch of keyframes
and let the curve figure out what the position at the current simulation time is (curves also
allow us to easily go backwards in time, but that is a story for another month). In the current
implementation, we add 4 additional waypoints to every spawned entity so that they follow a
"square" path after creation.&lt;/p&gt;
&lt;video width="400" height="318" controls&gt;
  &lt;source src="./images/news/2023-04/openage_curve_magic.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;h3&gt;What's next?&lt;/h3&gt;
&lt;p&gt;Spawning and moving entities is nice, but there is obviously more to do to make this feel more like an actual game.
There are actually several options for what to do next. Adding more input events that do other stuff than spawning
would be nice, e.g. movement or selection. On the other hand, we can also improve the internal gamestate by adding
more event types that affect the simulation itself. Or maybe we do both, depending on how well each of them
goes.&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="input"></category><category term="renderer"></category><category term="events"></category></entry><entry><title>Openage Development News: March 2023</title><link href="https://blog.openage.dev/openage-development-news-march-2023.html" rel="alternate"></link><published>2023-04-02T00:00:00+02:00</published><updated>2023-04-02T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2023-04-02:/openage-development-news-march-2023.html</id><summary type="html">&lt;p&gt;Devlog from March 2023&lt;/p&gt;</summary><content type="html">&lt;p&gt;Hello and welcome to the March 2023 update for openage.&lt;/p&gt;
&lt;p&gt;As promised last time, this months update is mostly about inputs, managing those inputs and a tiny bit of event handling.
It also contains small amounts of Gaben, so wait for the end of this post if you are into that. But first let us tell you
something about the challenges of processing inputs.&lt;/p&gt;
&lt;h3&gt;Inputs in RTS&lt;/h3&gt;
&lt;p&gt;The problem with RTS is that they can allow a wide range of different mechanics and actions that have to be mapped to inputs.
To complicate matters further, you usually don't control just one entity but many, which can also have their own actions
available depending on ownership, state and various usage contexts. Furthermore, shortcut keys may be assigned multiple
times in different contexts, so a naive mapping of key to action doesn't really work.&lt;/p&gt;
&lt;p&gt;For openage, we have to take all this into account and additionally ensure that everything is as configurable as
possible. Otherwise, support for multiple games will soon become very tricky.&lt;/p&gt;
&lt;h3&gt;openage's new input management&lt;/h3&gt;
&lt;p&gt;The solution implemented this month is to divide input processing into two stages: A low-level input system that
handles/preprocesses raw inputs from the Qt window system and several high-level input handlers that translate
the results into the actual (gameplay) actions or events.&lt;/p&gt;
&lt;p&gt;Here is an overview for how that works internally:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Workflow Input System" src="https://blog.openage.dev/images/news/2023-03/workflow_input_controller.png"&gt;&lt;/p&gt;
&lt;p&gt;Raw inputs from Qt (keyboard or mouse events) are first forwarded to the low-level input system (&lt;code&gt;InputManager&lt;/code&gt;)
via the window management. There, we do a little bit of preprocessing like stripping unnecessary information
from the raw inputs. Context management, i.e. figuring out the currently active key binding, is also handled at
this stage. If the input can be associated with an active key binding, it is sent to a high-level input system
that performs an action with the input.&lt;/p&gt;
&lt;p&gt;The high-level input systems are basically &lt;em&gt;gateways&lt;/em&gt; to other components inside the engine, e.g. the gamestate
or the renderer (&lt;code&gt;Controller&lt;/code&gt;). Therefore, these are the places where the actual actions that have an effect on the game or
visual output are performed. In the case of the engine controller - the gateway to the gamestate - the actions
are functions that create an event for the gamestate. Which action is performed is decided by a simple lookup
using the input event. The available actions will most likely be hardcoded until we introduce more scripting,
but the current system allows them to be mapped to any key combination or mouse button.&lt;/p&gt;
&lt;p&gt;With this feature done (or rather awaiting merging in &lt;a href="https://github.com/SFTtech/openage/pull/1501"&gt;PR #1501&lt;/a&gt;),
the engine is now able to spawn a game entity with the gaben graphic on mouse click:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Gaben entity" src="https://blog.openage.dev/images/news/2023-03/gaben_entity.png"&gt;&lt;/p&gt;
&lt;h3&gt;What's next?&lt;/h3&gt;
&lt;p&gt;Focus will now shift to implementing a few more input actions for creating gamestate events and implementing
the gamestate internals along the way. The internal gamestate implementation for processing these events still
needs a lot of work too, so we will probably try to implement one or two events at a time and see what else
needs to be done along the way.&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="input"></category><category term="events"></category></entry><entry><title>Openage Development News: February 2023</title><link href="https://blog.openage.dev/openage-development-news-february-2023.html" rel="alternate"></link><published>2023-03-01T00:00:00+01:00</published><updated>2023-03-01T00:00:00+01:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2023-03-01:/openage-development-news-february-2023.html</id><summary type="html">&lt;p&gt;Devlog from February 2023&lt;/p&gt;</summary><content type="html">&lt;p&gt;February is gone, but we're here with another update on openage and what happened over the month.&lt;/p&gt;
&lt;p&gt;Our initial February implementation goal from last month was getting the simulation running &lt;em&gt;with player input&lt;/em&gt;. However, that input part turned out to be more complicated than at first glance, so it will take a little longer before there is anything interesting to talk about. However, there are other things about the general simulation framework and the renderer that made some progress, so you get news about that instead.&lt;/p&gt;
&lt;h2&gt;Simulation Time Shenanigans&lt;/h2&gt;
&lt;p&gt;The most precious resource of our internal simulation is &lt;strong&gt;time&lt;/strong&gt; (as in actual time points provided by a clock). This has to do with how our engine calculates the current gamestate. In openage, the gamestate is event-based which means updates to anything (unit, building, or cactus) are scheduled for a specific time and then executed when the simulation time has advanced enough. Therefore, it is very important that the internal clock works correctly, since we would get all kinds of simulation deadlocks or desyncs otherwise.&lt;/p&gt;
&lt;p&gt;Which leads us to a funny little "problem" with the clock that was merged in &lt;a href="https://github.com/SFTtech/openage/pull/1492"&gt;PR #1492&lt;/a&gt; last month. Advancing the time consists of a simple diff between the current system time and the time of the last update, multiplying this value by the current simulation speed, and then adding the result to the cumulated simulation time. Additionally, this clock has no regular update intervals; it only advances time as a side effect of getting the current time. And all that works reasonably well... until the program is involuntarily stopped by a debugger or the OS going into sleep mode or your browser in the background eating too much RAM. You might have guessed it already but the problem is that the time diff between system time and last update grows larger and larger, even if the program is frozen by the OS. Technically, the simulation never stops in this case. When you close your laptop lid on a running game, you would probably be surprised that the AI won the game while you were away for 2 hours.&lt;/p&gt;
&lt;p&gt;But openage development isn't about AIs taking over when you don't expect them to. So in the implementation, the clock has a dedicated update method, caps time advancements at a very small time value, runs in its own thread, and (hopefully) doesn't cause trouble anymore.&lt;/p&gt;
&lt;h2&gt;Rendering with the Clock&lt;/h2&gt;
&lt;p&gt;Other than the internal event-based simulation, the clock is also used in the renderer to time animation frames. Most of the functionality for that was completed in a &lt;a href="https://github.com/SFTtech/openage/pull/1497"&gt;PR this month&lt;/a&gt; which also added a bunch of other rendering features (mostly asset management). Playing animations based on the current simulation time also got its own demo which you can see here:&lt;/p&gt;
&lt;video width="480" height="359" controls&gt;
  &lt;source src="./images/news/2023-02/clock_animation.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;p&gt;(Run with these commands:)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;./bin/run test --demo renderer.tests.renderer_demo 4
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The video of the demo also shows how animations can speed up, slow down and even reverse based on the simulation speed. Reversing time is something much more relevant for the gamestate than the renderer, but it's cool to show off here.&lt;/p&gt;
&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;It will be input events for the gamestate, but this time for real. There are no major features that need implementing anymore which don't involve the gamestate. Simulation, rendering and the event loop are all set up and working. For input events, we still need to rewrite the control flow of the old input handlers so that they produce events for the gamestate. Once that is finished, we can start creatng game objects that receive and act on these events.&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="simulation"></category><category term="renderer"></category></entry><entry><title>Openage Development News: January 2023</title><link href="https://blog.openage.dev/openage-development-news-january-2023.html" rel="alternate"></link><published>2023-02-04T00:00:00+01:00</published><updated>2023-02-04T00:00:00+01:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2023-02-04:/openage-development-news-january-2023.html</id><summary type="html">&lt;p&gt;Devlog from January 2023&lt;/p&gt;</summary><content type="html">&lt;p&gt;We're back with updates from December &amp;amp; January. Despite holiday stuff and being plagued by illnesses, we've made some progress on the codebase.&lt;/p&gt;
&lt;h2&gt;Camera&lt;/h2&gt;
&lt;p&gt;The renderer now supports a camera that acts as players' view into the rendered scene. It's pretty basic at the moment, but already supports moving around as well as zooming in and out of the scene. There's also functionality to &lt;em&gt;look at&lt;/em&gt; a position by centering the camera view on a scene coordinate. The latter should become more useful when there is actual gameplay to center on.&lt;/p&gt;
&lt;video width="480" height="359" controls&gt;
  &lt;source src="./images/news/2023-01/camera_movement.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;p&gt;Since openage implements a mixture of 2D (units/buildings) and 3D (terrain) for rendering, the camera can technically be used to display arbritrary 3D objects, i.e. calculate the necessary view and (isometric) projection matrices for 3D rendering. This is probably not interesting for classic Age of Empires gameplay, but we could use it for debug purposes in the future, e.g. to show collision boxes.&lt;/p&gt;
&lt;h2&gt;Merging Progress &amp;amp; Technical Demos&lt;/h2&gt;
&lt;p&gt;The current state of the renderer has matured enough that we can merge it into the main codebase now (see &lt;a href="https://github.com/SFTtech/openage/pull/1492"&gt;PR Link&lt;/a&gt;). There's still some things to do, but the structure of the renderer will likely stay the same for now. With the renderer "finished", this means we can focus on the gamestate part of the engine next.&lt;/p&gt;
&lt;p&gt;The code in the PR contains a few technical demos that show off the new renderer features and their usage. You can try them yourself, if you want, by building the project and running&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;./bin/run test --demo renderer.tests.renderer_demo X
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;in the project folder and replacing &lt;code&gt;X&lt;/code&gt; with a number between 0 and 3. For example, demo 3 allows controlling the camera in a basic test scene. That's also where the camera video comes from.&lt;/p&gt;
&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;Well, how about some gameplay? This is obviously the next step, although it could take us a while to get something playable running. The crucial step will be the implementation of the internal event simulation, e.g. getting input events and converting them into commands for the gamestate. We also need a way to time events with a simulation clock (which is already implemented in the &lt;a href="https://github.com/SFTtech/openage/pull/1492"&gt;renderer PR&lt;/a&gt;) and save them to an event log.&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="renderer"></category><category term="demo"></category></entry><entry><title>Openage Development News: November 2022</title><link href="https://blog.openage.dev/openage-development-news-november-2022.html" rel="alternate"></link><published>2022-12-02T00:00:00+01:00</published><updated>2022-12-02T00:00:00+01:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2022-12-02:/openage-development-news-november-2022.html</id><summary type="html">&lt;p&gt;Devlog from November 2022&lt;/p&gt;</summary><content type="html">&lt;p&gt;Hello again with a slightly delayed November Update for openage.&lt;/p&gt;
&lt;p&gt;Last month's post had an unfortunate lack of images, so I hope we can make up to it this time. With this in mind, we can present you a
wonky, weirdly colored screenshot taken straight from the current build.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Presenter test full" src="https://blog.openage.dev/images/news/2022-11/presenter_test_full.png"&gt;&lt;/p&gt;
&lt;p&gt;It probably doesn't look like much, but it actually
already shows the usage of rendering components directly by the engine's internal gamestate (although still making heavy use of test
textures and parameters). The current build also implements the major render stages for drawing the game: terrain and unit rendering.&lt;/p&gt;
&lt;h2&gt;Gamestate to Renderer&lt;/h2&gt;
&lt;p&gt;But let's backtrack a little bit and start from where we left off last month. In our last update, we talked about decoupling renderer
and gamestate as much as possible, so that they don't depend on each other as much. However, the gamestate still needs to communicate
with the renderer, so it can show what is happening inside the game on screen. Therefore, this month's work was focused on building a
generalized pipeline from the gamestate to the renderer. Its basic workflow looks like this for unit rendering:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Engine to renderer flow" src="https://blog.openage.dev/images/news/2022-11/engine_to_renderer.png"&gt;&lt;/p&gt;
&lt;p&gt;Left side shows the state inside the engine, right side the state inside the renderer. As you can see from the flowgraph, the gamestate
never directly uses the renderer itself. Instead, it only sends information on what it wants to be drawn to the renderer via a connector object
(the "render entity"). This object then converts the information from the gamestate into something the renderer can understand. For example,
it may convert the position of a unit inside the &lt;em&gt;game world&lt;/em&gt; into coordinates in the &lt;em&gt;graphics scene&lt;/em&gt; of OpenGL.&lt;/p&gt;
&lt;p&gt;The converted data from the render entities are then used for actual drawable objects (e.g. &lt;code&gt;WorldRenderObject&lt;/code&gt;). These are mostly used
to store the render state of the drawable, e.g. variables for the shader or texture handles for the animations that should be displayed.
Every frame, the drawable objects poll the render entities for updates and are then drawn by the renderer. Actually, there are several
subrenders which each represent a stage in the drawing process, e.g. terrain rendering, unit rendering, GUI rendering, etc. . In the end,
the outputs of each stage are blended together and create the result shown on screen.&lt;/p&gt;
&lt;p&gt;Here you can see how that happens behind the scenes.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Skybox Stage&lt;/strong&gt;: Draws the background of the scene in a single color (this would be black in AoE2).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img alt="Skybox stage" src="https://blog.openage.dev/images/news/2022-11/presenter_test_1.png"&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Terrain Stage&lt;/strong&gt;: Draws the terrain. The gamestate terrain is actually converted to a 3D mesh by the renderer which makes it much easier to texture.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img alt="Terrain stage" src="https://blog.openage.dev/images/news/2022-11/presenter_test_2.png"&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;World Stage&lt;/strong&gt;: Draws units, buildings and anything else that "physically" exists inside the game world. For now, it only draws dummy game objects that look like Gaben and the red X.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img alt="World stage" src="https://blog.openage.dev/images/news/2022-11/presenter_test_3.png"&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;GUI Stage&lt;/strong&gt;: Draws the GUI from Qt QML definitions.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img alt="GUI stage" src="https://blog.openage.dev/images/news/2022-11/presenter_test_full.png"&gt;&lt;/p&gt;
&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;With the rendering pipeline mostly done, we will probably start shifting to more work inside the gamestate. The first task here will
be to get the simulation running by setting up the event loops and implementing time management. The renderer also needs rudimentary
time management for correctly playing animations. Once that's done, we can play around with a dynamic gamestate that changes based
on inputs from the player.&lt;/p&gt;
&lt;p&gt;If there's enough time, we may also get around refactoring the old coordinate system for the game world. This would also be required
for reimplementing camera movement in the renderer.&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="gamestate"></category><category term="renderer"></category></entry><entry><title>Openage Development News: October 2022</title><link href="https://blog.openage.dev/openage-development-news-october-2022.html" rel="alternate"></link><published>2022-11-01T00:00:00+01:00</published><updated>2022-11-01T00:00:00+01:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2022-11-01:/openage-development-news-october-2022.html</id><summary type="html">&lt;p&gt;Devlog from October 2022&lt;/p&gt;</summary><content type="html">&lt;h2&gt;Goodbye SDL&lt;/h2&gt;
&lt;p&gt;As announced previous month, we've spent a lot of time removing SDL from the codebase and replacing it with Qt. Before, we used both SDL and Qt in tandem. This generally worked okay, but was always a bit weird, since both frameworks have essentially the same features. Mixing them together in our codebase also required a few workarounds, like having to convert SDL window events to Qt events (and vice versa), wrapping the Qt window inside SDL for GUI drawing (which also created problems on some OS's display servers), and numerous smaller forms of &lt;em&gt;jank&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;As of now, everything related to SDL graphics has been ported to Qt6. This includes these components for example:
    - Window Creation
    - Input Events (mouse clicks, key presses)
    - OpengL Context Management
    - Texture Loading
    - GUI Management and Drawing
A lot of the glue code connecting SDL and Qt could also be removed, which reduces the code complexity quite a bit. While SDL is not part of the graphics pipeline anymore, it still remains in other parts of the code, e.g. audio management, so it's not completely removed yet. However, we will probably replace that with a Qt equivalent in the near future.&lt;/p&gt;
&lt;h2&gt;Decoupling Renderer and Engine&lt;/h2&gt;
&lt;p&gt;Another side effect of the rework of the graphics code is that the remaining code is now separated from the main engine where the gameplay calculations happen. Before, graphics and gameplay were rather closely coupled, with direct communication between GUI, renderer and gameplay. There was also no clearly defined path between the components, so keeping the complex gamestate intact when the code was changed was not easy.&lt;/p&gt;
&lt;p&gt;We've now reworked this wild-west approach into something which is hopefully more manageable in the future. Basically, the new workflow of the engine considers the renderer and GUI components as &lt;em&gt;optional&lt;/em&gt;, i.e. everything in the engine concerning gamepay should work on its own without access to a display. Whenever the components have to communicate, there are now clearly defined paths that operate in one direction. For example, user input events will be funnelled into the engine by pushing them into the engine's event queue where they will be delegated to the correct place. Similarly, the engine can push animation requests into the rendering queue, where the renderer decides what to do with them.&lt;/p&gt;
&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;There are still some parts in the renderer which need improvement, so work on that will continue for the next month. To support the new rendering workflow, the renderer needs to provide connector objects, so that the engine can make rendering requests. For these requests, the renderer then has to decide where the objects have to be drawn on screen, what texture to use and potentially handle animation states.&lt;/p&gt;
&lt;p&gt;Since the engine is the main user of the renderer, we will also have to work on more basic engine stuff. This will probably involve a few rendering tests, before we actually implement "real" gameplay.&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="renderer"></category></entry><entry><title>Openage Development News: September 2022</title><link href="https://blog.openage.dev/openage-development-news-september-2022.html" rel="alternate"></link><published>2022-10-01T00:00:00+02:00</published><updated>2022-10-01T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2022-10-01:/openage-development-news-september-2022.html</id><summary type="html">&lt;p&gt;Devlog from September 2022&lt;/p&gt;</summary><content type="html">&lt;h2&gt;What's new&lt;/h2&gt;
&lt;h3&gt;Part 1 - SLD format documentation/parsing&lt;/h3&gt;
&lt;p&gt;In August the Definitive Edition of AoE2 received an update that changed its default graphics
files from the previously used SMX format to the new SLD format. Since the AoE2 devs did not
publish any information about the format, we had to reverse engineer it ourselves (together with
Tevious from SLX Studio, spriteblood from Overreign and simonsan from the LibreMatch project).
You can find the reversed specification in the openage repository (&lt;a href="https://github.com/SFTtech/openage/blob/master/doc/media/sld-files.md"&gt;Link&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;There are still some unknowns in the format that we don't fully understand, but the specification
allows decodung of the most relevant parts: the main graphics, shadows and the player color mask.
We still have to figure out how unit outlines and building damage masks are decoded exactly, so
you can expect some updates to the linked spec in the future. The openage converter can already
read the files and convert them to PNG with help of the &lt;a href="https://github.com/SFTtech/openage/blob/master/doc/convert/convert_single_file.md"&gt;singlefile converter&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For openage, the change to SLD doesn't change much because we don't use the files directly
and instead always convert them to PNG. However, one important thing to note is that the SLD
graphics compression is lossy, so the quality of sprites is slightly worse in comparison
to the lossless SMX compression. The difference is barely noticable ingame, but if you
like zooming in really far, you should probably make a backup of any SMX files in
the installation folder.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Blacksmith SLD main graphic" src="https://blog.openage.dev/images/news/2022-09/blacksmith_1.png"&gt;
&lt;img alt="Blacksmith SLD shadow graphic" src="https://blog.openage.dev/images/news/2022-09/blacksmith_2.png"&gt;
&lt;img alt="Blacksmith SLD damage mask" src="https://blog.openage.dev/images/news/2022-09/blacksmith_3.png"&gt;
&lt;img alt="Blacksmith SLD playercolor mask" src="https://blog.openage.dev/images/news/2022-09/blacksmith_4.png"&gt;&lt;/p&gt;
&lt;p&gt;(SLD layers: main graphics, shadows, damages mask, playcolor in that order)&lt;/p&gt;
&lt;p&gt;You can see the difference between SLD and SMX if you zoom in 1500%:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Blacksmith SLD/SMX comparison" src="https://blog.openage.dev/images/news/2022-09/blacksmith_SLD_SMX.png"&gt;&lt;/p&gt;
&lt;p&gt;(Left: SLD; Right: SMX)&lt;/p&gt;
&lt;p&gt;The SLD is more blocky because it uses a texture compression algorithm operating on 4x4
pixel blocks. Finer details are lost and there's less variety between colours.&lt;/p&gt;
&lt;h3&gt;Part 2 - GUI and Qt6&lt;/h3&gt;
&lt;p&gt;Back at the openage engine, there's also been progress, mainly focussed on the GUI framework.
The old GUI is "functional" but it does not work great and needs a serious overhaul before
we can start slapping new features onto it. Previously, we used a mixture of SDL2 and Qt5
for the GUI, which also required some hacky lines of code to get that working on different
platforms. There's also old engine code entangled into some of the classes which makes
maintance very unpleasent.&lt;/p&gt;
&lt;p&gt;The most important change so far in the new GUI is that we ported Qt5 code to Qt6. Qt6
can handle multiple graphics backends (OpenGL or Vulkan) much better than Qt5 and
also made some improvements in terms of cross-platform support. Hopefully, this means
we can get rid of a lot of weird and hacky stuff. In the long run, we will probably also
get rid of SDL2 (since Qt has mostly the same features) and maybe the codebase will
actually be readable :D&lt;/p&gt;
&lt;p&gt;Right now there's not much to see, unless you like empty window frames.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Qt6 window" src="https://blog.openage.dev/images/news/2022-09/qt6_window.png"&gt;&lt;/p&gt;
&lt;p&gt;Next month, there should be something more interesting that we can show you.&lt;/p&gt;
&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;There is still a lot to do for the new GUI, so that will also be the focus for next month.
After the GUI has been cleaned up, we have to stitch the individual components for
graphics output back together (unit rendering, camera movement, terrain drawing, etc.).
Once visual output works again, we can start testing the core engine.&lt;/p&gt;
&lt;p&gt;There is a chance that we'll also get to work on the gamestate in the engine, although
that would probably involve more render tests than actual gameplay. Getting something
visible on the screen is more important right now.&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="devlog"></category><category term="news"></category><category term="gui"></category></entry><entry><title>Engine Core Modules</title><link href="https://blog.openage.dev/engine-core-modules.html" rel="alternate"></link><published>2021-12-31T00:00:00+01:00</published><updated>2021-12-31T00:00:00+01:00</updated><author><name>jj</name></author><id>tag:blog.openage.dev,2021-12-31:/engine-core-modules.html</id><summary type="html">&lt;p&gt;our next steps for creating the engine core modules&lt;/p&gt;</summary><content type="html">&lt;p&gt;Hello everyone,&lt;/p&gt;
&lt;p&gt;It's time for another status report. Our &lt;a href="https://blog.openage.dev/new-gamestate-2020.html"&gt;blogpost from last year&lt;/a&gt;
and the subsequent &lt;a href="https://www.youtube.com/watch?v=2YG1sK4_SsU"&gt;talk at rC3&lt;/a&gt; dealt with the general handling
of game data with nyan and our modding API. This year, we focused on implementing the parts of the engine
that actually do something with the data... and also everything else necessary to make it usable. And how hard
could that be, right?&lt;/p&gt;
&lt;h2&gt;Current state&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Engine Core Modules" src="https://blog.openage.dev/images/T0008-engine-core-modules.svg"&gt;&lt;/p&gt;
&lt;p&gt;While the gamestate is integral for creating the game mechanics that define the games, other core modules
are equally as important for getting things to work. The gamestate module just drives the simulation of the
game world. It takes events and handles them based on certain rules (i.e. it is responsible for gameplay). However,
it is not concerned with user inputs or outputs. That's what the other modules are for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Renderer&lt;/strong&gt;: Shows what's happening in the game on your screen. It receives positional information and graphic assets from the gamestate and decides when and how to display them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Presenter&lt;/strong&gt;: Despite its name, it's not only used to "present" things, but also for receiving user inputs. The presenter module manages local user input and output for everything that is not graphics. For example, it translates all the key presses and mouse clicks to game events.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network&lt;/strong&gt;: Receives network packages for a multiplayer game and feeds them into the local simulation, i.e. the gamestate and eventsystem modules.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Eventsystem&lt;/strong&gt;: Manages and tracks events in the engine and ensures that they are properly ordered (the latter is important for receiving network events).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WorldUpdater&lt;/strong&gt;: Applies events to the game world.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of these modules have to communicate and work together for creating a functional (multiplayer) game. In openage,
the core modules will be &lt;em&gt;loosely&lt;/em&gt; coupled, i.e. we try to minimize their dependencies on each other. We do
this on the one hand to allow for flexibility for extensions or changes in the future, preparing the engine
for low-level modding. On the other hand, we hope a loose coupling keeps the code maintainable and prevents
the engine from evolving into a giant spaghetti monster.&lt;/p&gt;
&lt;h2&gt;Gamestate: How we do ingame things (Recap)&lt;/h2&gt;
&lt;p&gt;For those still unfamiliar with our game data handling, we recommend the &lt;a href="https://www.youtube.com/watch?v=2YG1sK4_SsU"&gt;rC3 talk&lt;/a&gt;
again which goes much more into detail about this. For everyone else, here's a quick refresher on how the general
workflow operates.&lt;/p&gt;
&lt;p&gt;Ingame units have so-called &lt;em&gt;abilities&lt;/em&gt; which define what they can do (e.g. move, attack, gather), what they are (e.g. selectable)
or what traits they have (e.g. attributes like HP). Abilities are assigned to a unit by adding the associated &lt;code&gt;Ability&lt;/code&gt;
object to the unit definition in the modpack data. The &lt;code&gt;Ability&lt;/code&gt; object also stores all necessary data related to that ability, e.g. a
gather rate for the &lt;code&gt;Gather&lt;/code&gt; ability.&lt;/p&gt;
&lt;p&gt;In the engine, every &lt;code&gt;Ability&lt;/code&gt; object is associated with a gameplay system that can be accessed by the gamestate for
unit instances with the assigned ability. This system uses the data from the object, e.g. for &lt;code&gt;Gather&lt;/code&gt; the gather rate,
to execute an action. In the case of a &lt;code&gt;Gather&lt;/code&gt; ability, the action would be that a villager's resource storage is
increased by the gather rate value, while the targeted resource spot's resources are decreased.&lt;/p&gt;
&lt;h2&gt;Gamestate 2: Do many things and do them right&lt;/h2&gt;
&lt;p&gt;So far so good. In this basic model, every ability has a corresponding gameplay system which, when used, handles the
necessary calculation to do the associated gameplay action. However, something that needs to be addressed is that
most gameplay mechanics in AoE (and RTS in general) can often not be modelled as one single action. More precisely,
gameplay mechanics often involve action &lt;em&gt;routines&lt;/em&gt; that are executed in order. For example, an infantry attack
in AoE2 actually involves at least two actions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Move to the target&lt;/li&gt;
&lt;li&gt;Attack the target&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These routines can also be much more complex. Take the gathering mechanic in AoE2 for example, which we will
break down for you.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Gather mechanic (AoE2)" src="https://blog.openage.dev/images/T0008-gather-mechanic-viz.png"&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The player commands the villager to a resource (beginning of the task)&lt;/li&gt;
&lt;li&gt;Villager moves to the resource spot (Move action)&lt;ul&gt;
&lt;li&gt;this action continues until the villager arrives at the resource spot&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Villager starts gathering the resource (Gather action)&lt;ul&gt;
&lt;li&gt;this action continues until the villager's resource storage is full&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Search for a resource dropsite (technically not an action, but important for the routine)&lt;/li&gt;
&lt;li&gt;Villager moves to a resource dropsite (Move action)&lt;ul&gt;
&lt;li&gt;this action continues until the villager arrives at the resource dropsite&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Villager deposits the gathered resource at the resource dropsite (DropResources action)&lt;/li&gt;
&lt;li&gt;Start again at step 2.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As you can see, these routines can get quite complex. In this example, we have actions that
end on a condition (step 2, 3 and 5), intermediary steps (step 4) and we even have to integrate a loop (step 7).
Mechanics might also have branching paths based on certain conditions, e.g. a farm is only reseeded if
the player has enough resources. Other actions, such as health regeneration for the unit, might also happen
in parallel.&lt;/p&gt;
&lt;p&gt;The solution we chose for this problem is to use flow graphs for handling these complex mechanics
(or &lt;em&gt;activities&lt;/em&gt; as they are called internally). We take advantage of the event-driven nature of our
gamestate implementation here. Starting, ending or cancelling an action always involves an
event. With the help of flow graphs, we can define what events start or end actions by mapping the
events to paths in the flow graph. When an event happens, the appropriate follow-up action is started.
How this would look like can be seen below.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Gather flow graph (AoE2)" src="https://blog.openage.dev/images/T0008-gather-mechanic-flow.svg"&gt;&lt;/p&gt;
&lt;p&gt;Every action can be represented as a node in the directed flow graph. When a node is &lt;em&gt;visited&lt;/em&gt;,
the associated action is taken, i.e. the gameplay system executes. Paths between the nodes
are mapped to events. The unit - in this case the villager - registers and listens for events that are
required for advancing from the current node to the next node. For example, if the current node is
step 3, the villager would listen for the event that its resource storage is full. When the event
fires, the activity advances to the next node and the next action is taken. Although not depicted
here, a node may have several outgoing paths that each map to a different action.&lt;/p&gt;
&lt;p&gt;The nice thing about this solution is that it allows for sophisticated control over the flow of actions,
while also being reasonably efficient in terms of memory and computation. The flow graph only
has to be defined once for every unit type. Sometimes the flow graph for an activity can be the same
for an entire class of units. For example, the AoE2 attack mechanics would use the same flow across every
military unit. At runtime, the unit only needs to know its current node in the activity's flow graph as well as
the events it needs to listen for. Advancing to the next action is a simple lookup for the next node, using
the received event.&lt;/p&gt;
&lt;h2&gt;Renderer&lt;/h2&gt;
&lt;p&gt;In theory, the renderer module has a simple task. It gets handed animation IDs and positional
arguments by the gamestate and draws them on the screen. openage, like AoE2 and other Genie Engine games,
uses a 2D renderer, so animations are sequences of 2D images (sprites).&lt;/p&gt;
&lt;p&gt;However, in practice the sprites are actually more than plain images. In AoE games, some of
the pixels in a sprite are "special" and are used to convey gameplay information. For example,
pixels can be marked as &lt;em&gt;player colors&lt;/em&gt; or as an &lt;em&gt;outline&lt;/em&gt;. How these pixels are displayed
depends on the associated gameplay information, e.g. the player ID. This situation imposes
two questions for us that we have to address. First of all, we need a way to mark the special
pixels, so that the renderer knows they exits. Secondly, the renderer needs to know how to
transform the special pixel into a color using the gameplay information.&lt;/p&gt;
&lt;p&gt;We address the first problem by encoding special pixels in the pixel data itself. Sprites
for openage are stored in PNGs using the 32 Bit RGBA format, where every color channel (red,
green, blue and alpha) is 8 Bit wide and thus can have 256 possible values.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;PNG 32 Bit RGBA

11001100  10101010  00001111  11111111
--------  --------  --------  --------
^         ^         ^         ^
Red       Green     Blue      Alpha
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;To mark our special pixels, we change the interpretation of the alpha channel slightly. We
reduce the alpha channel to 7 Bits and use the last bit as a &lt;em&gt;marker&lt;/em&gt; bit instead.
The marker indicates whether the pixel requires special processing.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;openage 31 Bit RGBA + marker bit (color)

11001100  10101010  00001111  1111111  1
--------  --------  --------  -------  -
^         ^         ^         ^        ^
Red       Green     Blue      Alpha    marker bit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If the last bit is &lt;code&gt;1&lt;/code&gt;, the pixel is treated as a normal color and would be copied directly into
the drawing buffer. If it is &lt;code&gt;0&lt;/code&gt;, then the remaining 7 bits of alpha channel are
interpreted as an index for a special &lt;em&gt;draw command&lt;/em&gt;. The 24 Bit of the RGB channels
may be used as a payload to store additional information such as a palette ID. Based on
the command index, the GPU can choose a corresponding code path to draw the special pixel.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;openage 31 Bit RGBA + marker bit (command)

00000000  00000000  00000000  1111111  0
--------  --------  --------  -------  -
^         ^         ^         ^        ^
Red       Green     Blue      Alpha    marker bit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This effectively leaves us with 128 usable alpha values for normal colors and 128 assignable
draw commands.&lt;/p&gt;
&lt;p&gt;Now we need to tell the renderer, or rather the GPU, how to handle these commands. We do this
by letting the renderer assign custom shader code chunks to each command index. At load-time, the
renderer assembles the code chunks for all commands into the fragment shader that is uploaded to the GPU.
When the fragment shader receives pixel data, it will first check the marker bit. If it's a command,
then the shader will execute the predefined code chunk passed to the renderer at load-time.
A side benefit of handling custom draw commands in shader code is that the commands can potentially be redefined
by each modpack, i.e. they are not hardcoded into the engine.&lt;/p&gt;
&lt;p&gt;For every command, we can define "associated gameplay data" that should be sent by the gamestate alongside
the animation ID. For example, this can be the ID of the owner of a unit (to determine the player color).
The information on how to find this data is defined in the modpack and stored in the engine's indexing system at runtime.
When a system in the gamestate sends an animation request to the renderer, it will also look
up all associated data using the information in the indexing system and attach it to the request.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Rendered sprite" src="https://blog.openage.dev/images/T0008-renderer-sprite.gif"&gt;&lt;/p&gt;
&lt;p&gt;(The final rendering result after processing all pixels. Red pixels are player color commands, green pixels
are outline comands.)&lt;/p&gt;
&lt;h2&gt;Presenter: Game Control&lt;/h2&gt;
&lt;p&gt;To make games running on the engine playable by actual people, we have to translate the input
events from the player's peripherals to game events usable for the game simulation. As stated in
our introduction, this is part of the presenter module's responsibility. The presenter manages the
peripherals as well as their configuration.&lt;/p&gt;
&lt;p&gt;However, mapping input events to game events is not the only relevant task. Game control is also
about the separation of concerns, specifically between &lt;em&gt;ingame&lt;/em&gt; and &lt;em&gt;outgame&lt;/em&gt; control information.
An example for ingame control information is the command queue of a unit. This type of information
is directly relevant for the game simulation as it affects the behaviour of units in the game world.
On the other hand, outgame information is everything that mostly concerns the person in front
of the screen, but does not affect the game world on its own. Example for this are the input devices of a player,
the layout of the UI, but also control &lt;em&gt;concepts&lt;/em&gt; like a selection queue for units. Outgame information
can be used to influence the game simulation, but it should not be required to run it.&lt;/p&gt;
&lt;p&gt;So, what's the point of having a separation of concerns here? Our main motivation is to generalize
the interface to the game simulation, so that it is not limited to human players. In RTS games,
humans are not the only actors that can exercise control. Possible actors could be an AI, a script, or
a dedicated server in a multiplayer game. The outgame information (and outgame control) these actors
posess can be very different, yet they should all be able to take control of ingame information in
their own way. This is especially relevant to AI, since it should not be limited to human control methods.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Controller structure" src="https://blog.openage.dev/images/T0008-controller.svg"&gt;&lt;/p&gt;
&lt;p&gt;Part of the solution to this problem is our model of "controllers". A &lt;code&gt;Controller&lt;/code&gt; object is
a link between the outgame control methods and the game simulation. The main purpose of a
controller in this regard is to define the level of access control an outgame actor has over
ingame information. For example, a controller may define that a human player has control
over an ingame faction with a specific ID. It can also define the permissions the actor
has when accessing the ingame information. A spectator may only have "view" access to
an ingame faction, while the acting player of said faction has "view" and "action" access.
A nice benefit of handling access control like this is that we can easily switch control
between ingame factions by modifying or replacing the controller.&lt;/p&gt;
&lt;p&gt;The second job of the controller is to map input events from the presenter to ingame
events for the game simulation. For this purpose, the controller acts as an interface between the
gamestate and presenter modules. The important thing is that the controller merely does
the mapping and does not care about the type of input device. That way, all kinds of input events
can be translated to the game simulation, whether they come from physical devices, an AI,
a script, or a network socket.&lt;/p&gt;
&lt;h2&gt;Questions&lt;/h2&gt;
&lt;p&gt;Do you have something to discuss? Visit &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt; or pass by in &lt;strong&gt;&lt;a href="https://github.com/SFTtech/openage/discussions"&gt;our discussion board&lt;/a&gt;&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;And you can reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="roadmap"></category><category term="gamestate"></category><category term="renderer"></category><category term="presenter"></category><category term="curves"></category></entry><entry><title>New Gamestate 2020</title><link href="https://blog.openage.dev/new-gamestate-2020.html" rel="alternate"></link><published>2020-08-15T00:00:00+02:00</published><updated>2020-08-15T00:00:00+02:00</updated><author><name>jj</name></author><id>tag:blog.openage.dev,2020-08-15:/new-gamestate-2020.html</id><summary type="html">&lt;p&gt;our next steps for integrating the new gamestate and gameplay&lt;/p&gt;</summary><content type="html">&lt;p&gt;Over the past weeks and months, two more important engine components of the engine
have become ready to be merged. These components are the
&lt;a href="https://github.com/SFTtech/openage/pull/1066"&gt;new gamestate&lt;/a&gt; and the
&lt;a href="https://github.com/SFTtech/openage/pull/1151"&gt;new nyan converter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The integration of both components marks the beginning of a new development phase
as pretty much all major engine core parts will be set in place. We can now use
this foundation to build all gameplay-relevant features around them.&lt;/p&gt;
&lt;h2&gt;What's the plan?&lt;/h2&gt;
&lt;p&gt;The first thing we will do is merge the new converter. In comparison to the
older code, which mainly just dumped the assets into open formats, the new converter
is able to create &lt;strong&gt;modpacks&lt;/strong&gt; that use the &lt;strong&gt;openage nyan API&lt;/strong&gt;. It also brings
(preliminary) &lt;strong&gt;support for the other Genie games&lt;/strong&gt; Age of Empires 1 and Star Wars:
Galactic Battlegrounds.&lt;/p&gt;
&lt;p&gt;Next up is the new gamestate PR. This replaces the lockstep implementation
we have used in the engine until now with an &lt;strong&gt;event-driven system&lt;/strong&gt;. Furthermore,
it makes use of the &lt;strong&gt;curve-based simulation model&lt;/strong&gt; that has been implemented for a
while now. Another core part that is coupled with the new gamestate is the new
&lt;strong&gt;low-level renderer/presenter&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;With the integration of the new components, the old gamestate implementation will
no longer work. However, this means that the gameplay features that were implemented
along with it will no longer work! There might be a lot less visible features for
a while. We have debated about leaving the old gamestate intact, but ultimately decided
that having parallel structures in the engine is too much work and probably
confusing to outside contributors. The old gameplay logic will also not be lost,
but rather re-implemented using the paradigms of the new gamestate.&lt;/p&gt;
&lt;h2&gt;What's the next step?&lt;/h2&gt;
&lt;p&gt;Once all the code merging, refactoring and documentation updating has been solved,
we will start to reimplement gameplay with the Entity-Component-System paradigm. With
this approach a lot of features can be added in parallel (although we can't promise
that it won't be complicated still). That also means that we do not have to
tell new contributors the phrase "you can work on anything, except gameplay"
anymore as implementing it is no longer blocked by missing egine core functionality.&lt;/p&gt;
&lt;p&gt;For testing features, we will create a simple gameplay demo which will be
gradually expanded with new systems. It is supposed to act as a testing bed for the
implementation and will probably not model a fully-featured game at first. It's main
goal is to give players and contributors an idea of what we are doing... because
nobody wants to read long blogposts all the time, am I right? :D&lt;/p&gt;
&lt;h2&gt;Questions&lt;/h2&gt;
&lt;p&gt;Do you have something to discuss? Visit &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt; or pass by in &lt;strong&gt;&lt;a href="https://github.com/SFTtech/openage/discussions"&gt;our discussion board&lt;/a&gt;&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;And you can reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="roadmap"></category><category term="gamestate"></category></entry><entry><title>The openage Converter - Part IV: Conclusions</title><link href="https://blog.openage.dev/the-openage-converter-part-iv-conclusions.html" rel="alternate"></link><published>2020-06-24T00:00:00+02:00</published><updated>2020-06-24T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2020-06-24:/the-openage-converter-part-iv-conclusions.html</id><summary type="html">&lt;p&gt;Now that the technical aspects of the converter are explained, we take some time to review its performance and talk about features that should be implemented in the future.&lt;/p&gt;</summary><content type="html">&lt;p&gt;With the general converter pipeline explained, there are not that many technical questions left
to be answered except the most important ones: &lt;em&gt;Does it work?&lt;/em&gt; and &lt;em&gt;How well does it work?&lt;/em&gt;.
You should be able to guess the answer to the first question yourself if you have read the
previous bloposts (Hint: It's "Yes"). The second question is what we want to answer
in this blogpost. To do that, we will take a look at the overall performance of
the converter, the file size of the created modpacks it generates and how well it is equipped for
future improvements.&lt;/p&gt;
&lt;h2&gt;Performance&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Structure" src="https://blog.openage.dev/images/T0003-converter-structure.svg"&gt;&lt;/p&gt;
&lt;p&gt;The most time-consuming operations in the conversion process are parsing the &lt;code&gt;.dat&lt;/code&gt; file
in the &lt;strong&gt;Reader&lt;/strong&gt; stage and writing media files during the &lt;strong&gt;Export&lt;/strong&gt; stage. Parsing
the AoC 1.0c &lt;code&gt;.dat&lt;/code&gt; file will usually take 1-5 minutes, depending on how old your
processor is. Media export for AoC is in the same range. In comparison to that,
the Genie to nyan format conversion in the &lt;strong&gt;Processor&lt;/strong&gt; is really fast and took a maximum
of 3 seconds in my tests. Its impact on the runtime is almost negligeble. All
in all, the conversion from AoC to an openage modpack should not take longer than 10 minutes.&lt;/p&gt;
&lt;p&gt;It should be noted that the conversion time does not increase linearly with the size
of the original game. AoE2: Definitive Edition, which is more than 100x bigger than
the AoC 1.0c, will therefore hopefully not take 100x as long to convert. Since the converter
does not fully support all media formats of the Definitive Editions yet, we cannot directly compare the
runtime right now. However, we estimate that total necessary conversion time will be between 30 minutes
and 2 hours.&lt;/p&gt;
&lt;p&gt;One remaining challenge is the reduction of the converter's memory consumption. Currently
the in-memory storage of the &lt;code&gt;.dat&lt;/code&gt; file values consumes a huge amount of space (~360MB for AoC). The reason for
this is that we store these values in Python objects along with contextual information
necessary for the conversion process (see the &lt;a href="https://blog.openage.dev/the-openage-converter-part-i-reading-data.html"&gt;first blogpost&lt;/a&gt;
in the series). In a worst-case
scenario, a boolean that has a length 1 Byte in the &lt;code&gt;.dat&lt;/code&gt; file will use up to 100 Bytes in
its Python object form, even when we employ memory optimizations like the usage of &lt;code&gt;__slots__&lt;/code&gt;. This only becomes a
real problem with the large dataset of the AoE2: Definitive Edition (~3,800MB), but it's a problem nevertheless.&lt;/p&gt;
&lt;p&gt;The solution to the memory problem will be to offload some of the larger structures to
temporary files during the &lt;strong&gt;Reader&lt;/strong&gt; stage and load them on-demand during the nyan conversion.
This will increase conversion time, but will be less demanding for devices with low
memory.&lt;/p&gt;
&lt;h2&gt;Modpack size&lt;/h2&gt;
&lt;p&gt;Modpack size is mostly determined by the size of media files, especially the graphics. Most graphics
in Genie games use palette-indexed sprites with a color depth of either 8 Bit (AoE1, AoC, SWGB)
or 10 Bit (AoE2: Definitive Edition). In comparison to that, openage sprites are stored in PNG files
using the 32 Bit RGBA format.&lt;/p&gt;
&lt;p&gt;To prevent the increase in color depth from blowing up the file size, we also compress the spritesheets
with standard PNG compression. Funnily enough, this can lead to situations where an openage 32 Bit
spritesheet has a &lt;em&gt;smaller&lt;/em&gt; file size than the uncompressed 8 Bit media file it was converted from.
In the end, the openage modpack size will be about even with the size of the original games and
could potentially be slightly smaller.&lt;/p&gt;
&lt;p&gt;Of course, compression always comes with a price: The time to decompress the spritesheet
at runtime before rendering. Unless your PC is from 1999, decompression time is so small
that it should not have an impact for the spritesheets of AoC. For the
Definitive Editions, which have sprites with higher resolution and frame rates, we will
have to see how much decompression affects texture load times. If it is an issue, we are probably
able to solve it by implementing predicted asset pre-loading or utilizing block-wise parallel
decompression methods.&lt;/p&gt;
&lt;h2&gt;Mod support&lt;/h2&gt;
&lt;p&gt;Future releases of the converter should also be able to transform a mod for the
original &lt;code&gt;.dat&lt;/code&gt; file into a valid mod for the converted AoE2 openage modpack. The challenge here is
that mods often not only change existing data; they can also add, remove or rearrange
logical entities in the dataset. Thus converting mods will need more than just diffing values
from the &lt;code&gt;.dat&lt;/code&gt; files, since we have to figure out how the change fits into the openage data model.
This could be more or less tricky depending on the features of the mod, but adding mod conversion
to the converter will make transitioning to openage much easier for modders used to AoC.&lt;/p&gt;
&lt;h2&gt;What about the other games?&lt;/h2&gt;
&lt;p&gt;AoC 1.0c is only one of the games running on the Genie Engine, so what about all the other games?
Over the years, there have been 6 different releases that use the engine.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Age of Empires 1 + Rise of Rome (&lt;strong&gt;RoR&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Age of Empires 1: Definitive Edition (&lt;strong&gt;DE1&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Age of Empires 2 + The Conqueror's (&lt;strong&gt;AoC&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Age of Empires 2: HD Edition (&lt;strong&gt;HD&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Age of Empires 2: Definitive Edition (&lt;strong&gt;DE2&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Star Wars: Galactic Battlegrounds + Clone Campaigns (&lt;strong&gt;SWGB&lt;/strong&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;At the time that this blogpost is published, we have already implemented partial support for
4 of these versions. The code for the &lt;strong&gt;AoC&lt;/strong&gt; processor is also the converter core. The conversion
processors for the other supported releases (&lt;strong&gt;RoR&lt;/strong&gt;, &lt;strong&gt;DE2&lt;/strong&gt; and &lt;strong&gt;SWGB&lt;/strong&gt;) reuse most
of the core functionality of the &lt;strong&gt;AoC&lt;/strong&gt; processor. Functions only need to be reimplemented
for abilities where behaviour between &lt;strong&gt;AoC&lt;/strong&gt; and the other games is different. This is where
our modular approach pays off.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Release&lt;/th&gt;
&lt;th&gt;Unique code lines&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AoC&lt;/strong&gt; (core)&lt;/td&gt;
&lt;td&gt;38,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RoR&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DE2&lt;/strong&gt; (partial)&lt;/td&gt;
&lt;td&gt;3,000 (est.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SWGB&lt;/strong&gt; (partial)&lt;/td&gt;
&lt;td&gt;8,000 (est.)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;(only data conversion)&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;DE2&lt;/strong&gt; and &lt;strong&gt;SWGB&lt;/strong&gt; conversion processors do not convert all features of the games
so far, but already produce functional modpacks. &lt;strong&gt;DE2's&lt;/strong&gt; processor is only missing some
of the newer tech effects. &lt;strong&gt;SWGB&lt;/strong&gt; deviates the most from &lt;strong&gt;AoC&lt;/strong&gt; and has its own
unique features, e.g. shields and stealth units, that are not supported yet;
This is partially the cause of me not being that knowledgable about the game.
So if you do know more about &lt;strong&gt;SWGB's&lt;/strong&gt; inner workings, feel free to
come by in our &lt;a href="https://riot.im/app/#/room/#sfttech:matrix.org"&gt;chat&lt;/a&gt;.
We appreciate the extra help :-)&lt;/p&gt;
&lt;h2&gt;Contact&lt;/h2&gt;
&lt;p&gt;If you have any questions regarding this blogpost or you are eager to help developing openage make sure to pass by in &lt;strong&gt;&lt;a href="https://github.com/SFTtech/openage/discussions"&gt;our discussion board&lt;/a&gt;&lt;/strong&gt;. You can also check the weekly development news on &lt;a href="https://reddit.com/r/openage"&gt;our subreddit&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="nyan"></category><category term="converter"></category><category term="assets"></category></entry><entry><title>The openage Converter - Part III: Convert!</title><link href="https://blog.openage.dev/the-openage-converter-part-iii-convert.html" rel="alternate"></link><published>2020-06-16T00:00:00+02:00</published><updated>2020-06-16T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2020-06-16:/the-openage-converter-part-iii-convert.html</id><summary type="html">&lt;p&gt;We describe how data in the API-like objects is transferred to nyan objects.&lt;/p&gt;</summary><content type="html">&lt;p&gt;In our previous blogpost we introduced the idea of &lt;strong&gt;API-like objects&lt;/strong&gt; which organize logical
entities from AoE2 in such a way that we can map their data to the concepts of the openage API.
With all preparation done, we can now take the final step and convert the data to our &lt;a href="https://github.com/SFTtech/nyan"&gt;nyan
data format&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="You are here" src="https://blog.openage.dev/images/T0005-converter-structure.svg"&gt;&lt;/p&gt;
&lt;h2&gt;Iterate!&lt;/h2&gt;
&lt;p&gt;The approach we take to create the nyan objects is very straightforward: We iterate through all
concept groups, check what properties they have and create the associated nyan objects. Since
we made sure during the preparation phase that every concept group has information to be processed
individually, the transformation to nyan is surprisingly simple. So let's do an example.&lt;/p&gt;
&lt;p&gt;A very basic concept group conversion for a &lt;code&gt;GenieUnitLineGroup&lt;/code&gt; would look like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We check for the properties the unit line could have one by one. A property (or &lt;em&gt;ability&lt;/em&gt; as it is
called in openage) represents something the unit line &lt;strong&gt;is&lt;/strong&gt; or &lt;strong&gt;does&lt;/strong&gt;, e.g.&lt;ul&gt;
&lt;li&gt;Can it attack?&lt;/li&gt;
&lt;li&gt;Can it build/create other game entities?&lt;/li&gt;
&lt;li&gt;Is it harvestable?&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If a property check is successful, the &lt;code&gt;GenieUnitLineGroup&lt;/code&gt; instance is passed to a function in a subprocessor.
There, the converter creates the corresponding nyan objects and assigns their member values by
mapping the unit values from the .dat file to them. All created nyan objects are stored with the
&lt;code&gt;GenieUnitLineGroup&lt;/code&gt; instance, so they can be exported to file later.&lt;/li&gt;
&lt;li&gt;Repeat this process for every possible property a unit line can have.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The same principle is applied to concept groups for buildings, ambient objects or concept groups
that are not even game entities such as techs or civs. The only difference for the latter is that
techs check for effect types, not properties. However, the workflow is the same, with the tech
being passed to a subprocessor that creates the nyan objects for its effect types.&lt;/p&gt;
&lt;p&gt;A subprocessor function in the AoE2 converter are designed to be reusable for the conversion
of other games running on the Genie Engine, if they implement the corresponding property in
the same way. For example, basic movement properties are the same across all games.
The reusability is a huge benefit as it drastically decreases code redundancy and makes implementing
converters for other Genie games much simpler.&lt;/p&gt;
&lt;h2&gt;Request!&lt;/h2&gt;
&lt;p&gt;Something we didn't talk about so far is the conversion of media files.
In the old converter, data and media files (mainly sounds and graphics) were exported separately.
The converter would just take a media container format like &lt;code&gt;graphics.drs&lt;/code&gt; and dump all its
contents into one folder, regardless of whether they were actually used in the game.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Media export request" src="https://blog.openage.dev/images/T0005-media-export.svg"&gt;&lt;/p&gt;
&lt;p&gt;This process has been revised for the new converter. The biggest change is that it now only exports media
files that were explicitly requested during data conversion. As a result, we can be more
selective about the media we want to have. For example, the "main" AoE2 modpack will only contain data
relevant for skirmish and multiplayer maps which means scenario or beta units are not included. Since these
units are not in the modpack, we also do not generate export requests for their graphics. This
ultimately saves a lot of conversion time for players that are not interested in singleplayer.&lt;/p&gt;
&lt;p&gt;Integrating the media conversion into the data conversion also enables us to automatically generate
context-specific filenames such as &lt;code&gt;idle_archer_animation.png&lt;/code&gt; instead of &lt;code&gt;8.slp.png&lt;/code&gt;. Sometimes this
doesn't work as well as intended - especially when a media file is shared between units - but it's
certainly better than finding volunteers to name 1000 files manually.&lt;/p&gt;
&lt;h2&gt;Export!&lt;/h2&gt;
&lt;p&gt;The export step is even more simple than conversion step as we just dump all the data we created. Nyan
objects are transformed into their human-readable string representation and printed into files. Media
files are converted into open image and sound formats as well as having their metadata extracted into
text files. It doesn't get more complicated than that.&lt;/p&gt;
&lt;p&gt;However, every modpack also gets a few extra meta formats for glueing the modpack together. One of these
is the &lt;strong&gt;modpack definition file&lt;/strong&gt;. This file stores the load configuration data for the engine initialization,
e.g. the paths to the included data folders and referenced to other modpacks it may require. It also
contains basic descriptive information such as the modpack's human-readable name, a (translated) description
or the list of authors.&lt;/p&gt;
&lt;p&gt;The other formats are a &lt;strong&gt;manifest file&lt;/strong&gt; optionally accompanied by a &lt;strong&gt;cryptographic signature&lt;/strong&gt;. Every manifest
stores a list of hash-filename pairs for every file in the modpack. This can be used to check the
integrity of the modpack during load time. Its main purpose is to ensure that all players in a multiplayer
game use the same files and thus operate on the same data. Signatures (generated by a trusted authority)
can be used to additionally verify that the signed modpack is &lt;em&gt;safe to use&lt;/em&gt;, e.g. they don't contain
malware or mine bitcoins while you play. However, this is much more relevant for user-created modpacks that use
complex scripting than for the modpacks generated by the converter.&lt;/p&gt;
&lt;h2&gt;To be continued...&lt;/h2&gt;
&lt;p&gt;There will be one final blogpost in this series where we talk about future plans and considerations for the converter.
Keep an eye out for that!&lt;/p&gt;
&lt;p&gt;If you have any questions regarding this blogpost or you are eager to help developing openage make sure to pass by in &lt;strong&gt;&lt;a href="https://github.com/SFTtech/openage/discussions"&gt;our discussion board&lt;/a&gt;&lt;/strong&gt;. You can also check the weekly development news on &lt;a href="https://reddit.com/r/openage"&gt;our subreddit&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="nyan"></category><category term="converter"></category><category term="assets"></category></entry><entry><title>The openage Converter - Part II: Preparations for Conversion</title><link href="https://blog.openage.dev/the-openage-converter-part-ii-preparations-for-conversion.html" rel="alternate"></link><published>2020-05-14T00:00:00+02:00</published><updated>2020-05-14T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2020-05-14:/the-openage-converter-part-ii-preparations-for-conversion.html</id><summary type="html">&lt;p&gt;We investigate how the Genie structures are organized into API-like objects.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Our last blogpost was all about parsing the AoE2 &lt;code&gt;.dat&lt;/code&gt; file and structuring its content into objects that
represent the &lt;strong&gt;logical entities&lt;/strong&gt; of the original format (like in Advanced Genie Editor). However, we cannot
start with the transition to nyan objects just yet. The reason for this is that the openage API has
a different structure than the objects we acquired from the &lt;code&gt;.dat&lt;/code&gt; file so far. Thus, an additional
refinement is required to before we can do the transition to nyan. How this affects the converter is
our topic for today.&lt;/p&gt;
&lt;p&gt;&lt;img alt="You are here!" src="https://blog.openage.dev/images/T0004-converter-structure.svg"&gt;&lt;/p&gt;
&lt;h2&gt;Spotting the Differences&lt;/h2&gt;
&lt;p&gt;Attributes from the &lt;code&gt;.dat&lt;/code&gt; file often do not have a direct 1-to-1 mapping to the nyan API. While openage
and AoE2 essentially do the same thing on the surface, the underlying structure of the openage API can differ quite
significantly from the structure of the logical entities in the Genie Engine. Some of the mechanics were
extended or streamlined by us, other had to be altered to fit the Entity-Component System model our API uses.
A few examples of different data models are listed below.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Game Mechanic&lt;/th&gt;
&lt;th&gt;Genie Engine&lt;/th&gt;
&lt;th&gt;openage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Unit Upgrades&lt;/td&gt;
&lt;td&gt;Units are &lt;em&gt;replaced&lt;/em&gt; with upgraded unit&lt;/td&gt;
&lt;td&gt;Unit &lt;em&gt;attributes&lt;/em&gt; are upgraded (with patches)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Creation location&lt;/td&gt;
&lt;td&gt;Stored in connection or &lt;em&gt;created&lt;/em&gt; unit object&lt;/td&gt;
&lt;td&gt;Stored with &lt;em&gt;creating&lt;/em&gt; unit object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trebuchet (un)packing&lt;/td&gt;
&lt;td&gt;Trebuchet is &lt;em&gt;replaced&lt;/em&gt; with (un)packed unit&lt;/td&gt;
&lt;td&gt;&lt;em&gt;State change&lt;/em&gt; in state machine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HP&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Hardcoded&lt;/em&gt; behaviour (damage, death, heal)&lt;/td&gt;
&lt;td&gt;HP is a &lt;em&gt;configurable attribute&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Unit upgrades are especially challenging because AoE2 replaces the whole unit object reference, while openage
upgrades only the attributes that actually change. In order to detect which attributes change we need to
know the upgrade order of units (also called a &lt;em&gt;unit line&lt;/em&gt;) and create a diff between neighboring units
in that line. Replacement mechanics are also used in other ways, e.g. for the trebuchet, which requires its
own special treatment.&lt;/p&gt;
&lt;p&gt;Other mechanics, such as the creation location of buildings or units, can sometimes be annoying to detect
when we process units one at a time. For example, there is no way to see which buildings a villager can
create by looking at the villager object alone.&lt;/p&gt;
&lt;h2&gt;Concept Grouping&lt;/h2&gt;
&lt;p&gt;The first step we take to solve the described problems is to use &lt;strong&gt;concept grouping&lt;/strong&gt;. The idea behind this
method is that even though the data model of the Genie Engine and openage can be very different, the gameplay
mechanics/concepts stay the same. One example of such a concept would be the aforementioned unit line, while
a concept group is a specific instance of the concept, e.g. the archer unit line in AoE2. Examples for other
concepts are age upgrades, civs or transform groups (trebuchets).&lt;/p&gt;
&lt;p&gt;In the converter, the concepts are implemented as Python classes whose instances become the concept groups.
The classes usually implement methods that can figure out additional context about the groups, e.g. whether
a unit line is unique or what position every unit in the line has. To establish the concept groups, the
converter iterates through every logical entity, finds the related concept and adds the entity to its
corresponding group.&lt;/p&gt;
&lt;p&gt;&lt;img alt="GenieUnitLineGroup UML" src="https://blog.openage.dev/images/T0004-group-object.svg"&gt;&lt;/p&gt;
&lt;p&gt;(The above image shows an UML excerpt from the Python class &lt;code&gt;GenieUnitLineGroup&lt;/code&gt; (for - you guessed it - the unit line concept)
on the left as well as an example instance in form of the archer line. The instance stores the units that are part of the line
as an ordered list of &lt;code&gt;GenieUnit&lt;/code&gt; objects which you should be familiar with from the last blogpost.
Methods from the class are available for every instance and help us determine a line's properties.)&lt;/p&gt;
&lt;p&gt;One big advantage of concept groups is that every concept does have a 1-to-1 mapping from AoE2 to openage;
something that a single logical entity did not necessarily provide. The groups' Python classes provide an
abstract view on the concepts in this case which translate the Genie data model to the openage data model.
Hence, you can also interpret the created concept groups as &lt;em&gt;API-like objects&lt;/em&gt; that represent an openage API
concept using Genie Engine data. By operating on the groups during nyan conversion, the converter does not
have to worry about the context of individual logical entities anymore and can concentrate solely on
fetching the necessary data from the groups.&lt;/p&gt;
&lt;h2&gt;Linking&lt;/h2&gt;
&lt;p&gt;The purpose of &lt;strong&gt;linking&lt;/strong&gt; is to add information about the relation to other groups to a concept group. We mostly
do this for relations that would be hard to detect from just looking at one concept group because it is
not stored as a value in its logical entities. An example for this that we mentioned before are the buildings
a villager creates. The links in a concept group are technically just a bunch of concept-specific lists in
the Python classes. These lists are filled by iterating through all concept groups we created, each time looking
for a relation to another group and appending the group to the list asspociated with the relation type.&lt;/p&gt;
&lt;p&gt;&lt;img alt="GenieUnitLineGroup UML" src="https://blog.openage.dev/images/T0004-group-object-linking.svg"&gt;&lt;/p&gt;
&lt;p&gt;(This is the same &lt;code&gt;GenieUnitLineGroup&lt;/code&gt; class as shown above, this time with linked information visible.
&lt;code&gt;creates&lt;/code&gt; stores the building lines created by the villager, &lt;code&gt;garrison_locations&lt;/code&gt; the places where it
can garrison.
Note that these links are also stored as lists, but in contrast to &lt;code&gt;line&lt;/code&gt; which stores references to
&lt;code&gt;GenieUnit&lt;/code&gt;s, links will usually reference group instances.)&lt;/p&gt;
&lt;p&gt;Linking is not as important as grouping, but it saves us a lot of runtime when a relation is relavant more than
once. It also ensures that every concept group has all information it needs for conversion available in the
Python object instance and (theoretically) does not need to search the rest of the dataset for information.&lt;/p&gt;
&lt;p&gt;Now that we have prepared the data for conversion, we can finally start to translate it to the nyan API.&lt;/p&gt;
&lt;h2&gt;To be continued...&lt;/h2&gt;
&lt;p&gt;The series will continue soon with another blogpost about the converter. Next time we will start to look at
the most important step in the conversion process: the nyan object creation.&lt;/p&gt;
&lt;p&gt;If you have any questions regarding this blogpost or you are eager to help developing openage make sure to pass by in &lt;strong&gt;&lt;a href="https://github.com/SFTtech/openage/discussions"&gt;our discussion board&lt;/a&gt;&lt;/strong&gt;. You can also check the weekly development news on &lt;a href="https://reddit.com/r/openage"&gt;our subreddit&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="nyan"></category><category term="converter"></category><category term="assets"></category></entry><entry><title>The openage Converter - Part I: Reading Data</title><link href="https://blog.openage.dev/the-openage-converter-part-i-reading-data.html" rel="alternate"></link><published>2020-03-13T00:00:00+01:00</published><updated>2020-03-13T00:00:00+01:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2020-03-13:/the-openage-converter-part-i-reading-data.html</id><summary type="html">&lt;p&gt;We present the structure of the new converter and how we read data from .dat files.&lt;/p&gt;</summary><content type="html">&lt;p&gt;In our &lt;a href="https://blog.openage.dev/d0-openage-modding-api-introduction.html"&gt;previous blogpost series&lt;/a&gt; about the openage modding API, we outlined how AoE-like gameplay mechanics will be implemented in openage and how they are modeled in our dedicated database language &lt;code&gt;nyan&lt;/code&gt;. However, one issue with creating a new modding interface from the ground up is that we cannot directly use the data files from the original games. We have to convert them to our own logic and formats for them to work with the openage engine. This process is what this new blogpost series will be about.&lt;/p&gt;
&lt;p&gt;Today's topic will be the overall structure of the new Python converter and its data reading module. There will be at least two more blogposts in the next week, covering the transformation from AoE2 structs to nyan API objects and the export to the file formats.&lt;/p&gt;
&lt;h1&gt;Converter Workflow&lt;/h1&gt;
&lt;p&gt;&lt;img alt="Structogram" src="https://blog.openage.dev/images/T0003-converter-structure.svg"&gt;&lt;/p&gt;
&lt;p&gt;Every game or game edition we convert will go through 3 different stages: &lt;strong&gt;&lt;em&gt;Reader&lt;/em&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;em&gt;Processor&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;Exporter&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In the &lt;em&gt;Reader&lt;/em&gt;, we parse data or media files and put them into a structured format that we can use during conversion. The content read is passed onto the &lt;em&gt;Processor&lt;/em&gt; where the actual conversion takes place. Here, the data are first organized into conversion objects that resemble the original games structure (AoE-like objects). These are transitioned into objects that model the openage API (API-like objects) and then put into nyan API objects that can be exported to file. An &lt;em&gt;Exporter&lt;/em&gt; will take the converted objects and sort them into modpacks. The very last stage of the conversion is printing the objects to nyan files and other human-readable formats along with requested media files.&lt;/p&gt;
&lt;p&gt;Every stage is modular which means it can easily be exchanged or replaced. This comes in handy when we have to consider the multiple releases of AoE1 and AoE2. For example, the Definitive Edition of AoE1 will use an extended Processor stage compared to the original version of AoE1 due to the presence of new features and different mechanics. With the modular approach we can do a lot of code sharing and do not have to build a new converter for every edition of a game.&lt;/p&gt;
&lt;p&gt;Note that from this point onwards we will exclusively talk about data conversion, or more specifically, converting gamedata from the &lt;code&gt;empires*.dat&lt;/code&gt; files. Media conversion is a separate topic that we will leave out for now and maybe describe in an additional blogpost in the future.&lt;/p&gt;
&lt;h2&gt;Reading and Storing&lt;/h2&gt;
&lt;p&gt;Our first goal in the conversion process is to access the data and load it into the converter in a usable format. Since AoE2's &lt;code&gt;.dat&lt;/code&gt; file uses a binary format, we have to &lt;em&gt;serialize&lt;/em&gt; the values before we can do anything with them. In this case, serialization means that we traverse the file byte by byte, extracting the values and storing them as Python structs. The format has been well documented over the years, so we know exactly at which offset what attribute can be found.&lt;/p&gt;
&lt;p&gt;When we encounter an attribute value in the &lt;code&gt;.dat&lt;/code&gt; file we have to worry about two things: How we &lt;strong&gt;read&lt;/strong&gt; it and how we &lt;strong&gt;store&lt;/strong&gt; it. The distinction between those two is a result of the different contraints values from the &lt;code&gt;.dat&lt;/code&gt; file and values in our own database language &lt;code&gt;nyan&lt;/code&gt; have. For example - depending on the attribute - integers in the &lt;code&gt;.dat&lt;/code&gt; file can differ in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Length&lt;/strong&gt;: An integer may be stored with length 8 Bit (&lt;code&gt;int8&lt;/code&gt;), 16 Bit (&lt;code&gt;int16&lt;/code&gt;) or 32 Bit (&lt;code&gt;int32&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Signing&lt;/strong&gt;: Integers may have 1 prefix Bit to signal a negative value (&lt;code&gt;signed int&lt;/code&gt;) or not (&lt;code&gt;unsigned int&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Therefore, we have to specify the correct read type for every attribute in the &lt;code&gt;.dat&lt;/code&gt;. Otherwise we would get the wrong values.&lt;/p&gt;
&lt;p&gt;Additionally, even if two attributes have the same read type, we might want to use a different storage type depending on the context the attribute is used in. For example, the converter used different storage types for attributes representing unit stats (e.g. HP, movement speed, damage vaues, ...) and resource IDs (e.g. sound or animation IDs). This becomes relevant when we want to compare two units later on to calculate upgrades or when we want to determine the differences between vanilla AoE2 and a user made data mod.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Read type and Storage type" src="https://blog.openage.dev/images/T0003-read-to-value-member.svg"&gt;&lt;/p&gt;
&lt;p&gt;In our code, the serialization of the attributes looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;dataformat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;READ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;hit_points&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StorageType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INT_MEMBER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;int16_t&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;READ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;line_of_sight&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StorageType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FLOAT_MEMBER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;float&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;READ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;dead_unit_id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StorageType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID_MEMBER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;int16_t&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IGNORE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;hidden_in_editor&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StorageType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BOOLEAN_MEMBER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;int8_t&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IGNORE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;old_portrait_icon_id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StorageType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID_MEMBER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;int16_t&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;READ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;enabled&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StorageType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BOOLEAN_MEMBER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;int8_t&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;READ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;resource_cost&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StorageType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ARRAY_CONTAINER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SubdataMember&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;ref_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ResourceCost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For every attribute in the &lt;code&gt;.dat&lt;/code&gt; file, the &lt;em&gt;Reader&lt;/em&gt; module contains a 4-tuple that stores its read mode, attribute name, storage type and read type.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read Mode&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This specifies whether we want to actually read the value (&lt;code&gt;READ&lt;/code&gt;) or skip over it (&lt;code&gt;IGNORE&lt;/code&gt;). The latter read mode is used for values that are irrelevant for conversion. A lot of the time these are leftovers from old beta versions (e.g. &lt;code&gt;old_portrait_icon_id&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Attribute Name&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A human-readable name for the attribute. This name will be used in the &lt;em&gt;Processor&lt;/em&gt; stage to address them and read their values.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Storage Type&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here we tell the &lt;em&gt;Reader&lt;/em&gt; which storage type it should use for an attribute. Every type corresponds to a &lt;code&gt;ValueMember&lt;/code&gt; subclass object that stores the attribute name, its value and its storage type. &lt;code&gt;ValueMember&lt;/code&gt; also implements an auxiliary method for diffing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read Type&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This determines what read type we have to use to extract the correct attribute value from the &lt;code&gt;.dat&lt;/code&gt; file. We can either refer to primitive types such as integers or floats, but we are also able to use nested dataformat definitions, like &lt;code&gt;ResourceCost&lt;/code&gt; in the code sample above. Nested definitions contain another list of 4-tuples which are read sequentially. Employing these definitions is very helpful for repeating structs as it lets us define its dataformat once and read it as many times as we want.&lt;/p&gt;
&lt;h2&gt;Organizing&lt;/h2&gt;
&lt;p&gt;After reading the &lt;code&gt;.dat&lt;/code&gt; file, we receive a full representation of its content in an array of &lt;code&gt;ValueMember&lt;/code&gt; instances. While the data dump we receive from the &lt;em&gt;Reader&lt;/em&gt; already contains all the attributes and values we need later on, this output is too unstructured to be handled efficiently yet. If possible, we would like to operate on logical entities we know from the game like units, buildings, civs or terrains, instead of cherry picking from a giant array of attributes.&lt;/p&gt;
&lt;p&gt;To do this, we transform the dumped values into converter objects that resemble the structure used in the original engine (hence &lt;em&gt;AoE-like&lt;/em&gt; objects). These objects (&lt;code&gt;GenieObject&lt;/code&gt;s) are very similar to what you would see in Advanced Genie Editor, just without the fancy GUI. For example, we put every &lt;code&gt;ValueMember&lt;/code&gt; attribute belonging to an AoE2 unit into a &lt;code&gt;GenieUnit&lt;/code&gt; object. The same process is repeated for every unit and every other logical structure that we can recognize in the game. Afterwards, each attribute will be assigned to an appropriate &lt;code&gt;GenieObject&lt;/code&gt; subclass. Every subclass instances receives its own list in a container which can be accessed in the &lt;em&gt;Processor&lt;/em&gt; stage.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Dump to GenieObjects" src="https://blog.openage.dev/images/T0003-dump-to-genie-objects.svg"&gt;&lt;/p&gt;
&lt;p&gt;Not only is this object-oriented approach much easier to work with, we also no longer have to worry about where exactly logical entities, e.g. units, are located in the dump. Thus we can focus purely on its content and leave the legacy of the &lt;code&gt;.dat&lt;/code&gt; file structure behind.&lt;/p&gt;
&lt;h2&gt;To be continued...&lt;/h2&gt;
&lt;p&gt;That's it for now. We will continue next time when we transform data from the older AoE-like structure to the openage API.&lt;/p&gt;
&lt;p&gt;If you have any questions regarding this blogpost or you are eager to help developing openage make sure to pass by in &lt;strong&gt;&lt;a href="https://github.com/SFTtech/openage/discussions"&gt;our discussion board&lt;/a&gt;&lt;/strong&gt;. You can also check the weekly development news on &lt;a href="https://reddit.com/r/openage"&gt;our subreddit&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="nyan"></category><category term="converter"></category><category term="assets"></category></entry><entry><title>D14: Openage modding API - Finale</title><link href="https://blog.openage.dev/d14-openage-modding-api-finale.html" rel="alternate"></link><published>2019-06-26T00:00:00+02:00</published><updated>2019-06-26T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2019-06-26:/d14-openage-modding-api-finale.html</id><summary type="html">&lt;p&gt;We look back at our API changes and summarize the new features&lt;/p&gt;</summary><content type="html">&lt;p&gt;Over the last year, we have introduced a lot of features to our API and spent a lot of time polishing and improving its core concepts. But as an old Chinese saying goes: "You have to let go, otherwise you will never finish the converter and jj will be unhappy". So today, we finally present you the first release version of the &lt;em&gt;openage Modding API&lt;/em&gt; tree and will talk a little bit about the features that come with it.&lt;/p&gt;
&lt;p&gt;We present you the result of hours of thought and discussions &lt;strong&gt;(Open picture in new tab to enlarge)&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt="modding API tree v0.2" src="https://blog.openage.dev/images/D0014-API-tree-0.2.svg"&gt;&lt;/p&gt;
&lt;h2&gt;Our Feature Set&lt;/h2&gt;
&lt;p&gt;As a baseline, everything that is and was possible in previous Genie Engine release versions will also be supported in the openage modding API. This includes all features from Age of Empires 1, Age of Empires 2 and Star Wars: Galactic Battlegrounds. Most of them have been reworked to provide better accessibility to modding, but the original behaviour can always be replicated.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Additionally&lt;/strong&gt;, the API provides these new exciting possibilities:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Modular ability and bonus system for units, buildings and other game objects&lt;/strong&gt;&lt;br/&gt;
Every ingame object, whether it is a unit, a building or part of the ambient scenery, is able to use any ability the API provides. This makes units much more flexible and enables modders to implement behaviour known from other games, e.g. Age of Mythology, such as mobile/movable dropoff points and military units constructing buildings. And of course other more crazy combinations are also possible:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Trading with trees or birds&lt;/li&gt;
&lt;li&gt;Shooting houses as projectiles&lt;/li&gt;
&lt;li&gt;Let relics research special techs and fight in combat&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Nonlinear tech trees&lt;/strong&gt;&lt;br/&gt;
Techs can be unlocked through alternative paths and are not necessarily bound to Age Upgrades. The upgrade path can be different for every civilization or game mode. It also allows giving players the choice to select one out of two (or more) upgrades for a unit, e.g. a decision between more attack damage and faster reload speed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Proper inventories and item systems&lt;/strong&gt;&lt;br/&gt;
Relics will no longer replace the monk unit when picked up. Instead, the API unifies garrisoning, transporting and inventories with a new container system that give units the ability to store other game entities properly. Items and garrisoned units are allowed to grant new abilities or remove existing ones.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Enable different abilities depending on the unit's state&lt;/strong&gt;&lt;br/&gt;
Like the trebuchet from AoE2, all game objects can have multiple states which activate other abilities and give different boni or mali. Modders will be able to define as many transformation states as they like. Additionally, construction, damage and harvest progress are able to change the state of the unit. For example, this can be used to make a building's armor weaker when it is not fully constructed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Combine effects such as damage, convert or heal&lt;/strong&gt;&lt;br/&gt;
Effects in the API are just as modular as our ability and modifier system. Any unit can apply any effect and is allowed to combine them freely. As an example, modders will be able to create attacks that do damage and also have a chance to convert the unit.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Techs and civ bonuses affect more diplomatic stances&lt;/strong&gt;&lt;br/&gt;
In AoE, your civ choice grants bonuses to the whole team. But what if your enemies would profit too? In our API, civs are allowed to define modifiers for other players that have a different stance than "friendly". Additionally, techs can influence not only yourself, but also others on the same map. Abilities and effects are also allowed to be limited to specific diplomatic stances which enables more specialized diplomacy such as overlord-vassal relationships.&lt;/p&gt;
&lt;p&gt;These are the most prominent features that we support. There are a lot of other helpful features that were either too small or too complex to mention. Be sure to check out our &lt;a href="https://blog.openage.dev/landing-page.html"&gt;previous blogposts&lt;/a&gt; if you are interested in more thorough explanations of the underlying mechanics.&lt;/p&gt;
&lt;h2&gt;What happens next?&lt;/h2&gt;
&lt;p&gt;We will stop thinking about new features for a while and integrate the existing API into the engine. The core engine parts that need to be worked on are the &lt;em&gt;core gamestate&lt;/em&gt; and the &lt;em&gt;converter&lt;/em&gt;. The gamestate needs to be able to understand the API objects and implement the behavior for abilities and modifiers. Our converter can already read the &lt;code&gt;.dat&lt;/code&gt; files of the original game and now needs to sort the old data into our nyan API tree.&lt;/p&gt;
&lt;p&gt;Roadmap for integration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The converter will be changed to create nyan API objects and assemble them as a modpack&lt;/li&gt;
&lt;li&gt;In parallel, the engine will be extended to load API objects and implement their intended behavior&lt;/li&gt;
&lt;li&gt;Once everything works, write a modding guide and tutorials&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let's do it!&lt;/p&gt;
&lt;h2&gt;Trivia&lt;/h2&gt;
&lt;p&gt;As a bonus, here is nice collection of fun and pointless facts about the API and its development.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The initial attempt at the API (April/May 2018):&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="API draft 1" src="https://blog.openage.dev/images/D0014-API-draft-1.png"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The API contains &lt;strong&gt;282 individual objects&lt;/strong&gt; of which &lt;strong&gt;58 are abilities&lt;/strong&gt;, &lt;strong&gt;34 are modifiers&lt;/strong&gt; and &lt;strong&gt;13 are effects&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;There are &lt;strong&gt;36 passive&lt;/strong&gt; and &lt;strong&gt;22 active abilities&lt;/strong&gt; (considering their functionality).&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Member type&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;bool&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;int&lt;/td&gt;
&lt;td&gt;47&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;float&lt;/td&gt;
&lt;td&gt;59&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;text&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;file&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;set&lt;/td&gt;
&lt;td&gt;126&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;orderedset&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;nyan::Object&lt;/td&gt;
&lt;td&gt;130&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;389&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;The only ability from the first draft that survived until today is &lt;code&gt;Fly&lt;/code&gt;. All other abilities have been reworked.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ShootProjectile&lt;/code&gt; has the &lt;strong&gt;most members&lt;/strong&gt; (18) of any API object.&lt;/li&gt;
&lt;li&gt;The object with the &lt;strong&gt;longest name&lt;/strong&gt; is &lt;code&gt;RelativeProjectileAmountModifier&lt;/code&gt; (32 characters). In contrast, the &lt;strong&gt;shortest object name&lt;/strong&gt; is &lt;code&gt;Mod&lt;/code&gt; (3 characters).&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;maximum depth&lt;/strong&gt; of the API tree is 5 which is the longest inheritance distance between the root object &lt;code&gt;Entity&lt;/code&gt; and the children of &lt;code&gt;FlatAttributeChangeModifier&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Even though nyan supports multiple inheritance, none of the API objects currently use it (this was not always the case). The small number of dependencies makes the API more robust to changes. However, mods using the API are expected to make extensive use of multi-inheritance.&lt;/li&gt;
&lt;li&gt;The lack of multiple inheritance means that the API is indeed a tree and not just a graph.&lt;/li&gt;
&lt;li&gt;The number of units from AoE2 will be reduced from 58 to 28 (excluding unique and cheat units) in the API. This is because we do not store upgraded units as separate ojects, but as patches to the original unit.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Questions?&lt;/h1&gt;
&lt;p&gt;Questions? We probably know the answer! Ask us something about the blogpost by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="nyan"></category><category term="modding"></category><category term="API"></category></entry><entry><title>D13: Openage modding API - Diplomatic Stances (+ more updates)</title><link href="https://blog.openage.dev/d13-openage-modding-api-diplomatic-stances-more-updates.html" rel="alternate"></link><published>2019-03-01T00:00:00+01:00</published><updated>2019-03-01T00:00:00+01:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2019-03-01:/d13-openage-modding-api-diplomatic-stances-more-updates.html</id><summary type="html">&lt;p&gt;Introducing new features that concentrate on the diplomatic relationship between players&lt;/p&gt;</summary><content type="html">&lt;p&gt;It's time for another update on the latest changes and this time, they primarily deal with the relationships between players. In previous blogposts, we always assumed that an ability already indirectly defines whether it can be used against friend or foe. However, this is often not as obvious as it seems, especially after the introduction of the &lt;code&gt;ApplyEffect&lt;/code&gt; ability (see our &lt;a href="https://blog.openage.dev/openage-modding-api-effects.html"&gt;last blogpost&lt;/a&gt;) which can be used for friendly actions like healing or hostile actions such as attacking. Our solution to this problem is the addition of &lt;em&gt;diplomatic stances&lt;/em&gt; which we will now discuss in detail.&lt;/p&gt;
&lt;p&gt;Other interesting articles in the modding API series:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d0-openage-modding-api-introduction.html"&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d7-openage-modding-api-too-many-villagers.html"&gt;Too many villagers!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d8-openage-modding-api-the-transformers.html"&gt;Transform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d10-openage-modding-api-restocking-farms.html"&gt;Restocking farms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/openage-modding-api-effects.html"&gt;Effects&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://blog.openage.dev/landing-page.html"&gt;View all articles&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Diplomacy and abilities&lt;/h2&gt;
&lt;p&gt;&lt;img alt="DiplomaticAbility" src="https://blog.openage.dev/images/D0013-diplo-ability.png"&gt;&lt;/p&gt;
&lt;p&gt;The core concept behind diplomatic stances is that they decide what abilities can be used on another player's units. This is realised through the new &lt;code&gt;DiplomaticAbility&lt;/code&gt; API object. Any ability that inherits from &lt;code&gt;DiplomaticAbility&lt;/code&gt; can only be used with/against units of players with the corresponding diplomatic stances defined in the member &lt;code&gt;stances&lt;/code&gt;. A really simple example is the &lt;code&gt;Attack&lt;/code&gt; ability from the example above that can only be used against units from players where the stance is set to &lt;code&gt;Enemy&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It is important to stress that the openage API only defines one built-in stance (&lt;code&gt;Self&lt;/code&gt;). &lt;code&gt;Self&lt;/code&gt; is a special stance that implies an abilitiy can be used on the player's own units, if added to the set of &lt;code&gt;stances&lt;/code&gt; of a &lt;code&gt;DiplomaticAbility&lt;/code&gt;. This can be used for active abilities like &lt;code&gt;Heal&lt;/code&gt;, but also for more passive ones like &lt;code&gt;DropSite&lt;/code&gt; which enables a &lt;code&gt;GameEntity&lt;/code&gt; to be a resource dropoff point. All other stances have to be defined by the mod or game they are part of. In the case of AoE2 these stances would be &lt;code&gt;Ally&lt;/code&gt;, &lt;code&gt;Neutral&lt;/code&gt;, &lt;code&gt;Enemy&lt;/code&gt; and possibly &lt;code&gt;Gaia&lt;/code&gt; for the special relationship with wildlife.&lt;/p&gt;
&lt;p&gt;Although players in AoE2 usually have the same stance towards each other, there is the potential to be more creative with diplomacy. For example, the stance system makes it possible to have vassal-overlord relationships where the overlord can use special abilities on its vassal, e.g. forcefully conscript the subject's units or collect tribute.&lt;/p&gt;
&lt;p&gt;It should be noted that inheriting from &lt;code&gt;DiplomaticAbility&lt;/code&gt; is entirely optional and by default, every ability works with all diplomatic stances.&lt;/p&gt;
&lt;h2&gt;Diplomacy elsewhere&lt;/h2&gt;
&lt;p&gt;&lt;img alt="DiplomaticEffect" src="https://blog.openage.dev/images/D0013-diplo-effect.png"&gt;&lt;/p&gt;
&lt;p&gt;Abilities are not the only useful application for diplomatic stances. Another use case are the &lt;code&gt;Effects&lt;/code&gt; that we introduced last time. If you recall, effects define a form of interaction (damaging, healing, converting, etc.) between two or more game entities. In some situations, the effect should only apply to units of players with a specific stance. For example, the kamikaze attacks of the petard and the demolition ship only do damage to enemy units. Similarly, projectiles usually do not damage friendly units with the exception of onager shots.&lt;/p&gt;
&lt;p&gt;The problem is solved by introducing a &lt;code&gt;DiplomaticEffect&lt;/code&gt; that works in the same way as &lt;code&gt;DiplomaticAbility&lt;/code&gt;. By making an &lt;code&gt;Effect&lt;/code&gt; inherit from &lt;code&gt;DiplomaticEffect&lt;/code&gt;, the effect will now only be applied to units of players that are covered by the diplomatic stances in the &lt;code&gt;stances&lt;/code&gt; member. &lt;code&gt;Effect&lt;/code&gt;s that do not inherit from &lt;code&gt;DiplomaticEffect&lt;/code&gt; will be applied regardless of the stance of the target.&lt;/p&gt;
&lt;p&gt;&lt;img alt="DiplomaticPatch" src="https://blog.openage.dev/images/D0013-diplo-patch.png"&gt;&lt;/p&gt;
&lt;p&gt;On the side of smaller changes, there is the new &lt;code&gt;DiplomaticPatch&lt;/code&gt; type. Before, patches in a &lt;code&gt;Tech&lt;/code&gt; only upgraded the game entities of the player who researched the technology. &lt;code&gt;DiplomaticPatch&lt;/code&gt; lets you define upgrades that can also apply to other players. These could be very fun to experiment with, as technologies are now able to influence enemies and allies alike.&lt;/p&gt;
&lt;p&gt;&lt;img alt="DiplomaticSetup" src="https://blog.openage.dev/images/D0013-diplo-setup.png"&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Civilization&lt;/code&gt; object previously contained a &lt;code&gt;team_setup&lt;/code&gt; member that stored the team boni that were applied to other team members in AoE2 games. Since the API now supports diplomatic stances directly, we have opted for a more fine-grained and flexible solution. &lt;code&gt;team_setup&lt;/code&gt; is superseded by the &lt;code&gt;DiplomaticSetup&lt;/code&gt; objects in &lt;code&gt;diplo_setup&lt;/code&gt;. &lt;code&gt;diplo_setup&lt;/code&gt; can store as many objects as necessary, so it is possible to define a setup for every existing stance, if required. As an interesting side effect, a civilization could also give boni/mali to its enemies.&lt;/p&gt;
&lt;h2&gt;Side notes (Container ability)&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Storage ability" src="https://blog.openage.dev/images/D0013-storage-ability.png"&gt;&lt;/p&gt;
&lt;p&gt;Last but not least, there is something else to discuss which is somewhat related to diplomatic stances. In &lt;a href="https://blog.openage.dev/d6-openage-modding-api-inventory-system.html"&gt;blogpost No. 7&lt;/a&gt; we introduced the &lt;code&gt;Inventory&lt;/code&gt; ability to provide a way  for units to store items like the relic rather than merging with them. Back then, Reddit-user Kaligule &lt;a href="https://www.reddit.com/r/openage/comments/9blg1k/openage_modding_api_inventory_system/e554xpx/"&gt;pointed out that transport ships, rams and siege towers&lt;/a&gt; (and garrisoning in general) could potentially be modelled the same way. However, at the time the API could not have supported this because &lt;code&gt;Inventory&lt;/code&gt; relied on items being neutral game entities that did not belong to a specific player.&lt;/p&gt;
&lt;p&gt;With the addition of diplomatic stances, there are no more excuses to keep &lt;code&gt;Inventory&lt;/code&gt; and &lt;code&gt;Garrison&lt;/code&gt; as separate abilities. Hence, they were merged into the &lt;code&gt;Storage&lt;/code&gt; ability. &lt;code&gt;Storage&lt;/code&gt; is essentially the same as &lt;code&gt;Inventory&lt;/code&gt;, so there is nothing special to tell about it that was not discussed before. A side effect of &lt;code&gt;Storage&lt;/code&gt; being a &lt;code&gt;DiplomaticAbility&lt;/code&gt; is that you can put other player's units in inventories now, which will make creating Pokemon game modes for AoE2 a bit easier.&lt;/p&gt;
&lt;p&gt;So as always: Do not hesitate to suggest improvement ideas on Reddit. It's encouraged to question the devs, it just takes long to implement :)&lt;/p&gt;
&lt;h1&gt;Questions?&lt;/h1&gt;
&lt;p&gt;Do you still have questions? Then let us know and discuss them with us and the community by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="nyan"></category><category term="modding"></category><category term="API"></category></entry><entry><title>Openage modding API - Effects</title><link href="https://blog.openage.dev/openage-modding-api-effects.html" rel="alternate"></link><published>2019-01-27T00:00:00+01:00</published><updated>2019-01-27T00:00:00+01:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2019-01-27:/openage-modding-api-effects.html</id><summary type="html">&lt;p&gt;A new way of interaction between game entities&lt;/p&gt;</summary><content type="html">&lt;p&gt;A recent discussion on how the &lt;code&gt;Convert&lt;/code&gt; ability should work brought up the question how we want to handle interaction between different game entities. In our previous drafts, every interaction had its own ability. This aproach works, but inevitably creates redundancy. We introduced a new mechanic in form of &lt;code&gt;Effect&lt;/code&gt; objects to address these issues and hopefully make the engine even more extensible along the way.&lt;/p&gt;
&lt;p&gt;Other interesting articles in the modding API series:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d0-openage-modding-api-introduction.html"&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d1-openage-modding-api-units-buildings-more.html"&gt;Units, Buildings &amp;amp; more&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d2-openage-modding-api-abilities.html"&gt;Abilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d3-openage-modding-api-patching.html"&gt;Patching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d4-openage-modding-api-archers-dont-kill-units-projectiles-do.html"&gt;Attack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d5-openage-modding-api-bonus.html"&gt;Bonus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d6-openage-modding-api-inventory-system.html"&gt;Inventory System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d7-openage-modding-api-too-many-villagers.html"&gt;Too many villagers!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d8-openage-modding-api-the-transformers.html"&gt;Transform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d9-openage-modding-api-civilizations-and-uniqueness.html"&gt;Civilizations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d10-openage-modding-api-restocking-farms.html"&gt;Restocking farms&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="https://blog.openage.dev/landing-page.html"&gt;View all articles&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Many abilities, many overlaps&lt;/h1&gt;
&lt;p&gt;&lt;img alt="Old interactive abilities" src="https://blog.openage.dev/images/D0012-old-abilities.png"&gt;&lt;/p&gt;
&lt;p&gt;The main problem with our interaction abilities is the lack of consistency in their mechanics. Some -- like &lt;code&gt;Heal&lt;/code&gt; or &lt;code&gt;Repair&lt;/code&gt; -- are one-sided as the outcome is solely decided by the unit that executes the ability, while others such as &lt;code&gt;Attack&lt;/code&gt; are two-sided with the final attack value depending on both the attacker and the defender. Also, there are specialized abilities for the purpose of activating a &lt;code&gt;ResourceSpot&lt;/code&gt; like the &lt;code&gt;Hunt&lt;/code&gt; ability. And of course there's &lt;code&gt;Convert&lt;/code&gt; with &lt;a href="https://www.aoezone.net/threads/how-monks-really-work-v-2-all-the-details.119879/#post-470767"&gt;weird and ridiculous rules&lt;/a&gt; (thanks go out to Jineapple who figured all of this out).&lt;/p&gt;
&lt;p&gt;One major drawback of having different behaviors for every interaction is that they are not compatible with each other. It is not possible to have an &lt;code&gt;Attack&lt;/code&gt; that does damage &lt;strong&gt;and&lt;/strong&gt; has a chance to convert for example. The idea behind the reorganization of abilities into an effect-based system is to eliminate these incompatabilities and to make combinations of different effects possible.&lt;/p&gt;
&lt;h1&gt;Effect and Resistance&lt;/h1&gt;
&lt;p&gt;The new system draws heavy inspiration from the old attack definition described in &lt;a href="https://blog.openage.dev/d4-openage-modding-api-archers-dont-kill-units-projectiles-do.html"&gt;blogpost No. 5&lt;/a&gt;. It is recommended that you read the whole article if you haven't already.&lt;/p&gt;
&lt;p&gt;&lt;img alt="New effect system" src="https://blog.openage.dev/images/D0012-effect-resistance.png"&gt;&lt;/p&gt;
&lt;p&gt;Every interaction is now two-sided and modeled through a pair of &lt;code&gt;Effect&lt;/code&gt; and &lt;code&gt;Resistance&lt;/code&gt;. The &lt;code&gt;Effect&lt;/code&gt;s are defined by the applicant of the effect, while the &lt;code&gt;Resistance&lt;/code&gt; is always defined by the unit the effect is applied on. For convenience sake, we will call the two sides "effector" and "resistor" from now on.&lt;/p&gt;
&lt;p&gt;The mechanics that were previously tied to abilities are now defined as generic effects and resistances, albeit with different names. For example, the &lt;code&gt;ArmorAttack&lt;/code&gt; and &lt;code&gt;ArmorDefense&lt;/code&gt; objects previously used for the &lt;code&gt;Attack&lt;/code&gt; ability are now covered by &lt;code&gt;FlatAttributeChange&lt;/code&gt; (on the left) and &lt;code&gt;FlatAttributeResistance&lt;/code&gt; (on the right). Despite the bulky object names, attacking still works the same way as before. Newly added are &lt;code&gt;ChanceEffect&lt;/code&gt;s, which can be used for conversion, and &lt;code&gt;MakeHarvestable&lt;/code&gt; that makes &lt;code&gt;ResourceSpot&lt;/code&gt;s accessible to villagers.&lt;/p&gt;
&lt;p&gt;One important mechanic that was carried over from the attack system is that the application of an &lt;code&gt;Effect&lt;/code&gt; by an effector always requires the corresponding &lt;code&gt;Resistance&lt;/code&gt; on the resistor's side. For example, if a resistor has no &lt;code&gt;ConversionResistance&lt;/code&gt; defined, it &lt;strong&gt;cannot&lt;/strong&gt; be converted with the &lt;code&gt;Conversion&lt;/code&gt; effect. This is slightly counterintuitive, but makes giving units immunities much easier. If you want a conversion with zero resistance, this can instead be done by assigning a &lt;code&gt;ConversionResistance&lt;/code&gt; object with &lt;code&gt;chance_resist&lt;/code&gt; set to 0 to the resistor.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Effect&lt;/code&gt; and &lt;code&gt;Resistance&lt;/code&gt; objects can usually be used both ways. Either for the benefit or for the disadvantage of the targeted game entity. For example, setting a positive value for &lt;code&gt;change_value&lt;/code&gt; in &lt;code&gt;FlatAttributeChange&lt;/code&gt; will damage a unit, while a negative value essentially be a heal. To prevent a heal from accidently damaging the resistor, modders can define minimum and maximum value limits for an &lt;code&gt;Effect&lt;/code&gt;. This is entirely optional, so you can also choose not to and let everything go haywire.&lt;/p&gt;
&lt;p&gt;Calculation examples can be found in the Addenndum section at the bottom of the article.&lt;/p&gt;
&lt;h2&gt;Discrete vs. Continuous&lt;/h2&gt;
&lt;p&gt;The current effects can come in two forms, &lt;em&gt;discrete&lt;/em&gt; and &lt;em&gt;continuous&lt;/em&gt;. &lt;code&gt;DiscreteEffect&lt;/code&gt;s are applied immediatly &lt;em&gt;at a specific point&lt;/em&gt; in time. &lt;code&gt;ContinuousEffect&lt;/code&gt;s on the other hand happen &lt;em&gt;over time&lt;/em&gt; at a defined rate (e.g. reduction of attribute points per second). The differentiation is necessary because an ability using &lt;code&gt;DiscreteEffect&lt;/code&gt; needs to define the application interval which is not necessary for &lt;code&gt;ContinuousEffect&lt;/code&gt;. Examples for the application of a &lt;code&gt;ContinuousEffect&lt;/code&gt; in Age of Empires include healing and repairing. &lt;/p&gt;
&lt;h2&gt;The new abilities&lt;/h2&gt;
&lt;p&gt;&lt;img alt="New exciting abilities" src="https://blog.openage.dev/images/D0012-effect-abilities.png"&gt;&lt;/p&gt;
&lt;p&gt;With the introduction of effects, the interaction abilities are subject to a lot of changes, too. As we can cover most of them with an &lt;code&gt;Effect&lt;/code&gt;, the &lt;code&gt;Convert&lt;/code&gt;, &lt;code&gt;Heal&lt;/code&gt; and &lt;code&gt;Repair&lt;/code&gt; ability do not need to be part of the API anymore, indicated by their white color. Instead, they are from now on handled as derivatives of &lt;code&gt;ApplyDiscreteEffect&lt;/code&gt; and &lt;code&gt;ApplyContinuousEffect&lt;/code&gt; shown in the centre of the diagram. For example, implementing the old &lt;code&gt;Heal&lt;/code&gt; ability would be realized by inheriting &lt;code&gt;ApplyContinuousEffect&lt;/code&gt; and defining one or more continuous &lt;code&gt;FlatAttributeChange&lt;/code&gt; effects. A dedicated &lt;code&gt;Heal&lt;/code&gt; ability is unnecessary as the needed definitions are stored in the effect. The only specific ability remaining is &lt;code&gt;DiscreteAttack&lt;/code&gt; because the API does not have a concept of diplomatic stances yet which is required for recognizing friendly fire (although this could change in a later API draft). Resistances are stored in the &lt;code&gt;Resistance&lt;/code&gt; ability (shown in the upper right corner).&lt;/p&gt;
&lt;p&gt;For every general application ability there also are two more specialized API abilities available: &lt;code&gt;AreaOfXXXEffect&lt;/code&gt; and &lt;code&gt;RangedXXXEffect&lt;/code&gt;. With &lt;code&gt;RangedXXXEffect&lt;/code&gt; one can define the minimum distance to a unit for the application of effects. &lt;code&gt;AreaOfXXXEffect&lt;/code&gt; applies the effects in an area around the effector. This was previously only modeled for attacking, but now it is available for all effects. This means that you can make super monks that convert everything around them. Neat! Because &lt;code&gt;effects&lt;/code&gt; is a set member, all abilities are able to bundle and apply multiple effects at once. &lt;/p&gt;
&lt;p&gt;The greatest advantage of this system is that it has eliminated the incompatibilities mentioned in the beginning. Delegating the behavior to individual effects allows us to derive abilities that combine them freely without being restricted to a specific type of effect. Theoretically, an ability can even apply both continuous and discrete effects by inheriting from &lt;code&gt;ApplyContinuousEffect&lt;/code&gt; and &lt;code&gt;ApplyDiscreteEffect&lt;/code&gt; simultaneously.&lt;/p&gt;
&lt;h2&gt;More to come..?&lt;/h2&gt;
&lt;p&gt;The next logical step to improve the effect system would obviously be the definition of even more effect and resistance types. Right now, the API only features 4 concrete effects and resistances and there is room for more. Extensions could be damage-over-time effects like Poison or Fire Damage as well as more creative effects like a Life Steal. Another addition would be allowing effects to attach modifiers to other units that give temporary buffs or debuffs, e.g. a Disease.&lt;/p&gt;
&lt;p&gt;There is also the question remaining whether &lt;code&gt;Gather&lt;/code&gt; and &lt;code&gt;Build&lt;/code&gt; are supposed to be effects or if they should be left as separate abilities. Both of them are candidates as they define a form of interaction, but modeling them as effects might require further depature from the way they were implemented in AoE2. Therefore, we will postpone the decision to a later date.&lt;/p&gt;
&lt;h1&gt;Questions?&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Hint&lt;/em&gt;: You can suggest your own improvement ideas on Reddit. It's not forbidden to question the devs.&lt;/p&gt;
&lt;p&gt;Do you still have questions? Then let us know and discuss them with us and the community by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on freenode.net&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Addendum: Example Calculations&lt;/h2&gt;
&lt;p&gt;Defining and calculating the result of an effect-resistance pairing is very easy and straight forward. Look at the example below for a simple interaction effect involving &lt;code&gt;FlatAttributeChange&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Effector&amp;#39;s side&lt;/span&gt;
&lt;span class="n"&gt;MeleeAttack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FlatAttributeChange&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MeleeArmor&lt;/span&gt;
    &lt;span class="n"&gt;min_change_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;max_change_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;change_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AttackAmount&lt;/span&gt;

    &lt;span class="n"&gt;AttackAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AttributeAmount&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Health&lt;/span&gt;
        &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;

    &lt;span class="n"&gt;ignore_protection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;###################################&lt;/span&gt;

&lt;span class="c1"&gt;# Resistor&amp;#39;s side&lt;/span&gt;
&lt;span class="n"&gt;MeleeResistance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FlatAttributeResistance&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MeleeArmor&lt;/span&gt;
    &lt;span class="n"&gt;block_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BlockAmount&lt;/span&gt;

    &lt;span class="n"&gt;BlockAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AttributeAmount&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Health&lt;/span&gt;
        &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The effector's attack does 4 health points of damage and the resistor blocks 1 damage, so the overall damage done is 3. Keep in mind that &lt;code&gt;Effect&lt;/code&gt; and &lt;code&gt;Resistance&lt;/code&gt; have to match up for this to work. For &lt;code&gt;FlatAttributeChange&lt;/code&gt;, the match is defined by the &lt;code&gt;type&lt;/code&gt; member of &lt;code&gt;FlatAttributeChange&lt;/code&gt;/&lt;code&gt;FlatAttributeResistance&lt;/code&gt; and the &lt;code&gt;type&lt;/code&gt; member of &lt;code&gt;AttributeAmount&lt;/code&gt;. An example where the pair doesn't match up can be seen below.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Effector&amp;#39;s side&lt;/span&gt;
&lt;span class="n"&gt;MeleeAttack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FlatAttributeChange&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MeleeArmor&lt;/span&gt;
    &lt;span class="n"&gt;min_change_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;max_change_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;change_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AttackAmount&lt;/span&gt;

    &lt;span class="n"&gt;AttackAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AttributeAmount&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Health&lt;/span&gt;
        &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;

    &lt;span class="n"&gt;ignore_protection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;###################################&lt;/span&gt;

&lt;span class="c1"&gt;# Resistor&amp;#39;s side&lt;/span&gt;
&lt;span class="n"&gt;MeleeResistance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FlatAttributeResistance&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MeleeArmor&lt;/span&gt;
    &lt;span class="n"&gt;block_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BlockAmount&lt;/span&gt;

    &lt;span class="n"&gt;BlockAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AttributeAmount&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Faith&lt;/span&gt;                   &lt;span class="c1"&gt;# &amp;lt;-- Not a match&lt;/span&gt;
        &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;type&lt;/code&gt; of &lt;code&gt;AttributeAmount&lt;/code&gt; in the effect does not match the &lt;code&gt;type&lt;/code&gt; of &lt;code&gt;AttributeAmount&lt;/code&gt; in the resistance. In this case the resistor is immune to the &lt;code&gt;MeleeAttack&lt;/code&gt; effect, but usually effector's apply more than one effect and resistor's have more than one resistance.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;
&lt;span class="normal"&gt;36&lt;/span&gt;
&lt;span class="normal"&gt;37&lt;/span&gt;
&lt;span class="normal"&gt;38&lt;/span&gt;
&lt;span class="normal"&gt;39&lt;/span&gt;
&lt;span class="normal"&gt;40&lt;/span&gt;
&lt;span class="normal"&gt;41&lt;/span&gt;
&lt;span class="normal"&gt;42&lt;/span&gt;
&lt;span class="normal"&gt;43&lt;/span&gt;
&lt;span class="normal"&gt;44&lt;/span&gt;
&lt;span class="normal"&gt;45&lt;/span&gt;
&lt;span class="normal"&gt;46&lt;/span&gt;
&lt;span class="normal"&gt;47&lt;/span&gt;
&lt;span class="normal"&gt;48&lt;/span&gt;
&lt;span class="normal"&gt;49&lt;/span&gt;
&lt;span class="normal"&gt;50&lt;/span&gt;
&lt;span class="normal"&gt;51&lt;/span&gt;
&lt;span class="normal"&gt;52&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Effector&amp;#39;s side&lt;/span&gt;
&lt;span class="n"&gt;MeleeAttack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FlatAttributeChange&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MeleeArmor&lt;/span&gt;
    &lt;span class="n"&gt;min_change_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;max_change_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;change_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AttackAmount&lt;/span&gt;

    &lt;span class="n"&gt;AttackAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AttributeAmount&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Health&lt;/span&gt;
        &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;

    &lt;span class="n"&gt;ignore_protection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="n"&gt;PierceAttack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FlatAttributeChange&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PierceArmor&lt;/span&gt;
    &lt;span class="n"&gt;min_change_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;max_change_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;change_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AttackAmount&lt;/span&gt;

    &lt;span class="n"&gt;AttackAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AttributeAmount&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Health&lt;/span&gt;
        &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

    &lt;span class="n"&gt;ignore_protection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="n"&gt;Convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChanceEffect&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Conversion&lt;/span&gt;
    &lt;span class="n"&gt;chance_success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;
    &lt;span class="n"&gt;cost_fail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;

&lt;span class="c1"&gt;###################################&lt;/span&gt;

&lt;span class="c1"&gt;# Resistor&amp;#39;s side&lt;/span&gt;
&lt;span class="n"&gt;MeleeResistance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FlatAttributeResistance&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MeleeArmor&lt;/span&gt;
    &lt;span class="n"&gt;block_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BlockAmount&lt;/span&gt;

    &lt;span class="n"&gt;BlockAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AttributeAmount&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Faith&lt;/span&gt; &lt;span class="c1"&gt;# No match&lt;/span&gt;
        &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="n"&gt;PierceResistance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FlatAttributeResistance&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PierceArmor&lt;/span&gt;
    &lt;span class="n"&gt;block_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BlockAmount&lt;/span&gt;

    &lt;span class="n"&gt;BlockAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AttributeAmount&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Health&lt;/span&gt;
        &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;

&lt;span class="n"&gt;ConversionResistance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChanceResistance&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Conversion&lt;/span&gt;
    &lt;span class="n"&gt;chance_resist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This time, multiple effects come into play. The effect &lt;code&gt;MeleeAttack&lt;/code&gt; attack has no match on the resistor's side, so it is ignored. &lt;/p&gt;
&lt;p&gt;&lt;code&gt;PierceAttack&lt;/code&gt; does match up with &lt;code&gt;PierceResistance&lt;/code&gt;, so the damage can be calculated. With a damage value of 2 and a block value of 5, the overall change to the resistor's health would be &lt;code&gt;-3&lt;/code&gt;, which is equivalent a heal of 3. Because the effector has initialized &lt;code&gt;min_change_value&lt;/code&gt; with 0, the change is rounded up to that number. As a result 0 pierce damage is done.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Convert&lt;/code&gt; also has a match (by type) on the resistor's side in form of &lt;code&gt;ConversionResistance&lt;/code&gt;. The chance is calculated by substracting &lt;code&gt;chance_resist&lt;/code&gt; from &lt;code&gt;chance_success&lt;/code&gt;, resulting in an overall chance of &lt;code&gt;0.4&lt;/code&gt; (40%) for the effector to be successful.&lt;/p&gt;</content><category term="blog"></category><category term="nyan"></category><category term="modding"></category><category term="API"></category></entry><entry><title>D11: Openage modding API - Additions and Updates</title><link href="https://blog.openage.dev/d11-openage-modding-api-additions-and-updates.html" rel="alternate"></link><published>2018-12-24T00:00:00+01:00</published><updated>2018-12-24T00:00:00+01:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2018-12-24:/d11-openage-modding-api-additions-and-updates.html</id><summary type="html">&lt;p&gt;An update on the previous blogposts&lt;/p&gt;</summary><content type="html">&lt;p&gt;Throughout the last months we made several corrections and additions affecting the modding API that were too small to discuss in one blogpost. Since quite a few changes accumulated though, we decided to bundle them and wrap up the year with a collection of mini blogposts.&lt;/p&gt;
&lt;p&gt;Other articles in the modding API series:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d0-openage-modding-api-introduction.html"&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d1-openage-modding-api-units-buildings-more.html"&gt;Units, Buildings &amp;amp; more&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d2-openage-modding-api-abilities.html"&gt;Abilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d3-openage-modding-api-patching.html"&gt;Patching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d4-openage-modding-api-archers-dont-kill-units-projectiles-do.html"&gt;Attack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d5-openage-modding-api-bonus.html"&gt;Bonus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d6-openage-modding-api-inventory-system.html"&gt;Inventory System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d7-openage-modding-api-too-many-villagers.html"&gt;Too many villagers!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d8-openage-modding-api-the-transformers.html"&gt;Transform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d9-openage-modding-api-civilizations-and-uniqueness.html"&gt;Civilizations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d10-openage-modding-api-restocking-farms.html"&gt;Restocking farms&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Game entity&lt;/h1&gt;
&lt;p&gt;&lt;img alt="Game Enitity (new)" src="https://blog.openage.dev/images/D0011-game-entity-new.png"&gt;&lt;/p&gt;
&lt;p&gt;From all of our API objects &lt;code&gt;GameEntity&lt;/code&gt; saw the most drastic changes. Firstly, the members for hitbox and language data were moved to abilities, while the &lt;code&gt;icon&lt;/code&gt; is now part of the nyan UI modding API (which is &lt;a href="https://github.com/SFTtech/openage/pull/1077"&gt;under construction&lt;/a&gt; at the moment). &lt;code&gt;Building&lt;/code&gt; also had unique members which were moved to the five new abilities &lt;code&gt;Constructable&lt;/code&gt;, &lt;code&gt;DamageableBuilbing&lt;/code&gt;, &lt;code&gt;TileRequirement&lt;/code&gt;, &lt;code&gt;Foundation&lt;/code&gt; and &lt;code&gt;TerrainRequirement&lt;/code&gt;. We hope that by outsourcing these members to abilities, game entities will become even more versatile and less restrictive in their definition.&lt;/p&gt;
&lt;p&gt;Secondly, we introduced &lt;code&gt;GameEntityType&lt;/code&gt; referenced by the member &lt;code&gt;types&lt;/code&gt; which is a new object that can be used for a broader classification of game entities. A game entity can be of several &lt;code&gt;GameEntityType&lt;/code&gt;s like &lt;code&gt;Infantry&lt;/code&gt; or &lt;code&gt;Archer&lt;/code&gt; or both. In comparison to the classes in AoE2, &lt;code&gt;GameEntityType&lt;/code&gt; is &lt;strong&gt;not&lt;/strong&gt; tied to armor and acts as an independent mechanism.&lt;/p&gt;
&lt;p&gt;Last but not least, we want to welcome &lt;code&gt;Projectile&lt;/code&gt; as the fifth &lt;code&gt;GameEntity&lt;/code&gt; category. In the &lt;a href="https://blog.openage.dev/d1-openage-modding-api-units-buildings-more.html"&gt;2. blogpost&lt;/a&gt; we declared that &lt;code&gt;Projectile&lt;/code&gt; should not be a &lt;code&gt;GameEntity&lt;/code&gt; because it does not operate independently and always needs a &lt;em&gt;host unit&lt;/em&gt; that shoots it. Howerever, we came to the conclusion that just because projectiles are dependent on their host in AoE2, this doesn't necessarily have to be the case in openage. Hence, the &lt;code&gt;Projectile&lt;/code&gt; object has emancipated itself and can now be used for other things than attacking, e.g. converting, resource gathering, repairing and more.&lt;/p&gt;
&lt;h1&gt;Resource Contingents&lt;/h1&gt;
&lt;p&gt;&lt;img alt="Resource Contingents" src="https://blog.openage.dev/images/D0011-resource-contingent.png"&gt;&lt;/p&gt;
&lt;p&gt;Another addition specifically designed for population space is &lt;code&gt;ResourceContingent&lt;/code&gt;. Contingents are resources with the additional feature that they can be used and provided &lt;em&gt;temporarily&lt;/em&gt;. In context of population space, this means that units use 1 &lt;code&gt;PopulationSpace&lt;/code&gt; resource while they are alive and free it again when they have died. Similarly, houses provide 5 &lt;code&gt;PopulationSpace&lt;/code&gt; once they are built which is available as long as they are not destroyed.&lt;/p&gt;
&lt;p&gt;Because &lt;code&gt;ResourceContingent&lt;/code&gt; is of type &lt;code&gt;Resource&lt;/code&gt;, contingents can potentially be gathered and thus &lt;em&gt;permanently&lt;/em&gt; added to the resource pool, too. This could lead to some interesting dual-use mechanics where a resource contingent is gathered first and then temporarily used. For example, one could define a resource contingent &lt;code&gt;Grain&lt;/code&gt; which has to be collected from farms, while the amount of grain is also used as the population limit. The player can then choose between&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Keep the &lt;code&gt;Grain&lt;/code&gt; for additional population space, thus being able to field more units&lt;/li&gt;
&lt;li&gt;Sell &lt;code&gt;Grain&lt;/code&gt; for &lt;code&gt;Gold&lt;/code&gt; and therefore lose room for population, but gain the potential to buy better upgrades for their units.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Attributes&lt;/h1&gt;
&lt;p&gt;&lt;img alt="Attributes" src="https://blog.openage.dev/images/D0011-attribute.png"&gt;&lt;/p&gt;
&lt;p&gt;Age of Empires 2 is not known for giving its units many attributes except HP, yet many other RTS games are more generous in that regard. Examples are mana, stamina (Battle Realms), "special" power (AoM, EE), shield (SWGB) and so on and so forth. So, instead of creating an ability for every single attribute RTS designers thought of, we generalize them with the &lt;code&gt;Attribute&lt;/code&gt; API object. The definition of attributes is very similar to that of &lt;code&gt;Resource&lt;/code&gt; which makes sense as attributes technically are resources, although only available in the scope of the unit. Abilities that cost attribute points reference &lt;code&gt;AttributeAmount&lt;/code&gt; which is an attribute's counterpart to &lt;code&gt;ResourceAmount&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For AoE2, two attributes are needed in total: &lt;code&gt;Health&lt;/code&gt; and &lt;code&gt;Faith&lt;/code&gt;. &lt;code&gt;Health&lt;/code&gt; should be self-explanatory, &lt;code&gt;Faith&lt;/code&gt; is used by monks to convert units. &lt;code&gt;Faith&lt;/code&gt; is also a &lt;code&gt;RegeneratingAttribute&lt;/code&gt; that is refilled at a defined &lt;code&gt;rate&lt;/code&gt;. In preparation for SWGB support, we also added &lt;code&gt;ProtectingAttribute&lt;/code&gt; which shields another attribute from damage. For example, if &lt;code&gt;Shield&lt;/code&gt; protects &lt;code&gt;Health&lt;/code&gt;, then the attribute points of the shield will be substracted first in case of an attack. Once the attribute points of &lt;code&gt;Shield&lt;/code&gt; reach 0, the &lt;code&gt;Health&lt;/code&gt; points of the unit start to get subtracted. Of course, we can also build longer protection chains with 3 or more attributes.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Attack (new)" src="https://blog.openage.dev/images/D0011-attack-new.png"&gt;&lt;/p&gt;
&lt;p&gt;Introducing the attribute system required reworking attacks and armor. Now &lt;code&gt;ArmorDefense&lt;/code&gt; is always connected to a specific attribute through &lt;code&gt;AttributeAmount&lt;/code&gt;. &lt;code&gt;ArmorAttack&lt;/code&gt; had a similar change so that every attack value is targeted at one specfic attribute. Optionally, &lt;code&gt;ArmorAttack&lt;/code&gt; is allowed to ignore protections from the &lt;code&gt;ignore_protections&lt;/code&gt; set. As a result, we can now have attacks in SWGB that only affect shields or ignore the shield entirely and damage the HP directly.&lt;/p&gt;
&lt;h1&gt;Training and building&lt;/h1&gt;
&lt;p&gt;&lt;img alt="Creatable" src="https://blog.openage.dev/images/D0011-game-entity-creatable.png"&gt;&lt;/p&gt;
&lt;p&gt;At last, we have made a small change to how the cost and creation time of units and buildings were managed. Before, cost and creation time were decided by the &lt;em&gt;created&lt;/em&gt; unit through the &lt;code&gt;Creatable&lt;/code&gt; ability. In our newest API draft, we delegated the decision to the &lt;em&gt;creating&lt;/em&gt; unit or more precisely, to the &lt;code&gt;Train&lt;/code&gt; and &lt;code&gt;Build&lt;/code&gt; abilities. These reference a &lt;code&gt;CreatableGameEntity&lt;/code&gt; object which stores cost, creation time, requirements and the unit/building that is created. This slight alteration should give more freedom to pricing when the same unit is produced in several different buildings.&lt;/p&gt;
&lt;h1&gt;Questions?&lt;/h1&gt;
&lt;p&gt;That's it for this time, but there will probably be more to add, change or discuss about soon.&lt;/p&gt;
&lt;p&gt;Did we leave something out or are we forgetting something important in our API? Shout at us (and discuss your ideas) by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="nyan"></category><category term="modding"></category><category term="API"></category></entry><entry><title>D10: Openage modding API - Restocking farms</title><link href="https://blog.openage.dev/d10-openage-modding-api-restocking-farms.html" rel="alternate"></link><published>2018-11-25T00:00:00+01:00</published><updated>2018-11-25T00:00:00+01:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2018-11-25:/d10-openage-modding-api-restocking-farms.html</id><summary type="html">&lt;p&gt;Renewable resources in openage with farming as an example&lt;/p&gt;</summary><content type="html">&lt;p&gt;Food takes quite an unusual role in the AoE economy as its main harvesting source from the mid-game onwards - the farm - is a &lt;em&gt;renewable&lt;/em&gt; resource spot. Other than the natural resources that are generated with the map, the farming economy relies on the constant reconstruction of the production building by the player. In this blogpost we will explain how resource spots can be restocked in openage and also how we implement the process of queueing farms in the mill.&lt;/p&gt;
&lt;p&gt;Other articles in the modding API series:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d0-openage-modding-api-introduction.html"&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d1-openage-modding-api-units-buildings-more.html"&gt;Units, Buildings &amp;amp; more&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d2-openage-modding-api-abilities.html"&gt;Abilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d3-openage-modding-api-patching.html"&gt;Patching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d4-openage-modding-api-archers-dont-kill-units-projectiles-do.html"&gt;Attack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d5-openage-modding-api-bonus.html"&gt;Bonus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d6-openage-modding-api-inventory-system.html"&gt;Inventory System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d7-openage-modding-api-too-many-villagers.html"&gt;Too many villagers!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d8-openage-modding-api-the-transformers.html"&gt;Transform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d9-openage-modding-api-civilizations-and-uniqueness.html"&gt;Civilizations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Restocking farms (you're here)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="https://blog.openage.dev/landing-page.html"&gt;View all articles&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Preliminary analysis&lt;/h1&gt;
&lt;p&gt;Before go into detail about the concrete API implementation, we should make clear how the farming economy from AoE2 works on an abstract level. For that purpose we prepared a simple diagram.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Farming BPMN" src="https://blog.openage.dev/images/D0010-farm-bpmn.svg"&gt;&lt;/p&gt;
&lt;p&gt;Note that we leave out unimportant aspects such as delivering food to a drop site or deleting the building. We focus solely on the standard life cycle of the farm. A stylized hand indicates that the task is initiated by the player through the GUI, while tasks with a stylized person are automatically executed by a villager.&lt;/p&gt;
&lt;p&gt;As seen above, the process of harvesting a farm can be divided into these steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A farm's life cycle starts with the player placing and constructing it (needs 60 wood) with a villager.&lt;/li&gt;
&lt;li&gt;One villager (more are not allowed) gathers food from the farm until it is depleted.&lt;/li&gt;
&lt;li&gt;Then one of three scenarios can happen:&lt;ol&gt;
&lt;li&gt;There is a farm queued in the mill at the moment the farm depletes. In this case, the villager automatically rebuilds it and 1 farm is removed from the queue. They automatically resume gathering. This is a feature introduced in the first expansion &lt;em&gt;The Conqueror's&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;The player rebuilds the farm manually by right-clicking on it with a villager. This will cost them 60 wood. They automatically resume gathering.&lt;/li&gt;
&lt;li&gt;If 3 minutes of ingame time passed, no farm was queued and the player did not manually rebuild the farm, the depleted farm is deleted.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Streamlining the process&lt;/h1&gt;
&lt;p&gt;One problem that remains is that the process described in the previous section is still very specific to farms. As we are writing an API, we would like to generalize it as much as possible. Particularly, we would like to fulfill these requirements:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Restocking resources should be possible for every &lt;code&gt;ResourceSpot&lt;/code&gt;, not just farms. Trees and berry bushes are candidates where renewability would make sense.&lt;/li&gt;
&lt;li&gt;Similar to what we said in previous blogposts, the game entity containing the &lt;code&gt;ResourceSpot&lt;/code&gt; should not be replaced when we restock it. The action should only refill the resources.&lt;/li&gt;
&lt;li&gt;Queuing restocks should also be very easy to control through the API. Modders should have the option to enable and disable automatic restocks.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With this in mind, we can now look at the API implementation.&lt;/p&gt;
&lt;h2&gt;Restock&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Restock API object" src="https://blog.openage.dev/images/D0010-restock-api.png"&gt;&lt;/p&gt;
&lt;p&gt;There are two abilities involved in the restocking process. On the left side we have the ability &lt;code&gt;Harvestable&lt;/code&gt; of the farm, which contains the &lt;code&gt;ResourceSpot&lt;/code&gt; that villagers can gather from. Villagers get the &lt;code&gt;Restock&lt;/code&gt; ability with which they can fill up the resources again.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Restock&lt;/code&gt; targets a specilization of &lt;code&gt;ResourceSpot&lt;/code&gt; which is called &lt;code&gt;RestockableResourceSpot&lt;/code&gt;. A restockable resource spot works like a normal resource spot, except that it is not immediatly destructed after the resources are harvested. Instead, it will be &lt;em&gt;depleted&lt;/em&gt; until it is either restocked or the time set in &lt;code&gt;destruction_time_limit&lt;/code&gt; has run out. We can also decide with &lt;code&gt;auto_restock&lt;/code&gt; whether queued/automatic restocks are allowed. The two sets of &lt;code&gt;Progress&lt;/code&gt; objects contain graphics that are used when a certain percentage of restocking is complete. It is important to stress that normal &lt;code&gt;ResourceSpot&lt;/code&gt;s can be turned into &lt;code&gt;RestockableResourceSpot&lt;/code&gt;s through patching.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Restock&lt;/code&gt; ability can be used on a restockable resource spot after its contents are depleted. Though its attributes look very similar to those of &lt;code&gt;Build&lt;/code&gt;, the two abilities operate completely independent from each other. &lt;code&gt;Restock&lt;/code&gt; is only concerned about the resource spot it is supposed to refill (&lt;code&gt;target&lt;/code&gt;) and will not reconstruct the whole building. The necessary time to restock is stored in &lt;code&gt;restock_time&lt;/code&gt;. We can also set the &lt;code&gt;amount&lt;/code&gt; of resources that should be restocked. The costs for a restock action is split into two options: &lt;code&gt;manual_cost&lt;/code&gt; is used when the player initiates the restock (like right-clicking on a depleted farm), while &lt;code&gt;auto_cost&lt;/code&gt; is used when villagers automatically execute the restock, provided the resource spot allows this. Both costs can be the same, but it can be handy to set them to different values as we will see now.&lt;/p&gt;
&lt;h2&gt;Queuing farms&lt;/h2&gt;
&lt;p&gt;When we implement our &lt;code&gt;Restock&lt;/code&gt; ability for the resource spot of AoE2 farms, we have to initialize &lt;code&gt;manual_cost&lt;/code&gt; and &lt;code&gt;auto_cost&lt;/code&gt;. The naïve approach would be to interpret both cases as "build farm" actions and set both values to 60 wood. But this would not suffice. As we can see in our first diagram, the automatic restock does not really cost 60 wood, it costs one farm from the queue in the mill. That begs the question of how we actually queue farms. Fortunately for us, it turns out to be quite trivial. &lt;/p&gt;
&lt;p&gt;First of all, the farm queue does not exactly represent buildings. It is probably closer to a "I can rebuild my farm"-ticket for the villager. Secondly, these tickets are available to all villagers and are not tied to a specific mill. They can be used from everywhere on the map on a first-come, first-serve basis. If you think about it, these tickets work like the other four resources in the game, with the exception that they cannot be gathered by the villagers. Thus, we are going to interpret the elements in the queue as actual resources. We will introduce a fifth &lt;code&gt;Resource&lt;/code&gt; called &lt;code&gt;FarmRestockResource&lt;/code&gt; which will work exactly like &lt;code&gt;Food&lt;/code&gt;, &lt;code&gt;Wood&lt;/code&gt;, &lt;code&gt;Gold&lt;/code&gt; and &lt;code&gt;Stone&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="TradeResource API" src="https://blog.openage.dev/images/D0010-trade-resource-api.png"&gt;&lt;/p&gt;
&lt;p&gt;Since &lt;code&gt;FarmRestock&lt;/code&gt; will probably not be gatherable on the map (although that is possible), we have to find another way to acquire it. For that purpose, we can use the &lt;code&gt;TradeResource&lt;/code&gt; ability which is also used for selling and buying with the market. In the context of farming, the mill will get a &lt;code&gt;TradeResource&lt;/code&gt; ability which sells 60 units of &lt;code&gt;Wood&lt;/code&gt; for 1 unit of &lt;code&gt;FarmRestockResource&lt;/code&gt;. We can then set &lt;code&gt;auto_cost&lt;/code&gt; in the villager's &lt;code&gt;Restock&lt;/code&gt; ability to 1 unit of &lt;code&gt;FarmRestockResource&lt;/code&gt; which is therfore consumed whenever a villager automatically restocks a farm.&lt;/p&gt;
&lt;h1&gt;Questions?&lt;/h1&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="nyan"></category><category term="modding"></category><category term="API"></category></entry><entry><title>D9: Openage modding API - Civilizations and Uniqueness</title><link href="https://blog.openage.dev/d9-openage-modding-api-civilizations-and-uniqueness.html" rel="alternate"></link><published>2018-09-20T00:00:00+02:00</published><updated>2018-09-20T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2018-09-20:/d9-openage-modding-api-civilizations-and-uniqueness.html</id><summary type="html">&lt;p&gt;Civilizations bring variety into games and add asymmetry&lt;/p&gt;</summary><content type="html">&lt;p&gt;Civilizations (also called &lt;em&gt;Factions&lt;/em&gt; or &lt;em&gt;Races&lt;/em&gt; in other games) are a concept as old as Dune 2. Their purpose is to add strategic complexity by inserting a layer of asymmetry to a game, thus enabling a variety of unique play styles and increasing replayability. How we are handling this and how much complexity we can add with the openage modding API is our topic for today.&lt;/p&gt;
&lt;p&gt;Other articles in the modding API series:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d0-openage-modding-api-introduction.html"&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d1-openage-modding-api-units-buildings-more.html"&gt;Units, Buildings &amp;amp; more&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d2-openage-modding-api-abilities.html"&gt;Abilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d3-openage-modding-api-patching.html"&gt;Patching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d4-openage-modding-api-archers-dont-kill-units-projectiles-do.html"&gt;Attack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d5-openage-modding-api-bonus.html"&gt;Bonus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d6-openage-modding-api-inventory-system.html"&gt;Inventory System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d7-openage-modding-api-too-many-villagers.html"&gt;Too many villagers!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d8-openage-modding-api-the-transformers.html"&gt;Transform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Civilizations (you're here)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d10-openage-modding-api-restocking-farms.html"&gt;Restocking farms&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="https://blog.openage.dev/landing-page.html"&gt;View all articles&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Initial requirements&lt;/h1&gt;
&lt;p&gt;Throughout the history of strategy games, a lot of different ways to implement civilizations have evolved. In some games factions distinguish themselves only by a difference in unit stats, e.g. in &lt;em&gt;Empire Earth&lt;/em&gt;, while others make them entirely unique (&lt;em&gt;Starcraft&lt;/em&gt; being a prime example) with individual units, techs and strategies built around them. The &lt;em&gt;Age of Empires&lt;/em&gt; series occupies some kind of middle ground in which each civilization uses a subset of a shared tech tree in addition to a few economic and military boni for each civ. Of course, other strategy games introduced many related flavors for their faction systems that come with their own quirks.&lt;/p&gt;
&lt;p&gt;To support all these levels of uniqueness, we need a system that is flexible and easy to adjust. We would also like it to still be easily moddable, so that graphical and balance changes can be made by the community. Fortuately for us, nyan makes both of these requirements really easy to fulfill.&lt;/p&gt;
&lt;h1&gt;Upgrades and unlocks in openage&lt;/h1&gt;
&lt;p&gt;Before we begin explaining how civilizations are implemented, we should do a quick recap on how upgrades and unlocks are realized in openage. On a technical level every upgrade in a game is defined as a bundle of &lt;a href="https://blog.openage.dev/d3-openage-modding-api-patching.html"&gt;patches&lt;/a&gt; which modify the game entities that are currently available. In turn most upgrades are unlocked by other upgrades and were therefore also patched in at some point. This basically means that any uprade is the result of a series of patch bundles which can be traced back to one starting configuration. For example, the upgrade from spearman to pikeman is a result of these events:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Starting configuration: &lt;em&gt;Dark Age&lt;/em&gt; buildings, units, techs are available&lt;/li&gt;
&lt;li&gt;Researching &lt;code&gt;FeudalAgeTech&lt;/code&gt; patches &lt;code&gt;CastleAgeTech&lt;/code&gt; into &lt;code&gt;Research&lt;/code&gt; ability of town center&lt;/li&gt;
&lt;li&gt;Researching &lt;code&gt;CastleAgeTech&lt;/code&gt; patches &lt;code&gt;PikemanTech&lt;/code&gt; into &lt;code&gt;Research&lt;/code&gt; ability of barracks&lt;/li&gt;
&lt;li&gt;Researching &lt;code&gt;PikemanTech&lt;/code&gt; patches graphics, name and attributes (HP (+10), attack damage (+1), etc.) of &lt;code&gt;Spearman&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The way we unlock &lt;code&gt;PikemanTech&lt;/code&gt; is implicitely defined through the previous techs and the starting configuration. It is also important to stress that the upgrade path is not fixed and could just as well look like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Starting configuration: &lt;em&gt;Dark Age&lt;/em&gt; buildings, units, techs are available&lt;/li&gt;
&lt;li&gt;Researching &lt;code&gt;FeudalAgeTech&lt;/code&gt; patches &lt;code&gt;WoodenStaffTech&lt;/code&gt; into &lt;code&gt;Research&lt;/code&gt; ability of blacksmith&lt;/li&gt;
&lt;li&gt;Researching &lt;code&gt;WoodenStaffTech&lt;/code&gt; patches &lt;code&gt;PointyStickTech&lt;/code&gt; into &lt;code&gt;Research&lt;/code&gt; ability of blacksmith&lt;/li&gt;
&lt;li&gt;Researching &lt;code&gt;PointyStickTech&lt;/code&gt; patches &lt;code&gt;PikemanTech&lt;/code&gt; into &lt;code&gt;Research&lt;/code&gt; ability of barracks&lt;/li&gt;
&lt;li&gt;Researching &lt;code&gt;PikemanTech&lt;/code&gt; patches graphics, name and attributes (HP (+10), attack damage (+1), etc.) of &lt;code&gt;Spearman&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is benefical for two major reasons. For one it allows techs or units to be unlocked in different ways, which is always cool. But more importantly it shows that a tech's functionality is independent from its unlock path. Sure, &lt;code&gt;PikemanTech&lt;/code&gt; has to be unlocked at some point, but it doesn't matter if &lt;code&gt;CastleAgeTech&lt;/code&gt; or &lt;code&gt;PointyStickTech&lt;/code&gt; did it. In consequence, this means that any of these five steps on the unlock path -- including the starting configuration -- can be altered individually without breaking the engine logic.&lt;/p&gt;
&lt;h2&gt;Civilizations&lt;/h2&gt;
&lt;p&gt;But what does this have to do with the uniqueness of civilizations? It turns out that any unique property of a civilization is just a change of a step on the unlock path. And because we are able to alter every individual step without dangerous consequences, we can change pretty much anything we want. The civilization setup is practically a 0th step that comes with its own changes which again are introduced by patching.&lt;/p&gt;
&lt;p&gt;Let's say we want to have a civilization that grants every pikeman of this civ 5 more HP than the "standard" pikemans have. We do so by patching the patch from &lt;code&gt;PikemanTech&lt;/code&gt; that upgrades HP to give another 5 points of health.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# The tech holds all the necessary patches for the upgrade&lt;/span&gt;
&lt;span class="c1"&gt;# from spearman to pikeman, including the patch for HP.&lt;/span&gt;
&lt;span class="n"&gt;PikemanTech&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tech&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;updates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;HPforPikeman&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# This is the standard HP increase for pikeman that&lt;/span&gt;
&lt;span class="c1"&gt;# patches the Live ability of Spearman units to gain&lt;/span&gt;
&lt;span class="c1"&gt;# 10 more HP.&lt;/span&gt;
&lt;span class="n"&gt;HPforPikeman&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Live&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Patch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;hp&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;

&lt;span class="c1"&gt;# With this addition, we patch the standard HP increase patch&lt;/span&gt;
&lt;span class="c1"&gt;# to give an additional 5 HP.&lt;/span&gt;
&lt;span class="n"&gt;CivAdditionalHP&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HPforPikeman&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Patch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;hp&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In the series of events that leads to the research of &lt;code&gt;PikemanTech&lt;/code&gt;, the application of &lt;code&gt;CivAdditionalHP&lt;/code&gt; is part of the 0th step we talked about earlier.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Civ setup: &lt;code&gt;CivAdditionalHP&lt;/code&gt; patches &lt;code&gt;HPforPikeman&lt;/code&gt; from &lt;code&gt;PikemanTech&lt;/code&gt; to grant an additional 5 points of health&lt;/li&gt;
&lt;li&gt;Starting configuration: &lt;em&gt;Dark Age&lt;/em&gt; buildings, units, techs are available&lt;/li&gt;
&lt;li&gt;Researching &lt;code&gt;FeudalAgeTech&lt;/code&gt; patches &lt;code&gt;CastleAgeTech&lt;/code&gt; into &lt;code&gt;Research&lt;/code&gt; ability of town center&lt;/li&gt;
&lt;li&gt;Researching &lt;code&gt;CastleAgeTech&lt;/code&gt; patches &lt;code&gt;PikemanTech&lt;/code&gt; into &lt;code&gt;Research&lt;/code&gt; ability of barracks&lt;/li&gt;
&lt;li&gt;Researching &lt;code&gt;PikemanTech&lt;/code&gt; patches graphics, name and attributes (&lt;strong&gt;HP (+15)&lt;/strong&gt;, attack damage (+1), etc.) of &lt;code&gt;Spearman&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Of course, as the unlock path of &lt;code&gt;PikemanTech&lt;/code&gt; itself consists of patches we are able to change them, too. For example, we can have &lt;code&gt;PikemanTech&lt;/code&gt; unlocked in Feudal instead of Castle Age.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# The standard Feudal upgrade which unlocks the tech for Castle Age&lt;/span&gt;
&lt;span class="n"&gt;FeudalAgeTech&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tech&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;updates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;CastleAgeUnlock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# On the standard unlock path CasteAgeTech enables PikemanTech&lt;/span&gt;
&lt;span class="n"&gt;CastleAgeTech&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tech&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;updates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;PikemanTechUnlock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# A new patch puts the unlock for pikeman into Feudal..&lt;/span&gt;
&lt;span class="n"&gt;CivMovePikeToFeudal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FeudalAgeTech&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Patch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;updates&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;PikemanTechUnlock&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# ..and removes it from Castle&lt;/span&gt;
&lt;span class="n"&gt;CivRemovePikeFromCastle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CastleAgeTech&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Patch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;updates&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;PikemanTechUnlock&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;We essentially removed one intermediate step on the unlock path.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Civ setup: &lt;code&gt;CivMovePikeToFeudal&lt;/code&gt; patches &lt;code&gt;PikemanTechUnlock&lt;/code&gt; into &lt;code&gt;FeudalAgeTech&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Starting configuration: &lt;em&gt;Dark Age&lt;/em&gt; buildings, units, techs are available&lt;/li&gt;
&lt;li&gt;Researching &lt;code&gt;FeudalAgeTech&lt;/code&gt; patches &lt;code&gt;PikemanTech&lt;/code&gt; into &lt;code&gt;Research&lt;/code&gt; ability of barracks&lt;/li&gt;
&lt;li&gt;Researching &lt;code&gt;PikemanTech&lt;/code&gt; patches graphics, name and attributes (HP (+10), attack damage (+1), etc.) of &lt;code&gt;Spearman&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When we handle things this way, we end up with a very flexible system that allows us to uniquely define how a game is played with a civilization. One faction might unlock the pikeman by researching Feudal Age, another one by researching Imperial Age. Keep in mind that we don't even need age upgrades for unlocks, &lt;code&gt;PikemanTech&lt;/code&gt; might as well be unlocked by Forging or another not so important tech. The starting configuration can also be changed easily because it just represents the game data before any patches have been applied. The civilization setup can alter it the same way we did with the other steps.&lt;/p&gt;
&lt;p&gt;The question that remains is whether this system still allows for easy modding. When we look at any unlock path, we see that the 0th step is nothing special and essentially the same as the others: The use of patching to alter attributes. Similar to how we added the 0th step for "Civ Setup", we can introduce another step that comes even before the 0th step. This step would be able to change all subsequent steps, including "Civ Setup". Such a preliminary step would be exactly what a data mod is. And because mods are also a bundle of patches, we can have a step before each mod, which would also be a mod that allows a preliminary step that would again be a mod... (repeat indefinitely)&lt;/p&gt;
&lt;h2&gt;API description&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Civilization API" src="https://blog.openage.dev/images/D0009-civ-api.png"&gt;&lt;/p&gt;
&lt;p&gt;All of a civilization's individual properties are handled by the &lt;code&gt;Civilization&lt;/code&gt; API object. &lt;code&gt;Civilization&lt;/code&gt; defines various attributes for its name and ingame help, the names of civilization leaders and its starting resources. &lt;code&gt;boni&lt;/code&gt; is meant for civilization specific &lt;code&gt;Bonus&lt;/code&gt; objects that are not bound to game entities or techs, such as the vietnamese bonus that reveals the starting positions of enemy players on the map. Everything concerning uniqueness of the civilization is handled by three patch bundles &lt;code&gt;civ_setup&lt;/code&gt;, &lt;code&gt;graphics_set&lt;/code&gt; and &lt;code&gt;team_setup&lt;/code&gt;. They will be applied in the "0th step" we mentioned previously.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;civ_setup&lt;/strong&gt;: Contains all patches for civ specific data changes, excluding graphical setup&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;graphics_set&lt;/strong&gt;: Contains all graphical changes for game entities&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;team_setup&lt;/strong&gt;: These patches are applied to the player of the civilization &lt;strong&gt;and&lt;/strong&gt; their allies&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All patches together define the unique properties of the civilization.&lt;/p&gt;
&lt;h1&gt;Questions?&lt;/h1&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="nyan"></category><category term="modding"></category><category term="API"></category></entry><entry><title>D8: Openage modding API - The Transformers</title><link href="https://blog.openage.dev/d8-openage-modding-api-the-transformers.html" rel="alternate"></link><published>2018-09-13T00:00:00+02:00</published><updated>2018-09-13T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2018-09-13:/d8-openage-modding-api-the-transformers.html</id><summary type="html">&lt;p&gt;Transforming between states with certain abilities available&lt;/p&gt;</summary><content type="html">&lt;p&gt;Anyone familiar with &lt;em&gt;The Transformers&lt;/em&gt; franchise by Michael Bay probably knows how the Autobots work. For those who don't: The Autobots are sentient robots from outer space that come to Earth for robot business reasons, but more interesting is that they can switch between two forms. The first one, vehicle form (a.k.a. product placement form), disguises them as cars or trucks from Earth while also allowing them to drive around at a very fast pace. When transforming to robot form, they lose both disguise and the option to move fast, but are able to shoot, punch or slice their enemies effectively. You could say that each form gives the Autobots different &lt;em&gt;abilities&lt;/em&gt;. In a sense, this concept is very similar to a unit from AoE2 that also possesses different abilities depending on its form. The trebuchet.&lt;/p&gt;
&lt;p&gt;Other articles in the modding API series:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d0-openage-modding-api-introduction.html"&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d1-openage-modding-api-units-buildings-more.html"&gt;Units, Buildings &amp;amp; more&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d2-openage-modding-api-abilities.html"&gt;Abilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d3-openage-modding-api-patching.html"&gt;Patching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d4-openage-modding-api-archers-dont-kill-units-projectiles-do.html"&gt;Attack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d5-openage-modding-api-bonus.html"&gt;Bonus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d6-openage-modding-api-inventory-system.html"&gt;Inventory System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d7-openage-modding-api-too-many-villagers.html"&gt;Too many villagers!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Transform (you're here)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d9-openage-modding-api-civilizations-and-uniqueness.html"&gt;Civilizations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d10-openage-modding-api-restocking-farms.html"&gt;Restocking farms&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="https://blog.openage.dev/landing-page.html"&gt;View all articles&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Generalizing the problem&lt;/h1&gt;
&lt;p&gt;What the little example from the Introduction shows us is that despite the uniqueness of the trebuchet in comparison to AoE2's units, the concept of units that have several forms, which give access to different abilities, is far from uncommon. This means there is a good chance that we can generalize the behavior of units that have multiple forms and use this generalization for the trebuchet, instead of having to hardcode specific behavior for just one unit.&lt;/p&gt;
&lt;p&gt;The way AoE2 handles its precious stone thrower is by defining the two forms, &lt;em&gt;packed&lt;/em&gt; and &lt;em&gt;unpacked&lt;/em&gt;, as separate units in the game data. Transforming from either of those forms to the other is done by replacing the unit after the transformation is done. We've already discussed why replacement is a bad idea for villagers &lt;a href="https://blog.openage.dev/d7-openage-modding-api-too-many-villagers.html"&gt;in our last blogpost&lt;/a&gt; and the same problem also applies to the trebuchet. It requires the replaced and replacing units to be in a predictable state. In openage, this is not guaranteed (by design) as individual units can go through a substantial number of changes due to patching, so we need a different approach here. Instead of two units that are switched, we would like to have a single unit where &lt;strong&gt;only&lt;/strong&gt; the active abilities change.&lt;/p&gt;
&lt;h1&gt;Finite-state machines&lt;/h1&gt;
&lt;p&gt;Before we consider the openage API definition, we should discuss how we would want transformations to work in general. Fortunately, there are already existing models that we can use for that purpose in the form of &lt;em&gt;finite-state machines&lt;/em&gt;. A finite-state machine is defined by a finite number of states, which are equal to what we have called forms until now, and the transitions - the equivalent of transformations - between them. Each state is further defined by the abilities and transitions that are available when the machine reaches it. Ideally, we would want our game entities to also be finite-state machines. We will go through an example to clarify what this means exactly. However, to explain the topic properly we need something more complex than an Autobot or a trebuchet: A vending machine.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Vending machine 1" src="https://blog.openage.dev/images/D0008-automaton-1.png"&gt;&lt;/p&gt;
&lt;p&gt;The vending machine that is shown here is defined by a finite-state machine with the three states &lt;code&gt;s_0&lt;/code&gt;, &lt;code&gt;s_1&lt;/code&gt;, &lt;code&gt;s_2&lt;/code&gt; (depicted as nodes) and various transitions between them (depicted as arrows). &lt;code&gt;s_0&lt;/code&gt; (marked with a double outline) is the starting state that we assume the machine is in when a customer would approach it. Abilities available in a specific state are visible next to the corresponding node in a blue colored font. The total number of abilities the machine has can be seen in the upper left. Only a subset of them is active in each state.&lt;/p&gt;
&lt;p&gt;Some of the abilities are transitional, for example &lt;code&gt;InsertCoin&lt;/code&gt;, which means they trigger a transition to another state when they are executed. A transition is denoted as an arrow with the name of the transitional ability next to it. Other abilities, like &lt;code&gt;ShowBeverages&lt;/code&gt;, do not result in a transition.&lt;/p&gt;
&lt;p&gt;Vending machines are a pretty good example case where finite-state machines are useful because we don't want to give the customer access to all of its abilities at once. For example, using &lt;code&gt;ShowSelection&lt;/code&gt; makes no sense before &lt;code&gt;SelectBeverage&lt;/code&gt; was executed. Giving access to the &lt;code&gt;EjectBeverage&lt;/code&gt; ability before &lt;code&gt;InsertCoin&lt;/code&gt; was used definitely requires a lot of goodwill, too. With state machines we can make sure that specific actions/transitions are taken before an ability is available to users.&lt;/p&gt;
&lt;p&gt;Note that the depicted vending machine always allows us to go back to the starting state &lt;code&gt;s_0&lt;/code&gt; from any other state. There are even multiple pathways of transitions that accomplish this. However, this is not necessarily the case for all finite-state machines. We can show this with a simple extension.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Vending machine 2" src="https://blog.openage.dev/images/D0008-automaton-2.png"&gt;&lt;/p&gt;
&lt;p&gt;This new version of the vending machine offers one new ability &lt;code&gt;Break&lt;/code&gt; and a new state &lt;code&gt;s_e&lt;/code&gt; (changes are colored red). &lt;code&gt;Break&lt;/code&gt; is available in every state except &lt;code&gt;s_e&lt;/code&gt;. The practical implications of this are that if our vending machine "breaks" in any of these states, the machine will transition to the error state &lt;code&gt;s_e&lt;/code&gt; and is only able to execute &lt;code&gt;ShowError&lt;/code&gt;. &lt;code&gt;s_e&lt;/code&gt; is a dead-end as there is no transition that gets us back to a previous state anymore.&lt;/p&gt;
&lt;p&gt;Dead-end states are not limited to errors in their use cases. They could just as well be defined for a situation where the vending machine runs out of drinks. The point is that it can sometimes be beneficial to transition to a state or even a branch of states, so that it is impossible to reach the starting state again.&lt;/p&gt;
&lt;p&gt;So far we discussed finite-state machines where every state is reachable from &lt;code&gt;s_0&lt;/code&gt; and the whole state graph is interconnected. This does not always have to be the case.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Vending machine 3" src="https://blog.openage.dev/images/D0008-automaton-3.png"&gt;&lt;/p&gt;
&lt;p&gt;We again introduced new states &lt;code&gt;s_3&lt;/code&gt; and &lt;code&gt;s_4&lt;/code&gt; and some new abilities which would qualify for some kind of "maintainance mode". In our example, it would make sense for these abilities to be completely unavailable from "customer mode" (especially &lt;code&gt;EjectMoney&lt;/code&gt;) and therefore have the state machine offer no transition to any of these states. Only an authorized person should have access to them. But how would they be able to reach these states?&lt;/p&gt;
&lt;p&gt;The obvious answer is to use &lt;em&gt;outside measures&lt;/em&gt; which add a transition at runtime, but are not part of the actual machine. As you might remember, game entities in openage can change at runtime. As a result, a transitional ability could be added at a later date by a patch, an item, a script or a trigger in a custom scenario. Finite-state machines in openage are not fixed as they are just as alterable as the game entities that represent them.&lt;/p&gt;
&lt;p&gt;Going back to our vending machine, an example for such an outside measure would be a keycard that is slotted into the machine. Similar to an &lt;code&gt;InventoryItem&lt;/code&gt;, this keycard would enable two additional abilities &lt;code&gt;EnterMaint.&lt;/code&gt; (for &lt;code&gt;s_0&lt;/code&gt;) and &lt;code&gt;LeaveMaint.&lt;/code&gt; (for &lt;code&gt;s_3&lt;/code&gt;) that transition between &lt;code&gt;s_0&lt;/code&gt; and &lt;code&gt;s_3&lt;/code&gt; (depicted as dashed red arrows).&lt;/p&gt;
&lt;p&gt;&lt;img alt="Vending machine 4" src="https://blog.openage.dev/images/D0008-automaton-4.png"&gt;&lt;/p&gt;
&lt;h1&gt;API definition&lt;/h1&gt;
&lt;p&gt;&lt;img alt="Transform API" src="https://blog.openage.dev/images/D0008-transform-api.png"&gt;&lt;/p&gt;
&lt;p&gt;Finally, we are going to look at the API definition of finite-state machines in openage. There are two core abilities that accomplish this, &lt;code&gt;Transform&lt;/code&gt; and &lt;code&gt;TransformTo&lt;/code&gt;. &lt;code&gt;Transform&lt;/code&gt; is the ability that enables a &lt;code&gt;GameEntity&lt;/code&gt; to be a state machine. It stores all the the possible states of the game entity and the startig state as &lt;code&gt;initial_state&lt;/code&gt;. &lt;code&gt;TransformTo&lt;/code&gt; on the other hand is meant as a transitional ability which can be used to get into another state. It does so by defining a &lt;code&gt;target_state&lt;/code&gt; that must point to a state from &lt;code&gt;states&lt;/code&gt; in &lt;code&gt;Transform&lt;/code&gt;. It also defines the time the transition takes (&lt;code&gt;transition_time&lt;/code&gt;) as well as the sprites used during the transition with &lt;code&gt;TransformProgress&lt;/code&gt; objects. After the transition time has passed, the game entity will switch to the target state.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Trebuchet API example" src="https://blog.openage.dev/images/D0008-transform-trebuchet-example.png"&gt;&lt;/p&gt;
&lt;p&gt;If we would model the trebuchet in our API, we would need one &lt;code&gt;Transform&lt;/code&gt; abilitiy and two transitional &lt;code&gt;TransformTo&lt;/code&gt; abilities for our state machine. The transitional abilities change the current state to &lt;code&gt;Packed&lt;/code&gt; or &lt;code&gt;Unpacked&lt;/code&gt;. Both of the states are defined in the set &lt;code&gt;states&lt;/code&gt; from &lt;code&gt;Transform&lt;/code&gt; as instances of &lt;code&gt;TransformState&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;All of the abilities referenced in the defined states are also stored in the &lt;code&gt;abilities&lt;/code&gt; attribute of the &lt;code&gt;Trebuchet&lt;/code&gt; game entity. This allows them to be easily accessible when we want to patch them, even if they are not enabled in the unit's current state.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Trebuchet API example" src="https://blog.openage.dev/images/D0008-transform-trebuchet-automaton.png"&gt;&lt;/p&gt;
&lt;h2&gt;Improvements?&lt;/h2&gt;
&lt;p&gt;While modelling game entities with finite-state machines can be very powerful, the current API system does not explore their full potential (yet). For example, the &lt;code&gt;TransformTo&lt;/code&gt; API ability does not do much except for transitioning between states. Furthermore, units will not be able to use any abilities during the transformation. There is a simple reason for that: We don't need so much complexity right now as the only real practical example is the trebuchet. The priority is making sure that the system works reliably for trebuchets first and then gradually improve it with ideas from modders and developers.&lt;/p&gt;
&lt;p&gt;For example, we could add a cost for transformations, cooldowns for transitions, states that units can only be in temporary or states that force them to transform back after a time limit. There is a lot of potential for extending the system.&lt;/p&gt;
&lt;h1&gt;Questions?&lt;/h1&gt;
&lt;p&gt;In our next iteration of the API blog series, civilizations will make an appearance. We will discuss how they work and how the openage modding API handles &lt;em&gt;uniqueness&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="nyan"></category><category term="modding"></category><category term="API"></category></entry><entry><title>D7: Openage modding API - Too many villagers!</title><link href="https://blog.openage.dev/d7-openage-modding-api-too-many-villagers.html" rel="alternate"></link><published>2018-09-06T00:00:00+02:00</published><updated>2018-09-06T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2018-09-06:/d7-openage-modding-api-too-many-villagers.html</id><summary type="html">&lt;p&gt;Villagers and their gathering abilities, animations and gender&lt;/p&gt;</summary><content type="html">&lt;p&gt;If we would ask AoE2 players how many villager units there are in the game files, most would probably answer one or two, depending on whether they consider female and male version as separate units. In reality, the AoE2 game data contains a total of 22 different villager units; enough for them to play their own football game. This seems a bit much, so maybe there is some redundancy that we can get rid of.&lt;/p&gt;
&lt;p&gt;Other articles in the modding API series:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d0-openage-modding-api-introduction.html"&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d1-openage-modding-api-units-buildings-more.html"&gt;Units, Buildings &amp;amp; more&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d2-openage-modding-api-abilities.html"&gt;Abilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d3-openage-modding-api-patching.html"&gt;Patching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d4-openage-modding-api-archers-dont-kill-units-projectiles-do.html"&gt;Attack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d5-openage-modding-api-bonus.html"&gt;Bonus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d6-openage-modding-api-inventory-system.html"&gt;Inventory System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Too many villagers! (you're here)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d8-openage-modding-api-the-transformers.html"&gt;Transform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d9-openage-modding-api-civilizations-and-uniqueness.html"&gt;Civilizations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d10-openage-modding-api-restocking-farms.html"&gt;Restocking farms&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="https://blog.openage.dev/landing-page.html"&gt;View all articles&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Divide..&lt;/h1&gt;
&lt;p&gt;Before we actually start working on the redundancy problem, we have to find out why the game data defines so many villagers. Obviously, Ensemble did not intend to make their units play football matches, &lt;a href="https://www.youtube.com/watch?v=NHEFPENBV-s"&gt;did they&lt;/a&gt;*? As it turns out, the game contains this many villagers because units in AoE2 are only able to have five animated abilities.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Action (for most units this is an attack)&lt;/li&gt;
&lt;li&gt;Idle&lt;/li&gt;
&lt;li&gt;Move&lt;/li&gt;
&lt;li&gt;Die&lt;/li&gt;
&lt;li&gt;Decay (this is not resource decay, but corpse decay)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This system works fine for military units, but creates trouble for villagers because they need more than one &lt;em&gt;Action&lt;/em&gt; to support all the types of gathering they do. AoE2 supports 8 different forms of gathering resources which, together with attacking, building and repairing, amounts to 11 &lt;em&gt;Actions&lt;/em&gt; a villager is required to support. So to solve this dilemma, Ensemble created a unique villager unit for every one of these &lt;em&gt;Actions&lt;/em&gt; (twice, because villagers come in two genders) and makes the game switch between them at runtime depending on the &lt;em&gt;Action&lt;/em&gt; that is currently needed. In addition to this, they also gave each of these villager units their own idle, move, die and decay animations that add a lot of visual variety.&lt;/p&gt;
&lt;p&gt;When we look at the game data in more detail, we see that the villager is not the only unit that is handled like this. Monks and trade carts are also units that have more than one unit defined in the original game data to make them support more animations, although the villager is the most extreme example.&lt;/p&gt;
&lt;p&gt;While this implementation certainly works for Age of Empires, there are several reasons why this design is not great. First of all, it adds a lot of redundancy just to change some of the animations. Values for HP, speed and other stats stay exactly the same for each unit, yet have to be redefined twenty-two times in the game data. Secondly, the ingame transitions between the villager types need to be hardcoded in the engine. This would likely mean that we would have to restrict modders that use the openage API to a specfific number of resources and gathering types, which is an unacceptable requirement for us. Finally, replacing different villager units at runtime "on-the-fly" is prone to consistency problems. In openage, units can be more individual than in the Genie Engine and it is very difficult to keep this individuality when replacing them. Ideally we would want the &lt;em&gt;Action&lt;/em&gt;s and alternative animations to be part of a single villager unit.&lt;/p&gt;
&lt;h1&gt;.. and Conquer&lt;/h1&gt;
&lt;p&gt;Our first advantage is that game entities in the openage API are not limited to five animated abilities. Therefore, we can assign all of the 11 villager-specific actions directly to one unit without much effort. However, we also need a way to include the related move, idle, die and decay animations that the individual villager units had for each type of &lt;em&gt;Action&lt;/em&gt;. We can do so with the &lt;code&gt;CommonAnimationOverride&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;&lt;img alt="CAO object API" src="https://blog.openage.dev/images/D0007-cao-common.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CommonAnimationOverride&lt;/code&gt; is an API object that any &lt;code&gt;Abiliy&lt;/code&gt; can inherit from. By doing this, the unit's default animations from the &lt;code&gt;Move&lt;/code&gt;, &lt;code&gt;Idle&lt;/code&gt;, &lt;code&gt;Die&lt;/code&gt; and &lt;code&gt;Decay&lt;/code&gt; abilities will be temporarily overriden with the ones from &lt;code&gt;CommonAnimationOverride&lt;/code&gt; until:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;any animated ability other than &lt;code&gt;Move&lt;/code&gt;, &lt;code&gt;Idle&lt;/code&gt;, &lt;code&gt;Die&lt;/code&gt; or &lt;code&gt;Decay&lt;/code&gt; is executed &lt;strong&gt;or&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;another ability inheriting from &lt;code&gt;CommonAnimationOverride&lt;/code&gt; is used&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In practice this means an ability can indicate it wants to temporarily replace the animations of the four "common" abilities mentioned above. The example below shows how this would look for the villager ability &lt;code&gt;Forage&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="CAO Forage Example" src="https://blog.openage.dev/images/D0007-cao-common-example.png"&gt;&lt;/p&gt;
&lt;p&gt;It is important to note that inheriting from &lt;code&gt;CommonAnimationOverride&lt;/code&gt; is entirely optional and all abilities should generally work fine without being of this type. It is also not limited to typical villager abilities like &lt;code&gt;Gather&lt;/code&gt;, &lt;code&gt;Build&lt;/code&gt; or &lt;code&gt;Repair&lt;/code&gt;. For example, another unit that can make use of it is the trade cart with its &lt;code&gt;Trade&lt;/code&gt; ability. In fact, any ability is allowed to inherit &lt;code&gt;CommonAnimationOverride&lt;/code&gt;, even though it doesn't make sense for all of them.&lt;/p&gt;
&lt;h1&gt;More alternative animations&lt;/h1&gt;
&lt;p&gt;&lt;img alt="Carry animations example" src="https://blog.openage.dev/images/D0007-cao-carry-villagers.png"&gt;&lt;/p&gt;
&lt;p&gt;Having &lt;code&gt;CommonAnimationOverride&lt;/code&gt; is still not enough because all gathering abilities have second alternative animations for &lt;code&gt;Move&lt;/code&gt; and &lt;code&gt;Idle&lt;/code&gt;. These are used as &lt;em&gt;carrying&lt;/em&gt; animations and replace their default counterparts as soon as the amount of resources carried by the villager exceeds 20% of their resource capacity. The way we can handle this is very similar in its mechanics to &lt;code&gt;CommonAnimationOverride&lt;/code&gt;: We just inherit from a second API override object called &lt;code&gt;CarryAnimationOverride&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Carry animation override" src="https://blog.openage.dev/images/D0007-cao-carry.png"&gt;&lt;/p&gt;
&lt;p&gt;By inheriting from &lt;code&gt;CarryAnimationOverride&lt;/code&gt;, an ability is able to provide alternative animations for &lt;code&gt;Move&lt;/code&gt; and &lt;code&gt;Idle&lt;/code&gt;. The alternative animations replace the default ones when the carried resource amount passes the &lt;code&gt;carry_threshold&lt;/code&gt; which should be a floating point number between 0 and 1, indicating the percentage at which the threshold is reached. It only works with abilities that make a game entity carry something, so it is best suited to be used with &lt;code&gt;Gather&lt;/code&gt;, &lt;code&gt;Transport&lt;/code&gt;, &lt;code&gt;ProvideGarrison&lt;/code&gt; and &lt;code&gt;Inventory&lt;/code&gt;. Even though it is not an ability, &lt;code&gt;InventoryItem&lt;/code&gt; is be allowed to inherit from it, too. This makes it possible for items like the relic to give a unit a unique carry animation.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CarryAnimationOverride&lt;/code&gt; can be used in combination with &lt;code&gt;CommonAnimationOverride&lt;/code&gt;. In this case, if the carry threshold is reached, the move and idle animations from &lt;code&gt;CarryAnimationOverride&lt;/code&gt; always take precedence over the definitions from &lt;code&gt;CommonAnimationOverride&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;Variants add variety (and genders)&lt;/h1&gt;
&lt;p&gt;So far we've only seen how abilities activate alternative animations, but we haven't covered how animations change depending on a villager's gender. It turns out this actually sounds harder than it is because in AoE2 genders are decided at creation time and don't change after that. Well, at least they don't by gathering and building. This means we can simply patch in the animation set for each gender before the unit is created. We do so by utilizing a so called &lt;code&gt;Variant&lt;/code&gt; of the unit.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Variants" src="https://blog.openage.dev/images/D0007-variants.png"&gt;&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;Variant&lt;/code&gt; object contains a number of patches that are applied to the unit on creation. Which variant is chosen depends on the type of the &lt;code&gt;Variant&lt;/code&gt; objects. A &lt;code&gt;RandomVariant&lt;/code&gt; has a chance to be chosen at random (which perfectly fits for our villagers), while &lt;code&gt;PerspectiveVariant&lt;/code&gt; depends on the angle the game entity is viewed. The latter variants are particularly useful for walls which have to cover up to 8 different angles. Other variant types could be introduced by us later, if there's a demand.&lt;/p&gt;
&lt;p&gt;Variants are not restricted to graphical changes and can patch pretty much every attribute of a game entity, e.g. add new abilities or change the attributes of existing ones. Therefore modders should be able to implement a lot more crazy ideas for unit variety than just alternative animations.&lt;/p&gt;
&lt;h1&gt;Questions?&lt;/h1&gt;
&lt;p&gt;Next time we will discuss everyone's favorite siege unit and the implications it has for the API.&lt;/p&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;* The sport depicted is obviously not &lt;strong&gt;foot&lt;/strong&gt;ball because the monks never use their feet. It actually is a special form of &lt;a href="https://en.wikipedia.org/wiki/Gridiron_football"&gt;gridiron&lt;/a&gt; which tries to make up for the lack of feet by making the rules more complicated and running more commercials.&lt;/p&gt;</content><category term="blog"></category><category term="nyan"></category><category term="modding"></category><category term="API"></category></entry><entry><title>D6: Openage modding API - Inventory System</title><link href="https://blog.openage.dev/d6-openage-modding-api-inventory-system.html" rel="alternate"></link><published>2018-08-30T00:00:00+02:00</published><updated>2018-08-30T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2018-08-30:/d6-openage-modding-api-inventory-system.html</id><summary type="html">&lt;p&gt;Ability for storing Item game entities&lt;/p&gt;</summary><content type="html">&lt;p&gt;Our topic for today is the &lt;code&gt;Inventory&lt;/code&gt; ability which allows units to store items. AoE2 only offers one item, the relic, but it is very popular in custom scenarios. Considering that other strategy games implement other and more various kinds of items, it makes sense to include a fully fledged inventory system in openage, too.&lt;/p&gt;
&lt;p&gt;Other articles in the modding API series:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d0-openage-modding-api-introduction.html"&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d1-openage-modding-api-units-buildings-more.html"&gt;Units, Buildings &amp;amp; more&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d2-openage-modding-api-abilities.html"&gt;Abilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d3-openage-modding-api-patching.html"&gt;Patching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d4-openage-modding-api-archers-dont-kill-units-projectiles-do.html"&gt;Attack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d5-openage-modding-api-bonus.html"&gt;Bonus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Inventory System (you're here)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d7-openage-modding-api-too-many-villagers.html"&gt;Too many villagers!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d8-openage-modding-api-the-transformers.html"&gt;Transform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d9-openage-modding-api-civilizations-and-uniqueness.html"&gt;Civilizations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d10-openage-modding-api-restocking-farms.html"&gt;Restocking farms&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="https://blog.openage.dev/landing-page.html"&gt;View all articles&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Inventory&lt;/h1&gt;
&lt;p&gt;&lt;img alt="Inventory ability" src="https://blog.openage.dev/images/D0006-inventory.png"&gt;&lt;/p&gt;
&lt;p&gt;The abilities for inventory management are &lt;code&gt;PickupItem&lt;/code&gt;, &lt;code&gt;DropItem&lt;/code&gt;, &lt;code&gt;TranferItem&lt;/code&gt; and &lt;code&gt;Inventory&lt;/code&gt;. The first three of these abilities interact with items in and out of the inventory, while the actual inventory is defined by an ability that is just called &lt;code&gt;Inventory&lt;/code&gt;. An inventory's definition is determined by a list of &lt;code&gt;InventoryItem&lt;/code&gt;s stored in the &lt;code&gt;allowed_items&lt;/code&gt; attribute. Note that &lt;code&gt;InventoryItem&lt;/code&gt; is different from &lt;code&gt;Item&lt;/code&gt; and has a different purpose:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Item&lt;/code&gt; is the (physical) &lt;em&gt;representation of the item in the game world&lt;/em&gt;. It is a &lt;code&gt;GameEntity&lt;/code&gt; and can therefore exist independently. This means it can also have its own abilities and boni.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;InventoryItem&lt;/code&gt; defines the effect of an &lt;code&gt;Item&lt;/code&gt; &lt;em&gt;when it is stored in a unit's inventory&lt;/em&gt;. In contrast to &lt;code&gt;Item&lt;/code&gt; it cannot exist independently and all of its effects are applied to the inventory owner. &lt;code&gt;InventoryItem&lt;/code&gt; always references the &lt;code&gt;Item&lt;/code&gt; for which it stores the effect in its &lt;code&gt;item&lt;/code&gt; member.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The benefit of modeling the inventory system like this is that the same item can have different effects for different units. We already know a situation where this is useful because a similar behavior can be observed in AoE2. When stored in a &lt;em&gt;monk's inventory&lt;/em&gt;, a relic provides no boni (and even takes away some of their abilities). However, when inside a &lt;em&gt;monastery's inventory&lt;/em&gt; it provides a continuous gold bonus to the player. Another more RPG-like example would be a health potion that provides 20HP when a villager consumes it, while a mighty and experienced warrior gets 100HP from using it.&lt;/p&gt;
&lt;p&gt;By keeping &lt;code&gt;Item&lt;/code&gt; and &lt;code&gt;InventoryItem&lt;/code&gt; as separate API objects, we also have more options for items that are outside of an inventory and lie on the ground. Because an &lt;code&gt;Item&lt;/code&gt; game entity can have its own abilities assigned, we could enable it to run away or hide from the player, summon units for its protection or just have it mind its own business by chopping trees in the woods.&lt;/p&gt;
&lt;h1&gt;A closer look at InventoryItem&lt;/h1&gt;
&lt;p&gt;&lt;img alt="InventoryItem examples" src="https://blog.openage.dev/images/D0006-inventory-example.png"&gt;&lt;/p&gt;
&lt;p&gt;The effects of &lt;code&gt;InventoryItem&lt;/code&gt; that we briefly touched a few paragraphs before are the following: First of all, &lt;code&gt;InventoryItem&lt;/code&gt; can grant a variable number of boni to the inventory owner through the &lt;code&gt;boni&lt;/code&gt; set attribute. In addition to this, &lt;code&gt;InventoryItem&lt;/code&gt; is allowed to take away units' abilities (through &lt;code&gt;disable_abilities&lt;/code&gt;) and add entirely new ones (through &lt;code&gt;enable_abilities&lt;/code&gt;). This means that a unit's abilities - like &lt;code&gt;Attack&lt;/code&gt; - can potentially be swapped for better (or worse) versions of the ability.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;items_per_slot&lt;/code&gt; determines how many items of the same type can be stacked in one inventory slot. In the diagram we see that &lt;code&gt;HealthPotion&lt;/code&gt; can be stacked 5 times before a new slot is required. In consequence, the &lt;code&gt;ExampleInventory&lt;/code&gt; can hold up to 30 health potions, while the maximum number of relics is 6. Of course, relics and health potions can be in the inventory at the same time, but every inventory slot can only be occupied by one type of item.&lt;/p&gt;
&lt;p&gt;An interesting attribute is &lt;code&gt;conflicts&lt;/code&gt;. While the &lt;code&gt;Item&lt;/code&gt; specified in &lt;code&gt;item&lt;/code&gt; resides in the inventory, items listed in &lt;code&gt;conflicts&lt;/code&gt; cannot be there at the same time. This is useful when items are supposed to be incompatible with each other, for example a &lt;em&gt;holy relic&lt;/em&gt; and a &lt;em&gt;satanic bible&lt;/em&gt;. It can also be beneficial for a rudimentary equipment system where a unit is only allowed to wear one garment for each body part. Considering the complexity, an equipment system should probably have its own ability, but this is something for a future version of the API. After all, we are still making a real-time strategy engine and not an RPG*.&lt;/p&gt;
&lt;p&gt;Last but not least, we will show you a code example showing how storing relics from AoE2 would work with &lt;code&gt;Inventory&lt;/code&gt; and &lt;code&gt;InventoryItem&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Monk&amp;#39;s inventory&lt;/span&gt;
&lt;span class="n"&gt;MonkInventory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Inventory&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;MonkInventoryRelic&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;slots&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="c1"&gt;# Monk&amp;#39;s inventory item&lt;/span&gt;
&lt;span class="n"&gt;MonkInventoryRelic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InventoryItem&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Relic&lt;/span&gt;
    &lt;span class="n"&gt;items_per_slot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;conflicts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;enable_abilities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;disable_abilities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Convert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Heal&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;boni&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;# Monastery&amp;#39;s inventory&lt;/span&gt;
&lt;span class="n"&gt;MonasteryInventory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Inventory&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;MonasteryInventoryRelic&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;slots&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;

&lt;span class="c1"&gt;# Monastery&amp;#39;s inventory item&lt;/span&gt;
&lt;span class="n"&gt;MonasteryInventoryRelic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InventoryItem&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Relic&lt;/span&gt;
    &lt;span class="n"&gt;items_per_slot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;conflicts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;enable_abilities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;disable_abilities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;boni&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;RelicGoldBonus&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;* If you're interested in that though, check out &lt;a href="http://flarerpg.org/"&gt;Flare&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Questions?&lt;/h1&gt;
&lt;p&gt;Our next blogpost will be about a very special and complicated unit from AoE2 - the villager, or rather the villager&lt;strong&gt;s&lt;/strong&gt;. Tune in next week when we tame this beast and adapt its quirks to our modding API.&lt;/p&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="nyan"></category><category term="modding"></category><category term="API"></category></entry><entry><title>D5: Openage modding API - Bonus</title><link href="https://blog.openage.dev/d5-openage-modding-api-bonus.html" rel="alternate"></link><published>2018-08-23T00:00:00+02:00</published><updated>2018-08-23T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2018-08-23:/d5-openage-modding-api-bonus.html</id><summary type="html">&lt;p&gt;Boni are the second customization option for game entities&lt;/p&gt;</summary><content type="html">&lt;p&gt;So far the only customization option we discussed were abilities. However, there's a second option that we brushed before: The &lt;code&gt;Bonus&lt;/code&gt; API objects.&lt;/p&gt;
&lt;p&gt;Other articles in the modding API series:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d0-openage-modding-api-introduction.html"&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d1-openage-modding-api-units-buildings-more.html"&gt;Units, Buildings &amp;amp; more&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d2-openage-modding-api-abilities.html"&gt;Abilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d3-openage-modding-api-patching.html"&gt;Patching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d4-openage-modding-api-archers-dont-kill-units-projectiles-do.html"&gt;Attack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Bonus (you're here)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d6-openage-modding-api-inventory-system.html"&gt;Inventory System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d7-openage-modding-api-too-many-villagers.html"&gt;Too many villagers!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d8-openage-modding-api-the-transformers.html"&gt;Transform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d9-openage-modding-api-civilizations-and-uniqueness.html"&gt;Civilizations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d10-openage-modding-api-restocking-farms.html"&gt;Restocking farms&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="https://blog.openage.dev/landing-page.html"&gt;View all articles&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Motivation&lt;/h1&gt;
&lt;p&gt;As establihed previously, each &lt;code&gt;Ability&lt;/code&gt; in the API is linked to an engine function where its behavior is defined. On the one hand this is a benefit because we know exactly what a unit can do when we give it the ability. On the other hand there could be an ingame situation where we want the ability to do something slightly different, an &lt;em&gt;edge case&lt;/em&gt; so to speak.&lt;/p&gt;
&lt;p&gt;An example for this is the elevation factor in the damage calculation in AoE2. When two units are on the same elevation level the damage they do and receive is calculated normally. But when the elevation level different, the unit on a higher elevation level will suddenly do 25% more damage, while the opponent does 25% less. The elevation factor is examplary for an edge case behavior that we want to cover in our API with the &lt;code&gt;Bonus&lt;/code&gt; object.&lt;/p&gt;
&lt;h1&gt;Ability and Bonus relation&lt;/h1&gt;
&lt;p&gt;On an implementation level, &lt;code&gt;Ability&lt;/code&gt; and &lt;code&gt;Bonus&lt;/code&gt; are quite similar. Every &lt;code&gt;Bonus&lt;/code&gt; provides a link to behavior hardcoded in the engine. The key difference however, is the purpose they are used for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Abilities define &lt;strong&gt;general behavior&lt;/strong&gt; of a &lt;code&gt;GameEntity&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Boni apply under &lt;strong&gt;certain conditions&lt;/strong&gt; or in &lt;strong&gt;certain situations&lt;/strong&gt;. They are not limited to &lt;code&gt;GameEntity&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So unlike abilities, which are usually always available to a unit, a bonus requires a condition to be fulfilled or a situation to occur. Then and only then do they have an impact on the game.&lt;/p&gt;
&lt;p&gt;Taking the previous example about elevation the process for handling a bonus would roughly look like this: On execution of the &lt;code&gt;Attack&lt;/code&gt; ability the engine checks if the units has any corresponding boni assigned. After that it checks whether the conditions of these boni apply. If they apply, the values in the engine function's calculation are modified accordingly.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Bonus and objects that use it" src="https://blog.openage.dev/images/D0005-bonus.png"&gt;&lt;/p&gt;
&lt;p&gt;Each &lt;code&gt;GameEntity&lt;/code&gt; can have an unlimited number of boni assigned in the &lt;code&gt;boni&lt;/code&gt; member. Other objects, like &lt;code&gt;Civilization&lt;/code&gt; or &lt;code&gt;Cheat&lt;/code&gt;, are also allowed to store boni.&lt;/p&gt;
&lt;p&gt;Until now we've only talked about boni in the context of (damage) modifiers. In practice, a bonus can do much more, e.g. a map reveal (cheats) or providing a flow of resources (relics). A &lt;code&gt;Bonus&lt;/code&gt; object does not necessarily have to alter an ability. This versatility is a requirement to a certin degree as &lt;code&gt;Bonus&lt;/code&gt; objects should be able to cover a lot of different edge cases by definition.&lt;/p&gt;
&lt;p&gt;While AoE2 has some applications for boni, it really are its successors Age of Mythology and Rise of Nations who make them an integral part of the game. In AoM relics can provide very unique boni, ranging from cheaper upgrades to automatically producing units for the player at the temple. RoN offers the player boni for building wonders and harvesting unique resources. These mechanics could act as a blueprint on what boni will be implemented into the API by us over time.&lt;/p&gt;
&lt;p&gt;It is important to note that &lt;code&gt;Bonus&lt;/code&gt; is &lt;strong&gt;not&lt;/strong&gt; the same as what the Age of Empires community colloquially refers to as &lt;em&gt;attack bonus&lt;/em&gt; or &lt;em&gt;civilization bonus&lt;/em&gt;. Most of these are not conditional and only change data. For these cases of application, nyan patching is suited much better.&lt;/p&gt;
&lt;h1&gt;Unconditional Bonus&lt;/h1&gt;
&lt;p&gt;We have established before that &lt;code&gt;Bonus&lt;/code&gt; objects are conditional, but sometimes it might be beneficial when the mere presence of the bonus is condition enough for its application. This especially concerns boni that are percentage-based.&lt;/p&gt;
&lt;p&gt;Consider a civilization that gives cavalry &lt;code&gt;10%&lt;/code&gt; more health in Feudal Age, &lt;code&gt;15%&lt;/code&gt; more in Castle Age and &lt;code&gt;20%&lt;/code&gt; more in Imperial Age. We could do this through patching, but it does not look nice.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;FeudalHPUpgrade&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Live&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Patch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# increase HP by 10% or 110/100&lt;/span&gt;
    &lt;span class="c1"&gt;# all is still fine&lt;/span&gt;
    &lt;span class="n"&gt;hp&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;

&lt;span class="n"&gt;CastleHPUpgrade&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Live&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Patch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# here the problems begin. To get&lt;/span&gt;
    &lt;span class="c1"&gt;# from 10% to 15%, we need to calculate&lt;/span&gt;
    &lt;span class="c1"&gt;# 115/110 which is&lt;/span&gt;
    &lt;span class="n"&gt;hp&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="mf"&gt;1.045454545&lt;/span&gt;

&lt;span class="n"&gt;ImperialHPUpgrade&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Live&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Patch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Last but not least, to get from 10%&lt;/span&gt;
    &lt;span class="c1"&gt;# to 15%, we need to calculate 120/115&lt;/span&gt;
    &lt;span class="n"&gt;hp&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="mf"&gt;1.043478261&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Not only is this very unreadable, it's also prone to rounding errors. We can improve it, if we model it with a &lt;code&gt;Bonus&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# We define bonus...&lt;/span&gt;
&lt;span class="n"&gt;CavHPBonus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bonus&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;

&lt;span class="c1"&gt;# ... and add it in Feudal Age to get 10% more HP&lt;/span&gt;
&lt;span class="n"&gt;FeudalHPUpgrade&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GameEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Patch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;boni&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;CavHPBonus&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# In Castle/Imperial Age, we increase the Bonus&lt;/span&gt;
&lt;span class="n"&gt;CastleAndImperialHPUpgrade&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CavHPBonus&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Patch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;0.05&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Much better to read for a human.&lt;/p&gt;
&lt;h1&gt;Questions?&lt;/h1&gt;
&lt;p&gt;Next time we are going to investigate abilities again by taking a look at the &lt;code&gt;Inventory&lt;/code&gt; ability.&lt;/p&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="nyan"></category><category term="modding"></category><category term="API"></category></entry><entry><title>D4: Openage modding API - Archers don't kill units, projectiles do!</title><link href="https://blog.openage.dev/d4-openage-modding-api-archers-dont-kill-units-projectiles-do.html" rel="alternate"></link><published>2018-08-17T00:00:00+02:00</published><updated>2018-08-17T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2018-08-17:/d4-openage-modding-api-archers-dont-kill-units-projectiles-do.html</id><summary type="html">&lt;p&gt;Attack with and without projectiles&lt;/p&gt;</summary><content type="html">&lt;p&gt;In a list of essential features for strategy games, attacking would probably be sorted in first or second place. Of course something that important should not be missing from the openage API. This time we are going to look at how units damage each other with the &lt;code&gt;Attack&lt;/code&gt; ability.&lt;/p&gt;
&lt;p&gt;Other articles in the modding API series:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d0-openage-modding-api-introduction.html"&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d1-openage-modding-api-units-buildings-more.html"&gt;Units, Buildings &amp;amp; more&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d2-openage-modding-api-abilities.html"&gt;Abilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d3-openage-modding-api-patching.html"&gt;Patching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Attack (you're here)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d5-openage-modding-api-bonus.html"&gt;Bonus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d6-openage-modding-api-inventory-system.html"&gt;Inventory System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d7-openage-modding-api-too-many-villagers.html"&gt;Too many villagers!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d8-openage-modding-api-the-transformers.html"&gt;Transform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d9-openage-modding-api-civilizations-and-uniqueness.html"&gt;Civilizations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d10-openage-modding-api-restocking-farms.html"&gt;Restocking farms&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="https://blog.openage.dev/landing-page.html"&gt;View all articles&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Damage calculation&lt;/h1&gt;
&lt;p&gt;&lt;img alt="Attack" src="https://blog.openage.dev/images/D0004-attack-defense.png"&gt;&lt;/p&gt;
&lt;p&gt;In the current API design, damage is dealt as a flat amount and is always directed against a specific type of armor. A single &lt;code&gt;Attack&lt;/code&gt; can damage several armor types at once through the definition of &lt;code&gt;ArmorAttack&lt;/code&gt; objects in the &lt;code&gt;damage&lt;/code&gt; member. Every &lt;code&gt;ArmorAttack&lt;/code&gt; stores the damage done against a type of armor. On execution of the attack, each damage value from &lt;code&gt;ArmorAttack&lt;/code&gt; the objects of the attacker is matched against a defender's &lt;code&gt;ArmorDefense&lt;/code&gt; object with the same armor type. &lt;/p&gt;
&lt;p&gt;It's best if we look at a simple example before explaining the system further.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Attack Example" src="https://blog.openage.dev/images/D0004-attack-example.png"&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;armor_type&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;damage&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;armor_value&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Melee&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pierce&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Crush&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fire&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The above diagram gives us very basic definitions of one unit's &lt;code&gt;Attack&lt;/code&gt; and another unit's &lt;code&gt;Defense&lt;/code&gt; abilities. For convenience, a table shows the comparisons between the corresponding damage and armor values of the armor types.&lt;/p&gt;
&lt;p&gt;The calculation for the &lt;code&gt;Melee&lt;/code&gt; and &lt;code&gt;Pierce&lt;/code&gt; armor types is very straight forward. &lt;code&gt;armor_value&lt;/code&gt; in &lt;code&gt;ArmorDefense&lt;/code&gt; is subtracted from &lt;code&gt;damage&lt;/code&gt; in &lt;code&gt;ArmorAttack&lt;/code&gt; which yields the following results:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Damage against Melee armor: 3 - 0 = 3 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Damage against Pierce armor: 5 - 4 = 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The situation for the &lt;code&gt;Crush&lt;/code&gt; armor type is a bit more tricky because subtracting &lt;code&gt;armor_value&lt;/code&gt; from &lt;code&gt;damage&lt;/code&gt; would result in a negative value. This behavior is generally undesirable as negative damage can have weird effects. Therefore, the engine will always round negative damage against an armor type up to &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Damage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;against&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Crush&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;armor&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rounded&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For the last armor type we are facing another special yet common case of the damage calculation. The attacking unit has an &lt;code&gt;ArmorAttack&lt;/code&gt; object for the &lt;code&gt;Fire&lt;/code&gt; armor type, but the defender does not have an &lt;code&gt;ArmorDefense&lt;/code&gt; object with matching armor type. Intuitively one might assume that the amount of fire damage dealt is &lt;code&gt;2&lt;/code&gt;, since the defender seems to have no armor against it. However, this is not true. The engine will only calculate damage when there is an armor type match between an &lt;code&gt;ArmorAttack&lt;/code&gt; and an &lt;code&gt;ArmorDefense&lt;/code&gt; object. If there is no match, the damage defaults to &lt;code&gt;0&lt;/code&gt;. We've already seen the correct way to give a unit no defense against an armor type when we look at &lt;code&gt;MeleeDefense&lt;/code&gt;. Here any attack against &lt;code&gt;Meelee&lt;/code&gt; armor does full damage because the defender has the matching armor type and &lt;code&gt;armor_value&lt;/code&gt; is set to &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The behavior is a bit unintuitive because it inevitably means that an attack will deal no damage when a unit has no &lt;code&gt;ArmorDefense&lt;/code&gt; objects defined in &lt;code&gt;armors&lt;/code&gt;, which goes against the expectations of the majority of people. On the other hand, resistances against specific types of damage can be modelled much easier.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Damage against Fire armor: 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In the end the individual damage values are summed up and then compared to &lt;code&gt;min_damage&lt;/code&gt; of the &lt;code&gt;Attack&lt;/code&gt; ability. The engine chooses the greater of the two values. In this example &lt;code&gt;min_damage&lt;/code&gt; was &lt;code&gt;1&lt;/code&gt; which is smaller than the calculated damage value &lt;code&gt;4&lt;/code&gt;. The overall damage is therefore &lt;code&gt;4&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Overall damage: max(1 , 3 + 1 + 0 + 0) = max(1 , 4) = 4
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At runtime there can be situations where the damage is modified further, e.g. because of a height advantage. But that's a story for another time. It is also important to note that openage will likely support other attack systems that use a different damage calculation, like percentage based armor or attacks with a block chance, in the future.&lt;/p&gt;
&lt;h1&gt;Other types of Attack&lt;/h1&gt;
&lt;p&gt;&lt;img alt="Other Attack types" src="https://blog.openage.dev/images/D0004-attack-special.png"&gt;&lt;/p&gt;
&lt;p&gt;In addition to the normal &lt;code&gt;Attack&lt;/code&gt; ability, the API supports three more special versions of attacking. &lt;code&gt;AreaAttack&lt;/code&gt; does area of effect damage with an optional damage dropoff over distance. The &lt;code&gt;SelfDestruct&lt;/code&gt; ability is an even more special &lt;code&gt;AreaAttack&lt;/code&gt; where the unit kills itself during the attack. With &lt;code&gt;RangedAttack&lt;/code&gt; the attacking unit can attack from a specified distance and does not have to stand right next to the target. &lt;code&gt;RangedAttack&lt;/code&gt; must not be confused with &lt;code&gt;ProjectileAttack&lt;/code&gt;, since the former does not require any projectile related data.&lt;/p&gt;
&lt;h2&gt;Shooting projectiles&lt;/h2&gt;
&lt;p&gt;&lt;img alt="ProjectileAttack" src="https://blog.openage.dev/images/D0004-attack-projectile.png"&gt;&lt;/p&gt;
&lt;p&gt;The first striking difference between &lt;code&gt;Attack&lt;/code&gt; and &lt;code&gt;ProjectileAttack&lt;/code&gt; is that they are not directly related (other than the previous "special" versions of &lt;code&gt;Attack&lt;/code&gt;). This is rooted in the fact that &lt;code&gt;ProjectileAttack&lt;/code&gt; merely enables a unit to fire one or more projectiles. Each projectile can have its own &lt;code&gt;Attack&lt;/code&gt; ability that is executed on hit. In other words: The units with &lt;code&gt;ProjectileAttack&lt;/code&gt; are not doing damage, it's the projectiles they shoot.&lt;/p&gt;
&lt;p&gt;The data for attacking with projectiles is partioned between the &lt;code&gt;ProjectileAttack&lt;/code&gt; ability and the &lt;code&gt;Projectile&lt;/code&gt; objects. In the ability &lt;em&gt;attack range&lt;/em&gt;, &lt;em&gt;number of projectiles per attack&lt;/em&gt; and of course the &lt;em&gt;projectiles&lt;/em&gt; themselves are defined. Inside the &lt;code&gt;Projectile&lt;/code&gt; objects we store the actual &lt;code&gt;Attack&lt;/code&gt; and other related properties such as &lt;em&gt;accuracy&lt;/em&gt;, whether it is fired in an &lt;em&gt;arc&lt;/em&gt; or not, whether it is allowed to pass through units. This is great because it allows for a lot of customization. A unit could fire 20 different projectiles, each with individual properties and &lt;code&gt;Attack&lt;/code&gt; values.&lt;/p&gt;
&lt;h1&gt;Questions?&lt;/h1&gt;
&lt;p&gt;Although behavior for abilities like &lt;code&gt;Attack&lt;/code&gt; is hardcoded in an engine function, the execution outcome should be allowed to deviate slightly. Preferrably we would want a way to define behavior edge cases have an influence on the calculation, e.g. when we attack with a height advantage. How that is handled is discussed next week, when we take a look at &lt;code&gt;Bonus&lt;/code&gt; objects.&lt;/p&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="nyan"></category><category term="modding"></category><category term="API"></category></entry><entry><title>D3: Openage modding API - Patching</title><link href="https://blog.openage.dev/d3-openage-modding-api-patching.html" rel="alternate"></link><published>2018-08-16T00:00:00+02:00</published><updated>2018-08-16T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2018-08-16:/d3-openage-modding-api-patching.html</id><summary type="html">&lt;p&gt;Patches introduce changes at runtime&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://blog.openage.dev/d2-openage-modding-api-abilities.html"&gt;In our last blogpost&lt;/a&gt; we talked about abilities, how they are used to define behavior of game entities and had a look at an initial declaration of a &lt;code&gt;Swordsman&lt;/code&gt; unit. This time we are going to investigate how we alter the initial declaration at runtime through the use of &lt;code&gt;Patch&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Other articles in the modding API series:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d0-openage-modding-api-introduction.html"&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d1-openage-modding-api-units-buildings-more.html"&gt;Units, Buildings &amp;amp; more&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d2-openage-modding-api-abilities.html"&gt;Abilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Patching (you're here)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d4-openage-modding-api-archers-dont-kill-units-projectiles-do.html"&gt;Attack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d5-openage-modding-api-bonus.html"&gt;Bonus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d6-openage-modding-api-inventory-system.html"&gt;Inventory System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d7-openage-modding-api-too-many-villagers.html"&gt;Too many villagers!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d8-openage-modding-api-the-transformers.html"&gt;Transform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d9-openage-modding-api-civilizations-and-uniqueness.html"&gt;Civilizations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d10-openage-modding-api-restocking-farms.html"&gt;Restocking farms&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="https://blog.openage.dev/landing-page.html"&gt;View all articles&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Motivation&lt;/h1&gt;
&lt;p&gt;Most RTS games let players increase the stats of units in one form or another, usually by researching technologies, levelling or giving items to them. Technology heavy games like AoE2 even allow units to upgrade multiple times, e.g. the &lt;em&gt;Miltia&lt;/em&gt; unit which can be improved up to four times. One of the easiest methods to accomplish this is by replacing the old unit with an upgraded version that has better stats. For example, the &lt;em&gt;Man-At-Arms upgrade&lt;/em&gt; in AoE2 switches all &lt;em&gt;Militia&lt;/em&gt; units with &lt;em&gt;Man-At-Arms&lt;/em&gt;. While handling upgrades like this is easy, it creates some problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Units cannot improve individually because the individual stats cannot be carried over to the upgraded replacement unit.&lt;/li&gt;
&lt;li&gt;The units will be very generic. A replacement unit has to be designed for every possible unit upgrade.&lt;/li&gt;
&lt;li&gt;Changing ownership of units can create weird bugs because different civilizations could have different upgrade paths for each unit.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We would prefer a more flexible system that is also easy to understand. That's where &lt;code&gt;Patch&lt;/code&gt; comes into play. A patch is a special object that defines attribute changes for another nyan object. Here is one simple example of a &lt;code&gt;Patch&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;MoreSpeed&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Move&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Patch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The declaration of a &lt;code&gt;Patch&lt;/code&gt; is very similar to the declaration of a normal object with the exception of &lt;code&gt;&amp;lt;engine.Move&amp;gt;&lt;/code&gt;. The reference in the angled brackets is the &lt;strong&gt;target object&lt;/strong&gt; of the patch. The line below shows the member that is altered by patching. In this case the current value of &lt;code&gt;speed&lt;/code&gt; is increased by &lt;code&gt;0.5&lt;/code&gt; when the patch is applied. Instead of a &lt;em&gt;relational&lt;/em&gt; change, &lt;em&gt;absolute&lt;/em&gt; changes are also possible.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;MoreSpeedAbsolute&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Move&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Patch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This alternative patch would set &lt;code&gt;speed&lt;/code&gt; to &lt;code&gt;2.0&lt;/code&gt; when it is applied.&lt;/p&gt;
&lt;h1&gt;API objects for applying Patches&lt;/h1&gt;
&lt;p&gt;As stated before, the declaration of a patch does not define in what situation it is applied. However, there are API objects that cover the most common situations, e.g. &lt;code&gt;Tech&lt;/code&gt; and &lt;code&gt;Mod&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Tech and Mod" src="https://blog.openage.dev/images/D0003-tech-mod.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Tech&lt;/code&gt; objects represent technologies that have to be researched by a &lt;code&gt;GameEntity&lt;/code&gt; with the &lt;code&gt;Research&lt;/code&gt; ability. The member &lt;code&gt;upgrades&lt;/code&gt; stores a set of patches that are the effects the technology has on the player's units. Patches of &lt;code&gt;Tech&lt;/code&gt; are applied as soon as the game entity has finished researching the technology.&lt;/p&gt;
&lt;p&gt;Similar to &lt;code&gt;Tech&lt;/code&gt;, &lt;code&gt;Mod&lt;/code&gt; also holds a set of patches, but they are automatically applied right at the start of a game with no further requirements. This can be utilized by modders to get their intended alteration into the game (e.g. different animations/sounds or balance changes) without touching the original dataset.&lt;/p&gt;
&lt;h1&gt;Benefits&lt;/h1&gt;
&lt;p&gt;The great advantage of a &lt;code&gt;Patch&lt;/code&gt; is that it only defines what is changed, but when, how often and which unit it will be applied to can be decided elsewhere. The patch &lt;code&gt;MoreSpeed&lt;/code&gt; of our example that changes the &lt;code&gt;Move&lt;/code&gt; ability could be applied on all units, only selected units, a single unit, a class of units, multiple times, once, every 2 minutes, and so on. Furthermore, it allows us to make more fine-grained upgrades, instead of the sledge hammer approach that the unit replacement method is.&lt;/p&gt;
&lt;p&gt;So will every upgrade be defined as patches? The answer is &lt;strong&gt;yes&lt;/strong&gt;. Every single upgrade will be done by a patch or a bundle of patches. This goes so far that in the AoE2 swordsman line (&lt;em&gt;Militia&lt;/em&gt;, &lt;em&gt;Man-At-Arms&lt;/em&gt;, &lt;em&gt;Longswordsman&lt;/em&gt;, &lt;em&gt;Two-Handed Swordsman&lt;/em&gt;, &lt;em&gt;Champion&lt;/em&gt;), &lt;em&gt;Militia&lt;/em&gt; will be the only unit that is initially defined. The other units will be defined as patches that upgrade animations, stats and abilities. This might be unintuitive at first, but gives considerably more options to developers and modders.&lt;/p&gt;
&lt;h1&gt;Questions?&lt;/h1&gt;
&lt;p&gt;Now that the basics of abilities and patching are established, we will dive deeper into the topic of abilities and take a look at the &lt;code&gt;Attack&lt;/code&gt; abilitiy. See you next time!&lt;/p&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="nyan"></category><category term="modding"></category><category term="API"></category></entry><entry><title>D2: Openage modding API - Abilities</title><link href="https://blog.openage.dev/d2-openage-modding-api-abilities.html" rel="alternate"></link><published>2018-08-02T00:00:00+02:00</published><updated>2018-08-02T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2018-08-02:/d2-openage-modding-api-abilities.html</id><summary type="html">&lt;p&gt;Abilities give units something to do&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://blog.openage.dev/d1-openage-modding-api-units-buildings-more.html"&gt;Last week&lt;/a&gt; we learned about the &lt;code&gt;GameEntity&lt;/code&gt; API object and how it provides a skeleton for the objects present in the game world. This time we are going to enable units to interact with each other by giving them &lt;em&gt;abilities&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Other articles in the modding API series:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d0-openage-modding-api-introduction.html"&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d1-openage-modding-api-units-buildings-more.html"&gt;Units, Buildings &amp;amp; more&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Abilities (you're here)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d3-openage-modding-api-patching.html"&gt;Patching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d4-openage-modding-api-archers-dont-kill-units-projectiles-do.html"&gt;Attack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d5-openage-modding-api-bonus.html"&gt;Bonus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d6-openage-modding-api-inventory-system.html"&gt;Inventory System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d7-openage-modding-api-too-many-villagers.html"&gt;Too many villagers!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d8-openage-modding-api-the-transformers.html"&gt;Transform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d9-openage-modding-api-civilizations-and-uniqueness.html"&gt;Civilizations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d10-openage-modding-api-restocking-farms.html"&gt;Restocking farms&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="https://blog.openage.dev/landing-page.html"&gt;View all articles&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;The Ability API object&lt;/h1&gt;
&lt;p&gt;&lt;img alt="Ability examples" src="https://blog.openage.dev/images/D0002-abilities-overview.png"&gt;&lt;/p&gt;
&lt;p&gt;Each &lt;code&gt;Ability&lt;/code&gt; API object has two main purposes.&lt;/p&gt;
&lt;p&gt;First of all, an &lt;code&gt;Ability&lt;/code&gt; is always linked to behavior that is defined by an engine function. By adding an &lt;code&gt;Ability&lt;/code&gt; to a game entity, the engine knows that the unit is allowed to execute this behavior. For example, once the &lt;code&gt;Move&lt;/code&gt; ability is added to a unit, it will automatically be able to move around. The exact behavior of an ability is always decided by the engine, hardcoded into a function.&lt;/p&gt;
&lt;p&gt;Furthermore, an &lt;code&gt;Ability&lt;/code&gt; object stores the attributes that are necessary for the execution of the ability. An example for &lt;code&gt;Move&lt;/code&gt; would be the speed at which a unit moves or for &lt;code&gt;Build&lt;/code&gt; the buildings that can be constructed. Keep in mind that nyan objects only store &lt;em&gt;definition data&lt;/em&gt; which is different from the stats of a unit at runtime. For example, the &lt;code&gt;Live&lt;/code&gt; ability only defines the &lt;strong&gt;maximum HP&lt;/strong&gt;, while the &lt;strong&gt;current HP&lt;/strong&gt; value is handled by the engine's runtime simulation system.&lt;/p&gt;
&lt;h2&gt;Complexity&lt;/h2&gt;
&lt;p&gt;Because pretty much everything is an ability, the associated properties can range in complexity. Some abilities are purely passive and don't even define members, e.g. &lt;code&gt;Passable&lt;/code&gt; which just tells the engine to turn the collision of a game entity off. Others define stats for units, like the &lt;code&gt;Live&lt;/code&gt; ability does with &lt;code&gt;hp&lt;/code&gt; and &lt;code&gt;line_of_sight&lt;/code&gt; or the &lt;code&gt;Creatable&lt;/code&gt; ability with &lt;code&gt;creation_time&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The more sophisticated abilities allow units to interact with other entities in the game world, e.g. &lt;code&gt;Repair&lt;/code&gt; or &lt;code&gt;Build&lt;/code&gt;. Often these complex abilities are also animated and have an execution sound. This is signified by them inheriting from &lt;code&gt;SoundAbility&lt;/code&gt; or &lt;code&gt;AnimatedAbility&lt;/code&gt;. Abilities usually only store one animation (with rare exceptions), but can define several sounds, one of which is played randomly on execution.&lt;/p&gt;
&lt;h2&gt;nyan example&lt;/h2&gt;
&lt;p&gt;Now (finally) we are going to have a look at how all the definition we talked about are written down in the nyan language.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;
&lt;span class="normal"&gt;36&lt;/span&gt;
&lt;span class="normal"&gt;37&lt;/span&gt;
&lt;span class="normal"&gt;38&lt;/span&gt;
&lt;span class="normal"&gt;39&lt;/span&gt;
&lt;span class="normal"&gt;40&lt;/span&gt;
&lt;span class="normal"&gt;41&lt;/span&gt;
&lt;span class="normal"&gt;42&lt;/span&gt;
&lt;span class="normal"&gt;43&lt;/span&gt;
&lt;span class="normal"&gt;44&lt;/span&gt;
&lt;span class="normal"&gt;45&lt;/span&gt;
&lt;span class="normal"&gt;46&lt;/span&gt;
&lt;span class="normal"&gt;47&lt;/span&gt;
&lt;span class="normal"&gt;48&lt;/span&gt;
&lt;span class="normal"&gt;49&lt;/span&gt;
&lt;span class="normal"&gt;50&lt;/span&gt;
&lt;span class="normal"&gt;51&lt;/span&gt;
&lt;span class="normal"&gt;52&lt;/span&gt;
&lt;span class="normal"&gt;53&lt;/span&gt;
&lt;span class="normal"&gt;54&lt;/span&gt;
&lt;span class="normal"&gt;55&lt;/span&gt;
&lt;span class="normal"&gt;56&lt;/span&gt;
&lt;span class="normal"&gt;57&lt;/span&gt;
&lt;span class="normal"&gt;58&lt;/span&gt;
&lt;span class="normal"&gt;59&lt;/span&gt;
&lt;span class="normal"&gt;60&lt;/span&gt;
&lt;span class="normal"&gt;61&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Swordsman&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Strings and translation data (not explained here)&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SwordsmanName&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SwordsmanDescription&lt;/span&gt;
    &lt;span class="n"&gt;tech_tree_help&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SwordsmanHelptext&lt;/span&gt;

    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="n"&gt;icon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;swordsman_icon.png&amp;quot;&lt;/span&gt;

    &lt;span class="c1"&gt;# Hitbox&lt;/span&gt;
    &lt;span class="n"&gt;radius_x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;
    &lt;span class="n"&gt;radius_y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;
    &lt;span class="n"&gt;radius_z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.55&lt;/span&gt;

    &lt;span class="n"&gt;variants&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;abilities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;SwordsmanLive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SwordsmanMove&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SwordsmanDie&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;boni&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="n"&gt;SwordsmanLive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Live&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;hp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;
        &lt;span class="n"&gt;line_of_sight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
        &lt;span class="n"&gt;pop_space&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;visible_in_fog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;

    &lt;span class="n"&gt;SwordsmanMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Move&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Inherited member from AnimatedAbility&lt;/span&gt;
        &lt;span class="n"&gt;animation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SwordsmanMoveAnimation&lt;/span&gt;

        &lt;span class="n"&gt;SwordsmanMoveAnimation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Animation&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;animation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;swordsman_move.sprite&amp;quot;&lt;/span&gt;

        &lt;span class="c1"&gt;# Inherited member from SoundAbility&lt;/span&gt;
        &lt;span class="n"&gt;sounds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;SwordsmanMoveSound1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SwordsmanMoveSound2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;SwordsmanMoveSound1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sound&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;play_delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
            &lt;span class="n"&gt;sounds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;swordsman_move.opus&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;SwordsmanMoveSound2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sound&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;play_delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
            &lt;span class="n"&gt;sounds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;swordsman_move_alt.opus&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;# Unique members of Move&lt;/span&gt;
        &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.56&lt;/span&gt;
        &lt;span class="n"&gt;turn_speed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inf&lt;/span&gt; &lt;span class="c1"&gt;# this means turns are instant&lt;/span&gt;


    &lt;span class="n"&gt;SwordsmanDie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Die&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Inherited member from AnimatedAbility&lt;/span&gt;
        &lt;span class="n"&gt;animation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SwordsmanDieAnimation&lt;/span&gt;

        &lt;span class="n"&gt;SwordsmanDieAnimation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Animation&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;animation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;swordsman_die.sprite&amp;quot;&lt;/span&gt;

        &lt;span class="c1"&gt;# Inherited member from SoundAbility&lt;/span&gt;
        &lt;span class="n"&gt;sounds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;SwordsmanDieSound&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;SwordsmanDieSound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sound&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;play_delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
            &lt;span class="n"&gt;sounds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;swordsman_die.opus&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In this example we have created a simple unit &lt;code&gt;Swordsman&lt;/code&gt;. Right from the start, we can see that &lt;code&gt;Swordsman&lt;/code&gt; inherits from the &lt;code&gt;Unit&lt;/code&gt; API object (referenced by &lt;code&gt;engine.Unit&lt;/code&gt;). Aside from the values that were required for the members inherited from &lt;code&gt;GameEntity&lt;/code&gt; there are three abilities defined: &lt;code&gt;SwordsmanLive&lt;/code&gt;, &lt;code&gt;SwordsmanMove&lt;/code&gt; and &lt;code&gt;SwordsmanDie&lt;/code&gt;. As you probably already guessed, they use the API objects &lt;code&gt;Live&lt;/code&gt;, &lt;code&gt;Move&lt;/code&gt; and &lt;code&gt;Die&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The three abilities are defined as &lt;em&gt;nested objects&lt;/em&gt;. Nested objects work just like normal objects with the neat little benefit that we can keep the notation of the units, its abilities and other dependent objects together in one space. For the abilities we do what we always do: We assign values to the members that are required by the API. After filling everything in, we have completed the definition of &lt;code&gt;Swordsman&lt;/code&gt;, a special case of &lt;code&gt;Unit&lt;/code&gt;/&lt;code&gt;GameEntity&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And that's really the gist of it. Using the API mostly evolves around "filling in the blanks" by assigning values to the required attributes. The above definition can be taken as is, placed as plaintext inside a &lt;code&gt;.nyan&lt;/code&gt; file and will be understood by the engine. Of course, in a real life situation a modder would also have to create animations and sounds to be included. But we hope it was clear that these do not get magically created out of the blue.&lt;/p&gt;
&lt;h1&gt;Questions?&lt;/h1&gt;
&lt;p&gt;We have now seen the initial definition of a unit in nyan, but in real-time strategy games the intial values are often changed by upgrades, techs and other modifiers. How these changes are handled in nyan and why it is awesome will be discussed next week when we talk about &lt;em&gt;Patches&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Until then feel free to ask questions and discuss the blogpost in &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="nyan"></category><category term="modding"></category><category term="API"></category></entry><entry><title>D1: Openage modding API - Units, Buildings &amp; more</title><link href="https://blog.openage.dev/d1-openage-modding-api-units-buildings-more.html" rel="alternate"></link><published>2018-07-26T00:00:00+02:00</published><updated>2018-07-26T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2018-07-26:/d1-openage-modding-api-units-buildings-more.html</id><summary type="html">&lt;p&gt;About the representation of game world objects&lt;/p&gt;</summary><content type="html">&lt;p&gt;Last week we explored the overall principles and design decision for our modding API. This time we will see how the definition of units, buildings and other visible objects in the game world will work.&lt;/p&gt;
&lt;p&gt;Other articles in the modding API series:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d0-openage-modding-api-introduction.html"&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Units, Buildings &amp;amp; more (you're here)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d2-openage-modding-api-abilities.html"&gt;Abilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d3-openage-modding-api-patching.html"&gt;Patching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d4-openage-modding-api-archers-dont-kill-units-projectiles-do.html"&gt;Attack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d5-openage-modding-api-bonus.html"&gt;Bonus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d6-openage-modding-api-inventory-system.html"&gt;Inventory System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d7-openage-modding-api-too-many-villagers.html"&gt;Too many villagers!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d8-openage-modding-api-the-transformers.html"&gt;Transform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d9-openage-modding-api-civilizations-and-uniqueness.html"&gt;Civilizations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d10-openage-modding-api-restocking-farms.html"&gt;Restocking farms&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="https://blog.openage.dev/landing-page.html"&gt;View all articles&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;GameEntity&lt;/h1&gt;
&lt;p&gt;&lt;img alt="GameEntity" src="https://blog.openage.dev/images/D0001-game-entity-overview.png"&gt;&lt;/p&gt;
&lt;p&gt;Everything that &lt;em&gt;visibly exists&lt;/em&gt; and &lt;em&gt;independently operates&lt;/em&gt; in the simulated game world can be modelled with the &lt;code&gt;GameEntity&lt;/code&gt; API object. This classification includes almost everything that moves, stands around or generally does things on the map. Projectiles are an exception because they need a &lt;code&gt;GameEntity&lt;/code&gt;, e.g. a unit, to be spawned, thus violating the &lt;em&gt;independent&lt;/em&gt; property. They also have some special features that differentiate them from &lt;code&gt;GameEntity&lt;/code&gt;. These will be discussed in another blogpost dedicated to ranged attacks.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;GameEntity&lt;/code&gt; requires very few attributes to be defined. Only name, description, helptext, an icon and some information about the hitbox (stored in the three &lt;code&gt;radius_&lt;/code&gt; members) are strictly necessary. The other attributes of each game entity are defined through &lt;code&gt;Ability&lt;/code&gt; objects which are stored in the &lt;code&gt;abilities&lt;/code&gt; member. By adding abilities, game entities gain their main features, like animations, hp, attack damage and more. Two other set members &lt;code&gt;variants&lt;/code&gt; and &lt;code&gt;boni&lt;/code&gt; exist and are able to specialize a game entity even more. However, we will come back for them at a later date to not complicate this blogpost further.&lt;/p&gt;
&lt;p&gt;Developers and modders should not let their objects inherit directly from &lt;code&gt;GameEntity&lt;/code&gt; and instead choose one of the four child objects &lt;code&gt;Unit&lt;/code&gt;, &lt;code&gt;Ambient&lt;/code&gt;, &lt;code&gt;Item&lt;/code&gt; or &lt;code&gt;Building&lt;/code&gt;. With the exception of &lt;code&gt;Building&lt;/code&gt; these objects are just for categorization and don't require additional attributes to be defined. An &lt;code&gt;Item&lt;/code&gt; object could have the same abilities as a &lt;code&gt;Unit&lt;/code&gt; object *. However the categorization helps us, the engine developers, because we are able to design abilities that are aimed at a specific category. For example, the &lt;code&gt;PickupItem&lt;/code&gt; will first and foremost be designed to handle game entities of type &lt;code&gt;Item&lt;/code&gt;. We'll now explain what is expected from each category.&lt;/p&gt;
&lt;p&gt;* &lt;em&gt;Fun fact: Because nyan allows for multiple inheritance an object can be in more than one of the categories. So if you think that your units should also be items, you can go for it!&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Unit&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Unit&lt;/code&gt; is probably the most generic category. In general, all game entities that move, die, decay and have HP should be units. In the current API design, units are the only types of &lt;code&gt;GameEntity&lt;/code&gt; that can be trained with the &lt;code&gt;Train&lt;/code&gt; ability.&lt;/p&gt;
&lt;p&gt;Examples: military, villagers, animals&lt;/p&gt;
&lt;h2&gt;Ambient&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Ambient&lt;/code&gt; objects usually lie or stand around on the map and look pretty. Typically, these objects never move, do not have HP and some of them are harvestable for resources. Flags and flag attachements would also be classified as &lt;code&gt;Ambient&lt;/code&gt;. In AoE2 most of these objects would be owned by the neutral player &lt;em&gt;Gaia&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Examples: cactus, tree, gold/stone pile, mountain&lt;/p&gt;
&lt;h2&gt;Item&lt;/h2&gt;
&lt;p&gt;These are very similar to &lt;code&gt;Ambient&lt;/code&gt; objects, but can be put in an inventory. openage features an inventory system through the &lt;code&gt;Inventory&lt;/code&gt; ability. Items in there can have special effects on the inventory owner, provide boni or grant new abilities.&lt;/p&gt;
&lt;p&gt;Example: relic&lt;/p&gt;
&lt;h2&gt;Building&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Building" src="https://blog.openage.dev/images/D0001-building.png"&gt;&lt;/p&gt;
&lt;p&gt;Buildings are more sophisticated than the othere three categories because they have to be constructed first and need space on the map grid. Each &lt;code&gt;Building&lt;/code&gt; can have construction and damage stages that are defined in a &lt;code&gt;Progress&lt;/code&gt; object. &lt;code&gt;Progress&lt;/code&gt; objects allow buildings to display an alternative sprite after a certain percentage of &lt;em&gt;something&lt;/em&gt; is complete. The number of stages is unlimited and theoretically a building could have 100 stages of construction that each have their own graphic.&lt;/p&gt;
&lt;p&gt;It is also allowed to define more complex buildings that consist of multiple parts by using &lt;code&gt;MultiPartBuilding&lt;/code&gt;. This type acts as a container that manages several subbuildings which are allowed to have individual properties, e.g. certain abilities and boni. &lt;code&gt;MultiPartBuildings&lt;/code&gt; are also useful for modelling buildings that have passable parts like the Town Center in AoE2.&lt;/p&gt;
&lt;h1&gt;Questions?&lt;/h1&gt;
&lt;p&gt;You've chosen the perfect category for your game entities - now what? Fear no more because next time, we are finally introducing the Ability system that gives them a purpose.&lt;/p&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="nyan"></category><category term="modding"></category><category term="API"></category></entry><entry><title>D0: Openage modding API - Introduction</title><link href="https://blog.openage.dev/d0-openage-modding-api-introduction.html" rel="alternate"></link><published>2018-07-19T00:00:00+02:00</published><updated>2018-07-19T00:00:00+02:00</updated><author><name>heinezen</name></author><id>tag:blog.openage.dev,2018-07-19:/d0-openage-modding-api-introduction.html</id><summary type="html">&lt;p&gt;a first draft of the openage mod API&lt;/p&gt;</summary><content type="html">&lt;p&gt;A while ago we &lt;a href="https://blog.openage.dev/t0-nyan-api-integration.html"&gt;introduced&lt;/a&gt; our game configuration database language nyan. Now we present our efforts to integrate nyan into openage and to create a powerful and extensible modding API.&lt;/p&gt;
&lt;p&gt;Other articles in the modding API series:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Introduction (you're here)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d1-openage-modding-api-units-buildings-more.html"&gt;Units, Buildings &amp;amp; more&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d2-openage-modding-api-abilities.html"&gt;Abilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d3-openage-modding-api-patching.html"&gt;Patching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d4-openage-modding-api-archers-dont-kill-units-projectiles-do.html"&gt;Attack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d5-openage-modding-api-bonus.html"&gt;Bonus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d6-openage-modding-api-inventory-system.html"&gt;Inventory System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d7-openage-modding-api-too-many-villagers.html"&gt;Too many villagers!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d8-openage-modding-api-the-transformers.html"&gt;Transform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d9-openage-modding-api-civilizations-and-uniqueness.html"&gt;Civilizations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d10-openage-modding-api-restocking-farms.html"&gt;Restocking farms&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="https://blog.openage.dev/landing-page.html"&gt;View all articles&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;What is an API?&lt;/h1&gt;
&lt;p&gt;As you probably all know, openage is not just one game. It is intended to be a fully functional game engine that provides a &lt;em&gt;framework&lt;/em&gt; for multiple RTS games. Because any game developer can start working the engine and we cannot anticipate how they want to use it, it wouldn't be smart to have every tiny bit of game logic hardcoded. Instead, the engine should only implement general behavior and provide an &lt;em&gt;interface&lt;/em&gt; for game developers. That's where the API comes into place.&lt;/p&gt;
&lt;p&gt;An API, also known as an &lt;em&gt;application programming interface&lt;/em&gt;, is a method of exposing an engine's functionality to its users (in our case: developers and modders). Engines can implement several APIs that give access to a variety of functionality, like scripting or adding GUI elements. This blogpost will solely focus on the &lt;em&gt;modding API&lt;/em&gt; which is used for defining game data.&lt;/p&gt;
&lt;p&gt;Developers usually take the API first and then use it to derive special cases they want for their game. You may wonder how this derivation process works exactly. We are going to look at a very simple example.&lt;/p&gt;
&lt;h2&gt;API example&lt;/h2&gt;
&lt;p&gt;&lt;img alt="API example 1" src="https://blog.openage.dev/images/D0001-API-example-1.png"&gt;&lt;/p&gt;
&lt;p&gt;In this example the engine has defined a function that lets a unit run around on a map and displays their name and HP when it is selected. The function takes a very simple API object called &lt;code&gt;Unit&lt;/code&gt; as input. &lt;code&gt;Unit&lt;/code&gt; objects must have the attributes &lt;code&gt;name&lt;/code&gt; (as a text value) and &lt;code&gt;hp&lt;/code&gt; (as an integer value), but the exact value of these attributes is up to the developer. By setting the value, the special cases are derived.&lt;/p&gt;
&lt;p&gt;&lt;img alt="API example 2" src="https://blog.openage.dev/images/D0001-API-example-2.png"&gt;&lt;/p&gt;
&lt;p&gt;The above diagram shows how units for a medieval game could be defined. A developer derived the three units &lt;code&gt;Swordsman&lt;/code&gt;, &lt;code&gt;Spearman&lt;/code&gt; and &lt;code&gt;Knight&lt;/code&gt; from the generic API object &lt;code&gt;Unit&lt;/code&gt; by assigning specific values to the attributes. The engine will handle all special cases like it will handle &lt;code&gt;Unit&lt;/code&gt;, but takes their specific values into account. For example, if a &lt;code&gt;Knight&lt;/code&gt; is selected, it will display &lt;em&gt;Knight&lt;/em&gt; as the name and &lt;em&gt;120&lt;/em&gt; as the HP.&lt;/p&gt;
&lt;p&gt;A developer with a different game in mind can also utilize the API to define completely different special cases.&lt;/p&gt;
&lt;p&gt;&lt;img alt="API example 3" src="https://blog.openage.dev/images/D0001-API-example-3.png"&gt;&lt;/p&gt;
&lt;p&gt;This would also be an viable use for the API when a developer wants to have a more modern setting in their game.&lt;/p&gt;
&lt;p&gt;You might wonder if the derived objects from the two games could be used simultaneously. The answer is yes, they can!&lt;/p&gt;
&lt;p&gt;&lt;img alt="API example 4" src="https://blog.openage.dev/images/D0001-API-example-4.png"&gt;&lt;/p&gt;
&lt;p&gt;In this API design the engine essentially does not care that the theme of the medieval and the modern units is vastly different. As long as they use the same API they can be used in any combination, even if it does not make much sense. For a modding community this kind of API design is a huge benefit because it is very easy to extend, replace and combine mods.&lt;/p&gt;
&lt;p&gt;We will later see how the openage modding API handles things in a similar manner, albeit the design is much more complex.&lt;/p&gt;
&lt;h1&gt;API Overview&lt;/h1&gt;
&lt;p&gt;The UML diagram below shows the latest draft of our API and should be very close to what will be implemented in the next months.&lt;/p&gt;
&lt;p&gt;&lt;img alt="API overview" src="https://blog.openage.dev/images/D0001-API-overview.png"&gt;&lt;/p&gt;
&lt;p&gt;If you are familiar with Age of Empires 2, you most likely spotted some similarities between the game and our API objects. Although it draws inspiration from the game, modding in openage will be completely different from modding in AoE2. The openage modding API exposes much more features and should allow for very complex mods and a range of different styles of RTS gaming.&lt;/p&gt;
&lt;p&gt;Over the next weeks, we will have a look at specific parts of the API and explain how it can be used.&lt;/p&gt;
&lt;h1&gt;General design decisions&lt;/h1&gt;
&lt;p&gt;To support our goal of making modding easy and keeping the API extensible we made a few major design decisions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Single API tree&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The whole API is part of a single object tree (or graph to be more specific). All API objects inherit implicetely or explicitely from the root object &lt;code&gt;Entity&lt;/code&gt;. This will keep the hierarchy of objects consistent, even if a lot of mods are activated at once. It also allows every object to be added to a &lt;code&gt;set&lt;/code&gt; with type &lt;code&gt;Entity&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Define units through abilities&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Units are almost entirely defined through API objects of type &lt;code&gt;Ability&lt;/code&gt;. Abilities describe what a unit can &lt;em&gt;do&lt;/em&gt; (e.g. &lt;code&gt;Build&lt;/code&gt;, &lt;code&gt;Move&lt;/code&gt;, &lt;code&gt;Research&lt;/code&gt;) or what it &lt;em&gt;is&lt;/em&gt; (e.g. &lt;code&gt;Creatable&lt;/code&gt;, &lt;code&gt;Selectable&lt;/code&gt;). Most of a unit's attributes will reside in an ability. This goes so far that &lt;code&gt;Live&lt;/code&gt; itself will be an ability that stores the member &lt;code&gt;hp&lt;/code&gt; and its value. Each unit stores its abilities in a set, so that they can easily be added or removed (including through patching at runtime).&lt;/p&gt;
&lt;p&gt;Because abilities are API objects themselves, their values can be uniquely defined for each unit. For example, two different units can derive their own version of the &lt;code&gt;Move&lt;/code&gt; ability and each specify different values for &lt;code&gt;speed&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Every object that is of type &lt;code&gt;GameEntity&lt;/code&gt; (e.g. units, buildings, items, trees, gold spots &amp;amp; more) can posess any ability. The system is very powerful and allows for&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Trees training units&lt;/li&gt;
&lt;li&gt;Animals converting villagers&lt;/li&gt;
&lt;li&gt;Relics chopping wood&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;and other crazy stuff.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;All game modifications are done only by patches&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;nyan allows us to dynamically change objects' members at runtime by applying Patches. Everything from upgrading stats to unlocking units will be done by patching the members of an object. Any value can be changed and adjusted by a patch. Also, individual units or game entities on the battlefield can be patched individually. This will allow developers and modders to create special units from generic units at runtime.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No replacement of units within their life cycle&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In AoE and other strategy games objects are often replaced by a new object when they switch to a new state. This can for example be observed when unit lines are upgraded or when villagers are assigned to the various gather tasks.&lt;/p&gt;
&lt;p&gt;We cannot use that strategy for openage as patching has the potential to severely alter the member values of the unit. By replacing a unit its changes would be lost. To avoid replacing objects we have implemented a variety of solutions which will enable the objects to switch states without losing their patch history.&lt;/p&gt;
&lt;h1&gt;Questions?&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://blog.openage.dev/d1-openage-modding-api-units-buildings-more.html"&gt;Next week&lt;/a&gt; we will explain how &lt;code&gt;GameEntity&lt;/code&gt;s, the objects in the game world, are handled.&lt;/p&gt;
&lt;p&gt;Any more questions? Let us know and discuss those ideas by visiting &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="nyan"></category><category term="modding"></category><category term="API"></category></entry><entry><title>Implementing Python-Style Enums in C++</title><link href="https://blog.openage.dev/implementing-python-style-enums-in-c.html" rel="alternate"></link><published>2018-04-21T23:01:00+02:00</published><updated>2018-04-21T23:01:00+02:00</updated><author><name>zuntrax</name></author><id>tag:blog.openage.dev,2018-04-21:/implementing-python-style-enums-in-c.html</id><summary type="html">&lt;p&gt;the fun journey of implementing proper enums in C++&lt;/p&gt;</summary><content type="html">&lt;p&gt;It has been proven over and over again that we suffer from a severe form of &lt;a href="https://en.wikipedia.org/wiki/Not_invented_here"&gt;NIH&lt;/a&gt;. Today, we tried to reinvent the wheel once again, but with rockets attached, and tackled the beauty of C++17 by creating a &lt;em&gt;usable&lt;/em&gt; enum implementation.&lt;/p&gt;
&lt;p&gt;The current &lt;code&gt;openage&lt;/code&gt; enums sometimes produce linker errors on macOS and warnings on other systems:&lt;/p&gt;
&lt;details&gt;
 &lt;summary&gt;(`instanciation of enum required here, but no definition is available`)&lt;/summary&gt;
 &lt;pre&gt;
...
[ 35%] Building CXX object libopenage/CMakeFiles/libopenage.dir/log/stdout_logsink.cpp.o
In file included from /home/jj/devel/openage/libopenage/log/stdout_logsink.cpp:3:
In file included from /home/jj/devel/openage/libopenage/log/stdout_logsink.h:5:
In file included from /home/jj/devel/openage/libopenage/log/logsink.h:8:
In file included from /home/jj/devel/openage/libopenage/log/level.h:8:
/home/jj/devel/openage/libopenage/log/../util/enum.h:99:17: warning: instantiation of variable 'openage::util::Enum&lt;openage::log::level_properties&gt;::data' required here, but no definition is available [-Wundefined-var-template]
                return &amp;this-&gt;data[this-&gt;id].second;
                              ^
/home/jj/devel/openage/libopenage/log/stdout_logsink.cpp:16:33: note: in instantiation of member function 'openage::util::Enum&lt;openage::log::level_properties&gt;::operator-&gt;' requested here
        std::cout &lt;&lt; "\x1b[" &lt;&lt; msg.lvl-&gt;colorcode &lt;&lt; "m" &lt;&lt; std::setw(4) &lt;&lt; msg.lvl-&gt;name &lt;&lt; "\x1b[m" " ";
                                       ^
/home/jj/devel/openage/libopenage/log/../util/enum.h:129:19: note: forward declaration of template entity is here
        static data_type data;
                         ^
/home/jj/devel/openage/libopenage/log/../util/enum.h:99:17: note: add an explicit instantiation declaration to suppress this warning if 'openage::util::Enum&lt;openage::log::level_properties&gt;::data' is explicitly instantiated in another translation unit
                return &amp;this-&gt;data[this-&gt;id].second;
                              ^
1 warning generated.
...
 &lt;/pre&gt;
&lt;/details&gt;

&lt;p&gt;We tried getting rid of that warning several times, but that always led into a deep rabbit hole of linker errors. Now we were fed up and decided to get rid of our &lt;a href="https://github.com/SFTtech/openage/blob/faae03bcbfd6685b2db8bd80a63b5762bcfc490e/libopenage/util/enum.h"&gt;old enum implementation&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Why?&lt;/h2&gt;
&lt;p&gt;But why this own enum implementation?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Usage exactly like the &lt;code&gt;enum class&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Have a string representation of each enum value&lt;/li&gt;
&lt;li&gt;Allow member methods for the enum type&lt;/li&gt;
&lt;li&gt;Everything at compile time and accross TUs without funny &lt;code&gt;extern&lt;/code&gt; definitions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After some experiments, we implemented it with a wrapper class (&lt;code&gt;EnumValueContainer&lt;/code&gt;) which has implicit conversions to the &lt;code&gt;EnumValue&lt;/code&gt; type. The actual enum values are &lt;code&gt;constexpr static&lt;/code&gt; members of a subclass of &lt;code&gt;EnumValue&lt;/code&gt;. We need this in order to use &lt;code&gt;LogLevel&lt;/code&gt; for both containing the all possible enum values, being the type for the enum like an &lt;code&gt;enum class&lt;/code&gt; name, and using it as non-const type that references to one of the possible values.&lt;/p&gt;
&lt;p&gt;This way, the container can store a reference to its static member, i.e. a handle to a enum value like you know from &lt;code&gt;enum class&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;The remaining problem was member methods, especially because the "container" class type should also be usable a enum-value type.
To achieve this, we had the idea of using a mixin class &lt;code&gt;LogLevelMethods&lt;/code&gt; with &lt;a href="https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern"&gt;CRTP&lt;/a&gt;. This is what we came up with:&lt;/p&gt;
&lt;h4&gt;enum.h&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;
&lt;span class="normal"&gt;36&lt;/span&gt;
&lt;span class="normal"&gt;37&lt;/span&gt;
&lt;span class="normal"&gt;38&lt;/span&gt;
&lt;span class="normal"&gt;39&lt;/span&gt;
&lt;span class="normal"&gt;40&lt;/span&gt;
&lt;span class="normal"&gt;41&lt;/span&gt;
&lt;span class="normal"&gt;42&lt;/span&gt;
&lt;span class="normal"&gt;43&lt;/span&gt;
&lt;span class="normal"&gt;44&lt;/span&gt;
&lt;span class="normal"&gt;45&lt;/span&gt;
&lt;span class="normal"&gt;46&lt;/span&gt;
&lt;span class="normal"&gt;47&lt;/span&gt;
&lt;span class="normal"&gt;48&lt;/span&gt;
&lt;span class="normal"&gt;49&lt;/span&gt;
&lt;span class="normal"&gt;50&lt;/span&gt;
&lt;span class="normal"&gt;51&lt;/span&gt;
&lt;span class="normal"&gt;52&lt;/span&gt;
&lt;span class="normal"&gt;53&lt;/span&gt;
&lt;span class="normal"&gt;54&lt;/span&gt;
&lt;span class="normal"&gt;55&lt;/span&gt;
&lt;span class="normal"&gt;56&lt;/span&gt;
&lt;span class="normal"&gt;57&lt;/span&gt;
&lt;span class="normal"&gt;58&lt;/span&gt;
&lt;span class="normal"&gt;59&lt;/span&gt;
&lt;span class="normal"&gt;60&lt;/span&gt;
&lt;span class="normal"&gt;61&lt;/span&gt;
&lt;span class="normal"&gt;62&lt;/span&gt;
&lt;span class="normal"&gt;63&lt;/span&gt;
&lt;span class="normal"&gt;64&lt;/span&gt;
&lt;span class="normal"&gt;65&lt;/span&gt;
&lt;span class="normal"&gt;66&lt;/span&gt;
&lt;span class="normal"&gt;67&lt;/span&gt;
&lt;span class="normal"&gt;68&lt;/span&gt;
&lt;span class="normal"&gt;69&lt;/span&gt;
&lt;span class="normal"&gt;70&lt;/span&gt;
&lt;span class="normal"&gt;71&lt;/span&gt;
&lt;span class="normal"&gt;72&lt;/span&gt;
&lt;span class="normal"&gt;73&lt;/span&gt;
&lt;span class="normal"&gt;74&lt;/span&gt;
&lt;span class="normal"&gt;75&lt;/span&gt;
&lt;span class="normal"&gt;76&lt;/span&gt;
&lt;span class="normal"&gt;77&lt;/span&gt;
&lt;span class="normal"&gt;78&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#pragma once&lt;/span&gt;

&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;typeinfo&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;type_traits&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cxxabi.h&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;DerivedType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;NumericType&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;EnumValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// enum values cannot be copied&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;EnumValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;EnumValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// enum values are equal if the pointers are equal.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* SNIP */&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;friend&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ostream&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ostream&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;abi&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;__cxa_demangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;::&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;NumericType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;DerivedType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;EnumValueContainer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumValueContainer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumValueContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// implicit conversion operator!&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumValueContainer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* SNIP */&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;friend&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ostream&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ostream&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;NOVAL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;VAL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{};&lt;/span&gt;


&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;novalue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;EnumMethods&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;novalue&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;enable_if&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_same&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NOVAL&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;get_this&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;novalue&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;enable_if&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_same&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;VAL&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;get_this&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;loglevel.h&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#pragma once&lt;/span&gt;

&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;enum.h&amp;quot;&lt;/span&gt;


&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;novalue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;LogLevelMethods&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumMethods&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;novalue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;foo is &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;get_this&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;span class="cm"&gt;/** Here, new member values for each enum value can be added */&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;LogLevelValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumValue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LogLevelValue&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LogLevelMethods&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LogLevelValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NOVAL&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;color_code&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;span class="cm"&gt;/** Usage of the first design attempt for the new enum */&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;LogLevel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumValueContainer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LogLevelValue&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LogLevelMethods&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LogLevelValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;VAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LogLevel&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumValueContainer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LogLevelValue&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;EnumValueContainer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LogLevelValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;debug&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;31;1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LogLevelValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;info&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;32&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Thus, it is now possible to do this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;LogLevel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LogLevel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// store a handle to the static constexpr member!&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="c1"&gt;// call the enum &amp;quot;member&amp;quot; method!&lt;/span&gt;
&lt;span class="n"&gt;LogLevel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;// same, but without the LogLevel wrapper!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;But why does that work?&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;=&lt;/code&gt; assignment uses the implicit conversion from &lt;code&gt;LogLevelValue&lt;/code&gt; to &lt;code&gt;LogLevel&lt;/code&gt;. The latter stores a reference to &lt;code&gt;LogLevelValue&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;a.foo()&lt;/code&gt; call is even more obscure: The magic with &lt;code&gt;LogLevelMethods&lt;/code&gt; effectively "redirects" the &lt;code&gt;operator .&lt;/code&gt; from &lt;code&gt;LogLevel&lt;/code&gt; to &lt;code&gt;LogLevelValue&lt;/code&gt; through &lt;code&gt;LogLevelMethods&lt;/code&gt; via &lt;code&gt;EnumMethods&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;EnumMethods&lt;/code&gt; adds the &lt;code&gt;foo&lt;/code&gt; method to both the &lt;code&gt;LogLevel&lt;/code&gt; container and each &lt;code&gt;LogLevelValue&lt;/code&gt; directly, and can convert the &lt;code&gt;this&lt;/code&gt; pointer accordingly to reach the per-enum-value data. If we kept this, we probably would have added macros to simplify the template shenanigans in the declarations of &lt;code&gt;LogLevelValue&lt;/code&gt; and &lt;code&gt;LogLevel&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Containing almost standard-library-levels of template magic, we didn't exactly want to commit this to the repo.&lt;/p&gt;
&lt;h2&gt;Improvements&lt;/h2&gt;
&lt;p&gt;The &lt;strong&gt;much easier variant&lt;/strong&gt;, which works without a redirect/"overload" of the &lt;code&gt;operator .&lt;/code&gt; is to just use &lt;code&gt;operator -&amp;gt;&lt;/code&gt; instead, which can actually be overloaded without hacks:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;EnumValueContainer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;LogLevelValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumValue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LogLevelValue&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;color_code&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// of course, more members and functions could be added here&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;foo: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/** Usage of the &amp;quot;final&amp;quot; design for our new enum */&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;LogLevel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumValueContainer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LogLevelValue&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumValueContainer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LogLevelValue&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;EnumValueContainer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LogLevelValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;debug&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;31;1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LogLevelValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;info&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;32&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now, we can just call it with &lt;code&gt;-&amp;gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;LogLevel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lvl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LogLevel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;lvl&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Mind that all this &lt;strong&gt;only works with C++17&lt;/strong&gt;.&lt;/p&gt;
&lt;details&gt;
 &lt;summary&gt;Here is the full code for our new enum (GPLv3 or later):&lt;/summary&gt;

#### Enum definition:

&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;  1&lt;/span&gt;
&lt;span class="normal"&gt;  2&lt;/span&gt;
&lt;span class="normal"&gt;  3&lt;/span&gt;
&lt;span class="normal"&gt;  4&lt;/span&gt;
&lt;span class="normal"&gt;  5&lt;/span&gt;
&lt;span class="normal"&gt;  6&lt;/span&gt;
&lt;span class="normal"&gt;  7&lt;/span&gt;
&lt;span class="normal"&gt;  8&lt;/span&gt;
&lt;span class="normal"&gt;  9&lt;/span&gt;
&lt;span class="normal"&gt; 10&lt;/span&gt;
&lt;span class="normal"&gt; 11&lt;/span&gt;
&lt;span class="normal"&gt; 12&lt;/span&gt;
&lt;span class="normal"&gt; 13&lt;/span&gt;
&lt;span class="normal"&gt; 14&lt;/span&gt;
&lt;span class="normal"&gt; 15&lt;/span&gt;
&lt;span class="normal"&gt; 16&lt;/span&gt;
&lt;span class="normal"&gt; 17&lt;/span&gt;
&lt;span class="normal"&gt; 18&lt;/span&gt;
&lt;span class="normal"&gt; 19&lt;/span&gt;
&lt;span class="normal"&gt; 20&lt;/span&gt;
&lt;span class="normal"&gt; 21&lt;/span&gt;
&lt;span class="normal"&gt; 22&lt;/span&gt;
&lt;span class="normal"&gt; 23&lt;/span&gt;
&lt;span class="normal"&gt; 24&lt;/span&gt;
&lt;span class="normal"&gt; 25&lt;/span&gt;
&lt;span class="normal"&gt; 26&lt;/span&gt;
&lt;span class="normal"&gt; 27&lt;/span&gt;
&lt;span class="normal"&gt; 28&lt;/span&gt;
&lt;span class="normal"&gt; 29&lt;/span&gt;
&lt;span class="normal"&gt; 30&lt;/span&gt;
&lt;span class="normal"&gt; 31&lt;/span&gt;
&lt;span class="normal"&gt; 32&lt;/span&gt;
&lt;span class="normal"&gt; 33&lt;/span&gt;
&lt;span class="normal"&gt; 34&lt;/span&gt;
&lt;span class="normal"&gt; 35&lt;/span&gt;
&lt;span class="normal"&gt; 36&lt;/span&gt;
&lt;span class="normal"&gt; 37&lt;/span&gt;
&lt;span class="normal"&gt; 38&lt;/span&gt;
&lt;span class="normal"&gt; 39&lt;/span&gt;
&lt;span class="normal"&gt; 40&lt;/span&gt;
&lt;span class="normal"&gt; 41&lt;/span&gt;
&lt;span class="normal"&gt; 42&lt;/span&gt;
&lt;span class="normal"&gt; 43&lt;/span&gt;
&lt;span class="normal"&gt; 44&lt;/span&gt;
&lt;span class="normal"&gt; 45&lt;/span&gt;
&lt;span class="normal"&gt; 46&lt;/span&gt;
&lt;span class="normal"&gt; 47&lt;/span&gt;
&lt;span class="normal"&gt; 48&lt;/span&gt;
&lt;span class="normal"&gt; 49&lt;/span&gt;
&lt;span class="normal"&gt; 50&lt;/span&gt;
&lt;span class="normal"&gt; 51&lt;/span&gt;
&lt;span class="normal"&gt; 52&lt;/span&gt;
&lt;span class="normal"&gt; 53&lt;/span&gt;
&lt;span class="normal"&gt; 54&lt;/span&gt;
&lt;span class="normal"&gt; 55&lt;/span&gt;
&lt;span class="normal"&gt; 56&lt;/span&gt;
&lt;span class="normal"&gt; 57&lt;/span&gt;
&lt;span class="normal"&gt; 58&lt;/span&gt;
&lt;span class="normal"&gt; 59&lt;/span&gt;
&lt;span class="normal"&gt; 60&lt;/span&gt;
&lt;span class="normal"&gt; 61&lt;/span&gt;
&lt;span class="normal"&gt; 62&lt;/span&gt;
&lt;span class="normal"&gt; 63&lt;/span&gt;
&lt;span class="normal"&gt; 64&lt;/span&gt;
&lt;span class="normal"&gt; 65&lt;/span&gt;
&lt;span class="normal"&gt; 66&lt;/span&gt;
&lt;span class="normal"&gt; 67&lt;/span&gt;
&lt;span class="normal"&gt; 68&lt;/span&gt;
&lt;span class="normal"&gt; 69&lt;/span&gt;
&lt;span class="normal"&gt; 70&lt;/span&gt;
&lt;span class="normal"&gt; 71&lt;/span&gt;
&lt;span class="normal"&gt; 72&lt;/span&gt;
&lt;span class="normal"&gt; 73&lt;/span&gt;
&lt;span class="normal"&gt; 74&lt;/span&gt;
&lt;span class="normal"&gt; 75&lt;/span&gt;
&lt;span class="normal"&gt; 76&lt;/span&gt;
&lt;span class="normal"&gt; 77&lt;/span&gt;
&lt;span class="normal"&gt; 78&lt;/span&gt;
&lt;span class="normal"&gt; 79&lt;/span&gt;
&lt;span class="normal"&gt; 80&lt;/span&gt;
&lt;span class="normal"&gt; 81&lt;/span&gt;
&lt;span class="normal"&gt; 82&lt;/span&gt;
&lt;span class="normal"&gt; 83&lt;/span&gt;
&lt;span class="normal"&gt; 84&lt;/span&gt;
&lt;span class="normal"&gt; 85&lt;/span&gt;
&lt;span class="normal"&gt; 86&lt;/span&gt;
&lt;span class="normal"&gt; 87&lt;/span&gt;
&lt;span class="normal"&gt; 88&lt;/span&gt;
&lt;span class="normal"&gt; 89&lt;/span&gt;
&lt;span class="normal"&gt; 90&lt;/span&gt;
&lt;span class="normal"&gt; 91&lt;/span&gt;
&lt;span class="normal"&gt; 92&lt;/span&gt;
&lt;span class="normal"&gt; 93&lt;/span&gt;
&lt;span class="normal"&gt; 94&lt;/span&gt;
&lt;span class="normal"&gt; 95&lt;/span&gt;
&lt;span class="normal"&gt; 96&lt;/span&gt;
&lt;span class="normal"&gt; 97&lt;/span&gt;
&lt;span class="normal"&gt; 98&lt;/span&gt;
&lt;span class="normal"&gt; 99&lt;/span&gt;
&lt;span class="normal"&gt;100&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// Copyright 2018 the openage authors, GPLv3 or later.&lt;/span&gt;
&lt;span class="cp"&gt;#pragma once&lt;/span&gt;

&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;typeinfo&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cxxabi.h&amp;gt;&lt;/span&gt;


&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;DerivedType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;NumericType&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;EnumValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// enum values cannot be copied&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;EnumValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;EnumValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// enum values are equal if the pointers are equal.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;numeric&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;numeric&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;numeric&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;numeric&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;friend&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ostream&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ostream&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;abi&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;__cxa_demangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;::&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;NumericType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;DerivedType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;EnumValueContainer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumValueContainer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumValueContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumValueContainer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DerivedType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;friend&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ostream&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ostream&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;



#### Usage:

&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#pragma once&lt;/span&gt;

&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;enum.h&amp;quot;&lt;/span&gt;


&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;LogLevelValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumValue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LogLevelValue&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;color_code&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bar is &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot; and &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;color_code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;LogLevel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumValueContainer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LogLevelValue&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EnumValueContainer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LogLevelValue&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;EnumValueContainer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LogLevelValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;debug&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;31;1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LogLevelValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;info&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;32&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;LogLevel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LogLevel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot; =&amp;gt; &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LogLevel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LogLevel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;



&lt;/details&gt;

&lt;p&gt;Oh C++, such an adventure game.&lt;/p&gt;</content><category term="blog"></category><category term="C++"></category><category term="templates"></category></entry><entry><title>T2: Curve and nyan roadmap</title><link href="https://blog.openage.dev/t2-curve-and-nyan-roadmap.html" rel="alternate"></link><published>2018-01-25T00:00:00+01:00</published><updated>2018-01-25T00:00:00+01:00</updated><author><name>jj</name></author><id>tag:blog.openage.dev,2018-01-25:/t2-curve-and-nyan-roadmap.html</id><summary type="html">&lt;p&gt;our next steps for integrating the event driven gamesimulation configured by nyan into openage&lt;/p&gt;</summary><content type="html">&lt;p&gt;After a very long planning and development phase,
two of our new core components are implemented:
&lt;a href="https://github.com/SFTtech/nyan"&gt;nyan&lt;/a&gt; and
the &lt;a href="https://blog.openage.dev/t1-curves-logic.html"&gt;curves&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Both are designed to work together:
&lt;code&gt;nyan&lt;/code&gt; provides the configuration building blocks,
the &lt;code&gt;curves&lt;/code&gt; enable our tickless, event-based game engine to work.
Now, we only have to combine them in order
to run &lt;a href="https://github.com/SFTtech/openage"&gt;openage&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Replacement strategy&lt;/h2&gt;
&lt;p&gt;The current simulation, which is implemented with a classic time step loop,
will be replaced by the new event based game simulation system.&lt;/p&gt;
&lt;p&gt;The replacement will be done in several steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Design of the &lt;a href="https://github.com/SFTtech/openage/issues/964"&gt;game state structure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Design of the &lt;code&gt;nyan&lt;/code&gt; model (i. e. API objects) for configuring the game state structure&lt;/li&gt;
&lt;li&gt;Creation of a &lt;a href="https://github.com/SFTtech/openage/issues/632"&gt;mod pack format&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The convert script has to create a mod pack with assets and &lt;code&gt;nyan&lt;/code&gt; files from the original game&lt;/li&gt;
&lt;li&gt;The engine has to load mod packs and start a basic game with a moving unit&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://github.com/SFTtech/openage/pull/850"&gt;new renderer&lt;/a&gt; has to be combined with the new simulation core&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those steps are tracked in a &lt;a href="https://github.com/SFTtech/openage/projects/14"&gt;github project board&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The first step is the cleanup and merge of the &lt;a href="https://github.com/SFTtech/openage/pull/744"&gt;eventsystem code&lt;/a&gt;.
Meanwhile we think about the &lt;code&gt;nyan&lt;/code&gt; API and the modpack format.&lt;/p&gt;
&lt;p&gt;Once the eventsystem is merged, we create a &lt;a href="https://github.com/SFTtech/openage/blob/master/doc/code/testing.md#demos"&gt;demo&lt;/a&gt;,
which basically is a new &lt;code&gt;main()&lt;/code&gt;.
In this, we slowly add features so game entities are instanced by &lt;code&gt;nyan&lt;/code&gt;
until we have a simple standing unit (militia, for simplicity).&lt;/p&gt;
&lt;p&gt;In order to see this on-screen, the &lt;a href="https://github.com/SFTtech/openage/pull/850"&gt;new renderer&lt;/a&gt; has to be able to display the terrain and units.&lt;/p&gt;
&lt;p&gt;After that, we should add create the &lt;code&gt;Movement&lt;/code&gt; ability, which allows walking around.
The pathfinding can remain very stupid (like our current implementation is),
but in the future should be far more sophisticated.
It should be quite easy to improve and extend.&lt;/p&gt;
&lt;p&gt;Likewise, we have to add &lt;a href="https://github.com/SFTtech/openage/issues/816"&gt;many other abilities&lt;/a&gt; to the new simulation.&lt;/p&gt;
&lt;p&gt;Once the demo is nearly as good as the current game,
we just enable it as the new main function of the game.&lt;/p&gt;
&lt;p&gt;Sounds easy, right? Then let's do it.&lt;/p&gt;
&lt;h2&gt;Questions&lt;/h2&gt;
&lt;p&gt;Do you have something to discuss? Visit &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;And you can reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="nyan"></category><category term="curves"></category><category term="API"></category><category term="roadmap"></category></entry><entry><title>T1: Curves logic</title><link href="https://blog.openage.dev/t1-curves-logic.html" rel="alternate"></link><published>2017-08-22T00:00:00+02:00</published><updated>2017-08-22T00:00:00+02:00</updated><author><name>jw</name></author><id>tag:blog.openage.dev,2017-08-22:/t1-curves-logic.html</id><summary type="html">&lt;p&gt;curves are simulation environment independent of discretisation&lt;/p&gt;</summary><content type="html">&lt;p&gt;The most important component of most games is the core gamestate. It contains all information relevant for the internal game logic, which the other components take into account and use for example for rendering or network transmission.&lt;/p&gt;
&lt;h2&gt;Gamestate Interpolation&lt;/h2&gt;
&lt;p&gt;The naive approach to this problem would be having a list of objects, every object has a position and hitpoints. If a object receives a move command, we can calculate a path, and move it along this path, frame by frame with deterministic lockstepping, whereby with the knowledge of how much time &lt;code&gt;dt&lt;/code&gt; has passed since the last frame, the current &lt;code&gt;position&lt;/code&gt; and the current &lt;code&gt;speed&lt;/code&gt; of a unit, we can integrate the position like&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This approach has the major benefit of being really simple, and there is not much fancyness involved.
This is the most simple, the &lt;a href="https://en.wikipedia.org/wiki/Euler_method"&gt;Euler integration&lt;/a&gt; method.
There are many more, more accurate and more calculation-heavy interpolations, but they all have the same drawbacks.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It is really hard to go back in time without keeping a store of old values.&lt;/li&gt;
&lt;li&gt;You diverge from your optimal path just because of numerical effects.&lt;/li&gt;
&lt;li&gt;You have to lay hand on every single object to update their position on each tick, even if they are not rendered at the moment.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Curves - the answer of your dreams?&lt;/h2&gt;
&lt;p&gt;And so we came up with another idea - the Curves, &lt;a href="https://blog.forrestthewoods.com/the-tech-of-planetary-annihilation-chronocam-292e3d6b169a#.lmxbu3vld"&gt;inspired&lt;/a&gt; by Planetary Annihilation.&lt;/p&gt;
&lt;p&gt;A curve is a collection of&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;#  time    value&lt;/span&gt;
&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;450&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;750&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The curve is visualized in the below image, whereby tha ball is flying in different directions.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Curve Graph" src="https://blog.openage.dev/images/T0001-timeline.png"&gt;&lt;/p&gt;
&lt;p&gt;containing for example the path of an object on the map over the time from 0 to 750ms.
What we see there is the list of keyframes to describe the position of an object, going from middle to right to left and back playing ping-pong.&lt;/p&gt;
&lt;p&gt;To access for example the position of the object at &lt;code&gt;now=100ms&lt;/code&gt; we can calulate between two keyframes: &lt;code&gt;(t0, k0)&lt;/code&gt; and &lt;code&gt;(t1, k1)&lt;/code&gt;. We hereby use element-wise addition and substraction of vectors and multiplication of a vector with a scalar.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;100ms&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k0&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;k1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;t0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;t0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.66&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.66&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;66.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Which is right between the two key-frames - the red dot in the above image.&lt;/p&gt;
&lt;h2&gt;It is awesome!&lt;/h2&gt;
&lt;p&gt;Now to move from a ball playing ping pong to units.
As you see - it is slightly more expensive to calulate the exact position of one unit, but this does not need to happen every frame for every unit, but instead only for those that are currently on screen. So huge armies, that are larger than a screen do not have to be interpolated as whole all the time.&lt;/p&gt;
&lt;p&gt;Another thing that comes free house is that it is very simple to go back to any point in time, since the old keyframes are not overwritten for new values.
And for RAM saving purposes, we can always remove keyframes that are not relevant anymore and lay some time in the past.&lt;/p&gt;
&lt;p&gt;This approach also does not accumulate floating point errors as fast as frame-by-frame interpolation, since key-frames lay further appart, and are not calculated as often.
The constant floating point error that occurs within the interpolation is negligible, since it is not integrated over.&lt;/p&gt;
&lt;h2&gt;Or maybe not?&lt;/h2&gt;
&lt;p&gt;Of course this approach has major drawbacks, especially if the future of a object is changing very often or is not predictable at all. This is the case for any user-controlled unit, because users are the major source of randomness, and curves do not like users.
But for command-driven genres like adventure-games, puzzle-games or realtime strategy games this comes in handy.
We only have to calculate the path of a unit once, and as long as we do not look, we do not care where the unit is - except if it collides with something else on the path. But that is a story for another time.&lt;/p&gt;
&lt;h2&gt;So can everything be represented as a curve?&lt;/h2&gt;
&lt;p&gt;There is a short answer to that, and a long one. the short answer is: &lt;em&gt;Yes!&lt;/em&gt;. And not can. Must!&lt;/p&gt;
&lt;p&gt;The long answer is: to be able to fully integrate the curve logic into the game logic, it is not sufficient to only use positions of objects. it is neccessary to track the hitpoints as well - because the path of the unit depends on the hitpoints of the building the unit is currently avoiding.
And the hitpoints of the unit depend on how many enemies are currenytly attacking it. How many enemies are attacking it depends on when the unit was built in the barracks. When the unit was built in the barracks depends on how many ressources are there ... gathering ... villager producing ... existence of town center ... it would go on all night.
So every value in the gamestate has to be time-dependent - a curve.&lt;/p&gt;
&lt;p&gt;The smallest common datatypes that can be used here are linear interpolated curves, as seen above, and discrete curves, that hold a value until the next keyframe.
Discrete curves do not need to be interpolated, and so they can contain data, that does not define "-" or "+", like strings and objects and nyan references.&lt;/p&gt;
&lt;h2&gt;Integration&lt;/h2&gt;
&lt;p&gt;Now you might wonder how &lt;code&gt;curves&lt;/code&gt; works together with the rest of the engine?
We've got many ideas there and are experimenting how the simulation could be done best,
but the overall structure boils down to this:&lt;/p&gt;
&lt;pre&gt;
client:
[nyan] &lt;-&gt; simulation playback/prediction with curves &lt;-&gt; [presenter: gui, renderer, audio]
           ^
           | network
server:    v
[nyan] &lt;-&gt; authoritative simulation with curves
&lt;/pre&gt;

&lt;p&gt;This architecture allows us to have one dedicated game server (which can be run by any player)
and users can still do client-side modding.&lt;/p&gt;
&lt;p&gt;Once the plan is more clear we'll explain the inner workings of the simulation and prediction.&lt;/p&gt;
&lt;h2&gt;Questions&lt;/h2&gt;
&lt;p&gt;Wanna discuss those ideas? Visit &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="curves"></category><category term="API"></category></entry><entry><title>T0: nyan API integration</title><link href="https://blog.openage.dev/t0-nyan-api-integration.html" rel="alternate"></link><published>2017-08-13T10:20:00+02:00</published><updated>2017-08-13T10:20:00+02:00</updated><author><name>jj</name></author><id>tag:blog.openage.dev,2017-08-13:/t0-nyan-api-integration.html</id><summary type="html">&lt;p&gt;nyan will be used for as content interface in openage&lt;/p&gt;</summary><content type="html">&lt;p&gt;This is probably our zeroth technical information post,
it may be informative to you if you want to follow development more closely.
We'll post more things on an irregular basis :)&lt;/p&gt;
&lt;h1&gt;What's nyan?&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://github.com/SFTtech/nyan"&gt;nyan&lt;/a&gt; is our new database for storing the game configuration:
It provides which units are available, what they can do, cultures, technologies,
i.e. everything that makes openage behave and look like age of empires.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;nyan&lt;/code&gt; also functions as mod-API, as it is designed to be easily usable and extensible
for content creators and modders.
After some minor changes and improvements in &lt;code&gt;nyan&lt;/code&gt;,
we start to integrate it into the engine and use it as data source.&lt;/p&gt;
&lt;p&gt;For this, we need to create the "openage API", i.e. everything the engine can do.
The API is defined in &lt;code&gt;nyan&lt;/code&gt;-files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The engine accesses content data by names and structures it defined in the API&lt;/li&gt;
&lt;li&gt;The game content is created and set up with this API&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;API Example&lt;/h2&gt;
&lt;p&gt;For example this could be a simplified version of the openage API,
defined in valid &lt;code&gt;nyan&lt;/code&gt; code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;
&lt;span class="normal"&gt;36&lt;/span&gt;
&lt;span class="normal"&gt;37&lt;/span&gt;
&lt;span class="normal"&gt;38&lt;/span&gt;
&lt;span class="normal"&gt;39&lt;/span&gt;
&lt;span class="normal"&gt;40&lt;/span&gt;
&lt;span class="normal"&gt;41&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;

&lt;span class="n"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;hp&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;abilities&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Ability&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# probably much more is missing here :)&lt;/span&gt;

&lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;
    &lt;span class="n"&gt;icon&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;

&lt;span class="n"&gt;DropSite&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;accepted_resources&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ResourceProvider&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;resource_type&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Resource&lt;/span&gt;
    &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;

&lt;span class="n"&gt;ResourceSpot&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;provided_resources&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ResourceProvider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;Animation&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;
    &lt;span class="n"&gt;frames&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
    &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;15.0&lt;/span&gt;
    &lt;span class="c1"&gt;# ^ the above information could also be in&lt;/span&gt;
    &lt;span class="c1"&gt;#   some info file that accompanies the image&lt;/span&gt;

&lt;span class="n"&gt;Ability&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;animation&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Animation&lt;/span&gt;

&lt;span class="n"&gt;Movement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Ability&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
    &lt;span class="n"&gt;instant&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
    &lt;span class="nb"&gt;range&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inf&lt;/span&gt;

&lt;span class="n"&gt;HarvestResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Movement&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Resource&lt;/span&gt;
    &lt;span class="n"&gt;harvest_animation&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Animation&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Using that API, we can now create content for a game that is running on the engine, e.g. our AoE2 implementation:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;
&lt;span class="normal"&gt;36&lt;/span&gt;
&lt;span class="normal"&gt;37&lt;/span&gt;
&lt;span class="normal"&gt;38&lt;/span&gt;
&lt;span class="normal"&gt;39&lt;/span&gt;
&lt;span class="normal"&gt;40&lt;/span&gt;
&lt;span class="normal"&gt;41&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Wood&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;chop chop&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;icon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;wood.svg&amp;quot;&lt;/span&gt;

&lt;span class="n"&gt;Tree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ResourceSpot&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;big ol&amp;#39; oak&amp;quot;&lt;/span&gt;

    &lt;span class="n"&gt;TreeWood&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ResourceProvider&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;resource_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Wood&lt;/span&gt;
        &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;

    &lt;span class="n"&gt;provided_resources&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;TreeWood&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="n"&gt;Villager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="n"&gt;Walking&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Movement&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;WalkingAnim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Animation&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;walking_villager.png&amp;quot;&lt;/span&gt;
            &lt;span class="n"&gt;frames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;

        &lt;span class="n"&gt;animation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WalkingAnim&lt;/span&gt;
        &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;15.0&lt;/span&gt;

    &lt;span class="n"&gt;HarvestWood&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HarvestResource&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;Transport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Animation&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;wood_transport.png&amp;quot;&lt;/span&gt;
            &lt;span class="n"&gt;frames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;

        &lt;span class="n"&gt;Chop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Animation&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;wood_cutting.png&amp;quot;&lt;/span&gt;
            &lt;span class="n"&gt;frames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;

        &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Wood&lt;/span&gt;
        &lt;span class="n"&gt;animation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Transport&lt;/span&gt;
        &lt;span class="n"&gt;harvest_animation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Chop&lt;/span&gt;
        &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;12.0&lt;/span&gt;

    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Villager&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;hp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;
    &lt;span class="n"&gt;abilities&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Walking&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HarvestWood&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If we now assume the engine properly implements the expected behavior of the API,
this could be an intuitive definition of a villager that can do wood cutting.&lt;/p&gt;
&lt;p&gt;The content for AoE1 can be described just as easily.
Modders will have a great time because they can add any object and action on the fly, as long as it uses the API.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You want to add a new resource? Define it, add resource spots and the harvesting action and it's in the game.&lt;/li&gt;
&lt;li&gt;You want "special moves" or hero units like in Warcraft 3 or AoM? Just define a new ability, add it to the units that shall have it and you're good to go.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You may now ask yourself "why the data is described this way and not another?"&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The majority of errors are checked at load-time through the &lt;code&gt;nyan&lt;/code&gt; type system.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nyan&lt;/code&gt; allows to change the data at run time with patches:&lt;ul&gt;
&lt;li&gt;A patch object defines changes to member values of a target object.&lt;/li&gt;
&lt;li&gt;This means that every possible change is already stored in the database.&lt;/li&gt;
&lt;li&gt;When mods e.g. add new abilities to a unit, this is done by a patch activated when your mod is activated.&lt;/li&gt;
&lt;li&gt;When you click a button for technology research, a patch is applied (villager now has +10 HP for example).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In essence: &lt;strong&gt;all game modifications&lt;/strong&gt; are done only by patches.
Be it technology research, development testing, mods or total gameplay overhauls.&lt;/p&gt;
&lt;p&gt;Here, have an overly-simplified example with the loom technology,
the first research usually available in the town center.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Loom&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Villager&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;hp&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;

&lt;span class="n"&gt;TownCenter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;researches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Loom&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The openage engine implements the feature "research buttons", which will activate the patch if a user clicked on it.
Missing in the example is of course configuration of the button look, delay, cost for the research etc, but you get the point.&lt;/p&gt;
&lt;h2&gt;Integration&lt;/h2&gt;
&lt;p&gt;Now you might wonder how &lt;code&gt;nyan&lt;/code&gt; works together with the rest of the engine?
We've got many ideas there and are experimenting how the simulation could be done best,
but the overall structure boils down to this:&lt;/p&gt;
&lt;pre&gt;
client:
nyan &lt;-&gt; [simulation playback/prediction with curves] &lt;-&gt; [presenter: gui, renderer, audio]
           ^
           | network
server:    v
nyan &lt;-&gt; [authoritative simulation with curves]
&lt;/pre&gt;

&lt;p&gt;This architecture allows us to have one dedicated game server (which can be run by any player)
and users can still do client-side modding.&lt;/p&gt;
&lt;p&gt;Once the plan is more clear we'll explain the inner workings of the simulation and prediction.&lt;/p&gt;
&lt;h2&gt;Questions&lt;/h2&gt;
&lt;p&gt;Wanna discuss those ideas? Visit &lt;a href="https://reddit.com/r/openage"&gt;our subreddit /r/openage&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;As always, if you want to reach us directly in the dev chatroom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Matrix: &lt;code&gt;#sfttech:matrix.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IRC: &lt;code&gt;#sfttech&lt;/code&gt; on libera.chat&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category><category term="nyan"></category><category term="API"></category></entry><entry><title>Stupid Test</title><link href="https://blog.openage.dev/stupid-test.html" rel="alternate"></link><published>2017-08-12T00:01:00+02:00</published><updated>2017-08-12T00:01:00+02:00</updated><author><name>anon</name></author><id>tag:blog.openage.dev,2017-08-12:/stupid-test.html</id><summary type="html">&lt;p&gt;This test is totally meaningless as it just is a test.
It contains literally no information. Go away. No reason to continue reading.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;wtf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;You can try as hard as you like, no riddle is hidden here.&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wtf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As you can see, boring things like code highlighting …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This test is totally meaningless as it just is a test.
It contains literally no information. Go away. No reason to continue reading.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;wtf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;You can try as hard as you like, no riddle is hidden here.&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wtf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As you can see, boring things like code highlighting works.
This is all defined in funny markdown files (may actually not be funny).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;TotallyUseless&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;its_very_boring&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stupid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;yes_even_here&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;its_very_boring&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;TotallyUseless&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;seriously&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;it&amp;#39;s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;37&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;not&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;getting&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;235&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;better&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;do_nothing&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;yes_even_here&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;do_nothing&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;seriously&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;protected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;yes_even_here&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;seriously&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;After some extensive suffering, it's also possible to draw tables:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;This is&lt;/th&gt;
&lt;th&gt;such a table&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;it also&lt;/td&gt;
&lt;td&gt;contains no content&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;you may&lt;/td&gt;
&lt;td&gt;have guessed this.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;but it&lt;/td&gt;
&lt;td&gt;looks pretty.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;And because sometimes you have non-code preformatted text,
we have a &lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt; feature.&lt;/p&gt;
&lt;pre&gt;
This allows drawing
░█░█░█▀▀░█▀▀░█░░░█▀▀░█▀▀░█▀▀░░░█▀█░█▀▀░█▀▀░▀█▀░▀█▀░░░░░█▀█░█▀▄░▀█▀░█
░█░█░▀▀█░█▀▀░█░░░█▀▀░▀▀█░▀▀█░░░█▀█░▀▀█░█░░░░█░░░█░░▄▄▄░█▀█░█▀▄░░█░░▀
░▀▀▀░▀▀▀░▀▀▀░▀▀▀░▀▀▀░▀▀▀░▀▀▀░░░▀░▀░▀▀▀░▀▀▀░▀▀▀░▀▀▀░░░░░▀░▀░▀░▀░░▀░░▀
&lt;/pre&gt;

&lt;p&gt;I now congratulate you warmly for standing through reading all this nonsense.&lt;/p&gt;
&lt;p&gt;You may now report your fabulous reading experience on &lt;a href="https://reddit.com/r/openage"&gt;/r/openage&lt;/a&gt;.&lt;/p&gt;</content><category term="blog"></category></entry><entry><title>Landing Page</title><link href="https://blog.openage.dev/landing-page.html" rel="alternate"></link><published>2013-08-21T00:00:00+02:00</published><updated>2013-08-21T00:00:00+02:00</updated><author><name>everyone</name></author><id>tag:blog.openage.dev,2013-08-21:/landing-page.html</id><summary type="html">&lt;p&gt;Landing page for all blog articles&lt;/p&gt;</summary><content type="html">&lt;h1&gt;Curve Logic&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/t1-curves-logic.html"&gt;Curves Logic Introduction&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Nyan roadmap&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/t0-nyan-api-integration.html"&gt;nyan API integration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/t2-curve-and-nyan-roadmap.html"&gt;Curve and nyan roadmap&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Modding API&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d0-openage-modding-api-introduction.html"&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d1-openage-modding-api-units-buildings-more.html"&gt;Units, Buildings &amp;amp; more&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d2-openage-modding-api-abilities.html"&gt;Abilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d3-openage-modding-api-patching.html"&gt;Patching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d4-openage-modding-api-archers-dont-kill-units-projectiles-do.html"&gt;Attack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d5-openage-modding-api-bonus.html"&gt;Bonus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d6-openage-modding-api-inventory-system.html"&gt;Inventory System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d7-openage-modding-api-too-many-villagers.html"&gt;Too many villagers!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d8-openage-modding-api-the-transformers.html"&gt;Transform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d9-openage-modding-api-civilizations-and-uniqueness.html"&gt;Civilizations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d10-openage-modding-api-restocking-farms.html"&gt;Restocking farms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d11-openage-modding-api-additions-and-updates.html"&gt;Intermission I&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/openage-modding-api-effects.html"&gt;Effects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d13-openage-modding-api-diplomatic-stances-more-updates.html"&gt;Diplomatic Stances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.openage.dev/d14-openage-modding-api-finale.html"&gt;Finale&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</content><category term="blog"></category><category term="overview"></category></entry></feed>