Please login or register.

Login with username, password and session length
Advanced search  


This forum provides RSS feed. To query recent posts use this url. More...

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Topics - MrBehemoth

Pages: [1]
General Discussion / The Trapdoor
« on: April 21, 2014, 03:26:30 PM »
Completely unrelated to WME, but thought you guys might to check the trailer for The Trapdoor, an Amnesia mod that I made. It's on my site:

Release date is set for 30/04/14 on and ModDb. It's been a lot of fun to make, but I'm also looking forward to getting back to work on with WME Black Aether.

Edit: I typed Steam Workshop but I meant ModDb. What a faux pas!

General Discussion / link to something I wrote about WME
« on: March 03, 2014, 02:00:01 AM »
Hi, thought I'd mention that I've just posted a wee write up of WME on my site:

Call this, if you will, a shameless attempt to get traffic and interest in my games, but I wrote it because I felt like I should give something back to Mnemonic and to the WME cause (and I'm not currently in a position to make a donation, but hope to soon).


Scripts, plugins, utilities, goodies / Array methods
« on: January 25, 2014, 03:46:05 PM »
I've made some custom methods for working with arrays. They're mostly pretty simple, but handy to have in the toolbox. It's nice to share, so here they are! (Code below.)

ArraySplice(InputArray, SpliceIndex, DeleteLength, InsertArray)                 
Removes and inserts elements in an array and returns a copy of it.         InputArray    Array    The array to be modified
          SpliceIndex    Int    The index of the first element to be deleted and the point to insert new elements
          DeleteLength    Int    The number of elements to be deleted, including the element at SpliceIndex
          InsertArray    Array    The array to be inserted (optional)

ArraySlice(InputArray, SliceIndex, SliceLength)                 
Returns a portion of an array.          InputArray    Array    The array to be extracted from
          SpliceIndex    Int    The index of the first element to be returned
          DeleteLength    Int    The number of elements to be returned, including the element at SliceIndex

ArrayConcat(InputArray1, InputArray2)                 
Returns an array made by joining two arrays together.          InputArray1    Array    The first array to join
          InputArray2    Array    The second array to join

Returns an array that is the input array in reverse order.          InputArray    Array    The array to be reversed

ArraySort(InputArray, Descending)                 
Sorts a numeric array and returns a copy of it.          InputArray    Array    The array to sort. Must contain only numbers or integers
          Descending    Boolean    If true, the sort will be from highest to lowest (optional)

ObjectArraySort(InputArray, Descending, Renumber)                 
Sorts an array consisting of objects.          InputArray    Array    The array to sort. Must contain only objects, which must all have a property "Index"
This was made for a specific purpose.          Descending    Boolean    If true, the sort will be from highest to lowest (optional)
You may or may not find it useful!          Renumber    Boolean    If true, the objects' "Index" properties will be updated to reflect the new order (optional)

And finally, here's all the code:
Code: WME Script
  1. method ArraySplice(InputArray,SpliceIndex,DeleteLength,InsertArray)
  2. {
  3.         var ReturnArray = new Array();
  4.         var i;
  5.         if(DeleteLength == null) DeleteLength = 0;
  6.         for(i = 0; i < SpliceIndex; i = i + 1)
  7.         {
  8.                 ReturnArray.Push(InputArray[i]);
  9.         }
  10.         if(InsertArray != null)
  11.         {
  12.                 for(i = 0; i < InsertArray.Length; i = i + 1)
  13.                 {
  14.                         ReturnArray.Push(InsertArray[i]);
  15.                 }
  16.         }
  17.         for(i = SpliceIndex + DeleteLength; i < InputArray.Length; i = i + 1)
  18.         {
  19.                 ReturnArray.Push(InputArray[i]);
  20.         }
  21.         return ReturnArray;
  22. }
  24. method ArraySlice(InputArray,SliceIndex,SliceLength)
  25. {
  26.         var ReturnArray = new Array();
  27.         var i;
  28.         for(i = SliceIndex; i < SliceIndex + SliceLength; i = i + 1)
  29.         {
  30.                 ReturnArray.Push(InputArray[i]);
  31.         }
  32.         return ReturnArray;
  33. }
  35. method ArrayConcat(InputArray1,InputArray2)
  36. {
  37.         var ReturnArray = new Array();
  38.         var i;
  39.         for(i = 0; i < InputArray1.Length; i = i + 1)
  40.         {
  41.                 ReturnArray.Push(InputArray1[i]);
  42.         }
  43.         for(i = 0; i < InputArray2.Length; i = i + 1)
  44.         {
  45.                 ReturnArray.Push(InputArray2[i]);
  46.         }
  47.         return ReturnArray;
  48. }
  50. method ArrayReverse(InputArray)
  51. {
  52.         var ReturnArray = new Array();
  53.         var i;
  54.         for(i = InputArray.Length - 1; i >= 0; i = i - 1)
  55.         {
  56.                 ReturnArray.Push(InputArray[i]);
  57.         }
  58.         return ReturnArray;
  59. }
  61. method ArraySort(InputArray,Descending)
  62. {
  63.         var ReturnArray = new Array();
  64.         var i;
  65.         var ii;
  66.         var InsertPos;
  67.         var InsertArray;
  68.         ReturnArray.Push(InputArray[0]);
  69.         for(i = 1; i < InputArray.Length; i = i + 1)
  70.         {
  71.                 InsertPos = -1;
  72.                 for(ii = ReturnArray.Length - 1; ii >= 0 ; ii = ii - 1)
  73.                 {
  74.                         if(InputArray[i] > ReturnArray[ii])
  75.                         {
  76.                                 InsertPos = ii + 1;
  77.                                 break;
  78.                         }
  79.                 }
  80.                 InsertArray = new Array();
  81.                 InsertArray.Push(InputArray[i]);
  82.                 if(InsertPos > -1) ReturnArray = ArraySplice(ReturnArray,InsertPos,0,InsertArray);
  83.                 else ReturnArray = ArrayConcat(InsertArray,ReturnArray);
  84.         }
  85.         if(Descending) ReturnArray = ArrayReverse(ReturnArray);
  86.         return ReturnArray;
  87. }
  89. method ObjectArraySort(InputArray,Descending,Renumber)
  90. {
  91.         var ReturnArray = new Array();
  92.         var i;
  93.         var ii;
  94.         var InsertPos;
  95.         var InsertArray;
  96.         var InputObject;
  97.         var ReturnObject;
  98.         ReturnArray.Push(InputArray[0]);
  99.         for(i = 1; i < InputArray.Length; i = i + 1)
  100.         {
  101.                 InsertPos = -1;
  102.                 InputObject = InputArray[i];
  103.                 for(ii = ReturnArray.Length - 1; ii >= 0 ; ii = ii - 1)
  104.                 {
  105.                         ReturnObject = ReturnArray[ii];
  106.                         if(InputObject.Index > ReturnObject.Index)
  107.                         {
  108.                                 InsertPos = ii + 1;
  109.                                 break;
  110.                         }
  111.                 }
  112.                 InsertArray = new Array();
  113.                 InsertArray.Push(InputArray[i]);
  114.                 if(InsertPos > -1) ReturnArray = ArraySplice(ReturnArray,InsertPos,0,InsertArray);
  115.                 else ReturnArray = ArrayConcat(InsertArray,ReturnArray);
  116.         }
  117.         if(Descending) ReturnArray = ArrayReverse(ReturnArray);
  118.         if(Renumber)
  119.         {
  120.                 for(i = 0; i < ReturnArray.Length; i = i + 1)
  121.                 {
  122.                         ReturnObject = ReturnArray[i];
  123.                         ReturnObject.Index = i;
  124.                         ReturnArray[i] = ReturnObject;
  125.                 }
  126.         }
  127.         return ReturnArray;
  128. }


Technical forum / optional parameters in a custom method
« on: January 25, 2014, 11:52:04 AM »
This might be a dumb question (or at least a question that shows I'm still learning as I go!) but how do you use optional parameters in a custom method definition?

For example, how would you get something like this to work:

Code: WME Script
  1. method TestMethod(param1)
  2. {
  3.   Game.Msg("You called TestMethod with 1 parameter: "+param1);
  4. }
  6. method TestMethod(param1,param2)
  7. {
  8.   Game.Msg("You called TestMethod with 2 parameters: "+param1+","+param2);
  9. }

...Obviously that just makes a duplicate declaration. Is it even possible for custom methods?

Scripts, plugins, utilities, goodies / Soundscape Manager
« on: January 05, 2014, 06:41:25 PM »
Hi Muties! I made this soundscape manager and thought I would share it. The download link is at the bottom of the post.

What is it for?
Soundscape Manager will generate layered, randomised ambient sound enviromnents (soundscapes) on the fly. For example, lets say you have a cave scene. You can use a soundscape to play randomly placed dripping sounds and rock noises. Other uses could be crowd scenes, cities with traffic, wind, forest sounds, etc.. Use it instead of creating a single looped ambient sound track and it will be less repetitive, more realistic and reduce file size.

What does it do?
The soundscape manager is an entity that you load from your game.script. The soundscapes themselves are defined by text files called something.soundscape. There are 3 channels. Each channel can be either randomised or looped. Randomised channels can have up to 5 sound files. The volume, pan and delay between each channel is randomised based on the values in the text file. You start a soundscape by calling a method from your scene_init.script (or wherever your like). The soundscape will continue playing across scenes (without a gap) until you stop it or change to a different soundscape.

How do I use it?
Copy the contents of the zip into your project folder. You'll now have a soundscapes folder. In there you will find an example soundscape called cave.soundscape and a template.soundscape to help you with making your own. Into this folder goes your sound files such as drips, wind bursts, birds tweeting etc.. There is also a subfolder that contains the Soundscape Manager entity and script.

To load the Soundscape Manager, add this to your game.script:
Code: WME Script
  1. global SoundscapeMgr = Game.LoadEntity("soundscapes\soundscapeMgr\soundscapeMgr.entity");

To start a soundscape or change to a different one, call this method:
Code: WME Script
  1. global SoundscapeMgr;
  2. SoundscapeMgr.ChangeSoundscape("cave");
Where cave is the name of the soundscape file (e.g. cave.soundscape).

What goes in the something.soundscape text file?
Compare the example and the template files. The template.soundscape file looks like this:
Code: [Select]
fade_in_time (ms: time for whole soundscape to fade in when started)
fade_out_time (ms: time for whole soundscape to fade out when stopped/changed)
type (bool: 0=random sounds, 1=single looping sound)
channel_0_sound (filename without path or ext, or "null")
channel_0_sound (filename without path or ext, or "null")
channel_0_sound (filename without path or ext, or "null")
channel_0_sound (filename without path or ext, or "null")
channel_0_sound (filename without path or ext, or "null")
channel_0_min_volume (%: minimum random volume)
channel_0_max_volume (%: maximum random volume)
channel_0_min_delay (ms: minimum length of the random time between sounds)
channel_0_max_delay (ms: maximum length of the random time between sounds)
channel_0_random_pan (bool: 0=centred, 1=randomly panned)
type (bool: 0=random sounds, 1=single looping sound)
channel_1_sound (filename without path or ext, or "null")
channel_1_sound (filename without path or ext, or "null")
channel_1_sound (filename without path or ext, or "null")
channel_1_sound (filename without path or ext, or "null")
channel_1_sound (filename without path or ext, or "null")
channel_1_min_volume (%: minimum random volume)
channel_1_max_volume (%: maximum random volume)
channel_1_min_delay (ms: minimum length of the random time between sounds)
channel_1_max_delay (ms: maximum length of the random time between sounds)
channel_1_random_pan (bool: 0=centred, 1=randomly panned)
type (bool: 0=random sounds, 1=single looping sound)
channel_2_sound (filename without path or ext, or "null")
channel_2_sound (filename without path or ext, or "null")
channel_2_sound (filename without path or ext, or "null")
channel_2_sound (filename without path or ext, or "null")
channel_2_sound (filename without path or ext, or "null")
channel_2_min_volume (%: minimum random volume)
channel_2_max_volume (%: maximum random volume)
channel_2_min_delay (ms: minimum length of the random time between sounds)
channel_2_max_delay (ms: maximum length of the random time between sounds)
channel_2_random_pan (bool: 0=centred, 1=randomly panned)

To make a new soundscape, just edit the template and you should end with something that looks like the "cave.soundscapes" file:
Code: [Select]
This soundscape takes 2000ms to fade in or out. In channel 0 there are 3 drip sounds which play at a volume between 10-100% with a random gap of 3000-6000ms between each play. The channel is randomly panned, so each play will be at a different left-right position. Channel 1 is similar. In channel 2 there is a single looped sound that plays continuously at full volume and does not pan.

  • For the filenames (the sounds and the something.soundscape files) you only need to give the name of the file, not the path or the extension. Just make sure everything is in the soundscapes folder and named correctly.
  • The script looks for OGG FILES, so make sure your sound files are .ogg format. (If you really want to use .wav files, you can edit lines 224-292 of soundscapeMgr.script.)
  • The soundscript files are read line-by-line, so don't mess with the layout.
  • The 3 lines with the slashes are just for spacing (i.e., lines 3,15 and 27). You can't put comments anywhere else, but anything in these lines will be ignored.
  • Remember to use "null" for a file listing that is not used (as in cave.soundscript above).
  • You can use a random volume and pan for the looping sounds if you want to, but they will pick a volume a pan when they first start to play an then not change.
  • You can't change the soundscape if another change is already in progress (i.e., it's currently fading in or out).

Here's the half-baked pseudo license note from the script:
Originally developed for Black Aether by Behemotronic Games. This code is distributed free for non-commercial use. Please feel free to use it in your own projects as long as you let me know so that I can check out what you've done with it. Please don't plagiarise or use it in commercial projects. This is provided "as-is" and has only had minimal testing. I take no responsibility blah blah blah.

Finally, here's the download link:
And if you just want to try it out, here's a simple test project of Molly in a cave:

Obviously, you can do a lot more with this than just make cave sounds. Thanks and have fun! Any questions, just ask.

Technical forum / physics: just a thought...
« on: December 31, 2013, 05:38:26 PM »
Hi folks. Just wanted to run something by you all - just an idea I've been thinking about. I've not done any real research or tried anything out yet... I might just be dreaming...

I've mentioned on other threads that I've used Flash a lot in the past. Something I've enjoyed is playing about with is 2D physics, for example these 2 flash toys: Capering Calavera and Shmetris (Use the mouse to interact in both. Mnemonic and anyone else who worked on Wilma Tetris might appreciate Shmetris!)

Anyway... these were made using Box2dFlashAS3 a Flash/AS3 port of the excellent Box2d rigid body physic engine, which is written in C++ and available on the zlib licence, although I've only ever used the Flash port myself.

Now I'll admit that I don't know much about dlls or writing plugins for WME (that is, I don't know anything) but I was wondering if anyone could shed any light on how easy/difficult it would be to create a 2D physics plug-in for WME, maybe using Box2D...?

Implementation aside, if such a thing was possible, I imagine that how it would work would be that if you wanted some entities to be physics enabled in your scene, then Box2D would be simulating it in the background and your entity would query the plugin for the x and y of the body it is representing and update it's position in the scene / it's position on the screen. Obvious this would only work in scenes/games that are truly 2D, i.e., no perspective.

Does anyone have any thoughts on this? Is it worth investigating? Mnemonic, do you see any potential issues?

Thanks for ideas, input, etc.

Game announcements / Bickadoodle
« on: December 29, 2013, 07:29:26 PM »
I took a break from working on my long term project to make Bickadoodle, a short game which was a Christmas present for my wife. She suggested I share it, so I thought I'd let my fellow muties have a go before anyone else.

Update: 08/02/13 It's now available to everyone on my new website Aetheric Games.

Bickadoodle is a comedy stick-man fairy-tale with a twist. Laugh! Vanquish evil! Use magic potions! Quest for treasure! Ride your very own horse! Find true love?

You can get more info, watch the trailer or download Bickadoodle here:

This is a very slightly updated version, now with an installer and with the game content distributed on the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International licence (subject to Mnemonic's WME licencing of course).

Cheers, MrBehemoth

Game design / Back to the old school
« on: November 03, 2013, 07:46:09 PM »
Hi folks. I've just returned to WME after a long absence. It's nice to be back! Since I've learnt a lot in the meantime I thought I'd share some experiences with you all.

For a few years now I've been working on a game called Black Aether (I'll announce it officially when it's closer to release). The story and art style have been brewing in my mind for even longer. The first incarnation was in Wintermute. I made most of the first chapter in 2008 or so. At the time my coding was ok, not great, and there were a lot of things I wanted to make Wintermute do that I couldn't figure out. I was quite familiar was Flash (AS2), though, and I made the decision to abandon the WME version and develop a purpose built graphic adventure engine in Flash.

It took a year or so to admit to myself that that'd been a bad idea. Aside from the fact that 99% of what I wanted my engine to do was already in place in WME, I realised I needed to learn AS3 and learn about all kinds of techniques like navigation. Long story short, through Black Aether and other projects, my coding improved to the point where I would have been able to do what I'd wanted to do in Wintermute in the first place, but not enough so that I could realistically code an engine from scratch. Besides, Flash is not the best way to do it for a ton of different reasons.

My homemade engine was about 75% complete when I got the idea into my head that I should abandon the 2d art style I'd developed and start again in a first-person 3d engine. Black Aether is a scary game with survival horror elements: I'd seen and played games like Amnesia, and I wanted to move in that direction. Since I've also been modding Valve's Source engine for years, I set to work on TC that brought an inventory and dialogue trees into Source. This was hard work and I learned even more about OOP. I finally got eveything in place and got back to work on game content.

The Source version of the game was certainly pretty, and immersive, but it was no longer the game I'd originally had in mind. In terms of playable content, the game was almost at the end of chapter one, at about the point where I'd left of with WME. Eventually (last week) frustrations with a constantly evolving engine, game breaking updates and poor communication between engine developers and modders, coupled with doubt over the new art direction of the game lead me to reconsider everything I'd done since Wintermute and, well, here I am, ready to get stuck in again.

Here's a summary of what I've learned:

1) Wintermute is exceedingly versatile. Just because you can't figure out how to code something doesn't mean it can't be done. Maybe you just need to level-up your coding and problem solving skills and come back later.

2) Mnemonic has done stellar work on WME over the years. One person committed to making a great engine is better than a big company who don't have indie developers in mind. (I still love Valve's games, I've just fallen out of love with Source.)

3) I tried to re-invent the wheel. I can now see that it wasn't necessary.

4) First person and 3d are not prerequisites for immersiveness.

5) Story and art are sacred and fundamental to experience. Don't compromise them to keep up with trends.

6) There's no school like the old school  ::rock, and there's still lots of room for innnovation in P&C graphic adventures.

I hope that will save someone some time some day, or maybe spark a discussion. Any comments appreciated.


Pages: [1]

Page created in 0.046 seconds with 23 queries.