<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>cat petra on petrak@&#39;s Website</title>
    <link>/blog/</link>
    <description>Recent content in cat petra on petrak@&#39;s Website</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Thu, 21 Jul 2022 21:07:20 -0500</lastBuildDate><atom:link href="/blog/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Retrospection: One Year of Hexcasting</title>
      <link>/blog/2022-12-29_retrospection/</link>
      <pubDate>Thu, 29 Dec 2022 16:19:00 -0500</pubDate>
      
      <guid>/blog/2022-12-29_retrospection/</guid>
      <description>The very first push to the Hexcasting Github repo was made about one year ago, on Christmas. Version 0.1.0 was released for Forge on Minecraft 1.18.2 three weeks later, on January 18th.
At the time, I was not known as a modder. I had one project on Curseforge called Axiomatic Teleportation, which let you walk through walls. My other modding explorations, which I never released, consisted of two shitty Botania addons.</description>
      <content>&lt;p&gt;The very first push to the Hexcasting Github repo was made about one year ago,
on Christmas. Version 0.1.0 was released for Forge on Minecraft 1.18.2 three
weeks later, on January 18th.&lt;/p&gt;
&lt;p&gt;At the time, I was not known as a modder. I had one project on Curseforge
called Axiomatic Teleportation, which let you walk through walls. My other
modding explorations, which I never released, consisted of two shitty Botania
addons.&lt;/p&gt;
&lt;p&gt;Now, a year later, I have over two and a half &lt;em&gt;million&lt;/em&gt; downloads across all my
mods. Hexcasting has been played live on camera by Direwolf20 and Soaryn,
and included in 249 modpacks on Curseforge, including several that are based
wholly around it. The Discord server has 1,571 members, and I even run the only
actually active forum I know of.&lt;/p&gt;
&lt;p&gt;So with one year behind us, and hopefully many more before, I thought I&amp;rsquo;d write
a little blog post doing a bit of retrospection. What I&amp;rsquo;ve learned, where I&amp;rsquo;ve
fallen, where I&amp;rsquo;ve succeeded. For posterity, maybe.&lt;/p&gt;
&lt;h2 id=&#34;two-and-a-half-million-downloads&#34;&gt;Two and a Half MILLION Downloads&lt;/h2&gt;
&lt;p&gt;I don&amp;rsquo;t know how to process that number. That is &lt;em&gt;so&lt;/em&gt; many. That&amp;rsquo;s more
downloads than people living in nearly every place I&amp;rsquo;ve lived. That&amp;rsquo;s more
than the number of people I will ever learn the name of &amp;ndash; that&amp;rsquo;s probably
more than the number of people I will ever &lt;em&gt;speak&lt;/em&gt; to.&lt;/p&gt;
&lt;p&gt;I know that download count isn&amp;rsquo;t everything. There are lots of great mods with
small download counts, and there are a lot of mods with tons of downloads that
suck. But maybe that&amp;rsquo;s easy for me to say cause I&amp;rsquo;m on &lt;em&gt;this&lt;/em&gt; side of the
fence&amp;hellip;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Aside: what the HELL happened December 23rd? December 22nd and before I was
getting about 6,000 downloads per day on Hexcasting and PAUCAL pretty
consistently. Then on the 23rd it spikes up to over 20,000 downloads in the
day. My guess is its people&amp;rsquo;s Christmas break?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&amp;rsquo;d really like to thank a few people here, for agreeing to poke at some funny
little magic mod and get it in front of their audiences. Firstly Vazkii, who
opened the door to getting Direwolf20 to play with it, and of course Dire, who
wasn&amp;rsquo;t afraid to stumble around the stack on camera. I&amp;rsquo;d like to thank the FTB
dev team for putting Hexcasting in the 1.18 DW20 pack, the first big modpack it
got into, and all the other modpack devs who have wrangled its strange form
into fitting in the pack.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d also like to thank Vallen, from Mischief of Mice. He was the first person
who agreed to put the mod on camera, but after trying it, he decided he couldn&amp;rsquo;t
do it justice with a clean explanation. I&amp;rsquo;d like to thank him for acceping that
he couldn&amp;rsquo;t figure it out &amp;hellip; oh, I&amp;rsquo;m not doing a good job of coming up with
words here that don&amp;rsquo;t sound condescending. I guess I&amp;rsquo;d just like to thank him
for tapping out, instead of releasing something confusing.&lt;/p&gt;
&lt;h2 id=&#34;lore&#34;&gt;Lore&lt;/h2&gt;
&lt;p&gt;I am proud of the lore for Hexcasting.&lt;/p&gt;
&lt;p&gt;I do, however, have a lot of stray thoughts about it, and I suppose this post
is as good a time as any to let them out.&lt;/p&gt;
&lt;p&gt;To put it lightly, it is &lt;em&gt;not&lt;/em&gt; a nice mod. The mod encourages you to do some
truly horrifying things in the lategame. And I suppose in the spirit of lifting
the curtain, I should say when the ideas for mindflaying first started spinning
around in my head, I really didn&amp;rsquo;t have anything more to think about it. I
implemented it mostly because it was fucked up and spooky and because I dislike
villager trading as a mechanic, and in general I was a lot stupider about the
stuff I &amp;ldquo;canonicalized.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;But I&amp;rsquo;d like to think I&amp;rsquo;m wiser than I was now. I&amp;rsquo;ve kept mindflaying and
Project Wooleye and all mostly as-is from those careless ideas, and I&amp;rsquo;ve done
that because I think I made something thought-provoking.&lt;/p&gt;
&lt;p&gt;I figure that it is OK to write about horrible, unethical things. It gets
stickier, however, when you encourage people to &lt;em&gt;do&lt;/em&gt; them, like the mod does.
I&amp;rsquo;d like to think that what I&amp;rsquo;m doing is OK for two reasons.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I am not at all &lt;em&gt;advocating&lt;/em&gt; for the player-character. I have done my best to
make it &lt;em&gt;really&lt;/em&gt; clear if you are rooting for them you are doing something
wrong.&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;m not especially trying to make a statement with the mechanics. I think it
would be &lt;em&gt;very&lt;/em&gt; crass of me to try and draw some parallels between the events
of the mod and some other human tragedy. Instead, I&amp;rsquo;m simply putting things
out into the world and letting you, the player, wrestle with them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And I think I&amp;rsquo;ve succeeded in these two points. I get a lot of worried comments
from friends asking if I think I&amp;rsquo;m going to get cancelled or dogpiled upon for
writing Hexcasting, but so far the most concern I&amp;rsquo;ve gotten is from people
worrying about worry, not anyone actually voicing about the mod. And I&amp;rsquo;ve heard
from other people who &lt;em&gt;refuse&lt;/em&gt; to play the endgame, who will get enlightened
and play with great spells, but who refuse to mindflay anything because it makes
them feel icky. I think these things together tell me that, although I am
definitely playing with fire, I&amp;rsquo;m doing it in a way that&amp;rsquo;s OK.&lt;/p&gt;
&lt;p&gt;And now that the lore is over and written and it&amp;rsquo;s had time to sit, I&amp;rsquo;m
starting to see one possible reading of the lore that I think is interesting.
Is it pretentious to analyze the writings of you and a friend like they&amp;rsquo;re some
great literary work? Maybe. But I&amp;rsquo;m going to do it anyways.&lt;/p&gt;
&lt;p&gt;I find it &lt;em&gt;fascinating&lt;/em&gt; how the way people act changes in different contexts.
Here&amp;rsquo;s an example; I&amp;rsquo;ve been watching &lt;a href=&#34;https://www.youtube.com/watch?v=8olgNZJh6vA&amp;list=PLnC1rWWvOq51mTk75cMY8LENgR9FHWcyl&#34;&gt;ilmango&amp;rsquo;s Vanilla Skyblock series&lt;/a&gt;,
and one of the major progression gates is villager trading. As anyone who&amp;rsquo;s
done villager trading knows, it is immensely frustrating. In a moment of anger
at a villager who won&amp;rsquo;t go where he wants them to go, he punches them off the
platform into the void, and says &amp;ldquo;if you want to have a mind of your own, you
can do it in the void.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;So, there&amp;rsquo;s some sequence of events that starts with ilmango, who I trust to be
a reasonable and nice person, and ends with him punching (a video-game
representation of) another person to their death for being too independent.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not saying that ilmango is some kind of twisted psychopath inside; in fact
I&amp;rsquo;d like to explicitly say the opposite. It&amp;rsquo;s macabre, I know, but I am
fascinated by how you can construct contexts in which people would do things
they ordinarily never would.&lt;/p&gt;
&lt;p&gt;So I guess you can read mindflaying as a sort of landscape in which you have to
sit with that difficult question. &amp;ldquo;Am I going to do it? Is it OK that I did?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s no value judgement there from me, and to be honest I don&amp;rsquo;t think the
answer matters all that much. I&amp;rsquo;d just like to think I&amp;rsquo;ve created something
provocative enough that you can sit and wrestle with yourself and your
thoughts.&lt;/p&gt;
&lt;h2 id=&#34;money&#34;&gt;Money&lt;/h2&gt;
&lt;p&gt;And now for something completely different: how much money do I make?&lt;/p&gt;
&lt;p&gt;Money is a big ol taboo but I do think it&amp;rsquo;s very important to talk about it,
so I&amp;rsquo;ll do this quick. On both Curseforge and Modrinth I get about a dollar
for every 2,000 downloads. Since I started making any money off of this March
2022, I&amp;rsquo;ve made on average $434.50 per month between Curseforge, Patreon, and
commissions (although the amount per month varies wildly).&lt;/p&gt;
&lt;p&gt;No one wants to hear it but I&amp;rsquo;ll say it anyways: please do not start Minecraft
modding in the hope you&amp;rsquo;ll make a lot of money. You&amp;rsquo;ll probably be really
disappointed, but more to the point making money is a really shit motivator.
You&amp;rsquo;ll have a lot more fun if you&amp;rsquo;re modding for the joy of modding, and see
any money you might make as a fun bonus on top.&lt;/p&gt;
&lt;p&gt;That being said, though, it is quite nice to be paid for what I love to do. It&amp;rsquo;s
not nearly enough to live on or anything, but it does help me pay the bills on
top of my work study at college. It&amp;rsquo;s especially nice because there&amp;rsquo;s such a
huge separation between work put in and money made; as I&amp;rsquo;ve demonstrated to
myself over my December-long hiatus from Hexcasting I can take it easy and
money will still trickle in, and I think that ontological distance is really
good for my mental health.&lt;/p&gt;
&lt;h2 id=&#34;and-thats-all-folks&#34;&gt;And That&amp;rsquo;s All Folks&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve got a couple more things in the tubes. The next Hexcasting major update
will probably be mostly bugfixes and balancing; there&amp;rsquo;s a lot of rough edges to
the mod that I just haven&amp;rsquo;t taken the time to clean up.&lt;/p&gt;
&lt;p&gt;Work on Bemis is slowing down mostly because it&amp;rsquo;s so &lt;em&gt;boring&lt;/em&gt;. I really want
the mod to exist. but almost all the work to be done is munging data around
into Asciidoctor, which really doesn&amp;rsquo;t like outputting to things that aren&amp;rsquo;t
text. Props to Vazkii; there is a &lt;em&gt;lot&lt;/em&gt; that goes into making a documentation
mod.&lt;/p&gt;
&lt;p&gt;Come back next time for Bemis 2: Just Write Your Docs On A Goddamn Web Site
And Send Your Players There.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Also, I am super smart and overwrote the State of the Petrak@ with this file.
Oof. I have a backup on my old laptop and I&amp;rsquo;ll fix it when I get back to
college in a few days.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>A Proof that `0^0 = 1` using Type Algebra</title>
      <link>/blog/2022-09-17_factorial/</link>
      <pubDate>Sat, 17 Sep 2022 14:22:29 -0500</pubDate>
      
      <guid>/blog/2022-09-17_factorial/</guid>
      <description>&amp;hellip; As taught by someone whose experience with type algebra consists of &amp;ldquo;figuring it out&amp;rdquo; and &amp;ldquo;being drip-fed things by Alwinfy.&amp;rdquo; This is going to be fast and loose.
Anyways. Type algebra is doing math on types. The core idea, I suppose, is that a type can be represented as an integer that is the number of possible values for the type.
That&amp;rsquo;s a weird idea, but let&amp;rsquo;s just try playing with it on some simple types.</description>
      <content>&lt;p&gt;&amp;hellip; As taught by someone whose experience with type algebra consists of &amp;ldquo;figuring it out&amp;rdquo; and &amp;ldquo;being drip-fed things by Alwinfy.&amp;rdquo;
This is going to be fast and loose.&lt;/p&gt;
&lt;p&gt;Anyways. Type algebra is doing math on types. The core idea, I suppose, is that a type can be represented as an integer that is the
number of possible values for the type.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s a weird idea, but let&amp;rsquo;s just try playing with it on some simple types. What about &lt;code&gt;bool&lt;/code&gt;? There are two values, &lt;code&gt;true&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt;,
so &lt;code&gt;bool = 2&lt;/code&gt;. We could imagine some kind of type with three states, which mathematicians call &lt;code&gt;Z3&lt;/code&gt; (&amp;ldquo;Z sub 3&amp;rdquo;), and that would equal &lt;code&gt;3&lt;/code&gt;,
of course. &lt;code&gt;u8&lt;/code&gt;, an unsigned 8-bit integer, would equal &lt;code&gt;2^8 = 256&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Also, note that &lt;code&gt;i8&lt;/code&gt;, a signed 8-bit integer, also equals &lt;code&gt;256&lt;/code&gt;. Only the &lt;em&gt;number&lt;/em&gt; of values matters in type algebra, not whatever the values
might actually be. Because you can losslessly convert from &lt;code&gt;i8&lt;/code&gt; to &lt;code&gt;u8&lt;/code&gt; and back, in type algebra they&amp;rsquo;re considered the same.&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2 id=&#34;composing-types&#34;&gt;Composing Types&lt;/h2&gt;
&lt;p&gt;Now, of course in computer science we can combine types into other types. For example, we can do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MyType&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    foo: &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    bar: &lt;span style=&#34;color:#a6e22e&#34;&gt;Z3&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(I&amp;rsquo;m writing that in Rust, but the language doesn&amp;rsquo;t really matter.)&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s think about what integer is equivalent to &lt;code&gt;MyType&lt;/code&gt;. We can enumerate the options pretty easily:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;{ foo: false, bar: 0 }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{ foo: false, bar: 1 }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{ foo: false, bar: 2 }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{ foo: true, bar: 0 }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{ foo: true, bar: 1 }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{ foo: true, bar: 2 }&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Alright, so &lt;code&gt;MyType = 6&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;What about a pair of &lt;code&gt;(bool, u8)&lt;/code&gt;? Well, we have 256 options for the &lt;code&gt;u8&lt;/code&gt;, and for each of them we can pick &lt;code&gt;true&lt;/code&gt; or
&lt;code&gt;false&lt;/code&gt; for the &lt;code&gt;bool&lt;/code&gt;. So it looks like &lt;code&gt;(bool, u8) = 2 * 256 = 512&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Hang on a moment. We know that &lt;code&gt;bool = 2&lt;/code&gt; and &lt;code&gt;u8 = 256&lt;/code&gt;&amp;hellip; and the size of &lt;code&gt;(bool, u8)&lt;/code&gt;, 512, was the result of multiplying
them together. Similarly, &lt;code&gt;MyType&lt;/code&gt; equaled &lt;code&gt;6 = bool * Z3 = 2 * 3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So, in type algebra, &lt;em&gt;making a struct is multiplication.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We can test this idea with some property-based tests. What do we know about multiplication? Casting back to grade school,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Commutative property: &lt;code&gt;x*y = y*x&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Associative property: &lt;code&gt;x*(y*z) = (x*y)*z&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Distributive property: &lt;code&gt;x*(y+z) = x*y + x*z&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Identity property: &lt;code&gt;x * 1 = x&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Zero property: &lt;code&gt;x * 0 = 0&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can&amp;rsquo;t test the last three properties because we don&amp;rsquo;t have an analogue for addition or the numbers 0 or 1 (yet). But let&amp;rsquo;s try out the other two:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;MyType&lt;/code&gt; would have 6 possible values no matter if it was defined with &lt;code&gt;foo&lt;/code&gt; before &lt;code&gt;bar&lt;/code&gt; or &lt;code&gt;bar&lt;/code&gt; before &lt;code&gt;foo&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Let&amp;rsquo;s examine &lt;code&gt;(bool, (Z3, Z4))&lt;/code&gt;. We know &lt;code&gt;(Z3, Z4)&lt;/code&gt; has &lt;code&gt;12 = 3*4&lt;/code&gt; possibilities (we could enumerate them if we want), and so
&lt;code&gt;(bool, (Z3, Z4))&lt;/code&gt; has &lt;code&gt;24 = 2*12&lt;/code&gt;. And if we change that to &lt;code&gt;((bool, Z3), Z4)&lt;/code&gt;, we already wrote all 6 possibilities for &lt;code&gt;(bool, Z3) = 6&lt;/code&gt;.
And that all multiplies together to &lt;code&gt;24 = 6*4&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Alright! Now, if we could only find a nice analogue for addition.&lt;/p&gt;
&lt;h2 id=&#34;a-nice-analogue-for-addition&#34;&gt;A Nice Analogue for Addition&lt;/h2&gt;
&lt;p&gt;Well, let&amp;rsquo;s start by exploring around. We know, say, &lt;code&gt;2 + 3 = 5&lt;/code&gt; in normal-math-land. So we need to do &lt;em&gt;something&lt;/em&gt; to &lt;code&gt;bool&lt;/code&gt; and &lt;code&gt;Z3&lt;/code&gt; and end up with five possibilities.&lt;/p&gt;
&lt;p&gt;We can go back to listing the possibilities outright, like we did way back at the beginning of the article.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bool&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;false&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Z3&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;hellip; and hey wait a second. Let&amp;rsquo;s remove the type headers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;false&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And lookie here, we end up with five possibilities! It looks like the analogue of addition is &lt;em&gt;picking one type or the other&lt;/em&gt;. So, &lt;code&gt;bool | Z3 = 2 + 3 = 5&lt;/code&gt;.&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;What about &lt;code&gt;Z3 | Z4&lt;/code&gt;? That looks like it should just be 7, but if we write them out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;3&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;hellip; we have repeats. It looks like we need to consider numbers of different types to be completely different. Some languages (like Rust) do this; most (like C and Java)
will automatically convert between numerical types sometimes. But in type algebra, the &lt;code&gt;0&lt;/code&gt; from &lt;code&gt;Z3&lt;/code&gt; and &lt;code&gt;0&lt;/code&gt; from &lt;code&gt;Z4&lt;/code&gt; have to be completely different.&lt;/p&gt;
&lt;p&gt;As an argument for that, imagine that we did fold these things together. So, &lt;code&gt;Z2 | Z3&lt;/code&gt; would have the values &lt;code&gt;0, 1, 2&lt;/code&gt;, and would equal &lt;code&gt;3&lt;/code&gt;. And &lt;code&gt;bool | Z3&lt;/code&gt; would have the values
&lt;code&gt;true, false, 0, 1, 2&lt;/code&gt;, and would equal 5. But we know that &lt;code&gt;bool = Z2&lt;/code&gt;, so we would have &lt;code&gt;3 = 5&lt;/code&gt; &amp;hellip; so we can&amp;rsquo;t have that. To avoid ambiguity, if it would be ambiguous I&amp;rsquo;ll
mark them as &lt;code&gt;Z3(0)&lt;/code&gt; and &lt;code&gt;Z4(0)&lt;/code&gt; or whatever.&lt;/p&gt;
&lt;p&gt;Anyone who&amp;rsquo;s coded in Rust (🚀🚀🚀) might recognize this addition operator as its enum construct. TypeScript coders might recognize it as its union types.&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; And programmers of Haskell or OCaml might recognize
it as an algebraic data type. Hey, it&amp;rsquo;s the same &lt;strong&gt;algebra&lt;/strong&gt; as in type &lt;strong&gt;algebra&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Again, let&amp;rsquo;s try picking at some property based tests. Addition has the following properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Commutative property: &lt;code&gt;x+y = y+x&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Associative property: &lt;code&gt;x+(y+z) = (x+y)+z&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Identity property: &lt;code&gt;x + 0 = x&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;(And the distributive property which we covered above)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We also don&amp;rsquo;t know a type for the number &lt;code&gt;0&lt;/code&gt;, but let&amp;rsquo;s try out the other two:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bool | Z3 = Z3 | bool = 5&lt;/code&gt;; it doesn&amp;rsquo;t matter which order we write the types in (&lt;code&gt;true, false, 0, 1, 2&lt;/code&gt; vs &lt;code&gt;0, 1, 2, true, false&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bool | (Z3 | Z4) = 2 + (3 + 4) = 7&lt;/code&gt;; &lt;code&gt;(bool | Z3) | Z4 = (2 + 3) + 4 = 7&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hey, that all seems to check out. Now, let&amp;rsquo;s tackle the distributive property. In other words, &lt;code&gt;(bool, (Z3 | Z4))&lt;/code&gt; should equal &lt;code&gt;(bool, Z3) | (bool, Z4)&lt;/code&gt;.
Well, these types are all small enough that we can just enumerate them.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;(bool, (Z3 | Z4))&lt;/code&gt; has 14 possibilities:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;true, Z3(0)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;true, Z3(1)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;true, Z3(2)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;true, Z4(0)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;true, Z4(1)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;true, Z4(2)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;true, Z4(3)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;false, Z3(0)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;false, Z3(1)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;false, Z3(2)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;false, Z4(0)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;false, Z4(1)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;false, Z4(2)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;false, Z4(3)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(bool, Z3) | (bool, Z4)&lt;/code&gt; also has 14 possibilities. I&amp;rsquo;ll label the options &lt;code&gt;L&lt;/code&gt; and &lt;code&gt;R&lt;/code&gt; for &lt;code&gt;L&lt;/code&gt;eft and &lt;code&gt;R&lt;/code&gt;right:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;L(true, 0)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;L(true, 1)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;L(true, 2)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;L(false, 0)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;L(false, 1)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;L(false, 2)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;R(true, 0)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;R(true, 1)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;R(true, 2)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;R(true, 3)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;R(false, 0)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;R(false, 1)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;R(false, 2)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;R(false, 3)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nice! Now if only we had types for 0 and 1.&lt;/p&gt;
&lt;h2 id=&#34;types-for-0-and-1&#34;&gt;Types for 0 and 1&lt;/h2&gt;
&lt;p&gt;A type for &lt;code&gt;1&lt;/code&gt; would have exactly one value. Not a lot of languages have this, but some do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rust has the &lt;code&gt;()&lt;/code&gt; type, pronounced &amp;ldquo;unit.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Java has the &lt;code&gt;Void&lt;/code&gt; type, which can only ever be &lt;code&gt;null&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;TypeScript lets you define &amp;ldquo;string types,&amp;rdquo; where the only valid value of that type is that particular string. Note that under type algebra all these string types
are considered the same.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For this article I&amp;rsquo;ll call this &lt;code&gt;unit&lt;/code&gt;. And we can play around with it: a struct &lt;code&gt;(T, ())&lt;/code&gt; adds no more information to &lt;code&gt;T&lt;/code&gt; that wasn&amp;rsquo;t already there. Hey look &lt;code&gt;x * 1 = 1&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;What about &lt;code&gt;0&lt;/code&gt;? A type that has &lt;em&gt;no&lt;/em&gt; values? What would you ever want that for?&lt;/p&gt;
&lt;p&gt;Actually, it&amp;rsquo;s quite handy. Both Rust and TypeScript have this and call it &lt;code&gt;never&lt;/code&gt;.&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; It&amp;rsquo;s the type of things like exiting the program or throwing an exception. The secret
sauce here is that both languages implicitly cast that type to anything else, which is OK because you can never have a value of that type. This lets you write type-checking
code like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ts&#34; data-lang=&#34;ts&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;myNum&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;number&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;// type of this branch is number
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DivideByZero&lt;/span&gt;() &lt;span style=&#34;color:#75715e&#34;&gt;// type of this branch is never, which we can pretend is a number because 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;                         &lt;span style=&#34;color:#75715e&#34;&gt;// we&amp;#39;ll never get to do anything with `myNum`
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But that&amp;rsquo;s the realm of actual computer science; we&amp;rsquo;re doing type algebra here. And we can test the additive identity with our new &lt;code&gt;never&lt;/code&gt; type. What happens if we go &lt;code&gt;x + 0&lt;/code&gt;?
We get something like &lt;code&gt;T | never&lt;/code&gt;. And look at that! We can&amp;rsquo;t actually have a &lt;code&gt;never&lt;/code&gt;. so &lt;code&gt;T | never = T&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can also test the multiplicative zero property: what happens if we have a type &lt;code&gt;(T, never)&lt;/code&gt;? Well, we can&amp;rsquo;t actually construct an instance of that type, because we would need
to get a &lt;code&gt;never&lt;/code&gt; somehow and we can&amp;rsquo;t. So, &lt;code&gt;(T, never)&lt;/code&gt; has 0 values &amp;hellip; and hey look, &lt;code&gt;x * 0 = 0&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;an-aside-about-generics&#34;&gt;An Aside About Generics&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s look at this type here.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;enum&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MyEnum&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    TheType(T),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Boolean(&lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(If you don&amp;rsquo;t know rust, that&amp;rsquo;s how you would write the equivalent of &lt;code&gt;T | bool&lt;/code&gt;. The &lt;code&gt;&amp;lt;T&amp;gt;&lt;/code&gt; is a generic parameter, meaning you can put any type you like in there).&lt;/p&gt;
&lt;p&gt;You know the drill, start plugging things into it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;MyEnum&amp;lt;Z3&amp;gt; = Z3 | bool = 3 + 2 = 5 &lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MyEnum&amp;lt;bool&amp;gt; = bool | bool = 2 + 2 = 4&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MyEnum&amp;lt;u8&amp;gt; = u8 | bool | 256 + 2 = 258&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;hellip; hey, that looks an awful lot like the function &lt;code&gt;f(x) = x + 2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In type algebra, &lt;em&gt;types with generics are functions.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&#34;exponentiation&#34;&gt;Exponentiation&lt;/h2&gt;
&lt;p&gt;Now let&amp;rsquo;s get onto the thing I actually promised in the title of the article. What on earth could exponentiation represent?&lt;/p&gt;
&lt;p&gt;Like we learned above, we&amp;rsquo;re going to want some generic type over two types, &lt;code&gt;T&lt;/code&gt; and &lt;code&gt;U&lt;/code&gt;, that somehow ends up exponentiating them.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at a simple arithmetic example again, let&amp;rsquo;s say &lt;code&gt;3^2&lt;/code&gt;. From grade school we know exponentiation is repeated multiplication,
so this equals &lt;code&gt;3 * 3&lt;/code&gt;. So we&amp;rsquo;re looking for something that will repeat &lt;code&gt;Z3&lt;/code&gt; twice, like a struct that automatically has two fields.&lt;/p&gt;
&lt;p&gt;Or how about &lt;code&gt;5^3&lt;/code&gt;? That&amp;rsquo;s &lt;code&gt;5*5*5&lt;/code&gt;, so we want something that has three fields of &lt;code&gt;Z5&lt;/code&gt;. In fact, any &lt;code&gt;T^U&lt;/code&gt; can be read as &amp;ldquo;something with the number &lt;code&gt;U&lt;/code&gt;
fields of type &lt;code&gt;T&lt;/code&gt;&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;So we have every value in &lt;code&gt;U&lt;/code&gt;, and a &lt;code&gt;T&lt;/code&gt; associated with each one. What does that sound like? Well,&lt;/p&gt;
&lt;p&gt;&amp;hellip; it&amp;rsquo;s a &lt;code&gt;HashMap&amp;lt;U, T&amp;gt;&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;Well, almost. Most languages don&amp;rsquo;t require every &lt;code&gt;U&lt;/code&gt; key to have an associated &lt;code&gt;T&lt;/code&gt; value. So I&amp;rsquo;ll call the exponentiation function an &lt;code&gt;OmniMap&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s enumerate one of these &lt;code&gt;OmniMap&lt;/code&gt;s to make sure we&amp;rsquo;re not completely barking up the wrong tree. What about checking &lt;code&gt;3^2&lt;/code&gt;? That would be
&lt;code&gt;OmniMap&amp;lt;bool, Z3&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;{true =&amp;gt; 0, false =&amp;gt; 0}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{true =&amp;gt; 0, false =&amp;gt; 1}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{true =&amp;gt; 0, false =&amp;gt; 2}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{true =&amp;gt; 1, false =&amp;gt; 0}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{true =&amp;gt; 1, false =&amp;gt; 1}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{true =&amp;gt; 1, false =&amp;gt; 2}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{true =&amp;gt; 2, false =&amp;gt; 0}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{true =&amp;gt; 2, false =&amp;gt; 1}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{true =&amp;gt; 2, false =&amp;gt; 2}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;hellip; and lo and behold there are 9 values!&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re at the home stretch here! Let&amp;rsquo;s look at powers of 0. &lt;code&gt;0^3&lt;/code&gt;, say, would be &lt;code&gt;OmniMap&amp;lt;Z3, never&amp;gt;&lt;/code&gt;. Let&amp;rsquo;s go and construct that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;{0 =&amp;gt; ... wait a minute }&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can&amp;rsquo;t actually construct &lt;em&gt;any&lt;/em&gt; values of &lt;code&gt;OmniMap&amp;lt;Z3, never&amp;gt;&lt;/code&gt;, because in order to do so, we would need a value of type &lt;code&gt;never&lt;/code&gt;. So, &lt;code&gt;0^3 = 0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Alright. We&amp;rsquo;re ready to tackle &lt;code&gt;0^0&lt;/code&gt;. That would be &lt;code&gt;OmniMap&amp;lt;never, never&amp;gt;&lt;/code&gt;. And &amp;hellip; we can construct exactly one value of that type: the empty map,
&lt;code&gt;{}&lt;/code&gt;, with no keys and no values. And so, &lt;code&gt;0^0 = 1&lt;/code&gt;. QED.&lt;/p&gt;
&lt;h2 id=&#34;lightning-round&#34;&gt;Lightning Round&lt;/h2&gt;
&lt;p&gt;The article proper&amp;rsquo;s over! But type algebra is so cool, here&amp;rsquo;s an unedited coredump of a bunch of other type algebra fun stuff.&lt;/p&gt;
&lt;h3 id=&#34;functions-are-also-exponentiation&#34;&gt;Functions Are Also Exponentiation&lt;/h3&gt;
&lt;p&gt;This &amp;ldquo;omnimap&amp;rdquo; is actually the mathematical definition of a function; a mapping from one type to another. I chose to use omnimaps instead of functions
for the example because I think it makes the &lt;code&gt;0^0&lt;/code&gt; case easier to understand.&lt;/p&gt;
&lt;h3 id=&#34;lists&#34;&gt;Lists&lt;/h3&gt;
&lt;p&gt;Lists are nice, easy types, right? What&amp;rsquo;s a list in type algebra? Well, let&amp;rsquo;s look at &lt;code&gt;List&amp;lt;bool&amp;gt;&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[false]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[false, false]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[false, false, false]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whoops, looks like lists are infinite.&lt;/p&gt;
&lt;h3 id=&#34;optional&#34;&gt;Optional&lt;/h3&gt;
&lt;p&gt;A lot of languages have an &amp;ldquo;optional&amp;rdquo; or &amp;ldquo;nullable&amp;rdquo; construct, meaning a value can be whatever value, &lt;em&gt;or&lt;/em&gt; null. So, that&amp;rsquo;s adding one value to the number of values
representable by the type.&lt;/p&gt;
&lt;p&gt;Hey, how does Rust define its &lt;code&gt;Option&amp;lt;T&amp;gt;&lt;/code&gt; type?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;enum&lt;/span&gt; Option&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Some(T),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    None,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;AKA, &lt;code&gt;T | unit&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;orderings&#34;&gt;Orderings&lt;/h3&gt;
&lt;p&gt;What about an ordering? That is, a list containing exactly one of each value of a type.&lt;/p&gt;
&lt;p&gt;Well, for the first slot in the list, we have &lt;code&gt;T&lt;/code&gt; options. For the next, we have &lt;code&gt;T-1&lt;/code&gt; options, because one of them we already picked for the first slot.
For the slot after that we have &lt;code&gt;T-2&lt;/code&gt; &amp;hellip; and so the total number of options for the ordering is &lt;code&gt;T * (T-1) * (T-2) * (T-3) * ... * 1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s factorial! &lt;code&gt;Ordering&amp;lt;T&amp;gt; = T!&lt;/code&gt;.&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s examine the identity &lt;code&gt;(T + 1)! = (T + 1) * T!&lt;/code&gt;. So, &lt;code&gt;Ordering&amp;lt;Z3&amp;gt; = (Z3, Ordering&amp;lt;bool&amp;gt;)&lt;/code&gt;. And that&amp;rsquo;s the car/cdr definition of a list.&lt;/p&gt;
&lt;h3 id=&#34;you-can-take-the-derivative-of-types&#34;&gt;You Can Take The Derivative Of Types&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;http://strictlypositive.org/diff.pdf&#34;&gt;http://strictlypositive.org/diff.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I won&amp;rsquo;t pretend to understand this any more than you do.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Mathematicians call this &amp;ldquo;lossless conversion&amp;rdquo; function a &amp;ldquo;bijection,&amp;rdquo; as in &amp;ldquo;we can form a bijection from &lt;code&gt;i8&lt;/code&gt; to &lt;code&gt;u8&lt;/code&gt;.&amp;rdquo;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;I&amp;rsquo;m using TypeScript&amp;rsquo;s union type notation here, &lt;code&gt;T | U&lt;/code&gt;. This is because Rust doesn&amp;rsquo;t let you define enums inline like this and I&amp;rsquo;ve never used Haskell.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;Actually, TypeScript will fold together identical types, so &lt;code&gt;number | number == number&lt;/code&gt;. But I&amp;rsquo;ll ignore that.&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;OK, Rust actually calls it &lt;code&gt;!&lt;/code&gt;, but it&amp;rsquo;s pronounced &lt;code&gt;never&lt;/code&gt;.&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;An early version of this article was a proof that &lt;code&gt;0! = 1&lt;/code&gt;. The proof is that an &lt;code&gt;Ordering&amp;lt;never&amp;gt;&lt;/code&gt; has exactly one value, the empty list.&amp;#160;&lt;a href=&#34;#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
    </item>
    
    <item>
      <title>The Current Project #8: Fabulous Prefabs</title>
      <link>/blog/2022-08-19_tcp8/</link>
      <pubDate>Fri, 19 Aug 2022 12:28:36 -0500</pubDate>
      
      <guid>/blog/2022-08-19_tcp8/</guid>
      <description>I guess I&amp;rsquo;m renaming this series to TCP now, for &amp;ldquo;The Current Project.&amp;rdquo; I&amp;rsquo;ve updated the tags on the old posts accordingly.
Anyways! Work on that project I talked about last week is going pretty great. While it&amp;rsquo;s indev, I&amp;rsquo;ve code-named1 it &amp;ldquo;Robot Language&amp;rdquo; after the meganeko album. Starting fresh has been really good for me, I think; I have gotten way more done in a week and a bit than I could have on Foxfire.</description>
      <content>&lt;p&gt;I guess I&amp;rsquo;m renaming this series to TCP now, for &amp;ldquo;The Current Project.&amp;rdquo; I&amp;rsquo;ve updated the tags on the old posts accordingly.&lt;/p&gt;
&lt;p&gt;Anyways! Work on that project I talked about last week is going pretty great. While it&amp;rsquo;s indev, I&amp;rsquo;ve
code-named&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; it &amp;ldquo;Robot Language&amp;rdquo; after the &lt;a href=&#34;https://meganeko.bandcamp.com/album/robot-language&#34;&gt;meganeko album&lt;/a&gt;.
Starting fresh has been really good for me, I think; I have gotten &lt;em&gt;way&lt;/em&gt; more done in a week and a bit than I could have on
Foxfire. I&amp;rsquo;ve implemented rendering, collision, FOV calculations &amp;hellip; lots and lots of things.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a screenshot of the game as it is so far.&lt;/p&gt;

  &lt;figure class=&#34;left&#34; &gt;
    &lt;a href=&#34;/img/2022-08-19_tcp8/1.png &#34;&gt;
      &lt;img src=&#34;/img/2022-08-19_tcp8/1.png&#34;  alt=&#34;An at sign stands in a dining hall drawn in characters, featuring some scattered tables and chars, and a kitchenette. 
        There&amp;#39;s a subtle CRT effect applied over the screen. A panel on the right says &amp;#34;Sink: Muddy waste pops up from the drain.&amp;#34;&#34;   /&gt;
    &lt;/a&gt;
    
      &lt;figcaption class=&#34;left&#34; &gt;That better CRT effect is courtesy of &lt;a href=&#34;https://www.youtube.com/watch?v=aWdySZ0BtJs&#34;&gt;a video by Acerola&lt;/a&gt;.
        The FOV calculations use &lt;a href=&#34;http://www.adammil.net/blog/v125_Roguelike_Vision_Algorithms.html&#34;&gt;Adam Milazzo&#39;s algorithm.&lt;/a&gt;&lt;/figcaption&gt;
    
  &lt;/figure&gt;


&lt;p&gt;It&amp;rsquo;s a mystery game, so I won&amp;rsquo;t reveal too much &amp;hellip; but I will say you wake up on a spacecraft with no memory, and have to figure out
what is going on. I&amp;rsquo;ve been playing Outer Wilds recently, and I&amp;rsquo;m really inspired by the idea of a metroidvania where your &amp;ldquo;keys&amp;rdquo; are
knowledge.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t think I&amp;rsquo;ve heard of a game that mixes metroidvanias with Zelda-like dungeons. To me, a Zelda dungeon feels kinda like a
metroidvania in minature.&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; The plan is to have the larger challenges in the game be unlocked with knowledge,
and smaller, self-contained challenges styled after Zelda dungeons with a key item that unlocks new areas in the ship.&lt;/p&gt;
&lt;p&gt;But we&amp;rsquo;ll see as I design it more.&lt;/p&gt;
&lt;h2 id=&#34;prefabs&#34;&gt;Prefabs&lt;/h2&gt;
&lt;p&gt;But anyways this post is not really about Robot Language; it&amp;rsquo;s about a (technology? idea? algorithm?) I&amp;rsquo;ve developed as I write the game.&lt;/p&gt;
&lt;p&gt;Robot Language&amp;rsquo;s world layout will have no randomization, given it&amp;rsquo;s a metroidvania-like. So, I need some way to make
the world, and doing it from code would be a pain in the ass.&lt;/p&gt;
&lt;p&gt;So, in short, what I do is I draw out a map in &lt;a href=&#34;https://www.gridsagegames.com/rexpaint/&#34;&gt;RexPaint&lt;/a&gt;, a kinda crufty but very useful
tool for drawing ASCII art. Then, the game loads the file at runtime using the aptly-named &lt;a href=&#34;https://crates.io/crates/rexpaint&#34;&gt;rexpaint crate&lt;/a&gt;.
Each character and its foreground color is then mapped to a prefab. That mapping is written in &lt;a href=&#34;https://kdl.dev/&#34;&gt;KDL&lt;/a&gt;,
a language like XML but not horrible to write which &lt;a href=&#34;https://lemmaeof.gay/&#34;&gt;Lemma&lt;/a&gt; has totally hooked me on.
Then, those prefabs are mapped to actual collections of components in code.&lt;/p&gt;
&lt;p&gt;I realize that makes no sense, so here&amp;rsquo;s some pictures to show you what I&amp;rsquo;m talking about.&lt;/p&gt;

  &lt;figure class=&#34;left&#34; &gt;
    &lt;a href=&#34;/img/2022-08-19_tcp8/2.png &#34;&gt;
      &lt;img src=&#34;/img/2022-08-19_tcp8/2.png&#34;  alt=&#34;A zoomed out view of the previous screenshot, revealing a large area of mostly hallways. Doors are marked in red and green, and walls
        that used to have connected textures are just hashtags.&#34;   /&gt;
    &lt;/a&gt;
    
      &lt;figcaption class=&#34;left&#34; &gt;Here&#39;s the map file for the area of the ship the previous screenshot is of. It&#39;s not cut off at the edge; this is a rotating spaceship! 
        This zone is a ring is connected at the left and right.&lt;/figcaption&gt;
    
  &lt;/figure&gt;


&lt;p&gt;Here&amp;rsquo;s part of &lt;code&gt;prefabs.kdl&lt;/code&gt;, which is loaded by the game on startup.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-kdl&#34; data-lang=&#34;kdl&#34;&gt;&amp;#34;#&amp;#34; color=0xffffff {
    prefab &amp;#34;wall&amp;#34;
    type &amp;#34;inner&amp;#34;
}
&amp;#34;#&amp;#34; color=0x3333ff {
    prefab &amp;#34;wall&amp;#34;
    type &amp;#34;outer&amp;#34;
}

&amp;#34;+&amp;#34; color=0xff0000 pass-color=true {
    prefab &amp;#34;door&amp;#34;
    closed true
}
&amp;#34;+&amp;#34; color=0x00ff00 pass-color=true {
    prefab &amp;#34;door&amp;#34;
    closed false
}

// --- Furniture ---

// This orangey color is for food
&amp;#34;T&amp;#34; color=0xff4000 { prefab &amp;#34;table&amp;#34;; type &amp;#34;dining&amp;#34;; }
&amp;#34;T&amp;#34; color=0x6666ff { prefab &amp;#34;table&amp;#34;; type &amp;#34;stainless&amp;#34;; }

&amp;#34;c&amp;#34; color=0xff4000 {
    prefab &amp;#34;widget&amp;#34;
    char 0xe3 // pi
    fg &amp;#34;dark-yellow&amp;#34;
    bg null
    z-level 300
    collider false
    occluder false
    description &amp;#34;chair?plastic&amp;#34;
}

// Angstrom for any and all misc furniture
&amp;#34;0x86&amp;#34; color=0xff4000 { prefab &amp;#34;microwave&amp;#34;; }
&amp;#34;0x86&amp;#34; color=0xd900d9 { prefab &amp;#34;sink&amp;#34;; }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Every character in one of those maps has to have an entry in here where the character and foreground color both match.
By marking &lt;code&gt;pass-color=true&lt;/code&gt;, they can also pass their background color as an argument, which I use for things like notes
that need a whole bunch of indices. (A white &lt;code&gt;≈&lt;/code&gt; with background color &lt;code&gt;0x000000&lt;/code&gt; is note #0, a white &lt;code&gt;≈&lt;/code&gt; with background color &lt;code&gt;0x000001&lt;/code&gt;
is note #1 &amp;hellip; etc.) Then, the &lt;code&gt;prefab&lt;/code&gt; string is matched against a bank of strings in the game code and used to spawn it with the given arguments.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s part of that code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;spawn_prefab&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    world: &lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mut&lt;/span&gt; World,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    globals: &lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Globals&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    prefab_name: &lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;str&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    color_arg: Option&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;u32&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    args: &lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;AHashMap&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;SmolStr, KdlLiteral&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pos: &lt;span style=&#34;color:#a6e22e&#34;&gt;Position&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;) -&amp;gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Entity&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; Some(color_arg) &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; color_arg {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; prefab_name {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;door&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; closed &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; args[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;closed&amp;#34;&lt;/span&gt;].as_bool().unwrap();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                door(world.spawn(), pos, closed, color_arg).build()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;note&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; note(world.spawn(), pos, color_arg).build(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            _ &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; panic!(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;unknown prefab &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{:?}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; (color argument &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{:#x}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                prefab_name, color_arg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; prefab_name {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;player&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; player &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; player(world.spawn(), pos).build();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                world.insert_resource(ThePlayerEntity(player));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                player
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;wall&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; ty &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;args[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;].as_string().unwrap();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                wall(world.spawn(), pos, ty).build()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;table&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; ty &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;args[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;].as_string().unwrap();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                table(world.spawn(), pos, ty).build()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sink&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; sink(world.spawn(), pos).build(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;microwave&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; microwave(world.spawn(), pos).build(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            _ &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; panic!(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;unknown prefab &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{:?}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; (with no color arg)&amp;#34;&lt;/span&gt;, prefab_name),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;player&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;B: &lt;span style=&#34;color:#a6e22e&#34;&gt;EntityBuilder&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;(builder: &lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;, pos: &lt;span style=&#34;color:#a6e22e&#34;&gt;Position&lt;/span&gt;) -&amp;gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    builder
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(Positioned(pos))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(ZLevel(&lt;span style=&#34;color:#66d9ef&#34;&gt;u16&lt;/span&gt;::&lt;span style=&#34;color:#66d9ef&#34;&gt;MAX&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(IsDrawable)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(HasSimpleDrawable(Drawable::simple(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Color::Magenta,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            None,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;b&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;@&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        )))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(Describable(SmolStr::new(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;player&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;wall&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;B: &lt;span style=&#34;color:#a6e22e&#34;&gt;EntityBuilder&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;(builder: &lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;, pos: &lt;span style=&#34;color:#a6e22e&#34;&gt;Position&lt;/span&gt;, ty: &lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;str&lt;/span&gt;) -&amp;gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; (desc, fg, bg) &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; ty {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;inner&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;inner-wall&amp;#34;&lt;/span&gt;, Color::Gray, Color::DarkGray),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;outer&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;outer-wall&amp;#34;&lt;/span&gt;, Color::White, Color::Gray),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _ &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; panic!(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;unknown wall type &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{:?}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;, ty),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    builder
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(Positioned(pos))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(Collider)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(Occluder)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(ZLevel(&lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(IsDrawable)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(HasSimpleDrawable(Drawable::box_drawing(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            fg,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Some(bg),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;walls&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        )))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(Describable(SmolStr::new(desc)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;table&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;B: &lt;span style=&#34;color:#a6e22e&#34;&gt;EntityBuilder&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;(builder: &lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;, pos: &lt;span style=&#34;color:#a6e22e&#34;&gt;Position&lt;/span&gt;, ty: &lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;str&lt;/span&gt;) -&amp;gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; (desc, fg, bg) &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; ty {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dining&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;table?dining&amp;#34;&lt;/span&gt;, Color::DarkYellow, None),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;stainless&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;table?stainless&amp;#34;&lt;/span&gt;, Color::DarkBlue, Some(Color::Gray)),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _ &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; panic!(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;unknown table type &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{:?}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;, ty),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    builder
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(Positioned(pos))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(ZLevel(&lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(Collider)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(IsDrawable)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(HasSimpleDrawable(Drawable::box_drawing(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            fg, bg, &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;table&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        )))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(Describable(SmolStr::new(desc)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// many other spawner funcs elided ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s look at the lifecycle of one of the orange &lt;code&gt;T&lt;/code&gt;s in the dining hall. &amp;ldquo;&lt;code&gt;T&lt;/code&gt; with background color &lt;code&gt;#ff4000&lt;/code&gt;&amp;rdquo; is mapped against
eack entry in &lt;code&gt;prefabs.kdl&lt;/code&gt;, and it matches this one:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-kdl&#34; data-lang=&#34;kdl&#34;&gt;&amp;#34;T&amp;#34; color=0xff4000 { prefab &amp;#34;table&amp;#34;; type &amp;#34;dining&amp;#34;; }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then, the game calls &lt;code&gt;spawn_prefab&lt;/code&gt;, looking for a prefab named &lt;code&gt;&amp;quot;table&amp;quot;&lt;/code&gt; and passing it the arguments &lt;code&gt;{type: &amp;quot;dining&amp;quot;}&lt;/code&gt;.
The &lt;code&gt;match&lt;/code&gt; statement matches it to the &lt;code&gt;table&lt;/code&gt; function, which is called and spawns the entity. Et voila!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I stand on the shoulders of giants here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I first saw the idea of reading prefabs from a file at all from Caves of Qud. I have a bit of an intermediary layer here; Qud&amp;rsquo;s prefabs (called &amp;ldquo;blueprints&amp;rdquo;)
directly put components on the entities, whereas I have this abstraction in the middle. It&amp;rsquo;s less flexible, but it does save me some serde work.
(However! I just finished writing serde support for palkia this morning, so a future version of this might deserialize components directly from the prefab file.)&lt;/li&gt;
&lt;li&gt;Kyzrati/Josh Ge, the person behind rexpaint and cogmind, has &lt;a href=&#34;https://www.gridsagegames.com/blog/2014/07/dungeon-prefabs/&#34;&gt;this blog post&lt;/a&gt; about how they use rexpaint
to add prefabs to dungeon maps. Their use of &amp;ldquo;prefab&amp;rdquo; is a bit different than mine; they mean specific rooms or features. Their implementation is a lot more regimented;
each layer has a specific job, tiles are matched by their color alone on layer 1, and entities are matched by their character alone on layers 3 and 4.
But that works for their game, because they have a lot of random generation to spruce things up (where I have to draw it all myself.)&lt;/li&gt;
&lt;li&gt;The idea of KDL as a prefab language goes to Lemma and its Minecraft mod &lt;a href=&#34;https://github.com/LemmaEOF/KdlyContent&#34;&gt;Kdly Content&lt;/a&gt;, which lets you add blocks and items
using kdl. Also, Caves of Qud uses XML, and KDL more or less maps 1-to-1 to XML, so I figured it would be a good shot.
(Early versions of this idea I had used &lt;a href=&#34;https://github.com/edn-format/edn&#34;&gt;EDN&lt;/a&gt;, which would have been &amp;hellip; fraught.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So yeah! This system lets me prototype really rapidly, which I think is REALLY important for game development.&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; I&amp;rsquo;m also really glad to have figured KDL out; it
really is a joy to write. (All the descriptions for tiles in the game are also written in KDL, and I&amp;rsquo;m planning for all the misc. strings and things to be KDL as well.)&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been working hard making Palkia more useable as I figure out where the rough edges are by working on Robot Language. Next week will probably be a more game-design-y
article, as I bootstrap Robot Language enough that I can start working on the game as opposed to the engine.&lt;/p&gt;
&lt;p&gt;So I&amp;rsquo;ll see you all next week &amp;hellip;&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;&amp;ldquo;Code-named&amp;rdquo; (haven&amp;rsquo;t thought of a real name yet)&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;The ones with lots of backtracking, at least.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;If I were being &lt;em&gt;really&lt;/em&gt; fancy, I could probably set up hot-reloading of the map, with some marker component that indicates it&amp;rsquo;s OK to clear it when reloading.&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
    </item>
    
    <item>
      <title>Foxfire Fridays #7: The Perils of Ambition</title>
      <link>/blog/2022-08-12_fff7/</link>
      <pubDate>Fri, 12 Aug 2022 19:00:57 -0500</pubDate>
      
      <guid>/blog/2022-08-12_fff7/</guid>
      <description>Got some bad news, everyone; I&amp;rsquo;m putting Foxfire on hiatus.
To put it shortly, Foxfire was too ambitious a project for me. I&amp;rsquo;ve never made a video game of this scope before; I&amp;rsquo;ve never released a paid game before; I&amp;rsquo;ve never done devlogs before &amp;hellip; and to try to do all that on top of completely in-house tooling was just too much for me.
I do aim to come back to it at some point, though.</description>
      <content>&lt;p&gt;Got some bad news, everyone; I&amp;rsquo;m putting Foxfire on hiatus.&lt;/p&gt;
&lt;p&gt;To put it shortly, Foxfire was too ambitious a project for me. I&amp;rsquo;ve never made a video game of this scope before;
I&amp;rsquo;ve never released a paid game before; I&amp;rsquo;ve never done devlogs before &amp;hellip; and to try to do all that on top of
completely in-house tooling was just too much for me.&lt;/p&gt;
&lt;p&gt;I do aim to come back to it at some point, though. But we&amp;rsquo;ll see.&lt;/p&gt;
&lt;h2 id=&#34;in-the-interim&#34;&gt;In The Interim&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m going to work on some less ambitious projects, and develop my tooling and my skills. Right now, I&amp;rsquo;m working on
a smaller game; a mystery game about deciphering robot language inspired by what I liked about Outer Wilds.&lt;/p&gt;
&lt;p&gt;I will still try and post my progress on whatever it is I&amp;rsquo;ve been working on every week, though. (And patrons&amp;ndash;you&amp;rsquo;ll
still get the inside scoop a week early.)&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m going to try to get myself into a more game-jam-like state of mind with these new projects, because I find that
little bit of time pressure really keeps me from overengineering things in the name of perfection.&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; I&amp;rsquo;m going to take
things about one month at a time; if a project isn&amp;rsquo;t really going anywhere after a month, I&amp;rsquo;m dropping it, cleaning up the
tools I made while working on it, and moving on to another one.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Not to be kitschy, but I&amp;rsquo;d also like to take a moment to thank all of you. Everyone I&amp;rsquo;ve revealed this decision to ahead
of time has been nothing but supportive. I guess I have some anxiety about the existence of some evil group of fans who
see me as nothing but a content generation machine &amp;hellip; while they&amp;rsquo;re probably out there somewhere, one or two of them,
I&amp;rsquo;m lucky to have not encountered them.&lt;/p&gt;
&lt;p&gt;So. Here&amp;rsquo;s to some smaller projects, some better games, and uhh rule of threes.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;For example, there&amp;rsquo;s a whole registry system in Foxfire a la Minecraft for registering sprites, items, senses and
their carrier radiation, &amp;hellip; etc.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
    </item>
    
    <item>
      <title>Foxfire Fridays #6: Resource Management Management</title>
      <link>/blog/2022-08-05_fff6/</link>
      <pubDate>Fri, 05 Aug 2022 10:57:29 -0500</pubDate>
      
      <guid>/blog/2022-08-05_fff6/</guid>
      <description>One thing I realize about Foxfire is that not everybody sitting down to play a roguelike wants to be bait-and-switched into playing Factorio.
But, I do really think there&amp;rsquo;s space for resource management somewhere between Qud&amp;rsquo;s weight and water management, and building whole factories to mass produce things. So this blog post will be my musings about micro-scale and macro-scale resource management, and how I intend to steer the player towards having fun with those two things in mind.</description>
      <content>&lt;p&gt;One thing I realize about Foxfire is that not everybody sitting down to play a roguelike wants to be bait-and-switched into
playing Factorio.&lt;/p&gt;
&lt;p&gt;But, I do really think there&amp;rsquo;s space for resource management somewhere between Qud&amp;rsquo;s weight and water management,
and building whole factories to mass produce things. So this blog post will be my musings about micro-scale and macro-scale
resource management, and how I intend to steer the player towards having fun with those two things in mind.&lt;/p&gt;
&lt;p&gt;The gist is, I want to reward both styles of play and let players choose whether to focus on micro or macro resource management,
while still requiring a little of both in any playthrough.&lt;/p&gt;
&lt;h2 id=&#34;the-progression-of-the-game&#34;&gt;The Progression of the Game&lt;/h2&gt;
&lt;p&gt;The goal of Foxfire is to restore the superstructure Foxfire to working order, and the plan is to do that through a list of quests.&lt;/p&gt;
&lt;p&gt;I haven&amp;rsquo;t decided on the exact numbers, but let&amp;rsquo;s say there&amp;rsquo;s 50 quests total, and you have to do 40 of them to win. A few of the quests
will be tutorial-y quests to teach new players the ropes and to help experienced players feel like they&amp;rsquo;re doing something worthwhile
while gearing up a little bit. The remainder, I aim to split roughly 50/50 between dungeon delving and resource production.&lt;/p&gt;
&lt;p&gt;Dungeon delving quests are for players who like micro-level resource management. They&amp;rsquo;ll be things like &amp;ldquo;This part, which we can&amp;rsquo;t easily
manufacture anymore, was stolen by these people who now worship it. Go get it back from the bottom of their lair.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Resource production quests are for players who like macro-level resource management. They&amp;rsquo;ll be things like &amp;ldquo;Get me 20,000kg of steel.&amp;rdquo;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;And I&amp;rsquo;m planning to have a few story-driven quests here and there, too, helping the player get to know the world they&amp;rsquo;ve found themself in.&lt;/p&gt;
&lt;p&gt;A cool thing about this framework is that I can have quests that are both micro level and macro level, and are different difficulties in each.
Imagine a quest to fetch Foxfire some kind of Nanoquantum Widget. Now, the player has a choice to go through the 8-stage processing chain to produce
a nanoquantum widget themself, or they can go fight their way down a dungeon to find one that already exists.&lt;/p&gt;
&lt;p&gt;And, I can have quests that are different difficulties if you&amp;rsquo;re focusing on micro or macro. One thing I want in this game is a section of the map that&amp;rsquo;s
just ocean, which of course is deadly to SP-1R17. If you&amp;rsquo;re specing into micro-level resource management, it&amp;rsquo;ll be a real challenge to make sure you
ration your electricity as you sail to an island, do some task there, and sail back. But if you&amp;rsquo;re specing into macro, it&amp;rsquo;ll be pretty easy to just bring
tanks of gasoline with you, or whatever.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Aside: I ADORE Ursula K. Le Guin&amp;rsquo;s descriptions of bleak wilderness. My favorite part of &lt;strong&gt;Earthsea&lt;/strong&gt; is when Ged is sailing across the oceans, and my
favorite part of &lt;strong&gt;The Left Hand of Darkness&lt;/strong&gt; is when Genly and Estraven are trekking across the blasted wintry plain. She makes you remember that Nature
is not designed for anyone or anything, and in fact is not even capable of caring for us. If I can, I want to evoke that feeling in the player, holding
their meager resources tight to themself as they walk or sail across dead, dead earth.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;the-micro&#34;&gt;The Micro&lt;/h2&gt;
&lt;p&gt;Roguelikes have a long tradition of having micro-level resource management. By this I mean any resource that you have the ability
to replenish or re-spec about every ten minutes to hour of play.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Caves of Qud has you manage your water.&lt;/li&gt;
&lt;li&gt;Nethack has you manage food and carrying capacity.&lt;/li&gt;
&lt;li&gt;Noita has you manage health. (I&amp;rsquo;m not counting health in the other roguelikes because you can reasonably regenerate health in those
by just resting after a fight with an enemy. In Noita the only really reliable source of healing is the holy mountains between zones.)&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;d like to say something about Spelunky here but to be honest I&amp;rsquo;m so bad at it I&amp;rsquo;m not really sure what you&amp;rsquo;re supposed to manage.
Probably bombs or something. (Health isn&amp;rsquo;t a micro resource in Spelunky for the opposite reason; you get more hearts very rarely.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And I&amp;rsquo;m sure you can think of analogues in your favorite roguelike.&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;I see the point of these systems as a sort of soft timer on the player. How long can you go without finding more water, or making hard
decisions about what to drop, or quitting exploring the level and going to the next safe zone?
The depletion of micro-level resources are that timer, and the better you are at managing them, the longer that timer runs.&lt;/p&gt;
&lt;p&gt;One thing I find disappointing in roguelikes is when these resources get too easy over time. For example, Caves of Qud lauds its water/fluid
dynamics system, but I don&amp;rsquo;t think I&amp;rsquo;ve ever &lt;em&gt;once&lt;/em&gt; thought &amp;ldquo;oh, I&amp;rsquo;m running low on water, better get out of here quick.&amp;rdquo;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Aside: I wish Qud didn&amp;rsquo;t have recoilers. It kills the feeling of there being a giant world to explore all too quickly, and makes resource
management too easy. I would be OK with a gradual opening-up of the world, but it really seems like it just flips to &amp;ldquo;too easy&amp;rdquo; the moment
you can identify and afford a Joppa recoiler.&lt;/p&gt;
&lt;p&gt;I would make them have a limited number of uses, or cut them entirely in favor of an item that teleports you to the
surface of whatever zone you&amp;rsquo;re in&amp;hellip;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That&amp;rsquo;s one thing I really like about Noita; even though you get more health over time, the &amp;ldquo;obvious&amp;rdquo; path deeper into the earth requires
you to keep vigilant about your HP, and any &amp;ldquo;shortcuts&amp;rdquo; or alternate progression just make it even harder.&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;In Foxfire, this will be developing your chassis with better mechanisms, software, etc. You&amp;rsquo;ll be managing mostly your electricity, and although
you might have some ability to create it yourself on the go in the mid-late game, your timer will be on how long you can spend away from Foxfire
or other safe zones where you can recharge.&lt;/p&gt;
&lt;h2 id=&#34;the-macro&#34;&gt;The Macro&lt;/h2&gt;
&lt;p&gt;By macro-level, I mean anything you have to think long-term about the consequences of.&lt;/p&gt;
&lt;p&gt;Macro-level resource management isn&amp;rsquo;t as much a focus of most roguelikes, except during character creation. I find this peculiar, really; your decisions
are split between immediate-term and game-spanning ones, without much middle ground. But I digress.&lt;/p&gt;
&lt;p&gt;A genre of game that is all &lt;em&gt;about&lt;/em&gt; macro-level resource management is the factory builder. I really love the feeling of starting from scraps
and developing a factory that processes millions of items per minute all around me.&lt;/p&gt;
&lt;p&gt;I suppose I don&amp;rsquo;t have as much to talk about on this front as I did with micro-level resource management because this is not really
something I&amp;rsquo;ve seen in a roguelike before. I want it to be &lt;em&gt;expensive&lt;/em&gt; to have a powerful build and expensive to repair Foxfire, with a volume of resources
that isn&amp;rsquo;t really feasible in other roguelikes.&lt;/p&gt;
&lt;p&gt;One thing I &lt;em&gt;haven&amp;rsquo;t&lt;/em&gt; figured out is how the player&amp;rsquo;s going to &lt;em&gt;get&lt;/em&gt; the resources places. I don&amp;rsquo;t think I have the wherewithall to code up a whole
logistics system like Factorio or Satisfactory &amp;hellip; I might take some notes from modded Minecraft here, where they just give you a bunch of pipes and machines
and tell you to figure it out yourself. That, or magic production of raw materials &amp;hellip; or take a page out of Kim Stanley Robinson&amp;rsquo;s &lt;strong&gt;Red Mars&lt;/strong&gt;,
and have the raw resources be commonplace, in the air and soil, and just require lots and lots of processing.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Aside: On the topic of books about space, I also really love &lt;strong&gt;The Martian&lt;/strong&gt;, by Andy Weir. Specifically, I love the concept of living with and
harnessing technology you can&amp;rsquo;t make more of, like the oxygen reprocessor and the hab. I want the early game of Foxfire to feel like that, clinging
to artifice you will never be able to recreate in a thousand thousand years, praying it doesn&amp;rsquo;t die on you.&lt;/p&gt;
&lt;p&gt;Hell, maybe even a better example of this is &lt;strong&gt;Lost in Space&lt;/strong&gt; (the Netflix reboot), my favorite TV show. Season 1 and 3 do the best job of capturing
that feeling for me, of being surrounded by a universe that &lt;em&gt;really&lt;/em&gt; wants you dead in a little tiny echelon of safety you can&amp;rsquo;t ever make more of.
And there&amp;rsquo;s cool robots!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Aside: There&amp;rsquo;s a lot of asides in this article.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;And, I think that the micro-level play and macro-level play can wind together really well. Imagine synthesizing high explosives, crafting them
into rockets, and absolutely destroying a dangerous area with atomic fire. Or, pulling off a tricky stint of dungeoneering and rescuing a chemical reactor
capable of crafting faster than you&amp;rsquo;ll be able to for hours of playtime.&lt;/p&gt;
&lt;p&gt;I guess I&amp;rsquo;m out of things to say for this blog post, then. It was ramblier than I&amp;rsquo;d like, but I do have to write two this week&amp;hellip;&lt;/p&gt;
&lt;p&gt;So, I&amp;rsquo;ll report back with whatever I&amp;rsquo;ve coded up in the interim next week.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Does anyone reading this blog know of Agrarian Skies? It was one of the first good Minecraft hardcore questing packs. The lategame quests were all
in that vein, producing a quarter million burgers and a million wheat and stuff like that. Modern pack devs are cowards for making you craft a bunch of things
into one item and turn that in. Make me pipe a million redstone into a block, dammit.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;I should play more roguelikes.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;Hmmm, today I will go get the orb on the other side of the volcano (clueless)&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
    </item>
    
    <item>
      <title>Foxfire Fridays #5: A Problem of Scale</title>
      <link>/blog/2022-07-29_fff5/</link>
      <pubDate>Wed, 27 Jul 2022 20:03:55 -0500</pubDate>
      
      <guid>/blog/2022-07-29_fff5/</guid>
      <description>First, a bit of bookkeeping stuff; I&amp;rsquo;ve decided that as another Patreon reward, you can get next week&amp;rsquo;s FFF, this week! FFF #5 (this one) will be released on 29 July 2022; patrons will be able to read FFF #6 on the 29th too. Non-patrons will get access to FFF #6 on August the 5th, when patrons will be reading FFF #7.
TL;DR this week I&amp;rsquo;m writing two FFF&amp;rsquo;s to kick off the week advance, as opposed to not having an FFF for non-patrons this week.</description>
      <content>&lt;p&gt;First, a bit of bookkeeping stuff; I&amp;rsquo;ve decided that as another Patreon reward, you can get next week&amp;rsquo;s FFF, this week!
FFF #5 (this one) will be released on 29 July 2022; patrons will be able to read FFF #6 on the 29th too. Non-patrons
will get access to FFF #6 on August the 5th, when patrons will be reading FFF #7.&lt;/p&gt;
&lt;p&gt;TL;DR this week I&amp;rsquo;m writing two FFF&amp;rsquo;s to kick off the week advance, as opposed to not having an FFF for non-patrons
this week.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Anyways! This week&amp;rsquo;s post is about a problem I&amp;rsquo;ve had a &lt;em&gt;lot&lt;/em&gt; during development; What do I do with the layout of the grid?
It&amp;rsquo;s a question in two parts: how large do I make each tile in pixels, and how many tiles large do I make the screen.&lt;/p&gt;
&lt;p&gt;The two limiting factors for tile size are pixel density and text size. Having the textures too large means you can&amp;rsquo;t actually
see the pixel art, and makes it impractical to draw any amount of text without it becoming too big. But having the textures
too small makes it hard to visually distinguish things at a glance.&lt;/p&gt;
&lt;p&gt;Window size has a similar problem. I&amp;rsquo;d love to cram as many tiles as I can onto the screen to get really nice big zones, but
that makes the displayed visual size of each tile smaller.&lt;/p&gt;
&lt;h2 id=&#34;16x24&#34;&gt;16x24&lt;/h2&gt;
&lt;p&gt;Caves of Qud, my fallback for when I don&amp;rsquo;t have any idea how to do something, uses 16x24 textures and has a zone size of
80x25 tiles.&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

  &lt;figure class=&#34;left&#34; &gt;
    &lt;a href=&#34;/img/2022-07-29_fff5/1.png &#34;&gt;
      &lt;img src=&#34;/img/2022-07-29_fff5/1.png&#34;  alt=&#34;A screenshot of Caves of Qud, with the player standing in the starting village of Joppa. There are ramshackle buildings, some farmers, 
and a small copse of plants growing in salty water.&#34;   /&gt;
    &lt;/a&gt;
    
      &lt;figcaption class=&#34;left&#34; &gt;Always pat Ctesiphus before you leave Joppa.&lt;/figcaption&gt;
    
  &lt;/figure&gt;


&lt;p&gt;The earlier screenshots of Foxfire I&amp;rsquo;ve been posting here were in that vein; 16x24 tiles, and 8x8 text. But, there&amp;rsquo;s a few problems with that.
The problem is I want Foxfire to actually be playable in a real terminal, and that means the tiles and characters have to be the same size
(cause the tiles &lt;em&gt;are&lt;/em&gt; going to be characters.)&lt;/p&gt;
&lt;p&gt;Caves of Qud does have a text mode, but it cheats with the game log and renders it smaller than it really should be able to if it was in a real terminal.&lt;/p&gt;

  &lt;figure class=&#34;left&#34; &gt;
    &lt;a href=&#34;/img/2022-07-29_fff5/2.png &#34;&gt;
      &lt;img src=&#34;/img/2022-07-29_fff5/2.png&#34;  alt=&#34;The same scene as last time, but the pixel art tiles have been replaced with characters in a console font.&#34;   /&gt;
    &lt;/a&gt;
    
      &lt;figcaption class=&#34;left&#34; &gt;To be honest, I wish Qud&#39;s font was 16x24 instead of the smooth curves.&lt;/figcaption&gt;
    
  &lt;/figure&gt;


&lt;p&gt;Imagine how little you could see if the log&amp;rsquo;s characters were as big as the characters making up the game world!&lt;/p&gt;
&lt;h2 id=&#34;16x16&#34;&gt;16x16&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s a little test scene in Foxfire with 16x16 tiles and an 80x50 zone:&lt;/p&gt;

  &lt;figure class=&#34;left&#34; &gt;
    &lt;a href=&#34;/img/2022-07-29_fff5/3.png &#34;&gt;
      &lt;img src=&#34;/img/2022-07-29_fff5/3.png&#34;  alt=&#34;SP-1R17 standing outside a rectangular building. The game log on the side is comically large and many of the words spill off the screen.&#34;   /&gt;
    &lt;/a&gt;
    
      &lt;figcaption class=&#34;left&#34; &gt;The font is 16x16, but it&#39;s just an 8x8 font I&#39;ve scaled 200%. I couldn&#39;t find a good DOS 16x16 font that wasn&#39;t serifed.&lt;/figcaption&gt;
    
  &lt;/figure&gt;


&lt;p&gt;The problem here is that the log is really REALLY big. Making it wide enough to actually print a line of any length would make it cover
a ton of the screen at all times&amp;hellip; and we don&amp;rsquo;t have the advantage of Caves of Qud where they can draw it semi-transparent, either.&lt;/p&gt;
&lt;h2 id=&#34;8x8&#34;&gt;8x8&lt;/h2&gt;
&lt;p&gt;And here&amp;rsquo;s the same scene with 8x8 tiles, and a 120x72 zone.&lt;/p&gt;

  &lt;figure class=&#34;left&#34; &gt;
    &lt;a href=&#34;/img/2022-07-29_fff5/4.png &#34;&gt;
      &lt;img src=&#34;/img/2022-07-29_fff5/4.png&#34;  alt=&#34;The same scene but with 8x8 tiles. The game log is less comically big.&#34;   /&gt;
    &lt;/a&gt;
    
      &lt;figcaption class=&#34;left&#34; &gt;I couldn&#39;t figure out how to fit SP-1R17&#39;s head &lt;i&gt;and&lt;/i&gt; body in 8x8 pixels, so it&#39;s just a head.&lt;/figcaption&gt;
    
  &lt;/figure&gt;


&lt;p&gt;And this looks &amp;hellip; alright, I guess. But given the line-of-sight calculations, there&amp;rsquo;s gonna be a whole lot of empty space on the screen.
Plus, the log still covers a lot.&lt;/p&gt;
&lt;h2 id=&#34;what-am-i-going-to-pick&#34;&gt;What am I Going To Pick&lt;/h2&gt;
&lt;p&gt;Rorax pointed me towards this game called &lt;a href=&#34;https://www.gridsagegames.com/cogmind/index.html&#34;&gt;Cogmind&lt;/a&gt;, which kinda seems like Foxfire but better.&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

  &lt;figure class=&#34;left&#34; &gt;
    &lt;a href=&#34;https://i.imgur.com/6x3TMuq.gif &#34;&gt;
      &lt;img src=&#34;https://i.imgur.com/6x3TMuq.gif&#34;  alt=&#34;Scenes of a tank moving and shooting around a really beautifully rendered world.&#34;   /&gt;
    &lt;/a&gt;
    
      &lt;figcaption class=&#34;left&#34; &gt;Maybe this whole &#34;16 color palette&#34; thing isn&#39;t actually a very good idea, cause hot DAMN does Cogmind look pretty.&lt;/figcaption&gt;
    
  &lt;/figure&gt;


&lt;p&gt;I haven&amp;rsquo;t bought it, but looking at screenshots of it I notice two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The zones are really large, but you only see so much of it at any given time because the camera follows the player.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;There&amp;rsquo;s no game log&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That second one was something I had never thought of before, to be honest. A roguelike without a gamelog? Absurd.&lt;/p&gt;
&lt;p&gt;Joking aside, I do want a game log in Foxfire, because I&amp;rsquo;m a much better writer than pixel artist and really love Nethack&amp;rsquo;s snarky little
quips and Qud&amp;rsquo;s unapologetic purple prose. So I think I&amp;rsquo;ll take a hybrid approach:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;8x8 tiles&lt;/li&gt;
&lt;li&gt;Have a smaller game window on the left, maybe 96x72 tiles&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;li&gt;Have zones be MUCH larger, 8x8 screens or more.&lt;/li&gt;
&lt;li&gt;Have a static game log on the right that never covers anything.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I might also take a page out of Nethack&amp;rsquo;s book. Nethack replaces the normal UI at the bottom of the screen with your HP and XP and all with a log
line when it&amp;rsquo;s added to the log, and then keeps displaying the UI once you press a key. And then there&amp;rsquo;s a button to bring up the whole scrollback
of the log.&lt;/p&gt;
&lt;p&gt;I found that system kind of annoying because I would always accidentally keymash through it, so I might constantly display the last 2 or 3 lines of the
log at the bottom of the screen and have the quick HUD above it. I do want &lt;em&gt;some&lt;/em&gt; form of HUD, though, because HUDs feel very robot-y to me. A HUD might
&lt;em&gt;increase&lt;/em&gt; the verisimilitude of playing as a robot, really, if I play my cards right.&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m also really inspired by Cogmind&amp;rsquo;s particle effects! So I think I might extend the colors in Foxfire to a larger palette.
&lt;a href=&#34;https://www.gridsagegames.com/blog/2014/04/accommodating-colorblindness/&#34;&gt;Here&amp;rsquo;s a post by the creator of Cogmind with a bit about how the palette in that game works&lt;/a&gt;;
the TL;DR is that he defines a set of 21 base hues, and the game produces 10 colors for each based on different brightnesses at runtime.&lt;/p&gt;
&lt;p&gt;But of course that all takes time to implement&amp;hellip; so I&amp;rsquo;ll see you all next week with progress on that. Or, if you&amp;rsquo;re a patron, you can read next week&amp;rsquo;s post today!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;The window is taller than just the zone, but the area outside of the main game display isn&amp;rsquo;t pixelated, so I&amp;rsquo;m not counting it.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;And also, yknow, actually out.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;I&amp;rsquo;m not sure I&amp;rsquo;m actually old enough to have nostalgia for 4x3 displays, and yet I do anyways. Hm.&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;I looked for that Questionable Content comic episode where Faye and Bubbles are talking about robot senses for a while and then kinda gave up looking.
If anyone has a link to it I would very much appreciate it!!&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
    </item>
    
    <item>
      <title>Foxfire Fridays #4: Now Featuring A Real Blog</title>
      <link>/blog/2022-07-22_fff4/</link>
      <pubDate>Fri, 22 Jul 2022 11:09:30 -0500</pubDate>
      
      <guid>/blog/2022-07-22_fff4/</guid>
      <description>Wow, it is very nice to have an actual text document that doesn&amp;rsquo;t artificially cap you at 240 characters to write an FFF in. Anyways, for this week the topic is &amp;hellip; more backend changes!
I know, exciting.
I&amp;rsquo;ve been moving the Foxfire engine from running on Specs ECS to a custom ECS-like crate named palkia.1 Like I mentioned in the previous FFF, this is less of an entity-component-system architecture and more of an entity-component-message architecture.</description>
      <content>&lt;p&gt;Wow, it is very nice to have an actual text document that doesn&amp;rsquo;t artificially cap you at 240 characters to write
an FFF in. Anyways, for this week the topic is &amp;hellip; more backend changes!&lt;/p&gt;
&lt;p&gt;I know, exciting.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been moving the Foxfire engine from running on Specs ECS to a custom ECS-like crate named &lt;code&gt;palkia&lt;/code&gt;.&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;
Like I mentioned in the previous FFF, this is less of an entity-component-system architecture and more of an
entity-component-&lt;em&gt;message&lt;/em&gt; architecture.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Update: I&amp;rsquo;ve now open-sourced Palkia, along with all the other helper crates in Foxfire! &lt;a href=&#34;https://crates.io/crates/palkia&#34;&gt;Get it here.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Why this change? Brian Bucklew goes over a lot of the advantages of this event/message based architecture
in his presentation about Caves of Qud and Sproggiwood (you can find the link in &lt;a href=&#34;../2022-07-21_4_fff3&#34;&gt;the previous FFF&lt;/a&gt;).
But here&amp;rsquo;s my takes on it.&lt;/p&gt;
&lt;h2 id=&#34;systems-get-really-complicated&#34;&gt;Systems get Really Complicated&lt;/h2&gt;
&lt;p&gt;ECM makes it easier to have tons and tons of components that &lt;em&gt;interact&lt;/em&gt; with each other. ECS was designed to solve
monolithic approaches like object-orientation, but the systems in it are still pretty top-down.&lt;/p&gt;
&lt;p&gt;As an example, say we want to have enemies that can attack each other. Alright then, let&amp;rsquo;s make up an &lt;code&gt;Attacker&lt;/code&gt;
component and a &lt;code&gt;HasHP&lt;/code&gt; component:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;N.B. I did not actually test any of this code so it&amp;rsquo;s possible it doesn&amp;rsquo;t compile.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#[derive(Component)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Attacker&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;/// Stores targets of the attack and the damage we wish to do to them.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;///
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;/// Presumably this is cleared and then filled every frame by some kind of `SysAI`.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&lt;/span&gt;    targets: Vec&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;(Entity, DamageInstance)&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;,    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DamageInstance&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    amount: &lt;span style=&#34;color:#66d9ef&#34;&gt;u32&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    kind: &lt;span style=&#34;color:#a6e22e&#34;&gt;DamageKind&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#[derive(Component)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;HasHP&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;u32&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Great, now let&amp;rsquo;s write the &lt;code&gt;SysDealDamage&lt;/code&gt; system:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SysDealDamage&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;impl&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; System&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; SysDealDamage {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SystemData&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ReadStorage&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;, Attacker&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        WriteStorage&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;, HasHP&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;run&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;mut&lt;/span&gt; self, (attacker, &lt;span style=&#34;color:#66d9ef&#34;&gt;mut&lt;/span&gt; has_hp): &lt;span style=&#34;color:#a6e22e&#34;&gt;Self&lt;/span&gt;::SystemData) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (attacker,) &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; (attacker,).join() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (target, dmg) &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;attacker.targets {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; Some(target_hp) &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; has_hp.get_mut(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;target) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    target_hp.&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; target_hp.&lt;span style=&#34;color:#ae81ff&#34;&gt;0.&lt;/span&gt;saturating_sub(dmg.amount);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;OK, great.&lt;/p&gt;
&lt;p&gt;But now, I want to add a potion of invincibility. Alright, let&amp;rsquo;s add a component for that&amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#[derive(Component)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IsInvincible&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;impl&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; System&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; SysDealDamage {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SystemData&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ReadStorage&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;, Attacker&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        WriteStorage&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;, HasHP&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ReadStorage&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;, IsInvincible&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;run&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;mut&lt;/span&gt; self, (attacker, &lt;span style=&#34;color:#66d9ef&#34;&gt;mut&lt;/span&gt; has_hp, invincible): &lt;span style=&#34;color:#a6e22e&#34;&gt;Self&lt;/span&gt;::SystemData) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (attacker,) &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; (attacker,).join() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (target, dmg) &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;attacker.targets {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; Some(target_hp) &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; has_hp.get_mut(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;target) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; invincible.get(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;target).is_none() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        target_hp.&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; target_hp.&lt;span style=&#34;color:#ae81ff&#34;&gt;0.&lt;/span&gt;saturating_sub(dmg.amount);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Great. There&amp;rsquo;s a lot of rightward drift, but we could factor that out into a helper function&amp;hellip;&lt;/p&gt;
&lt;p&gt;But now say I want to add resistances to certain types of damage. Maybe I want a gelatinous cube
that&amp;rsquo;s only hurt by slashing and magic weapons, for example.&lt;/p&gt;
&lt;p&gt;Alright, let&amp;rsquo;s add another few levels of indentation &amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#[derive(Component)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ResistsDamage&lt;/span&gt;(HashMap&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;DamageKind, &lt;span style=&#34;color:#66d9ef&#34;&gt;u32&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;impl&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; System&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; SysDealDamage {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SystemData&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ReadStorage&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;, Attacker&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        WriteStorage&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;, HasHP&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ReadStorage&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;, IsInvincible&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ReadStorage&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;, ResistsDamage&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;run&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;mut&lt;/span&gt; self, (attacker, &lt;span style=&#34;color:#66d9ef&#34;&gt;mut&lt;/span&gt; has_hp, invincible, resists): &lt;span style=&#34;color:#a6e22e&#34;&gt;Self&lt;/span&gt;::SystemData) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (attacker,) &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; (attacker,).join() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (target, dmg) &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;attacker.targets {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; Some(target_hp) &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; has_hp.get_mut(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;target) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; invincible.get(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;target).is_none() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;mut&lt;/span&gt; amount &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; dmg.amount;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; Some(resists) &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; resists.get(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;target) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; Some(resist_amt) &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; resists.&lt;span style=&#34;color:#ae81ff&#34;&gt;0.&lt;/span&gt;get(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;dmg.kind) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                amount &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; amount.saturating_sub(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;resist_amt);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        target_hp.&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; target_hp.&lt;span style=&#34;color:#ae81ff&#34;&gt;0.&lt;/span&gt;saturating_sub(amount);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And now what if I want to add an iron golem that&amp;rsquo;s &lt;em&gt;healed&lt;/em&gt; by fire damage? What if I want slimes to split
in two when damaged?&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t mean to claim that entity-component-message is the be-all-end-all successor to ECS&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;. But, for roguelikes,
where it&amp;rsquo;s really fun to have everything be able to influence everything else in the world, all of your systems
are just going to become horrid tangled knots.&lt;/p&gt;
&lt;p&gt;For example, here&amp;rsquo;s the (old) code in Foxfire that makes mechanisms apply their effects to the entities they&amp;rsquo;re on.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SysApplyMechanismEffects&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;impl&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; System&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; SysApplyMechanismEffects {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SystemData&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Entities&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ReadStorage&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;, HasMechanisms&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ReadStorage&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;, Activatable&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ReadStorage&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;, ProvidesSenses&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        WriteStorage&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;, HasSenses&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ReadStorage&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;, ProvidesRadiation&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        WriteStorage&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&amp;#39;a&lt;/span&gt;, Radiator&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;run&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;mut&lt;/span&gt; self,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            entities,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            mechanisms,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            active,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            provides_senses,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;mut&lt;/span&gt; senses,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            provides_radiation,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;mut&lt;/span&gt; radiator,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ): &lt;span style=&#34;color:#a6e22e&#34;&gt;Self&lt;/span&gt;::SystemData,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (owner, mechanisms) &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;entities, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;mechanisms).join() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; Some(senses) &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; senses.get_mut(owner) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                senses.senses_mut().clear();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; Some(radiation) &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; radiator.get_mut(owner) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                radiation.radiations.clear();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// Without this helper function I get up to 10 levels of indentation!
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// I&amp;#39;ve elided it for brevity but it&amp;#39;s quite long.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;mech &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; mechanisms.contained.iter() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                SysApplyMechanismEffects::run_inner(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    owner,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    mech,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;active,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;provides_senses,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;mut&lt;/span&gt; senses,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;provides_radiation,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;mut&lt;/span&gt; radiator,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ECS promises that it won&amp;rsquo;t get harder and harder to add new components the more components you add.
Which is true! But, the systems &lt;em&gt;do&lt;/em&gt; get harder and more complicated. Every time I want to have a mechanism
able to do something else, I&amp;rsquo;ll need to update that gigantic function.&lt;/p&gt;
&lt;p&gt;And it makes sense organizationally to have the components and their behavior near each other.
In the damage example above, wouldn&amp;rsquo;t it be nice if the code for the &lt;code&gt;IsInvincible&lt;/code&gt; component removing
all the damage was right there next to the component declaration, instead of off somewhere
in the middle of the &lt;code&gt;SysDealDamage&lt;/code&gt; function?&lt;/p&gt;
&lt;p&gt;So, the solution Brian Bucklew hit upon, which I am shamelessly stealing, is&lt;/p&gt;
&lt;h2 id=&#34;message-passing&#34;&gt;Message Passing&lt;/h2&gt;
&lt;p&gt;Like in ECS, under ECM you have entities, which are lists of components. But, instead of linking behavior
of different components with systems, you do it by passing messages.&lt;/p&gt;
&lt;p&gt;When you implement &lt;code&gt;Component&lt;/code&gt; for a struct, you implement a method that registers that struct with different
message types. Then, from a message handler, you can fire messages to other entities.&lt;/p&gt;
&lt;p&gt;When an entity gets a message, it runs through its components in order, and if that component type registers a handler
for that message type, it runs the handler and passes the updated value to the next component, and so on
&amp;hellip; and then finally returns the modified message to the caller.&lt;/p&gt;
&lt;p&gt;And there&amp;rsquo;s a method on &lt;code&gt;World&lt;/code&gt; to pass a message to all entities, as your entrypoint.&lt;/p&gt;
&lt;p&gt;How does this all work in practice? Here&amp;rsquo;s the damage example from above written with Palkia.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;N.B. palkia currently calls the messages &amp;ldquo;events,&amp;rdquo; so I suppose it&amp;rsquo;s an ECE architecture.
But it doesn&amp;rsquo;t really matter what you call it.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;EvDealDamage&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    amount: &lt;span style=&#34;color:#66d9ef&#34;&gt;u32&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    kind: &lt;span style=&#34;color:#a6e22e&#34;&gt;DamageKind&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;impl&lt;/span&gt; Event &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; EvDealDamage {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;HasHP&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;u32&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IsInvincible&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ResistsDamage&lt;/span&gt;(HashMap&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;DamageKind, &lt;span style=&#34;color:#66d9ef&#34;&gt;u32&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;impl&lt;/span&gt; HasHP {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Here&amp;#39;s the signature for an event listener: the component (&amp;amp; or &amp;amp;mut), the event,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// the entity the component is on, and a restricted accessor to the world for doing lazy
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// updates, returning the event.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;on_deal_damage&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;mut&lt;/span&gt; self, ev: &lt;span style=&#34;color:#a6e22e&#34;&gt;EvDealDamage&lt;/span&gt;, e: &lt;span style=&#34;color:#a6e22e&#34;&gt;Entity&lt;/span&gt;, world: &lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;WorldAccess&lt;/span&gt;) -&amp;gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;EvDealDamage&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; self.&lt;span style=&#34;color:#ae81ff&#34;&gt;0.&lt;/span&gt;checked_sub(ev.amount) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Some(it) &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; self.&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; it,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            None &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;// Set this entity to be despawned when `world.maintain` is called.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;                world.lazy_despawn(e);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;impl&lt;/span&gt; Component &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; HasHP {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;register_listeners&lt;/span&gt;(builder: &lt;span style=&#34;color:#a6e22e&#34;&gt;ListenerBuilder&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Self&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;) -&amp;gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ListenerBuilder&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Self&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;where&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Self: Sized,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// Register the listeners here.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        builder
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .listen_write(Self::on_deal_damage)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;impl&lt;/span&gt; Component &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; IsInvincible {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;register_listeners&lt;/span&gt;(builder: &lt;span style=&#34;color:#a6e22e&#34;&gt;ListenerBuilder&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Self&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;) -&amp;gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ListenerBuilder&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Self&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;where&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Self: Sized,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// You can use closures too, as long as they don&amp;#39;t close over anything.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// In the backend, the read and write listeners are treated more or less the same, but
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// there is dynamic borrow checking. So, components can send events to themselves iff it&amp;#39;s
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// immutably borrowed.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        builder
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .listen_read(&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;_: &lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Self&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;mut&lt;/span&gt; ev: &lt;span style=&#34;color:#a6e22e&#34;&gt;EvDealDamage&lt;/span&gt;, _: &lt;span style=&#34;color:#a6e22e&#34;&gt;Entity&lt;/span&gt;, _: &lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;WorldAccess&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;// Reduce the amount of damage to zero, easy as that.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;                ev.amount &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                ev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;impl&lt;/span&gt; Component &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; ResistsDamage {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;register_listeners&lt;/span&gt;(builder: &lt;span style=&#34;color:#a6e22e&#34;&gt;ListenerBuilder&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Self&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;) -&amp;gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ListenerBuilder&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Self&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;where&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Self: Sized,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        builder
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .listen_read(&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;this: &lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Self&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;mut&lt;/span&gt; ev: &lt;span style=&#34;color:#a6e22e&#34;&gt;EvDealDamage&lt;/span&gt;, _: &lt;span style=&#34;color:#a6e22e&#34;&gt;Entity&lt;/span&gt;, _: &lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;WorldAccess&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; Some(reduction) &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; this.&lt;span style=&#34;color:#ae81ff&#34;&gt;0.&lt;/span&gt;get(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;ev.kind) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    ev.amount &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ev.amount.saturating_sub(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;reduction);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                ev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;mut&lt;/span&gt; world &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; World::new();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// You have to register component types before you use them.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// This function calls its `register_listeners` impl.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    world.register::&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;HasHP&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    world.register::&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;IsInvincible&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    world.register::&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;ResistsDamage&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// When you create an entity you should make sure the components are in a sensible order.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// In this case, put the things that modify the event before the thing that uses it ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// I might add some kind of sorting function to the `Component` trait to facilitate this.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Caves of Qud solves this by having things be loaded from blueprint XML files, which are just
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// trusted to have the components be in the right order.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Anyways,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; target1 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; world.spawn().with(HasHP(&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;)).build();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    world.dispatch(EvDealDamage { 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        amount: &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        DamageKind: &lt;span style=&#34;color:#a6e22e&#34;&gt;DamageKind&lt;/span&gt;::Whatever,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }, target1);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Target1 is dead!
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// You have to call this method to finalize lazy updates, like spawning and despawning entities.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    world.finalize();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; target2 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; world.spawn()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(HasHP(&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(IsInvincible)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .build();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    world.dispatch(EvDealDamage { 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        amount: &lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        DamageKind: &lt;span style=&#34;color:#a6e22e&#34;&gt;DamageKind&lt;/span&gt;::Whatever,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }, target2);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// And `target2` has 10 HP still.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// I haven&amp;#39;t added querying methods yet (turns out, you often don&amp;#39;t need them except for debugging!)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// but I pinky-promise
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    world.finalize();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; target3 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; world.spawn()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(HasHP(&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .with(ResistsDamage([(DamageKind::Whatever, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;)].into_iter().collect()))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .build();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    world.dispatch(EvDealDamage { 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        amount: &lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        DamageKind: &lt;span style=&#34;color:#a6e22e&#34;&gt;DamageKind&lt;/span&gt;::Whatever,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }, target3);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// And `target3` will have 10 - (7 - 4) = 7 HP left.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    world.finalize();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 3 entities spawned, 1 killed.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    assert_eq!(world.len(), &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And that&amp;rsquo;s about it!&lt;/p&gt;
&lt;h2 id=&#34;why-messages-for-foxfire&#34;&gt;Why Messages for Foxfire?&lt;/h2&gt;
&lt;p&gt;I want Foxfire to be intricate and linked. I want my players to have interactions with the game that I
never could have dreamed of, but I don&amp;rsquo;t want them to be bugs. And this entity-component-message architecture
is the best way I&amp;rsquo;ve seen of doing that.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m also used to working with events/messages from Minecraft modding. Both Forge and Fabric&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; have event systems
that let you run code when something happens in game, like a tree growing or a mob taking damage, and call your
own code or modify the event itself (or both).&lt;/p&gt;
&lt;p&gt;On that point, messages make the game really moddable and hackable. The eventual-eventual goal is to have
Foxfire be mostly written in a scripting language, probably &lt;a href=&#34;https://rhai.rs&#34;&gt;rhai&lt;/a&gt;, and for there to be official
mod support! I&amp;rsquo;m really inspired by Factorio on this front.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;But that&amp;rsquo;s all very far in the future. For now, I&amp;rsquo;m going to keep porting Foxfire to using Palkia. I&amp;rsquo;ve been running
into the problem of trying to port the whole thing at once, so I think this week I&amp;rsquo;m going to cut a lot of the code,
implement simple things like movement and graphics, and then build back up to where I was with Specs.&lt;/p&gt;
&lt;p&gt;So, check back next week &amp;hellip;&lt;/p&gt;
&lt;h2 id=&#34;ps&#34;&gt;P.S.&lt;/h2&gt;
&lt;p&gt;Message passing is not a new idea. Check out the &lt;a href=&#34;https://codedocs.org/what-is/smalltalk&#34;&gt;Smalltalk language&lt;/a&gt;, which
was released in 1980!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Why &amp;ldquo;Palkia&amp;rdquo;? I&amp;rsquo;ve been naming most of the helper crates in Foxfire after Pokemon, just cause there&amp;rsquo;s a
lot of them and I like the theming. I picked Palkia specifically because Palkia has dominion over space and
&lt;code&gt;palkia&lt;/code&gt; the crate helps me organize things.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;Especially because I haven&amp;rsquo;t even introduced what it is yet&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;The two largest modding toolchains&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
    </item>
    
    <item>
      <title>Foxfire Fridays #3</title>
      <link>/blog/2022-07-21_4_fff3/</link>
      <pubDate>Thu, 21 Jul 2022 23:12:00 -0500</pubDate>
      
      <guid>/blog/2022-07-21_4_fff3/</guid>
      <description>This Foxfire Friday was originally posted on Twitter here.
Hello, there won&amp;rsquo;t be much of a #FoxfireFridays today, for two reasons.
This week, I did mostly back-end changes. I&amp;rsquo;m switching from specs to rolling my own entity-component-message kinda system, like Caves of Qud uses. Here&amp;rsquo;s my reference:
But more importantly, this weekend is the GMTK Game Jam! (Starting in about 3 hours as of this tweet.) So I wanna go work on that.</description>
      <content>&lt;p&gt;&lt;em&gt;This Foxfire Friday was &lt;a href=&#34;https://twitter.com/petrakat/status/1547945800021381123&#34;&gt;originally posted on Twitter here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Hello, there won&amp;rsquo;t be much of a #FoxfireFridays today, for two reasons.&lt;/p&gt;
&lt;p&gt;This week, I did mostly back-end changes. I&amp;rsquo;m switching from specs to rolling my own entity-component-message kinda system, like Caves of Qud uses. Here&amp;rsquo;s my reference:&lt;/p&gt;
&lt;div class=&#34;embed video-player&#34;&gt;
&lt;iframe class=&#34;youtube-player&#34; type=&#34;text/html&#34; width=&#34;640&#34; height=&#34;385&#34; src=&#34;https://www.youtube.com/embed/U03XXzcThGU&#34; allowfullscreen frameborder=&#34;0&#34;&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;But more importantly, this weekend is the GMTK Game Jam! (Starting in about 3 hours as of this tweet.)
So I wanna go work on that. And to anyone else participating, I wish you the best of luck!!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;N.B. You can play my entry, Roll Playing Game, &lt;a href=&#34;https://itch.io/jam/gmtk-jam-2022/rate/1617497&#34;&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Foxfire Fridays #2</title>
      <link>/blog/2022-07-21_3_fff2/</link>
      <pubDate>Thu, 21 Jul 2022 22:49:00 -0500</pubDate>
      
      <guid>/blog/2022-07-21_3_fff2/</guid>
      <description>This Foxfire Friday was originally posted on Twitter here.
Hello everyone, welcome to #FoxfireFridays number 2. By tradition, Foxfire will have you manage light in order to see different places. For debug purposes, instead of completely hiding things you can&amp;rsquo;t see, these screenshots have them darker.
But, Foxfire uses a more sophisticated algorithm than most roguelikes. First, sunlight is added to the map. Then, all the &amp;ldquo;emitters&amp;rdquo; on the map are polled every tick, and rays are cast from them to figure out the intensity at each tile &amp;hellip; and the intensity of each ray is reduced by any &amp;ldquo;occluders&amp;rdquo; they may hit until they reach the edge of the loaded area or have intensity 0.</description>
      <content>&lt;p&gt;&lt;em&gt;This Foxfire Friday was &lt;a href=&#34;https://twitter.com/petrakat/status/1545561236733140994&#34;&gt;originally posted on Twitter here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Hello everyone, welcome to #FoxfireFridays number 2.
By tradition, Foxfire will have you manage light in order to see different places. For debug purposes, instead of completely hiding things you can&amp;rsquo;t see, these screenshots have them darker.&lt;/p&gt;

  &lt;img src=&#34;/img/2022-07-21_3_fff2/1.jfif&#34;  alt=&#34;A top-down view of SP-1R17 standing outside of a building. It can&amp;#39;t see inside or too far to the sides of the building because the walls are in the way.&#34;  class=&#34;left&#34;  /&gt;


&lt;p&gt;But, Foxfire uses a more sophisticated algorithm than most roguelikes. First, sunlight is added to the map.
Then, all the &amp;ldquo;emitters&amp;rdquo; on the map are polled every tick, and rays are cast from them to figure out the intensity at each tile &amp;hellip;
and the intensity of each ray is reduced by any &amp;ldquo;occluders&amp;rdquo; they may hit until they reach the edge of the loaded area or have intensity 0.&lt;/p&gt;
&lt;p&gt;Because there&amp;rsquo;s inv-square falloff, pools of light merge, like metaballs.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;There is supposed to be a video of two pools of light merging here, but I can&amp;rsquo;t manage to get it as a gif. Check the twitter thread if you want to see it.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The player&amp;rsquo;s viewshed is calculated similarly; rays are cast to each tile in the current zone, occlusion is summed along that ray, and the intensity against that tile is compared against any sense-providing mechanisms the player has.&lt;/p&gt;
&lt;p&gt;Speaking of mechanisms, the player (and all robots in the game, eventually) have onboard, customizable logistic networks. Here&amp;rsquo;s an example one.&lt;/p&gt;

  &lt;figure class=&#34;left&#34; &gt;
    &lt;a href=&#34;/img/2022-07-21_3_fff2/2.jfif &#34;&gt;
      &lt;img src=&#34;/img/2022-07-21_3_fff2/2.jfif&#34;  alt=&#34;A UI showing a list of components, what they produce and consume, and their statuses. A fusion reactor producing 1kJ is highlighted.&#34;   /&gt;
    &lt;/a&gt;
    
      &lt;figcaption class=&#34;left&#34; &gt;Although the connections aren&#39;t shown (yet), there&#39;s a graph backing this, with mechanisms pulling items from other mechanisms.&lt;/figcaption&gt;
    
  &lt;/figure&gt;


&lt;p&gt;So, electricity flows from the fusion reactor to the battery, and then to the camera, the lamp, the Hall Effect sensor, and the &amp;ldquo;waste money&amp;rdquo;
(which doesn&amp;rsquo;t do anything and just consumes electricity for test purposes.) And you can en/disable mechanisms too!&lt;/p&gt;
&lt;p&gt;Speaking of, what happens if we turn on the Hall Effect sensor &amp;hellip;&lt;/p&gt;

  &lt;img src=&#34;/img/2022-07-21_3_fff2/3.jfif&#34;  alt=&#34;SP-1R17 standing outside a building. Everything is white and washed out.&#34;  class=&#34;left&#34;  /&gt;


&lt;p&gt;&amp;hellip; wait, why is everything washed out? Take a look at the status bar; we&amp;rsquo;re in a very powerful magnetic field of over 1 Tesla. The hall effect sensor is washed out!&lt;/p&gt;
&lt;p&gt;Normally this would white-out the screen and obscure things like being in total darkness would, but again I&amp;rsquo;ve kept things rendering for display purposes.&lt;/p&gt;
&lt;p&gt;The lamp we have is also emitting a magnetic field. So if we turn it off &amp;hellip;&lt;/p&gt;

  &lt;img src=&#34;/img/2022-07-21_3_fff2/3.jfif&#34;  alt=&#34;The same scene as the last tweet, but things have returned to their normal colors except an area around a light source, which is still white.&#34;  class=&#34;left&#34;  /&gt;


&lt;p&gt;&amp;hellip; that&amp;rsquo;s better!&lt;/p&gt;
&lt;p&gt;This sensor works anywhere from 20 microtesla to 5 millitesla. Earth&amp;rsquo;s magnetic field is 30 uT, so we can see by it! Notice how we can see through the wall of the building in the last screenshot. That glowglobe there also emits a magnetic field, so it can wash us out too.&lt;/p&gt;
&lt;p&gt;Finally, there&amp;rsquo;s a bit of world-generation now; specifically, a biome map. And, a cute little loading screen!
But every zone still just generates one rectangle &amp;hellip; so I&amp;rsquo;ll show you my progress on worldgen next Friday.&lt;/p&gt;

  &lt;img src=&#34;/img/2022-07-21_3_fff2/3.jfif&#34;  alt=&#34;A progress bar under a half-filled box showing a map of the biomes in the world.&#34;  class=&#34;left&#34;  /&gt;


</content>
    </item>
    
    <item>
      <title>Foxfire Fridays #1</title>
      <link>/blog/2022-07-21_2_fff1/</link>
      <pubDate>Thu, 21 Jul 2022 22:45:00 -0500</pubDate>
      
      <guid>/blog/2022-07-21_2_fff1/</guid>
      <description>This Foxfire Friday was originally posted on Twitter here.
Well, looks like #FoxfireFridays is a go. (Look at me usin a hashtag.) The features I&amp;rsquo;m working on right now are only half-finished and very buggy, so instead of screenshots I&amp;rsquo;ll just give a chat.
The game is written in Rust, with Specs ECS and Macroquad. You play as a robot, in a post-post apocalypse; humans went extinct millennia ago and robots became sentient sometime after and ruled the earth for a while.</description>
      <content>&lt;p&gt;&lt;em&gt;This Foxfire Friday was &lt;a href=&#34;https://twitter.com/petrakat/status/1543103156233637888&#34;&gt;originally posted on Twitter here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Well, looks like #FoxfireFridays is a go. (Look at me usin a hashtag.)
The features I&amp;rsquo;m working on right now are only half-finished and very buggy, so instead of screenshots I&amp;rsquo;ll just give a chat.&lt;/p&gt;
&lt;p&gt;The game is written in Rust, with Specs ECS and Macroquad.
You play as a robot, in a post-post apocalypse; humans went extinct millennia ago and robots became sentient sometime after and ruled the earth for a while.
But now even their monuments fade into dust.&lt;/p&gt;
&lt;p&gt;The PC&amp;rsquo;s name/ID is SP-1R17 (&amp;ldquo;Spirit&amp;rdquo;). You fell into disrepair long ago alongside Foxfire, the superstructure you were created to serve &amp;hellip;
And one day you woke up, and the game begins, and your task is to bring Foxfire back to working order.&lt;/p&gt;
&lt;p&gt;The game is a roguelike with a heavy focus on resource and inventory management. Your chassis is a factory,
and as you bring more components back to Foxfire it will slowly wake up and let you automate it.&lt;/p&gt;
&lt;p&gt;The plan is to have a listing of many quests for Foxfire, but not all of them will be required; you only have to complete 30/40, say.
Some will be resource/automation based like &amp;ldquo;Get me 20k steel;&amp;rdquo; some will be more dungeon delve-y like &amp;ldquo;Get me this part someone stole.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Right now I am working on senses. The system actually works! &amp;hellip; except for the lighting engine.
For testing purposes, SP-1R17 has a fusion reactor and a camera. Without power for the camera, it can&amp;rsquo;t see. It can&amp;rsquo;t see in the dark or if it&amp;rsquo;s too bright, either.&lt;/p&gt;
&lt;p&gt;And it&amp;rsquo;s easy to add more sense types, too! For example, you could have IR cameras, UV cameras, magnetic sensors &amp;hellip;
A very sensitive magnetic camera could let you &amp;ldquo;see&amp;rdquo; through walls via Earth&amp;rsquo;s magnetic field! But for balance it would blind you if you get close to a magnet.&lt;/p&gt;
&lt;p&gt;These aren&amp;rsquo;t hypotheticals; this code is in the game, &lt;em&gt;right now.&lt;/em&gt; I&amp;rsquo;d just have to add a couple components to SP-1R17. (I love ECS!)
Sadly right now light goes through walls and you can&amp;rsquo;t see anything up and to the right of you &amp;hellip; so I&amp;rsquo;ll save the pics to next week.&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Hello, World</title>
      <link>/blog/2022-07-21_1_hello-world/</link>
      <pubDate>Thu, 21 Jul 2022 21:10:08 -0500</pubDate>
      
      <guid>/blog/2022-07-21_1_hello-world/</guid>
      <description>Yay, I have a blog! Thank you very very much to grywo for helping me get this set up &amp;hellip; it took about 5 hours longer than it should&amp;rsquo;ve, but it&amp;rsquo;s here now!
Off the top of my head I have a few posts I want to make but mostly I wanna stop doing Foxfire Fridays on Twitter, cause ughhhhhhh Twitter sucks as a blogging platform.</description>
      <content>&lt;p&gt;Yay, I have a blog! Thank you very very much to grywo for helping me get this set up &amp;hellip; it took about 5 hours longer than it should&amp;rsquo;ve,
but it&amp;rsquo;s here now!&lt;/p&gt;
&lt;p&gt;Off the top of my head I have a few posts I want to make but mostly I wanna stop doing Foxfire Fridays on Twitter, cause ughhhhhhh Twitter
sucks as a blogging platform.&lt;/p&gt;
</content>
    </item>
    
  </channel>
</rss>
