<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://staging-wiki.unvanquished.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Afontain</id>
	<title>Unvanquished - User contributions [en-gb]</title>
	<link rel="self" type="application/atom+xml" href="https://staging-wiki.unvanquished.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Afontain"/>
	<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/wiki/Special:Contributions/Afontain"/>
	<updated>2026-04-05T00:28:47Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.8</generator>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Bot_skillset_modding&amp;diff=8352</id>
		<title>Bot skillset modding</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Bot_skillset_modding&amp;diff=8352"/>
		<updated>2023-05-31T12:07:50Z</updated>

		<summary type="html">&lt;p&gt;Afontain: Update the referenced PR&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This wiki page explains the skilltree as of https://github.com/Unvanquished/Unvanquished/pull/2635.&lt;br /&gt;
&lt;br /&gt;
== Basic principle ==&lt;br /&gt;
&lt;br /&gt;
[[File:Bot-skilltree-basic.png|thumbnail|An example of skilltree structure]]&lt;br /&gt;
&lt;br /&gt;
Each skill is a boolean on/off tag, that has some chance of being unlocked. As long as there are skill points to spend, the next skill is selected randomly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Visualising the skilltree ==&lt;br /&gt;
&lt;br /&gt;
There are two commands, &amp;lt;code&amp;gt;/devbotcountskillpoints&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;/devbotgraphskilltree [skillLevel]&amp;lt;/code&amp;gt; that can help handling the skilltree.&lt;br /&gt;
&lt;br /&gt;
The first command, &amp;lt;code&amp;gt;/devbotcountskillpoints&amp;lt;/code&amp;gt;, just prints a message with the total cost of (reachable) skills in the tree for each team. This can help figuring out the maximum budget want.&lt;br /&gt;
&lt;br /&gt;
[[File:Bot-skilltree-advanced.png|thumbnail|Here's an advanced example where the buy-modern-armor skill is a base-skill (always enabled) and the prefer-armor skill is disabled (never selected randomly)]]&lt;br /&gt;
&lt;br /&gt;
The second command, &amp;lt;code&amp;gt;/devbotgraphskilltree [skillLevel]&amp;lt;/code&amp;gt; saves a &amp;lt;code&amp;gt;.dot&amp;lt;/code&amp;gt; graph file that can be converted to an image. For example one can do this in the game console:&lt;br /&gt;
 /devbotgraphskilltree 5&lt;br /&gt;
 game/bot-skilltree-alien.dot written &lt;br /&gt;
 game/bot-skilltree-human.dot written &lt;br /&gt;
&lt;br /&gt;
Then (e.g.) this in a terminal:&lt;br /&gt;
 $ dot -Tpng ~/.local/share/unvanquished/game/bot-skilltree-human.dot &amp;gt; result.png &amp;amp;&amp;amp; xdg-open result.png&lt;br /&gt;
&lt;br /&gt;
If one gives the skill level as an argument argument to the &amp;lt;code&amp;gt;/devbotgraphskilltree&amp;lt;/code&amp;gt; command, it will print the statistics for that skill level, with colors for the disabled and forced skills.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Modifying and tweaking the skilltree ==&lt;br /&gt;
&lt;br /&gt;
Depending on your objectives, which maybe to offer diverse and interesting bots e.g. for a juggernaut mod, or to provide very predictable bots e.g. for a tournament, you may have different desire for bot customisations. The current implementation of the skilltree should be flexible enough to allow this.&lt;br /&gt;
&lt;br /&gt;
The skill selection process is customised by these cvars:&lt;br /&gt;
* &amp;lt;code&amp;gt;g_skillset_baseSkills&amp;lt;/code&amp;gt; which set the initial skills for the various skill levels.&lt;br /&gt;
* &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;g_skillset_disabledSkills&amp;lt;/code&amp;gt;, which will prevent skills from being randomly selected.&lt;br /&gt;
&lt;br /&gt;
=== Skilltree in pure random &amp;quot;mode&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You sometime want to have maximum randomness in your opponents, with a purely random skill setup. For example this can make PvE games or Juggernaut fights more interesting.&lt;br /&gt;
&lt;br /&gt;
You can do that by:&lt;br /&gt;
* setting the &amp;lt;code&amp;gt;g_skillset_baseSkills&amp;lt;/code&amp;gt; cvar to an empty string &lt;br /&gt;
* giving some skill funds for your bots to randomly choose from, using the &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt; cvars.&lt;br /&gt;
&lt;br /&gt;
In the current implementation, you get &amp;lt;code&amp;gt;floor(budget*(2+skillLevel)/9)&amp;lt;/code&amp;gt; skill points to spend so that the whole budget is unlocked at skill level 7 while keeping a reasonable amount of points at lower skills. The code for this is in &amp;lt;code&amp;gt;src/sgame/sg_bot_skilltree.cpp&amp;lt;/code&amp;gt;, in &amp;lt;code&amp;gt;BotPickSkillset&amp;lt;/code&amp;gt;'s definition of &amp;lt;code&amp;gt;skill_points&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Skilltree in pure deterministic &amp;quot;mode&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You sometime want purely deterministic bots, for example for tournaments or for easier inital balancing. This is the way I'd like Unvanquished to go towards on the long term.&lt;br /&gt;
&lt;br /&gt;
If you wish to have perfectly identical bots for some skill levels, you can set &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt; to 0 and write the &amp;lt;code&amp;gt;g_skillset_baseSkills&amp;lt;/code&amp;gt; list.&lt;br /&gt;
&lt;br /&gt;
=== Skilltree in mixed &amp;quot;mode&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
There is a third way, where one can define &amp;quot;vital&amp;quot; skills that have to be selected for given skill levels. You can do this by setting the base skills are always selected, and give more budget than those initial skills cost, so that the leftover skill points (if any) will be used randomly.&lt;br /&gt;
&lt;br /&gt;
You can do that by&lt;br /&gt;
* setting the &amp;lt;code&amp;gt;g_skillset_baseSkills&amp;lt;/code&amp;gt; cvar to the base required skills for each level, then &lt;br /&gt;
* giving some extra skill funds for your bots to randomly choose from, using the &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt; cvars.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;💡️ Tip:&amp;lt;/b&amp;gt; You can even have some skills mandatory at some skill levels and forbidden from the other skill levels. To do that, you add the skill in the &amp;lt;code&amp;gt;g_skillset_disabledSkills&amp;lt;/code&amp;gt; list AND in &amp;lt;code&amp;gt;g_skillset_baseSkills&amp;lt;/code&amp;gt; for your desired skill threshold. This will exclude a skill from the random selection but still allow the budget to select the other skills. This works because the base skill list takes precedence.&lt;br /&gt;
&lt;br /&gt;
The visualisation features explained in [[#Visualising_the_skilltree]] will be very useful in this situation, make sure you know how to use them.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Bot_skillset_modding&amp;diff=8351</id>
		<title>Bot skillset modding</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Bot_skillset_modding&amp;diff=8351"/>
		<updated>2023-05-31T12:07:16Z</updated>

		<summary type="html">&lt;p&gt;Afontain: Clarify language&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This wiki page explains the skilltree as of https://github.com/Unvanquished/Unvanquished/pull/2697.&lt;br /&gt;
&lt;br /&gt;
== Basic principle ==&lt;br /&gt;
&lt;br /&gt;
[[File:Bot-skilltree-basic.png|thumbnail|An example of skilltree structure]]&lt;br /&gt;
&lt;br /&gt;
Each skill is a boolean on/off tag, that has some chance of being unlocked. As long as there are skill points to spend, the next skill is selected randomly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Visualising the skilltree ==&lt;br /&gt;
&lt;br /&gt;
There are two commands, &amp;lt;code&amp;gt;/devbotcountskillpoints&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;/devbotgraphskilltree [skillLevel]&amp;lt;/code&amp;gt; that can help handling the skilltree.&lt;br /&gt;
&lt;br /&gt;
The first command, &amp;lt;code&amp;gt;/devbotcountskillpoints&amp;lt;/code&amp;gt;, just prints a message with the total cost of (reachable) skills in the tree for each team. This can help figuring out the maximum budget want.&lt;br /&gt;
&lt;br /&gt;
[[File:Bot-skilltree-advanced.png|thumbnail|Here's an advanced example where the buy-modern-armor skill is a base-skill (always enabled) and the prefer-armor skill is disabled (never selected randomly)]]&lt;br /&gt;
&lt;br /&gt;
The second command, &amp;lt;code&amp;gt;/devbotgraphskilltree [skillLevel]&amp;lt;/code&amp;gt; saves a &amp;lt;code&amp;gt;.dot&amp;lt;/code&amp;gt; graph file that can be converted to an image. For example one can do this in the game console:&lt;br /&gt;
 /devbotgraphskilltree 5&lt;br /&gt;
 game/bot-skilltree-alien.dot written &lt;br /&gt;
 game/bot-skilltree-human.dot written &lt;br /&gt;
&lt;br /&gt;
Then (e.g.) this in a terminal:&lt;br /&gt;
 $ dot -Tpng ~/.local/share/unvanquished/game/bot-skilltree-human.dot &amp;gt; result.png &amp;amp;&amp;amp; xdg-open result.png&lt;br /&gt;
&lt;br /&gt;
If one gives the skill level as an argument argument to the &amp;lt;code&amp;gt;/devbotgraphskilltree&amp;lt;/code&amp;gt; command, it will print the statistics for that skill level, with colors for the disabled and forced skills.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Modifying and tweaking the skilltree ==&lt;br /&gt;
&lt;br /&gt;
Depending on your objectives, which maybe to offer diverse and interesting bots e.g. for a juggernaut mod, or to provide very predictable bots e.g. for a tournament, you may have different desire for bot customisations. The current implementation of the skilltree should be flexible enough to allow this.&lt;br /&gt;
&lt;br /&gt;
The skill selection process is customised by these cvars:&lt;br /&gt;
* &amp;lt;code&amp;gt;g_skillset_baseSkills&amp;lt;/code&amp;gt; which set the initial skills for the various skill levels.&lt;br /&gt;
* &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;g_skillset_disabledSkills&amp;lt;/code&amp;gt;, which will prevent skills from being randomly selected.&lt;br /&gt;
&lt;br /&gt;
=== Skilltree in pure random &amp;quot;mode&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You sometime want to have maximum randomness in your opponents, with a purely random skill setup. For example this can make PvE games or Juggernaut fights more interesting.&lt;br /&gt;
&lt;br /&gt;
You can do that by:&lt;br /&gt;
* setting the &amp;lt;code&amp;gt;g_skillset_baseSkills&amp;lt;/code&amp;gt; cvar to an empty string &lt;br /&gt;
* giving some skill funds for your bots to randomly choose from, using the &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt; cvars.&lt;br /&gt;
&lt;br /&gt;
In the current implementation, you get &amp;lt;code&amp;gt;floor(budget*(2+skillLevel)/9)&amp;lt;/code&amp;gt; skill points to spend so that the whole budget is unlocked at skill level 7 while keeping a reasonable amount of points at lower skills. The code for this is in &amp;lt;code&amp;gt;src/sgame/sg_bot_skilltree.cpp&amp;lt;/code&amp;gt;, in &amp;lt;code&amp;gt;BotPickSkillset&amp;lt;/code&amp;gt;'s definition of &amp;lt;code&amp;gt;skill_points&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Skilltree in pure deterministic &amp;quot;mode&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You sometime want purely deterministic bots, for example for tournaments or for easier inital balancing. This is the way I'd like Unvanquished to go towards on the long term.&lt;br /&gt;
&lt;br /&gt;
If you wish to have perfectly identical bots for some skill levels, you can set &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt; to 0 and write the &amp;lt;code&amp;gt;g_skillset_baseSkills&amp;lt;/code&amp;gt; list.&lt;br /&gt;
&lt;br /&gt;
=== Skilltree in mixed &amp;quot;mode&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
There is a third way, where one can define &amp;quot;vital&amp;quot; skills that have to be selected for given skill levels. You can do this by setting the base skills are always selected, and give more budget than those initial skills cost, so that the leftover skill points (if any) will be used randomly.&lt;br /&gt;
&lt;br /&gt;
You can do that by&lt;br /&gt;
* setting the &amp;lt;code&amp;gt;g_skillset_baseSkills&amp;lt;/code&amp;gt; cvar to the base required skills for each level, then &lt;br /&gt;
* giving some extra skill funds for your bots to randomly choose from, using the &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt; cvars.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;💡️ Tip:&amp;lt;/b&amp;gt; You can even have some skills mandatory at some skill levels and forbidden from the other skill levels. To do that, you add the skill in the &amp;lt;code&amp;gt;g_skillset_disabledSkills&amp;lt;/code&amp;gt; list AND in &amp;lt;code&amp;gt;g_skillset_baseSkills&amp;lt;/code&amp;gt; for your desired skill threshold. This will exclude a skill from the random selection but still allow the budget to select the other skills. This works because the base skill list takes precedence.&lt;br /&gt;
&lt;br /&gt;
The visualisation features explained in [[#Visualising_the_skilltree]] will be very useful in this situation, make sure you know how to use them.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Bot_skillset_modding&amp;diff=8350</id>
		<title>Bot skillset modding</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Bot_skillset_modding&amp;diff=8350"/>
		<updated>2023-05-27T22:32:25Z</updated>

		<summary type="html">&lt;p&gt;Afontain: Rename and merge g_skillset_baseSkills_levelN cvars to only one: g_skillset_baseSkills&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This wiki page explains the skilltree as of https://github.com/Unvanquished/Unvanquished/pull/2697.&lt;br /&gt;
&lt;br /&gt;
== Basic principle ==&lt;br /&gt;
&lt;br /&gt;
[[File:Bot-skilltree-basic.png|thumbnail|An example of skilltree structure]]&lt;br /&gt;
&lt;br /&gt;
Each skill is a boolean on/off tag, that has some chance of being unlocked. As long as there are skill points to spend, the next skill is selected randomly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Visualising the skilltree ==&lt;br /&gt;
&lt;br /&gt;
There are two commands, &amp;lt;code&amp;gt;/devbotcountskillpoints&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;/devbotgraphskilltree [skillLevel]&amp;lt;/code&amp;gt; that can help handling the skilltree.&lt;br /&gt;
&lt;br /&gt;
The first command, &amp;lt;code&amp;gt;/devbotcountskillpoints&amp;lt;/code&amp;gt;, just prints a message with the total cost of (reachable) skills in the tree for each team. This can help figuring out the maximum budget want.&lt;br /&gt;
&lt;br /&gt;
[[File:Bot-skilltree-advanced.png|thumbnail|Here's an advanced example where the buy-modern-armor skill is a base-skill (always enabled) and the prefer-armor skill is disabled (never selected randomly)]]&lt;br /&gt;
&lt;br /&gt;
The second command, &amp;lt;code&amp;gt;/devbotgraphskilltree [skillLevel]&amp;lt;/code&amp;gt; saves a &amp;lt;code&amp;gt;.dot&amp;lt;/code&amp;gt; graph file that can be converted to an image. For example one can do this in the game console:&lt;br /&gt;
 /devbotgraphskilltree 5&lt;br /&gt;
 game/bot-skilltree-alien.dot written &lt;br /&gt;
 game/bot-skilltree-human.dot written &lt;br /&gt;
&lt;br /&gt;
Then (e.g.) this in a terminal:&lt;br /&gt;
 $ dot -Tpng ~/.local/share/unvanquished/game/bot-skilltree-human.dot &amp;gt; result.png &amp;amp;&amp;amp; xdg-open result.png&lt;br /&gt;
&lt;br /&gt;
If one gives the skill level as an argument argument to the &amp;lt;code&amp;gt;/devbotgraphskilltree&amp;lt;/code&amp;gt; command, it will print the statistics for that skill level, with colors for the disabled and forced skills.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Modifying and tweaking the skilltree ==&lt;br /&gt;
&lt;br /&gt;
Depending on your objectives, which maybe to offer diverse and interesting bots e.g. for a juggernaut mod, or to provide very predictable bots e.g. for a tournament, you may have different desire for bot customisations. The current implementation of the skilltree should be flexible enough to allow this.&lt;br /&gt;
&lt;br /&gt;
The skill selection process is customised by these cvars:&lt;br /&gt;
* &amp;lt;code&amp;gt;g_skillset_baseSkills&amp;lt;/code&amp;gt; which set the initial skills for the various skill levels.&lt;br /&gt;
* &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;g_skillset_disabledSkills&amp;lt;/code&amp;gt;, which will prevent skills from being randomly selected.&lt;br /&gt;
&lt;br /&gt;
=== Skilltree in pure random &amp;quot;mode&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You sometime want to have maximum randomness in your opponents, with a purely random skill setup. For example this can make PvE games or Juggernaut fights more interesting.&lt;br /&gt;
&lt;br /&gt;
You can do that by:&lt;br /&gt;
* setting the &amp;lt;code&amp;gt;g_skillset_baseSkills&amp;lt;/code&amp;gt; cvar to an empty string &lt;br /&gt;
* giving some skill funds for your bots to randomly choose from, using the &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt; cvars.&lt;br /&gt;
&lt;br /&gt;
In the current implementation, you get &amp;lt;code&amp;gt;floor(budget*(2+skillLevel)/9)&amp;lt;/code&amp;gt; skill points to spend so that the whole budget is unlocked at skill level 7 while keeping a reasonable amount of points at lower skills. The code for this is in &amp;lt;code&amp;gt;src/sgame/sg_bot_skilltree.cpp&amp;lt;/code&amp;gt;, in &amp;lt;code&amp;gt;BotPickSkillset&amp;lt;/code&amp;gt;'s definition of &amp;lt;code&amp;gt;skill_points&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Skilltree in pure deterministic &amp;quot;mode&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You sometime want purely deterministic bots, for example for tournaments or for easier inital balancing. This is the way I'd like Unvanquished to go towards on the long term.&lt;br /&gt;
&lt;br /&gt;
If you wish to have perfectly identical bots for some skill levels, you can set &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt; to 0 and write the &amp;lt;code&amp;gt;g_skillset_baseSkills&amp;lt;/code&amp;gt; list.&lt;br /&gt;
&lt;br /&gt;
=== Skilltree in mixed &amp;quot;mode&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
There is a third way, where one can define &amp;quot;vital&amp;quot; skills that have to be selected for given skill levels. You can do this by setting the base skills are always selected, and give more budget than those initial skills cost, so that the leftover skill points (if any) will be used randomly.&lt;br /&gt;
&lt;br /&gt;
You can do that by&lt;br /&gt;
* setting the &amp;lt;code&amp;gt;g_skillset_baseSkills&amp;lt;/code&amp;gt; cvar to the base required skills for each level, then &lt;br /&gt;
* giving some extra skill funds for your bots to randomly choose from, using the &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt; cvars.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;💡️ Tip:&amp;lt;/b&amp;gt; You can even have some skills mandatory at some skill levels and forbidden from the other skill levels. To do that, you add the skill in the &amp;lt;code&amp;gt;g_skillset_disabledSkills&amp;lt;/code&amp;gt; list AND in the base skill list for your desired skill levels. This works because putting skills in that list will prevent them from being chosen randomly, but the base skill lists take precedence.&lt;br /&gt;
&lt;br /&gt;
The visualisation features explained in [[#Visualising_the_skilltree]] will be very useful in this situation, make sure you know how to use them.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Bot_skillset_modding&amp;diff=8292</id>
		<title>Bot skillset modding</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Bot_skillset_modding&amp;diff=8292"/>
		<updated>2023-05-16T22:58:07Z</updated>

		<summary type="html">&lt;p&gt;Afontain: Rename g_skillset_baseSkills.levelN cvar to g_skillset_baseSkills_levelN&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This wiki page explains the skilltree as of https://github.com/Unvanquished/Unvanquished/pull/2697.&lt;br /&gt;
&lt;br /&gt;
== Basic principle ==&lt;br /&gt;
&lt;br /&gt;
[[File:Bot-skilltree-basic.png|thumbnail|An example of skilltree structure]]&lt;br /&gt;
&lt;br /&gt;
Each skill is a boolean on/off tag, that has some chance of being unlocked. As long as there are skill points to spend, the next skill is selected randomly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Visualising the skilltree ==&lt;br /&gt;
&lt;br /&gt;
There are two commands, &amp;lt;code&amp;gt;/devbotcountskillpoints&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;/devbotgraphskilltree [skillLevel]&amp;lt;/code&amp;gt; that can help handling the skilltree.&lt;br /&gt;
&lt;br /&gt;
The first command, &amp;lt;code&amp;gt;/devbotcountskillpoints&amp;lt;/code&amp;gt;, just prints a message with the total cost of (reachable) skills in the tree for each team. This can help figuring out the maximum budget want.&lt;br /&gt;
&lt;br /&gt;
[[File:Bot-skilltree-advanced.png|thumbnail|Here's an advanced example where the buy-modern-armor skill is a base-skill (always enabled) and the prefer-armor skill is disabled (never selected randomly)]]&lt;br /&gt;
&lt;br /&gt;
The second command, &amp;lt;code&amp;gt;/devbotgraphskilltree [skillLevel]&amp;lt;/code&amp;gt; saves a &amp;lt;code&amp;gt;.dot&amp;lt;/code&amp;gt; graph file that can be converted to an image. For example one can do this in the game console:&lt;br /&gt;
 /devbotgraphskilltree 5&lt;br /&gt;
 game/bot-skilltree-alien.dot written &lt;br /&gt;
 game/bot-skilltree-human.dot written &lt;br /&gt;
&lt;br /&gt;
Then (e.g.) this in a terminal:&lt;br /&gt;
 $ dot -Tpng ~/.local/share/unvanquished/game/bot-skilltree-human.dot &amp;gt; result.png &amp;amp;&amp;amp; xdg-open result.png&lt;br /&gt;
&lt;br /&gt;
If one gives the skill level as an argument argument to the &amp;lt;code&amp;gt;/devbotgraphskilltree&amp;lt;/code&amp;gt; command, it will print the statistics for that skill level, with colors for the disabled and forced skills.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Modifying and tweaking the skilltree ==&lt;br /&gt;
&lt;br /&gt;
Depending on your objectives, which maybe to offer diverse and interesting bots e.g. for a juggernaut mod, or to provide very predictable bots e.g. for a tournament, you may have different desire for bot customisations. The current implementation of the skilltree should be flexible enough to allow this.&lt;br /&gt;
&lt;br /&gt;
The skill selection process is customised by these cvars:&lt;br /&gt;
* &amp;lt;code&amp;gt;g_skillset_baseSkills_levelN&amp;lt;/code&amp;gt; which set the initial skills for the N-th skill level.&lt;br /&gt;
* &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;g_skillset_disabledSkills&amp;lt;/code&amp;gt;, which will prevent skills from being randomly selected.&lt;br /&gt;
&lt;br /&gt;
=== Skilltree in pure random &amp;quot;mode&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You sometime want to have maximum randomness in your opponents, with a purely random skill setup. For example this can make PvE games or Juggernaut fights more interesting.&lt;br /&gt;
&lt;br /&gt;
You can do that by:&lt;br /&gt;
* setting the &amp;lt;code&amp;gt;g_skillset_baseSkills_levelN&amp;lt;/code&amp;gt; cvars to an empty string &lt;br /&gt;
* giving some skill funds for your bots to randomly choose from, using the &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt; cvars.&lt;br /&gt;
&lt;br /&gt;
In the current implementation, you get &amp;lt;code&amp;gt;floor(budget*(2+skillLevel)/9)&amp;lt;/code&amp;gt; skill points to spend so that the whole budget is unlocked at skill level 7 while keeping a reasonable amount of points at lower skills. The code for this is in &amp;lt;code&amp;gt;src/sgame/sg_bot_skilltree.cpp&amp;lt;/code&amp;gt;, in &amp;lt;code&amp;gt;BotPickSkillset&amp;lt;/code&amp;gt;'s definition of &amp;lt;code&amp;gt;skill_points&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Skilltree in pure deterministic &amp;quot;mode&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You sometime want purely deterministic bots, for example for tournaments or for easier inital balancing. This is the way I'd like Unvanquished to go towards on the long term.&lt;br /&gt;
&lt;br /&gt;
If you wish to have perfectly identical bots for some skill levels, you can set &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt; to 0 and write the various &amp;lt;code&amp;gt;g_skillset_baseSkills_levelN&amp;lt;/code&amp;gt; lists.&lt;br /&gt;
&lt;br /&gt;
=== Skilltree in mixed &amp;quot;mode&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
There is a third way, where one can define &amp;quot;vital&amp;quot; skills that have to be selected for given skill levels. You can do this by setting the base skills are always selected, and give more budget than those initial skills cost, so that the leftover skill points (if any) will be used randomly.&lt;br /&gt;
&lt;br /&gt;
You can do that by&lt;br /&gt;
* setting the &amp;lt;code&amp;gt;g_skillset_baseSkills_levelN&amp;lt;/code&amp;gt; cvars to the base required skills for each level, then &lt;br /&gt;
* giving some extra skill funds for your bots to randomly choose from, using the &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt; cvars.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;💡️ Tip:&amp;lt;/b&amp;gt; You can even have some skills mandatory at some skill levels and forbidden from the other skill levels. To do that, you add the skill in the &amp;lt;code&amp;gt;g_skillset_disabledSkills&amp;lt;/code&amp;gt; list AND in the base skill list for your desired skill levels. This works because putting skills in that list will prevent them from being chosen randomly, but the base skill lists take precedence.&lt;br /&gt;
&lt;br /&gt;
The visualisation features explained in [[#Visualising_the_skilltree]] will be very useful in this situation, make sure you know how to use them.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Bot_design&amp;diff=8291</id>
		<title>Bot design</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Bot_design&amp;diff=8291"/>
		<updated>2023-05-16T22:17:59Z</updated>

		<summary type="html">&lt;p&gt;Afontain: /* Computer vision */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Generalities =&lt;br /&gt;
&lt;br /&gt;
The main situations we want bots to work in are:&lt;br /&gt;
&lt;br /&gt;
* In a game where a single user plays in a team against a team of bots (let's call this ''1v0'')&lt;br /&gt;
* In a game where a few users play against each others, with a considerable amount of bots on both teams (let's call this ''1v1, 2v2'', etc.)&lt;br /&gt;
* In a game where a considerable number of players team up to play against a horde of bots (let's call this ''PvE'')&lt;br /&gt;
* In a game where a single user (or few users) play against a considerably bigger number of other users (let's call this ''1v3'', etc.)&lt;br /&gt;
&lt;br /&gt;
In games where bots are a minority in both teams, bots are not that important. When playing PvE, the variations of bot skill are also not very important, as players can't feel like they got an unfairly weak ally.&lt;br /&gt;
&lt;br /&gt;
Bots are built from roughly 3 different &amp;quot;modules&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
* navigation, which is done with a combination of A* or Dijkstra and navmeshes;&lt;br /&gt;
* decision, which is done with the paradigm of behavior trees;&lt;br /&gt;
* computer vision, to complete what navmeshes can not provide;&lt;br /&gt;
&lt;br /&gt;
== Navigation ==&lt;br /&gt;
&lt;br /&gt;
All bots should be able to reach any part of the map that does not require special training.&lt;br /&gt;
&lt;br /&gt;
== Decision ==&lt;br /&gt;
&lt;br /&gt;
=== Bot levels ===&lt;br /&gt;
&lt;br /&gt;
For historical reasons, bots have a range of skills numbered from 1 to 9, all integers.&lt;br /&gt;
&lt;br /&gt;
Skill 1 is considered to be training dummies, while skill 9 is considered as the *user* is the training dummy.&lt;br /&gt;
&lt;br /&gt;
Skill 5 should never be so strong that an average player can not kill it in duel, nor so weak than an average player considers the bot negligible.&lt;br /&gt;
&lt;br /&gt;
==== Bot personalities ====&lt;br /&gt;
&lt;br /&gt;
In 2022 and early 2023, we did some experiments about giving each bot a personality. The idea was to have a number of skills that are valuable in playing. Each bot would receive its unique set of skills, by some random selection. That would make them different from each other.&lt;br /&gt;
&lt;br /&gt;
Some examples of &amp;quot;bot skills&amp;quot; we used are: various alien trick moves, the ability to aim better than other bots, smartly buying human equipment/weapons and using the human medkit.&lt;br /&gt;
&lt;br /&gt;
The pros of this approach:&lt;br /&gt;
&lt;br /&gt;
* Bots do not behave all the same. That makes them more difficult to predict.&lt;br /&gt;
* Bots simulate real users more accurately.&lt;br /&gt;
&lt;br /&gt;
The cons:&lt;br /&gt;
&lt;br /&gt;
* It is harder to balance bots against each other. We would have to test a significant subset of all possible combinations. This matters a lot in 1v1 or 2v2. It matters even more in 1v3.&lt;br /&gt;
* Users will discover what skills are more valuable. They can tweak the skills the bots on their team have, by voting to remove them and add them again until they hit a sweet spot.&lt;br /&gt;
&lt;br /&gt;
Those two cons should be mitigated by having sufficiently many skills and skills that have well adapted costs: that is by having costs reflect the skill's usefulness.&lt;br /&gt;
&lt;br /&gt;
== Computer vision ==&lt;br /&gt;
&lt;br /&gt;
Bots should be able to detect any enemy in their FoV. It would be nice to have bots not being too good at finding hiden buildables on the roof. This makes hiding eggs unfun and next to impossible in the current state. Unless they are placed outside of a navmesh, in which case bots are totally unable to discover them.&lt;br /&gt;
&lt;br /&gt;
To improve this and make bots feel more like human players, we should make bots:&lt;br /&gt;
* not automatically know the egg locations when rushing: https://github.com/Unvanquished/Unvanquished/pull/2683&lt;br /&gt;
* attack enemies that are visible but outside the navmesh&lt;br /&gt;
* for human bots, not be as great at spotting things vertically as they are with thing horizontally (like regular humans)&lt;br /&gt;
* maybe not discovering things always with the same reliability — but this would bring randomness.&lt;br /&gt;
&lt;br /&gt;
== Non-cheating ==&lt;br /&gt;
&lt;br /&gt;
Bots should not perform any action that could not be performed by a non-bot client. This is believed to be true in the current state. This property does take some care to maintain, as bot functions often act directly on sgame state rather than using client commands.&lt;br /&gt;
&lt;br /&gt;
It would be nice if additionally, bots only used ''information'' that could have been learned by a normal player. This is far from true in the current state: for example, bots have omniscience of all buildables in the level.&lt;br /&gt;
&lt;br /&gt;
When playing against bots, it should not ''feel'' like a bot is cheating, i.e. doing something that a human player could not have done. The bot should not have impossibly fast reaction times or seem like it's using an aimbot, triggerbot, etc.&lt;br /&gt;
&lt;br /&gt;
== Current Questions ==&lt;br /&gt;
&lt;br /&gt;
* Should we keep bot personalities, or make all bots the same?&lt;br /&gt;
* How much randomness should be involved in a bot's behavior?&lt;br /&gt;
* How many details of bot configuration should be hard-coded, and how many should be exposed by cvars?&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Bot_design&amp;diff=8290</id>
		<title>Bot design</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Bot_design&amp;diff=8290"/>
		<updated>2023-05-16T22:07:19Z</updated>

		<summary type="html">&lt;p&gt;Afontain: /* Bot levels */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Generalities =&lt;br /&gt;
&lt;br /&gt;
The main situations we want bots to work in are:&lt;br /&gt;
&lt;br /&gt;
* In a game where a single user plays in a team against a team of bots (let's call this ''1v0'')&lt;br /&gt;
* In a game where a few users play against each others, with a considerable amount of bots on both teams (let's call this ''1v1, 2v2'', etc.)&lt;br /&gt;
* In a game where a considerable number of players team up to play against a horde of bots (let's call this ''PvE'')&lt;br /&gt;
* In a game where a single user (or few users) play against a considerably bigger number of other users (let's call this ''1v3'', etc.)&lt;br /&gt;
&lt;br /&gt;
In games where bots are a minority in both teams, bots are not that important. When playing PvE, the variations of bot skill are also not very important, as players can't feel like they got an unfairly weak ally.&lt;br /&gt;
&lt;br /&gt;
Bots are built from roughly 3 different &amp;quot;modules&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
* navigation, which is done with a combination of A* or Dijkstra and navmeshes;&lt;br /&gt;
* decision, which is done with the paradigm of behavior trees;&lt;br /&gt;
* computer vision, to complete what navmeshes can not provide;&lt;br /&gt;
&lt;br /&gt;
== Navigation ==&lt;br /&gt;
&lt;br /&gt;
All bots should be able to reach any part of the map that does not require special training.&lt;br /&gt;
&lt;br /&gt;
== Decision ==&lt;br /&gt;
&lt;br /&gt;
=== Bot levels ===&lt;br /&gt;
&lt;br /&gt;
For historical reasons, bots have a range of skills numbered from 1 to 9, all integers.&lt;br /&gt;
&lt;br /&gt;
Skill 1 is considered to be training dummies, while skill 9 is considered as the *user* is the training dummy.&lt;br /&gt;
&lt;br /&gt;
Skill 5 should never be so strong that an average player can not kill it in duel, nor so weak than an average player considers the bot negligible.&lt;br /&gt;
&lt;br /&gt;
==== Bot personalities ====&lt;br /&gt;
&lt;br /&gt;
In 2022 and early 2023, we did some experiments about giving each bot a personality. The idea was to have a number of skills that are valuable in playing. Each bot would receive its unique set of skills, by some random selection. That would make them different from each other.&lt;br /&gt;
&lt;br /&gt;
Some examples of &amp;quot;bot skills&amp;quot; we used are: various alien trick moves, the ability to aim better than other bots, smartly buying human equipment/weapons and using the human medkit.&lt;br /&gt;
&lt;br /&gt;
The pros of this approach:&lt;br /&gt;
&lt;br /&gt;
* Bots do not behave all the same. That makes them more difficult to predict.&lt;br /&gt;
* Bots simulate real users more accurately.&lt;br /&gt;
&lt;br /&gt;
The cons:&lt;br /&gt;
&lt;br /&gt;
* It is harder to balance bots against each other. We would have to test a significant subset of all possible combinations. This matters a lot in 1v1 or 2v2. It matters even more in 1v3.&lt;br /&gt;
* Users will discover what skills are more valuable. They can tweak the skills the bots on their team have, by voting to remove them and add them again until they hit a sweet spot.&lt;br /&gt;
&lt;br /&gt;
Those two cons should be mitigated by having sufficiently many skills and skills that have well adapted costs: that is by having costs reflect the skill's usefulness.&lt;br /&gt;
&lt;br /&gt;
== Computer vision ==&lt;br /&gt;
&lt;br /&gt;
Bots should be able to detect any enemy in their FoV.&lt;br /&gt;
&lt;br /&gt;
== Non-cheating ==&lt;br /&gt;
&lt;br /&gt;
Bots should not perform any action that could not be performed by a non-bot client. This is believed to be true in the current state. This property does take some care to maintain, as bot functions often act directly on sgame state rather than using client commands.&lt;br /&gt;
&lt;br /&gt;
It would be nice if additionally, bots only used ''information'' that could have been learned by a normal player. This is far from true in the current state: for example, bots have omniscience of all buildables in the level.&lt;br /&gt;
&lt;br /&gt;
When playing against bots, it should not ''feel'' like a bot is cheating, i.e. doing something that a human player could not have done. The bot should not have impossibly fast reaction times or seem like it's using an aimbot, triggerbot, etc.&lt;br /&gt;
&lt;br /&gt;
== Current Questions ==&lt;br /&gt;
&lt;br /&gt;
* Should we keep bot personalities, or make all bots the same?&lt;br /&gt;
* How much randomness should be involved in a bot's behavior?&lt;br /&gt;
* How many details of bot configuration should be hard-coded, and how many should be exposed by cvars?&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Bot_skillset_modding&amp;diff=8289</id>
		<title>Bot skillset modding</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Bot_skillset_modding&amp;diff=8289"/>
		<updated>2023-05-16T21:46:38Z</updated>

		<summary type="html">&lt;p&gt;Afontain: add code tags around cvar names&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This wiki page explains the skilltree as of https://github.com/Unvanquished/Unvanquished/pull/2697.&lt;br /&gt;
&lt;br /&gt;
== Basic principle ==&lt;br /&gt;
&lt;br /&gt;
[[File:Bot-skilltree-basic.png|thumbnail|An example of skilltree structure]]&lt;br /&gt;
&lt;br /&gt;
Each skill is a boolean on/off tag, that has some chance of being unlocked. As long as there are skill points to spend, the next skill is selected randomly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Visualising the skilltree ==&lt;br /&gt;
&lt;br /&gt;
There are two commands, &amp;lt;code&amp;gt;/devbotcountskillpoints&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;/devbotgraphskilltree [skillLevel]&amp;lt;/code&amp;gt; that can help handling the skilltree.&lt;br /&gt;
&lt;br /&gt;
The first command, &amp;lt;code&amp;gt;/devbotcountskillpoints&amp;lt;/code&amp;gt;, just prints a message with the total cost of (reachable) skills in the tree for each team. This can help figuring out the maximum budget want.&lt;br /&gt;
&lt;br /&gt;
[[File:Bot-skilltree-advanced.png|thumbnail|Here's an advanced example where the buy-modern-armor skill is a base-skill (always enabled) and the prefer-armor skill is disabled (never selected randomly)]]&lt;br /&gt;
&lt;br /&gt;
The second command, &amp;lt;code&amp;gt;/devbotgraphskilltree [skillLevel]&amp;lt;/code&amp;gt; saves a &amp;lt;code&amp;gt;.dot&amp;lt;/code&amp;gt; graph file that can be converted to an image. For example one can do this in the game console:&lt;br /&gt;
 /devbotgraphskilltree 5&lt;br /&gt;
 game/bot-skilltree-alien.dot written &lt;br /&gt;
 game/bot-skilltree-human.dot written &lt;br /&gt;
&lt;br /&gt;
Then (e.g.) this in a terminal:&lt;br /&gt;
 $ dot -Tpng ~/.local/share/unvanquished/game/bot-skilltree-human.dot &amp;gt; result.png &amp;amp;&amp;amp; xdg-open result.png&lt;br /&gt;
&lt;br /&gt;
If one gives the skill level as an argument argument to the &amp;lt;code&amp;gt;/devbotgraphskilltree&amp;lt;/code&amp;gt; command, it will print the statistics for that skill level, with colors for the disabled and forced skills.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Modifying and tweaking the skilltree ==&lt;br /&gt;
&lt;br /&gt;
Depending on your objectives, which maybe to offer diverse and interesting bots e.g. for a juggernaut mod, or to provide very predictable bots e.g. for a tournament, you may have different desire for bot customisations. The current implementation of the skilltree should be flexible enough to allow this.&lt;br /&gt;
&lt;br /&gt;
The skill selection process is customised by these cvars:&lt;br /&gt;
* &amp;lt;code&amp;gt;g_skillset_baseSkills.levelN&amp;lt;/code&amp;gt; which set the initial skills for the N-th skill level.&lt;br /&gt;
* &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;g_skillset_disabledSkills&amp;lt;/code&amp;gt;, which will prevent skills from being randomly selected.&lt;br /&gt;
&lt;br /&gt;
=== Skilltree in pure random &amp;quot;mode&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You sometime want to have maximum randomness in your opponents, with a purely random skill setup. For example this can make PvE games or Juggernaut fights more interesting.&lt;br /&gt;
&lt;br /&gt;
You can do that by:&lt;br /&gt;
* setting the &amp;lt;code&amp;gt;g_skillset_baseSkills.levelN&amp;lt;/code&amp;gt; cvars to an empty string &lt;br /&gt;
* giving some skill funds for your bots to randomly choose from, using the &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt; cvars.&lt;br /&gt;
&lt;br /&gt;
In the current implementation, you get &amp;lt;code&amp;gt;floor(budget*(2+skillLevel)/9)&amp;lt;/code&amp;gt; skill points to spend so that the whole budget is unlocked at skill level 7 while keeping a reasonable amount of points at lower skills. The code for this is in &amp;lt;code&amp;gt;src/sgame/sg_bot_skilltree.cpp&amp;lt;/code&amp;gt;, in &amp;lt;code&amp;gt;BotPickSkillset&amp;lt;/code&amp;gt;'s definition of &amp;lt;code&amp;gt;skill_points&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Skilltree in pure deterministic &amp;quot;mode&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You sometime want purely deterministic bots, for example for tournaments or for easier inital balancing. This is the way I'd like Unvanquished to go towards on the long term.&lt;br /&gt;
&lt;br /&gt;
If you wish to have perfectly identical bots for some skill levels, you can set &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt; to 0 and write the various &amp;lt;code&amp;gt;g_skillset_baseSkills.levelN&amp;lt;/code&amp;gt; lists.&lt;br /&gt;
&lt;br /&gt;
=== Skilltree in mixed &amp;quot;mode&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
There is a third way, where one can define &amp;quot;vital&amp;quot; skills that have to be selected for given skill levels. You can do this by setting the base skills are always selected, and give more budget than those initial skills cost, so that the leftover skill points (if any) will be used randomly.&lt;br /&gt;
&lt;br /&gt;
You can do that by&lt;br /&gt;
* setting the &amp;lt;code&amp;gt;g_skillset_baseSkills.levelN&amp;lt;/code&amp;gt; cvars to the base required skills for each level, then &lt;br /&gt;
* giving some extra skill funds for your bots to randomly choose from, using the &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt; cvars.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;💡️ Tip:&amp;lt;/b&amp;gt; You can even have some skills mandatory at some skill levels and forbidden from the other skill levels. To do that, you add the skill in the &amp;lt;code&amp;gt;g_skillset_disabledSkills&amp;lt;/code&amp;gt; list AND in the base skill list for your desired skill levels. This works because putting skills in that list will prevent them from being chosen randomly, but the base skill lists take precedence.&lt;br /&gt;
&lt;br /&gt;
The visualisation features explained in [[#Visualising_the_skilltree]] will be very useful in this situation, make sure you know how to use them.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Bot_skillset_modding&amp;diff=8288</id>
		<title>Bot skillset modding</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Bot_skillset_modding&amp;diff=8288"/>
		<updated>2023-05-16T21:45:13Z</updated>

		<summary type="html">&lt;p&gt;Afontain: /* Skilltree in pure random &amp;quot;mode&amp;quot; */  add code tag&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This wiki page explains the skilltree as of https://github.com/Unvanquished/Unvanquished/pull/2697.&lt;br /&gt;
&lt;br /&gt;
== Basic principle ==&lt;br /&gt;
&lt;br /&gt;
[[File:Bot-skilltree-basic.png|thumbnail|An example of skilltree structure]]&lt;br /&gt;
&lt;br /&gt;
Each skill is a boolean on/off tag, that has some chance of being unlocked. As long as there are skill points to spend, the next skill is selected randomly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Visualising the skilltree ==&lt;br /&gt;
&lt;br /&gt;
There are two commands, &amp;lt;code&amp;gt;/devbotcountskillpoints&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;/devbotgraphskilltree [skillLevel]&amp;lt;/code&amp;gt; that can help handling the skilltree.&lt;br /&gt;
&lt;br /&gt;
The first command, &amp;lt;code&amp;gt;/devbotcountskillpoints&amp;lt;/code&amp;gt;, just prints a message with the total cost of (reachable) skills in the tree for each team. This can help figuring out the maximum budget want.&lt;br /&gt;
&lt;br /&gt;
[[File:Bot-skilltree-advanced.png|thumbnail|Here's an advanced example where the buy-modern-armor skill is a base-skill (always enabled) and the prefer-armor skill is disabled (never selected randomly)]]&lt;br /&gt;
&lt;br /&gt;
The second command, &amp;lt;code&amp;gt;/devbotgraphskilltree [skillLevel]&amp;lt;/code&amp;gt; saves a &amp;lt;code&amp;gt;.dot&amp;lt;/code&amp;gt; graph file that can be converted to an image. For example one can do this in the game console:&lt;br /&gt;
 /devbotgraphskilltree 5&lt;br /&gt;
 game/bot-skilltree-alien.dot written &lt;br /&gt;
 game/bot-skilltree-human.dot written &lt;br /&gt;
&lt;br /&gt;
Then (e.g.) this in a terminal:&lt;br /&gt;
 $ dot -Tpng ~/.local/share/unvanquished/game/bot-skilltree-human.dot &amp;gt; result.png &amp;amp;&amp;amp; xdg-open result.png&lt;br /&gt;
&lt;br /&gt;
If one gives the skill level as an argument argument to the &amp;lt;code&amp;gt;/devbotgraphskilltree&amp;lt;/code&amp;gt; command, it will print the statistics for that skill level, with colors for the disabled and forced skills.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Modifying and tweaking the skilltree ==&lt;br /&gt;
&lt;br /&gt;
Depending on your objectives, which maybe to offer diverse and interesting bots e.g. for a juggernaut mod, or to provide very predictable bots e.g. for a tournament, you may have different desire for bot customisations. The current implementation of the skilltree should be flexible enough to allow this.&lt;br /&gt;
&lt;br /&gt;
The skill selection process is customised by these cvars:&lt;br /&gt;
* &amp;lt;code&amp;gt;g_skillset_baseSkills.levelN&amp;lt;/code&amp;gt; which set the initial skills for the N-th skill level.&lt;br /&gt;
* &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;g_skillset_disabledSkills&amp;lt;/code&amp;gt;, which will prevent skills from being randomly selected.&lt;br /&gt;
&lt;br /&gt;
=== Skilltree in pure random &amp;quot;mode&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You sometime want to have maximum randomness in your opponents, with a purely random skill setup. For example this can make PvE games or Juggernaut fights more interesting.&lt;br /&gt;
&lt;br /&gt;
You can do that by:&lt;br /&gt;
* setting the &amp;lt;code&amp;gt;g_skillset_baseSkills.levelN&amp;lt;/code&amp;gt; cvars to an empty string &lt;br /&gt;
* giving some skill funds for your bots to randomly choose from, using the &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt; cvars.&lt;br /&gt;
&lt;br /&gt;
In the current implementation, you get &amp;lt;code&amp;gt;floor(budget*(2+skillLevel)/9)&amp;lt;/code&amp;gt; skill points to spend so that the whole budget is unlocked at skill level 7 while keeping a reasonable amount of points at lower skills. The code for this is in &amp;lt;code&amp;gt;src/sgame/sg_bot_skilltree.cpp&amp;lt;/code&amp;gt;, in &amp;lt;code&amp;gt;BotPickSkillset&amp;lt;/code&amp;gt;'s definition of &amp;lt;code&amp;gt;skill_points&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Skilltree in pure deterministic &amp;quot;mode&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You sometime want purely deterministic bots, for example for tournaments or for easier inital balancing. This is the way I'd like Unvanquished to go towards on the long term.&lt;br /&gt;
&lt;br /&gt;
If you wish to have perfectly identical bots for some skill levels, you can set g_skillset_budgetHumans and g_skillset_budgetAliens to 0 and write the various g_skillset_baseSkills.levelN lists.&lt;br /&gt;
&lt;br /&gt;
=== Skilltree in mixed &amp;quot;mode&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
There is a third way, where one can define &amp;quot;vital&amp;quot; skills that have to be selected for given skill levels. You can do this by setting the base skills are always selected, and give more budget than those initial skills cost, so that the leftover skill points (if any) will be used randomly.&lt;br /&gt;
&lt;br /&gt;
You can do that by&lt;br /&gt;
* setting the g_skillset_baseSkills.levelN cvars to the base required skills for each level, then &lt;br /&gt;
* giving some extra skill funds for your bots to randomly choose from, using the &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt; cvars.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;💡️ Tip:&amp;lt;/b&amp;gt; You can even have some skills mandatory at some skill levels and forbidden from the other skill levels. To do that, you add the skill in the &amp;lt;code&amp;gt;g_skillset_disabledSkills&amp;lt;/code&amp;gt; list AND in the base skill list for your desired skill levels. This works because putting skills in that list will prevent them from being chosen randomly, but the base skill lists take precedence.&lt;br /&gt;
&lt;br /&gt;
The visualisation features explained in [[#Visualising_the_skilltree]] will be very useful in this situation, make sure you know how to use them.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Bot_skillset_modding&amp;diff=8287</id>
		<title>Bot skillset modding</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Bot_skillset_modding&amp;diff=8287"/>
		<updated>2023-05-16T19:44:56Z</updated>

		<summary type="html">&lt;p&gt;Afontain: Finish documenting it as of the state in https://github.com/Unvanquished/Unvanquished/pull/2697, 16 of May&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This wiki page explains the skilltree as of https://github.com/Unvanquished/Unvanquished/pull/2697.&lt;br /&gt;
&lt;br /&gt;
== Basic principle ==&lt;br /&gt;
&lt;br /&gt;
[[File:Bot-skilltree-basic.png|thumbnail|An example of skilltree structure]]&lt;br /&gt;
&lt;br /&gt;
Each skill is a boolean on/off tag, that has some chance of being unlocked. As long as there are skill points to spend, the next skill is selected randomly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Visualising the skilltree ==&lt;br /&gt;
&lt;br /&gt;
There are two commands, &amp;lt;code&amp;gt;/devbotcountskillpoints&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;/devbotgraphskilltree [skillLevel]&amp;lt;/code&amp;gt; that can help handling the skilltree.&lt;br /&gt;
&lt;br /&gt;
The first command, &amp;lt;code&amp;gt;/devbotcountskillpoints&amp;lt;/code&amp;gt;, just prints a message with the total cost of (reachable) skills in the tree for each team. This can help figuring out the maximum budget want.&lt;br /&gt;
&lt;br /&gt;
[[File:Bot-skilltree-advanced.png|thumbnail|Here's an advanced example where the buy-modern-armor skill is a base-skill (always enabled) and the prefer-armor skill is disabled (never selected randomly)]]&lt;br /&gt;
&lt;br /&gt;
The second command, &amp;lt;code&amp;gt;/devbotgraphskilltree [skillLevel]&amp;lt;/code&amp;gt; saves a &amp;lt;code&amp;gt;.dot&amp;lt;/code&amp;gt; graph file that can be converted to an image. For example one can do this in the game console:&lt;br /&gt;
 /devbotgraphskilltree 5&lt;br /&gt;
 game/bot-skilltree-alien.dot written &lt;br /&gt;
 game/bot-skilltree-human.dot written &lt;br /&gt;
&lt;br /&gt;
Then (e.g.) this in a terminal:&lt;br /&gt;
 $ dot -Tpng ~/.local/share/unvanquished/game/bot-skilltree-human.dot &amp;gt; result.png &amp;amp;&amp;amp; xdg-open result.png&lt;br /&gt;
&lt;br /&gt;
If one gives the skill level as an argument argument to the &amp;lt;code&amp;gt;/devbotgraphskilltree&amp;lt;/code&amp;gt; command, it will print the statistics for that skill level, with colors for the disabled and forced skills.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Modifying and tweaking the skilltree ==&lt;br /&gt;
&lt;br /&gt;
Depending on your objectives, which maybe to offer diverse and interesting bots e.g. for a juggernaut mod, or to provide very predictable bots e.g. for a tournament, you may have different desire for bot customisations. The current implementation of the skilltree should be flexible enough to allow this.&lt;br /&gt;
&lt;br /&gt;
The skill selection process is customised by these cvars:&lt;br /&gt;
* &amp;lt;code&amp;gt;g_skillset_baseSkills.levelN&amp;lt;/code&amp;gt; which set the initial skills for the N-th skill level.&lt;br /&gt;
* &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;g_skillset_disabledSkills&amp;lt;/code&amp;gt;, which will prevent skills from being randomly selected.&lt;br /&gt;
&lt;br /&gt;
=== Skilltree in pure random &amp;quot;mode&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You sometime want to have maximum randomness in your opponents, with a purely random skill setup. For example this can make PvE games or Juggernaut fights more interesting.&lt;br /&gt;
&lt;br /&gt;
You can do that by:&lt;br /&gt;
* setting the g_skillset_baseSkills.levelN cvars to an empty string &lt;br /&gt;
* giving some skill funds for your bots to randomly choose from, using the &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt; cvars.&lt;br /&gt;
&lt;br /&gt;
In the current implementation, you get &amp;lt;code&amp;gt;floor(budget*(2+skillLevel)/9)&amp;lt;/code&amp;gt; skill points to spend so that the whole budget is unlocked at skill level 7 while keeping a reasonable amount of points at lower skills. The code for this is in &amp;lt;code&amp;gt;src/sgame/sg_bot_skilltree.cpp&amp;lt;/code&amp;gt;, in &amp;lt;code&amp;gt;BotPickSkillset&amp;lt;/code&amp;gt;'s definition of &amp;lt;code&amp;gt;skill_points&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Skilltree in pure deterministic &amp;quot;mode&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You sometime want purely deterministic bots, for example for tournaments or for easier inital balancing. This is the way I'd like Unvanquished to go towards on the long term.&lt;br /&gt;
&lt;br /&gt;
If you wish to have perfectly identical bots for some skill levels, you can set g_skillset_budgetHumans and g_skillset_budgetAliens to 0 and write the various g_skillset_baseSkills.levelN lists.&lt;br /&gt;
&lt;br /&gt;
=== Skilltree in mixed &amp;quot;mode&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
There is a third way, where one can define &amp;quot;vital&amp;quot; skills that have to be selected for given skill levels. You can do this by setting the base skills are always selected, and give more budget than those initial skills cost, so that the leftover skill points (if any) will be used randomly.&lt;br /&gt;
&lt;br /&gt;
You can do that by&lt;br /&gt;
* setting the g_skillset_baseSkills.levelN cvars to the base required skills for each level, then &lt;br /&gt;
* giving some extra skill funds for your bots to randomly choose from, using the &amp;lt;code&amp;gt;g_skillset_budgetHumans&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g_skillset_budgetAliens&amp;lt;/code&amp;gt; cvars.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;💡️ Tip:&amp;lt;/b&amp;gt; You can even have some skills mandatory at some skill levels and forbidden from the other skill levels. To do that, you add the skill in the &amp;lt;code&amp;gt;g_skillset_disabledSkills&amp;lt;/code&amp;gt; list AND in the base skill list for your desired skill levels. This works because putting skills in that list will prevent them from being chosen randomly, but the base skill lists take precedence.&lt;br /&gt;
&lt;br /&gt;
The visualisation features explained in [[#Visualising_the_skilltree]] will be very useful in this situation, make sure you know how to use them.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Bot_skillset_modding&amp;diff=8286</id>
		<title>Bot skillset modding</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Bot_skillset_modding&amp;diff=8286"/>
		<updated>2023-05-16T14:49:55Z</updated>

		<summary type="html">&lt;p&gt;Afontain: Created page with &amp;quot;This wiki page explains the skilltree as of https://github.com/Unvanquished/Unvanquished/pull/2697.  == Basic principle ==  File:Bot-skilltree-basic.png  == Visualising th...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This wiki page explains the skilltree as of https://github.com/Unvanquished/Unvanquished/pull/2697.&lt;br /&gt;
&lt;br /&gt;
== Basic principle ==&lt;br /&gt;
&lt;br /&gt;
[[File:Bot-skilltree-basic.png]]&lt;br /&gt;
&lt;br /&gt;
== Visualising the skilltree ==&lt;br /&gt;
&lt;br /&gt;
There are two commands, &amp;lt;code&amp;gt;/devbotcountskillpoints&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;/devbotgraphskilltree [skillLevel]&amp;lt;/code&amp;gt; that can help handling the skilltree.&lt;br /&gt;
&lt;br /&gt;
The first command, &amp;lt;code&amp;gt;/devbotcountskillpoints&amp;lt;/code&amp;gt;, just prints a message with the total cost of (reachable) skills in the tree for each team. This can help figuring out the maximum budget you may want.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The second command saves a &amp;lt;code&amp;gt;.dot&amp;lt;/code&amp;gt; graph file that can be converted to an image. For example one can do:&lt;br /&gt;
 dot -Tpng ~/.local/share/unvanquished/game/bot-skilltree-human.dot &amp;gt; result.png &amp;amp;&amp;amp; eog result.png.&lt;br /&gt;
&lt;br /&gt;
[[File:Bot-skilltree-advanced.png]]&lt;br /&gt;
&lt;br /&gt;
If one gives the skill level as an argument argument to the &amp;lt;code&amp;gt;/devbotgraphskilltree&amp;lt;/code&amp;gt; command, it will print the statistics for that skill level, with colors for the disabled and forced skills.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
== Modifying and tweaking the skilltree ==&lt;br /&gt;
&lt;br /&gt;
=== The existing cvars ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This PR adds a baseline of skill for each skill level, allowing for several modes of operation:&lt;br /&gt;
&lt;br /&gt;
    Pure random, which is the current&lt;br /&gt;
    Pure deterministic, for which you can set g_skillset_budgetHumans and g_skillset_budgetAliens to 0 and write the various g_skillset_baseSkills.levelN lists&lt;br /&gt;
    A mixed mode, where the base skills are selected first, and the leftover skill points (if any)&lt;br /&gt;
&lt;br /&gt;
You can even have some skills mandatory at some skill levels and forbidden from the random part by putting them in the g_skillset_disabledSkills list.&lt;br /&gt;
&lt;br /&gt;
This also renames the skilltree cvars so that that they are all under the g_skilltree_ namespace, to make them easier to find.&lt;br /&gt;
&lt;br /&gt;
This PR doesn't do any balancing or behavior change, but it should make switching the default mode to e.g. a deterministic one as &amp;quot;simple&amp;quot; as actually writting the skill lists and testing it for balancing.&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=File:Bot-skilltree-basic.png&amp;diff=8285</id>
		<title>File:Bot-skilltree-basic.png</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=File:Bot-skilltree-basic.png&amp;diff=8285"/>
		<updated>2023-05-16T14:49:32Z</updated>

		<summary type="html">&lt;p&gt;Afontain: /* Summary */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
Some simple skilltree example for human bots&lt;br /&gt;
&lt;br /&gt;
The code versions is as of 2023-05-16, with https://github.com/Unvanquished/Unvanquished/pull/2697.&lt;br /&gt;
&lt;br /&gt;
== Licencing ==&lt;br /&gt;
{{licenses/cc-by-4.0}}&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=File:Bot-skilltree-basic.png&amp;diff=8284</id>
		<title>File:Bot-skilltree-basic.png</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=File:Bot-skilltree-basic.png&amp;diff=8284"/>
		<updated>2023-05-16T14:49:16Z</updated>

		<summary type="html">&lt;p&gt;Afontain: Afontain uploaded a new version of File:Bot-skilltree-basic.png&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
Some skilltree example for human bots with one base skill (force-enabled) and one disabled skill.&lt;br /&gt;
&lt;br /&gt;
The code versions is as of 2023-05-16, with https://github.com/Unvanquished/Unvanquished/pull/2697.&lt;br /&gt;
== Licencing ==&lt;br /&gt;
{{licenses/cc-by-4.0}}&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=File:Bot-skilltree-advanced.png&amp;diff=8283</id>
		<title>File:Bot-skilltree-advanced.png</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=File:Bot-skilltree-advanced.png&amp;diff=8283"/>
		<updated>2023-05-16T14:47:50Z</updated>

		<summary type="html">&lt;p&gt;Afontain: Some skilltree example for human bots with one base skill (force-enabled) and one disabled skill.

The code versions is as of 2023-05-16, with https://github.com/Unvanquished/Unvanquished/pull/2697.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
Some skilltree example for human bots with one base skill (force-enabled) and one disabled skill.&lt;br /&gt;
&lt;br /&gt;
The code versions is as of 2023-05-16, with https://github.com/Unvanquished/Unvanquished/pull/2697. &lt;br /&gt;
== Licencing ==&lt;br /&gt;
{{licenses/cc-by-4.0}}&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=File:Bot-skilltree-basic.png&amp;diff=8282</id>
		<title>File:Bot-skilltree-basic.png</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=File:Bot-skilltree-basic.png&amp;diff=8282"/>
		<updated>2023-05-16T14:46:51Z</updated>

		<summary type="html">&lt;p&gt;Afontain: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
Some skilltree example for human bots with one base skill (force-enabled) and one disabled skill.&lt;br /&gt;
&lt;br /&gt;
The code versions is as of 2023-05-16, with https://github.com/Unvanquished/Unvanquished/pull/2697.&lt;br /&gt;
== Licencing ==&lt;br /&gt;
{{licenses/cc-by-4.0}}&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=File:Bot-skilltree-basic.png&amp;diff=8281</id>
		<title>File:Bot-skilltree-basic.png</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=File:Bot-skilltree-basic.png&amp;diff=8281"/>
		<updated>2023-05-16T14:45:33Z</updated>

		<summary type="html">&lt;p&gt;Afontain: The state of the skilltree as it is with https://github.com/Unvanquished/Unvanquished/pull/2697, 2023-05-16.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
The state of the skilltree as it is with https://github.com/Unvanquished/Unvanquished/pull/2697, 2023-05-16.&lt;br /&gt;
== Licencing ==&lt;br /&gt;
{{licenses/cc-by-4.0}}&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Bot_design&amp;diff=8200</id>
		<title>Bot design</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Bot_design&amp;diff=8200"/>
		<updated>2023-04-17T18:23:33Z</updated>

		<summary type="html">&lt;p&gt;Afontain: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The main situations we want bots to work in are:&lt;br /&gt;
&lt;br /&gt;
* In a game where a single user plays in a team against a team of bots (let's call this ''1v0'')&lt;br /&gt;
* In a game where a few users play against each others, with a considerable amount of bots on both teams (let's call this ''1v1, 2v2'', etc.)&lt;br /&gt;
* In a game where a considerable number of players team up to play against a horde of bots (let's call this ''PvE'')&lt;br /&gt;
* In a game where a single user (or few users) play against a considerably bigger number of other users (let's call this ''1v3'', etc.)&lt;br /&gt;
&lt;br /&gt;
In games where bots are a minority in both teams, bots are not that important. When playing PvE, the variations of bot skill are also not very important, as players can't feel like they got an unfairly weak ally.&lt;br /&gt;
&lt;br /&gt;
== Bot personalities ==&lt;br /&gt;
&lt;br /&gt;
In 2022 and early 2023, we did some experiments about giving each bot a personality. The idea was to have a number of skills that are valuable in playing. Each bot would receive its unique set of skills, by some random selection. That would make them different from each other.&lt;br /&gt;
&lt;br /&gt;
Some examples of &amp;quot;bot skills&amp;quot; we used are: various alien trick moves, the ability to aim better than other bots, smartly buying human equipment/weapons and using the human medkit.&lt;br /&gt;
&lt;br /&gt;
The pros of this approach:&lt;br /&gt;
&lt;br /&gt;
* Bots do not behave all the same. That makes them more difficult to predict.&lt;br /&gt;
* Bots simulate real users more accurately.&lt;br /&gt;
&lt;br /&gt;
The cons:&lt;br /&gt;
&lt;br /&gt;
* It is harder to balance bots against each other. We would have to test a significant subset of all possible combinations. This matters a lot in 1v1 or 2v2. It matters even more in 1v3.&lt;br /&gt;
* Users will discover what skills are more valuable. They can tweak the skills the bots on their team have, by voting to remove them and add them again until they hit a sweet spot.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Formats/DPK&amp;diff=8042</id>
		<title>Formats/DPK</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Formats/DPK&amp;diff=8042"/>
		<updated>2022-11-06T11:30:48Z</updated>

		<summary type="html">&lt;p&gt;Afontain: correct sections&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Formats]]&lt;br /&gt;
[[Category:Mapping]]&lt;br /&gt;
== About the DPK name ==&lt;br /&gt;
&lt;br /&gt;
''DPK'' stands for ''“Dæmon PacKage”'', the DPK VFS is a ''PacKage''-based VFS leveraging ''Dependency'' mechanism.&lt;br /&gt;
&lt;br /&gt;
== DPK format specification ==&lt;br /&gt;
&lt;br /&gt;
The DPK format extends the legacy PK3 format with dependency mechanism and versionning and was implemented for the need of the [https://unvanquished.net/ Unvanquished game]. Like the PK3 VFS, the DPK VFS allows to extend and override an existing file system using packages, see the [[Filesystem]] page to see how it works. The {{engine}} is the reference implementation, it has been introduced under this name in Unvanquished 0.51.0 release.&lt;br /&gt;
&lt;br /&gt;
There is two DPK formats: archive and directory format.&lt;br /&gt;
&lt;br /&gt;
* Archive format is for distribution (commonly named ''DPK''), this format is meant to be easily shareable over the network and auto-downloadable by game clients;&lt;br /&gt;
: The archive format uses the PKZIP container (the well-known ''zip'' format) with a ''.dpk'' extension.&lt;br /&gt;
* Directory format is for editing/testing (commonly named ''DPKDIR'');&lt;br /&gt;
: The directory format is a simple plain directory with a ''.dpkdir'' extension.&lt;br /&gt;
&lt;br /&gt;
=== Package naming ===&lt;br /&gt;
&lt;br /&gt;
Format: ''&amp;lt;package-name&amp;gt;_&amp;lt;version-string&amp;gt;.&amp;lt;extension&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
* package-name: name of the package, some names are prefixed&lt;br /&gt;
:* mandatory prefix for map packages: ''“map-”'' (the engine will not find neither load the map otherwise)&lt;br /&gt;
:* recommended prefix for texture packages: ''&amp;quot;tex-”''&lt;br /&gt;
:* recommended prefix for various resource packages (like a package providing both sounds effects, textures, models and animation for a given player model) : ''&amp;quot;res-”''&lt;br /&gt;
:* forbidden characters: underscore, dot ''[_.]''&lt;br /&gt;
* version: version of the package, follows [https://salsa.debian.org/dpkg-team/dpkg/-/blob/main/lib/dpkg/version.c dpkg's version comparison priority], see [[Packaging version guidelines]] for Unvanquished specificities.&lt;br /&gt;
:* characters allowed: alphanumeric plus hyphen and tilde ''[a-zA-Z0-9~-]''&lt;br /&gt;
* extension: ''“dpk”'' for archive, ''“dpkdir”'' for directory&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
* ''unvanquished_0.51.0.dpk''&lt;br /&gt;
* ''map-parpax_0.5d-viech.dpk''&lt;br /&gt;
* ''tex-vega_src.dpkdir''&lt;br /&gt;
* ''res-players_src.dpkdir''&lt;br /&gt;
&lt;br /&gt;
=== Package layout ===&lt;br /&gt;
&lt;br /&gt;
Package archive or directory can contain a ''DEPS'' file on its root directory containing a list of other package it depends on.&lt;br /&gt;
&lt;br /&gt;
Each package reproduces the file system tree from his root.&lt;br /&gt;
&lt;br /&gt;
=== DEPS file format ===&lt;br /&gt;
&lt;br /&gt;
* One package name per line, optional explicit version separated from package name using a whitespace;&lt;br /&gt;
* Dependencies are loaded giving priority to first ones if multiple package provides different files under the same name.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tex-space&lt;br /&gt;
tex-pk02 1.0&lt;br /&gt;
tex-vega 0.4b&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Loading a package providing this ''DEPS'' file will trigger the game engine to also load the ''tex-space'' package (the most recent version found), and to load the 1.0 version of the ''tex-pk02'' package and the 0.4b version of the tex-vega package.&lt;br /&gt;
&lt;br /&gt;
== Software compatibility ==&lt;br /&gt;
&lt;br /&gt;
Software that support DPK format and have first class Unvanquished support:&lt;br /&gt;
&lt;br /&gt;
* [[Engine|Dæmon]] game engine:&amp;lt;br /&amp;gt;full dpk/dpkdir support with dependency and version handling,&amp;lt;br /&amp;gt;support in master branch;&lt;br /&gt;
* [[Tools/NetRadiant|NetRadiant]] level editor:&amp;lt;br /&amp;gt;full dpk/dpkdir support with dependency and version handling,&amp;lt;br /&amp;gt;support in master branch;&lt;br /&gt;
* [[Tools/q3map2|q3map2]] map compiler (NetRadiant tree):&amp;lt;br /&amp;gt;basic dpk/dkdir support, loads all dpk/dpkdir it finds,&amp;lt;br /&amp;gt;support in master branch;&lt;br /&gt;
* [[Tools/Chameleon|Chameleon]] texture replacement editor:&amp;lt;br /&amp;gt;basic dpk/dpkdir support, loads all dpk/dpkdir it finds,&amp;lt;br /&amp;gt;support in master branch;&lt;br /&gt;
* [[Tools/Urcheon|Urcheon]] package build tool:&amp;lt;br /&amp;gt;basic dpkdir support, loads all dpkdir it finds,&amp;lt;br /&amp;gt;support in master branch;&lt;br /&gt;
* [[XQF]] game server browser:&amp;lt;br /&amp;gt;basic dpk support, loads all dpk it finds,&amp;lt;br /&amp;gt;support in master branch.&lt;br /&gt;
&lt;br /&gt;
Other software that are known to support DPK format and have working Unvanquished support:&lt;br /&gt;
&lt;br /&gt;
* [[Tools/GtkRadiant|GtkRadiant]] level editor:&amp;lt;br /&amp;gt;basic dpk/dkdir support in master branch, loads all dpk/dpkdir it finds,&amp;lt;br /&amp;gt;support in master branch,&amp;lt;br /&amp;gt;prefer using NetRadiant if possible and if NetRadiant is not possible prefer q3map2 from NetRadiant tree;&lt;br /&gt;
* [[Tools/q3map2|q3map2]] map compiler (GtkRadiant tree):&amp;lt;br /&amp;gt;basic dpk/dkdir support, loads all dpk/dpkdir it finds,&amp;lt;br /&amp;gt; support in master branch,&amp;lt;br /&amp;gt;not recommended for Dæmon mapping due to feature lacking.&lt;br /&gt;
&lt;br /&gt;
Other software that are known to support DPK format but have not working Unvanquished support:&lt;br /&gt;
&lt;br /&gt;
* [[tools/DarkRadiant|DarkRadiant]] level editor: basic dpk/dpkdir support, loads all dpk/dpkdir it finds,&amp;lt;br /&amp;gt;support in standard releases (just add &amp;quot;dpk&amp;quot; to game file),&amp;lt;br /&amp;gt;not yet usable for Dæmon/Unvanquished mapping due to some Q3 map parsing issues.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Merging several DPK==&lt;br /&gt;
{{OutOfDate}}&lt;br /&gt;
&lt;br /&gt;
To combine all packages together, at a Bash shell:&lt;br /&gt;
&lt;br /&gt;
 $ cd [[Game locations|&amp;lt;var&amp;gt;data directory&amp;lt;/var&amp;gt;]]/pkg; mkdir tmp; for pk3 in pak{{0..9},A}.pk3; do unzip -o $pk3 -d tmp; done&lt;br /&gt;
&lt;br /&gt;
(If there are additional &amp;lt;code&amp;gt;pak*&amp;lt;/code&amp;gt; files (e.g., &amp;lt;code&amp;gt;pakB.pk3&amp;lt;/code&amp;gt;), edit the pattern accordingly (e.g., to &amp;lt;code&amp;gt;pak{{0..9},{A..B}}.pk3&amp;lt;/code&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
This will place the cumulative contents (i.e., as the engine would see them) of all the &amp;lt;code&amp;gt;pak*.pk3&amp;lt;/code&amp;gt; archives into a new &amp;lt;code&amp;gt;tmp/&amp;lt;/code&amp;gt; directory in your data directory.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Testing&amp;diff=8041</id>
		<title>Testing</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Testing&amp;diff=8041"/>
		<updated>2022-11-06T11:29:48Z</updated>

		<summary type="html">&lt;p&gt;Afontain: fix spacing&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Testing]]&lt;br /&gt;
==Reporting bugs==&lt;br /&gt;
&lt;br /&gt;
Please see the [[Bug_reporting|bug reporting]] page. This page is about helping modders and developers testing their changes.&lt;br /&gt;
&lt;br /&gt;
==Debugging==&lt;br /&gt;
&lt;br /&gt;
To create a debug build, change &amp;lt;code&amp;gt;CMAKE_BUILD_TYPE&amp;lt;/code&amp;gt; in CMake from &amp;lt;code&amp;gt;Release&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;Debug&amp;lt;/code&amp;gt;, then [[Compiling_the_source|compile]].&lt;br /&gt;
&lt;br /&gt;
You may find it necessary to set &amp;lt;code&amp;gt;in_nograb&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; to disable pointer grabbing so that you may use your debugger.&lt;br /&gt;
&lt;br /&gt;
===Debugging with gdb===&lt;br /&gt;
&lt;br /&gt;
Start gdb as follows:&lt;br /&gt;
&lt;br /&gt;
 $ gdb --args ./daemon +devmap chasm&lt;br /&gt;
&lt;br /&gt;
If the program segfaults, a backtrace is very useful to the developers in determining the source of the problem. At the debugger prompt, type &amp;lt;code&amp;gt;bt&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 (gdb) bt&lt;br /&gt;
&lt;br /&gt;
===Debugging with Xcode===&lt;br /&gt;
&lt;br /&gt;
With Xcode 4, even if you did not build the game with Xcode, you may still use its facilities for debugging.&lt;br /&gt;
&lt;br /&gt;
# Open any project. If necessary, create a new one. It may contain anything.&lt;br /&gt;
# Click &amp;quot;Product&amp;quot; on the menu bar and navigate to &amp;quot;Attach to Process&amp;quot;. Look for &amp;quot;daemon&amp;quot; listed under &amp;quot;Applications&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
After a moment, the application will be ready for debugging.&lt;br /&gt;
&lt;br /&gt;
See the [https://developer.apple.com/library/mac/#documentation/ToolsLanguages/Conceptual/Xcode4UserGuide/060-Debug_Your_App/debug_app.html#//apple_ref/doc/uid/TP40010215-CH3-SW1 Xcode 4 User Guide] for more information.&lt;br /&gt;
&lt;br /&gt;
==Live Testing==&lt;br /&gt;
&lt;br /&gt;
===Starting a testing session===&lt;br /&gt;
&lt;br /&gt;
Start the game, and enter the following command:&lt;br /&gt;
&lt;br /&gt;
 /devmap &amp;lt;var&amp;gt;map name&amp;lt;/var&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding bots===&lt;br /&gt;
&lt;br /&gt;
Like fish in a fish bowl, they can bring some activity in a map. &lt;br /&gt;
&lt;br /&gt;
 /bot fill 5   # add 5 bots&lt;br /&gt;
&lt;br /&gt;
You can also have a look at all the &amp;lt;code&amp;gt;g_bot_*&amp;lt;/code&amp;gt; cvars, they are quite interesting. There is even a graphical user interface for these!&lt;br /&gt;
&lt;br /&gt;
===Moving around with ease and spawning anywhere===&lt;br /&gt;
&lt;br /&gt;
You can pass through walls and fly around using &amp;lt;code&amp;gt;/noclip&amp;lt;/code&amp;gt;, and you can spawn anywhere you want using &amp;lt;code&amp;gt;/devteam h&amp;lt;/code&amp;gt; for humans or &amp;lt;code&amp;gt;/teamteam a&amp;lt;/code&amp;gt; for aliens. That's very practical and can allow you to start from an empty map.&lt;br /&gt;
&lt;br /&gt;
To load an empty map without having the game finishing immediately, you can use &amp;lt;code&amp;gt;g_neverEnd&amp;lt;/code&amp;gt;. This can help porting maps.&lt;br /&gt;
&lt;br /&gt;
===The &amp;lt;code&amp;gt;/give&amp;lt;/code&amp;gt; command===&lt;br /&gt;
&lt;br /&gt;
The /give will give you an easy way to test situations without being blocked by funds or team advancement.&lt;br /&gt;
&lt;br /&gt;
 /team a           # join aliens&lt;br /&gt;
 /give momentum    # give all the momentum you can to your team&lt;br /&gt;
 /give bp 100      # get 100 build points free&lt;br /&gt;
 /give funds       # get rich quick! I swear it's not a pyramid scheme!&lt;br /&gt;
 /give all         # get all personal things you can get, in addition to money (BP and momentum are independant)&lt;br /&gt;
&lt;br /&gt;
You can also combine several commands into one, for example you can test advanced dragoon really quickly&lt;br /&gt;
&lt;br /&gt;
=== Some misc useful cvars===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;cg_drawSpeed&amp;lt;/code&amp;gt; to see how fast you are moving, &amp;lt;code&amp;gt;/set cg_drawSpeed 2&amp;lt;/code&amp;gt; even brings an histogram.&lt;br /&gt;
* &amp;lt;code&amp;gt;cg_drawBBOX&amp;lt;/code&amp;gt; to see how big or small the bounding box are&lt;br /&gt;
* &amp;lt;code&amp;gt;cg_drawDebugDistance&amp;lt;/code&amp;gt; to give you an idea of how far away of you a distance of &amp;quot;100 quake units&amp;quot; is&lt;br /&gt;
* &amp;lt;code&amp;gt;timescale&amp;lt;/code&amp;gt; setting this will make everything faster, or slower. Be careful that if you set it too low (say less than 0.1) the graphical console will take a lot of time to visibly appear, but you can still type in it. For example to do &amp;lt;code&amp;gt;/timescale 1&amp;lt;/code&amp;gt; again.&lt;br /&gt;
* &amp;lt;code&amp;gt;g_freeFundPeriod&amp;lt;/code&amp;gt; to change how often you and other clients are gifted money. This can be an alternative to making bots ignore limits that can give a bit more diversity in their choices and behaviours (rich bots will always rush, for example)&lt;br /&gt;
&lt;br /&gt;
==Debugging Graphics==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;cg_draw2D&amp;lt;/code&amp;gt; can allow you to disable 2D drawing. It may be useful if you want to ignore 2D performances from your benchmarks&lt;br /&gt;
&lt;br /&gt;
There probably exist proprietary tools for your platform. For example AMD used to have gDEBugger, and [https://gpuopen.com/archived/gpu-perfstudio/ GPU PerfStudio] proprietary debuggers.&lt;br /&gt;
&lt;br /&gt;
===apitrace===&lt;br /&gt;
&lt;br /&gt;
[https://apitrace.github.io/ apitrace] is an open-source tool that records every graphics API call made by an application. After the application has closed, you can step through individual calls to the graphics API, allowing you to&lt;br /&gt;
* see the result exactly as it would appear following each call,&lt;br /&gt;
* see graphs of API usage, and&lt;br /&gt;
* inspect buffers.&lt;br /&gt;
&lt;br /&gt;
Linux users can install it from their package manager, for example:&lt;br /&gt;
&lt;br /&gt;
 sudo apt install apitrace-tracers apitrace-gui&lt;br /&gt;
&lt;br /&gt;
Windows users can [http://people.freedesktop.org/~jrfonseca/apitrace/ download a build].&lt;br /&gt;
&lt;br /&gt;
==General Tips==&lt;br /&gt;
&lt;br /&gt;
===Miscellaneous===&lt;br /&gt;
&lt;br /&gt;
* To stress test the engine's ability to display a large number of buildables, you can tweak &amp;lt;code&amp;gt;g_BPInitialBudget&amp;lt;/code&amp;gt; and build as much as you wish.&lt;br /&gt;
* To determine what file was loaded for a particular asset (e.g., to determine if files are being read from a particular [[Formats/DPK|.dpk archive]]) use the &amp;lt;code&amp;gt;/which&amp;lt;/code&amp;gt; command with the relative path to the asset as an argument. You can use tab-completion.&lt;br /&gt;
&lt;br /&gt;
For example, this means that you are effectively the new version of an UI file:&lt;br /&gt;
&lt;br /&gt;
 /which ui/shared/circlemenu.rcss&lt;br /&gt;
 File &amp;quot;ui/shared/circlemenu.rcss&amp;quot; found in &amp;quot;/home/me/unv/Unvanquished/pkg/unvanquished_src.dpkdir/&amp;quot; &lt;br /&gt;
&lt;br /&gt;
==Viewing Runtime Information==&lt;br /&gt;
&lt;br /&gt;
The engine and game logic provide a number of commands for viewing information about its current state.&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===Renderer===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;fbolist&amp;lt;/code&amp;gt; &amp;amp;mdash; List all frame buffer objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;vbolist&amp;lt;/code&amp;gt; &amp;amp;mdash; List all vertex buffer objects.&lt;br /&gt;
&lt;br /&gt;
===Gamelogic===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;entityList&amp;lt;/code&amp;gt; &amp;amp;mdash; &lt;br /&gt;
* &amp;lt;code&amp;gt;sectorlist&amp;lt;/code&amp;gt; &amp;amp;mdash;&lt;br /&gt;
* &amp;lt;code&amp;gt;flaglist&amp;lt;/code&amp;gt; &amp;amp;mdash; List admin flags&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
==Testing materials and textures==&lt;br /&gt;
&lt;br /&gt;
See {{Subpage|Materials}}.&lt;br /&gt;
&lt;br /&gt;
==Testing maps==&lt;br /&gt;
&lt;br /&gt;
See {{Subpage|Maps}}.&lt;br /&gt;
&lt;br /&gt;
==Testing models==&lt;br /&gt;
&lt;br /&gt;
See {{Subpage|Models}}.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Testing&amp;diff=8040</id>
		<title>Testing</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Testing&amp;diff=8040"/>
		<updated>2022-11-06T11:27:30Z</updated>

		<summary type="html">&lt;p&gt;Afontain: Continue cleaning&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Testing]]&lt;br /&gt;
&lt;br /&gt;
==Reporting bugs==&lt;br /&gt;
&lt;br /&gt;
Please see the [[Bug_reporting|bug reporting]] page. This page is about helping modders and developers testing their changes.&lt;br /&gt;
&lt;br /&gt;
==Debugging==&lt;br /&gt;
&lt;br /&gt;
To create a debug build, change &amp;lt;code&amp;gt;CMAKE_BUILD_TYPE&amp;lt;/code&amp;gt; in CMake from &amp;lt;code&amp;gt;Release&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;Debug&amp;lt;/code&amp;gt;, then [[Compiling_the_source|compile]].&lt;br /&gt;
&lt;br /&gt;
You may find it necessary to set &amp;lt;code&amp;gt;in_nograb&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; to disable pointer grabbing so that you may use your debugger.&lt;br /&gt;
&lt;br /&gt;
===Debugging with gdb===&lt;br /&gt;
&lt;br /&gt;
Start gdb as follows:&lt;br /&gt;
&lt;br /&gt;
 $ gdb --args ./daemon +devmap chasm&lt;br /&gt;
&lt;br /&gt;
If the program segfaults, a backtrace is very useful to the developers in determining the source of the problem. At the debugger prompt, type &amp;lt;code&amp;gt;bt&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 (gdb) bt&lt;br /&gt;
&lt;br /&gt;
===Debugging with Xcode===&lt;br /&gt;
&lt;br /&gt;
With Xcode 4, even if you did not build the game with Xcode, you may still use its facilities for debugging.&lt;br /&gt;
&lt;br /&gt;
# Open any project. If necessary, create a new one. It may contain anything.&lt;br /&gt;
# Click &amp;quot;Product&amp;quot; on the menu bar and navigate to &amp;quot;Attach to Process&amp;quot;. Look for &amp;quot;daemon&amp;quot; listed under &amp;quot;Applications&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
After a moment, the application will be ready for debugging.&lt;br /&gt;
&lt;br /&gt;
See the [https://developer.apple.com/library/mac/#documentation/ToolsLanguages/Conceptual/Xcode4UserGuide/060-Debug_Your_App/debug_app.html#//apple_ref/doc/uid/TP40010215-CH3-SW1 Xcode 4 User Guide] for more information.&lt;br /&gt;
&lt;br /&gt;
==Live Testing==&lt;br /&gt;
&lt;br /&gt;
===Starting a testing session===&lt;br /&gt;
&lt;br /&gt;
Start the game, and enter the following command:&lt;br /&gt;
&lt;br /&gt;
 /devmap &amp;lt;var&amp;gt;map name&amp;lt;/var&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding bots===&lt;br /&gt;
&lt;br /&gt;
Like fish in a fish bowl, they can bring some activity in a map. &lt;br /&gt;
&lt;br /&gt;
 /bot fill 5   # add 5 bots&lt;br /&gt;
&lt;br /&gt;
You can also have a look at all the &amp;lt;code&amp;gt;g_bot_*&amp;lt;/code&amp;gt; cvars, they are quite interesting. There is even a graphical user interface for these!&lt;br /&gt;
&lt;br /&gt;
===Moving around with ease and spawning anywhere===&lt;br /&gt;
&lt;br /&gt;
You can pass through walls and fly around using &amp;lt;code&amp;gt;/noclip&amp;lt;/code&amp;gt;, and you can spawn anywhere you want using &amp;lt;code&amp;gt;/devteam h&amp;lt;/code&amp;gt; for humans or &amp;lt;code&amp;gt;/teamteam a&amp;lt;/code&amp;gt; for aliens. That's very practical and can allow you to start from an empty map.&lt;br /&gt;
&lt;br /&gt;
To load an empty map without having the game finishing immediately, you can use &amp;lt;code&amp;gt;g_neverEnd&amp;lt;/code&amp;gt;. This can help porting maps.&lt;br /&gt;
&lt;br /&gt;
===The &amp;lt;code&amp;gt;/give&amp;lt;/code&amp;gt; command===&lt;br /&gt;
&lt;br /&gt;
The /give will give you an easy way to test situations without being blocked by funds or team advancement.&lt;br /&gt;
&lt;br /&gt;
 /team a           # join aliens&lt;br /&gt;
 /give momentum    # give all the momentum you can to your team&lt;br /&gt;
 /give bp 100      # get 100 build points free&lt;br /&gt;
 /give funds       # get rich quick! I swear it's not a pyramid scheme!&lt;br /&gt;
 /give all         # get all personal things you can get, in addition to money (BP and momentum are independant)&lt;br /&gt;
&lt;br /&gt;
You can also combine several commands into one, for example you can test advanced dragoon really quickly&lt;br /&gt;
&lt;br /&gt;
=== Some misc useful cvars===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;cg_drawSpeed&amp;lt;/code&amp;gt; to see how fast you are moving, &amp;lt;code&amp;gt;/set cg_drawSpeed 2&amp;lt;/code&amp;gt; even brings an histogram.&lt;br /&gt;
* &amp;lt;code&amp;gt;cg_drawBBOX&amp;lt;/code&amp;gt; to see how big or small the bounding box are&lt;br /&gt;
* &amp;lt;code&amp;gt;cg_drawDebugDistance&amp;lt;/code&amp;gt; to give you an idea of how far away of you a distance of &amp;quot;100 quake units&amp;quot; is&lt;br /&gt;
* &amp;lt;code&amp;gt;timescale&amp;lt;/code&amp;gt; setting this will make everything faster, or slower. Be careful that if you set it too low (say less than 0.1) the graphical console will take a lot of time to visibly appear, but you can still type in it. For example to do &amp;lt;code&amp;gt;/timescale 1&amp;lt;/code&amp;gt; again.&lt;br /&gt;
* &amp;lt;code&amp;gt;g_freeFundPeriod&amp;lt;/code&amp;gt; to change how often you and other clients are gifted money. This can be an alternative to making bots ignore limits that can give a bit more diversity in their choices and behaviours (rich bots will always rush, for example)&lt;br /&gt;
&lt;br /&gt;
==Debugging Graphics==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;cg_draw2D&amp;lt;/code&amp;gt; can allow you to disable 2D drawing. It may be useful if you want to ignore 2D performances from your benchmarks&lt;br /&gt;
&lt;br /&gt;
There probably exist proprietary tools for your platform. For example AMD used to have gDEBugger, and [https://gpuopen.com/archived/gpu-perfstudio/ GPU PerfStudio] proprietary debuggers.&lt;br /&gt;
&lt;br /&gt;
===apitrace===&lt;br /&gt;
&lt;br /&gt;
[https://apitrace.github.io/ apitrace] is an open-source tool that records every graphics API call made by an application. After the application has closed, you can step through individual calls to the graphics API, allowing you to&lt;br /&gt;
* see the result exactly as it would appear following each call,&lt;br /&gt;
* see graphs of API usage, and&lt;br /&gt;
* inspect buffers.&lt;br /&gt;
&lt;br /&gt;
Linux users can install it from their package manager, for example:&lt;br /&gt;
&lt;br /&gt;
 sudo apt install apitrace-tracers apitrace-gui&lt;br /&gt;
&lt;br /&gt;
Windows users can [http://people.freedesktop.org/~jrfonseca/apitrace/ download a build].&lt;br /&gt;
&lt;br /&gt;
==General Tips==&lt;br /&gt;
&lt;br /&gt;
===Miscellaneous===&lt;br /&gt;
&lt;br /&gt;
* To stress test the engine's ability to display a large number of buildables, you can tweak &amp;lt;code&amp;gt;g_BPInitialBudget&amp;lt;/code&amp;gt; and build as much as you wish.&lt;br /&gt;
* To determine what file was loaded for a particular asset (e.g., to determine if files are being read from a particular [[Formats/DPK|.dpk archive]]) use the &amp;lt;code&amp;gt;/which&amp;lt;/code&amp;gt; command with the relative path to the asset as an argument. You can use tab-completion.&lt;br /&gt;
&lt;br /&gt;
For example, this means that you are effectively the new version of an UI file:&lt;br /&gt;
&lt;br /&gt;
 /which ui/shared/circlemenu.rcss&lt;br /&gt;
 File &amp;quot;ui/shared/circlemenu.rcss&amp;quot; found in &amp;quot;/home/me/unv/Unvanquished/pkg/unvanquished_src.dpkdir/&amp;quot; &lt;br /&gt;
&lt;br /&gt;
==Viewing Runtime Information==&lt;br /&gt;
&lt;br /&gt;
The engine and game logic provide a number of commands for viewing information about its current state.&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===Renderer===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;fbolist&amp;lt;/code&amp;gt; &amp;amp;mdash; List all frame buffer objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;vbolist&amp;lt;/code&amp;gt; &amp;amp;mdash; List all vertex buffer objects.&lt;br /&gt;
&lt;br /&gt;
===Gamelogic===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;entityList&amp;lt;/code&amp;gt; &amp;amp;mdash; &lt;br /&gt;
* &amp;lt;code&amp;gt;sectorlist&amp;lt;/code&amp;gt; &amp;amp;mdash;&lt;br /&gt;
* &amp;lt;code&amp;gt;flaglist&amp;lt;/code&amp;gt; &amp;amp;mdash; List admin flags&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
==Testing materials and textures==&lt;br /&gt;
&lt;br /&gt;
See {{Subpage|Materials}}.&lt;br /&gt;
&lt;br /&gt;
==Testing maps==&lt;br /&gt;
&lt;br /&gt;
See {{Subpage|Maps}}.&lt;br /&gt;
&lt;br /&gt;
==Testing models==&lt;br /&gt;
&lt;br /&gt;
See {{Subpage|Models}}.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Formats/DPK&amp;diff=8039</id>
		<title>Formats/DPK</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Formats/DPK&amp;diff=8039"/>
		<updated>2022-11-06T11:24:09Z</updated>

		<summary type="html">&lt;p&gt;Afontain: Move text that was on the Testing page (https://wiki.unvanquished.net/index.php?title=Testing)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Formats]]&lt;br /&gt;
[[Category:Mapping]]&lt;br /&gt;
== About the DPK name ==&lt;br /&gt;
&lt;br /&gt;
''DPK'' stands for ''“Dæmon PacKage”'', the DPK VFS is a ''PacKage''-based VFS leveraging ''Dependency'' mechanism.&lt;br /&gt;
&lt;br /&gt;
== DPK format specification ==&lt;br /&gt;
&lt;br /&gt;
The DPK format extends the legacy PK3 format with dependency mechanism and versionning and was implemented for the need of the [https://unvanquished.net/ Unvanquished game]. Like the PK3 VFS, the DPK VFS allows to extend and override an existing file system using packages, see the [[Filesystem]] page to see how it works. The {{engine}} is the reference implementation, it has been introduced under this name in Unvanquished 0.51.0 release.&lt;br /&gt;
&lt;br /&gt;
There is two DPK formats: archive and directory format.&lt;br /&gt;
&lt;br /&gt;
* Archive format is for distribution (commonly named ''DPK''), this format is meant to be easily shareable over the network and auto-downloadable by game clients;&lt;br /&gt;
: The archive format uses the PKZIP container (the well-known ''zip'' format) with a ''.dpk'' extension.&lt;br /&gt;
* Directory format is for editing/testing (commonly named ''DPKDIR'');&lt;br /&gt;
: The directory format is a simple plain directory with a ''.dpkdir'' extension.&lt;br /&gt;
&lt;br /&gt;
=== Package naming ===&lt;br /&gt;
&lt;br /&gt;
Format: ''&amp;lt;package-name&amp;gt;_&amp;lt;version-string&amp;gt;.&amp;lt;extension&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
* package-name: name of the package, some names are prefixed&lt;br /&gt;
:* mandatory prefix for map packages: ''“map-”'' (the engine will not find neither load the map otherwise)&lt;br /&gt;
:* recommended prefix for texture packages: ''&amp;quot;tex-”''&lt;br /&gt;
:* recommended prefix for various resource packages (like a package providing both sounds effects, textures, models and animation for a given player model) : ''&amp;quot;res-”''&lt;br /&gt;
:* forbidden characters: underscore, dot ''[_.]''&lt;br /&gt;
* version: version of the package, follows [https://salsa.debian.org/dpkg-team/dpkg/-/blob/main/lib/dpkg/version.c dpkg's version comparison priority], see [[Packaging version guidelines]] for Unvanquished specificities.&lt;br /&gt;
:* characters allowed: alphanumeric plus hyphen and tilde ''[a-zA-Z0-9~-]''&lt;br /&gt;
* extension: ''“dpk”'' for archive, ''“dpkdir”'' for directory&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
* ''unvanquished_0.51.0.dpk''&lt;br /&gt;
* ''map-parpax_0.5d-viech.dpk''&lt;br /&gt;
* ''tex-vega_src.dpkdir''&lt;br /&gt;
* ''res-players_src.dpkdir''&lt;br /&gt;
&lt;br /&gt;
=== Package layout ===&lt;br /&gt;
&lt;br /&gt;
Package archive or directory can contain a ''DEPS'' file on its root directory containing a list of other package it depends on.&lt;br /&gt;
&lt;br /&gt;
Each package reproduces the file system tree from his root.&lt;br /&gt;
&lt;br /&gt;
=== DEPS file format ===&lt;br /&gt;
&lt;br /&gt;
* One package name per line, optional explicit version separated from package name using a whitespace;&lt;br /&gt;
* Dependencies are loaded giving priority to first ones if multiple package provides different files under the same name.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tex-space&lt;br /&gt;
tex-pk02 1.0&lt;br /&gt;
tex-vega 0.4b&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Loading a package providing this ''DEPS'' file will trigger the game engine to also load the ''tex-space'' package (the most recent version found), and to load the 1.0 version of the ''tex-pk02'' package and the 0.4b version of the tex-vega package.&lt;br /&gt;
&lt;br /&gt;
== Software compatibility ==&lt;br /&gt;
&lt;br /&gt;
Software that support DPK format and have first class Unvanquished support:&lt;br /&gt;
&lt;br /&gt;
* [[Engine|Dæmon]] game engine:&amp;lt;br /&amp;gt;full dpk/dpkdir support with dependency and version handling,&amp;lt;br /&amp;gt;support in master branch;&lt;br /&gt;
* [[Tools/NetRadiant|NetRadiant]] level editor:&amp;lt;br /&amp;gt;full dpk/dpkdir support with dependency and version handling,&amp;lt;br /&amp;gt;support in master branch;&lt;br /&gt;
* [[Tools/q3map2|q3map2]] map compiler (NetRadiant tree):&amp;lt;br /&amp;gt;basic dpk/dkdir support, loads all dpk/dpkdir it finds,&amp;lt;br /&amp;gt;support in master branch;&lt;br /&gt;
* [[Tools/Chameleon|Chameleon]] texture replacement editor:&amp;lt;br /&amp;gt;basic dpk/dpkdir support, loads all dpk/dpkdir it finds,&amp;lt;br /&amp;gt;support in master branch;&lt;br /&gt;
* [[Tools/Urcheon|Urcheon]] package build tool:&amp;lt;br /&amp;gt;basic dpkdir support, loads all dpkdir it finds,&amp;lt;br /&amp;gt;support in master branch;&lt;br /&gt;
* [[XQF]] game server browser:&amp;lt;br /&amp;gt;basic dpk support, loads all dpk it finds,&amp;lt;br /&amp;gt;support in master branch.&lt;br /&gt;
&lt;br /&gt;
Other software that are known to support DPK format and have working Unvanquished support:&lt;br /&gt;
&lt;br /&gt;
* [[Tools/GtkRadiant|GtkRadiant]] level editor:&amp;lt;br /&amp;gt;basic dpk/dkdir support in master branch, loads all dpk/dpkdir it finds,&amp;lt;br /&amp;gt;support in master branch,&amp;lt;br /&amp;gt;prefer using NetRadiant if possible and if NetRadiant is not possible prefer q3map2 from NetRadiant tree;&lt;br /&gt;
* [[Tools/q3map2|q3map2]] map compiler (GtkRadiant tree):&amp;lt;br /&amp;gt;basic dpk/dkdir support, loads all dpk/dpkdir it finds,&amp;lt;br /&amp;gt; support in master branch,&amp;lt;br /&amp;gt;not recommended for Dæmon mapping due to feature lacking.&lt;br /&gt;
&lt;br /&gt;
Other software that are known to support DPK format but have not working Unvanquished support:&lt;br /&gt;
&lt;br /&gt;
* [[tools/DarkRadiant|DarkRadiant]] level editor: basic dpk/dpkdir support, loads all dpk/dpkdir it finds,&amp;lt;br /&amp;gt;support in standard releases (just add &amp;quot;dpk&amp;quot; to game file),&amp;lt;br /&amp;gt;not yet usable for Dæmon/Unvanquished mapping due to some Q3 map parsing issues.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Merging several DPK===&lt;br /&gt;
{{OutOfDate}}&lt;br /&gt;
&lt;br /&gt;
To combine all packages together, at a Bash shell:&lt;br /&gt;
&lt;br /&gt;
 $ cd [[Game locations|&amp;lt;var&amp;gt;data directory&amp;lt;/var&amp;gt;]]/pkg; mkdir tmp; for pk3 in pak{{0..9},A}.pk3; do unzip -o $pk3 -d tmp; done&lt;br /&gt;
&lt;br /&gt;
(If there are additional &amp;lt;code&amp;gt;pak*&amp;lt;/code&amp;gt; files (e.g., &amp;lt;code&amp;gt;pakB.pk3&amp;lt;/code&amp;gt;), edit the pattern accordingly (e.g., to &amp;lt;code&amp;gt;pak{{0..9},{A..B}}.pk3&amp;lt;/code&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
This will place the cumulative contents (i.e., as the engine would see them) of all the &amp;lt;code&amp;gt;pak*.pk3&amp;lt;/code&amp;gt; archives into a new &amp;lt;code&amp;gt;tmp/&amp;lt;/code&amp;gt; directory in your data directory.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Testing&amp;diff=8038</id>
		<title>Testing</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Testing&amp;diff=8038"/>
		<updated>2022-11-06T10:16:57Z</updated>

		<summary type="html">&lt;p&gt;Afontain: Update quite a bit the page, and give testing tips&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{OutOfDate}}&lt;br /&gt;
[[Category:Testing]]&lt;br /&gt;
==Reporting a bug==&lt;br /&gt;
&lt;br /&gt;
If you wish to report a bug, you may want to have a look at [[bug reporting]] instead&lt;br /&gt;
&lt;br /&gt;
==Debugging==&lt;br /&gt;
&lt;br /&gt;
To create a debug build, change &amp;lt;code&amp;gt;CMAKE_BUILD_TYPE&amp;lt;/code&amp;gt; in CMake from &amp;lt;code&amp;gt;Release&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;Debug&amp;lt;/code&amp;gt;, then [[Compiling_the_source|compile]].&lt;br /&gt;
&lt;br /&gt;
You may find it necessary to set &amp;lt;code&amp;gt;in_nograb&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; to disable pointer grabbing so that you may use your debugger.&lt;br /&gt;
&lt;br /&gt;
===Debugging with gdb===&lt;br /&gt;
&lt;br /&gt;
Start gdb as follows:&lt;br /&gt;
&lt;br /&gt;
 $ gdb --args ./daemon +devmap chasm&lt;br /&gt;
&lt;br /&gt;
If the program segfaults, a backtrace is very useful to the developers in determining the source of the problem. At the debugger prompt, type &amp;lt;code&amp;gt;bt&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 (gdb) bt&lt;br /&gt;
&lt;br /&gt;
===Debugging with Xcode===&lt;br /&gt;
&lt;br /&gt;
With Xcode 4, even if you did not build the game with Xcode, you may still use its facilities for debugging.&lt;br /&gt;
&lt;br /&gt;
# Open any project. If necessary, create a new one. It may contain anything.&lt;br /&gt;
# Click &amp;quot;Product&amp;quot; on the menu bar and navigate to &amp;quot;Attach to Process&amp;quot;. Look for &amp;quot;daemon.i386&amp;quot; listed under &amp;quot;Applications&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
After a moment, the application will be ready for debugging.&lt;br /&gt;
&lt;br /&gt;
See the [https://developer.apple.com/library/mac/#documentation/ToolsLanguages/Conceptual/Xcode4UserGuide/060-Debug_Your_App/debug_app.html#//apple_ref/doc/uid/TP40010215-CH3-SW1 Xcode 4 User Guide] for more information.&lt;br /&gt;
&lt;br /&gt;
==Live Testing==&lt;br /&gt;
&lt;br /&gt;
===Starting a testing session===&lt;br /&gt;
&lt;br /&gt;
Start the game, and enter the following command:&lt;br /&gt;
&lt;br /&gt;
 /devmap &amp;lt;var&amp;gt;map name&amp;lt;/var&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding bots===&lt;br /&gt;
&lt;br /&gt;
Like fish in a fish bowl, they can bring some activity in a map. &lt;br /&gt;
&lt;br /&gt;
 /bot fill 5   # add 5 bots&lt;br /&gt;
&lt;br /&gt;
You can also have a look at all the &amp;lt;code&amp;gt;g_bot_*&amp;lt;/code&amp;gt; cvars, they are quite interesting. There is even a graphical user interface for these!&lt;br /&gt;
&lt;br /&gt;
===The &amp;lt;code&amp;gt;/give&amp;lt;/code&amp;gt; command===&lt;br /&gt;
&lt;br /&gt;
The /give will give you an easy way to test situations without being blocked by funds or team advancement.&lt;br /&gt;
&lt;br /&gt;
 /team a           # join aliens&lt;br /&gt;
 /give momentum    # give all the momentum you can to your team&lt;br /&gt;
 /give bp 100      # get 100 build points free&lt;br /&gt;
 /give funds       # get rich quick! I swear it's not a pyramid scheme!&lt;br /&gt;
 /give all         # get all personal things you can get, in addition to money (BP and momentum are independant)&lt;br /&gt;
&lt;br /&gt;
You can also combine several commands into one, for example you can test advanced dragoon really quickly&lt;br /&gt;
&lt;br /&gt;
=== Some misc useful cvars===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;cg_drawSpeed&amp;lt;/code&amp;gt; to see how fast you are moving, &amp;lt;code&amp;gt;/set cg_drawSpeed 2&amp;lt;/code&amp;gt; even brings an histogram.&lt;br /&gt;
* &amp;lt;code&amp;gt;cg_drawBBOX&amp;lt;/code&amp;gt; to see how big or small the bounding box are&lt;br /&gt;
* &amp;lt;code&amp;gt;cg_drawDebugDistance&amp;lt;/code&amp;gt; to give you an idea of how far away of you a distance of &amp;quot;100 quake units&amp;quot; is&lt;br /&gt;
* &amp;lt;code&amp;gt;timescale&amp;lt;/code&amp;gt; setting this will make everything faster, or slower. Be careful that if you set it too low (say less than 0.1) the graphical console will take a lot of time to visibly appear, but you can still type in it. For example to do &amp;lt;code&amp;gt;/timescale 1&amp;lt;/code&amp;gt; again.&lt;br /&gt;
* &amp;lt;code&amp;gt;g_freeFundPeriod&amp;lt;/code&amp;gt; to change how often you and other clients are gifted money. This can be an alternative to making bots ignore limits that can give a bit more diversity in their choices and behaviours (rich bots will always rush, for example)&lt;br /&gt;
&lt;br /&gt;
==Debugging Graphics==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;cg_draw2D&amp;lt;/code&amp;gt; can allow you to disable 2D drawing. It may be useful if you want to ignore 2D performances from your benchmarks&lt;br /&gt;
&lt;br /&gt;
There probably exist proprietary tools for your platform. For example AMD used to have gDEBugger, and [https://gpuopen.com/archived/gpu-perfstudio/ GPU PerfStudio] proprietary debuggers.&lt;br /&gt;
&lt;br /&gt;
===apitrace===&lt;br /&gt;
&lt;br /&gt;
[https://apitrace.github.io/ apitrace] is an open-source tool that records every graphics API call made by an application. After the application has closed, you can step through individual calls to the graphics API, allowing you to&lt;br /&gt;
* see the result exactly as it would appear following each call,&lt;br /&gt;
* see graphs of API usage, and&lt;br /&gt;
* inspect buffers.&lt;br /&gt;
&lt;br /&gt;
Linux users can install it from their package manager, for example:&lt;br /&gt;
&lt;br /&gt;
 sudo apt install apitrace-tracers apitrace-gui&lt;br /&gt;
&lt;br /&gt;
Windows users can [http://people.freedesktop.org/~jrfonseca/apitrace/ download a build].&lt;br /&gt;
&lt;br /&gt;
==General Tips==&lt;br /&gt;
&lt;br /&gt;
===Miscellaneous===&lt;br /&gt;
&lt;br /&gt;
* To stress test the engine's ability to display a large number of buildables, set &amp;lt;code&amp;gt;g_humanBuildPoints&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;g_alienBuildPoints&amp;lt;/code&amp;gt;  to as high as you wish; this will allow you to build as much as you please.&lt;br /&gt;
* To determine what file was loaded for a particular asset (e.g., to determine if files are being read from a particular &amp;lt;code&amp;gt;.pk3&amp;lt;/code&amp;gt; archive), use the &amp;lt;code&amp;gt;\which&amp;lt;/code&amp;gt; command with the relative path to the asset as an argument, such as &amp;lt;code&amp;gt;\which&amp;amp;nbsp;models/buildables/acid_tube/acid_tube.md5mesh&amp;lt;/code&amp;gt;. Note that &amp;lt;code&amp;gt;which&amp;lt;/code&amp;gt; accepts both forward- and backslashes regardless of platform.&lt;br /&gt;
&lt;br /&gt;
===Working with packages===&lt;br /&gt;
&lt;br /&gt;
To combine all packages together, at a Bash shell:&lt;br /&gt;
&lt;br /&gt;
 $ cd [[Game locations|&amp;lt;var&amp;gt;data directory&amp;lt;/var&amp;gt;]]/pkg; mkdir tmp; for pk3 in pak{{0..9},A}.pk3; do unzip -o $pk3 -d tmp; done&lt;br /&gt;
&lt;br /&gt;
(If there are additional &amp;lt;code&amp;gt;pak*&amp;lt;/code&amp;gt; files (e.g., &amp;lt;code&amp;gt;pakB.pk3&amp;lt;/code&amp;gt;), edit the pattern accordingly (e.g., to &amp;lt;code&amp;gt;pak{{0..9},{A..B}}.pk3&amp;lt;/code&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
This will place the cumulative contents (i.e., as the engine would see them) of all the &amp;lt;code&amp;gt;pak*.pk3&amp;lt;/code&amp;gt; archives into a new &amp;lt;code&amp;gt;tmp/&amp;lt;/code&amp;gt; directory in your data directory.&lt;br /&gt;
&lt;br /&gt;
==Viewing Runtime Information==&lt;br /&gt;
&lt;br /&gt;
The engine and game logic provide a number of commands for viewing information about its current state.&lt;br /&gt;
&lt;br /&gt;
===Common Engine Functionality===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;developer&amp;lt;/code&amp;gt; &amp;amp;mdash; Set this to a true value (e.g., &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) to enable displaying debugging information and the like.&lt;br /&gt;
* &amp;lt;code&amp;gt;fs_debug&amp;lt;/code&amp;gt; &amp;amp;mdash; Set this to a true value (e.g., &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) to enable filesystem debugging.&lt;br /&gt;
* &amp;lt;code&amp;gt;meminfo&amp;lt;/code&amp;gt; &amp;amp;mdash; Display current memory usage.&lt;br /&gt;
* &amp;lt;code&amp;gt;fs_referencedList&amp;lt;/code&amp;gt; &amp;amp;mdash; &lt;br /&gt;
* &amp;lt;code&amp;gt;fs_openedList&amp;lt;/code&amp;gt; &amp;amp;mdash; List currently open files.&lt;br /&gt;
&lt;br /&gt;
===Renderer===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;fbolist&amp;lt;/code&amp;gt; &amp;amp;mdash; List all frame buffer objects.&lt;br /&gt;
* &amp;lt;code&amp;gt;vbolist&amp;lt;/code&amp;gt; &amp;amp;mdash; List all vertex buffer objects.&lt;br /&gt;
&lt;br /&gt;
===Gamelogic===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;entityList&amp;lt;/code&amp;gt; &amp;amp;mdash; &lt;br /&gt;
&amp;lt;!-- others that I don't know what they do:&lt;br /&gt;
* &amp;lt;code&amp;gt;sectorlist&amp;lt;/code&amp;gt; &amp;amp;mdash; &lt;br /&gt;
* &amp;lt;code&amp;gt;flaglist&amp;lt;/code&amp;gt; &amp;amp;mdash; &lt;br /&gt;
* &amp;lt;code&amp;gt;s_list&amp;lt;/code&amp;gt; &amp;amp;mdash; &lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Testing materials and textures==&lt;br /&gt;
&lt;br /&gt;
See {{Subpage|Materials}}.&lt;br /&gt;
&lt;br /&gt;
==Testing maps==&lt;br /&gt;
&lt;br /&gt;
See {{Subpage|Maps}}.&lt;br /&gt;
&lt;br /&gt;
==Testing models==&lt;br /&gt;
&lt;br /&gt;
See {{Subpage|Models}}.&lt;br /&gt;
&lt;br /&gt;
==Reporting bugs==&lt;br /&gt;
&lt;br /&gt;
Please see the [[Bug_reporting|bug reporting]] page.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Static_Analysis&amp;diff=8037</id>
		<title>Static Analysis</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Static_Analysis&amp;diff=8037"/>
		<updated>2022-11-06T09:08:01Z</updated>

		<summary type="html">&lt;p&gt;Afontain: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{OutOfDate}}&lt;br /&gt;
&lt;br /&gt;
==What is static analysis?==&lt;br /&gt;
&lt;br /&gt;
Static code analysis is a technique to identify potential faults and vulnerabilities in software without actually running the code. Static analysis software will examine the code itself to identify possible problem locations, then work backwards to identify how those could be reached. John Carmack, founder of id Software, has written an article [http://www.altdevblogaday.com/2011/12/24/static-code-analysis/ detailing the benefits of the technique].&lt;br /&gt;
&lt;br /&gt;
==Xcode==&lt;br /&gt;
&lt;br /&gt;
To use Xcode 4 to perform static analysis of the code, first follow the [[Compiling_the_source#Mac_OS_X|Xcode compilation instructions]], then in Xcode, select &amp;quot;Analyze&amp;quot;. The process will take considerably longer than just compiling the source, so be patient.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Static_Analysis&amp;diff=8036</id>
		<title>Static Analysis</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Static_Analysis&amp;diff=8036"/>
		<updated>2022-11-06T09:07:47Z</updated>

		<summary type="html">&lt;p&gt;Afontain: Move text that was on the Testing page (https://wiki.unvanquished.net/index.php?title=Testing)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{OutOfDate}}&lt;br /&gt;
=Static Analysis=&lt;br /&gt;
&lt;br /&gt;
==What is static analysis?==&lt;br /&gt;
&lt;br /&gt;
Static code analysis is a technique to identify potential faults and vulnerabilities in software without actually running the code. Static analysis software will examine the code itself to identify possible problem locations, then work backwards to identify how those could be reached. John Carmack, founder of id Software, has written an article [http://www.altdevblogaday.com/2011/12/24/static-code-analysis/ detailing the benefits of the technique].&lt;br /&gt;
&lt;br /&gt;
==Xcode==&lt;br /&gt;
&lt;br /&gt;
To use Xcode 4 to perform static analysis of the code, first follow the [[Compiling_the_source#Mac_OS_X|Xcode compilation instructions]], then in Xcode, select &amp;quot;Analyze&amp;quot;. The process will take considerably longer than just compiling the source, so be patient.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Formats/Behavior_tree&amp;diff=7942</id>
		<title>Formats/Behavior tree</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Formats/Behavior_tree&amp;diff=7942"/>
		<updated>2022-09-03T13:41:08Z</updated>

		<summary type="html">&lt;p&gt;Afontain: /* List of functions (as of 0.52) */ update to 0.53.1&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Formats]]&lt;br /&gt;
[[Category:Bots]]&lt;br /&gt;
Behavior trees file format is game-specific (mods may modify it).&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
Bot behaviors are decided individually, at each &amp;quot;frame&amp;quot; (read: server's main loop passage), starting from a root node (I am not sure when exactly evaluation ends). An overview can be found in the [https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control) Wikipedia article].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Syntax Reference =&lt;br /&gt;
&lt;br /&gt;
Behavior trees use a specific syntax, which obey following rules (guessed from actual implementation and some C++ readings):&lt;br /&gt;
&lt;br /&gt;
* Each node or leaf returns either &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;.&lt;br /&gt;
* at most one node, leaf, block start or block end per line&lt;br /&gt;
* empty lines are accepted&lt;br /&gt;
* comments can either:&lt;br /&gt;
:* start with &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and go to the end of line&lt;br /&gt;
:* start with &amp;lt;code&amp;gt;/*&amp;lt;/code&amp;gt; and go to next &amp;lt;code&amp;gt;*/&amp;lt;/code&amp;gt;, including out of current line (TODO: verify).&lt;br /&gt;
* comments can not be nested&lt;br /&gt;
* actions and conditions taking parameters must enclose those withing parentheses, separated with commas (i.e. &amp;lt;code&amp;gt;roamInRadius( E_H_REACTOR, 500 )&amp;lt;/code&amp;gt;)&lt;br /&gt;
* if an action or a condition does not need parameters, parentheses are optional&lt;br /&gt;
* spaces and tabulations are meaningless&lt;br /&gt;
* strings start and end with a double quote &amp;lt;code&amp;gt;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
* keywords are reserved (TODO: verify, but even if wrong, better avoid their use)&lt;br /&gt;
* values can't be stored or modified (additions, subtractions, multiplications, etc)&lt;br /&gt;
* no user-defined function (but files can be included, and C++ functions can be written in the game logic and be used in the behavior tree)&lt;br /&gt;
* each possible path should (TODO: verify, even if I fail to understand why one would break that willingly) end by one or more action&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
It is not possible to do mathematical operations such as additions, multiplications, divisions, ...&lt;br /&gt;
&lt;br /&gt;
== Keywords ==&lt;br /&gt;
&lt;br /&gt;
There are several keywords:&lt;br /&gt;
&lt;br /&gt;
* behavior&lt;br /&gt;
* action&lt;br /&gt;
* sequence&lt;br /&gt;
* selector&lt;br /&gt;
* fallback&lt;br /&gt;
* concurrent&lt;br /&gt;
* decorator&lt;br /&gt;
* condition&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;behavior&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 behavior NAME&lt;br /&gt;
&lt;br /&gt;
Include named behavior at current place.&lt;br /&gt;
It is unsure if this is just an inclusion of if the subtree is parsed and stored individually.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;action&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 action NAME&lt;br /&gt;
&lt;br /&gt;
 action NAME()&lt;br /&gt;
&lt;br /&gt;
 action NAME( param )&lt;br /&gt;
&lt;br /&gt;
 action NAME( param1, param2, ..., paramN )&lt;br /&gt;
&lt;br /&gt;
Leaves of the tree, they trigger an action from the bot.&lt;br /&gt;
&lt;br /&gt;
=== List of actions ===&lt;br /&gt;
&lt;br /&gt;
Titles provide a link to more detailed pages.&lt;br /&gt;
TODO: have something more time-resilient (one page per call, with it's changelog, maybe?)&lt;br /&gt;
&lt;br /&gt;
==== 0.53.1 ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* activateUpgrade&lt;br /&gt;
* aimAtGoal&lt;br /&gt;
* alternateStrafe&lt;br /&gt;
* buy&lt;br /&gt;
* changeGoal&lt;br /&gt;
* classDodge&lt;br /&gt;
* deactivateUpgrade&lt;br /&gt;
* equip&lt;br /&gt;
* evolve&lt;br /&gt;
* evolveTo&lt;br /&gt;
* fight&lt;br /&gt;
* fireWeapon&lt;br /&gt;
* flee&lt;br /&gt;
* gesture&lt;br /&gt;
* heal&lt;br /&gt;
* jump&lt;br /&gt;
* moveInDir&lt;br /&gt;
* moveTo&lt;br /&gt;
* moveToGoal&lt;br /&gt;
* repair&lt;br /&gt;
* resetStuckTime&lt;br /&gt;
* roam&lt;br /&gt;
* roamInRadius&lt;br /&gt;
* rush&lt;br /&gt;
* say&lt;br /&gt;
* strafeDodge&lt;br /&gt;
* suicide&lt;br /&gt;
* teleport&lt;br /&gt;
&lt;br /&gt;
=== Creating new actions ===&lt;br /&gt;
&lt;br /&gt;
Actions are exported in the &amp;lt;code&amp;gt;AIActionMap_s AIActions[]&amp;lt;/code&amp;gt; C array.&lt;br /&gt;
Actions always return a status.&lt;br /&gt;
Actions can take a variable number of parameters (they have minimum and maximum parameter numbers).&lt;br /&gt;
Parameter types are not described by API.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;concurrent&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 concurrent&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
 	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Concurrent nodes evaluate each children until one returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;.&lt;br /&gt;
Differences with sequence:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt; does not trigger a return&lt;br /&gt;
* Returns either &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt; except if one child failed &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* if 2 tasks were previously in &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt; and the 1st returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;, concurrent returns immediately.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;sequence&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 sequence&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
  	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Sequential nodes evaluate each children one after the other, as long as they return &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;.&lt;br /&gt;
Return last child's status.&lt;br /&gt;
&lt;br /&gt;
Differences with concurrent:&lt;br /&gt;
&lt;br /&gt;
* Sequence breaks if a child returns &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;&lt;br /&gt;
* Starts at last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;, if any&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;selector&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 selector&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
 	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Selector nodes evaluate each children one after the other, as long as they return &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;.&lt;br /&gt;
Return last child's status.&lt;br /&gt;
Does not restart from last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;fallback&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 fallback&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
  	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Fallback nodes start by evaluating the first children, and switch to the next one if a child returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;. It will continue from the last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt; child.&lt;br /&gt;
Return last child's status.&lt;br /&gt;
&lt;br /&gt;
Difference with sequence:&lt;br /&gt;
&lt;br /&gt;
* Sequence switch to the next child on &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;, while fallback switch to the next child on code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Difference with selector:&lt;br /&gt;
* Starts at last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;, if any&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;decorator&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 decorator TYPE( VALUE )&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
 	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Decorator nodes alters their children's behavior.&lt;br /&gt;
Decorator types:&lt;br /&gt;
&lt;br /&gt;
* return&lt;br /&gt;
* invert&lt;br /&gt;
* timer&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
Force children nodes to return a specific value&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;invert&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
An &amp;lt;code&amp;gt;invert&amp;lt;/code&amp;gt; node will negate the return value of its node, &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;code&amp;gt; is turned into &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; is turned into &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;STATUS_RUNNINGcode&amp;gt; is unaffected.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;timer&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
On encountering a &amp;lt;code&amp;gt;timer( &amp;lt;i&amp;gt;N&amp;lt;/i&amp;gt; )&amp;lt;/code&amp;gt; node, &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; is immediately returned if the timer's child node has already returned &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; within the last N milliseconds.&lt;br /&gt;
&lt;br /&gt;
The node may run more often than every N milliseconds if it keeps returning success.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;condition&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
  condition EXPRESSION&lt;br /&gt;
&lt;br /&gt;
  condition EXPRESSION&lt;br /&gt;
  {&lt;br /&gt;
  	NODE&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
The first form immediately returns ''EXPRESSION'' as its status: &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt; for true and &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; for false.&lt;br /&gt;
&lt;br /&gt;
The second form returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; if the expression is false, or otherwise the child's status. Note that ''EXPRESSION'' is re-evaluated every frame. If it becomes false at any time during execution of the child node, the child subtree aborts and the condition node returns failure.&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
* only executes a single child.&lt;br /&gt;
* EXPRESSION can include function calls.&lt;br /&gt;
&lt;br /&gt;
== Operators ==&lt;br /&gt;
&lt;br /&gt;
Operators are listed in the &amp;lt;code&amp;gt;AIOpMap_s conditionOps[]&amp;lt;/code&amp;gt; array.&lt;br /&gt;
operators sorted by precedence (1st have higher priority):&lt;br /&gt;
* &amp;quot;!&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;lt;&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;lt;=&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;gt;=&amp;quot;&lt;br /&gt;
* &amp;quot;==&amp;quot;&lt;br /&gt;
* &amp;quot;!=&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;amp;&amp;amp;&amp;quot;&lt;br /&gt;
* &amp;quot;||&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Functions ==&lt;br /&gt;
&lt;br /&gt;
Return value is &amp;quot;boxed&amp;quot; (&amp;lt;code&amp;gt;AIBox&amp;lt;T&amp;gt;()&amp;lt;/code&amp;gt;) in the C++ code.&lt;br /&gt;
Conditions are exported in the &amp;lt;code&amp;gt;AIConditionMap_s conditionFuncs[]&amp;lt;/code&amp;gt; array.&lt;br /&gt;
&lt;br /&gt;
=== List of functions (as of 0.53.1) ===&lt;br /&gt;
&lt;br /&gt;
* alertedToEnemy&lt;br /&gt;
* aliveTime&lt;br /&gt;
* baseRushScore&lt;br /&gt;
* buildingIsDamaged&lt;br /&gt;
* canEvolveTo&lt;br /&gt;
* class&lt;br /&gt;
* cvar&lt;br /&gt;
* directPathTo&lt;br /&gt;
* distanceTo&lt;br /&gt;
* goalBuildingType&lt;br /&gt;
* goalIsDead&lt;br /&gt;
* goalTeam&lt;br /&gt;
* goalType&lt;br /&gt;
* haveUpgrade&lt;br /&gt;
* haveWeapon&lt;br /&gt;
* healScore&lt;br /&gt;
* inAttackRange&lt;br /&gt;
* isVisible&lt;br /&gt;
* matchTime&lt;br /&gt;
* momentum&lt;br /&gt;
* percentAmmo&lt;br /&gt;
* percentHealth&lt;br /&gt;
* random&lt;br /&gt;
* skill&lt;br /&gt;
* stuckTime&lt;br /&gt;
* team&lt;br /&gt;
* teamateHasWeapon&lt;br /&gt;
* weapon&lt;br /&gt;
&lt;br /&gt;
== Pre-defined symbols ==&lt;br /&gt;
&lt;br /&gt;
Some values are pre-defined and usable as action's or function's parameters.&lt;br /&gt;
&lt;br /&gt;
Those are exported by calling a macro named 'D' (yes, I know).&lt;br /&gt;
List of exported symbols:&lt;br /&gt;
&lt;br /&gt;
* human upgrades (including medkit)&lt;br /&gt;
* human weapons (excluding blaster)&lt;br /&gt;
* team names (aliens, humans, and none)&lt;br /&gt;
* alien buildings&lt;br /&gt;
* human buildings&lt;br /&gt;
* &amp;lt;code&amp;gt;E_GOAL&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;E_ENEMY&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;E_DAMAGEDBUILDING&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;E_SELF&amp;lt;/code&amp;gt;&lt;br /&gt;
* classes (human ones, alien ones, and &amp;lt;code&amp;gt;PCL_NONE&amp;lt;/code&amp;gt;)&lt;br /&gt;
* moves (forward, backward, right, left)&lt;br /&gt;
* some say commands (all, team, area, area_team)&lt;br /&gt;
* task/check status names (running, success, failure)&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
&lt;br /&gt;
Parameters needs to be (un)wrapped in C++ before being accessed.&lt;br /&gt;
&lt;br /&gt;
Parameters can be of the following (C) types:&lt;br /&gt;
* float&lt;br /&gt;
* int (probably better assume 32 bit signed integers)&lt;br /&gt;
* string (probably better assume null-terminated)&lt;br /&gt;
* double (Unboxed only)&lt;br /&gt;
* token (Boxed only, either a &amp;lt;code&amp;gt;TT_STRING&amp;lt;/code&amp;gt;, a float or an int...)&lt;br /&gt;
&lt;br /&gt;
To provide a value to an action or check, the C++ code must UnBox (&amp;lt;code&amp;gt;AIUnBox&amp;lt;T&amp;gt;()&amp;lt;/code&amp;gt;) it.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Formats/Behavior_tree&amp;diff=7941</id>
		<title>Formats/Behavior tree</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Formats/Behavior_tree&amp;diff=7941"/>
		<updated>2022-09-03T13:39:53Z</updated>

		<summary type="html">&lt;p&gt;Afontain: /* 0.53.1 */ remove the link to the webpage&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Formats]]&lt;br /&gt;
[[Category:Bots]]&lt;br /&gt;
Behavior trees file format is game-specific (mods may modify it).&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
Bot behaviors are decided individually, at each &amp;quot;frame&amp;quot; (read: server's main loop passage), starting from a root node (I am not sure when exactly evaluation ends). An overview can be found in the [https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control) Wikipedia article].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Syntax Reference =&lt;br /&gt;
&lt;br /&gt;
Behavior trees use a specific syntax, which obey following rules (guessed from actual implementation and some C++ readings):&lt;br /&gt;
&lt;br /&gt;
* Each node or leaf returns either &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;.&lt;br /&gt;
* at most one node, leaf, block start or block end per line&lt;br /&gt;
* empty lines are accepted&lt;br /&gt;
* comments can either:&lt;br /&gt;
:* start with &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and go to the end of line&lt;br /&gt;
:* start with &amp;lt;code&amp;gt;/*&amp;lt;/code&amp;gt; and go to next &amp;lt;code&amp;gt;*/&amp;lt;/code&amp;gt;, including out of current line (TODO: verify).&lt;br /&gt;
* comments can not be nested&lt;br /&gt;
* actions and conditions taking parameters must enclose those withing parentheses, separated with commas (i.e. &amp;lt;code&amp;gt;roamInRadius( E_H_REACTOR, 500 )&amp;lt;/code&amp;gt;)&lt;br /&gt;
* if an action or a condition does not need parameters, parentheses are optional&lt;br /&gt;
* spaces and tabulations are meaningless&lt;br /&gt;
* strings start and end with a double quote &amp;lt;code&amp;gt;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
* keywords are reserved (TODO: verify, but even if wrong, better avoid their use)&lt;br /&gt;
* values can't be stored or modified (additions, subtractions, multiplications, etc)&lt;br /&gt;
* no user-defined function (but files can be included, and C++ functions can be written in the game logic and be used in the behavior tree)&lt;br /&gt;
* each possible path should (TODO: verify, even if I fail to understand why one would break that willingly) end by one or more action&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
It is not possible to do mathematical operations such as additions, multiplications, divisions, ...&lt;br /&gt;
&lt;br /&gt;
== Keywords ==&lt;br /&gt;
&lt;br /&gt;
There are several keywords:&lt;br /&gt;
&lt;br /&gt;
* behavior&lt;br /&gt;
* action&lt;br /&gt;
* sequence&lt;br /&gt;
* selector&lt;br /&gt;
* fallback&lt;br /&gt;
* concurrent&lt;br /&gt;
* decorator&lt;br /&gt;
* condition&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;behavior&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 behavior NAME&lt;br /&gt;
&lt;br /&gt;
Include named behavior at current place.&lt;br /&gt;
It is unsure if this is just an inclusion of if the subtree is parsed and stored individually.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;action&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 action NAME&lt;br /&gt;
&lt;br /&gt;
 action NAME()&lt;br /&gt;
&lt;br /&gt;
 action NAME( param )&lt;br /&gt;
&lt;br /&gt;
 action NAME( param1, param2, ..., paramN )&lt;br /&gt;
&lt;br /&gt;
Leaves of the tree, they trigger an action from the bot.&lt;br /&gt;
&lt;br /&gt;
=== List of actions ===&lt;br /&gt;
&lt;br /&gt;
Titles provide a link to more detailed pages.&lt;br /&gt;
TODO: have something more time-resilient (one page per call, with it's changelog, maybe?)&lt;br /&gt;
&lt;br /&gt;
==== 0.53.1 ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* activateUpgrade&lt;br /&gt;
* aimAtGoal&lt;br /&gt;
* alternateStrafe&lt;br /&gt;
* buy&lt;br /&gt;
* changeGoal&lt;br /&gt;
* classDodge&lt;br /&gt;
* deactivateUpgrade&lt;br /&gt;
* equip&lt;br /&gt;
* evolve&lt;br /&gt;
* evolveTo&lt;br /&gt;
* fight&lt;br /&gt;
* fireWeapon&lt;br /&gt;
* flee&lt;br /&gt;
* gesture&lt;br /&gt;
* heal&lt;br /&gt;
* jump&lt;br /&gt;
* moveInDir&lt;br /&gt;
* moveTo&lt;br /&gt;
* moveToGoal&lt;br /&gt;
* repair&lt;br /&gt;
* resetStuckTime&lt;br /&gt;
* roam&lt;br /&gt;
* roamInRadius&lt;br /&gt;
* rush&lt;br /&gt;
* say&lt;br /&gt;
* strafeDodge&lt;br /&gt;
* suicide&lt;br /&gt;
* teleport&lt;br /&gt;
&lt;br /&gt;
=== Creating new actions ===&lt;br /&gt;
&lt;br /&gt;
Actions are exported in the &amp;lt;code&amp;gt;AIActionMap_s AIActions[]&amp;lt;/code&amp;gt; C array.&lt;br /&gt;
Actions always return a status.&lt;br /&gt;
Actions can take a variable number of parameters (they have minimum and maximum parameter numbers).&lt;br /&gt;
Parameter types are not described by API.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;concurrent&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 concurrent&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
 	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Concurrent nodes evaluate each children until one returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;.&lt;br /&gt;
Differences with sequence:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt; does not trigger a return&lt;br /&gt;
* Returns either &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt; except if one child failed &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* if 2 tasks were previously in &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt; and the 1st returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;, concurrent returns immediately.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;sequence&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 sequence&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
  	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Sequential nodes evaluate each children one after the other, as long as they return &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;.&lt;br /&gt;
Return last child's status.&lt;br /&gt;
&lt;br /&gt;
Differences with concurrent:&lt;br /&gt;
&lt;br /&gt;
* Sequence breaks if a child returns &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;&lt;br /&gt;
* Starts at last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;, if any&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;selector&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 selector&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
 	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Selector nodes evaluate each children one after the other, as long as they return &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;.&lt;br /&gt;
Return last child's status.&lt;br /&gt;
Does not restart from last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;fallback&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 fallback&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
  	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Fallback nodes start by evaluating the first children, and switch to the next one if a child returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;. It will continue from the last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt; child.&lt;br /&gt;
Return last child's status.&lt;br /&gt;
&lt;br /&gt;
Difference with sequence:&lt;br /&gt;
&lt;br /&gt;
* Sequence switch to the next child on &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;, while fallback switch to the next child on code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Difference with selector:&lt;br /&gt;
* Starts at last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;, if any&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;decorator&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 decorator TYPE( VALUE )&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
 	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Decorator nodes alters their children's behavior.&lt;br /&gt;
Decorator types:&lt;br /&gt;
&lt;br /&gt;
* return&lt;br /&gt;
* invert&lt;br /&gt;
* timer&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
Force children nodes to return a specific value&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;invert&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
An &amp;lt;code&amp;gt;invert&amp;lt;/code&amp;gt; node will negate the return value of its node, &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;code&amp;gt; is turned into &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; is turned into &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;STATUS_RUNNINGcode&amp;gt; is unaffected.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;timer&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
On encountering a &amp;lt;code&amp;gt;timer( &amp;lt;i&amp;gt;N&amp;lt;/i&amp;gt; )&amp;lt;/code&amp;gt; node, &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; is immediately returned if the timer's child node has already returned &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; within the last N milliseconds.&lt;br /&gt;
&lt;br /&gt;
The node may run more often than every N milliseconds if it keeps returning success.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;condition&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
  condition EXPRESSION&lt;br /&gt;
&lt;br /&gt;
  condition EXPRESSION&lt;br /&gt;
  {&lt;br /&gt;
  	NODE&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
The first form immediately returns ''EXPRESSION'' as its status: &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt; for true and &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; for false.&lt;br /&gt;
&lt;br /&gt;
The second form returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; if the expression is false, or otherwise the child's status. Note that ''EXPRESSION'' is re-evaluated every frame. If it becomes false at any time during execution of the child node, the child subtree aborts and the condition node returns failure.&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
* only executes a single child.&lt;br /&gt;
* EXPRESSION can include function calls.&lt;br /&gt;
&lt;br /&gt;
== Operators ==&lt;br /&gt;
&lt;br /&gt;
Operators are listed in the &amp;lt;code&amp;gt;AIOpMap_s conditionOps[]&amp;lt;/code&amp;gt; array.&lt;br /&gt;
operators sorted by precedence (1st have higher priority):&lt;br /&gt;
* &amp;quot;!&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;lt;&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;lt;=&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;gt;=&amp;quot;&lt;br /&gt;
* &amp;quot;==&amp;quot;&lt;br /&gt;
* &amp;quot;!=&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;amp;&amp;amp;&amp;quot;&lt;br /&gt;
* &amp;quot;||&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Functions ==&lt;br /&gt;
&lt;br /&gt;
Return value is &amp;quot;boxed&amp;quot; (&amp;lt;code&amp;gt;AIBox&amp;lt;T&amp;gt;()&amp;lt;/code&amp;gt;) in the C++ code.&lt;br /&gt;
Conditions are exported in the &amp;lt;code&amp;gt;AIConditionMap_s conditionFuncs[]&amp;lt;/code&amp;gt; array.&lt;br /&gt;
&lt;br /&gt;
=== List of functions (as of 0.52) ===&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;alienMomentum&amp;quot;,     VALUE_INT,   alienMomentum,     0 }, &lt;br /&gt;
 { &amp;quot;humanMomentum&amp;quot;,     VALUE_INT,   humanMomentum,     0 }, &lt;br /&gt;
 { &amp;quot;alertedToEnemy&amp;quot;,    VALUE_INT,   alertedToEnemy,    0 }, &lt;br /&gt;
 { &amp;quot;baseRushScore&amp;quot;,     VALUE_FLOAT, baseRushScore,     0 }, &lt;br /&gt;
 { &amp;quot;buildingIsDamaged&amp;quot;, VALUE_INT,   buildingIsDamaged, 0 }, &lt;br /&gt;
 { &amp;quot;canEvolveTo&amp;quot;,       VALUE_INT,   botCanEvolveTo,    1 }, &lt;br /&gt;
 { &amp;quot;class&amp;quot;,             VALUE_INT,   botClass,          0 }, &lt;br /&gt;
 { &amp;quot;cvarFloat&amp;quot;,         VALUE_FLOAT, cvarFloat,         1 }, &lt;br /&gt;
 { &amp;quot;cvarInt&amp;quot;,           VALUE_INT,   cvarInt,           1 }, &lt;br /&gt;
 { &amp;quot;directPathTo&amp;quot;,      VALUE_INT,   directPathTo,      1 }, &lt;br /&gt;
 { &amp;quot;distanceTo&amp;quot;,        VALUE_FLOAT, distanceTo,        1 }, &lt;br /&gt;
 { &amp;quot;goalBuildingType&amp;quot;,  VALUE_INT,   goalBuildingType,  0 }, &lt;br /&gt;
 { &amp;quot;goalIsDead&amp;quot;,        VALUE_INT,   goalDead,          0 }, &lt;br /&gt;
 { &amp;quot;goalTeam&amp;quot;,          VALUE_INT,   goalTeam,          0 }, &lt;br /&gt;
 { &amp;quot;goalType&amp;quot;,          VALUE_INT,   goalType,          0 }, &lt;br /&gt;
 { &amp;quot;haveUpgrade&amp;quot;,       VALUE_INT,   haveUpgrade,       1 }, &lt;br /&gt;
 { &amp;quot;haveWeapon&amp;quot;,        VALUE_INT,   haveWeapon,        1 }, &lt;br /&gt;
 { &amp;quot;healScore&amp;quot;,         VALUE_FLOAT, healScore,         0 }, &lt;br /&gt;
 { &amp;quot;inAttackRange&amp;quot;,     VALUE_INT,   inAttackRange,     1 }, &lt;br /&gt;
 { &amp;quot;isVisible&amp;quot;,         VALUE_INT,   isVisible,         1 }, &lt;br /&gt;
 { &amp;quot;percentAmmo&amp;quot;,       VALUE_FLOAT, percentAmmo,       0 }, &lt;br /&gt;
 { &amp;quot;percentHealth&amp;quot;,     VALUE_FLOAT, percentHealth,     1 }, &lt;br /&gt;
 { &amp;quot;random&amp;quot;,            VALUE_FLOAT, randomChance,      0 }, &lt;br /&gt;
 { &amp;quot;skill&amp;quot;,             VALUE_INT,   botSkill,          0 }, &lt;br /&gt;
 { &amp;quot;stuckTime&amp;quot;,         VALUE_INT,   stuckTime,         0 }, &lt;br /&gt;
 { &amp;quot;team&amp;quot;,              VALUE_INT,   botTeam,           0 }, &lt;br /&gt;
 { &amp;quot;teamateHasWeapon&amp;quot;,  VALUE_INT,   teamateHasWeapon,  1 }, &lt;br /&gt;
 { &amp;quot;weapon&amp;quot;,            VALUE_INT,   currentWeapon,     0 },&lt;br /&gt;
&lt;br /&gt;
== Pre-defined symbols ==&lt;br /&gt;
&lt;br /&gt;
Some values are pre-defined and usable as action's or function's parameters.&lt;br /&gt;
&lt;br /&gt;
Those are exported by calling a macro named 'D' (yes, I know).&lt;br /&gt;
List of exported symbols:&lt;br /&gt;
&lt;br /&gt;
* human upgrades (including medkit)&lt;br /&gt;
* human weapons (excluding blaster)&lt;br /&gt;
* team names (aliens, humans, and none)&lt;br /&gt;
* alien buildings&lt;br /&gt;
* human buildings&lt;br /&gt;
* &amp;lt;code&amp;gt;E_GOAL&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;E_ENEMY&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;E_DAMAGEDBUILDING&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;E_SELF&amp;lt;/code&amp;gt;&lt;br /&gt;
* classes (human ones, alien ones, and &amp;lt;code&amp;gt;PCL_NONE&amp;lt;/code&amp;gt;)&lt;br /&gt;
* moves (forward, backward, right, left)&lt;br /&gt;
* some say commands (all, team, area, area_team)&lt;br /&gt;
* task/check status names (running, success, failure)&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
&lt;br /&gt;
Parameters needs to be (un)wrapped in C++ before being accessed.&lt;br /&gt;
&lt;br /&gt;
Parameters can be of the following (C) types:&lt;br /&gt;
* float&lt;br /&gt;
* int (probably better assume 32 bit signed integers)&lt;br /&gt;
* string (probably better assume null-terminated)&lt;br /&gt;
* double (Unboxed only)&lt;br /&gt;
* token (Boxed only, either a &amp;lt;code&amp;gt;TT_STRING&amp;lt;/code&amp;gt;, a float or an int...)&lt;br /&gt;
&lt;br /&gt;
To provide a value to an action or check, the C++ code must UnBox (&amp;lt;code&amp;gt;AIUnBox&amp;lt;T&amp;gt;()&amp;lt;/code&amp;gt;) it.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Formats/Behavior_tree&amp;diff=7940</id>
		<title>Formats/Behavior tree</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Formats/Behavior_tree&amp;diff=7940"/>
		<updated>2022-09-03T13:38:51Z</updated>

		<summary type="html">&lt;p&gt;Afontain: update action list&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Formats]]&lt;br /&gt;
[[Category:Bots]]&lt;br /&gt;
Behavior trees file format is game-specific (mods may modify it).&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
Bot behaviors are decided individually, at each &amp;quot;frame&amp;quot; (read: server's main loop passage), starting from a root node (I am not sure when exactly evaluation ends). An overview can be found in the [https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control) Wikipedia article].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Syntax Reference =&lt;br /&gt;
&lt;br /&gt;
Behavior trees use a specific syntax, which obey following rules (guessed from actual implementation and some C++ readings):&lt;br /&gt;
&lt;br /&gt;
* Each node or leaf returns either &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;.&lt;br /&gt;
* at most one node, leaf, block start or block end per line&lt;br /&gt;
* empty lines are accepted&lt;br /&gt;
* comments can either:&lt;br /&gt;
:* start with &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and go to the end of line&lt;br /&gt;
:* start with &amp;lt;code&amp;gt;/*&amp;lt;/code&amp;gt; and go to next &amp;lt;code&amp;gt;*/&amp;lt;/code&amp;gt;, including out of current line (TODO: verify).&lt;br /&gt;
* comments can not be nested&lt;br /&gt;
* actions and conditions taking parameters must enclose those withing parentheses, separated with commas (i.e. &amp;lt;code&amp;gt;roamInRadius( E_H_REACTOR, 500 )&amp;lt;/code&amp;gt;)&lt;br /&gt;
* if an action or a condition does not need parameters, parentheses are optional&lt;br /&gt;
* spaces and tabulations are meaningless&lt;br /&gt;
* strings start and end with a double quote &amp;lt;code&amp;gt;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
* keywords are reserved (TODO: verify, but even if wrong, better avoid their use)&lt;br /&gt;
* values can't be stored or modified (additions, subtractions, multiplications, etc)&lt;br /&gt;
* no user-defined function (but files can be included, and C++ functions can be written in the game logic and be used in the behavior tree)&lt;br /&gt;
* each possible path should (TODO: verify, even if I fail to understand why one would break that willingly) end by one or more action&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
It is not possible to do mathematical operations such as additions, multiplications, divisions, ...&lt;br /&gt;
&lt;br /&gt;
== Keywords ==&lt;br /&gt;
&lt;br /&gt;
There are several keywords:&lt;br /&gt;
&lt;br /&gt;
* behavior&lt;br /&gt;
* action&lt;br /&gt;
* sequence&lt;br /&gt;
* selector&lt;br /&gt;
* fallback&lt;br /&gt;
* concurrent&lt;br /&gt;
* decorator&lt;br /&gt;
* condition&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;behavior&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 behavior NAME&lt;br /&gt;
&lt;br /&gt;
Include named behavior at current place.&lt;br /&gt;
It is unsure if this is just an inclusion of if the subtree is parsed and stored individually.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;action&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 action NAME&lt;br /&gt;
&lt;br /&gt;
 action NAME()&lt;br /&gt;
&lt;br /&gt;
 action NAME( param )&lt;br /&gt;
&lt;br /&gt;
 action NAME( param1, param2, ..., paramN )&lt;br /&gt;
&lt;br /&gt;
Leaves of the tree, they trigger an action from the bot.&lt;br /&gt;
&lt;br /&gt;
=== List of actions ===&lt;br /&gt;
&lt;br /&gt;
Titles provide a link to more detailed pages.&lt;br /&gt;
TODO: have something more time-resilient (one page per call, with it's changelog, maybe?)&lt;br /&gt;
&lt;br /&gt;
==== [[0.53.1]] ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* activateUpgrade&lt;br /&gt;
* aimAtGoal&lt;br /&gt;
* alternateStrafe&lt;br /&gt;
* buy&lt;br /&gt;
* changeGoal&lt;br /&gt;
* classDodge&lt;br /&gt;
* deactivateUpgrade&lt;br /&gt;
* equip&lt;br /&gt;
* evolve&lt;br /&gt;
* evolveTo&lt;br /&gt;
* fight&lt;br /&gt;
* fireWeapon&lt;br /&gt;
* flee&lt;br /&gt;
* gesture&lt;br /&gt;
* heal&lt;br /&gt;
* jump&lt;br /&gt;
* moveInDir&lt;br /&gt;
* moveTo&lt;br /&gt;
* moveToGoal&lt;br /&gt;
* repair&lt;br /&gt;
* resetStuckTime&lt;br /&gt;
* roam&lt;br /&gt;
* roamInRadius&lt;br /&gt;
* rush&lt;br /&gt;
* say&lt;br /&gt;
* strafeDodge&lt;br /&gt;
* suicide&lt;br /&gt;
* teleport&lt;br /&gt;
&lt;br /&gt;
=== Creating new actions ===&lt;br /&gt;
&lt;br /&gt;
Actions are exported in the &amp;lt;code&amp;gt;AIActionMap_s AIActions[]&amp;lt;/code&amp;gt; C array.&lt;br /&gt;
Actions always return a status.&lt;br /&gt;
Actions can take a variable number of parameters (they have minimum and maximum parameter numbers).&lt;br /&gt;
Parameter types are not described by API.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;concurrent&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 concurrent&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
 	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Concurrent nodes evaluate each children until one returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;.&lt;br /&gt;
Differences with sequence:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt; does not trigger a return&lt;br /&gt;
* Returns either &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt; except if one child failed &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* if 2 tasks were previously in &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt; and the 1st returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;, concurrent returns immediately.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;sequence&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 sequence&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
  	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Sequential nodes evaluate each children one after the other, as long as they return &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;.&lt;br /&gt;
Return last child's status.&lt;br /&gt;
&lt;br /&gt;
Differences with concurrent:&lt;br /&gt;
&lt;br /&gt;
* Sequence breaks if a child returns &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;&lt;br /&gt;
* Starts at last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;, if any&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;selector&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 selector&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
 	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Selector nodes evaluate each children one after the other, as long as they return &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;.&lt;br /&gt;
Return last child's status.&lt;br /&gt;
Does not restart from last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;fallback&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 fallback&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
  	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Fallback nodes start by evaluating the first children, and switch to the next one if a child returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;. It will continue from the last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt; child.&lt;br /&gt;
Return last child's status.&lt;br /&gt;
&lt;br /&gt;
Difference with sequence:&lt;br /&gt;
&lt;br /&gt;
* Sequence switch to the next child on &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;, while fallback switch to the next child on code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Difference with selector:&lt;br /&gt;
* Starts at last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;, if any&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;decorator&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 decorator TYPE( VALUE )&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
 	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Decorator nodes alters their children's behavior.&lt;br /&gt;
Decorator types:&lt;br /&gt;
&lt;br /&gt;
* return&lt;br /&gt;
* invert&lt;br /&gt;
* timer&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
Force children nodes to return a specific value&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;invert&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
An &amp;lt;code&amp;gt;invert&amp;lt;/code&amp;gt; node will negate the return value of its node, &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;code&amp;gt; is turned into &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; is turned into &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;STATUS_RUNNINGcode&amp;gt; is unaffected.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;timer&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
On encountering a &amp;lt;code&amp;gt;timer( &amp;lt;i&amp;gt;N&amp;lt;/i&amp;gt; )&amp;lt;/code&amp;gt; node, &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; is immediately returned if the timer's child node has already returned &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; within the last N milliseconds.&lt;br /&gt;
&lt;br /&gt;
The node may run more often than every N milliseconds if it keeps returning success.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;condition&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
  condition EXPRESSION&lt;br /&gt;
&lt;br /&gt;
  condition EXPRESSION&lt;br /&gt;
  {&lt;br /&gt;
  	NODE&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
The first form immediately returns ''EXPRESSION'' as its status: &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt; for true and &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; for false.&lt;br /&gt;
&lt;br /&gt;
The second form returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; if the expression is false, or otherwise the child's status. Note that ''EXPRESSION'' is re-evaluated every frame. If it becomes false at any time during execution of the child node, the child subtree aborts and the condition node returns failure.&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
* only executes a single child.&lt;br /&gt;
* EXPRESSION can include function calls.&lt;br /&gt;
&lt;br /&gt;
== Operators ==&lt;br /&gt;
&lt;br /&gt;
Operators are listed in the &amp;lt;code&amp;gt;AIOpMap_s conditionOps[]&amp;lt;/code&amp;gt; array.&lt;br /&gt;
operators sorted by precedence (1st have higher priority):&lt;br /&gt;
* &amp;quot;!&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;lt;&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;lt;=&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;gt;=&amp;quot;&lt;br /&gt;
* &amp;quot;==&amp;quot;&lt;br /&gt;
* &amp;quot;!=&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;amp;&amp;amp;&amp;quot;&lt;br /&gt;
* &amp;quot;||&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Functions ==&lt;br /&gt;
&lt;br /&gt;
Return value is &amp;quot;boxed&amp;quot; (&amp;lt;code&amp;gt;AIBox&amp;lt;T&amp;gt;()&amp;lt;/code&amp;gt;) in the C++ code.&lt;br /&gt;
Conditions are exported in the &amp;lt;code&amp;gt;AIConditionMap_s conditionFuncs[]&amp;lt;/code&amp;gt; array.&lt;br /&gt;
&lt;br /&gt;
=== List of functions (as of 0.52) ===&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;alienMomentum&amp;quot;,     VALUE_INT,   alienMomentum,     0 }, &lt;br /&gt;
 { &amp;quot;humanMomentum&amp;quot;,     VALUE_INT,   humanMomentum,     0 }, &lt;br /&gt;
 { &amp;quot;alertedToEnemy&amp;quot;,    VALUE_INT,   alertedToEnemy,    0 }, &lt;br /&gt;
 { &amp;quot;baseRushScore&amp;quot;,     VALUE_FLOAT, baseRushScore,     0 }, &lt;br /&gt;
 { &amp;quot;buildingIsDamaged&amp;quot;, VALUE_INT,   buildingIsDamaged, 0 }, &lt;br /&gt;
 { &amp;quot;canEvolveTo&amp;quot;,       VALUE_INT,   botCanEvolveTo,    1 }, &lt;br /&gt;
 { &amp;quot;class&amp;quot;,             VALUE_INT,   botClass,          0 }, &lt;br /&gt;
 { &amp;quot;cvarFloat&amp;quot;,         VALUE_FLOAT, cvarFloat,         1 }, &lt;br /&gt;
 { &amp;quot;cvarInt&amp;quot;,           VALUE_INT,   cvarInt,           1 }, &lt;br /&gt;
 { &amp;quot;directPathTo&amp;quot;,      VALUE_INT,   directPathTo,      1 }, &lt;br /&gt;
 { &amp;quot;distanceTo&amp;quot;,        VALUE_FLOAT, distanceTo,        1 }, &lt;br /&gt;
 { &amp;quot;goalBuildingType&amp;quot;,  VALUE_INT,   goalBuildingType,  0 }, &lt;br /&gt;
 { &amp;quot;goalIsDead&amp;quot;,        VALUE_INT,   goalDead,          0 }, &lt;br /&gt;
 { &amp;quot;goalTeam&amp;quot;,          VALUE_INT,   goalTeam,          0 }, &lt;br /&gt;
 { &amp;quot;goalType&amp;quot;,          VALUE_INT,   goalType,          0 }, &lt;br /&gt;
 { &amp;quot;haveUpgrade&amp;quot;,       VALUE_INT,   haveUpgrade,       1 }, &lt;br /&gt;
 { &amp;quot;haveWeapon&amp;quot;,        VALUE_INT,   haveWeapon,        1 }, &lt;br /&gt;
 { &amp;quot;healScore&amp;quot;,         VALUE_FLOAT, healScore,         0 }, &lt;br /&gt;
 { &amp;quot;inAttackRange&amp;quot;,     VALUE_INT,   inAttackRange,     1 }, &lt;br /&gt;
 { &amp;quot;isVisible&amp;quot;,         VALUE_INT,   isVisible,         1 }, &lt;br /&gt;
 { &amp;quot;percentAmmo&amp;quot;,       VALUE_FLOAT, percentAmmo,       0 }, &lt;br /&gt;
 { &amp;quot;percentHealth&amp;quot;,     VALUE_FLOAT, percentHealth,     1 }, &lt;br /&gt;
 { &amp;quot;random&amp;quot;,            VALUE_FLOAT, randomChance,      0 }, &lt;br /&gt;
 { &amp;quot;skill&amp;quot;,             VALUE_INT,   botSkill,          0 }, &lt;br /&gt;
 { &amp;quot;stuckTime&amp;quot;,         VALUE_INT,   stuckTime,         0 }, &lt;br /&gt;
 { &amp;quot;team&amp;quot;,              VALUE_INT,   botTeam,           0 }, &lt;br /&gt;
 { &amp;quot;teamateHasWeapon&amp;quot;,  VALUE_INT,   teamateHasWeapon,  1 }, &lt;br /&gt;
 { &amp;quot;weapon&amp;quot;,            VALUE_INT,   currentWeapon,     0 },&lt;br /&gt;
&lt;br /&gt;
== Pre-defined symbols ==&lt;br /&gt;
&lt;br /&gt;
Some values are pre-defined and usable as action's or function's parameters.&lt;br /&gt;
&lt;br /&gt;
Those are exported by calling a macro named 'D' (yes, I know).&lt;br /&gt;
List of exported symbols:&lt;br /&gt;
&lt;br /&gt;
* human upgrades (including medkit)&lt;br /&gt;
* human weapons (excluding blaster)&lt;br /&gt;
* team names (aliens, humans, and none)&lt;br /&gt;
* alien buildings&lt;br /&gt;
* human buildings&lt;br /&gt;
* &amp;lt;code&amp;gt;E_GOAL&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;E_ENEMY&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;E_DAMAGEDBUILDING&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;E_SELF&amp;lt;/code&amp;gt;&lt;br /&gt;
* classes (human ones, alien ones, and &amp;lt;code&amp;gt;PCL_NONE&amp;lt;/code&amp;gt;)&lt;br /&gt;
* moves (forward, backward, right, left)&lt;br /&gt;
* some say commands (all, team, area, area_team)&lt;br /&gt;
* task/check status names (running, success, failure)&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
&lt;br /&gt;
Parameters needs to be (un)wrapped in C++ before being accessed.&lt;br /&gt;
&lt;br /&gt;
Parameters can be of the following (C) types:&lt;br /&gt;
* float&lt;br /&gt;
* int (probably better assume 32 bit signed integers)&lt;br /&gt;
* string (probably better assume null-terminated)&lt;br /&gt;
* double (Unboxed only)&lt;br /&gt;
* token (Boxed only, either a &amp;lt;code&amp;gt;TT_STRING&amp;lt;/code&amp;gt;, a float or an int...)&lt;br /&gt;
&lt;br /&gt;
To provide a value to an action or check, the C++ code must UnBox (&amp;lt;code&amp;gt;AIUnBox&amp;lt;T&amp;gt;()&amp;lt;/code&amp;gt;) it.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Formats/Behavior_tree&amp;diff=7939</id>
		<title>Formats/Behavior tree</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Formats/Behavior_tree&amp;diff=7939"/>
		<updated>2022-09-02T23:28:57Z</updated>

		<summary type="html">&lt;p&gt;Afontain: Add &amp;quot;invert&amp;quot; decorator documentation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Formats]]&lt;br /&gt;
[[Category:Bots]]&lt;br /&gt;
Behavior trees file format is game-specific (mods may modify it).&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
Bot behaviors are decided individually, at each &amp;quot;frame&amp;quot; (read: server's main loop passage), starting from a root node (I am not sure when exactly evaluation ends). An overview can be found in the [https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control) Wikipedia article].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Syntax Reference =&lt;br /&gt;
&lt;br /&gt;
Behavior trees use a specific syntax, which obey following rules (guessed from actual implementation and some C++ readings):&lt;br /&gt;
&lt;br /&gt;
* Each node or leaf returns either &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;.&lt;br /&gt;
* at most one node, leaf, block start or block end per line&lt;br /&gt;
* empty lines are accepted&lt;br /&gt;
* comments can either:&lt;br /&gt;
:* start with &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and go to the end of line&lt;br /&gt;
:* start with &amp;lt;code&amp;gt;/*&amp;lt;/code&amp;gt; and go to next &amp;lt;code&amp;gt;*/&amp;lt;/code&amp;gt;, including out of current line (TODO: verify).&lt;br /&gt;
* comments can not be nested&lt;br /&gt;
* actions and conditions taking parameters must enclose those withing parentheses, separated with commas (i.e. &amp;lt;code&amp;gt;roamInRadius( E_H_REACTOR, 500 )&amp;lt;/code&amp;gt;)&lt;br /&gt;
* if an action or a condition does not need parameters, parentheses are optional&lt;br /&gt;
* spaces and tabulations are meaningless&lt;br /&gt;
* strings start and end with a double quote &amp;lt;code&amp;gt;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
* keywords are reserved (TODO: verify, but even if wrong, better avoid their use)&lt;br /&gt;
* values can't be stored or modified (additions, subtractions, multiplications, etc)&lt;br /&gt;
* no user-defined function (but files can be included, and C++ functions can be written in the game logic and be used in the behavior tree)&lt;br /&gt;
* each possible path should (TODO: verify, even if I fail to understand why one would break that willingly) end by one or more action&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
It is not possible to do mathematical operations such as additions, multiplications, divisions, ...&lt;br /&gt;
&lt;br /&gt;
== Keywords ==&lt;br /&gt;
&lt;br /&gt;
There are several keywords:&lt;br /&gt;
&lt;br /&gt;
* behavior&lt;br /&gt;
* action&lt;br /&gt;
* sequence&lt;br /&gt;
* selector&lt;br /&gt;
* fallback&lt;br /&gt;
* concurrent&lt;br /&gt;
* decorator&lt;br /&gt;
* condition&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;behavior&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 behavior NAME&lt;br /&gt;
&lt;br /&gt;
Include named behavior at current place.&lt;br /&gt;
It is unsure if this is just an inclusion of if the subtree is parsed and stored individually.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;action&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 action NAME&lt;br /&gt;
&lt;br /&gt;
 action NAME()&lt;br /&gt;
&lt;br /&gt;
 action NAME( param )&lt;br /&gt;
&lt;br /&gt;
 action NAME( param1, param2, ..., paramN )&lt;br /&gt;
&lt;br /&gt;
Leaves of the tree, they trigger an action from the bot.&lt;br /&gt;
&lt;br /&gt;
=== List of actions ===&lt;br /&gt;
&lt;br /&gt;
Titles provide a link to more detailed pages.&lt;br /&gt;
TODO: have something more time-resilient (one page per call, with it's changelog, maybe?)&lt;br /&gt;
&lt;br /&gt;
==== [[0.52]] ====&lt;br /&gt;
&lt;br /&gt;
* activateUpgrade&lt;br /&gt;
* aimAtGoal&lt;br /&gt;
* alternateStrafe&lt;br /&gt;
* buy&lt;br /&gt;
* changeGoal&lt;br /&gt;
* classDodge&lt;br /&gt;
* deactivateUpgrade&lt;br /&gt;
* equip&lt;br /&gt;
* evolve&lt;br /&gt;
* evolveTo&lt;br /&gt;
* fight&lt;br /&gt;
* fireWeapon&lt;br /&gt;
* flee&lt;br /&gt;
* heal&lt;br /&gt;
* jump&lt;br /&gt;
* moveInDir&lt;br /&gt;
* moveTo&lt;br /&gt;
* moveToGoal&lt;br /&gt;
* repair&lt;br /&gt;
* resetStuckTime&lt;br /&gt;
* roam&lt;br /&gt;
* roamInRadius&lt;br /&gt;
* rush&lt;br /&gt;
* say&lt;br /&gt;
* strafeDodge&lt;br /&gt;
* suicide&lt;br /&gt;
&lt;br /&gt;
=== Creating new actions ===&lt;br /&gt;
&lt;br /&gt;
Actions are exported in the &amp;lt;code&amp;gt;AIActionMap_s AIActions[]&amp;lt;/code&amp;gt; C array.&lt;br /&gt;
Actions always return a status.&lt;br /&gt;
Actions can take a variable number of parameters (they have minimum and maximum parameter numbers).&lt;br /&gt;
Parameter types are not described by API.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;concurrent&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 concurrent&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
 	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Concurrent nodes evaluate each children until one returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;.&lt;br /&gt;
Differences with sequence:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt; does not trigger a return&lt;br /&gt;
* Returns either &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt; except if one child failed &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* if 2 tasks were previously in &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt; and the 1st returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;, concurrent returns immediately.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;sequence&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 sequence&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
  	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Sequential nodes evaluate each children one after the other, as long as they return &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;.&lt;br /&gt;
Return last child's status.&lt;br /&gt;
&lt;br /&gt;
Differences with concurrent:&lt;br /&gt;
&lt;br /&gt;
* Sequence breaks if a child returns &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;&lt;br /&gt;
* Starts at last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;, if any&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;selector&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 selector&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
 	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Selector nodes evaluate each children one after the other, as long as they return &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;.&lt;br /&gt;
Return last child's status.&lt;br /&gt;
Does not restart from last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;fallback&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 fallback&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
  	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Fallback nodes start by evaluating the first children, and switch to the next one if a child returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;. It will continue from the last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt; child.&lt;br /&gt;
Return last child's status.&lt;br /&gt;
&lt;br /&gt;
Difference with sequence:&lt;br /&gt;
&lt;br /&gt;
* Sequence switch to the next child on &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;, while fallback switch to the next child on code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Difference with selector:&lt;br /&gt;
* Starts at last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;, if any&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;decorator&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 decorator TYPE( VALUE )&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
 	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Decorator nodes alters their children's behavior.&lt;br /&gt;
Decorator types:&lt;br /&gt;
&lt;br /&gt;
* return&lt;br /&gt;
* invert&lt;br /&gt;
* timer&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
Force children nodes to return a specific value&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;invert&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
An &amp;lt;code&amp;gt;invert&amp;lt;/code&amp;gt; node will negate the return value of its node, &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;code&amp;gt; is turned into &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; is turned into &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;STATUS_RUNNINGcode&amp;gt; is unaffected.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;timer&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
On encountering a &amp;lt;code&amp;gt;timer( &amp;lt;i&amp;gt;N&amp;lt;/i&amp;gt; )&amp;lt;/code&amp;gt; node, &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; is immediately returned if the timer's child node has already returned &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; within the last N milliseconds.&lt;br /&gt;
&lt;br /&gt;
The node may run more often than every N milliseconds if it keeps returning success.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;condition&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
  condition EXPRESSION&lt;br /&gt;
&lt;br /&gt;
  condition EXPRESSION&lt;br /&gt;
  {&lt;br /&gt;
  	NODE&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
The first form immediately returns ''EXPRESSION'' as its status: &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt; for true and &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; for false.&lt;br /&gt;
&lt;br /&gt;
The second form returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; if the expression is false, or otherwise the child's status. Note that ''EXPRESSION'' is re-evaluated every frame. If it becomes false at any time during execution of the child node, the child subtree aborts and the condition node returns failure.&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
* only executes a single child.&lt;br /&gt;
* EXPRESSION can include function calls.&lt;br /&gt;
&lt;br /&gt;
== Operators ==&lt;br /&gt;
&lt;br /&gt;
Operators are listed in the &amp;lt;code&amp;gt;AIOpMap_s conditionOps[]&amp;lt;/code&amp;gt; array.&lt;br /&gt;
operators sorted by precedence (1st have higher priority):&lt;br /&gt;
* &amp;quot;!&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;lt;&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;lt;=&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;gt;=&amp;quot;&lt;br /&gt;
* &amp;quot;==&amp;quot;&lt;br /&gt;
* &amp;quot;!=&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;amp;&amp;amp;&amp;quot;&lt;br /&gt;
* &amp;quot;||&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Functions ==&lt;br /&gt;
&lt;br /&gt;
Return value is &amp;quot;boxed&amp;quot; (&amp;lt;code&amp;gt;AIBox&amp;lt;T&amp;gt;()&amp;lt;/code&amp;gt;) in the C++ code.&lt;br /&gt;
Conditions are exported in the &amp;lt;code&amp;gt;AIConditionMap_s conditionFuncs[]&amp;lt;/code&amp;gt; array.&lt;br /&gt;
&lt;br /&gt;
=== List of functions (as of 0.52) ===&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;alienMomentum&amp;quot;,     VALUE_INT,   alienMomentum,     0 }, &lt;br /&gt;
 { &amp;quot;humanMomentum&amp;quot;,     VALUE_INT,   humanMomentum,     0 }, &lt;br /&gt;
 { &amp;quot;alertedToEnemy&amp;quot;,    VALUE_INT,   alertedToEnemy,    0 }, &lt;br /&gt;
 { &amp;quot;baseRushScore&amp;quot;,     VALUE_FLOAT, baseRushScore,     0 }, &lt;br /&gt;
 { &amp;quot;buildingIsDamaged&amp;quot;, VALUE_INT,   buildingIsDamaged, 0 }, &lt;br /&gt;
 { &amp;quot;canEvolveTo&amp;quot;,       VALUE_INT,   botCanEvolveTo,    1 }, &lt;br /&gt;
 { &amp;quot;class&amp;quot;,             VALUE_INT,   botClass,          0 }, &lt;br /&gt;
 { &amp;quot;cvarFloat&amp;quot;,         VALUE_FLOAT, cvarFloat,         1 }, &lt;br /&gt;
 { &amp;quot;cvarInt&amp;quot;,           VALUE_INT,   cvarInt,           1 }, &lt;br /&gt;
 { &amp;quot;directPathTo&amp;quot;,      VALUE_INT,   directPathTo,      1 }, &lt;br /&gt;
 { &amp;quot;distanceTo&amp;quot;,        VALUE_FLOAT, distanceTo,        1 }, &lt;br /&gt;
 { &amp;quot;goalBuildingType&amp;quot;,  VALUE_INT,   goalBuildingType,  0 }, &lt;br /&gt;
 { &amp;quot;goalIsDead&amp;quot;,        VALUE_INT,   goalDead,          0 }, &lt;br /&gt;
 { &amp;quot;goalTeam&amp;quot;,          VALUE_INT,   goalTeam,          0 }, &lt;br /&gt;
 { &amp;quot;goalType&amp;quot;,          VALUE_INT,   goalType,          0 }, &lt;br /&gt;
 { &amp;quot;haveUpgrade&amp;quot;,       VALUE_INT,   haveUpgrade,       1 }, &lt;br /&gt;
 { &amp;quot;haveWeapon&amp;quot;,        VALUE_INT,   haveWeapon,        1 }, &lt;br /&gt;
 { &amp;quot;healScore&amp;quot;,         VALUE_FLOAT, healScore,         0 }, &lt;br /&gt;
 { &amp;quot;inAttackRange&amp;quot;,     VALUE_INT,   inAttackRange,     1 }, &lt;br /&gt;
 { &amp;quot;isVisible&amp;quot;,         VALUE_INT,   isVisible,         1 }, &lt;br /&gt;
 { &amp;quot;percentAmmo&amp;quot;,       VALUE_FLOAT, percentAmmo,       0 }, &lt;br /&gt;
 { &amp;quot;percentHealth&amp;quot;,     VALUE_FLOAT, percentHealth,     1 }, &lt;br /&gt;
 { &amp;quot;random&amp;quot;,            VALUE_FLOAT, randomChance,      0 }, &lt;br /&gt;
 { &amp;quot;skill&amp;quot;,             VALUE_INT,   botSkill,          0 }, &lt;br /&gt;
 { &amp;quot;stuckTime&amp;quot;,         VALUE_INT,   stuckTime,         0 }, &lt;br /&gt;
 { &amp;quot;team&amp;quot;,              VALUE_INT,   botTeam,           0 }, &lt;br /&gt;
 { &amp;quot;teamateHasWeapon&amp;quot;,  VALUE_INT,   teamateHasWeapon,  1 }, &lt;br /&gt;
 { &amp;quot;weapon&amp;quot;,            VALUE_INT,   currentWeapon,     0 },&lt;br /&gt;
&lt;br /&gt;
== Pre-defined symbols ==&lt;br /&gt;
&lt;br /&gt;
Some values are pre-defined and usable as action's or function's parameters.&lt;br /&gt;
&lt;br /&gt;
Those are exported by calling a macro named 'D' (yes, I know).&lt;br /&gt;
List of exported symbols:&lt;br /&gt;
&lt;br /&gt;
* human upgrades (including medkit)&lt;br /&gt;
* human weapons (excluding blaster)&lt;br /&gt;
* team names (aliens, humans, and none)&lt;br /&gt;
* alien buildings&lt;br /&gt;
* human buildings&lt;br /&gt;
* &amp;lt;code&amp;gt;E_GOAL&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;E_ENEMY&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;E_DAMAGEDBUILDING&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;E_SELF&amp;lt;/code&amp;gt;&lt;br /&gt;
* classes (human ones, alien ones, and &amp;lt;code&amp;gt;PCL_NONE&amp;lt;/code&amp;gt;)&lt;br /&gt;
* moves (forward, backward, right, left)&lt;br /&gt;
* some say commands (all, team, area, area_team)&lt;br /&gt;
* task/check status names (running, success, failure)&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
&lt;br /&gt;
Parameters needs to be (un)wrapped in C++ before being accessed.&lt;br /&gt;
&lt;br /&gt;
Parameters can be of the following (C) types:&lt;br /&gt;
* float&lt;br /&gt;
* int (probably better assume 32 bit signed integers)&lt;br /&gt;
* string (probably better assume null-terminated)&lt;br /&gt;
* double (Unboxed only)&lt;br /&gt;
* token (Boxed only, either a &amp;lt;code&amp;gt;TT_STRING&amp;lt;/code&amp;gt;, a float or an int...)&lt;br /&gt;
&lt;br /&gt;
To provide a value to an action or check, the C++ code must UnBox (&amp;lt;code&amp;gt;AIUnBox&amp;lt;T&amp;gt;()&amp;lt;/code&amp;gt;) it.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Formats/Behavior_tree&amp;diff=7938</id>
		<title>Formats/Behavior tree</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Formats/Behavior_tree&amp;diff=7938"/>
		<updated>2022-09-02T23:24:21Z</updated>

		<summary type="html">&lt;p&gt;Afontain: Add &amp;quot;fallback&amp;quot; node documentation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Formats]]&lt;br /&gt;
[[Category:Bots]]&lt;br /&gt;
Behavior trees file format is game-specific (mods may modify it).&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
Bot behaviors are decided individually, at each &amp;quot;frame&amp;quot; (read: server's main loop passage), starting from a root node (I am not sure when exactly evaluation ends). An overview can be found in the [https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control) Wikipedia article].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Syntax Reference =&lt;br /&gt;
&lt;br /&gt;
Behavior trees use a specific syntax, which obey following rules (guessed from actual implementation and some C++ readings):&lt;br /&gt;
&lt;br /&gt;
* Each node or leaf returns either &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;.&lt;br /&gt;
* at most one node, leaf, block start or block end per line&lt;br /&gt;
* empty lines are accepted&lt;br /&gt;
* comments can either:&lt;br /&gt;
:* start with &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and go to the end of line&lt;br /&gt;
:* start with &amp;lt;code&amp;gt;/*&amp;lt;/code&amp;gt; and go to next &amp;lt;code&amp;gt;*/&amp;lt;/code&amp;gt;, including out of current line (TODO: verify).&lt;br /&gt;
* comments can not be nested&lt;br /&gt;
* actions and conditions taking parameters must enclose those withing parentheses, separated with commas (i.e. &amp;lt;code&amp;gt;roamInRadius( E_H_REACTOR, 500 )&amp;lt;/code&amp;gt;)&lt;br /&gt;
* if an action or a condition does not need parameters, parentheses are optional&lt;br /&gt;
* spaces and tabulations are meaningless&lt;br /&gt;
* strings start and end with a double quote &amp;lt;code&amp;gt;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
* keywords are reserved (TODO: verify, but even if wrong, better avoid their use)&lt;br /&gt;
* values can't be stored or modified (additions, subtractions, multiplications, etc)&lt;br /&gt;
* no user-defined function (but files can be included, and C++ functions can be written in the game logic and be used in the behavior tree)&lt;br /&gt;
* each possible path should (TODO: verify, even if I fail to understand why one would break that willingly) end by one or more action&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
It is not possible to do mathematical operations such as additions, multiplications, divisions, ...&lt;br /&gt;
&lt;br /&gt;
== Keywords ==&lt;br /&gt;
&lt;br /&gt;
There are several keywords:&lt;br /&gt;
&lt;br /&gt;
* behavior&lt;br /&gt;
* action&lt;br /&gt;
* sequence&lt;br /&gt;
* selector&lt;br /&gt;
* fallback&lt;br /&gt;
* concurrent&lt;br /&gt;
* decorator&lt;br /&gt;
* condition&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;behavior&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 behavior NAME&lt;br /&gt;
&lt;br /&gt;
Include named behavior at current place.&lt;br /&gt;
It is unsure if this is just an inclusion of if the subtree is parsed and stored individually.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;action&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 action NAME&lt;br /&gt;
&lt;br /&gt;
 action NAME()&lt;br /&gt;
&lt;br /&gt;
 action NAME( param )&lt;br /&gt;
&lt;br /&gt;
 action NAME( param1, param2, ..., paramN )&lt;br /&gt;
&lt;br /&gt;
Leaves of the tree, they trigger an action from the bot.&lt;br /&gt;
&lt;br /&gt;
=== List of actions ===&lt;br /&gt;
&lt;br /&gt;
Titles provide a link to more detailed pages.&lt;br /&gt;
TODO: have something more time-resilient (one page per call, with it's changelog, maybe?)&lt;br /&gt;
&lt;br /&gt;
==== [[0.52]] ====&lt;br /&gt;
&lt;br /&gt;
* activateUpgrade&lt;br /&gt;
* aimAtGoal&lt;br /&gt;
* alternateStrafe&lt;br /&gt;
* buy&lt;br /&gt;
* changeGoal&lt;br /&gt;
* classDodge&lt;br /&gt;
* deactivateUpgrade&lt;br /&gt;
* equip&lt;br /&gt;
* evolve&lt;br /&gt;
* evolveTo&lt;br /&gt;
* fight&lt;br /&gt;
* fireWeapon&lt;br /&gt;
* flee&lt;br /&gt;
* heal&lt;br /&gt;
* jump&lt;br /&gt;
* moveInDir&lt;br /&gt;
* moveTo&lt;br /&gt;
* moveToGoal&lt;br /&gt;
* repair&lt;br /&gt;
* resetStuckTime&lt;br /&gt;
* roam&lt;br /&gt;
* roamInRadius&lt;br /&gt;
* rush&lt;br /&gt;
* say&lt;br /&gt;
* strafeDodge&lt;br /&gt;
* suicide&lt;br /&gt;
&lt;br /&gt;
=== Creating new actions ===&lt;br /&gt;
&lt;br /&gt;
Actions are exported in the &amp;lt;code&amp;gt;AIActionMap_s AIActions[]&amp;lt;/code&amp;gt; C array.&lt;br /&gt;
Actions always return a status.&lt;br /&gt;
Actions can take a variable number of parameters (they have minimum and maximum parameter numbers).&lt;br /&gt;
Parameter types are not described by API.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;concurrent&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 concurrent&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
 	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Concurrent nodes evaluate each children until one returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;.&lt;br /&gt;
Differences with sequence:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt; does not trigger a return&lt;br /&gt;
* Returns either &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt; except if one child failed &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* if 2 tasks were previously in &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt; and the 1st returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;, concurrent returns immediately.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;sequence&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 sequence&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
  	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Sequential nodes evaluate each children one after the other, as long as they return &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;.&lt;br /&gt;
Return last child's status.&lt;br /&gt;
&lt;br /&gt;
Differences with concurrent:&lt;br /&gt;
&lt;br /&gt;
* Sequence breaks if a child returns &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;&lt;br /&gt;
* Starts at last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;, if any&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;selector&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 selector&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
 	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Selector nodes evaluate each children one after the other, as long as they return &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;.&lt;br /&gt;
Return last child's status.&lt;br /&gt;
Does not restart from last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;fallback&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 fallback&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
  	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Fallback nodes start by evaluating the first children, and switch to the next one if a child returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;. It will continue from the last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt; child.&lt;br /&gt;
Return last child's status.&lt;br /&gt;
&lt;br /&gt;
Difference with sequence:&lt;br /&gt;
&lt;br /&gt;
* Sequence switch to the next child on &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;, while fallback switch to the next child on code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Difference with selector:&lt;br /&gt;
* Starts at last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;, if any&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;decorator&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 decorator TYPE( VALUE )&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
 	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Decorator nodes alters their children's behavior.&lt;br /&gt;
Decorator types:&lt;br /&gt;
&lt;br /&gt;
* return&lt;br /&gt;
* timer&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
Force children nodes to return a specific value&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;timer&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
On encountering a &amp;lt;code&amp;gt;timer( &amp;lt;i&amp;gt;N&amp;lt;/i&amp;gt; )&amp;lt;/code&amp;gt; node, STATUS_FAILURE is immediately returned if the timer's child node has already returned STATUS_FAILURE within the last N milliseconds.&lt;br /&gt;
&lt;br /&gt;
The node may run more often than every N milliseconds if it keeps returning success.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;condition&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
  condition EXPRESSION&lt;br /&gt;
&lt;br /&gt;
  condition EXPRESSION&lt;br /&gt;
  {&lt;br /&gt;
  	NODE&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
The first form immediately returns ''EXPRESSION'' as its status: &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt; for true and &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; for false.&lt;br /&gt;
&lt;br /&gt;
The second form returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; if the expression is false, or otherwise the child's status. Note that ''EXPRESSION'' is re-evaluated every frame. If it becomes false at any time during execution of the child node, the child subtree aborts and the condition node returns failure.&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
* only executes a single child.&lt;br /&gt;
* EXPRESSION can include function calls.&lt;br /&gt;
&lt;br /&gt;
== Operators ==&lt;br /&gt;
&lt;br /&gt;
Operators are listed in the &amp;lt;code&amp;gt;AIOpMap_s conditionOps[]&amp;lt;/code&amp;gt; array.&lt;br /&gt;
operators sorted by precedence (1st have higher priority):&lt;br /&gt;
* &amp;quot;!&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;lt;&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;lt;=&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;gt;=&amp;quot;&lt;br /&gt;
* &amp;quot;==&amp;quot;&lt;br /&gt;
* &amp;quot;!=&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;amp;&amp;amp;&amp;quot;&lt;br /&gt;
* &amp;quot;||&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Functions ==&lt;br /&gt;
&lt;br /&gt;
Return value is &amp;quot;boxed&amp;quot; (&amp;lt;code&amp;gt;AIBox&amp;lt;T&amp;gt;()&amp;lt;/code&amp;gt;) in the C++ code.&lt;br /&gt;
Conditions are exported in the &amp;lt;code&amp;gt;AIConditionMap_s conditionFuncs[]&amp;lt;/code&amp;gt; array.&lt;br /&gt;
&lt;br /&gt;
=== List of functions (as of 0.52) ===&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;alienMomentum&amp;quot;,     VALUE_INT,   alienMomentum,     0 }, &lt;br /&gt;
 { &amp;quot;humanMomentum&amp;quot;,     VALUE_INT,   humanMomentum,     0 }, &lt;br /&gt;
 { &amp;quot;alertedToEnemy&amp;quot;,    VALUE_INT,   alertedToEnemy,    0 }, &lt;br /&gt;
 { &amp;quot;baseRushScore&amp;quot;,     VALUE_FLOAT, baseRushScore,     0 }, &lt;br /&gt;
 { &amp;quot;buildingIsDamaged&amp;quot;, VALUE_INT,   buildingIsDamaged, 0 }, &lt;br /&gt;
 { &amp;quot;canEvolveTo&amp;quot;,       VALUE_INT,   botCanEvolveTo,    1 }, &lt;br /&gt;
 { &amp;quot;class&amp;quot;,             VALUE_INT,   botClass,          0 }, &lt;br /&gt;
 { &amp;quot;cvarFloat&amp;quot;,         VALUE_FLOAT, cvarFloat,         1 }, &lt;br /&gt;
 { &amp;quot;cvarInt&amp;quot;,           VALUE_INT,   cvarInt,           1 }, &lt;br /&gt;
 { &amp;quot;directPathTo&amp;quot;,      VALUE_INT,   directPathTo,      1 }, &lt;br /&gt;
 { &amp;quot;distanceTo&amp;quot;,        VALUE_FLOAT, distanceTo,        1 }, &lt;br /&gt;
 { &amp;quot;goalBuildingType&amp;quot;,  VALUE_INT,   goalBuildingType,  0 }, &lt;br /&gt;
 { &amp;quot;goalIsDead&amp;quot;,        VALUE_INT,   goalDead,          0 }, &lt;br /&gt;
 { &amp;quot;goalTeam&amp;quot;,          VALUE_INT,   goalTeam,          0 }, &lt;br /&gt;
 { &amp;quot;goalType&amp;quot;,          VALUE_INT,   goalType,          0 }, &lt;br /&gt;
 { &amp;quot;haveUpgrade&amp;quot;,       VALUE_INT,   haveUpgrade,       1 }, &lt;br /&gt;
 { &amp;quot;haveWeapon&amp;quot;,        VALUE_INT,   haveWeapon,        1 }, &lt;br /&gt;
 { &amp;quot;healScore&amp;quot;,         VALUE_FLOAT, healScore,         0 }, &lt;br /&gt;
 { &amp;quot;inAttackRange&amp;quot;,     VALUE_INT,   inAttackRange,     1 }, &lt;br /&gt;
 { &amp;quot;isVisible&amp;quot;,         VALUE_INT,   isVisible,         1 }, &lt;br /&gt;
 { &amp;quot;percentAmmo&amp;quot;,       VALUE_FLOAT, percentAmmo,       0 }, &lt;br /&gt;
 { &amp;quot;percentHealth&amp;quot;,     VALUE_FLOAT, percentHealth,     1 }, &lt;br /&gt;
 { &amp;quot;random&amp;quot;,            VALUE_FLOAT, randomChance,      0 }, &lt;br /&gt;
 { &amp;quot;skill&amp;quot;,             VALUE_INT,   botSkill,          0 }, &lt;br /&gt;
 { &amp;quot;stuckTime&amp;quot;,         VALUE_INT,   stuckTime,         0 }, &lt;br /&gt;
 { &amp;quot;team&amp;quot;,              VALUE_INT,   botTeam,           0 }, &lt;br /&gt;
 { &amp;quot;teamateHasWeapon&amp;quot;,  VALUE_INT,   teamateHasWeapon,  1 }, &lt;br /&gt;
 { &amp;quot;weapon&amp;quot;,            VALUE_INT,   currentWeapon,     0 },&lt;br /&gt;
&lt;br /&gt;
== Pre-defined symbols ==&lt;br /&gt;
&lt;br /&gt;
Some values are pre-defined and usable as action's or function's parameters.&lt;br /&gt;
&lt;br /&gt;
Those are exported by calling a macro named 'D' (yes, I know).&lt;br /&gt;
List of exported symbols:&lt;br /&gt;
&lt;br /&gt;
* human upgrades (including medkit)&lt;br /&gt;
* human weapons (excluding blaster)&lt;br /&gt;
* team names (aliens, humans, and none)&lt;br /&gt;
* alien buildings&lt;br /&gt;
* human buildings&lt;br /&gt;
* &amp;lt;code&amp;gt;E_GOAL&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;E_ENEMY&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;E_DAMAGEDBUILDING&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;E_SELF&amp;lt;/code&amp;gt;&lt;br /&gt;
* classes (human ones, alien ones, and &amp;lt;code&amp;gt;PCL_NONE&amp;lt;/code&amp;gt;)&lt;br /&gt;
* moves (forward, backward, right, left)&lt;br /&gt;
* some say commands (all, team, area, area_team)&lt;br /&gt;
* task/check status names (running, success, failure)&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
&lt;br /&gt;
Parameters needs to be (un)wrapped in C++ before being accessed.&lt;br /&gt;
&lt;br /&gt;
Parameters can be of the following (C) types:&lt;br /&gt;
* float&lt;br /&gt;
* int (probably better assume 32 bit signed integers)&lt;br /&gt;
* string (probably better assume null-terminated)&lt;br /&gt;
* double (Unboxed only)&lt;br /&gt;
* token (Boxed only, either a &amp;lt;code&amp;gt;TT_STRING&amp;lt;/code&amp;gt;, a float or an int...)&lt;br /&gt;
&lt;br /&gt;
To provide a value to an action or check, the C++ code must UnBox (&amp;lt;code&amp;gt;AIUnBox&amp;lt;T&amp;gt;()&amp;lt;/code&amp;gt;) it.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=UI/Design&amp;diff=7473</id>
		<title>UI/Design</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=UI/Design&amp;diff=7473"/>
		<updated>2022-07-07T01:03:36Z</updated>

		<summary type="html">&lt;p&gt;Afontain: delete page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Humans&amp;diff=5563</id>
		<title>Humans</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Humans&amp;diff=5563"/>
		<updated>2021-11-23T14:09:54Z</updated>

		<summary type="html">&lt;p&gt;Afontain: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{InfoBoxStart | name = Human | image = Human standing.jpeg | caption = A fearless clone trooper.}}&lt;br /&gt;
{{InfoRow | caption = Health | value = 100 }}&lt;br /&gt;
{{InfoBoxEnd}}&lt;br /&gt;
&lt;br /&gt;
==Tips==&lt;br /&gt;
&lt;br /&gt;
* Go out in groups. Unlike aliens, humans have little chance of escaping if they meet an overwhelming force outside their base.&lt;br /&gt;
&lt;br /&gt;
* If you have enough credits, buy at least a [[Light Armour|light armour]]. With it you can't be killed in a single hit, except by a [[tyrant]].&lt;br /&gt;
&lt;br /&gt;
* Energy weapons ([[Las Gun|lasgun]], [[Pulse Rifle|pulse rifle]], [[Lucifer Cannon|Lucifer cannon]]) can also be recharged at the [[reactor]].&lt;br /&gt;
&lt;br /&gt;
[[File:Exploding_Turret.png|thumb|center|Don't stay close to dead buildings: their explosion will hurt you.]]&lt;br /&gt;
&lt;br /&gt;
* When keeping the &amp;quot;jump&amp;quot; key pressed while touching a wall, humans can &amp;quot;wall run&amp;quot;, increasing their mobility.&lt;br /&gt;
&lt;br /&gt;
* Humans, unlike aliens, can use ladders.&lt;br /&gt;
&lt;br /&gt;
* Humans can &amp;quot;slide&amp;quot;, whatever that mean (please update this if you know more).&lt;br /&gt;
&lt;br /&gt;
* Medkit will progressively restore all the health you loosed at the moment you use it, in roughly 13s. Using it wisely will allow you to retreat safely, or to launch an attack at full health.&lt;br /&gt;
&lt;br /&gt;
* Crouching reduces recoil with weapons. This is mostly (only?) useful for chaingun though, and makes you slower.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Weapons==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable spaced&amp;quot;&lt;br /&gt;
! Name&lt;br /&gt;
! Unlock&lt;br /&gt;
! Cost&lt;br /&gt;
! Ammo&lt;br /&gt;
! Damage&lt;br /&gt;
|-&lt;br /&gt;
| [[Blaster]]&lt;br /&gt;
| 0&lt;br /&gt;
| Free&lt;br /&gt;
| ∞&lt;br /&gt;
| 10 per second&lt;br /&gt;
|-&lt;br /&gt;
| [[Construction Kit]]&lt;br /&gt;
| 0&lt;br /&gt;
| Free&lt;br /&gt;
| -&lt;br /&gt;
| Used to build structures (cooldown ~6s).&lt;br /&gt;
|-&lt;br /&gt;
| [[SMG]]&lt;br /&gt;
| 0&lt;br /&gt;
| Free&lt;br /&gt;
| 30/6&lt;br /&gt;
| 62.5 per second, 150 per magazine.&lt;br /&gt;
|-&lt;br /&gt;
| [[Shotgun]]&lt;br /&gt;
| 0&lt;br /&gt;
| 150&lt;br /&gt;
| 8/3&lt;br /&gt;
| 55 per second, 440 per magazine.&lt;br /&gt;
|-&lt;br /&gt;
| [[Las Gun]]&lt;br /&gt;
| 0&lt;br /&gt;
| 250&lt;br /&gt;
| 200&lt;br /&gt;
| 45 per second, 1800 per magazine.&lt;br /&gt;
|-&lt;br /&gt;
| [[Mass Driver]]&lt;br /&gt;
| 0&lt;br /&gt;
| 350&lt;br /&gt;
| 6/4&lt;br /&gt;
| 40 per second, 240 per magazine.&lt;br /&gt;
|-&lt;br /&gt;
| [[Chaingun]]&lt;br /&gt;
| 0&lt;br /&gt;
| 400&lt;br /&gt;
| 300&lt;br /&gt;
| 68 per second, 1800 per magazine.&lt;br /&gt;
|-&lt;br /&gt;
| [[Pain Saw]]&lt;br /&gt;
| 1&lt;br /&gt;
| 100&lt;br /&gt;
| ∞&lt;br /&gt;
| 147 per second.&lt;br /&gt;
|-&lt;br /&gt;
| [[Flame Thrower]]&lt;br /&gt;
| 2&lt;br /&gt;
| 450&lt;br /&gt;
| 300&lt;br /&gt;
| 140 per second, 4200 per magazine.&lt;br /&gt;
|-&lt;br /&gt;
| [[Pulse Rifle]]&lt;br /&gt;
| 2&lt;br /&gt;
| 450&lt;br /&gt;
| 50/5&lt;br /&gt;
| 90 per second, 450 per magazine.&lt;br /&gt;
|-&lt;br /&gt;
| [[Lucifer Cannon]]&lt;br /&gt;
| 5&lt;br /&gt;
| 600&lt;br /&gt;
| 100&lt;br /&gt;
| Up to 265 per shot, 88 per second, 2650 per magazine.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Armour==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable spaced&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name&lt;br /&gt;
! Unlock&lt;br /&gt;
! Cost&lt;br /&gt;
! % of base damage (head/back/front/legs)&lt;br /&gt;
! walk speed (forward/backward/lateral) in game's units&lt;br /&gt;
! run speed (forward/backward/lateral) in game's units&lt;br /&gt;
! comment&lt;br /&gt;
|-&lt;br /&gt;
| [[Basic Armour]]&lt;br /&gt;
| 0&lt;br /&gt;
| Free&lt;br /&gt;
| 150/100/100/60&lt;br /&gt;
| 319/255/287&lt;br /&gt;
| 383/307/345&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
| [[Light Armour]]&lt;br /&gt;
| 0&lt;br /&gt;
| 200&lt;br /&gt;
| 80/50/35/20&lt;br /&gt;
| 319/255/287&lt;br /&gt;
| 383/307/345&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
| [[Medium Armour]]&lt;br /&gt;
| 3&lt;br /&gt;
| 300&lt;br /&gt;
| 60/35/30/20&lt;br /&gt;
| 319/255/287&lt;br /&gt;
| 367/294/331&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
| [[Battlesuit]]&lt;br /&gt;
| 4&lt;br /&gt;
| 400&lt;br /&gt;
| 40/20/20/15&lt;br /&gt;
| 319/255/287&lt;br /&gt;
| 367/294/331&lt;br /&gt;
| prevent the use of jetpacks or radars. Wearing Battlesuit reduces mobility, preventing the user to wallrun and slide.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* Walk speed seems to never be affected.&lt;br /&gt;
* Only armor affect speeds. Probably same for stamina.&lt;br /&gt;
* Each armor class have a different impact on stamina reserves.&lt;br /&gt;
* Sufficient stamina reserves is needed to be able to jump.&lt;br /&gt;
&lt;br /&gt;
==Backpacks==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable spaced&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name&lt;br /&gt;
! Unlock&lt;br /&gt;
! Cost&lt;br /&gt;
! Effects&lt;br /&gt;
|-&lt;br /&gt;
| [[Radar]] &lt;br /&gt;
| 1&lt;br /&gt;
| 100&lt;br /&gt;
| Communicates position of seen aliens to the team.&lt;br /&gt;
|-&lt;br /&gt;
| [[Jetpack|Jet Pack]]&lt;br /&gt;
| 2&lt;br /&gt;
| 120&lt;br /&gt;
| Allows the user to fly for short periods of time.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Grenades==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable spaced&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name&lt;br /&gt;
! Unlock&lt;br /&gt;
! Cost&lt;br /&gt;
! Damage&lt;br /&gt;
|-&lt;br /&gt;
| [[Firebomb]]&lt;br /&gt;
| 2&lt;br /&gt;
| 200&lt;br /&gt;
| 50 at epicenter, sets alien structures on fire.&lt;br /&gt;
|-&lt;br /&gt;
| [[Grenade]]&lt;br /&gt;
| 4&lt;br /&gt;
| 250&lt;br /&gt;
| 310 at epicenter.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Buildables== &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable spaced&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name&lt;br /&gt;
! Unlock&lt;br /&gt;
! Cost&lt;br /&gt;
! Health&lt;br /&gt;
| Regen&lt;br /&gt;
| Time to heal&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| [[Reactor]]&lt;br /&gt;
| 0&lt;br /&gt;
| Free&lt;br /&gt;
| 930&lt;br /&gt;
| 15&lt;br /&gt;
| 62&lt;br /&gt;
| Keep everything around the map powered. If it goes down, you turrets will quickly get destroyed and you can't use the armory or the medistation.&lt;br /&gt;
|-&lt;br /&gt;
| [[Telenode]]&lt;br /&gt;
| 0&lt;br /&gt;
| 10&lt;br /&gt;
| 310&lt;br /&gt;
| 10&lt;br /&gt;
| 31&lt;br /&gt;
| Allows humans to enter the battle arena. Defeat is imminent upon destruction of the last telenode.&lt;br /&gt;
|-&lt;br /&gt;
| [[Armory]]&lt;br /&gt;
| 0&lt;br /&gt;
| 8&lt;br /&gt;
| 420&lt;br /&gt;
| 10&lt;br /&gt;
| 42&lt;br /&gt;
| Allows humans to buy weapons and upgrades.&lt;br /&gt;
|-&lt;br /&gt;
| [[Medistation]]&lt;br /&gt;
| 0&lt;br /&gt;
| 8&lt;br /&gt;
| 190&lt;br /&gt;
| 5&lt;br /&gt;
| 38&lt;br /&gt;
| Restores health and issues medkits. Can only be used by one human at a time.&lt;br /&gt;
|-&lt;br /&gt;
| [[Machinegun Turret]]&lt;br /&gt;
| 0&lt;br /&gt;
| 10&lt;br /&gt;
| 250&lt;br /&gt;
| 5&lt;br /&gt;
| 50&lt;br /&gt;
| Short-range defensive structure. Very powerful area denial weapon.&lt;br /&gt;
|-&lt;br /&gt;
| [[Rocket Pod]]&lt;br /&gt;
| 1&lt;br /&gt;
| 10&lt;br /&gt;
| 250&lt;br /&gt;
| 5&lt;br /&gt;
| 50&lt;br /&gt;
| Long-range defensive structure. Fires missiles that track ennemies every ~3s but won't shot at close range.&lt;br /&gt;
|-&lt;br /&gt;
| [[Drill]]&lt;br /&gt;
| 0&lt;br /&gt;
| 4&lt;br /&gt;
| 200&lt;br /&gt;
| 5&lt;br /&gt;
| 40&lt;br /&gt;
| Drills for materials.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Humans]]&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Humans&amp;diff=5562</id>
		<title>Humans</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Humans&amp;diff=5562"/>
		<updated>2021-11-23T14:09:26Z</updated>

		<summary type="html">&lt;p&gt;Afontain: Rework tips&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{InfoBoxStart | name = Human | image = Human standing.jpeg | caption = A fearless clone trooper.}}&lt;br /&gt;
{{InfoRow | caption = Health | value = 100 }}&lt;br /&gt;
{{InfoBoxEnd}}&lt;br /&gt;
&lt;br /&gt;
==Tips==&lt;br /&gt;
&lt;br /&gt;
* Go out in groups. Unlike aliens, humans have little chance of escaping if they meet an overwhelming force outside their base.&lt;br /&gt;
&lt;br /&gt;
* If you have enough credits, buy at least a [[Light Armour|light armour]]. With it you can't be killed in a single hit, except by a [[tyrant]].&lt;br /&gt;
&lt;br /&gt;
* Energy weapons ([[Las Gun|lasgun]], [[Pulse Rifle|pulse rifle]], [[Lucifer Cannon|Lucifer cannon]]) can also be recharged at the [[reactor]].&lt;br /&gt;
&lt;br /&gt;
[[File:Exploding_Turret.png|thumb|center|Don't stay close to dead buildings: their explosion will hurt you.]]&lt;br /&gt;
&lt;br /&gt;
* When keeping the &amp;quot;jump&amp;quot; key pressed while touching a wall, humans can &amp;quot;wall run&amp;quot;, increasing their mobility.&lt;br /&gt;
&lt;br /&gt;
* Humans, unlike aliens, can use ladders.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- * Humans can &amp;quot;slide&amp;quot;, whatever that mean (please update this if you know more). --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Medkit will progressively restore all the health you loosed at the moment you use it, in roughly 13s. Using it wisely will allow you to retreat safely, or to launch an attack at full health.&lt;br /&gt;
&lt;br /&gt;
* Crouching reduces recoil with weapons. This is mostly (only?) useful for chaingun though, and makes you slower.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Weapons==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable spaced&amp;quot;&lt;br /&gt;
! Name&lt;br /&gt;
! Unlock&lt;br /&gt;
! Cost&lt;br /&gt;
! Ammo&lt;br /&gt;
! Damage&lt;br /&gt;
|-&lt;br /&gt;
| [[Blaster]]&lt;br /&gt;
| 0&lt;br /&gt;
| Free&lt;br /&gt;
| ∞&lt;br /&gt;
| 10 per second&lt;br /&gt;
|-&lt;br /&gt;
| [[Construction Kit]]&lt;br /&gt;
| 0&lt;br /&gt;
| Free&lt;br /&gt;
| -&lt;br /&gt;
| Used to build structures (cooldown ~6s).&lt;br /&gt;
|-&lt;br /&gt;
| [[SMG]]&lt;br /&gt;
| 0&lt;br /&gt;
| Free&lt;br /&gt;
| 30/6&lt;br /&gt;
| 62.5 per second, 150 per magazine.&lt;br /&gt;
|-&lt;br /&gt;
| [[Shotgun]]&lt;br /&gt;
| 0&lt;br /&gt;
| 150&lt;br /&gt;
| 8/3&lt;br /&gt;
| 55 per second, 440 per magazine.&lt;br /&gt;
|-&lt;br /&gt;
| [[Las Gun]]&lt;br /&gt;
| 0&lt;br /&gt;
| 250&lt;br /&gt;
| 200&lt;br /&gt;
| 45 per second, 1800 per magazine.&lt;br /&gt;
|-&lt;br /&gt;
| [[Mass Driver]]&lt;br /&gt;
| 0&lt;br /&gt;
| 350&lt;br /&gt;
| 6/4&lt;br /&gt;
| 40 per second, 240 per magazine.&lt;br /&gt;
|-&lt;br /&gt;
| [[Chaingun]]&lt;br /&gt;
| 0&lt;br /&gt;
| 400&lt;br /&gt;
| 300&lt;br /&gt;
| 68 per second, 1800 per magazine.&lt;br /&gt;
|-&lt;br /&gt;
| [[Pain Saw]]&lt;br /&gt;
| 1&lt;br /&gt;
| 100&lt;br /&gt;
| ∞&lt;br /&gt;
| 147 per second.&lt;br /&gt;
|-&lt;br /&gt;
| [[Flame Thrower]]&lt;br /&gt;
| 2&lt;br /&gt;
| 450&lt;br /&gt;
| 300&lt;br /&gt;
| 140 per second, 4200 per magazine.&lt;br /&gt;
|-&lt;br /&gt;
| [[Pulse Rifle]]&lt;br /&gt;
| 2&lt;br /&gt;
| 450&lt;br /&gt;
| 50/5&lt;br /&gt;
| 90 per second, 450 per magazine.&lt;br /&gt;
|-&lt;br /&gt;
| [[Lucifer Cannon]]&lt;br /&gt;
| 5&lt;br /&gt;
| 600&lt;br /&gt;
| 100&lt;br /&gt;
| Up to 265 per shot, 88 per second, 2650 per magazine.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Armour==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable spaced&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name&lt;br /&gt;
! Unlock&lt;br /&gt;
! Cost&lt;br /&gt;
! % of base damage (head/back/front/legs)&lt;br /&gt;
! walk speed (forward/backward/lateral) in game's units&lt;br /&gt;
! run speed (forward/backward/lateral) in game's units&lt;br /&gt;
! comment&lt;br /&gt;
|-&lt;br /&gt;
| [[Basic Armour]]&lt;br /&gt;
| 0&lt;br /&gt;
| Free&lt;br /&gt;
| 150/100/100/60&lt;br /&gt;
| 319/255/287&lt;br /&gt;
| 383/307/345&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
| [[Light Armour]]&lt;br /&gt;
| 0&lt;br /&gt;
| 200&lt;br /&gt;
| 80/50/35/20&lt;br /&gt;
| 319/255/287&lt;br /&gt;
| 383/307/345&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
| [[Medium Armour]]&lt;br /&gt;
| 3&lt;br /&gt;
| 300&lt;br /&gt;
| 60/35/30/20&lt;br /&gt;
| 319/255/287&lt;br /&gt;
| 367/294/331&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
| [[Battlesuit]]&lt;br /&gt;
| 4&lt;br /&gt;
| 400&lt;br /&gt;
| 40/20/20/15&lt;br /&gt;
| 319/255/287&lt;br /&gt;
| 367/294/331&lt;br /&gt;
| prevent the use of jetpacks or radars. Wearing Battlesuit reduces mobility, preventing the user to wallrun and slide.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* Walk speed seems to never be affected.&lt;br /&gt;
* Only armor affect speeds. Probably same for stamina.&lt;br /&gt;
* Each armor class have a different impact on stamina reserves.&lt;br /&gt;
* Sufficient stamina reserves is needed to be able to jump.&lt;br /&gt;
&lt;br /&gt;
==Backpacks==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable spaced&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name&lt;br /&gt;
! Unlock&lt;br /&gt;
! Cost&lt;br /&gt;
! Effects&lt;br /&gt;
|-&lt;br /&gt;
| [[Radar]] &lt;br /&gt;
| 1&lt;br /&gt;
| 100&lt;br /&gt;
| Communicates position of seen aliens to the team.&lt;br /&gt;
|-&lt;br /&gt;
| [[Jetpack|Jet Pack]]&lt;br /&gt;
| 2&lt;br /&gt;
| 120&lt;br /&gt;
| Allows the user to fly for short periods of time.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Grenades==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable spaced&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name&lt;br /&gt;
! Unlock&lt;br /&gt;
! Cost&lt;br /&gt;
! Damage&lt;br /&gt;
|-&lt;br /&gt;
| [[Firebomb]]&lt;br /&gt;
| 2&lt;br /&gt;
| 200&lt;br /&gt;
| 50 at epicenter, sets alien structures on fire.&lt;br /&gt;
|-&lt;br /&gt;
| [[Grenade]]&lt;br /&gt;
| 4&lt;br /&gt;
| 250&lt;br /&gt;
| 310 at epicenter.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Buildables== &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable spaced&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name&lt;br /&gt;
! Unlock&lt;br /&gt;
! Cost&lt;br /&gt;
! Health&lt;br /&gt;
| Regen&lt;br /&gt;
| Time to heal&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| [[Reactor]]&lt;br /&gt;
| 0&lt;br /&gt;
| Free&lt;br /&gt;
| 930&lt;br /&gt;
| 15&lt;br /&gt;
| 62&lt;br /&gt;
| Keep everything around the map powered. If it goes down, you turrets will quickly get destroyed and you can't use the armory or the medistation.&lt;br /&gt;
|-&lt;br /&gt;
| [[Telenode]]&lt;br /&gt;
| 0&lt;br /&gt;
| 10&lt;br /&gt;
| 310&lt;br /&gt;
| 10&lt;br /&gt;
| 31&lt;br /&gt;
| Allows humans to enter the battle arena. Defeat is imminent upon destruction of the last telenode.&lt;br /&gt;
|-&lt;br /&gt;
| [[Armory]]&lt;br /&gt;
| 0&lt;br /&gt;
| 8&lt;br /&gt;
| 420&lt;br /&gt;
| 10&lt;br /&gt;
| 42&lt;br /&gt;
| Allows humans to buy weapons and upgrades.&lt;br /&gt;
|-&lt;br /&gt;
| [[Medistation]]&lt;br /&gt;
| 0&lt;br /&gt;
| 8&lt;br /&gt;
| 190&lt;br /&gt;
| 5&lt;br /&gt;
| 38&lt;br /&gt;
| Restores health and issues medkits. Can only be used by one human at a time.&lt;br /&gt;
|-&lt;br /&gt;
| [[Machinegun Turret]]&lt;br /&gt;
| 0&lt;br /&gt;
| 10&lt;br /&gt;
| 250&lt;br /&gt;
| 5&lt;br /&gt;
| 50&lt;br /&gt;
| Short-range defensive structure. Very powerful area denial weapon.&lt;br /&gt;
|-&lt;br /&gt;
| [[Rocket Pod]]&lt;br /&gt;
| 1&lt;br /&gt;
| 10&lt;br /&gt;
| 250&lt;br /&gt;
| 5&lt;br /&gt;
| 50&lt;br /&gt;
| Long-range defensive structure. Fires missiles that track ennemies every ~3s but won't shot at close range.&lt;br /&gt;
|-&lt;br /&gt;
| [[Drill]]&lt;br /&gt;
| 0&lt;br /&gt;
| 4&lt;br /&gt;
| 200&lt;br /&gt;
| 5&lt;br /&gt;
| 40&lt;br /&gt;
| Drills for materials.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Humans]]&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=File:Exploding_Turret.png&amp;diff=5561</id>
		<title>File:Exploding Turret.png</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=File:Exploding_Turret.png&amp;diff=5561"/>
		<updated>2021-11-23T14:01:27Z</updated>

		<summary type="html">&lt;p&gt;Afontain: Human turret exploding&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
Human turret exploding&lt;br /&gt;
== Licencing ==&lt;br /&gt;
{{licenses/cc-by-sa-3.0}}&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Drill&amp;diff=5485</id>
		<title>Drill</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Drill&amp;diff=5485"/>
		<updated>2021-11-07T23:45:16Z</updated>

		<summary type="html">&lt;p&gt;Afontain: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{InfoBoxStart | name = Drill | image = Drill.png | caption = Why hasn't the floor collapsed yet?}}&lt;br /&gt;
{{InfoRow | caption = Cost | value = 0 Credits }}&lt;br /&gt;
{{InfoRow | caption = Unlock | value = - }}&lt;br /&gt;
{{InfoRow | caption = Health | value = 200 }}&lt;br /&gt;
{{InfoRow | caption = Build Time | value = 10 seconds }}&lt;br /&gt;
{{InfoBoxEnd}}&lt;br /&gt;
&lt;br /&gt;
Drills the ground for materials.&lt;br /&gt;
&lt;br /&gt;
== Tips ==&lt;br /&gt;
&lt;br /&gt;
* Spread them apart for maximum mining efficiency. Keep in mind that two drills right next to each other will mine out less material than a single drill.&lt;br /&gt;
&lt;br /&gt;
* Defend your drills well. If a drill is destroyed, you'll lose a portion of your stored material.&lt;br /&gt;
&lt;br /&gt;
* If you feel a forward base with a drill in it isn't going to last for much longer, deconstruct the buildables that are worth money to prevent the loss of material.&lt;br /&gt;
&lt;br /&gt;
[[File:Unvanquished 2021-11-Light armor with lasgun.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:2021-11-Drills too close.jpg]]&lt;br /&gt;
&lt;br /&gt;
When Drills and [[Leech|Leeches]] are close together, they annihilates themself.&lt;br /&gt;
# Only with the [[Construction_Kit|Construction Kit]] you can see that they consume BP instead generate power.&lt;br /&gt;
&lt;br /&gt;
It's the same for a Drill near a [[Leech|Leech]].&lt;br /&gt;
&lt;br /&gt;
[[Category:Humans]]&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Formats/Behavior_tree&amp;diff=5221</id>
		<title>Formats/Behavior tree</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Formats/Behavior_tree&amp;diff=5221"/>
		<updated>2021-11-01T22:02:54Z</updated>

		<summary type="html">&lt;p&gt;Afontain: /* The return keyword */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
Bot behaviors are decided individually, at each &amp;quot;frame&amp;quot; (read: server's main loop passage), starting from a root node (I am not sure when exactly evaluation ends). An overview can be found in the [https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control) Wikipedia article].&lt;br /&gt;
&lt;br /&gt;
= Syntax Reference =&lt;br /&gt;
&lt;br /&gt;
Behavior trees use a specific syntax, which obey following rules (guessed from actual implementation and some C++ readings):&lt;br /&gt;
&lt;br /&gt;
* Each node or leaf returns either &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;.&lt;br /&gt;
* at most one node, leaf, block start or block end per line&lt;br /&gt;
* empty lines are accepted&lt;br /&gt;
* comments can either:&lt;br /&gt;
:* start with &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and go to the end of line&lt;br /&gt;
:* start with &amp;lt;code&amp;gt;/*&amp;lt;/code&amp;gt; and go to next &amp;lt;code&amp;gt;*/&amp;lt;/code&amp;gt;, including out of current line (TODO: verify).&lt;br /&gt;
* comments can not be nested&lt;br /&gt;
* actions and conditions taking parameters must enclose those withing parentheses, separated with commas (i.e. &amp;lt;code&amp;gt;roamInRadius( E_H_REACTOR, 500 )&amp;lt;/code&amp;gt;)&lt;br /&gt;
* if an action or a condition does not need parameters, parentheses are optional&lt;br /&gt;
* spaces and tabulations are meaningless&lt;br /&gt;
* strings start and end with a double quote &amp;lt;code&amp;gt;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
* keywords are reserved (TODO: verify, but even if wrong, better avoid their use)&lt;br /&gt;
* values can't be stored or modified (additions, subtractions, multiplications, etc)&lt;br /&gt;
* no user-defined function (but files can be included, and C++ functions can be written in the game logic and be used in the behavior tree)&lt;br /&gt;
* each possible path should (TODO: verify, even if I fail to understand why one would break that willingly) end by one or more action&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
It is not possible to do mathematical operations such as additions, multiplications, divisions, ...&lt;br /&gt;
&lt;br /&gt;
== Keywords ==&lt;br /&gt;
&lt;br /&gt;
There are several keywords:&lt;br /&gt;
&lt;br /&gt;
* behavior&lt;br /&gt;
* action&lt;br /&gt;
* sequence&lt;br /&gt;
* selector&lt;br /&gt;
* concurrent&lt;br /&gt;
* decorator&lt;br /&gt;
* condition&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;behavior&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 behavior NAME&lt;br /&gt;
&lt;br /&gt;
Include named behavior at current place.&lt;br /&gt;
It is unsure if this is just an inclusion of if the subtree is parsed and stored individually.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;action&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 action NAME&lt;br /&gt;
&lt;br /&gt;
 action NAME()&lt;br /&gt;
&lt;br /&gt;
 action NAME( param )&lt;br /&gt;
&lt;br /&gt;
 action NAME( param1, param2, ..., paramN )&lt;br /&gt;
&lt;br /&gt;
Leaves of the tree, they trigger an action from the bot.&lt;br /&gt;
&lt;br /&gt;
=== List of actions ===&lt;br /&gt;
&lt;br /&gt;
Titles provide a link to more detailed pages.&lt;br /&gt;
TODO: have something more time-resilient (one page per call, with it's changelog, maybe?)&lt;br /&gt;
&lt;br /&gt;
==== [[0.52]] ====&lt;br /&gt;
&lt;br /&gt;
* activateUpgrade&lt;br /&gt;
* aimAtGoal&lt;br /&gt;
* alternateStrafe&lt;br /&gt;
* buy&lt;br /&gt;
* changeGoal&lt;br /&gt;
* classDodge&lt;br /&gt;
* deactivateUpgrade&lt;br /&gt;
* equip&lt;br /&gt;
* evolve&lt;br /&gt;
* evolveTo&lt;br /&gt;
* fight&lt;br /&gt;
* fireWeapon&lt;br /&gt;
* flee&lt;br /&gt;
* heal&lt;br /&gt;
* jump&lt;br /&gt;
* moveInDir&lt;br /&gt;
* moveTo&lt;br /&gt;
* moveToGoal&lt;br /&gt;
* repair&lt;br /&gt;
* resetStuckTime&lt;br /&gt;
* roam&lt;br /&gt;
* roamInRadius&lt;br /&gt;
* rush&lt;br /&gt;
* say&lt;br /&gt;
* strafeDodge&lt;br /&gt;
* suicide&lt;br /&gt;
&lt;br /&gt;
=== Creating new actions ===&lt;br /&gt;
&lt;br /&gt;
Actions are exported in the &amp;lt;code&amp;gt;AIActionMap_s AIActions[]&amp;lt;/code&amp;gt; C array.&lt;br /&gt;
Actions always return a status.&lt;br /&gt;
Actions can take a variable number of parameters (they have minimum and maximum parameter numbers).&lt;br /&gt;
Parameter types are not described by API.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;concurrent&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 concurrent&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
 	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Concurrent nodes evaluate each children until one returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;.&lt;br /&gt;
Differences with sequence:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt; does not trigger a return&lt;br /&gt;
* Returns either &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt; except if one child failed &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* if 2 tasks were previously in &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt; and the 1st returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;, concurrent returns immediately.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;sequence&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 sequence&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
  	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Sequential nodes evaluate each children one after the other, as long as they return &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt;.&lt;br /&gt;
Return last child's status.&lt;br /&gt;
&lt;br /&gt;
Differences with concurrent:&lt;br /&gt;
&lt;br /&gt;
* Sequence breaks if a child returns &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;&lt;br /&gt;
* Starts at last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;, if any&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;selector&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 selector&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
 	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Selector nodes evaluate each children one after the other, as long as they return &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt;.&lt;br /&gt;
Return last child's status.&lt;br /&gt;
Does not restart from last &amp;lt;code&amp;gt;STATUS_RUNNING&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;decorator&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
 decorator TYPE( VALUE )&lt;br /&gt;
 {&lt;br /&gt;
 	NODE_1&lt;br /&gt;
 	NODE_2&lt;br /&gt;
 	...&lt;br /&gt;
 	NODE_N&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Decorator nodes alters their children's behavior.&lt;br /&gt;
Decorator types:&lt;br /&gt;
&lt;br /&gt;
* return&lt;br /&gt;
* timer&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
Force children nodes to return a specific value&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;timer&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
On encountering a &amp;lt;code&amp;gt;timer( &amp;lt;i&amp;gt;N&amp;lt;/i&amp;gt; )&amp;lt;/code&amp;gt; node, STATUS_FAILURE is immediately returned if the timer's child node has already returned STATUS_FAILURE within the last N milliseconds.&lt;br /&gt;
&lt;br /&gt;
The node may run more often than every N milliseconds if it keeps returning success.&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;condition&amp;lt;/code&amp;gt; keyword ==&lt;br /&gt;
&lt;br /&gt;
  condition EXPRESSION&lt;br /&gt;
&lt;br /&gt;
  condition EXPRESSION&lt;br /&gt;
  {&lt;br /&gt;
  	NODE&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
The first form immediately returns ''EXPRESSION'' as its status: &amp;lt;code&amp;gt;STATUS_SUCCESS&amp;lt;/code&amp;gt; for true and &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; for false.&lt;br /&gt;
&lt;br /&gt;
The second form returns &amp;lt;code&amp;gt;STATUS_FAILURE&amp;lt;/code&amp;gt; if the expression is false, or otherwise the child's status. Note that ''EXPRESSION'' is re-evaluated every frame. If it becomes false at any time during execution of the child node, the child subtree aborts and the condition node returns failure.&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
* only executes a single child.&lt;br /&gt;
* EXPRESSION can include function calls.&lt;br /&gt;
&lt;br /&gt;
== Operators ==&lt;br /&gt;
&lt;br /&gt;
Operators are listed in the &amp;lt;code&amp;gt;AIOpMap_s conditionOps[]&amp;lt;/code&amp;gt; array.&lt;br /&gt;
operators sorted by precedence (1st have higher priority):&lt;br /&gt;
* &amp;quot;! &amp;quot;&lt;br /&gt;
* &amp;quot;&amp;lt; &amp;quot;&lt;br /&gt;
* &amp;quot;&amp;lt;=&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;gt; &amp;quot;&lt;br /&gt;
* &amp;quot;&amp;gt;=&amp;quot;&lt;br /&gt;
* &amp;quot;==&amp;quot;&lt;br /&gt;
* &amp;quot;!=&amp;quot;&lt;br /&gt;
* &amp;quot;&amp;amp;&amp;amp;&amp;quot;&lt;br /&gt;
* &amp;quot;||&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Functions ==&lt;br /&gt;
&lt;br /&gt;
Return value is &amp;quot;boxed&amp;quot; (&amp;lt;code&amp;gt;AIBox&amp;lt;T&amp;gt;()&amp;lt;/code&amp;gt;) in the C++ code.&lt;br /&gt;
Conditions are exported in the &amp;lt;code&amp;gt;AIConditionMap_s conditionFuncs[]&amp;lt;/code&amp;gt; array.&lt;br /&gt;
&lt;br /&gt;
=== List of functions (as of 0.52) ===&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;alienMomentum&amp;quot;,     VALUE_INT,   alienMomentum,     0 }, &lt;br /&gt;
 { &amp;quot;humanMomentum&amp;quot;,     VALUE_INT,   humanMomentum,     0 }, &lt;br /&gt;
 { &amp;quot;alertedToEnemy&amp;quot;,    VALUE_INT,   alertedToEnemy,    0 }, &lt;br /&gt;
 { &amp;quot;baseRushScore&amp;quot;,     VALUE_FLOAT, baseRushScore,     0 }, &lt;br /&gt;
 { &amp;quot;buildingIsDamaged&amp;quot;, VALUE_INT,   buildingIsDamaged, 0 }, &lt;br /&gt;
 { &amp;quot;canEvolveTo&amp;quot;,       VALUE_INT,   botCanEvolveTo,    1 }, &lt;br /&gt;
 { &amp;quot;class&amp;quot;,             VALUE_INT,   botClass,          0 }, &lt;br /&gt;
 { &amp;quot;cvarFloat&amp;quot;,         VALUE_FLOAT, cvarFloat,         1 }, &lt;br /&gt;
 { &amp;quot;cvarInt&amp;quot;,           VALUE_INT,   cvarInt,           1 }, &lt;br /&gt;
 { &amp;quot;directPathTo&amp;quot;,      VALUE_INT,   directPathTo,      1 }, &lt;br /&gt;
 { &amp;quot;distanceTo&amp;quot;,        VALUE_FLOAT, distanceTo,        1 }, &lt;br /&gt;
 { &amp;quot;goalBuildingType&amp;quot;,  VALUE_INT,   goalBuildingType,  0 }, &lt;br /&gt;
 { &amp;quot;goalIsDead&amp;quot;,        VALUE_INT,   goalDead,          0 }, &lt;br /&gt;
 { &amp;quot;goalTeam&amp;quot;,          VALUE_INT,   goalTeam,          0 }, &lt;br /&gt;
 { &amp;quot;goalType&amp;quot;,          VALUE_INT,   goalType,          0 }, &lt;br /&gt;
 { &amp;quot;haveUpgrade&amp;quot;,       VALUE_INT,   haveUpgrade,       1 }, &lt;br /&gt;
 { &amp;quot;haveWeapon&amp;quot;,        VALUE_INT,   haveWeapon,        1 }, &lt;br /&gt;
 { &amp;quot;healScore&amp;quot;,         VALUE_FLOAT, healScore,         0 }, &lt;br /&gt;
 { &amp;quot;inAttackRange&amp;quot;,     VALUE_INT,   inAttackRange,     1 }, &lt;br /&gt;
 { &amp;quot;isVisible&amp;quot;,         VALUE_INT,   isVisible,         1 }, &lt;br /&gt;
 { &amp;quot;percentAmmo&amp;quot;,       VALUE_FLOAT, percentAmmo,       0 }, &lt;br /&gt;
 { &amp;quot;percentHealth&amp;quot;,     VALUE_FLOAT, percentHealth,     1 }, &lt;br /&gt;
 { &amp;quot;random&amp;quot;,            VALUE_FLOAT, randomChance,      0 }, &lt;br /&gt;
 { &amp;quot;skill&amp;quot;,             VALUE_INT,   botSkill,          0 }, &lt;br /&gt;
 { &amp;quot;stuckTime&amp;quot;,         VALUE_INT,   stuckTime,         0 }, &lt;br /&gt;
 { &amp;quot;team&amp;quot;,              VALUE_INT,   botTeam,           0 }, &lt;br /&gt;
 { &amp;quot;teamateHasWeapon&amp;quot;,  VALUE_INT,   teamateHasWeapon,  1 }, &lt;br /&gt;
 { &amp;quot;weapon&amp;quot;,            VALUE_INT,   currentWeapon,     0 },&lt;br /&gt;
&lt;br /&gt;
== Pre-defined symbols ==&lt;br /&gt;
&lt;br /&gt;
Some values are pre-defined and usable as action's or function's parameters.&lt;br /&gt;
&lt;br /&gt;
Those are exported by calling a macro named 'D' (yes, I know).&lt;br /&gt;
List of exported symbols:&lt;br /&gt;
&lt;br /&gt;
* human upgrades (including medkit)&lt;br /&gt;
* human weapons (excluding blaster)&lt;br /&gt;
* team names (aliens, humans, and none)&lt;br /&gt;
* alien buildings&lt;br /&gt;
* human buildings&lt;br /&gt;
* &amp;lt;code&amp;gt;E_GOAL&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;E_ENEMY&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;E_DAMAGEDBUILDING&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;E_SELF&amp;lt;/code&amp;gt;&lt;br /&gt;
* classes (human ones, alien ones, and &amp;lt;code&amp;gt;PCL_NONE&amp;lt;/code&amp;gt;)&lt;br /&gt;
* moves (forward, backward, right, left)&lt;br /&gt;
* some say commands (all, team, area, area_team)&lt;br /&gt;
* task/check status names (running, success, failure)&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
&lt;br /&gt;
Parameters needs to be (un)wrapped in C++ before being accessed.&lt;br /&gt;
&lt;br /&gt;
Parameters can be of the following (C) types:&lt;br /&gt;
* float&lt;br /&gt;
* int (probably better assume 32 bit signed integers)&lt;br /&gt;
* string (probably better assume null-terminated)&lt;br /&gt;
* double (Unboxed only)&lt;br /&gt;
* token (Boxed only, either a &amp;lt;code&amp;gt;TT_STRING&amp;lt;/code&amp;gt;, a float or an int...)&lt;br /&gt;
&lt;br /&gt;
To provide a value to an action or check, the C++ code must UnBox (&amp;lt;code&amp;gt;AIUnBox&amp;lt;T&amp;gt;()&amp;lt;/code&amp;gt;) it.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Modder_Documentation:_classes_.attr.cfg&amp;diff=5217</id>
		<title>Modder Documentation: classes .attr.cfg</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Modder_Documentation:_classes_.attr.cfg&amp;diff=5217"/>
		<updated>2021-10-25T16:57:08Z</updated>

		<summary type="html">&lt;p&gt;Afontain: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here are some of the fields present in an &amp;lt;code&amp;gt;pkg/unvanquished_src.dpkdir/configs/classes/'''''class'''''.attr.cfg&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Metadata ==&lt;br /&gt;
 description &amp;quot;null&amp;quot;&lt;br /&gt;
 icon &amp;quot;null&amp;quot;&lt;br /&gt;
 fovCvar &amp;quot;cg_fov_human&amp;quot;&lt;br /&gt;
 team human&lt;br /&gt;
 unlockThreshold 0&lt;br /&gt;
&lt;br /&gt;
TODO: document&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Health ==&lt;br /&gt;
&lt;br /&gt;
here's an ''attr.cfg'' extract:&lt;br /&gt;
 health 100 &lt;br /&gt;
 fallDamage 1.0 &lt;br /&gt;
 regen 0.0&lt;br /&gt;
&lt;br /&gt;
in it we see:&lt;br /&gt;
* &amp;lt;code&amp;gt;health&amp;lt;/code&amp;gt; how many hp the form have (note that this doesn't work for humans as of 0.52.1)&lt;br /&gt;
* &amp;lt;code&amp;gt;fallDamage&amp;lt;/code&amp;gt; how much hp is lost when falling. 1.0 is &amp;quot;as much as a normal human&amp;quot;. Note that it is also affected by armor if armor is worn (&amp;quot;nonloc&amp;quot; damage)&lt;br /&gt;
* &amp;lt;code&amp;gt;regen&amp;lt;/code&amp;gt; how many hp/second are recovered when the creature hasn't been hurt for some time&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== View ==&lt;br /&gt;
&lt;br /&gt;
here's an ''attr.cfg'' extract:&lt;br /&gt;
 //View parameters&lt;br /&gt;
 fov 90&lt;br /&gt;
 bob 0.001&lt;br /&gt;
 bobCycle 1.1 &lt;br /&gt;
 stepTime 100 &lt;br /&gt;
&lt;br /&gt;
TODO: explain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Movement and mass parameters ==&lt;br /&gt;
&lt;br /&gt;
here's an ''attr.cfg'' extract:&lt;br /&gt;
 // Physics parameters&lt;br /&gt;
 speed 1.1&lt;br /&gt;
 sprintMod 1.2&lt;br /&gt;
 acceleration 10.0&lt;br /&gt;
 airAcceleration 1.0 &lt;br /&gt;
 friction 7 &lt;br /&gt;
 stopSpeed 100.0&lt;br /&gt;
 jumpMagnitude 170.0&lt;br /&gt;
&lt;br /&gt;
in it we see:&lt;br /&gt;
* &amp;lt;code&amp;gt;speed&amp;lt;/code&amp;gt; the maximum speed (relative: 1.0 is the speed of a naked human)&lt;br /&gt;
* &amp;lt;code&amp;gt;sprintMod&amp;lt;/code&amp;gt; (only makes sense for humans) how much sprinting accelerates (relative: 2.0 is the double of the normal &amp;lt;code&amp;gt;speed&amp;lt;/code&amp;gt;)&lt;br /&gt;
* &amp;lt;code&amp;gt;acceleration&amp;lt;/code&amp;gt; how fast can you change speed while touching the ground&lt;br /&gt;
* &amp;lt;code&amp;gt;airAcceleration&amp;lt;/code&amp;gt; how fast can you change speed while in the air: you'll notice that a marauder can easily change direction on the ground, but has more trouble steering in the air.&lt;br /&gt;
* &amp;lt;code&amp;gt;friction&amp;lt;/code&amp;gt; how fast is speed lost. Note that if it is high (in the hundreds), it will actually limit your max speed noticeably.&lt;br /&gt;
* &amp;lt;code&amp;gt;stopSpeed&amp;lt;/code&amp;gt; means the speed under which the speed will be set to 0.&lt;br /&gt;
* &amp;lt;code&amp;gt;jumpMagnitude&amp;lt;/code&amp;gt; is how high you can jump.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Abilities ==&lt;br /&gt;
here are some possible values (''attr.cfg'' extract):&lt;br /&gt;
 // Abilities&lt;br /&gt;
 takesFallDamage&lt;br /&gt;
 canUseLadders&lt;br /&gt;
 wallRunner&lt;br /&gt;
 slider&lt;br /&gt;
 alienSense&lt;br /&gt;
 fovWarps&lt;br /&gt;
&lt;br /&gt;
TODO: explain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Stamina (humans) ==&lt;br /&gt;
here's an ''attr.cfg'' extract:&lt;br /&gt;
 // Stamina (per action or second)&lt;br /&gt;
 staminaJumpCost    3750&lt;br /&gt;
 staminaSprintCost  750 &lt;br /&gt;
 staminaJogRestore  750 &lt;br /&gt;
 staminaWalkRestore 2250&lt;br /&gt;
 staminaStopRestore 4500&lt;br /&gt;
&lt;br /&gt;
in it we see:&lt;br /&gt;
* &amp;lt;code&amp;gt;staminaJumpCost&amp;lt;/code&amp;gt; how much stamina you spend for a jump&lt;br /&gt;
* &amp;lt;code&amp;gt;staminaSprintCost&amp;lt;/code&amp;gt; how much stamina you spend per second when running&lt;br /&gt;
* &amp;lt;code&amp;gt;staminaJogRestore&amp;lt;/code&amp;gt; how fast you recover your stamina (amount per second) '''while walking but not running'''&lt;br /&gt;
* &amp;lt;code&amp;gt;staminaWalkRestore&amp;lt;/code&amp;gt; how fast you recover your stamina (amount per second) '''while walking slowly or crouching'''&lt;br /&gt;
* &amp;lt;code&amp;gt;staminaStopRestore&amp;lt;/code&amp;gt; how fast you recover your stamina (amount per second) when not moving&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Miscs ==&lt;br /&gt;
here's an ''attr.cfg'' extract:&lt;br /&gt;
 // Misc&lt;br /&gt;
 cost 200&lt;br /&gt;
 buildDistance 110.0&lt;br /&gt;
&lt;br /&gt;
in it we see:&lt;br /&gt;
* &amp;lt;code&amp;gt;cost&amp;lt;/code&amp;gt; how much it costs to buy the class or the object. From 0 to 2000 (for all teams)&lt;br /&gt;
* &amp;lt;code&amp;gt;buildDistance&amp;lt;/code&amp;gt; the maximum distance this form can build (assuming a suitable weapon and class)&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Modder_Documentation:_classes_.attr.cfg&amp;diff=5216</id>
		<title>Modder Documentation: classes .attr.cfg</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Modder_Documentation:_classes_.attr.cfg&amp;diff=5216"/>
		<updated>2021-10-25T16:56:45Z</updated>

		<summary type="html">&lt;p&gt;Afontain: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here are some of the fields present in an &amp;lt;code&amp;gt;pkg/unvanquished_src.dpkdir/configs/classes/'''''class'''''.attr.cfg&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Metadata ==&lt;br /&gt;
 description &amp;quot;null&amp;quot;&lt;br /&gt;
 icon &amp;quot;null&amp;quot;&lt;br /&gt;
 fovCvar &amp;quot;cg_fov_human&amp;quot;&lt;br /&gt;
 team human&lt;br /&gt;
 unlockThreshold 0&lt;br /&gt;
&lt;br /&gt;
TODO: document&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Health ==&lt;br /&gt;
&lt;br /&gt;
here's an ''attr.cfg'' extract:&lt;br /&gt;
 health 100 &lt;br /&gt;
 fallDamage 1.0 &lt;br /&gt;
 regen 0.0&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;health&amp;lt;/code&amp;gt; how many hp the form have (note that this doesn't work for humans as of 0.52.1)&lt;br /&gt;
* &amp;lt;code&amp;gt;fallDamage&amp;lt;/code&amp;gt; how much hp is lost when falling. 1.0 is &amp;quot;as much as a normal human&amp;quot;. Note that it is also affected by armor if armor is worn (&amp;quot;nonloc&amp;quot; damage)&lt;br /&gt;
* &amp;lt;code&amp;gt;regen&amp;lt;/code&amp;gt; how many hp/second are recovered when the creature hasn't been hurt for some time&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== View ==&lt;br /&gt;
&lt;br /&gt;
here's an ''attr.cfg'' extract:&lt;br /&gt;
 //View parameters&lt;br /&gt;
 fov 90&lt;br /&gt;
 bob 0.001&lt;br /&gt;
 bobCycle 1.1 &lt;br /&gt;
 stepTime 100 &lt;br /&gt;
&lt;br /&gt;
TODO: explain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Movement and mass parameters ==&lt;br /&gt;
&lt;br /&gt;
here's an ''attr.cfg'' extract:&lt;br /&gt;
 // Physics parameters&lt;br /&gt;
 speed 1.1&lt;br /&gt;
 sprintMod 1.2&lt;br /&gt;
 acceleration 10.0&lt;br /&gt;
 airAcceleration 1.0 &lt;br /&gt;
 friction 7 &lt;br /&gt;
 stopSpeed 100.0&lt;br /&gt;
 jumpMagnitude 170.0&lt;br /&gt;
&lt;br /&gt;
in it we see:&lt;br /&gt;
* &amp;lt;code&amp;gt;speed&amp;lt;/code&amp;gt; the maximum speed (relative: 1.0 is the speed of a naked human)&lt;br /&gt;
* &amp;lt;code&amp;gt;sprintMod&amp;lt;/code&amp;gt; (only makes sense for humans) how much sprinting accelerates (relative: 2.0 is the double of the normal &amp;lt;code&amp;gt;speed&amp;lt;/code&amp;gt;)&lt;br /&gt;
* &amp;lt;code&amp;gt;acceleration&amp;lt;/code&amp;gt; how fast can you change speed while touching the ground&lt;br /&gt;
* &amp;lt;code&amp;gt;airAcceleration&amp;lt;/code&amp;gt; how fast can you change speed while in the air: you'll notice that a marauder can easily change direction on the ground, but has more trouble steering in the air.&lt;br /&gt;
* &amp;lt;code&amp;gt;friction&amp;lt;/code&amp;gt; how fast is speed lost. Note that if it is high (in the hundreds), it will actually limit your max speed noticeably.&lt;br /&gt;
* &amp;lt;code&amp;gt;stopSpeed&amp;lt;/code&amp;gt; means the speed under which the speed will be set to 0.&lt;br /&gt;
* &amp;lt;code&amp;gt;jumpMagnitude&amp;lt;/code&amp;gt; is how high you can jump.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Abilities ==&lt;br /&gt;
here are some possible values (''attr.cfg'' extract):&lt;br /&gt;
 // Abilities&lt;br /&gt;
 takesFallDamage&lt;br /&gt;
 canUseLadders&lt;br /&gt;
 wallRunner&lt;br /&gt;
 slider&lt;br /&gt;
 alienSense&lt;br /&gt;
 fovWarps&lt;br /&gt;
&lt;br /&gt;
TODO: explain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Stamina (humans) ==&lt;br /&gt;
here's an ''attr.cfg'' extract:&lt;br /&gt;
 // Stamina (per action or second)&lt;br /&gt;
 staminaJumpCost    3750&lt;br /&gt;
 staminaSprintCost  750 &lt;br /&gt;
 staminaJogRestore  750 &lt;br /&gt;
 staminaWalkRestore 2250&lt;br /&gt;
 staminaStopRestore 4500&lt;br /&gt;
&lt;br /&gt;
in it we see:&lt;br /&gt;
* &amp;lt;code&amp;gt;staminaJumpCost&amp;lt;/code&amp;gt; how much stamina you spend for a jump&lt;br /&gt;
* &amp;lt;code&amp;gt;staminaSprintCost&amp;lt;/code&amp;gt; how much stamina you spend per second when running&lt;br /&gt;
* &amp;lt;code&amp;gt;staminaJogRestore&amp;lt;/code&amp;gt; how fast you recover your stamina (amount per second) '''while walking but not running'''&lt;br /&gt;
* &amp;lt;code&amp;gt;staminaWalkRestore&amp;lt;/code&amp;gt; how fast you recover your stamina (amount per second) '''while walking slowly or crouching'''&lt;br /&gt;
* &amp;lt;code&amp;gt;staminaStopRestore&amp;lt;/code&amp;gt; how fast you recover your stamina (amount per second) when not moving&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Miscs ==&lt;br /&gt;
here's an ''attr.cfg'' extract:&lt;br /&gt;
 // Misc&lt;br /&gt;
 cost 200&lt;br /&gt;
 buildDistance 110.0&lt;br /&gt;
&lt;br /&gt;
in it we see:&lt;br /&gt;
* &amp;lt;code&amp;gt;cost&amp;lt;/code&amp;gt; how much it costs to buy the class or the object. From 0 to 2000 (for all teams)&lt;br /&gt;
* &amp;lt;code&amp;gt;buildDistance&amp;lt;/code&amp;gt; the maximum distance this form can build (assuming a suitable weapon and class)&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Modder_Documentation:_classes_.attr.cfg&amp;diff=5215</id>
		<title>Modder Documentation: classes .attr.cfg</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Modder_Documentation:_classes_.attr.cfg&amp;diff=5215"/>
		<updated>2021-10-25T16:48:52Z</updated>

		<summary type="html">&lt;p&gt;Afontain: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here are some of the fields present in an &amp;lt;code&amp;gt;pkg/unvanquished_src.dpkdir/configs/classes/'''''class'''''.attr.cfg&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Metadata ==&lt;br /&gt;
 description &amp;quot;null&amp;quot;&lt;br /&gt;
 icon &amp;quot;null&amp;quot;&lt;br /&gt;
 fovCvar &amp;quot;cg_fov_human&amp;quot;&lt;br /&gt;
 team human&lt;br /&gt;
 unlockThreshold 0&lt;br /&gt;
&lt;br /&gt;
TODO: document&lt;br /&gt;
&lt;br /&gt;
== Health ==&lt;br /&gt;
&lt;br /&gt;
here's an ''attr.cfg'' extract:&lt;br /&gt;
 health 100 &lt;br /&gt;
 fallDamage 1.0 &lt;br /&gt;
 regen 0.0&lt;br /&gt;
&lt;br /&gt;
this should be clear enough&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== View ==&lt;br /&gt;
&lt;br /&gt;
here's an ''attr.cfg'' extract:&lt;br /&gt;
 //View parameters&lt;br /&gt;
 fov 90&lt;br /&gt;
 bob 0.001&lt;br /&gt;
 bobCycle 1.1 &lt;br /&gt;
 stepTime 100 &lt;br /&gt;
&lt;br /&gt;
TODO: explain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Movement and mass parameters ==&lt;br /&gt;
&lt;br /&gt;
here's an ''attr.cfg'' extract:&lt;br /&gt;
 // Physics parameters&lt;br /&gt;
 speed 1.1&lt;br /&gt;
 sprintMod 1.2&lt;br /&gt;
 acceleration 10.0&lt;br /&gt;
 airAcceleration 1.0 &lt;br /&gt;
 friction 7 &lt;br /&gt;
 stopSpeed 100.0&lt;br /&gt;
 jumpMagnitude 170.0&lt;br /&gt;
&lt;br /&gt;
in it we see:&lt;br /&gt;
* &amp;lt;code&amp;gt;speed&amp;lt;/code&amp;gt; the maximum speed (relative: 1.0 is the speed of a naked human)&lt;br /&gt;
* &amp;lt;code&amp;gt;sprintMod&amp;lt;/code&amp;gt; (only makes sense for humans) how much sprinting accelerates (relative: 2.0 is the double of the normal &amp;lt;code&amp;gt;speed&amp;lt;/code&amp;gt;)&lt;br /&gt;
* &amp;lt;code&amp;gt;acceleration&amp;lt;/code&amp;gt; how fast can you change speed while touching the ground&lt;br /&gt;
* &amp;lt;code&amp;gt;airAcceleration&amp;lt;/code&amp;gt; how fast can you change speed while in the air: you'll notice that a marauder can easily change direction on the ground, but has more trouble steering in the air.&lt;br /&gt;
* &amp;lt;code&amp;gt;friction&amp;lt;/code&amp;gt; how fast is speed lost. Note that if it is high (in the hundreds), it will actually limit your max speed noticeably.&lt;br /&gt;
* &amp;lt;code&amp;gt;stopSpeed&amp;lt;/code&amp;gt; means the speed under which the speed will be set to 0.&lt;br /&gt;
* &amp;lt;code&amp;gt;jumpMagnitude&amp;lt;/code&amp;gt; is how high you can jump.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Abilities ==&lt;br /&gt;
here are some possible values (''attr.cfg'' extract):&lt;br /&gt;
 // Abilities&lt;br /&gt;
 takesFallDamage&lt;br /&gt;
 canUseLadders&lt;br /&gt;
 wallRunner&lt;br /&gt;
 slider&lt;br /&gt;
 alienSense&lt;br /&gt;
 fovWarps&lt;br /&gt;
&lt;br /&gt;
TODO: explain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Stamina (humans) ==&lt;br /&gt;
here's an ''attr.cfg'' extract:&lt;br /&gt;
 // Stamina (per action or second)&lt;br /&gt;
 staminaJumpCost    3750&lt;br /&gt;
 staminaSprintCost  750 &lt;br /&gt;
 staminaJogRestore  750 &lt;br /&gt;
 staminaWalkRestore 2250&lt;br /&gt;
 staminaStopRestore 4500&lt;br /&gt;
&lt;br /&gt;
in it we see:&lt;br /&gt;
* &amp;lt;code&amp;gt;staminaJumpCost&amp;lt;/code&amp;gt; how much stamina you spend for a jump&lt;br /&gt;
* &amp;lt;code&amp;gt;staminaSprintCost&amp;lt;/code&amp;gt; how much stamina you spend per second when running&lt;br /&gt;
* &amp;lt;code&amp;gt;staminaJogRestore&amp;lt;/code&amp;gt; how fast you recover your stamina (amount per second) '''while walking but not running'''&lt;br /&gt;
* &amp;lt;code&amp;gt;staminaWalkRestore&amp;lt;/code&amp;gt; how fast you recover your stamina (amount per second) '''while walking slowly or crouching'''&lt;br /&gt;
* &amp;lt;code&amp;gt;staminaStopRestore&amp;lt;/code&amp;gt; how fast you recover your stamina (amount per second) when not moving&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Miscs ==&lt;br /&gt;
here's an ''attr.cfg'' extract:&lt;br /&gt;
 // Misc&lt;br /&gt;
 cost 200&lt;br /&gt;
 buildDistance 110.0&lt;br /&gt;
&lt;br /&gt;
in it we see:&lt;br /&gt;
* &amp;lt;code&amp;gt;cost&amp;lt;/code&amp;gt; how much it costs to buy the class or the object. From 0 to 2000 (for all teams)&lt;br /&gt;
* &amp;lt;code&amp;gt;buildDistance&amp;lt;/code&amp;gt; the maximum distance this form can build (assuming a suitable weapon and class)&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Modder_Documentation:_classes_.attr.cfg&amp;diff=5214</id>
		<title>Modder Documentation: classes .attr.cfg</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Modder_Documentation:_classes_.attr.cfg&amp;diff=5214"/>
		<updated>2021-10-25T16:28:51Z</updated>

		<summary type="html">&lt;p&gt;Afontain: created&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here are some of the fields present in an &amp;lt;code&amp;gt;pkg/unvanquished_src.dpkdir/configs/classes/'''''form'''''.attr.cfg&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Metadata ==&lt;br /&gt;
 description &amp;quot;null&amp;quot;&lt;br /&gt;
 icon &amp;quot;null&amp;quot;&lt;br /&gt;
 fovCvar &amp;quot;cg_fov_human&amp;quot;&lt;br /&gt;
 team human&lt;br /&gt;
 unlockThreshold 0&lt;br /&gt;
&lt;br /&gt;
TODO: document&lt;br /&gt;
&lt;br /&gt;
== Health ==&lt;br /&gt;
&lt;br /&gt;
here's an ''attr.cfg'' extract:&lt;br /&gt;
 health 100 &lt;br /&gt;
 fallDamage 1.0 &lt;br /&gt;
 regen 0.0&lt;br /&gt;
&lt;br /&gt;
this should be clear enough&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== View ==&lt;br /&gt;
&lt;br /&gt;
here's an ''attr.cfg'' extract:&lt;br /&gt;
 //View parameters&lt;br /&gt;
 fov 90&lt;br /&gt;
 bob 0.001&lt;br /&gt;
 bobCycle 1.1 &lt;br /&gt;
 stepTime 100 &lt;br /&gt;
&lt;br /&gt;
TODO: explain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Movement and mass parameters ==&lt;br /&gt;
&lt;br /&gt;
here's an ''attr.cfg'' extract:&lt;br /&gt;
 // Physics parameters&lt;br /&gt;
 speed 1.1&lt;br /&gt;
 sprintMod 1.2&lt;br /&gt;
 acceleration 10.0&lt;br /&gt;
 airAcceleration 1.0 &lt;br /&gt;
 friction 7 &lt;br /&gt;
 stopSpeed 100.0&lt;br /&gt;
 jumpMagnitude 170.0&lt;br /&gt;
&lt;br /&gt;
in it we see:&lt;br /&gt;
* &amp;lt;code&amp;gt;speed&amp;lt;/code&amp;gt; the maximum speed (relative: 1.0 is the speed of a naked human)&lt;br /&gt;
* &amp;lt;code&amp;gt;sprintMod&amp;lt;/code&amp;gt; (only makes sense for humans) how much sprinting accelerates (relative: 2.0 is the double of the normal &amp;lt;code&amp;gt;speed&amp;lt;/code&amp;gt;)&lt;br /&gt;
* &amp;lt;code&amp;gt;acceleration&amp;lt;/code&amp;gt; how fast can you change speed while touching the ground&lt;br /&gt;
* &amp;lt;code&amp;gt;airAcceleration&amp;lt;/code&amp;gt; how fast can you change speed while in the air: you'll notice that a marauder can easily change direction on the ground, but has more trouble steering in the air.&lt;br /&gt;
* &amp;lt;code&amp;gt;friction&amp;lt;/code&amp;gt; how fast is speed lost. Note that if it is high (in the hundreds), it will actually limit your max speed noticeably.&lt;br /&gt;
* &amp;lt;code&amp;gt;stopSpeed&amp;lt;/code&amp;gt; means the speed under which the speed will be set to 0.&lt;br /&gt;
* &amp;lt;code&amp;gt;jumpMagnitude&amp;lt;/code&amp;gt; is how high you can jump.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Abilities ==&lt;br /&gt;
here are some possible values (''attr.cfg'' extract):&lt;br /&gt;
 // Abilities&lt;br /&gt;
 takesFallDamage&lt;br /&gt;
 canUseLadders&lt;br /&gt;
 wallRunner&lt;br /&gt;
 slider&lt;br /&gt;
 alienSense&lt;br /&gt;
 fovWarps&lt;br /&gt;
&lt;br /&gt;
TODO: explain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Stamina (humans) ==&lt;br /&gt;
here's an ''attr.cfg'' extract:&lt;br /&gt;
 // Stamina (per action or second)&lt;br /&gt;
 staminaJumpCost    3750&lt;br /&gt;
 staminaSprintCost  750 &lt;br /&gt;
 staminaJogRestore  750 &lt;br /&gt;
 staminaWalkRestore 2250&lt;br /&gt;
 staminaStopRestore 4500&lt;br /&gt;
&lt;br /&gt;
in it we see:&lt;br /&gt;
* &amp;lt;code&amp;gt;staminaJumpCost&amp;lt;/code&amp;gt; how much stamina you spend for a jump&lt;br /&gt;
* &amp;lt;code&amp;gt;staminaSprintCost&amp;lt;/code&amp;gt; how much stamina you spend per second when running&lt;br /&gt;
* &amp;lt;code&amp;gt;staminaJogRestore&amp;lt;/code&amp;gt; how fast you recover your stamina (amount per second) '''while walking but not running'''&lt;br /&gt;
* &amp;lt;code&amp;gt;staminaWalkRestore&amp;lt;/code&amp;gt; how fast you recover your stamina (amount per second) '''while walking slowly or crouching'''&lt;br /&gt;
* &amp;lt;code&amp;gt;staminaStopRestore&amp;lt;/code&amp;gt; how fast you recover your stamina (amount per second) when not moving&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Miscs ==&lt;br /&gt;
here's an ''attr.cfg'' extract:&lt;br /&gt;
 // Misc&lt;br /&gt;
 cost 200&lt;br /&gt;
 buildDistance 110.0&lt;br /&gt;
&lt;br /&gt;
in it we see:&lt;br /&gt;
* &amp;lt;code&amp;gt;cost&amp;lt;/code&amp;gt; how much it costs to buy the class or the object. From 0 to 2000 (for all teams)&lt;br /&gt;
* &amp;lt;code&amp;gt;buildDistance&amp;lt;/code&amp;gt; the maximum distance this form can build (assuming a suitable weapon and class)&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Compatibility&amp;diff=5211</id>
		<title>Compatibility</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Compatibility&amp;diff=5211"/>
		<updated>2021-10-17T20:18:31Z</updated>

		<summary type="html">&lt;p&gt;Afontain: /* Daemon */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Inter-module compatibility =&lt;br /&gt;
&lt;br /&gt;
Unvanquished has many software components: engine binaries, based on the Daemon repository (client and server); gamelogic binaries, based on the Unvanquished repository (cgame and sgame); and various other files shipped in DPKs, which may be used by any of the binaries. Currently, all components are on a single release cycle. A given user normally has only one version of the client installed, but different servers may distribute differing versions of the other components via the auto-download mechanism. This means many different combinations of versions of the components are possible. It can be difficult to reason about which combinations will work correctly, and even which combinations ought to be allowed.&lt;br /&gt;
&lt;br /&gt;
In the rest of this article, &amp;quot;Unvanquished&amp;quot; refers to the eponymous Git repository, not the game.&lt;br /&gt;
&lt;br /&gt;
== Desired use cases ==&lt;br /&gt;
=== Use cases we want to support ===&lt;br /&gt;
* &amp;lt;b&amp;gt;Develop on next-release branch (e.g. &amp;lt;code&amp;gt;0.52.0/sync&amp;lt;/code&amp;gt;) of all repos (Daemon, Unvanquished, unvanquished_src.dpkdir)&amp;lt;/b&amp;gt;&lt;br /&gt;
* &amp;lt;b&amp;gt;Develop on master branch of all repos&amp;lt;/b&amp;gt;&lt;br /&gt;
* &amp;lt;b&amp;gt;Build client from laster master and connect to latest-release servers&amp;lt;/b&amp;gt; &amp;lt;br&amp;gt; We should be able to play with everyone on a client with the latest bug fixes.&lt;br /&gt;
* &amp;lt;b&amp;gt;Build server from latest master and host with latest-release DPKs&amp;lt;/b&amp;gt; &amp;lt;br&amp;gt; Likewise with a server.&lt;br /&gt;
* &amp;lt;b&amp;gt;Build sgame from master and use it with latest-release cgame&amp;lt;/b&amp;gt; &amp;lt;br&amp;gt; Server owners could ship sgame bug fixes without requiring a download.&lt;br /&gt;
* &amp;lt;b&amp;gt;Develop Unvanquished on master, using latest-release DPKs&amp;lt;/b&amp;gt; &amp;lt;br&amp;gt; Development for simple cases should be accessible, not requiring &amp;lt;code&amp;gt;-pakpath&amp;lt;/code&amp;gt; flags etc.&lt;br /&gt;
&lt;br /&gt;
=== Use cases we don't really care about ===&lt;br /&gt;
* &amp;lt;i&amp;gt;Using unvanquished_src.dpkdir from master with latest-release gamelogic&amp;lt;/i&amp;gt;&lt;br /&gt;
* &amp;lt;i&amp;gt;Using a cgame built from an older commit than the sgame&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Per-repository guidance ==&lt;br /&gt;
&lt;br /&gt;
=== Daemon ===&lt;br /&gt;
&lt;br /&gt;
Adding or removing an IPC call must be done on the next-release branch.&lt;br /&gt;
&lt;br /&gt;
When developing Daemon master, you need to keep in mind compatibility with both the latest release and the current master of the gamelogic.&lt;br /&gt;
&lt;br /&gt;
=== Unvanquished ===&lt;br /&gt;
&lt;br /&gt;
Try to keep the submodule pointers to Daemon and unvanquished_src.dpkdir at commits which are compatible with the Unvanquished commit containing them. We want to get a harmonious set of components when we do a recursive checkout of some Unvanquished commit.&lt;br /&gt;
&lt;br /&gt;
In addition to compatibility with other repos, it is necessary to consider compatibility between cgame and sgame. For example, if you want to add a field to the &amp;lt;code&amp;gt;playerState_t&amp;lt;/code&amp;gt; netcode &amp;lt;ref&amp;gt;It is only possible to change this without rebuilding the engine starting from version 0.52.&amp;lt;/ref&amp;gt;, you should do that on the next-release branch. (But if you are a mod developer, you may add fields at any time, provided you ship a cgame.)&lt;br /&gt;
&lt;br /&gt;
=== unvanquished_src.dpkdir ===&lt;br /&gt;
&lt;br /&gt;
When developing on master, you just need to keep it working with the master of Unvanquished. The expectation is that server owners who are shipping a cutting-edge version of this repo should also rebuild the gamelogic.&lt;br /&gt;
&lt;br /&gt;
=== Other *.dkpdir repos ===&lt;br /&gt;
&lt;br /&gt;
There isn't a lot of precedent here. Probably it's best to do anything except bug fixes on a next-release branch. If possible, we want to avoid any situation where developers are required to use any unreleased stuff from these to get a working setup.&lt;br /&gt;
&lt;br /&gt;
== Open questions ==&lt;br /&gt;
&lt;br /&gt;
Should gameplay changes be encouraged on the Unvanquished master branch, as long as they follow compatibility guidelines? Or should those stick to the next-release branch?&lt;br /&gt;
&lt;br /&gt;
On one hand, it might be nice to build the gamelogic from master as a way to test the latest gameplay changes. On the other hand, many gameplay changes will require cgame or pak changes to work; perhaps it is better to keep all gameplay changes together on the next-release branch. We could consider dropping the use-case &amp;quot;Build sgame from master and use it with latest-release cgame&amp;quot; to allow a greater share of gameplay changes on master (ones which modify both sgame and cgame, not just sgame), but we should still forbid changes to master that require modification of unvanquished_src.dpkdir or other paks, since it inconveniences developers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=File:Chaingun.png&amp;diff=5145</id>
		<title>File:Chaingun.png</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=File:Chaingun.png&amp;diff=5145"/>
		<updated>2021-07-29T13:39:07Z</updated>

		<summary type="html">&lt;p&gt;Afontain: Afontain uploaded a new version of File:Chaingun.png&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Chaingun&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Chaingun&amp;diff=5144</id>
		<title>Chaingun</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Chaingun&amp;diff=5144"/>
		<updated>2021-07-29T13:36:56Z</updated>

		<summary type="html">&lt;p&gt;Afontain: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{InfoBoxStart | name = Chaingun | image = Chaingun.png | caption = Possibly the biggest gun of all.}}&lt;br /&gt;
{{InfoRow | caption = Cost | value = 400 credits }}&lt;br /&gt;
{{InfoRow | caption = Unlock | value = - }}&lt;br /&gt;
{{InfoRow | caption = Ammo | value = 300 }}&lt;br /&gt;
{{InfoRow | caption = Energy Weapon | value = No }}&lt;br /&gt;
{{InfoRow | caption = Damage | value = 6 }}&lt;br /&gt;
{{InfoRow | caption = Damage Per Second | value = 68 }}&lt;br /&gt;
{{InfoRow | caption = Damage Per Magazine | value = 1800 }}&lt;br /&gt;
{{InfoRow | caption = Fire Rate | value = 11 per second }}&lt;br /&gt;
{{InfoBoxEnd}}&lt;br /&gt;
&lt;br /&gt;
The chaingun provides a high rate of fire, moderate damage per shot, and a large ammo capacity. It fires many weak shots at a rapid pace, and causes enough knockback to send your view flying all over the place if you're not crouching or wearing a battlesuit. Absolutely fantastic against tyrants and opponents that keep moving around.&lt;br /&gt;
&lt;br /&gt;
==Tips==&lt;br /&gt;
&lt;br /&gt;
* Stay close to your opponent, as the chaingun is far too inaccurate for long range combat.&lt;br /&gt;
* crouching helps accuracy, but makes head more vulnerable&lt;br /&gt;
&lt;br /&gt;
[[Category:Humans]]&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Las_Gun&amp;diff=5143</id>
		<title>Las Gun</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Las_Gun&amp;diff=5143"/>
		<updated>2021-07-29T13:14:19Z</updated>

		<summary type="html">&lt;p&gt;Afontain: battery pack is dead&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{InfoBoxStart | name = Las Gun | image = Lasgun.jpg | caption = Sanest of them all.}}&lt;br /&gt;
{{InfoRow | caption = Cost | value = 250 credits }}&lt;br /&gt;
{{InfoRow | caption = Unlock | value = - }}&lt;br /&gt;
{{InfoRow | caption = Ammo | value = 200 }}&lt;br /&gt;
{{InfoRow | caption = Energy Weapon | value = Yes }}&lt;br /&gt;
{{InfoRow | caption = Damage | value = 9 }}&lt;br /&gt;
{{InfoRow | caption = Damage Per Second | value = 45 }}&lt;br /&gt;
{{InfoRow | caption = Damage Per Magazine | value = 1800 }}&lt;br /&gt;
{{InfoRow | caption = Fire Rate | value = 5 per second }}&lt;br /&gt;
{{InfoBoxEnd}}&lt;br /&gt;
&lt;br /&gt;
The first energy weapon available. It functions much like a vastly improved rifle, at the cost of a decline in the rate of fire.&lt;br /&gt;
&lt;br /&gt;
==Tips==&lt;br /&gt;
&lt;br /&gt;
* Use this against alien bases. It's great! Park yourself in a corner where you aren't being acid tubed, and fire away at eggs while your teammates shoot at other things.&lt;br /&gt;
&lt;br /&gt;
* Don't be afraid to duel with it, as long as you're good at keeping range. You don't need to make up for accuracy with this weapon, so it works fine at any range. Keep circling and firing until they're dead.&lt;br /&gt;
&lt;br /&gt;
* Use this in groups, much like the rifle. It'll make up for your lower firing rate, and the constant shooting will scare most aliens off.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
Fulfilling a similar role to the more common rifle, the lasgun possesses several advantages of its own. Unlike its bullet-churning cousin, the weapon possesses a single large power cell, eliminating the need to reload and allowing its user to keep a constant rate of fire for as long as the cell is charged and the trigger is held. Each “shot” is a pinpoint accurate, coherent burst of high frequency electromagnetic radiation, invisible to human eyes but readily felt as a sudden shock of intense heat that burns flesh with ease. The amplifier must be cooled down between shots, and while this is accomplished in a fraction of a second, there is still an easily noticed delay in comparison to the rifle.&lt;br /&gt;
&lt;br /&gt;
Although superior to the rifle in most regards, the lasgun’s components are far more expensive to manufacture, and thus it is typically entrusted to soldiers that show some degree of marksmanship and survivability above that of a new recruit. Although eclipsed by the other energy weapons in terms of damage output, it is highly regarded as the most efficient weapon in the human arsenal.&lt;br /&gt;
&lt;br /&gt;
[[Category:Humans]]&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Las_Gun&amp;diff=5142</id>
		<title>Las Gun</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Las_Gun&amp;diff=5142"/>
		<updated>2021-07-29T13:13:20Z</updated>

		<summary type="html">&lt;p&gt;Afontain: lasgun can't reload&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{InfoBoxStart | name = Las Gun | image = Lasgun.jpg | caption = Sanest of them all.}}&lt;br /&gt;
{{InfoRow | caption = Cost | value = 250 credits }}&lt;br /&gt;
{{InfoRow | caption = Unlock | value = - }}&lt;br /&gt;
{{InfoRow | caption = Ammo | value = 200 }}&lt;br /&gt;
{{InfoRow | caption = Energy Weapon | value = Yes }}&lt;br /&gt;
{{InfoRow | caption = Damage | value = 9 }}&lt;br /&gt;
{{InfoRow | caption = Damage Per Second | value = 45 }}&lt;br /&gt;
{{InfoRow | caption = Damage Per Magazine | value = 1800 }}&lt;br /&gt;
{{InfoRow | caption = Fire Rate | value = 5 per second }}&lt;br /&gt;
{{InfoBoxEnd}}&lt;br /&gt;
&lt;br /&gt;
The first energy weapon available. It functions much like a vastly improved rifle, at the cost of a decline in the rate of fire.&lt;br /&gt;
&lt;br /&gt;
==Tips==&lt;br /&gt;
&lt;br /&gt;
* Use this against alien bases. It's great! Park yourself in a corner where you aren't being acid tubed, and fire away at eggs while your teammates shoot at other things.&lt;br /&gt;
&lt;br /&gt;
* Don't be afraid to duel with it, as long as you're good at keeping range. You don't need to make up for accuracy with this weapon, so it works fine at any range. Keep circling and firing until they're dead.&lt;br /&gt;
&lt;br /&gt;
* Use this in groups, much like the rifle. It'll make up for your lower firing rate, and the constant shooting will scare most aliens off.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
Fulfilling a similar role to the more common rifle, the lasgun possesses several advantages of its own. Unlike its bullet-churning cousin, the weapon possesses a single large power cell, eliminating the need to reload and allowing its user to keep a constant rate of fire for as long as the cell is charged and the trigger is held. Each “shot” is a pinpoint accurate, coherent burst of high frequency electromagnetic radiation, invisible to human eyes but readily felt as a sudden shock of intense heat that burns flesh with ease. The amplifier must be cooled down between shots, and while this is accomplished in a fraction of a second, there is still an easily noticed delay in comparison to the rifle.&lt;br /&gt;
&lt;br /&gt;
Although superior to the rifle in most regards, the lasgun’s components are far more expensive to manufacture, and thus it is typically entrusted to soldiers that show some degree of marksmanship and survivability above that of a new recruit. It may be connected to a battery pack, providing even more energy to the power cell. Although eclipsed by the other energy weapons in terms of damage output, it is highly regarded as the most efficient weapon in the human arsenal.&lt;br /&gt;
&lt;br /&gt;
[[Category:Humans]]&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=File:Lasgun.jpg&amp;diff=5141</id>
		<title>File:Lasgun.jpg</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=File:Lasgun.jpg&amp;diff=5141"/>
		<updated>2021-07-29T13:11:10Z</updated>

		<summary type="html">&lt;p&gt;Afontain: Afontain uploaded a new version of File:Lasgun.jpg&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Lasgun.&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Light_Armour&amp;diff=5140</id>
		<title>Light Armour</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Light_Armour&amp;diff=5140"/>
		<updated>2021-07-29T12:56:13Z</updated>

		<summary type="html">&lt;p&gt;Afontain: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{InfoBoxStart | name = Light Armor | image = Light-armor-lasgun-0.52.png | caption = Fancy armor. Weapon sold separately.}}&lt;br /&gt;
{{InfoRow | caption = Cost | value = 200 }}&lt;br /&gt;
{{InfoRow | caption = Unlock | value = 0 }}&lt;br /&gt;
{{InfoBoxSection | name = % of base damage }}&lt;br /&gt;
{{InfoRow | caption = Head  | value = 80% }}&lt;br /&gt;
{{InfoRow | caption = Torso Back | value = 50% }}&lt;br /&gt;
{{InfoRow | caption = Torso Front | value = 35% }}&lt;br /&gt;
{{InfoRow | caption = Legs  | value = 25% }}&lt;br /&gt;
{{InfoRow | caption = Non-Locational  | value = 50% }}&lt;br /&gt;
{{InfoBoxEnd}}&lt;br /&gt;
&lt;br /&gt;
This will be your first armor, grab it as soon as you can on the battlefield. Before even weapons!&lt;br /&gt;
[[Category:Humans]]&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Medium_Armour&amp;diff=5139</id>
		<title>Medium Armour</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Medium_Armour&amp;diff=5139"/>
		<updated>2021-07-29T12:39:39Z</updated>

		<summary type="html">&lt;p&gt;Afontain: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{InfoBoxStart | name = Medium Armour | image = Armour medium.png | caption = The mobile killing armor.}}&lt;br /&gt;
{{InfoRow | caption = Cost | value = 300 }}&lt;br /&gt;
{{InfoRow | caption = Unlock | value = 3 }}&lt;br /&gt;
{{InfoBoxSection | name = % of base damage }}&lt;br /&gt;
{{InfoRow | caption = Head  | value = 60% }}&lt;br /&gt;
{{InfoRow | caption = Torso Back | value = 35% }}&lt;br /&gt;
{{InfoRow | caption = Torso Front | value = 30% }}&lt;br /&gt;
{{InfoRow | caption = Legs  | value = 20% }}&lt;br /&gt;
{{InfoRow | caption = Non-Locational | value = 30% }}&lt;br /&gt;
{{InfoBoxEnd}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Humans]]&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Medium_Armour&amp;diff=5138</id>
		<title>Medium Armour</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Medium_Armour&amp;diff=5138"/>
		<updated>2021-07-29T12:37:35Z</updated>

		<summary type="html">&lt;p&gt;Afontain: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{InfoBoxStart | name = Medium Armour | image = Armour medium.png | caption = The mobile killing armor.}}&lt;br /&gt;
{{InfoRow | caption = Cost | value = 300 }}&lt;br /&gt;
{{InfoRow | caption = Unlock | value = 3 }}&lt;br /&gt;
{{InfoBoxSection | name = % of base damage }}&lt;br /&gt;
{{InfoRow | caption = Head  | value = 60% }}&lt;br /&gt;
{{InfoRow | caption = Torso Back | value = 35% }}&lt;br /&gt;
{{InfoRow | caption = Torso Front | value = 30% }}&lt;br /&gt;
{{InfoRow | caption = Legs  | value = 20% }}&lt;br /&gt;
{{InfoRow | caption = Non-Locational | value = 30% }}&lt;br /&gt;
&lt;br /&gt;
{{InfoBoxEnd}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Humans]]&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Light_Armour&amp;diff=5137</id>
		<title>Light Armour</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Light_Armour&amp;diff=5137"/>
		<updated>2021-07-29T12:34:57Z</updated>

		<summary type="html">&lt;p&gt;Afontain: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{InfoBoxStart | name = Light Armor | image = Light-armor-lasgun-0.52.png | caption = Fancy armor. Weapon sold separately.}}&lt;br /&gt;
{{InfoRow | caption = Cost | value = 200 }}&lt;br /&gt;
{{InfoRow | caption = Unlock | value = 5 }}&lt;br /&gt;
{{InfoBoxSection | name = % of base damage }}&lt;br /&gt;
{{InfoRow | caption = Head  | value = 80% }}&lt;br /&gt;
{{InfoRow | caption = Torso Back | value = 50% }}&lt;br /&gt;
{{InfoRow | caption = Torso Front | value = 35% }}&lt;br /&gt;
{{InfoRow | caption = Legs  | value = 25% }}&lt;br /&gt;
{{InfoRow | caption = Non-Locational  | value = 50% }}&lt;br /&gt;
{{InfoBoxEnd}}&lt;br /&gt;
&lt;br /&gt;
This will be your first armor, grab it as soon as you can on the battlefield. Before even weapons!&lt;br /&gt;
[[Category:Humans]]&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=Light_Armour&amp;diff=5136</id>
		<title>Light Armour</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=Light_Armour&amp;diff=5136"/>
		<updated>2021-07-29T12:34:38Z</updated>

		<summary type="html">&lt;p&gt;Afontain: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{InfoBoxStart | name = Light Armor | image = Light-armor-lasgun-0.52.png | caption = Fancy armor. Weapon sold separately.}}&lt;br /&gt;
{{InfoRow | caption = Cost | value = 400 }}&lt;br /&gt;
{{InfoRow | caption = Unlock | value = 5 }}&lt;br /&gt;
{{InfoBoxSection | name = % of base damage }}&lt;br /&gt;
{{InfoRow | caption = Head  | value = 80% }}&lt;br /&gt;
{{InfoRow | caption = Torso Back | value = 50% }}&lt;br /&gt;
{{InfoRow | caption = Torso Front | value = 35% }}&lt;br /&gt;
{{InfoRow | caption = Legs  | value = 25% }}&lt;br /&gt;
{{InfoRow | caption = Non-Locational  | value = 50% }}&lt;br /&gt;
{{InfoBoxEnd}}&lt;br /&gt;
&lt;br /&gt;
This will be your first armor, grab it as soon as you can on the battlefield. Before even weapons!&lt;br /&gt;
[[Category:Humans]]&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
	<entry>
		<id>https://staging-wiki.unvanquished.net/index.php?title=File:Light-armor-lasgun-0.52.png&amp;diff=5135</id>
		<title>File:Light-armor-lasgun-0.52.png</title>
		<link rel="alternate" type="text/html" href="https://staging-wiki.unvanquished.net/index.php?title=File:Light-armor-lasgun-0.52.png&amp;diff=5135"/>
		<updated>2021-07-29T12:29:00Z</updated>

		<summary type="html">&lt;p&gt;Afontain: An human with a light armor and the new lasgun&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
An human with a light armor and the new lasgun&lt;br /&gt;
== Licencing ==&lt;br /&gt;
{{licenses/cc-by-nc-sa-3.0}}&lt;/div&gt;</summary>
		<author><name>Afontain</name></author>
	</entry>
</feed>