profectus-docs/guide/migrations/0-6.html

65 lines
69 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="en-US" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Migrating to Profectus 0.6 | Profectus</title>
<meta name="description" content="A game engine that grows with you.">
<link rel="preload stylesheet" href="/assets/style.49aa32a7.css" as="style">
<script type="module" src="/assets/app.68642a14.js"></script>
<link rel="preload" href="/assets/inter-roman-latin.2ed14f66.woff2" as="font" type="font/woff2" crossorigin="">
<link rel="modulepreload" href="/assets/chunks/framework.0799945b.js">
<link rel="modulepreload" href="/assets/chunks/theme.52324978.js">
<link rel="modulepreload" href="/assets/guide_migrations_0-6.md.d198a7d2.lean.js">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,400;0,600;1,400">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest">
<script defer="true" data-domain="moddingtree.com" src="https://plausible.io/js/plausible.js"></script>
<meta name="og:description" content="A game engine that grows with you">
<meta name="og:image" content="/Logo.png">
</head>
<body>
<div id="app"><div class="Layout" data-v-b2cf3e0b><!--[--><!--]--><!--[--><span tabindex="-1" data-v-c8616af1></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-c8616af1> Skip to content </a><!--]--><!----><header class="VPNav" data-v-b2cf3e0b data-v-7e5bc4a5><div class="VPNavBar has-sidebar" data-v-7e5bc4a5 data-v-1d30fa41><div class="container" data-v-1d30fa41><div class="title" data-v-1d30fa41><div class="VPNavBarTitle has-sidebar" data-v-1d30fa41 data-v-f4ef19a3><a class="title" href="/" data-v-f4ef19a3><!--[--><!--]--><!--[--><img class="VPImage logo" src="/favicon.svg" alt data-v-6db2186b><!--]--><!--[-->Profectus<!--]--><!--[--><!--]--></a></div></div><div class="content" data-v-1d30fa41><div class="curtain" data-v-1d30fa41></div><div class="content-body" data-v-1d30fa41><!--[--><!--]--><!----><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-1d30fa41 data-v-7f418b0f><span id="main-nav-aria-label" class="visually-hidden" data-v-7f418b0f>Main Navigation</span><!--[--><!--[--><a class="VPLink link VPNavBarMenuLink active" href="/guide/" tabindex="0" data-v-7f418b0f data-v-37adc828 data-v-8f4dc553><!--[-->Guide<!--]--><!----></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/api/overview" tabindex="0" data-v-7f418b0f data-v-37adc828 data-v-8f4dc553><!--[-->API<!--]--><!----></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="https://forums.moddingtree.com" target="_blank" rel="noreferrer" tabindex="0" data-v-7f418b0f data-v-37adc828 data-v-8f4dc553><!--[-->Forums<!--]--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" height="24px" viewbox="0 0 24 24" width="24px" class="icon" data-v-8f4dc553><path d="M0 0h24v24H0V0z" fill="none"></path><path d="M9 5v2h6.59L4 18.59 5.41 20 17 8.41V15h2V5H9z"></path></svg></a><!--]--><!--]--></nav><!----><!----><div class="VPSocialLinks VPNavBarSocialLinks social-links" data-v-1d30fa41 data-v-0394ad82 data-v-f6988cfb><!--[--><a class="VPSocialLink" href="https://discord.gg/yJ4fjnjU54" aria-label="discord" target="_blank" rel="noopener" data-v-f6988cfb data-v-c530cc0a><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Discord</title><path d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z"/></svg></a><a class="VPSocialLink" href="https://github.com/profectus-engine/Profectus" aria-label="github" target="_blank" rel="noopener" data-v-f6988cfb data-v-c530cc0a><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3
<span class="line"><span style="color:#C792EA;">const</span><span style="color:#A6ACCD;"> job </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">createJob</span><span style="color:#A6ACCD;">(name</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#A6ACCD;"> (</span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">/** snip **/</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#F07178;">resource</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> flowers</span></span>
<span class="line"><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;">))</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">/** snip **/</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">/** snip **/</span></span>
<span class="line"><span style="color:#A6ACCD;"> flowers</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> job</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p>This example stores the same persistent data in two locations - <code>flowers.flowers</code> and <code>flowers.job.resource</code>. We can mark the latter usage as a reference by wrapping it in the <a href="./../../api/modules/game/persistence#nopersist">noPersist</a> utility, so it&#39;d look like <code>resource: noPersist(flowers)</code>. Otherwise, you will encounter an error in the console when the layer is loaded:</p><p><img src="/assets/persistence-error.537e237b.png" alt="Persistence Error"></p><p>Use these console errors to identify save data redundancy that needs correction. It is recommended to run the app and use the errors as a guide rather than trying to identify redundancies manually.</p><p>In addition to obtaining non-persistent refs from your persistent refs, you may need to wrap entire features containing persistent refs. For example, in Kronos, there are seven layers with &quot;Job&quot; features, which are combined into a dictionary in the main layer. This would cause the persistent state to appear in both layers, but you can wrap the dictionary in a noPersist call to bypass serialization, ensuring it only uses the jobs within their respective layers. Here&#39;s an example from Kronos:</p><div class="language-ts"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">const</span><span style="color:#A6ACCD;"> jobs </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">noPersist</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#F07178;">flowers</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> flowers</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">job</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#F07178;">distill</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> distill</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">job</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#F07178;">study</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> study</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">job</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#F07178;">experiments</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> experiments</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">job</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#F07178;">generators</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> generators</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">job</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#F07178;">breeding</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> breeding</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">job</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#F07178;">rituals</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> rituals</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">job</span></span>
<span class="line"><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;">) </span><span style="color:#89DDFF;font-style:italic;">as</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">Record</span><span style="color:#89DDFF;">&lt;</span><span style="color:#FFCB6B;">JobKeys</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">GenericJob</span><span style="color:#89DDFF;">&gt;;</span></span></code></pre></div><p>The time required for this step depends on your project structure. You can use <a href="https://github.com/thepaperpilot/Kronos/commit/6e8bfc1a78df0a7957de06bacdabf87c688b917c" target="_blank" rel="noreferrer">this commit</a> to see all the changes made for Kronos, which used a utility function for similar features that limited the number of required changes.</p><h2 id="breaking-feature-changes" tabindex="-1">Breaking feature changes <a class="header-anchor" href="#breaking-feature-changes" aria-label="Permalink to &quot;Breaking feature changes&quot;"></a></h2><h3 id="achievements-and-milestones" tabindex="-1">Achievements and Milestones <a class="header-anchor" href="#achievements-and-milestones" aria-label="Permalink to &quot;Achievements and Milestones&quot;"></a></h3><p>Achievements and milestones have been merged. Any existing achievements should now have the <code>small: true</code> property set to keep the same display as before. Milestones should now use the <code>createAchievement</code> constructor instead of <code>createMilestone</code>, and they will appear and behave as before.</p><h3 id="buyables" tabindex="-1">Buyables <a class="header-anchor" href="#buyables" aria-label="Permalink to &quot;Buyables&quot;"></a></h3><p>Buyables have been renamed to &quot;repeatables&quot;. To update your code, you&#39;ll need to replace all references to buyable with repeatable. Additionally, various properties have been removed or changed to no longer refer to purchases:</p><ul><li><code>canAfford</code> no longer exists, and you should instead add conditions via the requirements system</li><li><code>onPurchase</code> should become <code>onClick</code></li><li><code>purchase()</code> should become <code>click()</code></li></ul><h3 id="requirements" tabindex="-1">Requirements <a class="header-anchor" href="#requirements" aria-label="Permalink to &quot;Requirements&quot;"></a></h3><p>Many features now use <code>requirements</code> properties where before they would have a cost or other condition. The <code>requirements</code> property takes a single <code>Requirement</code> object or an array of them. Requirements make it easier to support features requiring multiple currencies or other conditions.</p><p>When coupled with the formulas system, they also allow for scaling requirements that can be calculated efficiently. Here is an example repeatable that starts by costing 100 points and gets 1.05x more expensive with each purchase, compounding. Thanks to formulas the repeatable will be able to immediately increase as many levels as the player can afford at once:</p><div class="language-ts"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">const</span><span style="color:#A6ACCD;"> myRepeatable </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">createRepeatable</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#A6ACCD;"> (</span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#F07178;">requirements</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">createCostRequirement</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#A6ACCD;"> (</span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#F07178;">resource</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> points</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#F07178;">cost</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> Formula</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">variable</span><span style="color:#A6ACCD;">(myRepeatable</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">amount)</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">pow_base</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">1.05</span><span style="color:#A6ACCD;">)</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">times</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;">))</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#F07178;">maximize</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#FF9CAC;">true</span></span>
<span class="line"><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;">))</span><span style="color:#89DDFF;">;</span></span></code></pre></div><p>To update an existing non-scaling cost requirement, wrap your current cost function and resource property as follows:</p><div class="language-ts"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">const</span><span style="color:#A6ACCD;"> upgrade </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">createUpgrade</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#A6ACCD;"> (</span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#F07178;">requirements</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">createCostRequirement</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#A6ACCD;"> (</span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">cost</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#A6ACCD;"> Decimal</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">pow</span><span style="color:#A6ACCD;">(priceRatio</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">unref</span><span style="color:#A6ACCD;">(machines</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">amount))</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#F07178;">resource</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> generators</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">energeia</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;">))</span></span>
<span class="line"><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;">))</span><span style="color:#89DDFF;">;</span></span></code></pre></div><p>For other conditions, you can use the <code>createBooleanRequirement</code> constructor instead:</p><div class="language-ts"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">const</span><span style="color:#A6ACCD;"> spellExpMilestone </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">createAchievement</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#A6ACCD;"> (</span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#F07178;">requirements</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">createBooleanRequirement</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#A6ACCD;"> Decimal</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">gte</span><span style="color:#A6ACCD;">(job</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">rawLevel</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">value</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;">))</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;">))</span><span style="color:#89DDFF;">;</span></span></code></pre></div><p>Learn more about requirements and their capabilities in <a href="./../important-concepts/requirements">this guide page</a>.</p><h3 id="formulas" tabindex="-1">Formulas <a class="header-anchor" href="#formulas" aria-label="Permalink to &quot;Formulas&quot;"></a></h3><p>Formulas are a new feature that allows for scaling cost or effect functions to be inverted or integrated without requiring the developer to code anything beyond the original formula. They can simplify support for &quot;buy max&quot; functionalities and make conversions easier to read and write.</p><p>Any cost requirements can now accept a formula instead of a cost function. The formula system can then handle determining how many purchases can be made at once. To continue the example above, here&#39;s how it would be rewritten:</p><div class="language-ts"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#FFCB6B;">requirements</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">createCostRequirement</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#A6ACCD;"> (</span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#F07178;">cost</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> Formula</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">variable</span><span style="color:#A6ACCD;">(machines</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">amount)</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">pow_base</span><span style="color:#A6ACCD;">(priceRatio)</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#F07178;">resource</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> generators</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">energeia</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;">))</span></span></code></pre></div><p>Conversions work a bit differently. Their scaling function system has been replaced with a <code>formula</code> property that takes a lambda - it provides the input formula variable, representing the base resource, as a parameter, and you return a formula representing the amount of the gain resource that could be converted. For example, if you previously had code like this:</p><div class="language-ts"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#FFCB6B;">scaling</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">addSoftcap</span><span style="color:#A6ACCD;">(</span><span style="color:#82AAFF;">createPolynomialScaling</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">10</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0.5</span><span style="color:#A6ACCD;">)</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1e100</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0.5</span><span style="color:#A6ACCD;">)</span></span></code></pre></div><p>you can now write this:</p><div class="language-ts"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#FFCB6B;">formula</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">x</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#A6ACCD;"> x</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">div</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;">)</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">sqrt</span><span style="color:#A6ACCD;">()</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">step</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">1e100</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">f</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#A6ACCD;"> f</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">sqrt</span><span style="color:#A6ACCD;">())</span></span></code></pre></div><p>Learn more about formulas and their capabilities in <a href="./../important-concepts/formulas">this guide page</a>.</p><h3 id="modifiers" tabindex="-1">Modifiers <a class="header-anchor" href="#modifiers" aria-label="Permalink to &quot;Modifiers&quot;"></a></h3><p>Modifiers now display negative effects in red. The current implementation assumes any value that reduces the result is negative, and the output being less than the base value is a negative outcome. However, for some modifiers, this may be the opposite of what you want - for example, a cooldown being reduced below its base value is a positive effect. For those modifiers, set the <code>smallerIsBetter</code> property to <code>true</code>. This property also exists when creating collapsible modifier sections.</p><p>Modifiers have renamed their <code>revert</code> property to <code>invert</code> to match the terms used by formulas. Update any custom modifiers you&#39;ve created accordingly.</p><h3 id="custom-features" tabindex="-1">Custom Features <a class="header-anchor" href="#custom-features" aria-label="Permalink to &quot;Custom Features&quot;"></a></h3><p>Lazy proxies now call the options function with the base object as the <code>this</code> argument and the first parameter. Features with <code>options</code> functions are
<span class="line"><span style="color:#F07178;"> </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#F07178;"> </span><span style="color:#82AAFF;">showIf</span><span style="color:#F07178;">(</span><span style="color:#A6ACCD;">spellExpMilestone</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">earned</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">value</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p>This code can now be simplified to:</p><div class="language-ts"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#FFCB6B;">visibility</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> spellExpMilestone</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">earned</span></span></code></pre></div><p>Be aware that using the computed ref directly instead of a function can cause circular dependency issues. If you encounter one while simplifying a visibility property, resolve the issue or continue using a function, returning the computed ref value.</p><h3 id="custom-components" tabindex="-1">Custom Components <a class="header-anchor" href="#custom-components" aria-label="Permalink to &quot;Custom Components&quot;"></a></h3><p>If you created any custom features with their own Vue components, you&#39;ll need to update them to support booleans for visibility values. This means replacing <strong>ALL</strong> equality checks for specific visibilities with calls to <a href="./../../api/modules/features/feature#isvisible">isVisible</a> and <a href="./../../api/modules/features/feature#ishidden">isHidden</a>.</p><p>While updating your component, you may need to cast the component to <a href="./../../api/modules/features/feature#genericcomponent">GenericComponent</a>.</p></div></div></main><footer class="VPDocFooter" data-v-c4b0d3cf data-v-face870a><!--[--><!--]--><div class="edit-info" data-v-face870a><div class="edit-link" data-v-face870a><a class="VPLink link edit-link-button" href="https://github.com/profectus-engine/profectus-docs/edit/main/docs/guide/migrations/0-6.md" target="_blank" rel="noreferrer" data-v-face870a data-v-8f4dc553><!--[--><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" class="edit-link-icon" aria-label="edit icon" data-v-face870a><path d="M18,23H4c-1.7,0-3-1.3-3-3V6c0-1.7,1.3-3,3-3h7c0.6,0,1,0.4,1,1s-0.4,1-1,1H4C3.4,5,3,5.4,3,6v14c0,0.6,0.4,1,1,1h14c0.6,0,1-0.4,1-1v-7c0-0.6,0.4-1,1-1s1,0.4,1,1v7C21,21.7,19.7,23,18,23z"></path><path d="M8,17c-0.3,0-0.5-0.1-0.7-0.3C7,16.5,6.9,16.1,7,15.8l1-4c0-0.2,0.1-0.3,0.3-0.5l9.5-9.5c1.2-1.2,3.2-1.2,4.4,0c1.2,1.2,1.2,3.2,0,4.4l-9.5,9.5c-0.1,0.1-0.3,0.2-0.5,0.3l-4,1C8.2,17,8.1,17,8,17zM9.9,12.5l-0.5,2.1l2.1-0.5l9.3-9.3c0.4-0.4,0.4-1.1,0-1.6c-0.4-0.4-1.2-0.4-1.6,0l0,0L9.9,12.5z M18.5,2.5L18.5,2.5L18.5,2.5z"></path></svg> Edit this page<!--]--><!----></a></div><div class="last-updated" data-v-face870a><p class="VPLastUpdated" data-v-face870a data-v-7b3ebfe1>Last updated: <time datetime="2023-04-23T17:47:49.000Z" data-v-7b3ebfe1></time></p></div></div><div class="prev-next" data-v-face870a><div class="pager" data-v-face870a><a class="pager-link prev" href="/guide/advanced-concepts/nodes" data-v-face870a><span class="desc" data-v-face870a>Previous page</span><span class="title" data-v-face870a>Nodes</span></a></div><div class="has-prev pager" data-v-face870a><!----></div></div></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><!----><!--[--><!--]--></div></div>
<script>__VP_HASH_MAP__ = JSON.parse("{\"api_components_fields_selectcomponent.md\":\"ace2bb01\",\"api_components_layout_rowcomponent.md\":\"2f1b6079\",\"api_components_contextcomponent.md\":\"088cd8fb\",\"api_components_hotkeycomponent.md\":\"94af8a77\",\"api_components_infocomponent.md\":\"5e7ed906\",\"api_components_layercomponent.md\":\"fb5a91af\",\"api_components_marknodecomponent.md\":\"95ce4d1c\",\"api_components_modalcomponent.md\":\"40989410\",\"api_components_nodecomponent.md\":\"6c607feb\",\"api_components_savecomponent.md\":\"bc14d931\",\"api_components_fields_feedbackbuttoncomponent.md\":\"3022117b\",\"api_components_fields_dangerbuttoncomponent.md\":\"43aea00b\",\"api_components_layout_verticalrulecomponent.md\":\"87270803\",\"api_components_fields_slidercomponent.md\":\"de4f5cd1\",\"api_components_fields_textcomponent.md\":\"039dbcea\",\"api_components_fields_togglecomponent.md\":\"0126692d\",\"api_components_layout_collapsiblecomponent.md\":\"b792d45f\",\"api_components_layout_columncomponent.md\":\"0a31ce33\",\"api_components_math_sqrtcomponent.md\":\"a610fb30\",\"api_components_layout_stickycomponent.md\":\"3605e970\",\"api_components_math_floorcomponent.md\":\"765da36c\",\"api_components_layout_spacercomponent.md\":\"8e0b53af\",\"api_modules_data_themes.md\":\"6eb6114d\",\"api_modules_features_bar.md\":\"ecd958de\",\"api_modules_features_achievement.md\":\"2c24bff1\",\"api_modules_data_common.md\":\"ddd5306c\",\"api_modules_features_action.md\":\"68a2726b\",\"api_modules_data_projentry.md\":\"9038ba8a\",\"guide_migrations_0-6.md\":\"d198a7d2\",\"api_modules_features_feature.md\":\"46957c9a\",\"api_modules_features_tabs_tab.md\":\"f017505a\",\"api_modules_features_hotkey.md\":\"9918ca5a\",\"api_modules_game_events.md\":\"58d1639b\",\"api_modules_features_links.md\":\"b811d3f9\",\"api_modules_features_infobox.md\":\"2d5cad15\",\"api_modules_features_repeatable.md\":\"2e29a1c8\",\"api_modules_features_tabs_tabfamily.md\":\"ea7f06e8\",\"api_modules_features_decorators_common.md\":\"b44a5589\",\"api_modules_features_clickable.md\":\"06b42fa3\",\"api_modules_features_resource.md\":\"241276ff\",\"api_modules_game_formulas_formulas.md\":\"71568576\",\"api_modules_features_decorators_bonusdecorator.md\":\"d14c50e1\",\"api_modules_features_challenge.md\":\"96ef86ff\",\"api_modules_features_tooltip.md\":\"745d275c\",\"api_modules_game_gameloop.md\":\"4808c315\",\"api_modules_features_conversion.md\":\"fff57241\",\"guide_getting-started_setup.md\":\"6352aee6\",\"guide_getting-started_updating.md\":\"071cfa1a\",\"guide_important-concepts_coercable.md\":\"8e00dc5b\",\"guide_important-concepts_layers.md\":\"383ccadd\",\"guide_important-concepts_features.md\":\"17d1011c\",\"guide_important-concepts_formulas.md\":\"dba9ca99\",\"guide_important-concepts_persistence.md\":\"526805da\",\"guide_important-concepts_reactivity.md\":\"6248c914\",\"guide_important-concepts_requirements.md\":\"2ba8dc89\",\"guide_index.md\":\"2a71345c\",\"api_modules_features_board.md\":\"64b17759\",\"guide_recipes_save-progress.md\":\"f4e00f9f\",\"index.md\":\"6b1702a1\",\"api_modules_features_particles.md\":\"843bb46c\",\"api_modules_features_reset.md\":\"5dd84152\",\"api_modules_game_state.md\":\"7f559afd\",\"api_modules_features_tree.md\":\"21682f1f\",\"api_modules_lib_pwa-register.md\":\"744751d6\",\"api_modules_game_requirements.md\":\"bce28c41\",\"api_modules_game_formulas_types.md\":\"94b9e46f\",\"api_modules_lib_vue-textarea-autosize.md\":\"a92591ec\",\"api_overview.md\":\"88cceb38\",\"guide_advanced-concepts_nodes.md\":\"73d33be3\",\"api_modules_util_bignum.md\":\"56df6c58\",\"api_modules_util_computed.md\":\"b8b246ff\",\"api_modules_features_upgrade.md\":\"e2714559\",\"guide_advanced-concepts_creating-features.md\":\"b7295777\",\"api_modules_lib_pixi.md\":\"2b426252\",\"guide_creating-your-project_project-info.md\":\"c5a1be3c\",\"api_modules_game_layers.md\":\"35b5fbc8\",\"guide_advanced-concepts_dynamic-layers.md\":\"dfd52482\",\"api_modules_game_modifiers.md\":\"83a3c67d\",\"api_modules_game_notifications.md\":\"3509d0e7\",\"api_
__VP_SITE_DATA__ = JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"Profectus\",\"description\":\"A game engine that grows with you.\",\"base\":\"/\",\"head\":[],\"appearance\":false,\"themeConfig\":{\"logo\":\"/favicon.svg\",\"editLink\":{\"pattern\":\"https://github.com/profectus-engine/profectus-docs/edit/main/docs/:path\",\"editLinkText\":\"Edit this page on GitHub\"},\"nav\":[{\"text\":\"Guide\",\"link\":\"/guide/\",\"activeMatch\":\"^/guide/\"},{\"text\":\"API\",\"link\":\"/api/overview\",\"activeMatch\":\"^/api/\"},{\"text\":\"Forums\",\"link\":\"https://forums.moddingtree.com\"}],\"socialLinks\":[{\"icon\":\"discord\",\"link\":\"https://discord.gg/yJ4fjnjU54\"},{\"icon\":\"github\",\"link\":\"https://github.com/profectus-engine/Profectus\"}],\"sidebar\":{\"/guide/\":[{\"text\":\"Getting Started\",\"collapsed\":false,\"items\":[{\"text\":\"Introduction\",\"link\":\"/guide/\"},{\"text\":\"Setting Up\",\"link\":\"/guide/getting-started/setup\"},{\"text\":\"Updating Profectus\",\"link\":\"/guide/getting-started/updating\"},{\"text\":\"Your First Layer\",\"link\":\"/guide/getting-started/first-layer\"},{\"text\":\"Example Projects\",\"link\":\"/guide/getting-started/examples\"},{\"text\":\"Profectus Changelog\",\"link\":\"https://github.com/profectus-engine/Profectus/blob/main/CHANGELOG.md\"}]},{\"text\":\"Creating Your Project\",\"collapsed\":false,\"items\":[{\"text\":\"Project Info\",\"link\":\"/guide/creating-your-project/project-info\"},{\"text\":\"Project Entry\",\"link\":\"/guide/creating-your-project/project-entry\"},{\"text\":\"Changelog\",\"link\":\"/guide/creating-your-project/changelog\"},{\"text\":\"Themes\",\"link\":\"/guide/creating-your-project/themes\"},{\"text\":\"Utilities\",\"link\":\"/guide/creating-your-project/utils\"}]},{\"text\":\"Important Concepts\",\"collapsed\":false,\"items\":[{\"text\":\"Layers\",\"link\":\"/guide/important-concepts/layers\"},{\"text\":\"Features\",\"link\":\"/guide/important-concepts/features\"},{\"text\":\"Coercable Components\",\"link\":\"/guide/important-concepts/coercable\"},{\"text\":\"Reactivity\",\"link\":\"/guide/important-concepts/reactivity\"},{\"text\":\"Persistence\",\"link\":\"/guide/important-concepts/persistence\"},{\"text\":\"Requirements\",\"link\":\"/guide/important-concepts/requirements\"},{\"text\":\"Formulas\",\"link\":\"/guide/important-concepts/formulas\"}]},{\"text\":\"Recipes\",\"collapsed\":false,\"items\":[{\"text\":\"Prestige Mechanic\",\"link\":\"/guide/recipes/prestige\"},{\"text\":\"Display Save Progress\",\"link\":\"/guide/recipes/save-progress\"},{\"text\":\"Display Particle Effect\",\"link\":\"/guide/recipes/particles\"}]},{\"text\":\"Advanced Concepts\",\"collapsed\":false,\"items\":[{\"text\":\"Creating Features\",\"link\":\"/guide/advanced-concepts/creating-features\"},{\"text\":\"Dynamic Layers\",\"link\":\"/guide/advanced-concepts/dynamic-layers\"},{\"text\":\"Nodes\",\"link\":\"/guide/advanced-concepts/nodes\"}]},{\"text\":\"Migrations\",\"collapsed\":true,\"items\":[{\"text\":\"0.5.X to 0.6.0\",\"link\":\"/guide/migrations/0-6\"}]}],\"/api/\":[{\"text\":\"Components\",\"collapsed\":true,\"items\":[{\"text\":\"Fields\",\"items\":[{\"text\":\" Danger Button Component\",\"link\":\"/api/components/fields/DangerButtonComponent.html\"},{\"text\":\" Feedback Button Component\",\"link\":\"/api/components/fields/FeedbackButtonComponent.html\"},{\"text\":\" Select Component\",\"link\":\"/api/components/fields/SelectComponent.html\"},{\"text\":\" Slider Component\",\"link\":\"/api/components/fields/SliderComponent.html\"},{\"text\":\" Text Component\",\"link\":\"/api/components/fields/TextComponent.html\"},{\"text\":\" Toggle Component\",\"link\":\"/api/components/fields/ToggleComponent.html\"}],\"collapsed\":true},{\"text\":\"Layout\",\"items\":[{\"text\":\" Collapsible Component\",\"link\":\"/api/components/layout/CollapsibleComponent.html\"},{\"text\":\" Column Component\",\"link\":\"/api/components/layout/ColumnComponent.html\"},{\"text\":\" Row Component\",\"link\":\"/api/components/layout/RowComponent.html\"},{\"text\":\"
</body>
</html>