<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>Helldorado Team Dev Log</title><link>https://www.helldoradoteam.com/</link><description>Helldorado Team is a two-person indie game studio from Barranquilla, Colombia, building games since 2005: a faithful web port of TetriNET, The Descent, ARThings, Doom WADs, the FilmScout web app and a developer dev log.</description><language>en-us</language><image><url>https://www.helldoradoteam.com/images/icon-512.png</url><title>Helldorado Team</title><link>https://www.helldoradoteam.com/</link></image><lastBuildDate>Sun, 27 Sep 2026 12:00:00 -0500</lastBuildDate><atom:link href="https://www.helldoradoteam.com/index.xml" rel="self" type="application/rss+xml"/><item><title>Game Engines – To build, or not to build: The Eternal Conundrum (Part 5)</title><link>https://www.helldoradoteam.com/2026/09/27/game-engines-build-not-build-eternal-conundrum-part-5/</link><pubDate>Sun, 27 Sep 2026 12:00:00 -0500</pubDate><dc:creator>Elioncho</dc:creator><guid>https://www.helldoradoteam.com/2026/09/27/game-engines-build-not-build-eternal-conundrum-part-5/</guid><category>Developer Journals</category><category>Game Development</category><description>Three designers, five years, no-shows, lost money, a style we didn't want and the easter eggs we never shipped: the art story of The Descent, finally written as it returns as Cave Glider.</description><content:encoded><![CDATA[<p><a href="https://www.helldoradoteam.com/2016/12/09/game-engines-build-not-build-eternal-conundrum-part-4/">Go to Part 4</a></p>
<p>On September 27, 2018, I left a comment on Part 4 of this series: <em>&ldquo;Where is part 5?&rdquo;</em> One minute later Tiogus replied: <em>&ldquo;Elias is supposed to finish part 5, thanks.&rdquo;</em></p>
<p>He was right. Pieces of this post have been sitting in my head (and in a folder on my laptop called <code>designs</code>) ever since. I&rsquo;m finally finishing it now for a very good reason: <strong>The Descent is coming back.</strong> It&rsquo;s being re-released as <strong>Cave Glider</strong>, and this time it&rsquo;s the game we dreamt about in 2014. More on that at the end.</p>
<p>This series is about one question: <em>to build or not to build</em>. Parts 3 and 4 were about code, and about the engines and libraries we should have picked instead of writing everything ourselves. This part is about the other dependency nobody warned us about: <strong>art</strong>.</p>
<p><em>(Tiogus promised that the next article would be about Condor Wars Redux. That story is still his to tell.)</em></p>
<h2 id="2010-a-pink-wall-and-a-paper-plane">2010: a pink wall and a paper plane</h2>
<p>This is the oldest screenshot I have of The Descent. It&rsquo;s <strong>November 12, 2010, 11:30 PM</strong>. Eclipse is open, the Android emulator is running, and the game is a pink brick wall, two yellow rectangles, a tiny paper plane and a score counter that says <strong>2</strong>.</p>
<figure><img src="https://www.helldoradoteam.com/images/posts/the-descent-part-5/prototype-2010.png"
			alt="November 12, 2010: the first build of The Descent, running in the Android emulator."><figcaption>
			<p>November 12, 2010: the first build of The Descent, running in the Android emulator.</p>
		</figcaption>
</figure>

<p>Placeholder art, and honestly, already a game. Remember that paper plane. It comes back.</p>
<h2 id="2011-the-digger">2011: the digger</h2>
<p>As Tiogus told in <a href="https://www.helldoradoteam.com/2016/12/06/game-engines-build-not-build-eternal-conundrum-part-3/">Part 3</a>, in 2011 the hero became a digger drilling through the layers of the Earth&rsquo;s crust. We brought in our first freelance designer (the one we called <em>Claudia Pulcher</em> in <a href="https://www.helldoradoteam.com/2015/06/28/the-making-of-the-descent/">The Making of The Descent</a>; the pseudonyms stay). She drew a beautiful green drilling machine in seven angles, and backgrounds that got hotter the deeper you dug.</p>
<figure><img src="https://www.helldoradoteam.com/images/posts/the-descent-part-5/art-2011.png"
			alt="The 2011 art: the digger in seven angles, and the layers of the Earth, from dirt to magma."><figcaption>
			<p>The 2011 art: the digger in seven angles, and the layers of the Earth, from dirt to magma.</p>
		</figcaption>
</figure>

<p>None of it shipped. By August 2011 we were burnt out, Tiogus went back to school, and The Descent went into the freezer.</p>
<h2 id="2014-the-gliding-man-and-a-cave-full-of-secrets">2014: the gliding man, and a cave full of secrets</h2>
<p>When we brought The Descent back from the dead in the spring of 2014, the code side went well: Tiogus built a prototype with Cocos2D, and I moved it to SpriteKit. For once we didn&rsquo;t write our own engine.</p>
<p>The art side was a different story. Our first mockups still used the old digger, drilling past little hidden caves in the rock. That was the plan: <strong>every layer of the earth would hide secrets</strong>. A treasure chest, a well full of fish, the gnomes&rsquo; kitchen, a secret stash, a buried lab, a snake watching TV, a lava beach with an umbrella, a baby dragon, a dragon&rsquo;s eye, the seven dragon balls, a buried skeleton wearing a suspiciously familiar green cap. Easter eggs everywhere.</p>
<figure><img src="https://www.helldoradoteam.com/images/posts/the-descent-part-5/eggs.png"
			alt="April 2014: a mockup with the digger, and the secret caves we wanted players to find along the way."><figcaption>
			<p>April 2014: a mockup with the digger, and the secret caves we wanted players to find along the way.</p>
		</figcaption>
</figure>

<p>And we knew what we wanted it to look like: <strong>pixel art</strong>.</p>
<p>This time we tried to do things properly. In May 2014 I wrote a <em>design bible</em> for our new designer: the protagonist (a character we called the <strong>&ldquo;GLIDING MAN&rdquo;</strong>) with exact sprite sizes for each angle, obstacles built out of 2:1 rectangles with minimum and maximum sizes per level, backgrounds on a 12 × 43 grid, and a mockup of how level III would look on an iPhone 4. We even had a spreadsheet, <code>paper_plane.xlsx</code>, cataloguing obstacle patterns: right, left, double, and what follows what.</p>
<figure><img src="https://www.helldoradoteam.com/images/posts/the-descent-part-5/bible.png"
			alt="The May 2014 design bible (in Spanish): the gliding man&rsquo;s sprite sizes, obstacle proportions per level, and level III on an iPhone 4."><figcaption>
			<p>The May 2014 design bible (in Spanish): the gliding man&rsquo;s sprite sizes, obstacle proportions per level, and level III on an iPhone 4.</p>
		</figcaption>
</figure>

<h2 id="20142015-the-no-show-year">2014–2015: the no-show year</h2>
<p>Our second designer, <em>Quintus Sertorius</em> in the making-of, came on board in April 2014. His first deliveries, in June, were promising: a pilot hanging from a hang glider with red-and-white chevron wings, clouds, obstacles and floating islands.</p>
<figure><img src="https://www.helldoradoteam.com/images/posts/the-descent-part-5/art-2014.png"
			alt="June 2014: the hang glider, and the first obstacles and scenery."><figcaption>
			<p>June 2014: the hang glider, and the first obstacles and scenery.</p>
		</figcaption>
</figure>

<p>Then things stalled. In Colombia we have an expression for this: <em><strong>mamar gallo</strong></em>. It means stringing someone along: always joking around, always &ldquo;almost done&rdquo;, never quite delivering. From April to the end of July 2014, that&rsquo;s what we got. Then we took a break of our own until October (that part is on us). From October until the end of February 2015, more of the same: missed dates, silence, files that never came.</p>
<p>When files did come, they didn&rsquo;t always move us forward. In January 2015, eight months in, we received a completely new direction: a zeppelin, a man riding a bomb, a galleon, a mechanical fish, a tank, a dinosaur skeleton, the Aztec calendar stone, a holy grail. Interesting drawings, but not one finished level, and nothing like the game we had specified.</p>
<figure><img src="https://www.helldoradoteam.com/images/posts/the-descent-part-5/art-2015-jan.png"
			alt="January 2015: new ideas, eight months into the project."><figcaption>
			<p>January 2015: new ideas, eight months into the project.</p>
		</figcaption>
</figure>

<p>In February 2015 we parted ways. That made <strong>two designers in five years and zero shipped art</strong>. Along the way we also paid for artwork that never arrived, money we never saw again.</p>
<h2 id="2015-a-trade-and-a-style-we-didnt-want">2015: a trade, and a style we didn&rsquo;t want</h2>
<p>By 2015 we had no budget left for designers. What we had was a skill to trade. I had been doing freelance work for <strong>Carlos Forero</strong> of <a href="http://milmentes.co/">Milmentes</a>, so we made a deal: I would help with his website, and in exchange he would do the artwork for The Descent.</p>
<p>Carlos started in earnest in April 2015. <strong>Two months later, we had everything</strong>: the hero in seven angles, the caverns and the transitions between them, achievement badges and the title screen.</p>
<figure><img src="https://www.helldoradoteam.com/images/posts/the-descent-part-5/art-2015-forero.png"
			alt="April–July 2015: Carlos Forero&rsquo;s paper plane, achievement badges and cavern transitions."><figcaption>
			<p>April–July 2015: Carlos Forero&rsquo;s paper plane, achievement badges and cavern transitions.</p>
		</figcaption>
</figure>

<p>The catch: it wasn&rsquo;t the style we wanted. It was flat and geometric, and we had dreamt of pixel art. At first we didn&rsquo;t like it. But it was complete, it was consistent, and it arrived on time, which is more than five years of our &ldquo;perfect&rdquo; plans had produced. On June 22, 2015, I clicked Publish in Xcode.</p>
<p>And the hero? A <strong>paper plane</strong>. Five years, three designers, a digger and a hang glider later, we were back to the paper plane from that 2010 emulator screenshot.</p>
<figure><img src="https://www.helldoradoteam.com/images/posts/the-descent-part-5/art-final.png"
			alt="The Descent as it shipped in 2015."><figcaption>
			<p>The Descent as it shipped in 2015.</p>
		</figcaption>
</figure>

<h2 id="what-we-had-to-cut">What we had to cut</h2>
<p>The easter eggs never made it. There was no budget left for dozens of hand-drawn secret caves, and every week spent on art was another week The Descent wasn&rsquo;t in the App Store. The game shipped with six caverns and nothing hidden in them. The gnomes, the dragon and the snake watching TV stayed in a folder.</p>
<h2 id="build-or-buy-art-edition">Build or buy, art edition</h2>
<p>Looking back, our art story repeats every mistake we made with code:</p>
<ul>
<li><strong>Art is a dependency, just like a library.</strong> We picked ours the way we picked the Android Canvas library: quickly, hopefully and without a plan B. Pick an artist you can rely on, not just one whose portfolio you like.</li>
<li><strong>Pay for delivered work, not for promises.</strong> Milestones, dates, and payment when the files arrive.</li>
<li><strong>Decide the style before you hire, and write it down.</strong> The design bible was the best thing we did in 2014. It came a year too late.</li>
<li><strong>Placeholder art is fine.</strong> A pink wall and a yellow rectangle were enough to know if the game was fun.</li>
<li><strong>A finished style beats a perfect one you never get.</strong> We didn&rsquo;t choose flat art. It chose us, and it shipped.</li>
</ul>
<h2 id="2026-cave-glider">2026: Cave Glider</h2>
<p>Ten years later, we finally have what we were missing back then: the resources to build the game we actually dreamt about. <strong>The Descent is being re-released as Cave Glider.</strong></p>
<p>The hero is a pilot on a hang glider, the &ldquo;gliding man&rdquo; from the 2014 design bible, finally flying. The feel of the original is preserved from the 2015 source code: the seven steps of banking, the descent speeds, the obstacle patterns and the scoring. Around it, the cave grew from six caverns to twenty (and counting), and <strong>the easter eggs are back</strong>: an explorer stuck headfirst in a narrow passage, a sleeping octopus inside a treasure chest, a tea break under a giant mushroom, Robby the Robot waving from a balcony, and, snagged in a ventilation grille, a small cream-colored paper plane. That one&rsquo;s a nod to the plane that carried The Descent in 2015.</p>
<figure><img src="https://www.helldoradoteam.com/images/posts/the-descent-part-5/cave-glider.png"
			alt="Cave Glider, currently in beta testing."><figcaption>
			<p>Cave Glider, currently in beta testing.</p>
		</figcaption>
</figure>

<p>And to close the loop on this series: we didn&rsquo;t build an engine this time either. Cave Glider runs on Godot.</p>
<p>It&rsquo;s in <strong>beta testing</strong> right now. We&rsquo;ll share more very soon.</p>
<p>Tiogus, Part 6 is yours.</p>
]]></content:encoded></item><item><title>TetriNET Is Back: A Faithful Web Port of the 1997 Classic</title><link>https://www.helldoradoteam.com/2026/09/27/tetrinet-is-back/</link><pubDate>Sun, 27 Sep 2026 09:00:00 -0500</pubDate><dc:creator>Elioncho</dc:creator><guid>https://www.helldoradoteam.com/2026/09/27/tetrinet-is-back/</guid><category>News &amp; Releases</category><description>Our newest game is a faithful browser port of TetriNET v1.13, St0rmCat's six-player Tetris with special blocks from 1997. No install, just send your friends a link.</description><content:encoded><![CDATA[<p>Remember TetriNET? Six players, one server, and a bottom row full of little lettered blocks that could nuke your opponent&rsquo;s field. St0rmCat released <strong>TetriNET v1.13</strong> in February 1997, for Windows 95/NT, and the original readme opened by admitting that Tetris had &ldquo;been done 2 billion times before (give or take a few bil)&rdquo;. Then it went on to eat countless hours of everyone&rsquo;s time anyway.</p>
<p>Today we&rsquo;re releasing our newest game: <strong>a faithful web port of TetriNET 1.13</strong> that runs right in your browser. No install, no finding a server on EFnet, no port forwarding. Create a room, send the invite link to up to five friends, and start dropping blocks on each other.</p>
<p><a class="btn" href="https://tetrinet.helldoradoteam.com">▶ Play TetriNET now</a></p>
<figure><img src="https://www.helldoradoteam.com/images/posts/tetrinet/modern-game.png"
			alt="Modern mode: a three-player game in progress. Your field on the left, your rivals on the right."><figcaption>
			<p>Modern mode: a three-player game in progress. Your field on the left, your rivals on the right.</p>
		</figcaption>
</figure>

<h2 id="faithful-means-faithful">Faithful means <em>faithful</em></h2>
<p>We didn&rsquo;t want &ldquo;a Tetris game inspired by TetriNET&rdquo;. We wanted <strong>the</strong> game. So we reverse-engineered the original <code>TETRINET.EXE</code> (a Delphi 2 binary from 1997) and rebuilt it from the disassembly:</p>
<ul>
<li><strong>The rules, timings, randomness and network messages follow the original code.</strong> Pieces spawn the way 1.13 spawned them, gravity ticks at the same 1010-ms-minus-10-per-level rate, and even Delphi&rsquo;s random number generator is reproduced.</li>
<li><strong>The windows are generated from the original Delphi form layouts</strong>, and the original graphics, sounds and music are used.</li>
<li><strong>The quirks stay.</strong> Every weird thing that made 1.13 feel like 1.13 is still there, on purpose. A few of our favorites:
<ul>
<li>The readme says levels cap at 100. The binary never checks, so they don&rsquo;t.</li>
<li>Soft drop is fixed at 100 ms, so from level 92 on, pressing ↓ actually makes your piece fall <em>slower</em>.</li>
<li><em>Random Blocks Clear</em> picks 10 random cells, empty ones included, so sometimes it clears nothing at all.</li>
<li><em>Clear Special Blocks</em> doesn&rsquo;t remove specials. It turns them into random colours.</li>
<li>You can attack your own teammates. We know. We kept it.</li>
</ul>
</li>
</ul>
<p>Every one of these was checked against the disassembly, and each one is documented. The list of original quirks we kept, and the handful of things we changed, lives in the project&rsquo;s notes.</p>
<h2 id="two-ways-to-play-modern-and-legacy">Two ways to play: Modern and Legacy</h2>
<p>The same engine and the same server power two completely different interfaces, and players on either one can share a room.</p>
<p><strong>Modern mode</strong> is a neon-arcade makeover: rooms with invite links, a lobby with partyline chat, the rules editor and the win list, plus effects and our own synthesized sound and music.</p>
<figure><img src="https://www.helldoradoteam.com/images/posts/tetrinet/modern-lobby.png"
			alt="The lobby: players, the partyline chat and the game rules. The 1.13 defaults are one click away."><figcaption>
			<p>The lobby: players, the partyline chat and the game rules. The 1.13 defaults are one click away.</p>
		</figcaption>
</figure>

<p><strong>Legacy mode</strong> is the 1997 Windows interface, rebuilt pixel for pixel from the original forms, down to the StormCat Productions splash screen, the gray bevels and the &ldquo;Attacks/Defenses&rdquo; log.</p>
<figure><img src="https://www.helldoradoteam.com/images/posts/tetrinet/legacy-game.png"
			alt="Legacy mode: the original Playing Fields window, in a browser, in the same room as the modern players."><figcaption>
			<p>Legacy mode: the original Playing Fields window, in a browser, in the same room as the modern players.</p>
		</figcaption>
</figure>

<figure><img src="https://www.helldoradoteam.com/images/posts/tetrinet/legacy-splash.png"
			alt="Yes, even the splash screen asking you to mail $10 to Minnesota."><figcaption>
			<p>Yes, even the splash screen asking you to mail $10 to Minnesota.</p>
		</figcaption>
</figure>

<h2 id="whats-different">What&rsquo;s different</h2>
<p>Moving a Windows game where one player hosted the server into browsers took a few changes:</p>
<ul>
<li><strong>The server is a small Node process</strong> and everyone connects over WebSockets. The message strings are the original&rsquo;s.</li>
<li><strong>The moderator</strong> (the first player, marked with <code>*</code> just like in 1.13) also gets the server operator&rsquo;s powers: game settings, block occurrence, kicking players and resetting the win list.</li>
<li><strong>Solo practice.</strong> You can start a game alone to warm up. It ends when you top out.</li>
<li><strong>The server checks who&rsquo;s talking.</strong> In 1.13 any client could send messages pretending to be another player. Not anymore.</li>
<li><strong>Music.</strong> Browsers don&rsquo;t come with a MIDI synth, so the original <code>TETRINET.MID</code> plays through a tiny synthesizer we wrote for the web.</li>
</ul>
<p>Still on the to-do list: the ban list, theme (<code>.tnp</code>) switching, and letting real 1.13 clients connect over TCP. The protocol is already there.</p>
<h2 id="how-to-play">How to play</h2>
<ol>
<li>Go to <a href="https://tetrinet.helldoradoteam.com">tetrinet.helldoradoteam.com</a>, pick a nickname and click <strong>Create room</strong>.</li>
<li>Send the invite link to up to five friends.</li>
<li>Clear lines to collect <strong>special blocks</strong> into your inventory. Press <strong>1–6</strong> to fire your first special at that player (your own number uses it on yourself) and <strong>D</strong> to discard it.</li>
<li>The last player (or team) standing wins. The top three score 3, 2 and 1 points on the win list.</li>
</ol>
<table>
	<thead>
			<tr>
					<th>Key</th>
					<th>Action</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>← →</td>
					<td>Move</td>
			</tr>
			<tr>
					<td>↑ / Ctrl</td>
					<td>Rotate right / left</td>
			</tr>
			<tr>
					<td>↓</td>
					<td>Faster fall</td>
			</tr>
			<tr>
					<td>Space</td>
					<td>Drop</td>
			</tr>
			<tr>
					<td>1–6</td>
					<td>Use a special on a player</td>
			</tr>
			<tr>
					<td>D</td>
					<td>Discard a special</td>
			</tr>
			<tr>
					<td>T</td>
					<td>Talk</td>
			</tr>
	</tbody>
</table>
<p>Prefer the old look? Jump straight into <a href="https://tetrinet.helldoradoteam.com/legacy.html">Legacy mode</a>.</p>
<p>Huge thanks to <strong>St0rmCat</strong> for creating TetriNET back in 1997. This port exists because we loved the original. Now go find five friends and send them a Nuke Field.</p>
]]></content:encoded></item><item><title>ARThings v2.3 Released!</title><link>https://www.helldoradoteam.com/2020/10/25/arthings-v2-3-released/</link><pubDate>Sun, 25 Oct 2020 09:59:29 -0500</pubDate><dc:creator>Tiogus</dc:creator><guid>https://www.helldoradoteam.com/2020/10/25/arthings-v2-3-released/</guid><category>News &amp; Releases</category><description>Download v2.3 now! It’s been kind of a long development cycle but we decided to launch this release with some features which include the following: Update to ARCore 1.20 Added support for OpenGL ES 3.0 Added Push Notifications New monster: Added the Cacodemon! Added ability to toggle God Mode in the Cheats section under the Settings menu Made some changes to spawn pickup items closer to player to lower the difficulty Capped the rendering framerate to resolve some FPS inconsistencies HUD change: Added screen flash effect when picking up items Fixed some crashes causing app instability Here’s a preview of an early Alpha version of v2.3 that shows the Cacodemon in action:</description><content:encoded><![CDATA[<p><a href="https://play.google.com/store/apps/details?id=com.helldoradoteam.ardoom&amp;hl=en_US"><strong>Download v2.3 now!</strong></a></p>
<p>It&rsquo;s been kind of a long development cycle but we decided to launch this release with some features which include the following:</p>
<ol>
<li>Update to ARCore 1.20</li>
<li>Added support for OpenGL ES 3.0</li>
<li>Added Push Notifications</li>
<li><strong>New monster</strong>: Added the Cacodemon!</li>
<li>Added ability to toggle God Mode in the Cheats section under the Settings menu</li>
<li>Made some changes to spawn pickup items closer to player to lower the difficulty</li>
<li>Capped the rendering framerate to resolve some FPS inconsistencies</li>
<li><strong>HUD change</strong>: Added screen flash effect when picking up items</li>
<li>Fixed some crashes causing app instability</li>
</ol>
<p>Here&rsquo;s a preview of an early Alpha version of v2.3 that shows the Cacodemon in action:</p>
<div class="yt" data-id="y6XGOALC9QI" data-title="ARThings v2.3 Released!" style="background-image:url(https://i.ytimg.com/vi/y6XGOALC9QI/hqdefault.jpg)">
  <button type="button" aria-label="Play video: ARThings v2.3 Released!"></button>
</div>


<p>We haven&rsquo;t made a blog post on other releases after v2.0 (5 months ago!) so here&rsquo;s what we&rsquo;ve incorporated since then:</p>
<p><strong>v2.2 - v2.2.3</strong></p>
<ol>
<li>Fixed some issues with OpenGL alpha blending</li>
<li>Added Firebase Crashlytics to debug an OpenGL Shader compilation issue in some affected devices</li>
</ol>
<p><strong>v2.1</strong></p>
<ol>
<li>Updated to ARCore 1.19</li>
<li>Enabled Depth API Depth Occlusion for supported devices</li>
<li>Made some rendering frame rate tweaks</li>
<li>Made a change to spawn monsters at least 2 meters away from the player</li>
</ol>
]]></content:encoded></item><item><title>ARThings v2.0 Released!</title><link>https://www.helldoradoteam.com/2020/05/22/arthings-v2-0-released/</link><pubDate>Fri, 22 May 2020 10:17:31 -0500</pubDate><dc:creator>Tiogus</dc:creator><guid>https://www.helldoradoteam.com/2020/05/22/arthings-v2-0-released/</guid><category>News &amp; Releases</category><description>After a long period of Development Hell, we’re proud to release ARThings v2.0. Download v2.0 now! We added support for floating monsters (Lost Souls, Cacodemons, etc.) however v2.0 only spawns Lost Souls. We also added the Chainsaw due to popular demand, so you can saw “Pinkies” to the tune of I Sawed Demons.</description><content:encoded><![CDATA[<p>After a long period of Development Hell, we&rsquo;re proud to release ARThings v2.0.</p>
<p><a href="https://play.google.com/store/apps/details?id=com.helldoradoteam.ardoom&amp;hl=en_US"><strong>Download v2.0 now!</strong></a></p>
<p>We added support for floating monsters (Lost Souls, Cacodemons, etc.) however v2.0 only spawns Lost Souls. We also added the Chainsaw due to popular demand, so you can saw &ldquo;Pinkies&rdquo; to the tune of <a href="https://www.youtube.com/watch?v=NlWDSvNSzlA&amp;t=12s">I Sawed Demons</a>.</p>
<p>Adding the Chainsaw required some changes to the sound effects implementation, so we refactored this code quite a bit. The Vanilla Doom code handles the playing and stopping of sounds, and the unique sound effects of the Chainsaw make use of this, particularly the switching between the idle, attack and hit frames of the Chainsaw. So we had to do some work in the sound code to replicate this same behavior in ARThings. We also updated ARCore to v1.17 in this version.</p>
<p>Anyways below are 2 videos that showcase these features:</p>
<div class="yt" data-id="uRO2mQQa22o" data-title="ARThings v2.0 Released!" style="background-image:url(https://i.ytimg.com/vi/uRO2mQQa22o/hqdefault.jpg)">
  <button type="button" aria-label="Play video: ARThings v2.0 Released!"></button>
</div>


<div class="yt" data-id="qaT1yKpZrco" data-title="ARThings v2.0 Released!" style="background-image:url(https://i.ytimg.com/vi/qaT1yKpZrco/hqdefault.jpg)">
  <button type="button" aria-label="Play video: ARThings v2.0 Released!"></button>
</div>


]]></content:encoded></item><item><title>ARThings v1.9 Released... Finally!</title><link>https://www.helldoradoteam.com/2020/02/08/arthings-v1-9-released-finally/</link><pubDate>Sat, 08 Feb 2020 06:51:30 -0500</pubDate><dc:creator>Tiogus</dc:creator><guid>https://www.helldoradoteam.com/2020/02/08/arthings-v1-9-released-finally/</guid><category>News &amp; Releases</category><description>Download v1.9 now! We recently released v1.9 of ARThings, which included a couple of new features (addition of a new monster and weapon) and some under-the-hood improvements. We also introduced 3 new achievements and some game difficulty balancing. We discovered some major bugs (pre v1.9) with monster spawning that made the game incredibly difficult - monsters spawn too frequently, and these bugs are fixed in v1.9.</description><content:encoded><![CDATA[<p><a href="https://play.google.com/store/apps/details?id=com.helldoradoteam.ardoom&amp;hl=en_US"><strong>Download v1.9 now!</strong></a></p>
<p>We recently released v1.9 of ARThings, which included a couple of new features (addition of a new monster and weapon) and some under-the-hood improvements.</p>
<p>We also introduced 3 new achievements and some game difficulty balancing. We discovered some major bugs (pre v1.9) with monster spawning that made the game incredibly difficult - monsters spawn too frequently, and these bugs are fixed in v1.9.</p>
<p>Below is a clip of a pre-alpha version of v1.9 showcasing a rough implementation of the Plasma Gun:</p>
<div class="yt" data-id="ZJ_GBaZX_7w" data-title="ARThings v1.9 Released... Finally!" style="background-image:url(https://i.ytimg.com/vi/ZJ_GBaZX_7w/hqdefault.jpg)">
  <button type="button" aria-label="Play video: ARThings v1.9 Released... Finally!"></button>
</div>


<p>Below are the full release notes, we hope you enjoy!</p>
<ol>
<li>Added spawning of Baron of Hells</li>
<li>Added spawning of Plasma Gun when killing Baron of Hells</li>
<li>Reduced the frequency of Chaingunners spawning</li>
<li>Added gib animation for Zombies, Imps and Shotgun Guys</li>
<li>Added some logic to make missiles explode when too far</li>
<li>Fixed thrust and friction implementation that was not working before</li>
<li>Added 3 new achievements - Picking up Plasma Gun, Killing Baron of Hell (Boss) and Gibbing a monster</li>
<li>Added spawning of Blue Armor</li>
<li>Added spawning of clips, 4 shotgun shells and cells</li>
<li>Fixed bug of monsters spawning when they&rsquo;re not supposed to</li>
</ol>
]]></content:encoded></item><item><title>ARThings v1.8 Released!</title><link>https://www.helldoradoteam.com/2019/12/24/arthings-v1-8-released/</link><pubDate>Tue, 24 Dec 2019 11:22:40 -0500</pubDate><dc:creator>Tiogus</dc:creator><guid>https://www.helldoradoteam.com/2019/12/24/arthings-v1-8-released/</guid><category>News &amp; Releases</category><description>Download v1.8 now! This is a light release and the last one before the start of 2020. We introduced 2 Leaderboards: Most kills in a single round. Total kills for all rounds. We also display Top kills in a single round in the HUD (displayed in green color).</description><content:encoded><![CDATA[<p><a href="https://play.google.com/store/apps/details?id=com.helldoradoteam.ardoom&amp;hl=en_US"><strong>Download v1.8 now!</strong></a></p>
<p>This is a light release and the last one before the start of 2020. We introduced 2 Leaderboards:</p>
<ul>
<li>Most kills in a single round.</li>
<li>Total kills for all rounds.</li>
</ul>
<p>We also display Top kills in a single round in the HUD (displayed in green color).</p>
<p>I took a video of v1.8 today, which includes footage of unlocking some achievements - including unlocking and picking up the Super Shotgun before I was mowed down by demons:</p>
<div class="yt" data-id="e9RTMcSKJ_4" data-title="ARThings v1.8 Released!" style="background-image:url(https://i.ytimg.com/vi/e9RTMcSKJ_4/hqdefault.jpg)">
  <button type="button" aria-label="Play video: ARThings v1.8 Released!"></button>
</div>


]]></content:encoded></item><item><title>Configuring Google Play Game Services for Android Debug and Release Apps</title><link>https://www.helldoradoteam.com/2019/12/21/configuring-google-play-game-services-for-android-debug-and-release-apps/</link><pubDate>Sat, 21 Dec 2019 15:31:40 -0500</pubDate><dc:creator>Tiogus</dc:creator><guid>https://www.helldoradoteam.com/2019/12/21/configuring-google-play-game-services-for-android-debug-and-release-apps/</guid><category>News &amp; Releases</category><description>While developing an Android app with Google Play Game Services integration a developer needs the following for testing Game Services features: Ability to test in a Android debug app (signed with debug certificate) with unpublished achievements using a tester account.</description><content:encoded><![CDATA[<p>While developing an Android app with Google Play Game Services integration a developer needs the following for testing Game Services features:</p>
<ol>
<li>
<p>Ability to test in a Android debug app (signed with debug certificate) with unpublished achievements using a tester account.</p>
</li>
<li>
<p>Ability to test in a Android release app (signed with release certification), fully signed by Google Play with a published Game Services configuration.</p>
</li>
</ol>
<p>Google provides some documentation on how to setup Game Services for Android. This documentation clearly outlines the configuration process:</p>
<ol>
<li><a href="https://developers.google.com/games/services/console/enabling">Setting Up Google Play Game Services</a></li>
<li><a href="https://developers.google.com/games/services/android/quickstart">Getting Started with Play Game Services for Android</a></li>
</ol>
<p>However, despite these guides some developers might face some stumbling blocks along the way. After dealing with this myself, I&rsquo;ve outlined below some general guidelines on how accomplish the configuration for both Android debug and release apps published to Google Play.</p>
<p><strong>Testing in Debug Mode</strong></p>
<p>To test in debug mode, you need to create a Linked App inside the Game Services configuration that corresponds to your Android debug app. The Client ID used by this Linked App needs to use the SHA1 fingerprint of the Android debug keystore (debug.keystore). Typically, for Windows users this keystore is located in the following path:</p>
<pre tabindex="0"><code>C:\Users\{your Windows username}\.android\debug.keystore
</code></pre><p>To find the fingerprint of this keystore all you need to do is run the following in the command prompt:</p>
<pre tabindex="0"><code>keytool -list -v -keystore &#34;C:\Users\{your Windows username}\.android\debug.keystore&#34; -alias androiddebugkey -storepass android -keypass android
</code></pre><p>This command will spit out the SHA1 fingerprint of the certificate:</p>
<pre tabindex="0"><code>Certificate chain length: 1

Certificate[1]:

Owner: C=US, O=Android, CN=Android Debug

Issuer: C=US, O=Android, CN=Android Debug

Serial number: 1

Valid from: Thu Jul 07 15:17:58 EDT 2016 until: Sat Jun 30 15:17:58 EDT 2046

Certificate fingerprints:

         SHA1: [SHA1 fingerprint]

         SHA256: [SHA256 fingerprint]

Signature algorithm name: SHA1withRSA

Subject Public Key Algorithm: 1024-bit RSA key

Version: 1
</code></pre><p>You can then copy paste the SHA1 fingerprint into the SHA1 fingerprint of the Client ID needed by Game Services and you should be good to go.</p>
<p>If for some reason you can&rsquo;t find the keystore there&rsquo;s another way to find out the SHA1 fingerprint based on the Android app&rsquo;s generated apk. The Android SDK Build Tools come with a nice little tool called &ldquo;apksigner&rdquo; that can be accessed through the command line via the following path</p>
<pre tabindex="0"><code>C:\Users\{your Windows username}\AppData\Local\Android\sdk\build-tools\{version}
</code></pre><p>The &ldquo;apksigner&rdquo; tool takes the path of an apk and returns information about the certificate that the apk was signed with. Below is an example of the command line:</p>
<pre tabindex="0"><code>apksigner verify --print-certs C:\{Your apk path}\app-debug.apk
</code></pre><p>This will spit out the SHA256, SHA1 and MD5 fingerprints of the keystore the apk was signed with:</p>
<pre tabindex="0"><code>Signer #1 certificate DN: C=US, O=Android, CN=Android Debug

Signer #1 certificate SHA-256 digest: [SHA-256 fingerprint]

Signer #1 certificate SHA-1 digest: [SHA-1 fingerprint]

Signer #1 certificate MD5 digest: [MD5 fingerprint]
</code></pre><p><strong>Testing in Release Mode</strong></p>
<p>The above instructions also apply for Release Mode, but with one small change: <strong>You need to use the SHA1 fingerprint of the certificate that Google Play uses to sign the release apk with in Google Play (called the &ldquo;App signing certificate&rdquo;, NOT the certificate you use to bundle your apk in release mode (called the &ldquo;Upload Certificate&rdquo;) from the &ldquo;Build -&gt; Generate Signed Bundle / APK&rdquo; option in Android Studio.</strong></p>
<p>Getting the SHA1 fingerprint of the App signing certificate is very simple. Go to Google Play Console, click on your app and navigate to the &ldquo;Release Management -&gt; App signing&rdquo; section. In the &ldquo;App signing certificate&rdquo; section (screenshot below), use the SHA1 certificate fingerprint (masked in the screenshot below) for your release app Client ID.</p>
<p>The important thing here is to use SHA-1 fingerprint of the <strong>App signing certificate</strong>, NOT the <strong>Upload certificate</strong>.</p>
<figure><img src="https://www.helldoradoteam.com/wp-content/uploads/2019/12/image.png">
</figure>

<p>In a nutshell, here&rsquo;s the overall approach:</p>
<ol>
<li><strong>Testing Game Services for debug Android</strong>: Create a Linked App using using a Client ID using the SHA1 fingerprint of Android&rsquo;s default debug keystore (debug.keystore).</li>
<li><strong>Testing Game Services for release Android app in the Play Store</strong>: Create a Linked App using a Client ID using the SHA1 fingerprint of the &ldquo;App signing certificate&rdquo;.</li>
</ol>
]]></content:encoded></item><item><title>ARThings v1.7 released!</title><link>https://www.helldoradoteam.com/2019/12/17/arthings-v1-7-released/</link><pubDate>Tue, 17 Dec 2019 06:56:19 -0500</pubDate><dc:creator>Tiogus</dc:creator><guid>https://www.helldoradoteam.com/2019/12/17/arthings-v1-7-released/</guid><category>News &amp; Releases</category><description>Download v1.7 here! After a small period of development hell, we finally released ARThings v1.6 last Saturday. This release is a big step into making ARThings more of a game experience versus just a mere technical demo. We’ve still got a long way to go, but we’re ok with taking baby steps and experimenting with new features.</description><content:encoded><![CDATA[<p><a href="https://play.google.com/store/apps/details?id=com.helldoradoteam.ardoom&amp;hl=en_US">Download v1.7 here!</a></p>
<p>After a small period of development hell, we finally released ARThings v1.6 last Saturday. This release is a big step into making ARThings more of a game experience versus just a mere technical demo. We&rsquo;ve still got a long way to go, but we&rsquo;re ok with taking baby steps and experimenting with new features.</p>
<p>The main addition in v1.6 is the integration of Google Play Game Services, supporting the following 3 achievements:</p>
<ol>
<li>Killing 30 monsters in a row without dying</li>
<li>Picking up the Chaingun</li>
<li>Picking up the Super Shotgun</li>
</ol>
<p>Below are the full v1.6 release notes:</p>
<pre tabindex="0"><code>1. ARCore 1.13 update
2. Google Play Game Services integration with 3 achievements 
3. AR Session filter -&gt; limited camera capture rate to 30fps and prevented the use of depth sensor
4. Added the Super Shotgun (awarded as a gift but won&#39;t give you spoilers on how to get it!)
2. HUD changes
</code></pre><p>Version 1.6 ended up having a bug with Google Sign In, so we made an emergency v1.7 release with the following changes:</p>
<pre tabindex="0"><code>1. ARCore 1.14 update
2. Google Play Game Services update to 19.0.0
3. Disabled AR Session filtering -&gt; camera capture rate and use of depth sensor is not limited anymore
4. Settings menu -&gt; Added Player Id to Signed In message
5. Settings menu -&gt; Added icon to achievement button
6. Settings menu -&gt; Positioned Sign Out button at the bottom
7. Updated Sign In error dialogs to display more informational messages
8. Sign out -&gt; Updated sign out handling code
9. Game Services -&gt; Released achievements buffer to fix memory leak
10. Fixed memory leaks in Game Services static member variables
</code></pre><p>Below is a short video of v1.7 - it doesn&rsquo;t showcase all the features of this release (like the Super Shotgun) since I was killed repeatedly before I was able to unlock it but I&rsquo;ll post a video of the Super Shotgun soon!</p>
<div class="yt" data-id="4141vHMQ9ac" data-title="ARThings v1.7 released!" style="background-image:url(https://i.ytimg.com/vi/4141vHMQ9ac/hqdefault.jpg)">
  <button type="button" aria-label="Play video: ARThings v1.7 released!"></button>
</div>


]]></content:encoded></item><item><title>FilmScout Released!</title><link>https://www.helldoradoteam.com/2019/09/30/filmscout-released/</link><pubDate>Mon, 30 Sep 2019 12:28:59 -0500</pubDate><dc:creator>Elioncho</dc:creator><guid>https://www.helldoradoteam.com/2019/09/30/filmscout-released/</guid><category>App Development</category><category>Movies</category><description>UPDATE: FilmScout is now a web app at filmscout.net. The iOS and Android apps are no longer available. We are happy to announce the official release of FilmScout for iOS and Android.</description><content:encoded><![CDATA[<p><strong>UPDATE: FilmScout is now a web app at <a href="https://filmscout.net">filmscout.net</a>. The iOS and Android apps are no longer available.</strong></p>
<p>We are happy to announce the official release of FilmScout for <a href="https://apps.apple.com/us/app/filmscout/id1471828639?ls=1">iOS</a> and <a href="https://play.google.com/store/apps/details?id=com.helldoradoteam.movies">Android</a>.</p>
<p>FilmScout lets you keep track of your favorite filmmaker&rsquo;s projects. You can search for information on your favorite movies and TV shows, check the filmmaking team, explore their works, and follow them to keep track of their upcoming projects.</p>
<p>Right now, you can track filmmakers in the following roles:</p>
<ul>
<li>Director</li>
<li>Screenwriter/Writer</li>
<li>Composer</li>
<li>Cinematographer/Director of Photography</li>
<li>Editor</li>
</ul>
<p>Feel free to write to us with any feedback you have!</p>
]]></content:encoded></item><item><title>Handling AWS SNS notifications in Ruby on Rails</title><link>https://www.helldoradoteam.com/2019/09/24/handling-aws-sns-notifications-in-ruby-on-rails/</link><pubDate>Tue, 24 Sep 2019 17:00:26 -0500</pubDate><dc:creator>Elioncho</dc:creator><guid>https://www.helldoradoteam.com/2019/09/24/handling-aws-sns-notifications-in-ruby-on-rails/</guid><category>App Development</category><description>Today I’m going to share with you how to handle AWS SNS notifications in a Ruby on Rails app. An SNS topic publishes every message it receives to every subscriber, and our app is subscribed to receive these messages via HTTP.</description><content:encoded><![CDATA[<p>Today I&rsquo;m going to share with you how to handle AWS SNS notifications in a Ruby on Rails app. An SNS topic publishes every message it receives to every subscriber, and our app is subscribed to receive these messages via HTTP.</p>
<p>SNS messages come in 2 types:</p>
<ul>
<li>SubscriptionConfirmation: Is sent when a subscription is created to confirm that the endpoint is up an running. The <em>confirm_subscription</em> method handles this.</li>
<li>Notification: Once the subscription is confirmed, all the following messages will be of this type. These are the messages that are sent to a topic and then fanned out to every subscriber out there.</li>
</ul>
<p>The <em>verify_request_authenticity</em> method is called first to verify the authenticity of the SNS message. It checks that the message is not empty and verifies its origin using the <em>MessageVerifier</em> class. Finally, the <em>create</em> method parses the message content accordingly.</p>
<p>I hope this can be of great help to everyone out there. Feel free to comment if you have any questions or feedback.</p>
<pre tabindex="0"><code># frozen_string_literal: true

# Notifications coming from SNS
class NotificationsController &lt; ActionController::Base
  before_action :verify_request_authenticity

  # @url /notifications
  #
  # @action POST
  #
  # Broadcasts a SNS message to an ActionCable channel
  #
  #
  def create
    case message_body[&#39;Type&#39;]
    when &#39;SubscriptionConfirmation&#39;
      confirm_subscription ? (head :ok) : (head :bad_request)
    when &#39;Notification&#39;
      message = JSON.parse(message_body[&#39;Message&#39;])
      BroadcastExecutionNotificationJob.perform_later(message)
      head :ok
    end
  end

  private

  def verify_request_authenticity
    head :unauthorized if raw_post.blank? || !message_verifier.authentic?(raw_post)
  end

  def raw_post
    @raw_post ||= request.raw_post
  end

  def message_body
    @message_body ||= JSON.parse(raw_post)
  end

  def message_verifier
    @message_verifier ||= Aws::SNS::MessageVerifier.new
  end

  def confirm_subscription
    AWS_SNS_CLIENT.confirm_subscription(
      topic_arn: message_body[&#39;TopicArn&#39;],
      token: message_body[&#39;Token&#39;]
    )
    true
  rescue Aws::SNS::Errors::ServiceError =&gt; e
    Rails.logger.info(e.message)
    false
  end
end
</code></pre>]]></content:encoded></item><item><title>The Breach (Doom 2 WAD) Released!</title><link>https://www.helldoradoteam.com/2019/09/21/the-breach-doom-2-wad-released/</link><pubDate>Sat, 21 Sep 2019 19:06:39 -0500</pubDate><dc:creator>Tiogus</dc:creator><guid>https://www.helldoradoteam.com/2019/09/21/the-breach-doom-2-wad-released/</guid><category>News &amp; Releases</category><description>Helldorado Team’s Doom WAD portfolio hasn’t been particularly illustrious. In fact until this year its been nonexistent. Can we recall the overly hyped Confessions from the Flesh - announced back in May of 2006 but cancelled after only 2 days of development?</description><content:encoded><![CDATA[<p>Helldorado Team&rsquo;s Doom WAD portfolio hasn&rsquo;t been particularly illustrious. In fact until this year its been nonexistent. Can we recall the overly hyped <a href="https://brain-dead-studios.blogspot.com/2006/05/confessions-from-flesh-announced.html">Confessions from the Flesh</a> - announced back in May of 2006 but cancelled after only 2 days of development?</p>
<p>Let&rsquo;s recount Helldorado Team&rsquo;s various attempt at WAD building for a moment:</p>
<ul>
<li><strong>Exhumed</strong> - began in 2012 as a single map for ZDoom. Much more progress was made compared to Confessions but after 3 weeks the team lost interest. Development resumed in December 2018 but yet again scope creep derailed the project when the team tried to incorporate countless features to showcase GZDoom advanced capabilities. The project was shelved by end of December.</li>
<li><strong>Septic Shock</strong> - After Exhumed, the development team decided to keep it simple. The goal was to build a single Boom-compatible map for Doom 2 and avoid the development pitfall every Doom mapping newcomer faces - getting carried away with ZDoom features. Development began in January 1st 2019 but the project was put on hold in mid February due to other priorities.</li>
</ul>
<p>Despite the aforementioned facepalms, we&rsquo;re proud to celebrate the breaking of this vicious cycle. Today we release Helldorado Team&rsquo;s first Doom WAD - The Breach. It&rsquo;s a Boom-compatible 2-map WAD for Doom 2. You can download the WAD by downloading the breach.rar file from the original Doomworld thread:</p>
<p><a href="https://www.doomworld.com/forum/topic/109113-the-breach-2-techbase-maps/">Doomworld: The Breach - 2 Techbase maps</a></p>
<p><strong>How to play?</strong> If you are newcomer to Doom and its source ports, you can download a Doom source port such as PrBoom+ or GZDoom and drag and drop breach.wad over to the source port executable. The WAD requires Doom 2 so make sure Doom2.wad is in the same folder as the source port executable.</p>
<p>Screenshots below:</p>
<figure><img src="https://www.helldoradoteam.com/wp-content/uploads/2019/09/map01.png"
			alt="MAP01: The Pass"><figcaption>
			<p>MAP01: The Pass</p>
		</figcaption>
</figure>

<figure><img src="https://www.helldoradoteam.com/wp-content/uploads/2019/09/map02.png"
			alt="MAP02: Perimeter"><figcaption>
			<p>MAP02: Perimeter</p>
		</figcaption>
</figure>

]]></content:encoded></item><item><title>ARThings v1.4 released!</title><link>https://www.helldoradoteam.com/2019/09/08/arthings-v1-4-released/</link><pubDate>Sun, 08 Sep 2019 10:28:12 -0500</pubDate><dc:creator>Tiogus</dc:creator><guid>https://www.helldoradoteam.com/2019/09/08/arthings-v1-4-released/</guid><category>News &amp; Releases</category><description>It’s been a little bit over a month but finally v1.4 is out. We already covered what’s new on our previous sneak peek post, but below is a laundry list of some of the major changes:</description><content:encoded><![CDATA[<p>It&rsquo;s been a little bit over a month but finally v1.4 is out. We already covered what&rsquo;s new on our previous sneak peek post, but below is a laundry list of some of the major changes:</p>
<ul>
<li>Added the Imp monster</li>
<li>Added player damage and player death, plus player&rsquo;s ability to retry after dying</li>
<li>Random spawning of health and armor items</li>
<li>Some changes to the HUD</li>
</ul>
<p>Check out some of the action below, any feedback is welcome for v1.5!</p>
<p><a href="https://play.google.com/store/apps/details?id=com.helldoradoteam.ardoom&amp;hl=en_US">Download v1.4 from Google Play now!</a></p>
<div class="yt" data-id="QpRzRl4cJZg" data-title="ARThings v1.4 released!" style="background-image:url(https://i.ytimg.com/vi/QpRzRl4cJZg/hqdefault.jpg)">
  <button type="button" aria-label="Play video: ARThings v1.4 released!"></button>
</div>


]]></content:encoded></item><item><title>Sneak peek at ARThings v1.4 (Alpha)</title><link>https://www.helldoradoteam.com/2019/08/31/sneak-peek-at-arthings-v1-4-alpha/</link><pubDate>Sat, 31 Aug 2019 08:36:47 -0500</pubDate><dc:creator>Tiogus</dc:creator><guid>https://www.helldoradoteam.com/2019/08/31/sneak-peek-at-arthings-v1-4-alpha/</guid><category>Developer Journals</category><description>ARThings v1.3 introduced the Shotgun Guy monster from Doom. Since then we’ve been brainstorming ideas for new features. Given the sandboxy feeling of ARThings so far the natural course was incorporating features that would make the experience feel more like a game.</description><content:encoded><![CDATA[<p>ARThings v1.3 introduced the <a href="https://doomwiki.org/wiki/Shotgun_guy">Shotgun Guy</a> monster from Doom. Since then we&rsquo;ve been brainstorming ideas for new features. Given the sandboxy feeling of ARThings so far the natural course was incorporating features that would make the experience feel more like a game.</p>
<p>Users have been clamoring for the introduction of health and player damage, so that&rsquo;s what we primarily focused on for v1.4, in addition to the introduction of another monster - the <a href="https://doomwiki.org/wiki/Imp">Imp</a>. We also introduced some minor HUD changes to display Health and Armor.</p>
<p>Check out some of the action from v1.4 (to be released soon) below!</p>
<div class="yt" data-id="njNrigid6xg" data-title="Sneak peek at ARThings v1.4 (Alpha)" style="background-image:url(https://i.ytimg.com/vi/njNrigid6xg/hqdefault.jpg)">
  <button type="button" aria-label="Play video: Sneak peek at ARThings v1.4 (Alpha)"></button>
</div>


]]></content:encoded></item><item><title>ARThings v1.3 Released!</title><link>https://www.helldoradoteam.com/2019/08/02/arthings-v1-3-released/</link><pubDate>Fri, 02 Aug 2019 07:35:01 -0500</pubDate><dc:creator>Tiogus</dc:creator><guid>https://www.helldoradoteam.com/2019/08/02/arthings-v1-3-released/</guid><category>News &amp; Releases</category><description>Yes, it’s been a while but v1.3 is finally out. Helldorado Team has been busy with other projects since November 2018 (wasting time creating vaporware WADs amongst other things thanks to Elioncho’s encouragement) but we plan to add more features over the next couple of months and focus on this app for the remainder of the year.</description><content:encoded><![CDATA[<p>Yes, it&rsquo;s been a while but v1.3 is finally out. Helldorado Team has been busy with other projects since November 2018 (wasting time creating vaporware WADs amongst other things thanks to Elioncho&rsquo;s encouragement) but we plan to add more features over the next couple of months and focus on this app for the remainder of the year.</p>
<p>This is a minor release with one major addition - the Shotgun Guy monster. The plan was also to add another weapon - the Super Shotgun. However this plan was too ambitious and the feature discarded for the time being. Another addition is the update to ARCore 1.10 - we hope this enhances the overall AR experience.</p>
<p>Thinking ahead we might add one more monster in 2019 and focus more on enhancing the gameplay experience.</p>
<p><a href="https://play.google.com/store/apps/details?id=com.helldoradoteam.ardoom&amp;hl=en_US">Download v1.3 now!</a></p>
]]></content:encoded></item><item><title>John Romero's Level Design Tips</title><link>https://www.helldoradoteam.com/2018/12/19/john-romeros-level-design-tips/</link><pubDate>Wed, 19 Dec 2018 09:14:55 -0500</pubDate><dc:creator>Tiogus</dc:creator><guid>https://www.helldoradoteam.com/2018/12/19/john-romeros-level-design-tips/</guid><category>Level Design</category><description>Recently I’ve been doing some research on what makes a Doom level great from a gameplay standpoint. I wanted to go back to the Vanilla days and understand how the founding fathers of Doom level design did it.</description><content:encoded><![CDATA[<p>Recently I&rsquo;ve been doing some research on what makes a Doom level great from a gameplay standpoint. I wanted to go back to the Vanilla days and understand how the founding fathers of Doom level design did it.</p>
<p>Having played Ultimate Doom recently, I was captivated by the simplicity and seamless flow of E1&rsquo;s techbase levels. Romero&rsquo;s <a href="https://doomwiki.org/wiki/Knee-Deep_in_the_Dead">Knee-Deep in the Dead</a> levels breathe layout, something not found for the most part in Sandy Petersen&rsquo;s E2 levels, though they get better (<a href="https://doomwiki.org/wiki/E2M6:_Halls_of_the_Damned_(Doom)">E2M6: Halls of the Damned</a> is a classic) as the player progresses through The Ultimate Doom&rsquo;s <a href="https://doomwiki.org/wiki/The_Shores_of_Hell">The Shores of Hell.</a></p>
<p>Below is a compilation of Romero&rsquo;s level design tips, including some insights from his &ldquo;Devs Play&rdquo; playthrough of <a href="https://doomwiki.org/wiki/E1M1:_Hangar_(Doom)">E1M1: Hangar</a>.</p>
<p><strong>Level Design Tips</strong></p>
<blockquote>
<p><strong>Always change floor height when changing floor textures</strong></p>
</blockquote>
<p>Nobody likes the basic square rooms with homogeneous ceiling heights. Varying floor and ceiling heights for different rooms are more pleasing to the eye.</p>
<figure><img src="https://www.helldoradoteam.com/images/external/6c91eca3-tumblr_inline_nrajgy8zMI1ty1nlq_500.png"
			alt="E1M1: The small courtyard with blue floor texturing, lowered floor and raised ceiling"><figcaption>
			<p>E1M1: The small courtyard with blue floor texturing, lowered floor and raised ceiling</p>
		</figcaption>
</figure>

<blockquote>
<p><strong>Use special border textures between different wall segments and doorways</strong></p>
</blockquote>
<p>This is extremely important and distinguishes amateurish levels from high quality maps. Texturing shouldn&rsquo;t be treated as applying wallpaper to floors, ceilings and walls, but rather as placing different materials on a scene (rock, stone, metal, wood, etc).</p>
<figure><img src="https://www.helldoradoteam.com/wp-content/uploads/2018/12/image-1.png"
			alt="E1M2 (Nuclear Plant): A metal textured beam separates 2 walls with different wall textures. Without a transition texture the wall transition doesn&rsquo;t look smooth. John Romero is pretty consistent with this motif throughout his levels"><figcaption>
			<p>E1M2 (Nuclear Plant): A metal textured beam separates 2 walls with different wall textures. Without a transition texture the wall transition doesn&rsquo;t look smooth. John Romero is pretty consistent with this motif throughout his levels</p>
		</figcaption>
</figure>

<blockquote>
<p><strong>Be strict about texture alignment</strong></p>
</blockquote>
<p>All mappers should be obsessive about texture alignment, except in certain situations, for example - misaligned textures on a wall that leads the player toward a secret area.</p>
<blockquote>
<p><strong>Use contrast everywhere in a level between light and dark areas, cramped and open areas</strong></p>
</blockquote>
<p>Contrast also applies to sectors with different floor and ceiling heights.</p>
<blockquote>
<p><strong>Make sure that if a player could see outside that they should be able to somehow get there</strong></p>
</blockquote>
<figure><img src="https://www.helldoradoteam.com/images/external/7b904d3c-tumblr_inline_nrajicdsdc1ty1nlq_500.png"
			alt="E1M1: Overlooking the Blue Armor from the small courtyard. This outdoor area is accessible via a secret entrance"><figcaption>
			<p>E1M1: Overlooking the Blue Armor from the small courtyard. This outdoor area is accessible via a secret entrance</p>
		</figcaption>
</figure>

<blockquote>
<p><strong>Be strict about designing several secret areas on every level</strong></p>
</blockquote>
<p>If you build a map without at least one secret area, is it even a level?</p>
<blockquote>
<p><strong>Make the level flow so the player will revisit areas several times so they will better understand the 3D space of the level</strong></p>
</blockquote>
<blockquote>
<p><strong>Create easily recognizable landmarks in several places for easier navigation</strong></p>
</blockquote>
<blockquote>
<p><strong>Golden rule of level design - the &ldquo;Horseshoe&rdquo; layout</strong></p>
</blockquote>
<p>Romero mentions adopting a non-linear level design paradigm. The rule is simple, according to the Gamasutra <a href="http://www.gamasutra.com/blogs/HamishTodd/20150217/236516/Level_design_Dooms_quothorseshoequot.php">article</a> - <em>make sure the player is likely to look at every wall of a room.</em> This wouldn&rsquo;t have been possible had the level presented the player with a linear path. This pattern is common in every first level of Doom, Hexen and Quake as well.</p>
<figure><img src="https://www.helldoradoteam.com/images/external/8e8ccf0f-Doom-2-.png"
			alt="Horseshoe pattern in the beginning of E1M1: Hangar. The player is forced to explore 75% of the room"><figcaption>
			<p>Horseshoe pattern in the beginning of E1M1: Hangar. The player is forced to explore 75% of the room</p>
		</figcaption>
</figure>

<p>Valve Software also produced some similar thought-leadership in this area documented in their developer portal as the <a href="https://developer.valvesoftware.com/wiki/Loops_(level_design)">Loop</a> layout element. In this layout, the &ldquo;Loop&rdquo; guides the player back to a previously explored area of the level, and while maintaining strict linearity, provides the illusion of non-linearity and progression.</p>
<figure><img src="https://www.helldoradoteam.com/images/external/262d798d-Loop_diagram.png"
			alt="A symbolic diagram of a loop - it begins and ends in the same room."><figcaption>
			<p>The Loop element</p>
		</figcaption>
</figure>

<blockquote>
<p><strong>Build your first level last</strong></p>
</blockquote>
<p>Romero started E1M1 early in the development of Doom, but was the last level that he completed. In this way he was able to use his learnings from the design of all other Doom levels and apply them to the first. In this progression, the first couple of levels are the weaker ones (sans the first), middle ones get better, and culminating with the stronger levels.</p>
<blockquote>
<p><strong>Don&rsquo;t constrain player movement (aka don&rsquo;t let detailing get in the way of gameplay)</strong></p>
</blockquote>
<p>Tom Hall wanted to detail E1M1 with movable chairs, but the chairs ended up interfering with smooth player movement. When mapping, consider the trade-off between focusing on detailing versus pure gameplay mechanics. The former can be sacrificed for the sake of gameplay.</p>
<blockquote>
<p><strong>Use fullbright textures</strong></p>
</blockquote>
<p>Use fullbright textures when appropriate. Fullbright textures ignore the surrounding light in a scene and render at full brightness to create the appearance of emitting their own light.</p>
<figure><img src="https://www.helldoradoteam.com/wp-content/uploads/2018/12/image.png"
			alt="The light source on the left is rendered with a fullbright texture and provides the illusion of self-illumination. In a dark room, light sources can orient the player"><figcaption>
			<p>The light source on the left is rendered with a fullbright texture and provides the illusion of self-illumination. In a dark room, light sources can orient the player</p>
		</figcaption>
</figure>

<p>If you want to see out Romero&rsquo;s playthrough of E1M1, where he offers his insightful level design tips, check out the video below:</p>
<div class="yt" data-id="rV6HlBa88js" data-title="John Romero&#39;s Level Design Tips" style="background-image:url(https://i.ytimg.com/vi/rV6HlBa88js/hqdefault.jpg)">
  <button type="button" aria-label="Play video: John Romero&#39;s Level Design Tips"></button>
</div>


]]></content:encoded></item><item><title>Cacowards 2018 Announced!</title><link>https://www.helldoradoteam.com/2018/12/17/cacowards-2018-announced/</link><pubDate>Mon, 17 Dec 2018 13:49:50 -0500</pubDate><dc:creator>Tiogus</dc:creator><guid>https://www.helldoradoteam.com/2018/12/17/cacowards-2018-announced/</guid><category>Doom</category><description>Doomworld’s 2018 Cacowards recently came out and with it a series of amazing articles from Doomworld. You can check them out below 2018 Cacowards: The quintessential Cacowards, celebrating 25 years of Doom. Also included is an amazing write-up on Erik Alm’s legacy as a mapper and how his enduring vision influenced other legendary projects. Top 100 Most Memorable Maps: Curated list of the top 100 Doom maps produced by the Doom community. Either as single-map contributions or cherry-picked maps from multi-level WADs. Top 25 Missed Cacowards: Projects that didn’t win a Cacoward but who looking back, should have been awarded one.</description><content:encoded><![CDATA[<figure><img src="https://www.helldoradoteam.com/images/external/bad02c86-1184530823_3_cacowardslogo.jpg"
			alt="Cacowards 2018">
</figure>

<p>Doomworld&rsquo;s 2018 Cacowards recently came out and with it a series of amazing articles from Doomworld. You can check them out below</p>
<ol>
<li><a href="https://www.doomworld.com/cacowards/2018/index/">2018 Cacowards</a>: The quintessential Cacowards, celebrating 25 years of Doom. Also included is an amazing write-up on Erik Alm&rsquo;s legacy as a mapper and how his enduring vision influenced other legendary projects.</li>
<li><a href="https://www.doomworld.com/25years/top-100-memorable-maps/">Top 100 Most Memorable Maps</a>: Curated list of the top 100 Doom maps produced by the Doom community. Either as single-map contributions or cherry-picked maps from multi-level WADs.</li>
<li><a href="https://www.doomworld.com/25years/top-25-missed-cacowards/">Top 25 Missed Cacowards</a>: Projects that didn&rsquo;t win a Cacoward but who looking back, should have been awarded one.</li>
</ol>
]]></content:encoded></item><item><title>Auferstehung 2 (Doom WAD) Released!</title><link>https://www.helldoradoteam.com/2018/11/22/auferstehung-2-doom-wad-released/</link><pubDate>Thu, 22 Nov 2018 11:29:09 -0500</pubDate><dc:creator>Tiogus</dc:creator><guid>https://www.helldoradoteam.com/2018/11/22/auferstehung-2-doom-wad-released/</guid><category>Doom</category><category>Game Development</category><description>It’s been 12 years since Helldorado Team (formerly Brain Dead Studios, formerly Elioncho’s Engine team, formerly the Condor Team) announced the development of a Doom WAD - the never released Confessions from the Flesh. But today, after more than 10 years of projects sinking down the drain, prototypes never seeing the light of day, and other tech demos lost to numerous formatted hard drives, we can finally announce the release of our first 11-level Doom WAD (wow, it only took a decade): Auferstehung 2.</description><content:encoded><![CDATA[<p><img src="https://www.helldoradoteam.com/wp-content/uploads/2018/11/logo.png" alt="" loading="lazy" decoding="async"></p>
<p>It&rsquo;s been 12 years since Helldorado Team (formerly Brain Dead Studios, formerly Elioncho&rsquo;s Engine team, formerly the Condor Team) announced the development of a Doom WAD - the never released <a href="http://brain-dead-studios.blogspot.com/2006/05/confessions-from-flesh-announced.html">Confessions from the Flesh</a>. But today, after more than 10 years of projects sinking down the drain, prototypes never seeing the light of day, and other tech demos lost to numerous formatted hard drives, we can finally announce the release of our first 11-level Doom WAD (wow, it only took a decade): Auferstehung 2.</p>
<p>Auferstehung 2 is the unofficial sequel and homage to Nazi Auferstehung, named the <a href="https://www.doomworld.com/13years/others.php">Worst WAD of 2006 by Doomworld</a>.</p>
<p>And now, from the depths of the Doom community a similar turd emerges, albeit not as worse, but still pretty bad. Following the footsteps of the predecessor&rsquo;s creator (who used <a href="https://www.doomworld.com/slige/">Slige</a>), Helldorado Team leveraged <a href="http://oblige.sourceforge.net/">Oblige</a> to produce the 11 procedurally generated levels of Auferstehung 2.</p>
<h2 id="download-auferstehung-2"><a href="https://www.helldoradoteam.com/wp-content/uploads/2018/11/auferstehung2.zip">Download Auferstehung 2!</a></h2>
<p>Levels:</p>
<p>MAP01: Enter the Dominion<br>
MAP02: The Prison of Despair<br>
MAP03: Horrendous Temple<br>
MAP04: Blood Shrine of the Beast<br>
MAP05: The Nukage Shaft<br>
MAP06: Thermal Terminal<br>
MAP07: Pain from the Base<br>
MAP08: Lockdown<br>
MAP09: The Crossroads of Menace<br>
MAP10: Arson Anthem<br>
MAP11: Palace of Danger</p>
<p>Special thanks to:</p>
<ul>
<li>Andrew Apted for creating Oblige and making this project possible</li>
<li>Dark Exodus for Nazi Auferstehung</li>
<li>id Software for Doom 2</li>
<li>Elioncho for emotional support</li>
</ul>
<p>Tools used:</p>
<ul>
<li><a href="https://devbuilds.drdteam.org/gzdbbf/">GZDoom Builder</a></li>
<li><a href="http://slade.mancubus.net/">Slade 3</a></li>
<li><a href="https://zdoom.org/downloads">GZDoom</a> (for playtesting)</li>
</ul>
<p>How to play:</p>
<ol>
<li>Drag and drop auferstehung2.wad into the .exe of your favorite Doom Source Port (for example GZDoom, Zandronum, etc). Boom-compatible port recommended.</li>
<li>Make sure Doom2.wad is in the same folder as the Source Port&rsquo;s .exe file</li>
</ol>
]]></content:encoded></item><item><title>ARThings v1.2 Released</title><link>https://www.helldoradoteam.com/2018/10/11/arthings-v1-2-released/</link><pubDate>Thu, 11 Oct 2018 13:43:50 -0500</pubDate><dc:creator>Tiogus</dc:creator><guid>https://www.helldoradoteam.com/2018/10/11/arthings-v1-2-released/</guid><category>Doom</category><category>Game Development</category><description>We made some tweaks over the past couple of weeks and finally ARThings v1.2 is out. Click on the cool Doomguy below to check it out:</description><content:encoded><![CDATA[<p><a href="https://play.google.com/store/apps/details?id=com.helldoradoteam.ardoom"><img src="https://www.helldoradoteam.com/wp-content/uploads/2018/10/arthingslogo.png" alt="" loading="lazy" decoding="async"></a></p>
<p>We made some tweaks over the past couple of weeks and finally <strong>ARThings v1.2</strong> is out. Click on the cool Doomguy below to check it out:</p>
<p><a href="https://play.google.com/store/apps/details?id=com.helldoradoteam.ardoom"><img src="https://www.helldoradoteam.com/wp-content/uploads/2018/10/ardoom-icon.png" alt="" loading="lazy" decoding="async"></a></p>
<p>Here&rsquo;s a laundry list of the updates we made:</p>
<ol>
<li>Updated HUD graphics - Updated fire button graphics and added a new &ldquo;switch weapon&rdquo; button</li>
<li>Removed the ability to spawn monsters by tapping on planes. This was an experimental feature pre-v1.2 that has now been removed</li>
<li>Removed the tracking of vertical planes such as walls. This was not needed as monsters spawn on top of upward facing horizontal planes (such as floors).</li>
<li>You can now pick up and use the Chaingun</li>
<li>Updated spawner to spawn Shotgun and Chaingun ammo when you&rsquo;re low on ammo</li>
<li>Updated spawner to spawn 3 different types of monsters: 1) Zombiemen, 2) Chaingunners and 3) Demons</li>
<li>Dead Zombiemen drop clips when dead</li>
<li>Dead Chaingunners drop Chainguns when dead</li>
<li>Added other effects such as blood and teleport fog when spawning monsters</li>
<li>Other bug fixes</li>
</ol>
<p>Also, here&rsquo;s a video of some &ldquo;in-game&rdquo; action from v1.2:</p>
<div class="yt" data-id="6-A4ywmokjY" data-title="ARThings v1.2 Released" style="background-image:url(https://i.ytimg.com/vi/6-A4ywmokjY/hqdefault.jpg)">
  <button type="button" aria-label="Play video: ARThings v1.2 Released"></button>
</div>


]]></content:encoded></item><item><title>Doom AI Game Logic Explained, kinda</title><link>https://www.helldoradoteam.com/2018/09/26/doom-ai-game-logic-explained-kinda/</link><pubDate>Wed, 26 Sep 2018 18:11:27 -0500</pubDate><dc:creator>Tiogus</dc:creator><guid>https://www.helldoradoteam.com/2018/09/26/doom-ai-game-logic-explained-kinda/</guid><category>Doom</category><category>Game Development</category><description>A couple of weeks ago we released ARThings, please check it out when you get a chance. Like we mentioned previously this project began as an academic exercise to build something more interactive with ARCore, but to bring this Doom experience to ARCore we had to invest time to learn the inner workings of Doom’s AI/Game Logic system. Below is some light commentary on this experience, including some insights and lessons learned.</description><content:encoded><![CDATA[<p>A couple of weeks ago we released <a href="https://play.google.com/store/apps/details?id=com.helldoradoteam.ardoom">ARThings</a>, please check it out when you get a chance. Like we mentioned previously this project began as an academic exercise to build something more interactive with ARCore, but to bring this Doom experience to ARCore we had to invest time to learn the inner workings of Doom&rsquo;s AI/Game Logic system. Below is some light commentary on this experience, including some insights and lessons learned.</p>
<h3 id="picking-a-doom-source-port"><strong>Picking a Doom Source Port</strong></h3>
<p>To port the Doom AI game logic we had to pick a Doom source port. We narrowed down the list to 2 contenders:</p>
<ul>
<li><a href="https://github.com/id-Software/DOOM">Linux Doom</a></li>
<li><a href="https://zdoom.org/downloads">ZDoom</a></li>
</ul>
<p>There&rsquo;s pros and cons with each of these but ultimately we settled with Linux Doom. By doing so we could deal with less complexity. The ZDoom codebase is much more modernized but quite extensive - it not only runs Doom but also Heretic, Hexen, Strife and other &ldquo;Doom clones&rdquo;. Learning ZDoom meant going through a much more extensive and technically sophisticated codebase. ZDoom&rsquo;s AI and gameplay code architecture was revamped to include <a href="https://zdoom.org/wiki/ACS">ACS</a>, a flexible scripting system that developers could use to extend gameplay and AI behavior without having to write additional code to be compiled with the master codebase.</p>
<p>Having settled with Linux Doom, we unzipped the codebase and immediately faced with an even bigger challenge - working with legacy code. Doom was written in the early 90s, and as such the code was meant to push the limits of the hardware of that era (i386, i486, etc). If you get some time, I recommend reading Fabien Sanglard&rsquo;s <a href="https://www.amazon.com/Game-Engine-Black-Book-Wolfenstein/dp/1539692876">Game Engine Black Book</a>, he does an amazing job describing the technical limitations id Software&rsquo;s faced when developing Wolfenstein 3D. These limitations drove the technical direction of both the Wolfenstein 3D and Doom codebase.</p>
<p>So we went deep into the Doom source code. After studying the source code for a couple of days we encountered these technical pain points:</p>
<ol>
<li><strong>Reading C</strong> - Doom&rsquo;s code is not Object Oriented. Functions are grouped into source files based on functionality. The code can be hard to come to terms with if you&rsquo;ve been writing OO code for a while.</li>
<li><strong>Absence of Floating Point arithmetic</strong> - To cope with CPU&rsquo;s lack of floating point arithmetic during the mid-90s Doom uses <a href="https://doomwiki.org/wiki/Fixed_point">Fixed point arithmetic</a>. The gist of this is that floating points are represented using 32-bit integers. 16 bits for the integer portion and the remaining 16 for the fractional part.</li>
<li><strong>Angles are represented using <a href="https://doomwiki.org/wiki/Angle">Binary Angle Measurement (BAM)</a></strong> - This is new territory if you&rsquo;re used to storing angles as doubles (or floats) when working with computer graphics or trigonometric calculations. in BAM, angles are represented using the full range of values of a 32-bit unsigned int. The challenge with this is that some languages do not support unsigned int as a primitive data type (Java for instance). You have to provide your own wrapper functions when performing computations that result on unsigned integers. Another challenge with BAM is that to perform trigonometric calculations you have to provide your own special purpose sin/cos/tan lookup tables.</li>
<li><strong>Usage of C function pointers</strong> - These are used heavily in the code, sometimes to mimic Polymorphism. C function pointer code can be hard to port with the right architectural approach, especially if the language you are porting to implements similar functionality using a different programming paradigm. Again, using the Java example you can accomplish this using Lambda expressions and <a href="https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html">Method References</a>.</li>
</ol>
<h3 id="the-basics---understanding-mobjs-and-states"><strong>The Basics - Understanding Mobjs and States</strong></h3>
<p>Let&rsquo;s now get to the basics. To understand how the Doom AI works we need to understand how objects, or <a href="https://doomwiki.org/wiki/Thing">Things</a> (<a href="https://doomwiki.org/wiki/Mobj">mobjs</a>), are represented in the codebase. Things are monsters, items, pickups, fireballs, projectiles, or anything that is represented by a sprite in the game. For example, when you shoot a monster and you see a blood effect rendered as a sprite, the blood effect is a mobj.</p>
<p>Things are represented by the <strong>mobj_t</strong> struct defined in <a href="https://github.com/id-Software/DOOM/blob/master/linuxdoom-1.10/p_mobj.h">p_mobj.h</a>. mobjs and have attributes such as (x,y,z) position, (x,y,z) momentum (used to simulate physics) and many other object properties.</p>
<blockquote>
<p><strong>Side note</strong>: The Doom coordinate system treats Z as the vertical &ldquo;up&rdquo; axis, as opposed to the Y axis. If you are coming from the OpenGL world this might be hard to stomach.</p>
</blockquote>
<p>For the purposes of AI, a mobj (I&rsquo;ll be using mobj and Thing interchangeably) functions as a <a href="https://en.wikipedia.org/wiki/Finite-state_machine">finite state machine</a>. Through its lifespan a mobj will cycle through various states as determined by the core engine AI logic. A mobj&rsquo;s current state is kept as a reference to a <a href="https://doomwiki.org/wiki/State">State</a> object:</p>
<pre tabindex="0"><code>state_t* state;
</code></pre><p>The declaration of <strong>state_t</strong> is defined in <a href="https://github.com/id-Software/DOOM/blob/master/linuxdoom-1.10/info.h">info.h</a> and all state definitions in the game are stored as a global array:</p>
<pre tabindex="0"><code>typedef struct
{
  spritenum_t	sprite;
  long		frame;
  long		tics;
  // void	(*action) ();
  actionf_t	action;
  statenum_t	nextstate;
  long	        misc1, misc2;
} state_t;

extern state_t	states[NUMSTATES];
</code></pre><p>The state object has the following attributes and characteristics:</p>
<ul>
<li><strong>sprite</strong> - Sprite to use to render the mobj for this state</li>
<li><strong>frame</strong> - Animation frame to use for this state</li>
<li><strong>tics</strong> - How many tics to run this state for (We will explain the concept of tics in the next section)</li>
<li><strong>action</strong> - Pointer to the function to run when transitioning to this state</li>
<li><strong>nextstate</strong> - State to transition to when this state is over</li>
<li><strong>misc1</strong> - Miscellaneous attribute</li>
<li><strong>misc2</strong> - Miscellaneous attribute</li>
</ul>
<p>The list of all state numbers for all the different types of mobjs in the game are defined in the <strong>statenum_t</strong> enum in info.h.</p>
<p>To decide what states correspond to each mobj type there&rsquo;s a structure called <strong>mobjinfo_t</strong> in info.h that contains this information. The engine stores this as a global array as well:</p>
<pre tabindex="0"><code>typedef struct
{
    int	doomednum;
    int	spawnstate;
    int	spawnhealth;
    int	seestate;
    int	seesound;
    int	reactiontime;
    int	attacksound;
    int	painstate;
    int	painchance;
    int	painsound;
    int	meleestate;
    int	missilestate;
    int	deathstate;
    int	xdeathstate;
    int	deathsound;
    int	speed;
    int	radius;
    int	height;
    int	mass;
    int	damage;
    int	activesound;
    int	flags;
    int	raisestate;
} mobjinfo_t;

extern mobjinfo_t mobjinfo[NUMMOBJTYPES];
</code></pre><p>Let&rsquo;s provide an example with one of the Doom monsters, the <a href="https://doomwiki.org/wiki/Zombieman">Zombieman.</a></p>
<p>Here&rsquo;s how the Zombieman&rsquo;s mobjinfo is defined in the info.c file. Note that the Zombieman&rsquo;s mobj type is MT_POSSESSED:</p>
<pre tabindex="0"><code>mobjinfo_t mobjinfo[NUMMOBJTYPES] = {
   .
   .
   .
   {
	// MT_POSSESSED
	3004,		// doomednum
	S_POSS_STND,	// spawnstate
	20,		// spawnhealth
	S_POSS_RUN1,	// seestate
	sfx_posit1,	// seesound
	8,		// reactiontime
	sfx_pistol,	// attacksound
	S_POSS_PAIN,	// painstate
	200,		// painchance
	sfx_popain,	// painsound
	0,		// meleestate
	S_POSS_ATK1,	// missilestate
	S_POSS_DIE1,	// deathstate
	S_POSS_XDIE1,	// xdeathstate
	sfx_podth1,	// deathsound
	8,		// speed
	20*FRACUNIT,	// radius
	56*FRACUNIT,	// height
	100,		// mass
	0,		// damage
	sfx_posact,	// activesound
	MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
	S_POSS_RAISE1	// raisestate
   },
   .
   .
   .
};
</code></pre><p>The attributes in the mobjinfo object define the states to transition to and the sound effects to play for a particular mobj type when entering the following core mobj states handled by the engine:</p>
<ul>
<li><strong>Spawn State</strong> - state to transition to when the mobj is spawned in the game. This is the &ldquo;idle&rdquo; state where the monster just stands and does nothing, checking its field of view until it spots a player to chase and attack.</li>
<li><strong>See State</strong> - state to transition to when the mobj spots an enemy (in this case the player) and should chase it. Inside the code this is sometimes referred to as the &ldquo;Chase&rdquo; state.</li>
<li><strong>Pain State</strong> - state to transition to when the mobj takes damage</li>
<li><strong>Melee State</strong> - state to transition to when the mobj is ready to perform a close range melee attack. Only applies to mobjs that perform melee attacks. For the Zombieman, notice that the meleestate attribute is &ldquo;0&rdquo;, which corresponds to the NULL state, since the Zombieman doesn&rsquo;t have a melee attack.</li>
<li><strong>Missile State</strong> - state to transition to when the mobj is ready to perform a ranged attack. Only applies to mobjs that perform ranged attacks such as a Zombieman firing his rifle or a Cacodemon belching a fireball.</li>
<li><strong>Death State</strong> - state to transition to when the mobj is killed</li>
<li><strong>XDeath State</strong> - state to transition to when the mobj is killed via explosion (gibbed)</li>
</ul>
<p>Now let&rsquo;s look at the complete list of Zombieman state definitions as defined in info.c:</p>
<pre tabindex="0"><code>state_t	states[NUMSTATES] = {   
    .
    .
    . 
    {SPR_POSS,0,10,{A_Look},S_POSS_STND2,0,0},	// S_POSS_STND
    {SPR_POSS,1,10,{A_Look},S_POSS_STND,0,0},	// S_POSS_STND2
    {SPR_POSS,0,4,{A_Chase},S_POSS_RUN2,0,0},	// S_POSS_RUN1
    {SPR_POSS,0,4,{A_Chase},S_POSS_RUN3,0,0},	// S_POSS_RUN2
    {SPR_POSS,1,4,{A_Chase},S_POSS_RUN4,0,0},	// S_POSS_RUN3
    {SPR_POSS,1,4,{A_Chase},S_POSS_RUN5,0,0},	// S_POSS_RUN4
    {SPR_POSS,2,4,{A_Chase},S_POSS_RUN6,0,0},	// S_POSS_RUN5
    {SPR_POSS,2,4,{A_Chase},S_POSS_RUN7,0,0},	// S_POSS_RUN6
    {SPR_POSS,3,4,{A_Chase},S_POSS_RUN8,0,0},	// S_POSS_RUN7
    {SPR_POSS,3,4,{A_Chase},S_POSS_RUN1,0,0},	// S_POSS_RUN8
    {SPR_POSS,4,10,{A_FaceTarget},S_POSS_ATK2,0,0},	// S_POSS_ATK1
    {SPR_POSS,5,8,{A_PosAttack},S_POSS_ATK3,0,0},	// S_POSS_ATK2
    {SPR_POSS,4,8,{NULL},S_POSS_RUN1,0,0},	// S_POSS_ATK3
    {SPR_POSS,6,3,{NULL},S_POSS_PAIN2,0,0},	// S_POSS_PAIN
    {SPR_POSS,6,3,{A_Pain},S_POSS_RUN1,0,0},	// S_POSS_PAIN2
    {SPR_POSS,7,5,{NULL},S_POSS_DIE2,0,0},	// S_POSS_DIE1
    {SPR_POSS,8,5,{A_Scream},S_POSS_DIE3,0,0},	// S_POSS_DIE2
    {SPR_POSS,9,5,{A_Fall},S_POSS_DIE4,0,0},	// S_POSS_DIE3
    {SPR_POSS,10,5,{NULL},S_POSS_DIE5,0,0},	// S_POSS_DIE4
    {SPR_POSS,11,-1,{NULL},S_NULL,0,0},	// S_POSS_DIE5
    {SPR_POSS,12,5,{NULL},S_POSS_XDIE2,0,0},	// S_POSS_XDIE1
    {SPR_POSS,13,5,{A_XScream},S_POSS_XDIE3,0,0},	// S_POSS_XDIE2
    {SPR_POSS,14,5,{A_Fall},S_POSS_XDIE4,0,0},	// S_POSS_XDIE3
    {SPR_POSS,15,5,{NULL},S_POSS_XDIE5,0,0},	// S_POSS_XDIE4
    {SPR_POSS,16,5,{NULL},S_POSS_XDIE6,0,0},	// S_POSS_XDIE5
    {SPR_POSS,17,5,{NULL},S_POSS_XDIE7,0,0},	// S_POSS_XDIE6
    {SPR_POSS,18,5,{NULL},S_POSS_XDIE8,0,0},	// S_POSS_XDIE7
    {SPR_POSS,19,5,{NULL},S_POSS_XDIE9,0,0},	// S_POSS_XDIE8
    {SPR_POSS,20,-1,{NULL},S_NULL,0,0},	// S_POSS_XDIE9
    {SPR_POSS,10,5,{NULL},S_POSS_RAISE2,0,0},	// S_POSS_RAISE1
    {SPR_POSS,9,5,{NULL},S_POSS_RAISE3,0,0},	// S_POSS_RAISE2
    {SPR_POSS,8,5,{NULL},S_POSS_RAISE4,0,0},	// S_POSS_RAISE3
    {SPR_POSS,7,5,{NULL},S_POSS_RUN1,0,0},	// S_POSS_RAISE4
    .
    .
    .
};
</code></pre><p>Before diving deeper into these states, let&rsquo;s go back and cover the tics concept that I mentioned briefly.</p>
<h3 id="gametics-and-thinkers"><strong>Gametics and Thinkers</strong></h3>
<p>Doom doesn&rsquo;t manage the concept of game updates in terms of milliseconds since the last game update. A <a href="https://doomwiki.org/wiki/Tic">gametic</a> is the equivalent of a single game update - basically one iteration of the Doom game loop. During this iteration the engine performs one frame update and executes basic game loop activities such as capturing input, executing gameplay logic and rendering to the framebuffer.</p>
<p>Doom&rsquo;s engine is clamped at 35 tics per second (35 iterations of the Doom game loop every second), so a single tic should take no longer than 1000/35 = <strong>28.57</strong> milliseconds. This is the behavior of Vanilla Doom, however some source ports have removed this technical restriction and allow <a href="https://doomwiki.org/wiki/Uncapped_framerate">uncapped framerates</a>.</p>
<p>To understand the game loop, lets look at some code. The Doom main game loop makes a call to the G_Ticker() function in <a href="https://github.com/id-Software/DOOM/blob/master/linuxdoom-1.10/g_game.c">g_game.c</a>. A call to P_Ticker() (defined in <a href="https://github.com/id-Software/DOOM/blob/master/linuxdoom-1.10/p_tick.c">p_tick.c</a>) is made as long as the game is running a level (gamestate=GS_LEVEL):</p>
<pre tabindex="0"><code>//
// G_Ticker
// Make ticcmd_ts for the players.
//
void G_Ticker (void) 
{    
    .
    .
    .
    // do main actions
    switch (gamestate) 
    { 
      case GS_LEVEL: 
	P_Ticker (); 
	ST_Ticker (); 
	AM_Ticker (); 
	HU_Ticker ();            
	break; 

      case GS_INTERMISSION: 
	WI_Ticker (); 
	break; 

      case GS_FINALE: 
	F_Ticker (); 
	break; 

      case GS_DEMOSCREEN: 
	D_PageTicker (); 
	break; 
    }
}
</code></pre><p>P_Ticker() handles game updates for the following:</p>
<ul>
<li>All Players in the game (via a call to P_PlayerThink)</li>
<li>Mobjs (via call to P_RunThinkers)</li>
<li>Other things that we don&rsquo;t care about right now</li>
</ul>
<pre tabindex="0"><code>//
// P_Ticker
//

void P_Ticker (void)
{
  .
  .
  .
  for (i=0 ; i&lt;MAXPLAYERS ; i++)
	  if (playeringame[i])
	      P_PlayerThink (&amp;players[i]);

  P_RunThinkers ();
  P_UpdateSpecials ();
  P_RespawnSpecials ();
  .
  .
  .
}
</code></pre><p>Let&rsquo;s digest all of this for a moment. You might think that to run game updates for all mobjs in the game you would just call an update() method passing the mobj as a parameter and do this for every single mobj in the game.</p>
<p>Doom handles game updates for mobjs a bit differently. Every mobj in the game has a <a href="https://doomwiki.org/wiki/Thinker">Thinker</a> object that manages the execution of game updates per frame for that specific mobj. The structure of a Thinker object looks like this (declared in <a href="https://github.com/id-Software/DOOM/blob/master/linuxdoom-1.10/d_think.h">d_think.h</a>):</p>
<pre tabindex="0"><code>// Doubly linked list of actors.
typedef struct thinker_s
{
    struct thinker_s*	prev;
    struct thinker_s*	next;
    think_t		function;

} thinker_t;
</code></pre><p>As mobjs spawn in a level, their Thinkers are created and added to a doubly linked list (hence the prev and next pointers). This happens in the P_SpawnMobj() function (in p_mobj.c):</p>
<pre tabindex="0"><code>//
// P_SpawnMobj
//
mobj_t*
P_SpawnMobj
( fixed_t	x,
  fixed_t	y,
  fixed_t	z,
  mobjtype_t	type )
{
    .
    .
    .

    mobj-&gt;thinker.function.acp1 = (actionf_p1)P_MobjThinker;	
    P_AddThinker (&amp;mobj-&gt;thinker);

    return mobj;
}
</code></pre><p>Likewise, as mobjs are removed from a level (for example a projectile mobj hits a monster and needs to be removed after the explosion), their Thinkers are removed from the doubly linked list (P_RemoveMobj function in p_mobj.c):</p>
<pre tabindex="0"><code>//
// P_RemoveMobj
//
mapthing_t	itemrespawnque[ITEMQUESIZE];
int		itemrespawntime[ITEMQUESIZE];
int		iquehead;
int		iquetail;

void P_RemoveMobj (mobj_t* mobj)
{
    .
    .
    .

    // free block
    P_RemoveThinker ((thinker_t*)mobj);
}
</code></pre><p>Every Thinker object has a reference to a function (attribute <strong>think_t function</strong>) that executes an mobj&rsquo;s game updates. This function is P_MobjThinker() in p_mobj.c:</p>
<pre tabindex="0"><code>//
// P_MobjThinker
//
void P_MobjThinker (mobj_t* mobj)
{
   // We&#39;ll go through this code later
}
</code></pre><p>P_RunThinkers() simply iterates through each mobj&rsquo;s Thinker and executes its Thinker function - <strong>P_MobjThinker()</strong>:</p>
<pre tabindex="0"><code>//
// P_RunThinkers
//
void P_RunThinkers (void)
{
    thinker_t*	currentthinker;

    currentthinker = thinkercap.next;
    while (currentthinker != &amp;thinkercap)
    {
	if ( currentthinker-&gt;function.acv == (actionf_v)(-1) )
	{
	    // time to remove it
	    currentthinker-&gt;next-&gt;prev = currentthinker-&gt;prev;
	    currentthinker-&gt;prev-&gt;next = currentthinker-&gt;next;
	    Z_Free (currentthinker);
	}
	else
	{
	    if (currentthinker-&gt;function.acp1)
		currentthinker-&gt;function.acp1 (currentthinker);
	}
	currentthinker = currentthinker-&gt;next;
    }
}
</code></pre><p>We can think of P_MobjThinker() as the function called for each game state update for each mobj. This function will take care of movement, physics simulation and cycle between AI states.</p>
<p>We can summarize the above behavior with the following pseudocode:</p>
<pre tabindex="0"><code>G_Ticker() // g_game.c
{
	switch(gamestate)
	{
		case GS_LEVEL:
			P_Ticker() // p_tick.c
			{
				P_RunThinkers() // p_tick.c
				{
					// Iterate through all thinkers in level (linked list)
					foreach(thinker in thinker linked list)
					{
						function = thinker.function;
						// Execute thinker function
						// Runs P_MobjThinker() function in p_mobj.c
						function.run();
					}
				}
			}
	}
}
</code></pre><p>In the next article we&rsquo;ll continue our deep dive into Doom AI game logic and the technical details of P_MobjThinker().</p>
<p>While you wait for the next article we recommend reading:</p>
<ul>
<li><a href="https://doomwiki.org/wiki/Monster_behavior">Doom Monster Behavior</a></li>
</ul>
]]></content:encoded></item><item><title>ARThings Released - Augmented Reality Doom</title><link>https://www.helldoradoteam.com/2018/09/18/arthings-released-augmented-reality-doom/</link><pubDate>Tue, 18 Sep 2018 09:23:37 -0500</pubDate><dc:creator>Tiogus</dc:creator><guid>https://www.helldoradoteam.com/2018/09/18/arthings-released-augmented-reality-doom/</guid><category>Doom</category><category>Game Development</category><description>We recently released a Doom experience for Android’s ARCore titled ARThings. It was originally titled ARDoom but after receiving hate mail from the Google Play admins informing me that I couldn’t use the brand name “Doom” as part of the app title, I changed the name.</description><content:encoded><![CDATA[<p>We recently released a Doom experience for Android&rsquo;s ARCore titled <a href="https://play.google.com/store/apps/details?id=com.helldoradoteam.ardoom"><strong>ARThings</strong></a>. It was originally titled ARDoom but after receiving hate mail from the Google Play admins informing me that I couldn&rsquo;t use the brand name &ldquo;Doom&rdquo; as part of the app title, I changed the name.</p>
<p>Click below to check it out!</p>
<p><a href="https://play.google.com/store/apps/details?id=com.helldoradoteam.ardoom"><img src="https://www.helldoradoteam.com/wp-content/uploads/2017/05/google-play-badge.png" alt="" loading="lazy" decoding="async"></a></p>
<p>We&rsquo;re currently on <strong>v1.1</strong> which has the following features:</p>
<ul>
<li>Click on a horizontal tracked plane to spawn either <a href="https://doomwiki.org/wiki/4_shotgun_shells">4 shotgun shells</a>, a <a href="https://doomwiki.org/wiki/Zombieman">Zombieman</a> or a <a href="https://doomwiki.org/wiki/Heavy_weapon_dude">Heavy weapon dude</a></li>
<li>Shotgun shells, Zombiemen or Heavy weapon dudes spawn randomly on detected horizontal planes</li>
<li>Blast away Zombiemen and Heavy weapon dudes with the proverbial Doom <a href="https://doomwiki.org/wiki/Shotgun">shotgun</a></li>
</ul>
<p>Some technical facts:</p>
<ul>
<li>Monster AI code is based on the <a href="https://github.com/id-Software/DOOM">Doom Linux codebase</a></li>
<li>OpenGL ES 2.0 is used for rendering</li>
</ul>
<p>Special thanks to:</p>
<ul>
<li>John Carmack for answering some questions via email related to framerate clamping in the Doom Linux codebase</li>
<li><a href="http://fabiensanglard.net/">Fabien Sanglard</a> for letting me proofread his upcoming Doom Game Engine Black Book. This was instrumental in helping me understand Doom monster AI</li>
</ul>
]]></content:encoded></item></channel></rss>