At the end of 2022 I launched Cogmind’s most involved special event yet: Polymind (not to be confused with my earlier unrelated 7DRL, POLYBOT-7!). The release announcement already covers the basics, so I’ll assume you’re familiar with those already and avoid rehashing most of that here. Instead let’s talk development! Now that the event is over, towards the end we’ll also be taking a look at player stats from Polymind, which also had its own leaderboard for the duration.
In terms of dev investment, Polymind is Cogmind’s most involved alternate mode yet, requiring well over a hundred high-paced hours of mostly coding work to realize. Unlike most prior events which tended to be concentrated in just a few areas of the code, this one is all over the place. It modifies the AI, player input, alert mechanics, part interaction… all sorts of stuff, while also adding many of its own new mechanics, too.
In short, Polymind enables the player to take direct control of almost any other robot, basically “possession” mechanics as found in many other games. For years players have jokingly imagined roleplaying as a Worker or some other lowly non-combat robot frequently seen roaming the complex. In Polymind it’s not only possible, but doing so can even aid in your survival :)
In a complete departure from Cogmind’s normal core mechanic, the player is unable to attach any parts, or even evolve more slots, but is instead entirely dependent on hosts for protection, or avoiding detection completely by melding into Complex 0b10. While undetected, you can move around as if you belong, trying to keep your suspicion down, or eventually need to figure out a way out of trouble when things start going south. Fighting is always an option, too, but can be a dangerous one in the long term without access to Cogmind’s normally superior capabilities.
Is this Even Possible?
There were a lot of questions when initially considering whether to implement this mode, since more often than not a common but high-level comment like “[feature X] would be pretty cool…” is so much easier to say than actually build :P
So the very first thing I had to do after selecting Polymind from my list of potential event ideas was to do a feasibility study looking at the potential roadblocks with respect to Cogmind’s fundamental architecture and design.
Architecture
A good many roguelikes are coded such that the player and non-player “actors” (creatures/mobs/entities/whateveryoucallthem) are based on the exact same systems and data structures. This is really helpful for balancing the game, simplifying player understanding of mechanics and interactions, and of course simply building the game where you can have a ton of interactive systems but don’t have to always treat the player as some separate special case.
In this sense, roguelikes probably lend themselves well to possession mechanics, inherently being easier to swap in some other actor for the player to control without worrying about too many unexpected side effects. While Cogmind does have a few player-specific exceptions with regard to certain mechanics where necessary for balance reasons (usually being a little more lenient on the player), for the most part it follows this roguelike design tenet: The player is just another Entity composed of a handful of base stats and operating as a collection of items that confer the majority of their additional capabilities.
That doesn’t mean Polymind was completely smooth sailing on the architecture front, just… close to it :P
As I wrote about in Item Variants and Randomization in Roguelikes, data for Cogmind objects such as items (and Entities!) is mostly held in static databases loaded on startup, essentially a large number of game-defining values which are assumed to remain unchanged while Cogmind is running. I already had to address this roadblock in order to implement Constructs with variable stats for the upcoming Scrap Engine mechanics, so I was able to draw from that experience and code when working with Polymind. Directly editing the underlying data seems easy enough, and makes sense, but could have unintended side effects since it wasn’t built with that in mind, not to mention requires separate attention to actually loading and saving the relevant unique data changes for runs in progress, data which exists outside the normal serialization process. Anyway, as with Constructs it works but it’s a bit crude, as one might expect when venturing outside the bounds of what a system was designed to do in the first place…
Polymind also benefited from RPGLIKE, another earlier special mode, for which I had already added indirect access to a number of Cogmind stats that might be modified through abnormal/non-part means as a simpler alternative to editing underlying data which I had always wanted to avoid before. For example, instead of editing Cogmind’s base sight range in the database, leveling up that stat in RPGLIKE would edit a separate value, and retrieving sight range for an Entity first checks whether it’s the player, in which case it will draw from the separate value, or instead from the database for any other Entity. This offers another avenue for changing that value (and a few others) where applicable, if I don’t want to worry about saving and loading things directly to and from a supposedly static database…
So while this mode was already a lot of work, it would’ve been even more time-consuming if not for the fact that it could be built on the foundation of several big projects that came before.
In the end it’s not an ideal solution for the architecture side of things, but it works, and I’m open to cooking up a bit of spaghetti when it comes to putting together special events since they’re short-term projects isolated in the code anyway.
The “possession” process itself is interesting in that it actually destroys the host and transfers their stats to Cogmind, while separately storing as much of the original information necessary to recreate the host if and when the player releases control at a later point.
Due to how this latter system operates, storing the host’s original faction to restore it later, one side effect allowed players to discover a facet of Cogmind’s internal design which wasn’t previously known (and is confusing unless I explain it :P).
As players see it, Cogmind robots don’t actually indicate their specific faction, instead simply showing whether they are friendly, neutral, or hostile to the player, so sometimes in a few special case branch maps, as far as the data goes NPCs might technically belong to a “faction” that doesn’t behave as one might expect in another map. What this means is that specifically in Polymind, controlling such an NPC and releasing them in one of these other maps might cause them to be friendly to robots one would think are their enemies!
I did this early on in Cogmind development since it wouldn’t have any noticeable impact on the game, reusing “factions” on different maps for different purposes in order to keep the total number of required factions as low as possible. This is one of many things that could be addressed in the long term if more work was put into this event, but the focus was on gameplay in the main complex (more on that decision later), and the potentially unexpected faction behavior actually only comes into play in very few situations anyway.
Honestly I recall considering a more dynamic faction system for pre-alpha Cogmind, since at the time I was close to building one for X@COM, Cogmind’s predecessor and the source of its initial code, and although I later did do that for X@COM, I didn’t really see a strong need for it in Cogmind compared to the overhead it would add, so decided to forgo it. I’ve since started adding a few extra faction slots to Cogmind for different purposes, but it’s still not a dynamic system which would be even more flexible.
Design
On the design side my primary concern was interface complications, since all necessary interactions must be fully mouse and keyboard compatible, where a deficiency on one side or the other will as usual serve to limit and guide the mechanics. While in some cases mouse input in particular did require special attention, I was happy to discover that pretty much all of my goals there were achievable.
One new UI feature required on several different levels in order for Polymind to even be feasible is a toggleable force melee mode. Normally a “force melee” type interaction is enabled by holding a modifier key, though technically due to command conflicts has never been possible when combining force melee and diagonal movements using vi key directional input, for example. Alternative input options exist for such an occasion (not incredibly common), but for quite a while I have always planned to address the issue more directly with an optional universal toggle, so this was the perfect opportunity to finally make it a reality.
(I’ll write about more mode-specific interface features later.)
Mechanically speaking, one of the big potential roadblocks was how to let the player remain friendly with all those bots out there that otherwise attack on sight. It’s not as simple as changing faction relation settings, which would introduce its own set of bigger problems. Instead I found a simpler solution to circumvent faction considerations and treat the player differently depending on their current host and status: just don’t let hostiles add the player as an enemy if they don’t currently see them as one.
Each AI normally stores its own list of enemies that it remembers for however long, a duration set initially by the AI’s robot type and can be shortened by system corruption or ECM effects. Polymind-Cogmind is blocked from being added to “hostile” AI memory if using a host friendly to the AI (based on that host data we stored earlier!) and not currently suspicious.
Technically under this system, if the player manages to break line of sight with hostile pursuers and significantly lower their suspicion level, perhaps in combination with switching to a new host (which itself lowers suspicion), they can once again be removed from pursuers’ memory and operate in safety, though the pursuers will likely investigate the local area and potentially discover the player again if suspicion again reaches the maximum level.
Technical design issues resolved, the other early requirement was to convince myself that the mode would actually be fun.
This aspect can be harder to nail down in gamedev, but at an early stage there’s really no need to get into the nitty gritty details--I just needed to focus on the bigger picture: Will this create challenges that the player can overcome by making interesting decisions using the resources and capabilities they have available at the time? What will the player be thinking from moment to moment during the various scenarios I can envision under the type of gameplay this will lead to? What can I do or add to help facilitate that interesting gameplay?
This line of thinking leads into some Polymind-specific features like the free intel system on controlling a new host. And of course first and foremost this is also where the suspicion system and corresponding jobs system come into play. I saw enough flexibility in those that players could find a fun balancing act to carry out in there, oscillating between suspicious and unsuspicious as necessary throughout their run to achieve their goals amidst evolving circumstances. Assuming the numbers are set right, that is, but balancing is for later when the features are actually implemented. The important part is to know that it’s theoretically a good track to be on before investing the required dev time.
Multitile Robots
This was huge (haha). Multitile robots are cool. They also tend to be a nightmare to work with. I wrote a lot about them in Developing Multitile Creatures in Roguelikes, but letting the player control one is a different and even more complex matter!
Multitile bots felt like they were close to derailing the project in its latest stages, since I had repeatedly pushed them further and further down the TODO list until they were just about at the end, then by the time I got to working on them and we were past my initial deadline for completion, all the related bugs sure took a long time to weed out (Polymind was definitely completed later than I wanted).
At one point it felt like they might need to be cut--essentially no controlling multitile hosts allowed, but I really felt like we had to have them in there if at all possible! They’re just too cool, and an important goal of this mode was to attempt to allow the player to control almost anybot. Even if only a few players ever ended up doing it, it needed to be a thing (cue late-hour coding sessions xD).
My first experience with this was back in 2019, when players were postulating what it’d be like if Cogmind could occupy multiple spaces as 2×2 bots do, so at the time as a joke test I simply changed the one variable determining Cogmind’s Entity size and surprisingly it actually more or less worked. Now that’s a far cry from what it takes to have proper full control of a large robot, but at least it showed me that such a change doesn’t immediately break the game!
So what’s the big deal with multitile actors?
Limited freedom of movement due to terrain is not something we’d address here--at worst they’ll just have to blast open doorways, take down walls, or even widen shorter corridors if they really want to head in some partially obstructed direction. But another movement issue that absolutely must be addressed is interaction with other robots, because those are everywhere, not to mention moving around most of the time and therefore easy to become repeatedly annoying obstacles.
For this I decided it’d be great to have them just push any blocking robots out of the way. Not like the ramming, crushing, or kicking that normally results from bumping another non-allied robot, mind you, just nudging anyone out of the way, regardless of their affiliation.
This is a pretty sensible and elegant solution, I think, although I admit it was kind of a little recursive nightmare--recursion be like that xD. I had to set up specific tests to be able to reliably repeat and fix issues, and just when I thought it was fixed, filling a room with all manner of other robots and randomly pushing through them in various directions would crash the game again in some new and unexpected way, or push one in an unexpected direction. The weirdest issue I recall was when pushing one blocking robot managed to crush it to death while simultaneously pushing a different robot that wasn’t even on the target path!?
Eventually it always worked, whew :)
On the UI side, multitile Entities naturally also have a fair number of issues that require special handling, so much so that I entirely separated out the code for their player movement input processing, as well as excluded from those options certain actions that would be problematic in more ways that I didn’t have time to address (such as interacting with machines, or ramming with intent to damage or destroy robots and terrain).
Still, they can perform a majority of useful actions, and most importantly they work!
After all of the above architecture and design worries, I was pleased to see Polymind work out in the end. While at the beginning I could imagine a lot of potential issues down the road, I also really wanted to bring Polymind to life, so rather than fret over all of them in advance and try to draw up detailed plans, as soon as I had a general feeling that it might be feasible I simply started, which helped avoid the inevitable temporary paralysis from seeing so many issues without clear solutions.
We’ve barely scratched the surface here and you can already see there were tons of moving parts behind this event (and as you’ll see later quite a lot of code!), but sometimes you have to just say “I’ll figure it out when we get there” and hope for the best :P. At least the initial feasibility study where I examined some of those fundamental questions suggested I wouldn’t hit any serious show stoppers on the way!
Polymind-specific Features
Beyond simply taking control of other robots, sharing their parts and basic stats, conceptually what does that mean, both in terms of gameplay and theme.
Thematically this goes back to players’ original desire to roleplay a Worker, doing Worker things. (And actually even before all that, one player in particular (zxc) always thought it would be fun to be able to temporarily disguise oneself in the regular game purely in order to bypass enemies, though a combination of significant technical hurdles and balance issues kept me from considering it in a more serious capacity.)
This is where suspicion and jobs come in. An idea central to the gameplay here is to remain unsuspicious, and for that to work we clearly need to define a new set of capabilities outside the scope of what’s offered by the game through normal part interactions.
The above list of abilities adds some of the tools necessary to remain unsuspicious. It is not, however, an exhaustive list of ways to modify suspicion (either up or down), since other relevant actions are already covered by existing behaviors, such as combat, or even just Operators working at terminals (hacking!) or Minesweepers collecting traps. But those are very easy to incorporate since they already existed in the code, whereas the notes were focused on the creation of entirely new features which would require separate implementation.
Yet more thematic abilities were listed as possibilities, but would be too complex to tackle in the short term, and for little benefit compared to the importance of core behaviors one expects from the bot classes listed above.
New features also generally require new supporting interface elements, at least concerning QoL to smooth out the experience. For example some of those class abilities require a way to designate valid targets, such as areas for tunnelers to dig.
For the Engineer in particular I decided Polymind-specific highlighting was unnecessary, since by default even in the regular game it’s pretty obvious when areas have been destroyed and are in need of repair.
For a few of the more complex hosts, it became necessary to blink other robots in white or pink to imply what action would take place if interacted with given the player’s current host and status. This is because item toggle state, suspicion level, and whether the target is hostile could all impact what action currently applies.
The actual meaning of these colors, and class abilities in general, are conveyed through the Polymind info panel for the current host, accessed through the usual special event UI window over the bottom-left corner of the map.
The info panel includes all of the host’s innate stats, like built-in energy generation and damage modifiers, so playing Polymind and controlling different hosts offers an interesting alternative way for players to gain deeper insight into robot capabilities (and weaknesses!) even in the regular game.
Also on that panel is a list of any intel obtained from controlling a new host of that class. The intel idea was something I added only at the very end, not only because it’s logical, but also for design reasons: Players are trying to make informed decisions as they hop around between bots, and intel helps in that regard while also giving yet another reason for wanting to take over multiple different bots to begin with, depending on the circumstances. So it’s not just about what the bot is capable of, but also what information they’ll reveal when you take control. This info is also often tied to their respective jobs, so this feature brings way too many advantages to leave it out…
Fortunately the intel portion was much less work that it otherwise would’ve been, because it drew directly from all the normal robot hacks you can perform on 0b10 bots to get information!
Balance
This mode was designed under a lot of time pressure, meaning not much time left at the end for proper balance work. Much of the balance for Polymind’s first release was based on hypotheticals, though I do think it worked out pretty well for the most part.
Once players got hold of it, and I had an opportunity for real playtesting myself, there were multiple updates within a week of release to make some adjustments, but still nowhere near the attention a mode like this would get if it were to become something even bigger. As a timed special event though, I’m satisfied as long as it meets the goal of being fun for at least a little while.
Aside: Designing these events feels somewhat like a 7DRL--basically you’ve got a new core mechanic around which to quickly design a unique experience, just within the confines of Cogmind’s world. So in that sense even though I rarely participate in 7DRLC (even though I always want to and have lots of ideas for it xD), technically I’ve made a good many “XDRLs” over the years. In fact, on that note the idea for POLYBOT-7 came from what was originally going to be a Cogmind event!
On the topic of fun, the relevant “numbers” mentioned earlier could definitely have used more tweaking, but that level of balance requires a fair amount of data that we just didn’t have yet.
There are many numbers involved, but among the most important, and numerous, is the cost of taking control of each type of host. Of course it can’t be free, so for this I resurrected the idea of Protomatter first introduced for the RPGLIKE event, a matter-like item salvaged from some robots as an alternative mode-specific resource.
Even if I did have time for proper playtesting (I didn’t…), we’d still need some kind of starting point for setting these costs, so I decided to base them on a formula derived from each robot’s core integrity and exposure:
cost = [core_integrity] * (1 + ((0.40-[core_exposure%]) / [core_exposure%]))
This formula uses 40% as an average core exposure and increases or reduces their integrity-based cost by a corresponding percentage when they have a lower or higher value than that. The actual costs are not as important here, it’s more about relative cost, since we can always tweak the Protomatter drop rate and amounts as necessary, but the idea is to assign a higher cost to more powerful robots, and by design power level generally corresponds to core integrity and exposure.
I originally tried a formula based on part rating, since many capabilities are based on parts, after all, but found that to be overall too unreliable as a basis for cost. Basing it on integrity/exposure isn’t perfect, either, but it would have to do!
I also considered but did not factor robot speed into the formula--faster robots do indeed enjoy greater survivability as a result of their speed, but as far as Polymind mechanics go, balance-wise it is not only more likely that faster hosts will lose their capabilities, it is also generally more likely that high-integrity/low-core-exposure hosts will be more capable of acquiring additional Protomatter (through the destruction of other robots) in order to keep taking control of other targets. Fast hosts certainly have their advantages, but generally do not contribute as much to later progress (or score, for that matter).
While building the event I was worried Polymind might be too easy overall, but as it turns out the difficulty ramp is similar to the regular game, growing increasingly challenging all the way to the end. To give that claim some context: Cheaper host-dense early depths make it easier to avoid detection completely if desired, compared to later maps which are much larger, along with the usual increasingly powerful enemies roaming about despite Cogmind having access to fewer tools (generally little to no inventory, and no part swapping, slot expansions, or most consumables). Combat becomes all but unavoidable at some junctions.
Polymind is still very winnable, so that’s good, but while I like the resulting challenge level, it could still stand to be tweaked and expanded for an even smoother, better-balanced experience.
As usual when working on a new feature, while building it I also made a list of areas or potential add-ons that could be important to examine for “optional balance tweaks” later on, depending on how the final gameplay turns out and what players do with it, though for the subsequent updates I did not yet need to revisit that list so much since many of those options were implemented shortly before even the first release once I realized there’d be no time for playtesting and instead continued on the instinct that they’d inevitably be applied anyway. (I had wanted to let patrons try out Polymind in advance and tweak from there, but again there was no time.)
Polymind can especially get weird outside Complex 0b10, in branches, since the mode was mainly designed around non-branch content. But unlike some of the previous events (Abominations, for example) and challenge modes, I didn’t want to prevent the player from visiting branches and interacting with much of the game content, especially when it’s possible to take control of a whole bunch of different hosts out there as well, plus trigger interesting game events. So while all maps were left accessible, we had to simply assume that all the other factions recognize you as Cogmind regardless of your current form, and plot/NPC interactions more or less remain the same. So that’d be another area that could be expanded or addressed in other ways, a topic I’ll get into more at the end.
Players Meet Polymind
Part 2 of this article looks at player stats, strategy, merging code, and more…
2 Comments
Could this lead the way to a 2X2 cogmind in the future!? Honestly that wouldn’t work as the main game isn’t really designed/balanced around that, but think! Could be huge (also ha). Thanks for the Polymind experience, and as always these are fun to read!
Glad you liked it, and there’s more writing to come, too. This article just started getting waaay too long, so I decided to split it in two :P
The second part will indeed mention the future of Polymind and its code :). In short, though, it’s true that the work that goes into events can be reused in other ways later. 2×2 specifically is something I’m interested in exploring more, perhaps in a different capacity--larger rideable machines??? Huge indeed.