magic_chopstick [Lexaloffle Blog Feed]https://www.lexaloffle.com/bbs/?uid=94681 expint(): Counting To Eleventy-Bajillion In PICO-8 With Exponential Integers <h1>expint(): Counting To Eleventy-Bajillion In PICO-8 With Exponential Integers (v 1.01)</h1> <p> <table><tr><td> <a href="/bbs/?pid=167835#p"> <img src="/bbs/thumbs/pico8_mcg_expint_test-2.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=167835#p"> mcg_expint_test</a><br><br> by <a href="/bbs/?uid=94681"> magic_chopstick</a> <br><br><br> <a href="/bbs/?pid=167835#p"> [Click to Play]</a> </td></tr></table> </p> <h2>Overview</h2> <p>Hello, everyone! I'm back with another Quick 'n' Dirty code snippet: extreme range, low precision Exponential Integers!</p> <p><code>expint()</code> lets you easily work with <strong>extremely large numbers</strong> at low precision in PICO-8. You can create them, add to them, &quot;spend&quot; from them, display them in a friendly format, and save/load them using a single 32-bit data slot.</p> <p><code>expint()</code> is particularly well-suited to games where you need to track very large amounts of points or money, like <strong>incremental games/idle clickers</strong>, large-scale <strong>exploration games</strong>, and other places where 32k just isn't gonna cut it.</p> <h3>Update: Version 1.01</h3> <ul> <li>Fixed weirdness with the <code>print()</code> function</li> <li>Shaved a few tokens off, to boot</li> </ul> <h2>The Snippet And Its Use</h2> <h3>Install</h3> <p>Paste the following snippet into your cart:</p> <p><div><div><input type="button" value=" Show " onClick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = ''; this.innerText = ''; this.value = ' Hide '; } else { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none'; this.innerText = ''; this.value = ' Show '; }"></div><div><div style="display: none;"></p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>function expint(new_sig, new_exp) local num = {} function num._step_up(steps) while steps &gt; 0 do num.sig \= 10 num.exp += 1 steps -= 1 if num.sig == 0 then -- we've lost all precision; for whatever we're doing, this number is as good as zero num.exp += steps steps = 0 end end end function num._norm() while num.sig &gt;= 10000 do num._step_up(1) end while num.sig &lt; 1000 and num.exp &gt; 0 do num.sig *= 10 num.exp -= 1 end end function num.add(val, sig) local to_add = expint(val, sig) -- be non-destructive with arithmetic; copy info into another expint to protect precision to_add._step_up(num.exp-to_add.exp) -- instead of doing any logic, just run step_up num._step_up(to_add.exp-num.exp) -- on both the numbers. It'll only affect one of them. num.sig += to_add.sig num._norm() end function num.spend(val, sig) -- if val &lt; num, subtracts val from num and returns true -- otherwise, returns false local to_spend = expint(val, sig) if to_spend.exp &gt; num.exp or to_spend.exp == num.exp and num.sig &lt; to_spend.sig then return false -- to_spend is greater than num; can't make the spend end to_spend._step_up(num.exp-to_spend.exp) -- instead of doing any logic, just run step_up num._step_up(to_spend.exp-num.exp) -- on both the numbers. It'll only affect one of them. num.sig -= to_spend.sig num._norm() return true end function num.print() -- local suffixes = split(&quot;K,m,g,T,P,E,Z,Y,R,Q&quot;) -- SI suffixes local suffixes = split(&quot;K,m,b,t,qU,qI,sX,sP,oC,nO,dE&quot;) -- number suffixes local return_string = num.sig if num.sig &gt; 1000 then local modval = num.exp%3+1 local suffix = num.exp\3+1 if suffix &gt; #suffixes then return_string = sub(return_string,1,1)..&quot;.&quot;..sub(return_string, 2)..&quot;X10^&quot;..(num.exp+3) else return_string = sub(return_string, 1, modval)..&quot;.&quot;..sub(return_string, modval+1)..suffixes[suffix] end end return return_string end function num.save(cart_slot) dset(cart_slot, num.sig | num.exp&gt;&gt;16) end function num.load(cart_slot) num.sig = dget(cart_slot)\1 num.exp = dget(cart_slot)&lt;&lt;16 end num.sig = new_sig num.exp = new_exp or 0 -- handle special cases: input can also be either an integer in string format or a table (assume it's another expint()!) if type(new_sig) == &quot;string&quot; then num.sig = tonum(sub(new_sig, 1, 4)) num.exp = max(#new_sig-4, 0) elseif type(new_sig) == &quot;table&quot; then num.sig = new_sig.sig num.exp = new_sig.exp end num._norm() return num end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p></div></div></div></p> <p>At present, this snippet uses 351 tokens; Shrinko-8 will reduce this to 347.</p> <h3>Instantiate</h3> <p>To create a new <code>expint()</code>, you can do one of the following:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre> w = expint(1,4) -- significand, exponent: in this case, 1x10^3, or 10000 -- values must be whole numbers between 0 and 32767 (inclusive) x = expint(10000) -- built-in number type -- whole numbers only between 0 and 32767 (inclusive) y = expint(&quot;10000&quot;) -- a whole number as a string; digits only -- can be as long as 32,767 characters, which is frankly silly z = expint(y) -- create a copy of an existing expint</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h3>Manipulate</h3> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre> x.add(y) -- add the value of y to x x.spend(y) -- if y &lt; x, subtract the value of y from x and return true -- If y &gt; x, make no changes to x and return false -- NOTE: add() and spend() will accept all the same parameters as expint() above </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h3>Display</h3> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre> x.print() -- returns the current value of x using a compact, human-friendly format x = expint(10001) print(x.print()) &gt; 10.00k </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h3>Store</h3> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre> x.save(1) -- saves the current value of x to the cart data slot provided x.load(1) -- loads the cart data from the slot provided into the current value of x -- NOTE: you must call cartdata() before using save() and load() </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h1>Discussion</h1> <p><div><div><input type="button" value=" Show " onClick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = ''; this.innerText = ''; this.value = ' Hide '; } else { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none'; this.innerText = ''; this.value = ' Show '; }"></div><div><div style="display: none;"></p> <h2>The Problem</h2> <p>One of the great things about PICO-8 is that invites you to look for ways to work around its stringent limitations. One of the biggest limitations I've found myself repeatedly bumping up against is, quite simply, &quot;I want to count higher than 32 thousand, dangit!&quot;</p> <p>I've used a variety of solutions in the past, all adequate for their various purposes, but none of them really <em>satisfying</em>&ndash;and none of them good for really <em>ridiculously</em> high counting. All told, I set out to find a counting system that met the following criteria:</p> <ul> <li>I want to be able to count big numbers. Just bonkers, bonkers big numbers, stupid huge numbers, thankyouverymuch</li> <li>I don't want to spend too many tokens getting there</li> <li>I want to support earning (add) and spending (subtract if less than) these numbers</li> <li>I want to be able to easily create these numbers from an integer-as-string or built-in number type</li> <li>I want to be able to display these huge numbers in a compact yet readable format</li> <li>I don't need a lot of precision; if I already have a million points, a single additional point is meaningless to me.</li> <li>I want to be able to save this huge number to a single slot of cart data (32 bits).</li> </ul> <h2>The Solution: Exponental Notation</h2> <p>Enter exponential notation. By using a significand (or mantissa) and an exponent, we can represent bonkers-high numbers in comparatively little space. Since space is always at a premium in PICO-8, we want to keep each of these numbers fairly small; in order to pack this into a single 32-bit space, we only want to use 16 bits each for the significand and exponent. (We <em>could</em> allocate this differently, but there are good reasons for doing it this way; see the Various Ramblings below for more details.)</p> <p>With the expint() data type, we can store an almost arbitrarily large number to four significant digits. We can then represent that number in an exponential format, either in traditional scientific notation (1.234x10^4) or as a human-friendly string (12.34k). This suits PICO-8 quite well: you don't have much space to display your large numbers, and once you start getting into serious number territory, you can't even fit them on the screen anymore.</p> <h2>The Drawback: Also Exponential Notation</h2> <p>This is where the low precision comes in. Using <code>expint()</code>, <code>10,000 + 9 = 10,000</code>. If you're doing important things, like flying an airplane or building a bridge, that's a <em>very bad</em> result! Happily, we're <em>not</em> doing important things; we're making video games! What's more, once you have ten thousand of something, another nine of that thing isn't going to be <em>that big of a deal</em>, especially if you're displaying that number as an approximation&ndash;for example, <code>10.13B</code> instead of <code>10,132,449,018</code>.</p> <h2>Other Limitations Of This Implementation</h2> <ul> <li><strong>Whole numbers only.</strong> This isn't designed to work with negative numbers or non-integers, either in the significand or in the exponent. I haven't tried doing it, and I'm quite confident it'd behave badly if I did.</li> <li><strong>Even big numbers have their limits.</strong> We're still using a 16-bit number to hold our exponent; we can't go any higher than that. This will conk out around <code>9999x10^32767</code>.</li> <li><strong>This code is not particularly optimized for space.</strong> I'm confident that there are folks out there who will look at this, shake their heads at my foolishness, and proceed to strip this down to half its current size and twice its current speed. As an aside, Shrinko-8 will minify the verbose variable names quite nicely.</li> <li><strong>You can add, and you can spend, and that's it.</strong> Adding other operations should be fairly straightforward, but I'm limiting this release to the two biggies for most of the applications of this number type in PICO-8.</li> <li><strong>There are no guardrails.</strong> In an effort to save tokens, I'm not doing any real error handling or boundary testing here. There's nothing stopping you from driving this thing off a cliff.</li> <li><strong>I, uh, haven't really tested this all that thoroughly yet.</strong> The happy path works, but there are probably some real forehead-smackers floating around in here. Set me straight in the comments, please!</li> </ul> <h2>Various Ramblings</h2> <p>At first, I thought about doing a true single-precision floating point number implementation. This, after all, is industry standard, and there are plenty of implementations I could crib off of to make this happen. Before long, though, I stumbled across a common enemy: all of these implementations were <em>way</em> more token-intensive than I was looking to do. (This, I suspect, is why we don't see a bunch of floating-point custom types kicking around the forums for this purpose.)</p> <p>So scratch going the IEEE route; given what I know about PICO-8, my most likely path to success would be to look for nifty, imperfect ways to leverage what the system already gives me.</p> <p>Eventually, two separate but related concepts came together in my head like peanut butter and chocolate:</p> <ul> <li>PICO-8 stores numbers as 16:16 fixed point decimals, neatly splitting them down the middle</li> <li><a href="https://www.lexaloffle.com/bbs/?uid=1"> @zep</a> added some nice format flags to tonum() and tostr() to hack this 16:16 fixed point format into a 32-bit integer format</li> </ul> <p>32 bits is <em>nice</em>, but still cuts you off a little over 2 billion, which for a lot of games isn't gonna cut it. What <em>will</em> cut it for this kind of game, though, is exponential notation: using a mantissa and an exponent, you can represent pretty much any number your heart can dream of. (Note that this is the basic concept behind standard floating-point implementations: so many bits reserved for the exponent, so many reserved for the mantissa.)</p> <p>So I was <em>kinda</em> back where I started, but not quite: I realized I could use PICO-8's 16:16 fixed-point number format as a jumping-off point for a lot of shortcuts if I used it to store my mantissa and exponent in that same 16:16 layout. I could use some basic arithmetic and bitwise operators to cram the 16-bit significand and 16-bit exponent into the integer and fractional parts of the built-in number type for easy storage:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>function num.save(cart_slot) dset(cart_slot, num.sig | num.exp&gt;&gt;16) end function num.load(cart_slot) num.sig = dget(cart_slot)\1 num.exp = dget(cart_slot)&lt;&lt;16 end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p></div></div></div></p> https://www.lexaloffle.com/bbs/?tid=149290 https://www.lexaloffle.com/bbs/?tid=149290 Fri, 30 May 2025 22:38:45 UTC WIP Toy: Endless Ships! <p> <table><tr><td> <a href="/bbs/?pid=166236#p"> <img src="/bbs/thumbs/pico8_mcg_endlessshipstoy-1.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=166236#p"> Toy: Endless Ships! (update 1)</a><br><br> by <a href="/bbs/?uid=94681"> magic_chopstick</a> <br><br><br> <a href="/bbs/?pid=166236#p"> [Click to Play]</a> </td></tr></table> </p> <h1>Update 1!</h1> <p>This is still very much a toy, but it's very close to &quot;done&quot; for purposes of the larger game. Ships are stronger, but so are your weapons&ndash;and you can do more than just deal direct damage now!</p> <h2>Of note in this update:</h2> <ul> <li>Added module modifiers! <ul> <li>heal</li> <li>hack (disable enemy die)</li> <li>ion (extra damage to shields and set enemy die to one)</li> <li>burn (stackable damage over time)</li> <li>trap (sets a trap on an enemy die that does damage when used)</li> </ul></li> <li>Improved crew (dice)! <ul> <li>Crew now have names</li> <li>Crew may have non-standard roll possibilities (including a wildcard roll!)</li> <li>Crew can have modifiers, much like modules</li> </ul></li> <li>Improved modules! <ul> <li>Added small modules that take up less space</li> <li>adjusted balance somewhat</li> </ul></li> <li>Improved ships! <ul> <li>Changed health/shield readout to support more damage points</li> </ul></li> <li>And a bunch of other stuff!</li> </ul> <h2>Previously:</h2> <p>Following cold on the heels of my earlier <a href="https://www.lexaloffle.com/bbs/?tid=146453">Quick 'n' Dirty Galaxy Generator</a>, here's another little toy cart that'll ultimately be part of a larger effort. Right now it's a pretty basic dice-based endless space battler. You control the ship on the left, the computer controls the ship on the right. Blow each other up using the power of six-sided die!</p> <p>There's a laundry list of to-dos here, including making the weapons modules a bit more balanced&ndash;right now it's kinda all-or-nothing for how useful a module is in a fight. As with the QnD Galaxy Generator, the intent here is to deterministically generate a vast array of different ships from a single seed, allowing for ultra-compact save files.</p> <p>Controls:<br /> arrows: move cursor<br /> X: action<br /> Z/O: swap out your ship for a new one (on your turn)</p> https://www.lexaloffle.com/bbs/?tid=148670 https://www.lexaloffle.com/bbs/?tid=148670 Tue, 29 Apr 2025 03:07:57 UTC Quick 'n' Dirty Galaxy Generator <p> <table><tr><td> <a href="/bbs/?pid=160275#p"> <img src="/bbs/thumbs/pico8_mcg_qndgalgen-3.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=160275#p"> Quick 'N' Dirty Galaxy Generator 0.2</a><br><br> by <a href="/bbs/?uid=94681"> magic_chopstick</a> <br><br><br> <a href="/bbs/?pid=160275#p"> [Click to Play]</a> </td></tr></table> </p> <p>The Quick 'N' Dirty Galaxy Generator builds off of my my <a href="https://www.lexaloffle.com/bbs/?pid=159148#p">Quick 'N' Dirty Planet Generator</a> by adding procedurally generated planets, routes, names, and governments to create a nice, compact little galaxy to explore. Right now, it's just a toy, but you can probably see where I'm planning to go with this!</p> <h1>Version 0.2 update: Saving Things!</h1> <ul> <li>Added auto-saving and auto-loading of the galaxy and the current state of your exploration. Reload your browser and pick right back up where you left off!</li> <li>Fixed a bug where the same governments and government colors were chosen over and over</li> <li>Fixed a bug where governments could take over the capitals of other governments during generation</li> <li>Added &quot;new galaxy&quot; button</li> </ul> <p>The save functionality is both simple and nifty: basically, just poke all the values I want to save in sequence to general memory with poke, write this memory in chunks to the cart data using peek and dset, then reverse the process to load. You can store a surprising amount of data this way!</p> https://www.lexaloffle.com/bbs/?tid=146453 https://www.lexaloffle.com/bbs/?tid=146453 Tue, 07 Jan 2025 03:35:44 UTC Quick 'N' Dirty Planet Generator <p> <table><tr><td> <a href="/bbs/?pid=159148#p"> <img src="/bbs/thumbs/pico8_mcg_qndpg_1-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=159148#p"> Quick 'N' Dirty Planet Generator 0.1</a><br><br> by <a href="/bbs/?uid=94681"> magic_chopstick</a> <br><br><br> <a href="/bbs/?pid=159148#p"> [Click to Play]</a> </td></tr></table> </p> <p>Hello, everyone! I'm back with another Quick 'N' Dirty cart!</p> <p>This time, I've put together a little planet generation and rendering system I'm looking to use in a bigger project. From the cart's intro comments:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>This is a very very work-in progress planet generator. I'm not (yet) going for huge amounts of complexity or variation in my texture generator. Rather, right now, I'm working to make as *performant* a planet generator and renderer as I reasonably can. To generate terrain, I'm using the diamond-square algorithm to rende a 64x128 pixel heightmap on the bottom half of the sprite sheet, which is mapped to the bottom half of the PICO-8 map. To help ensure that we're not impacting performance, I've added some break logic to the rendering routine that lets us stop processing once we hit a certain CPU threshold, spreading the work across a few frames. This is fast enough that planets render in well under a second, even with the added overhead of the break logic. Of note here is that planet generation is entirely deterministic and stems from a single seed value. If you want to build a galaxy of planets, all you need to do is store a number per planet and re-render them on the fly. To render, I'm relying on tline to draw a linearly-banded UV map that reads from the bottom half of PICO-8's map and draws a series of horizontal tlines across the unit circle. At higher rotation rates, this is very obviously not an accurate way to draw a sphere, but it *is* a blazingly *fast* way to do it, and at slow enough rotation rates, it's good enough to fool the casual observer. Rendering times increase as the planet grows, but even when the planet takes up most of the screen it only eats about 30% of the standard update cycle's CPU time. Future improvements will be focused on adding some good variety to the planets being generated, along with features like polar regions and wind/precipitation-based biome coloring.</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>Arrow keys to zoom and control the speed of rotation; O/Z to generate a new planet.</p> <p>Have fun!</p> https://www.lexaloffle.com/bbs/?tid=146073 https://www.lexaloffle.com/bbs/?tid=146073 Fri, 13 Dec 2024 04:11:05 UTC Agent Seeker <p> <table><tr><td> <a href="/bbs/?pid=145943#p"> <img src="/bbs/thumbs/pico8_mcg_agntsekr_1_02-1.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=145943#p"> Agent Seeker 1.02</a><br><br> by <a href="/bbs/?uid=94681"> magic_chopstick</a> <br><br><br> <a href="/bbs/?pid=145943#p"> [Click to Play]</a> </td></tr></table> </p> <h1>Agent Seeker</h1> <h3><em>A PICO-8 Spy Hunter demake/remake/homage</em></h3> <h2>Overview</h2> <p><em>Agent Seeker</em> is a fast-paced, reflex-taxing game built in the style of the original Spy Hunter, one of the greatest video games ever created. <code>[no citation needed]</code></p> <p>Drive your heavily-customized luxury sports car down an endless roadway, protecting innocent motorists from a rogue's gallery of menacing enemy agents. Use machine guns, oil slicks, smoke screens, flamethrowers, and armor-piercing cannons to stop as many enemy agents as you can!</p> <h2>Controls</h2> <p>Arrow keys/D-Pad: Drive (l/r to steer, up for gas, down for brake)<br /> Z key / O button: fire machine guns (front-facing, infinite ammunition)<br /> X key / X button: activate secondary weapon (Catch drones to gain limited-use secondary weapons)</p> <p><img loading="lazy" style="margin-bottom:16px" border=0 src="/media/94681/agntsekr p8_5.gif" alt="" /> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/94681/agntsekr p8_1.gif" alt="" /> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/94681/agntsekr p8_3.gif" alt="" /> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/94681/agntsekr p8_6.gif" alt="" /></p> <h2>You</h2> <p> <table><tr><td width=32> <img src="https://www.lexaloffle.com/bbs/gfxc/94681_9.png" width=32 height=32> </td> <td valign=bottom> <a style="cursor:pointer;font-size:8pt" onclick=' var el = document.getElementById("gfxcode_94681_9"); if (el.style.display == "none") el.style.display = ""; else el.style.display = "none"; microAjax("https://www.lexaloffle.com/bbs/gfxc/94681_9.txt", function (retdata){ var el = document.getElementById("gfxcode_94681_9"); el.innerHTML = retdata; el.focus(); el.select(); } ); '> [8x8]</a> </td></tr> <tr><td colspan=2> <textarea rows=3 class=lexinput id="gfxcode_94681_9" style="width:640px;background-color:#fed;display:none;overflow:hidden; font-size:6pt;"></textarea> </td> </tr> </table> </p> <p>You are the Agent Seeker, one of our top undercover operatives. Your skill behind the wheel is peerless, and your car, the Z-1983 Interdictor, sports the most advanced active anti-vehicle countermeasures the agency has at our disposal. Your mission: eliminate any and all enemy agents on our nation's roadways!</p> <h2>Civilians</h2> <p> <table><tr><td width=32> <img src="https://www.lexaloffle.com/bbs/gfxc/94681_0.png" width=32 height=32> </td> <td valign=bottom> <a style="cursor:pointer;font-size:8pt" onclick=' var el = document.getElementById("gfxcode_94681_0"); if (el.style.display == "none") el.style.display = ""; else el.style.display = "none"; microAjax("https://www.lexaloffle.com/bbs/gfxc/94681_0.txt", function (retdata){ var el = document.getElementById("gfxcode_94681_0"); el.innerHTML = retdata; el.focus(); el.select(); } ); '> [8x8]</a> </td></tr> <tr><td colspan=2> <textarea rows=3 class=lexinput id="gfxcode_94681_0" style="width:640px;background-color:#fed;display:none;overflow:hidden; font-size:6pt;"></textarea> </td> </tr> </table> <table><tr><td width=32> <img src="https://www.lexaloffle.com/bbs/gfxc/94681_1.png" width=32 height=32> </td> <td valign=bottom> <a style="cursor:pointer;font-size:8pt" onclick=' var el = document.getElementById("gfxcode_94681_1"); if (el.style.display == "none") el.style.display = ""; else el.style.display = "none"; microAjax("https://www.lexaloffle.com/bbs/gfxc/94681_1.txt", function (retdata){ var el = document.getElementById("gfxcode_94681_1"); el.innerHTML = retdata; el.focus(); el.select(); } ); '> [8x8]</a> </td></tr> <tr><td colspan=2> <textarea rows=3 class=lexinput id="gfxcode_94681_1" style="width:640px;background-color:#fed;display:none;overflow:hidden; font-size:6pt;"></textarea> </td> </tr> </table> </p> <p>Ordinary, everyday motorists, enjoying a pleasant daily commute. Don't shoot civilians or run them off the road, or you'll lose your combo and not gain points for a few seconds! (If a civilian crashes through no fault of your own, you won't get penalized.)</p> <h2>Enemies</h2> <p>Destroy enemies to earn points and increase your combo multiplier. If you take too long between destroying enemies, you'll lose your combo!</p> <h3>Tire Slasher</h3> <p> <table><tr><td width=32> <img src="https://www.lexaloffle.com/bbs/gfxc/94681_2.png" width=32 height=32> </td> <td valign=bottom> <a style="cursor:pointer;font-size:8pt" onclick=' var el = document.getElementById("gfxcode_94681_2"); if (el.style.display == "none") el.style.display = ""; else el.style.display = "none"; microAjax("https://www.lexaloffle.com/bbs/gfxc/94681_2.txt", function (retdata){ var el = document.getElementById("gfxcode_94681_2"); el.innerHTML = retdata; el.focus(); el.select(); } ); '> [8x8]</a> </td></tr> <tr><td colspan=2> <textarea rows=3 class=lexinput id="gfxcode_94681_2" style="width:640px;background-color:#fed;display:none;overflow:hidden; font-size:6pt;"></textarea> </td> </tr> </table> <br /> Weak against weapons, but equipped with deadly tire spikes. Don't hit them from the sides!</p> <h3>Bulletproof Bruiser</h3> <p> <table><tr><td width=32> <img src="https://www.lexaloffle.com/bbs/gfxc/94681_3.png" width=32 height=32> </td> <td valign=bottom> <a style="cursor:pointer;font-size:8pt" onclick=' var el = document.getElementById("gfxcode_94681_3"); if (el.style.display == "none") el.style.display = ""; else el.style.display = "none"; microAjax("https://www.lexaloffle.com/bbs/gfxc/94681_3.txt", function (retdata){ var el = document.getElementById("gfxcode_94681_3"); el.innerHTML = retdata; el.focus(); el.select(); } ); '> [8x8]</a> </td></tr> <tr><td colspan=2> <textarea rows=3 class=lexinput id="gfxcode_94681_3" style="width:640px;background-color:#fed;display:none;overflow:hidden; font-size:6pt;"></textarea> </td> </tr> </table> <br /> Heavy and well-armored, these brutes will shrug off machine-gun fire and try to run you off the road. Return the favor!</p> <h3>Spikelayer</h3> <p> <table><tr><td width=32> <img src="https://www.lexaloffle.com/bbs/gfxc/94681_4.png" width=32 height=32> </td> <td valign=bottom> <a style="cursor:pointer;font-size:8pt" onclick=' var el = document.getElementById("gfxcode_94681_4"); if (el.style.display == "none") el.style.display = ""; else el.style.display = "none"; microAjax("https://www.lexaloffle.com/bbs/gfxc/94681_4.txt", function (retdata){ var el = document.getElementById("gfxcode_94681_4"); el.innerHTML = retdata; el.focus(); el.select(); } ); '> [8x8]</a> </td></tr> <tr><td colspan=2> <textarea rows=3 class=lexinput id="gfxcode_94681_4" style="width:640px;background-color:#fed;display:none;overflow:hidden; font-size:6pt;"></textarea> </td> </tr> </table> <br /> Souped-up box trucks that get ahead of you and drop tire spike strips. They're tough but not bulletproof!</p> <h2>Secondary Weapons / Drones</h2> <p>Throughout the game, you'll have the opportunity to gain drone-delivered secondary weapon systems. These powerful weapons vastly increase your car's firepower, but have limited ammunition. Catching drones can be a challenge!</p> <h3>Oil Slick</h3> <p> <table><tr><td width=32> <img src="https://www.lexaloffle.com/bbs/gfxc/94681_5.png" width=32 height=32> </td> <td valign=bottom> <a style="cursor:pointer;font-size:8pt" onclick=' var el = document.getElementById("gfxcode_94681_5"); if (el.style.display == "none") el.style.display = ""; else el.style.display = "none"; microAjax("https://www.lexaloffle.com/bbs/gfxc/94681_5.txt", function (retdata){ var el = document.getElementById("gfxcode_94681_5"); el.innerHTML = retdata; el.focus(); el.select(); } ); '> [8x8]</a> </td></tr> <tr><td colspan=2> <textarea rows=3 class=lexinput id="gfxcode_94681_5" style="width:640px;background-color:#fed;display:none;overflow:hidden; font-size:6pt;"></textarea> </td> </tr> </table> <br /> Catch the drone with green highlights to gain an oil slick. Oil slicks are applied directly to the road behind you. Any car that touches an oil slick will skid out of control and crash!</p> <h3>Smokescreen</h3> <p> <table><tr><td width=32> <img src="https://www.lexaloffle.com/bbs/gfxc/94681_6.png" width=32 height=32> </td> <td valign=bottom> <a style="cursor:pointer;font-size:8pt" onclick=' var el = document.getElementById("gfxcode_94681_6"); if (el.style.display == "none") el.style.display = ""; else el.style.display = "none"; microAjax("https://www.lexaloffle.com/bbs/gfxc/94681_6.txt", function (retdata){ var el = document.getElementById("gfxcode_94681_6"); el.innerHTML = retdata; el.focus(); el.select(); } ); '> [8x8]</a> </td></tr> <tr><td colspan=2> <textarea rows=3 class=lexinput id="gfxcode_94681_6" style="width:640px;background-color:#fed;display:none;overflow:hidden; font-size:6pt;"></textarea> </td> </tr> </table> <br /> Catch the drone with blue highlights to gain a smokescreen. Smokescreens will temporarily blind drivers in a wide cone behind your car, which will often cause them to veer off the road and crash!</p> <h3>Flamethrower</h3> <p> <table><tr><td width=32> <img src="https://www.lexaloffle.com/bbs/gfxc/94681_7.png" width=32 height=32> </td> <td valign=bottom> <a style="cursor:pointer;font-size:8pt" onclick=' var el = document.getElementById("gfxcode_94681_7"); if (el.style.display == "none") el.style.display = ""; else el.style.display = "none"; microAjax("https://www.lexaloffle.com/bbs/gfxc/94681_7.txt", function (retdata){ var el = document.getElementById("gfxcode_94681_7"); el.innerHTML = retdata; el.focus(); el.select(); } ); '> [8x8]</a> </td></tr> <tr><td colspan=2> <textarea rows=3 class=lexinput id="gfxcode_94681_7" style="width:640px;background-color:#fed;display:none;overflow:hidden; font-size:6pt;"></textarea> </td> </tr> </table> <br /> Catch the drone with pink highlights to gain a flamethrower. Flamethrowers will blast a gout of flame out both sides of your car, incinerating anything too close. The flamethrower works against everything, but is highly effective when dealing with Tire Slashers!</p> <h3>Armor-Piercing Cannon</h3> <p> <table><tr><td width=32> <img src="https://www.lexaloffle.com/bbs/gfxc/94681_8.png" width=32 height=32> </td> <td valign=bottom> <a style="cursor:pointer;font-size:8pt" onclick=' var el = document.getElementById("gfxcode_94681_8"); if (el.style.display == "none") el.style.display = ""; else el.style.display = "none"; microAjax("https://www.lexaloffle.com/bbs/gfxc/94681_8.txt", function (retdata){ var el = document.getElementById("gfxcode_94681_8"); el.innerHTML = retdata; el.focus(); el.select(); } ); '> [8x8]</a> </td></tr> <tr><td colspan=2> <textarea rows=3 class=lexinput id="gfxcode_94681_8" style="width:640px;background-color:#fed;display:none;overflow:hidden; font-size:6pt;"></textarea> </td> </tr> </table> <br /> Catch the drone with orange highlights to gain armor-piercing cannons. The AP Cannon replaces your car's machine guns with high-caliber anti-vehicle cannons. While their rate of fire is lower than your standard machine guns, a single round can take out anything it hits!</p> <h2>Development</h2> <p>Hi, everyone! Say hello to Agent Seeker!</p> <p>I'm <em>finally</em> to a version one of this started-as-a-personal-jam project, a fun demake of the old Spy Hunter arcade game. I built the original version on a self-inflicted SFO-DCA plane jam, but I had so much fun making what I could on the plane ride that I decided I had to flesh it out some more, and here we are.</p> <p>I can't even begin to imagine how many quarters I poured into the original Spy Hunter (thank you, George Gomez!) Hopefully, I've captured the fun and challenge of the original without losing too much of that PICO-8 charm. </p> <p>Have fun, Agent Seeker!</p> <h2>Updates</h2> <h3>Version 1.02: Balance and shine!</h3> <p>Graphics: Added more trees, rocks, and color depth to background<br /> Balance: increased the chances of having an enemy appear when no other cars are on the road (help to keep those combos alive!)<br /> Bug: fixed a very minor issue where trees were drawing out-of-order<br /> Bug: fixed the byline on the published PNG cart</p> <h3>Version 1.01: A Little Change In Scene</h3> <ul> <li>Added cool transition screens!</li> <li>Also updated the license so you can play around with it and see my horrible, sloppy code!</li> <li>That's it!</li> </ul> <h3>Version 1.0: Agent Seeker, you are go!</h3> <ul> <li>Updated music: now 27% better than before</li> <li>Improved adaptive music algorithm: more responsive, fewer weird hiccoughs</li> <li>Improved ambiance: added trees and overpasses</li> <li>Added flair: your car goes psychedelic once you hit 15 combo</li> <li>Updated title graphic: now 36% better than before</li> <li>Gameplay balance: Tire Slashers will no longer deploy their slashers when they're under the effect of a smokescreen</li> <li>Minor annoyance fixed: Once the player crashes, the score penalty is removed promptly to show end-of-game score</li> <li>Performance bug fixed: new tire skids were continuing to be created ad infinitum on the game over screen. Fixed that madness.</li> <li>Added polish: improved skid algorithm</li> <li>Added polish: fixed drone approach algorithm</li> <li>Fancy gadgetry: your car's glovebox now contains a powerful spring-loaded boxing glove, designed to quickly and effectively incapacitate a hostile passenger. Should you ever need to use it, simply press the leftmost button hidden under the cap of your gearshift. It's a real knockout, agent!</li> </ul> <h3>WIP.5: Adding polish!</h3> <ul> <li>Rad new title screen added</li> <li>Improved &quot;burning&quot; effect</li> <li>Extended top-tier music</li> <li>Some small copy edits</li> <li>Added highly advanced system capable of pinpointing your exact position, to within a few meters, anywhere on the globe. Research calls it their &quot;Worldwide Telemetry Feature&quot;. It's available in your car's secret dashboard (which, sorry again, is inside the car, very small, and hard to see)</li> </ul> <h3>WIP.4: Balance and flow!</h3> <ul> <li>Added speedometer (choose metric or standard units in the pause menu!)</li> <li>Reduced minimum score for first enemy from 50 to 30</li> <li>Fixed bug where spike strips could have negative speed (weird)</li> <li>Added to top speed of car to better reflect it's extreme spy nature (causes some tearing in the scenery, but what can ya do)</li> <li>Fixed bug where resupply drones would keep coming after player crash</li> <li>Fixed bug where alt fire would rapidly drain cannon ammo without firing cannon</li> <li>Added champagne bottle chiller to center console of player car. Again, hard to see</li> </ul> <h3>WIP.3: challenge and cleanup!</h3> <ul> <li>Major update: Added HARD MODE (score 100k points to unlock!) Tougher AI, tougher course, more points, higher combo chain max, and more!</li> <li>Improved AI</li> <li>Improved music tracking/looping algorithms</li> <li>Improved crash tracking, made running enemies off the road more forgiving</li> <li>Adjusted color on spike strips dropped by Spiker enemies to make them look less like flames</li> <li>Added a martini glass holder to the player's car. It's very, very small and a little tough to see ;)</li> <li>Lotsa little bugs and adjustments</li> </ul> https://www.lexaloffle.com/bbs/?tid=141512 https://www.lexaloffle.com/bbs/?tid=141512 Sun, 07 Apr 2024 02:06:42 UTC