FMOD in C#… it’s a pain to set up. here’s how I did it:

I’ve been having a lot of trouble playing music in Mysterious Space, due to bugs with MonoGame. these bugs range from failing to properly loop songs to crashing the game! music-related bugs have plagued MonoGame for a while (like, years), so waiting for them to get fixed… yeah… dunno about that.

in light of these issues, DDRKirby(ISQ) recommended FMOD to me. it’s a music-playing library that’s been around for a long time. it’s a mature, stable library.

that being said, getting it working in C# has always been something of a problem. there are a lot of wrappers that you can find online, but most have not been updated in a couple years; FMOD comes with a wrapper of its own, but documentation is poor.

I was finally about to get it working in Mysterious Space, though, so for anyone out there googling “FMOD C# example”, as I was trying to do, this is for you.

a few things to mention about my setup:

  • I will be using FMOD’s built-in wrapper
  • I’m using Visual Studio 2012
  • I’m compiling for mixed platforms (32 AND 64-bit; this makes using FMOD a little more “exciting”)

Adding the .cs Files

you can’t add FMOD as a “Reference” for your project. instead, you need to add the DLL files to your project’s root, and include a few .cs files that come with FMOD.

let’s start with the .cs files. they can be found in FMOD’s install directory, under api\lowlevel\inc, for example, C:\Program Files (x86)\FMOD SoundSystem\FMOD Studio API Windows\api\lowlevel\inc. add all the .cs files there to your project.

open up fmod.cs and check out that #if WIN64 block. this is telling the fmod wrapper which dll to include. if you’re happy compiling strictly for 32-bit, or strictly for 64-bit, leave this code alone, and #define WIN64 if needed (you can do this either right in the file, or through the project’s settings, or edit out the #if block, or whatever).

if you want your program to run on both 32 AND 64-bit platforms, you’re in for a touch of extra coding which we’ll get to in a moment. for now, though, remove the #if block entirely, leaving only the line public const string dll = "fmod"; (define-related code is determined at compile-time, but we need to include the right DLL during run-time!) technically you don’t have to do this (assuming you DON’T #define WIN64), but I didn’t want to leave in code that suggested something platform-specific was going on. it’s up to you.

Adding the .dll File(s)

if you’re compiling only for 32-bit, or only for 64-bit, find the appropriate dll and add it to the root directory of your project. for 32-bit, the file is fmod.dll; for 64-bit, it’s fmod64.dll. both files are in FMOD’s install directory, under api\lowlevel\lib.

fmod-dllsif you’re compiling for BOTH, you’ll need to do things a little differently: you’ll need to add both files, but they both need to be called fmod.dll (fmod64.dll will be renamed; remember how we modified fmod.cs so that it always looks for “fmod.dll”?). this means putting them in different directories. for myself, I created an “FMOD” directory, and then created directories named “32” and “64” inside that, placing fmod.dll into “32”, and fmod64.dll into “64” before renaming it to fmod.dll.

whichever files you included, make sure that their “Copy to Output Directory” property is set to “Copy if newer” (or “Copy always”). if you leave this property to “Do not copy”, the file(s) will not be copied over to the directory where your program’s executable is placed when compiling.

Actually Using FMOD

I wrote a class responsible for handling music, from loading it, to playing it. I feel like examples are more helpful than long explanations, so here’s the class I wrote. You’ll need to modify it; most of those modifications should be obvious. Further explanation, and example usage, are below the code.

using System;
using System.Runtime.InteropServices;

namespace MysteriousSpace
{
    public class MusicPlayer
    {
        public const int NUM_SONGS = 14;

        public const int SONG_TITLE_MENU = 0;

        public const int SONG_SECTOR_MAP = 1;

        public const int SONG_DESERT = 2;
        public const int SONG_FOREST = 3;
        public const int SONG_OCEAN = 4;
        public const int SONG_BARREN = 5;
        public const int SONG_ICE = 6;
        public const int SONG_LAVA = 7;
        public const int SONG_MINING = 8;
        public const int SONG_ASTEROID_BELT = 9;
        public const int SONG_ENCOUNTER_HUMAN = 10;
        public const int SONG_ENCOUNTER_CYBORG = 11;
        public const int SONG_ENCOUNTER_AI = 12;
        public const int SONG_ENCOUNTER_ALIEN = 13;

        private FMOD.System FMODSystem;
        private FMOD.Channel Channel;
        private FMOD.Sound[] Songs;

        private static MusicPlayer _instance;

        public static MusicPlayer Instance { get { return _instance; } }

        [DllImport("kernel32.dll")]
        public static extern IntPtr LoadLibrary(string dllToLoad);

        public static void Init()
        {
            if (Environment.Is64BitProcess)
                LoadLibrary(System.IO.Path.GetFullPath("FMOD\\64\\fmod.dll"));
            else
                LoadLibrary(System.IO.Path.GetFullPath("FMOD\\32\\fmod.dll"));

            _instance = new MusicPlayer();
        }

        public void Unload()
        {
            FMODSystem.release();
        }

        private MusicPlayer()
        {
            FMOD.Factory.System_Create(out FMODSystem);

            FMODSystem.setDSPBufferSize(1024, 10);
            FMODSystem.init(32, FMOD.INITFLAGS.NORMAL, (IntPtr)0);

            Songs = new FMOD.Sound[NUM_SONGS];

            //LoadSong(SONG_TITLE_MENU, "");
            LoadSong(SONG_SECTOR_MAP, "Set a Course [Seamless]");
            LoadSong(SONG_DESERT, "Uncharted Expanse [Seamless]");
            LoadSong(SONG_FOREST, "Mystic Depths [Seamless]");
            LoadSong(SONG_OCEAN, "Dreamscape (Mysterious Space Edit)");
            //LoadSong(SONG_BARREN, "");
            LoadSong(SONG_ICE, "Always (Mysterious Space Edit)");
            LoadSong(SONG_LAVA, "Afterglow [Seamless]");
            LoadSong(SONG_MINING, "Eternal Excavation");
            LoadSong(SONG_ASTEROID_BELT, "Not the Same Level (Mysterious Space Edit)");
            //LoadSong(SONG_ENCOUNTER_HUMAN, "");
            //LoadSong(SONG_ENCOUNTER_CYBORG, "");
            //LoadSong(SONG_ENCOUNTER_AI, "");
            //LoadSong(SONG_ENCOUNTER_ALIEN, "");
        }

        private void LoadSong(int songId, string name)
        {
            FMOD.RESULT r = FMODSystem.createStream("Content/Music/" + name + ".flac", FMOD.MODE.DEFAULT, out Songs[songId]);
            //Console.WriteLine("loading " + songId + ", got result " + r);
        }

        private int _current_song_id;

        public bool IsPlaying()
        {
            bool isPlaying = false;
            
            if (Channel != null)
                Channel.isPlaying(out isPlaying);

            return isPlaying;
        }

        public void Play(int songId)
        {
            Console.WriteLine("Play(" + songId + ")");

            if (_current_song_id != songId)
            {
                Stop();

                if (songId >= 0 && songId < NUM_SONGS && Songs[songId] != null)
                {
                    FMODSystem.playSound(Songs[songId], null, false, out Channel);
                    UpdateVolume();
                    Channel.setMode(FMOD.MODE.LOOP_NORMAL);
                    Channel.setLoopCount(-1);

                    _current_song_id = songId;
                }
            }
        }

        public void UpdateVolume()
        {
            if(Channel != null)
                Channel.setVolume(Settings.GetInstance().MusicVolume / 100f);
        }

        public void Stop()
        {
            if (IsPlaying())
                Channel.stop();

            _current_song_id = -1;
        }
    }
}

let’s talk about CREATING the instance first.

I implemented MusicPlayer as a “singleton”: it’s constructor is private, but an instance is available via MusicPlayer.Instance.

I’ve got some FUNNY BUSINESS surrounding the instantiation of MusicPlayer.Instance, however:

the following code is required when compiling for both 32 and 64-bit systems. before using MusicPlayer.Instance, you will need to call MusicPlayer.Init().

        private static MusicPlayer _instance;

        public static MusicPlayer Instance { get { return _instance; } }

        [DllImport("kernel32.dll")]
        public static extern IntPtr LoadLibrary(string dllToLoad);

        public static void Init()
        {
            if (Environment.Is64BitProcess)
                LoadLibrary(System.IO.Path.GetFullPath("FMOD\\64\\fmod.dll"));
            else
                LoadLibrary(System.IO.Path.GetFullPath("FMOD\\32\\fmod.dll"));

            _instance = new MusicPlayer();
        }

the conditional LoadLibrary calls are the magic that make running on 32 and 64-bit platforms possible. you may notice the [DllImport("kernel32.dll")] call, and wonder why that’s always 32-bit… it isn’t! confusingly, even in 64-bit Windows, this file is still called “kernel32.dll”!

if you are ONLY targeting 32 OR 64-bit, however, you can replace the above mess with this:

        private static MusicPlayer _instance = new MusicPlayer();

        public static MusicPlayer Instance { get { return _instance; } }

all that funny business surrounding LoadLibrary is gone, and you no longer need to call MusicPlayer.Init() (giving us a much cleaner singleton!)

with that stuff out of the way, what other modifications will you need to make before using MusicPlayer in your code?

the most obvious changes would be to the CONSTs defined at the top. so obvious, I won’t even explain 😛

the MusicPlayer() constructor needs similarly-obvious modifications to load up the proper songs. also, make sure to update the LoadSong(...) method to point to whatever directory your music files are stored in.

finally, check out the UpdateVolume() method. for my game, I keep all the game’s settings in a singleton, which UpdateVolume() is looking at to determine how to set the music’s volume. you’ll need to change this method to grab the volume from wherever you keep it. (if you don’t have such a setting yet, just do Channel.setVolume(1f); note that the volume goes from 0.0f to 1.0f!)

oh, and you don’t HAVE to, but you’ll probably want to change the namespace from “MysteriousSpace” to whatever you’re using for your application.

alright: so how do we actually play music in your application?

  • first, if you’re doing the whole 32+64-bit messiness, call MusicPlayer.Init() before calling any other MusicPlayer method!
  • call PlaySong(...) to play a song, passing in the song id you want to play, for example: MusicPlayer.Instance.PlaySong(MusicPlayer.SONG_TITLE_MENU); the music will loop automatically (check out the PlaySong method to see how this is accomplished; hint: it’s accomplished easily!)
  • if you call PlaySong(...) while another song is playing, the previous song will be stopped, and the new one started! handy!
  • you can call MusicPlayer.Instance.Stop() to stop the music.
  • you can call MusicPlayer.Instance.IsPlaying() to see if a song is currently playing; you may not ever need to use this method, but it’s used internally by other MusicPlayer methods.
  • remember to call MusicPlayer.Instance.UpdateVolume() whenever you need to update the music volume. (for example, in my game, the player can access volume settings during gameplay; when the player changes the volume here, MusicPlayer.Instance.UpdateVolume() is called so that the volume change is applied immediately.)
  • call MusicPlayer.Instance.Unload() to unload FMOD as part of your application’s shutdown/exit code.

All Done!

I had a lot of trouble getting FMOD to work in my project; hopefully this article will save some other people the same trouble I had!

fun with assembly attributes (warning: this is a highly technical post)

since installing CrashReporter.net, I noticed that I haven’t really been storing Mysterious Space’s version information correctly. well, or not in a way that Windows really understands. as a result, my reports from CrashReporter.NET keep reporting version “0.0.0.0”.

I wanted to fix this.

and that lead down an exciting rabbit hole!

SO: in my code, I used to have a few variables, like this:

public const int VERSION = "0.7.5";
public const int RELEASE_YEAR = 2015;
public const int RELEASE_MONTH = 5;
public const int RELEASE_DAY = 24;

a single place for me to keep all the version-related info, that I always made sure to update when compiling for release.

at first I thought I wanted a way to get that VERSION into whatever field Windows and CrashReporter.NET were looking at, but I quickly realized this was backwards; what I REALLY wanted was for VERSION to be populated from the field that Windows and CrashReporter.NET look at: Windows keeps a bunch of application metadata in the “assembly”, including version number, copyright date… all that stuff you see when you right-click an executable and get its properties, and you can’t set that from a variable!

you can find all that stuff in your project’s AssemblyInfo.cs file, which has lines like this:

[assembly: AssemblyTitle("Mysterious Space")]

and this:

[assembly: AssemblyVersion("0.0.0.0")]
[assembly: AssemblyFileVersion("0.0.0.0")]

hey, those look like version numbers!

but what’s the difference between the two?

honestly, it’s all still a little confusing to me, but the details mostly seems to matter only when you’re building a library, or something; less so when building a stand-alone application. you can read all about it on StackOverflow.

but I also learned that there’s an AssmeblyInformationVersion, and THIS one is intended for display to users, and is listed in your file properties as “Product version”, which sounded EXACTLY like what I wanted, so: in goes:

[assembly:AssemblyInformationVersion("0.7.5")]

(it’s perhaps worth mentioning that CrashReporter.NET looks to the AssemblyVersion, so I made sure to set that, as well. though P.S. it irks me that I can’t #define VERSION "0.7.5" and then use that in both places, like I would be able to in C++. I want all the things in place! oh, god, did I just express a longing for C++? sorry, sorry. that was a mistake! :P)

at this point, I still wasn’t sure how I was going to get at this version string in the code, but something else was on my mind: “can I add my release date here, as well?”

I COULD have left it in as those const variables, but that bugged me, somehow. I want all this stuff in ONE PLACE, so that when I go to edit, say, the version string, I KNOW I’ll see the date, too, and so be sure to update it accordingly.

unfortunately, there isn’t a built-in field for storing a release date. fortunately, you can add ANYTHING YOUR HEART DESIRES through the use of custom assembly attributes.

you can google around for how to implement those, but here’s what I came up with for Mysterious Space:

using System;

namespace MysteriousSpace
{
    [AttributeUsage(AttributeTargets.Assembly)]
    class BuildDateAttribute: Attribute
    {
        public int Year { get; private set; }
        public int Month { get; private set; }
        public int Day { get; private set; }

        public BuildDateAttribute(int year, int month, int day)
        {
            Year = year;
            Month = month;
            Day = day;
        }
    }
}

which allows me to add, in my AssemblyInfo.cs file:

[assembly:BuildDate(2015, 5, 24)]

awesome!

but NOW: how do we get at that information from within the game code? for example, I display the game’s version and release date in the lower-left of the title menu.

well, the AssemblyInformationalVersion is easy to get at:

string version = Application.ProductVersion;

(you’ll need to be using System.Windows.Forms; to get the Application object.)

getting at custom attributes is a bit trickier, though, and again, in the interest of keeping all this stuff in one place, I created yet another class:

using System.Reflection;
using System.Windows.Forms;

namespace MysteriousSpace
{
    public class BuildInfo
    {
        public string Version { get; private set; }
        public int Year { get; private set; }
        public int Month { get; private set; }
        public int Day { get; private set; }

        public BuildInfo()
        {
            Version = Application.ProductVersion;

            BuildDateAttribute[] attributes = (BuildDateAttribute[])Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(BuildDateAttribute), false);

            Year = attributes[0].Year;
            Month = attributes[0].Month;
            Day = attributes[0].Day;
        }
    }
}

excellent.

now I can just make a new instance of BuildInfo, and I’m good to go. since I’m using MonoGame, I added a public static variable on my main Game object (which I creatively called TheGame), and initialize it before calling Run(). this way, it’s available anywhere:

string releaseDate = TheGame.Build.Year + "-" + TheGame.Build.Month + "-" + TheGame.Build.Day;

ta-da! at last!

as it always is with code, there are many possible solutions to the same problem. I happened to feel strongly that all this information should be in one place, and that lead to the addition of two new classes to my code! overkill? *shrugs* I think it’s cool, and I learned how to do some new stuff. I’m’a call that a win 😛

crashes are bad, mkay; 0.7.2 features a crash reporter

my friend Stephen let me know tonight that Mysterious Space doesn’t start up for him AT ALL!

whoa!

this made me realize that I’m really going to need some kind of crash reporting software! after all, while I can probably convince my friend to go through his system error logs, or maybe send an stderr dump, I can’t ask anyone else!

I imagined that this would have to be some EXTRA piece of software that kind of stood separately, and watched, waiting for a crash, and started googling on that premise… fortunately, nothing so complicated is needed!

I found this delightful C# library: CrashReporter.NET

it’s super-easy to set up, requiring very few lines of code, has a very permissive license, and seems – so far – to JUST WORK: it e-mails a stack trace, screenshot, and whatever the user chooses to type and send to whatever e-mail address you specify! awesome!

I was planning on getting some more changes into 0.7.2 (including some much-needed translation work), but the addition of a crash reporter seemed significant enough to warrant an immediate release, so out it goes!

there were a couple little gameplay fixes as well; check out the full changelog for details

omg, I’m on Steam!

seeing the game in Steam… finding it in the store… pressing “PLAY”… I’m literally sitting here laughing and pulling my shirt up over my face saying “oh my god”, a tear forming in the corner of one eye. it’s so exciting! it’s so crazy!

I just… this has been a really cool experience. it’s been a lot of fun, awesome work, and I WOULD NOT have done it if I hadn’t happened to participate in 2014’s “make a rogue-like in 7-days” challenge: the 7DRL. (Google it! participate!) and I WOULD NOT have done it if I hadn’t had awesome friends – like Stephen, and Katie, and Steve, and Sandy, and my dad – willing to play, and do videos with me on YouTube, and everything else. and I WOULD NOT have done it if groupees.com hadn’t stumbled upon my game and thought “huh, this looks cool; let’s contact this random Ben guy and see if he wants to be in a bundle.” and on and on…

but moreover, while this is in some ways “special”, it’s also quite ordinary! anyone can do this; many people already have. I’ve never thought about publishing on Steam before; I didn’t try to get included in a bundle; I just made a thing, and I kept it making, and people happened to like it. and it still isn’t even THAT MANY people who do. PsyPets, for example, has been way more successful than Mysterious Space (so far :P) and I have made MANY things before that people DIDN’T like, and I DIDN’T keep making, and never got anywhere! and I’ll probably make many more things that similarly go nowhere.

so go! make a thing! participate in funny challenges that force you do things you’ve never done before! if it’s great, keep working on it; if it continues to be great, KEEP WORKING ON IT! publish to something you respect; laugh excitedly; wipe a tear from the corner of one eye!

thanks, 7DRL, and everyone who participates and judges!

thanks, Steve, for reminding me that Mysterious Space existed, and deserved to be worked on!

thanks, Stephen, for all your awesome advice, and doing a YouTube video with me!

thanks, Sandy, Katie, dad… and probably other people. I’m super-sorry and embarrassed if I forgot to list you; I’m a terrible friend.

thanks, Annette, for taking over PsyPets! I could not have taken care of both PsyPets and Mysterious Space; both would have suffered!

thanks, groupees.com for inviting me to be in your sci-fi bundle!

thanks, DDRKirby(ISQ), for making – and continuing to make – AMAZING music for me!

thanks, Markieer, for making a trailer!

thanks, Steam, and everyone who upvoted Mysterious Space, commented on it, and left feedback – good or bad!

thank you, everyone, whatever your level of involvement!

Mysterious Space is now on Steam!

last night I dreamed that I released 0.7.0 with a bug that crashed the game, and was frequently encountered

fortunately it was just a dream. but I wish I remembered what the bug was, so I could test it, just to be SUPER SURE 😛

0.7.0 is released! get it at either of these two familiar places:

this week I’ll be focusing on getting a Steam release. not sure if it’ll take a week, less than a week, or more than a week, but I’ll definitely keep you guys posted 🙂

0.7.0! (to be released later this week or weekend!)

(check out the current, development changelog, if you like!)

what I was expecting to be a small update has become rather large, in a strange sort of way: gameplay is entirely different due to a whole new class of item – Advanced Technology – along with cursed/blessed items, and the new “weakened” state that items may suffer.

it’s kind of crazy! I feel like this has been one of the more “efficient” updates I’ve made (at least so far; there’s still some work to do!) in terms of gameplay gains for time taken. sure, coding all the curses and blessings has been a lot of work, but not nearly as much as thinking up, drawing, animating, and balancing just one new mini-boss!

the previous update – 0.6.5 – was pretty big, too, with new enemies, equipment, a new mini-boss, and some graphical improvements… but it didn’t quiiiite add anything new or truly game-changing.

combined with all the new mechanics surrounding Advanced Technology, though, I feel like it’s really a new milestone in Mysterious Space.

and so: 0.7.0!

a part of me does wonder: is it worth making such a to-do over version numbers? *shrugs*

in some ways, maybe not: they’re just a label. the changes are there regardless. but I guess I really do see these last couple changes as being strong additions to the game. they feel like they’re worth celebrating, in some way. like your age is just your age; the current year is just the current year. they’re all labels. but they tell us something. the 90s were the 90s, the 2000s were the 2000s, and Mysterious Space 0.6.x was Mysterious Space 0.6.x.

when will 0.7.0 be released? I’m aiming for sometime later this week, or possibly during this weekend. I’ve got some testing to do, and I’d like to add more – and more-interesting – Advanced Technology effects. (for example: spoiler: today I implemented what you might call a “polymorph self” effect, turning your ship into some other ship entirely!)

I’ll probably post another update video sometime during the week, and announce a more-precise release date.

until then, thanks for following along!

and thanks for playing! 🙂

(and again: check out the current, development changelog, if you like!)

Encyclopedia Magica

when I was little, I played a super-old DOS game called DND. it wasn’t really a D&D game (it shared the list of core stats, but not much else), OR a rogue-like (there was permadeath, but the dungeons were not procedurally generated). not that I knew about either of those things at the time, but DND got me interested in both.

it so happened that my dad had played D&D in highschool or college (I forget which…), so he was able to tell me about it, and I was instantly interested, and began saving all my allowance money for D&D books, even though I had no one to play with.

the purchase I was most proud of, and which I still sometimes use today, is the Encyclopedia Magica: a collection of four colored – and yes, I’m about to call them “tomes” – tomes.

Encyclopedia Magica

the first book is 400 pages of magic items, and each subsequent book is longer, with the fourth being 1500 pages (excluding the index)!

I was going to write something like “from the FIRST ITEM IN THE FIRST BOOK to the LAST ITEM IN THE LAST BOOK, bla-bla-bla, a wealth of ideas,” but the first item is the first book is the “Abacus of Calculation”, which is probably among the least-inventive things you could come up with.

so let’s look at some Wands of Wonder, instead:

Encylcopedia Magica - Wand of Wonder

the Wand of Wonder is perhaps one of the more (in)famous items in D&D. you point it at whatever you want, and roll a 100-sided die (or, more likely, two 10-sided dice) to determine what happens. sure, it might shrink the target to half their size, or throw a lightning bolt at them, but it might also just summon a swarm of “attack butterflies (no effective attack)”, cause the target to uncontrollably recite bad poetry, or cover the both of you in warm, gooey chocolate.

the reason I love these books today is that the entire collection acts as a sort of wand of wonder. if I ever need a ideas – be it for a table-top role-playing game, or a video game – I can just open one of these up, and flip around.

and right now, I find myself with a problem: I need more unique “blessings” and “curses” to give to equipment in Mysterious Space, but am running out of ideas. many of them are just variations on existing mechanics, but something DIFFERENT would really make the system stand out.

so let’s see here… I’ll grab, um, the first book, and open up about 3/4 through…

“Cursed Copper Piece”? *reads* god, no, that’s… that’s a terrible item. uh. let’s see…

Noora’s Ring of Djinn Summoning

Noora’s ring is similar in many ways to a standard ring of djinn summoning. Noora’s ring, however, will summon a tasked artist genie known as Akmed. Akmed is a skilled weaver and can produce some of the finest cloth, fabrics, and rugs ever seen in Zakhara. Akmed often gives his work to Noora so that she may present them to others as gifts. Noora uses these gifts to solidify alliances, reward services well done, or simply as tokens of friendship.

that is both a weirdly-vague and also weirdly-specific item. most old-school D&D items will be like “you can use it only three times a day, and not for more minutes than you roll on two six-sided dice, and you can’t use it along with this other item in order to do bla-bla-bla”. also, I don’t think most of them tell you what their OWNER might use it for. we may have learned as much about Noora as we did her ring!

but those kinds of details are actually really cool! I’m kind of happy about how non-D&D this item is… like, it COULD have just been a magic stone that you put on the ground, and a rug appears under it, or whatever. similarly, in Mysterious Space, I COULD make an item that just creates another item without explanation, and I doubt anyone would think twice about it. but what if, instead, using the item causes some broken alien AI hologram to appear, all like “he–o Noora. –t can I –p you wi– –oday?” and you pick from a menu of broken options, and you get a random one of the selected things.

THAT would be way cooler.

not quite the inspiration I was expecting – I’m, again, more-used to D&D items with layers upon layers of rules and dice rolls, and maybe even tables – but hey: I’ll take it!

look forward to dialogs with broken alien AI holograms next release 😛 haha

“scroll of enchant weapon”

Mysterious Space already has “potions” in the game, via Alien Artifacts, but I’d like to add “scrolls” as well. These will be rarer, and often have permanent effects, including “blessing” and “cursing” equipment, in the Roguelike tradition.

it’s something I’ve been considering adding for a while, but today I happened to read @Play: The Eight Rules of Roguelike Design, which convinced me to work on this now, rather than later!

of course, Mysterious Space will not use words like “scroll”, “bless”, or “curse”, but I haven’t decided on the vocabulary yet, so for now, I will refer to them using these words.

I’m handling blesses and curses a little differently in Mysterious Space, by giving each piece of equipment a blessing or curse specific TO that piece of equipment.

for example, when an EMP Resistant shield is blessed, it grants a temporary shield whenever you’re slowed; when cursed, slowing disables the shield entirely.

when Regenerating Armor is blessed, it fires bullets around you when it’s at full strength; when cursed, it’s permanently destroyed if the armor is reduced to 0.

as a final example, the RNG blaster imposes random effects on the player; good effects when blessed (such as doubling weapon fire rates, granting haste, etc); bad effects when cursed (including getting randomly teleported, being slowed, etc).

blessings and curses can also be layered on multiple times, for stronger effects. in a few cases – such as the Regenerating Armor’s permanent destruction – the effect can’t get any stronger, but in most cases, it can. for example, effect durations such as slow and haste will get longer, and the RNG blaster will apply it’s good/bad effects more frequently.

since I’ve chosen to customize the effects for each piece of equipment, it’s a lot of work. there are 9 accessories, 9 armors, 10 shields, and 13 weapons. but I think it will be worth it.

and this is all for just TWO effects that the scrolls will have: curse equipment and bless equipment. I haven’t even started on the other effects, yet, or even figured out what they’ll all be.

I want to look at some roguelike wikis for inspiration, but so far I’m considering:

  • permanent hull upgrades
  • locking an equipment slot for a few levels
  • slowing all enemies on the screen
  • teleporting the user
  • disabling all weapons for a few seconds
  • revealing the locations of all fuel on the level
  • destroying terrain in a circle around the player
  • spawning a bunch of enemies

why bother with all this work? to add more depth and strategy to the game! destroying terrain in a circle could be anything from a time saver to a life saver, depending on when it’s used. spawning enemies is usually bad, but if you’re doing well for the level you’re on (or have a smart bomb effect handy), it might provide some quick extra loot. and the opportunity to bless equipment gives the old “do I bless now, to increase my survival, or save it for a better item?” dilemma that roguelikes have been enjoying for decades.

I’m not sure when I’ll get all this stuff in, but I’ll definitely keep you posted, and get a video together, at some point, to showcase some of the new effects, when they’re ready 🙂