Show / Hide Table of Contents

    AGS Cheat Sheet

    This is a "cheat sheet" for people coming in from AGS. The "cheat sheet" is divided into 2 sections. The first section roughly demonstrates the language differences between AGS script and c#. The second section goes over the AGS scripting API (individual functions and properties) and compares them with AGS: it shows how to do the same in MonoAGS, or if something is missing, and also explaining some differences between the two, with brief highlights of things that don't exist in AGS but do exist in MonoAGS.

    General Scripting Differences

    C# has a lot of similarities to AGS Script, but there are also many differences. In some sense, c# is simpler than AGS script (no pointers, no script headers, the order of the scripts doesn't matter), and in another sense it's more complicated (all functions need to be wrapped in classes/structs, and there are a lot more keywords). Let's go over the main differences:

    Writing Functions

    In AGS, a common function signature might look like this:

    
    function do_something(int param)
    {
        // contents of function go here
    }
    

    The equivalent in c# would look like this:

    
    void do_something(int param)
    {
        // contents of function go here
    }
    

    The only difference here is that instead of function we wrote void. void is a keyword that means that the function doesn't return anything. In c#, when you write a function, you need to declare what the function returns.

    So, if the AGS function returns an int, like this:

    
    function do_something(int param)
    {
        return 5;
    }
    

    The c# equivalent function will look like this:

    
    int do_something(int param)
    {
        return 5;
    }
    

    Another big difference is that in AGS we can write a function anywhere in the file. In c#, the functions need to be written inside either a class or a struct, and that needs to be wrapped inside a namespace. A namespace is used to group multiple classes together, you shouldn't usually worry about this, when you add a new code file from the editor the namespace is automatically generated and written to the file.

    A c# struct is identical to the AGS struct, and a c# class represents a reference type, which basically means it's an instance that you can carry around: this is basically the replacement to pointers in AGS. It's not critical to understand this at first, as almost always you'd want to use a class. If you want to dig deeper and understand when you'd like to use a struct, this link is a good start: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/choosing-between-class-and-struct

    A single class can contain multiple functions, and is usually used to group functions which revolve around the same purpose. So, in our example, we'll put the do_something function in a class like this:

    
    namespace MyGame
    {
        class MyClass
        {
            int do_something(int param)
            {
                return 5;
            }
        }
    }
    

    Returning multiple values from a function

    If you want to return multiple values from your function in AGS script, you'd have to create a struct especially for that purpose, which complicates things. In c#, you can just use tuples for this:

    
    (float x, float y) get_position()
    {
        return (100, 200);
    }
    

    You can now call this function easily like this:

    
    (float x, float y) = get_position();
    Debug.WriteLine($"X = {x}, Y = {y}");
    

    Variables & Scope

    Variables in c# are declared the same way as in AGS script, with the difference that, like functions, the variables need to reside inside the class/struct.

    Variables can also declared inside a function, this would make their scope local to the function, meaning that the variable will not exist once the function completes.

    Here's an example:

    
    namespace MyGame
    {
        class MyClass
        {
            string var1;
            string var2 = "Hello";
    
            int do_something(int param)
            {
                string var3 = "Hi";
    
                var1 = "aaa";
                var2 = "bbb";
                var3 = "ccc";
    
                return 5;
            }
    
            int do_something2()
            {
                var1 = "aaa";
                var2 = "bbb";
                var3 = "ccc"; //THIS DOES NOT COMPILE, var3 does not exist!
            }
        }
    }
    

    In the example above, var1 and var2 are class variables, so they can be used anywhere within the class. var3 however, is local to the do_something function, so it cannot be accessed from the do_something2 function.

    Exporting functions & variables

    In AGS script, in order to be able to access a function from different script, you need to add an import to it in your exporting script header, and in order to export a variable you need to add an export to it and that export must reside in the end of the file.

    In c#, there is no script header file: both functions and variables can be exported simply by prefixing them with the keyword public, like this:

    
    public string var1;
    
    public int do_something()
    {
        return 5;
    }
    

    Static vs instance

    Another big difference that needs to be understood, is the different between static functions/variables to instance functions/variables. In AGS, functions and variables that are declared inside a struct are instance functions/variables, but all other functions and variables that you code are static.

    In c#, however, all functions/variables are instance by default, unless you explicitly make them static. The difference is that instance functions/variables are associated with instances that are generated from the class (which can be looked at like a blueprint for creating instances), while static variables belong to the class itself.

    If I have a Dog class to represent a dog, and a health variable that gives a number between 0-100 to say how healthy the dog is, then health should be an instance variable: if I create 3 different dogs, they should have 3 different health states. If, on the other hand, I have a Utilities class with random scripts, and among them I have a sum_two_numbers function, that function makes sense as a static function, there is no point in having 2 (or more) "Utilities".

    In c#, to have a function (or variable) static, you prefix it with the keyword static.

    So the 2 examples from above would look like this:

    
    namespace MyGame
    {
        class Dog
        {
            public int Health;
        }
    
        class Utitilies
        {
            public static int sum_two_numbers(int x, int y)
            {
                return x + y;
            }
        }
    }
    

    Importing functions & variables

    In AGS, to import functions/variables you need to add an import for them in the script header. In c#, assuming both files are using the same namespace, you can call them without adding anything specific.

    How you call the functions/variables in c# depends if they are static or instance functions/variables. For static functions/variables you need to prefix the class name and a dot before the function/variable. For instance functions/variables you need to create a new instance of your class using the new keyword, assign that to a variable, and then you can call that instance's functions/variables by prefixing it with the variable name and a dot.

    As an example, let's use or Dog and Utilities classes from the previous example in a different file:

    
    namespace MyGame
    {
        class MyClass
        {
            Dog dog1 = new Dog();
            Dog dog2 = new Dog();
    
            void init()
            {
                dog1.Health = 10;
                dog2.Health = 20;
    
                int combined_health = get_dogs_combined_health();
                Debug.WriteLine($"The combined health of both dogs is: {combined_health}");
            }
    
            int get_dogs_combined_health()
            {
                return Utilities.sum_two_numbers(dog1.Health, dog2.Health);
            }
        }
    }
    

    Sometimes we want to import functions/variables from another namespace which is not our own. For example, the Debug.WriteLine we used above (that writes a message to our debug console) is part of the System.Diagnostics namespace, as that is part of the c# standard library. The standard library is a library of common useful functions that is bundled with every c# application (and it has a lot of useful stuff in there). Because it's in a different namespace than ours, we need to explicitly import that namespace, and we do that with the using keyword:

    
    using System.Diagnostics;
    
    namespace MyGame
    {
        class MyClass
        {
            void write_hello()
            {
                Debug.WriteLine("Hello!");
            }
        }
    }
    

    Note that if you're using an IDE like Visual Studio to write your code, and you forgot putting the using section, a lot of times Visual Studio can add this automatically for you: you'll see a squigly line under your usage of a missing library (Debug.WriteLine in this scenario) and a lightbulb icon which, when clicked on, will give you the option to automatically add the missing using clause.

    Sometimes we want to import functions/variables from an external library: in that case we'll want to add a reference to that library before we can add using clauses for its namespaces. For example, we might want to add a library that will allow us to vibrate the mobile phone (if the game is played on a mobile phone). We can search for an available package directly from the IDE. From Visual Studio, under your project node in the solution explorer, there's a "Packages" node, right click it and select "add package". This will open a window in which you can search and install packages. If you search for "vibrate", for example, you'll see "Vibrate Plugin for Xamarin and Windows" which you can then install by clicking "Add Package". Once you have the package installed, you can use its namespaces using the same using keyword we saw before (and you should read that package documentation to understand how to use it).

    Scripts

    In AGS, you have a global script, room scripts, and additional scripts you can create on will. In c# there's no global script, and you are free to organize the scripts as you want them to be. The order of the scripts (unlike AGS) does not matter. There are no "special functions" that you can put in your script (like game_start) that are magically called, you have to call it yourself.

    Data types and operators

    All AGS data types and operators exist in c# with the same syntax, and used the same way. c# has additional data types and operators which do not exist in AGS.

    You can see all data types here: https://docs.microsoft.com/en-us/dotnet/csharp/tour-of-csharp/types-and-variables

    You can see all operators here: https://msdn.microsoft.com/en-us/library/6a71f45d(v=vs.120).aspx

    Additionally, c# has the keyword var which can be used when declaring the variable is it is clear what data type it has. For example:

    
    var x = "hello"; //x is a string, it's clear from how x is initialized, so we can use var instead of string when declaring the variable (if we want).
    

    Arrays

    The c# syntax for arrays is slightly different from the AGS syntax for dynamic arrays, in that you put the brackets next to the type and not next to the variable name:

    
    int[] characterHealth = new int[50];
    
    

    Also, in c# you have lists, which is like an array only without a size limit, so you can add and remove items from the list:

    
    List<int> characterHealth = new List<int>();
    
    characterHealth.Add(5);
    characterHealth.Add(6);
    characterHealth.Add(7);
    
    Debug.WriteLine(characterHealth[0]); //5
    Debug.WriteLine(characterHealth[1]); //6
    Debug.WriteLine(characterHealth[2]); //7
    
    characterHealth.RemoveAt(1);
    Debug.WriteLine(characterHealth[0]); //5
    Debug.WriteLine(characterHealth[1]); //7
    

    Conditionals and Loops

    The syntax for if, else, while and switch in c# is identical to the syntax in AGS.

    C# also had additional constructs for conditionals and loops: most notably the ? operator can be used in some scenarios instead of if, and the foreach keyword can be used in some scenarios instead of while:

    
    //using an if:
    string getVisibleWord()
    {
        if (visible) return "visible";
        else return "invisible";
    }
    
    //using '?'
    string getVisibleWord()
    {
        return visible ? "visible" : "invisible";
    }
    
    //using while
    int getSum(int[] numbers)
    {
        int sum = 0;
        int index = 0;
        while (index < numbers.Length)
        {
            sum += numbers[index];
            index++;
        }
        return sum;
    }
    
    //using foreach
    int getSum(int[] numbers)
    {
        int sum = 0;
        foreach (int number in numbers)
        {
            sum += number;
        }
        return sum;
    }
    

    Also, c# has a wonderful querying language for collections, called LINQ, which can be used to make a lot of tasks more simpler. For example:

    
    //without LINQ
    int getSumOfNumbersBiggerThan10(int[] numbers)
    {
        int sum = 0;
        foreach (int number in numbers)
        {
            if (number > 10) sum += number;
        }
        return sum
    }
    
    //with LINQ
    int getSumOfNumbersBiggerThan10(int[] numbers)
    {
        return numbers.Where(number => number > 10).Sum();
    }
    

    You can read more on LINQ here: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/getting-started-with-linq

    String Formatting

    c# has a string.Format function which is similar to the String.Format function in AGS. c# also has support for string interpolation, though, which usually gives a better experience.

    Let's go over the different of string.Format first:

    In AGS script:

    
    String posString = String.Format("The position is: %d,%d", x, y);
    

    In c#:

    
    string posString = string.Format("The position is: {0},{1}", x, y);
    

    The main different is that in AGS script you need to specify the type of the variables, where you don't have to do that in c#, but in c# you have to specify the location of the parameter in the string.

    AGS also has the %0Xd and %.Xf special formatting codes for zero padding and showing decimal places. c# also has special formatting codes for a lot more scenarios. So, for example, for padding to 5 zeroes and showing 3 decimal places, we can rewrite our previous formatting like this:

    
    string posString = string.Format("The position is: {0:00000.###},{1:00000.###}", x, y);
    

    You can read about all the special formatting codes here: https://docs.microsoft.com/en-us/dotnet/standard/base-types/formatting-types

    AGS also uses the left bracket as a special code for a new line, in c# you can use Environment.NewLine instead.

    String Interpolation

    String interpolation is a newer type of formatting which allows placing the parameters directly in the string. For creating an interpolated string, you should prefix the string with $, and then can directly put the parameters inside {}. So we can rewrite our previous example like this:

    
    string posString = $"The position is: {x:00000.###},{y::00000.###}";
    

    You can read more about interpolated strings here: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/interpolated-strings

    Constants (Compilation Flags)

    What in AGS script is called "constants" is actually 2 separate things in c#: constants and compilation flags. In c# constants are variables that cannot be changed ever:

    
    const int x = 5;
    x = 6; //This is illegal -> will not compile
    

    So, the AGS constant AGS_MAX_INV_ITEMS would have been defined as a constant in c# as well (though MonoAGS doesn't have all of the limit constants in AGS, there are no limits in MonoAGS).

    On the contrary, all of the AGS constants that might or might not be defined, those are compilation flags. The AGS directive #ifdef has an equivalent #if directive in c# and #ifndef equivalent is #if !. The DEBUG compilation flag that exists in AGS also exists in c#, so you can use it to do things only when debugging:

    
    #if DEBUG
    
    //do something debug specific here.
    
    #endif
    

    All of the other AGS compilation flags are AGS specific and have no equivalents in MonoAGS. Except for #if, c# has more directives which you can see here: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives/

    Extender functions

    The c# equivalent to AGS extender functions is extension methods (note that in c# a function is called a method usually, but it means the same thing).

    The syntax is similar, with the exception that in c# you need to mark your method static and the class should also be marked as static (a static class is a class for which all the functions within are also static).

    So, in AGS you would write:

    
    function Scream(this Character*)
    {
        this.Say("AAAAARRRRGGGGHHHHHH!!!!");
    }
    

    In c# you would write:

    
    public static class CharacterExtensions
    {
        public static void Scream(this ICharacter character)
        {
            character.Say("AAAAARRRRGGGGHHHHHH!!!!");
        }
    }
    

    noloopcheck

    noloopcheck is something that's AGS specific and has no equivalent in c#. Or rather, the loop checks are AGS specific, you can think of all loops in c# as noloopcheck.

    async/await

    async/await is a c# specific mechanism for asynchronous programming which doesn't have an equivalent in AGS. As it's an important part of programming your game, there's a specific article devoted to async/await, which you can find here.

    API Comparisons

    This section goes over each API provided by AGS (based on the AGS manual), and compares against the MonoAGS API. Items marked with ? are items that currently don't have an equivalent in MonoAGS.

    AudioChannel

    The equivalent in MonoAGS would be ISound. Both are returned when you're playing an audio clip. The difference between AGS channel and MonoAGS sound is that a sound relates to the specific sound you're playing, it "dies" when you finished playing the sound. The channel however lives on throughout the game and can play other sounds in the future, so you can't always trust it's playing the sound you requested.

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    Seek Position channel.Seek(2500); sound.Position = 2.5; Milliseconds in AGS, seconds in MonoAGS. In AGS the value is int meaning you can't get a lower resolution than milliseconds. In MonoAGS the value is float meaning you can go as low in resolution as the hardware understands.
    SetRoomLocation ? channel.SetRoomLocation(x,y); ? MonoAGS has the concept of a sound emitter which automatically pans the sound based on the location in the room, and can set the volume based on volume-changing areas, but nothing currently specifically exists for volume based on distance from a character.
    Speed Pitch channel.Speed = 2000; sound.Pitch = 2;
    Stop Stop channel.Stop(); sound.Stop();
    ID SourceID channel.ID sound.SourceID
    IsPlaying HasCompleted if (!channel.IsPlaying) if (sound.HasCompleted) If you want to check whether the sound you played completed playing, MonoAGS provides you with a better option: In AGS, channel.IsPlaying might return true even if your sound finished playing, because another sound is now being played on that channel.
    LengthMs Duration channel.LengthMs sound.Duration
    Panning Panning channel.Panning = -100; sound.Panning = -1; -100 - 100 in AGS, -1 - 1 in MonoAGS. In AGS the value is int (meaning you can only have 200 values) where in MonoAGS the value is float (when you can have a range as big as the hardware understands).
    PlayingClip ? channel.PlayingClip ? This is critical in AGS due to the fact the channel might be playing a lot of clips in its lifetime. Much less important in MonoAGS as you can know which clip the sound is coming from, because you're playing that sound.
    Position Position if (channel.Position == 1500) if (channel.Position == 1.5) Milliseconds in AGS, seconds in MonoAGS
    Volume Volume channel.Volume = 100; sound.Volume = 1f; 0 - 100 in AGS, 0 - 1 in MonoAGS. In AGS the value is int (meaning you can only have 200 values) where in MonoAGS the value is float (when you can have a range as big as the hardware understands).

    Missing in AGS but exists in MonoAGS: Asynchronous completion API, Pause/Resume, Rewind, IsPaused, IsLooping, IsValid.

    AudioClip

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    Play Play clip.Play(eAudioPriorityNormal, eOnce); clip.Play(eAudioPriorityNormal, eRepeat); clip.Play(false); clip.Play(true); There's no equivalence for audio priority currently.
    PlayFrom Seek the sound coming back from the clip. clip.PlayFrom(1000); var sound = clip.Play(); sound.Seek = 1;
    PlayQueued ? clip.PlayQueued(); ? Note that in AGS the number of available channels is 10; In MonoAGS the number of available channels is based on what the running hardware provides, which, on modern machines is usually at least 32 (and on older machines, usually at least 16), so this feature becomes less important.
    Stop You can query all playing sounds and stop them clip.Stop(); foreach (var sound in clip.CurrentlyPlayingSounds) sound.Stop();
    FileType ? clip.FileType ?
    IsAvailable ? clip.IsAvailable ?
    Type ? clip.Type ?

    Missing in AGS but exists in MonoAGS: ID, CurrentlyPlayingSounds, Volume/Pitch/Panning (so you can change the template at runtime, not just from the editor), playing a clip while overriding default volume/pitch/panning.

    Character

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    AddInventory Inventory.Items.Add cEgo.AddInventory(iKey); cEgo.Inventory.Items.Add(iKey)
    AddWaypoint Either use await or ContinueWith cSomeguy.Walk(160, 100); cSomeguy.AddWaypoint(50, 150); Using await: private async Task walk() { await cSomeguy.WalkAsync(160, 100); await cSomeguy.WalkAsync(50, 150); } (we can now call this walk method and either block (with another await) or doesn't block, it's up to us. Using ContinueWith: cSomeguy.WalkAsync(160, 100).ContinueWith(_ => cSomeguy.WalkAsync(50, 150)); Note what we gain using the await that we can't do with AGS: we can easily create an endless loop of non-blocking walking in circles: private async void endlessWalk() { while (true) { await cSomeguy.WalkAsync(50, 150); await cSomeguy.WalkAsync(160, 100);}}
    Animate AnimateAsync cEgo.Animate(3, 1, 0, eBlock, eBackwards); For blocking: await cEgo.AnimateAsync(jumpUpAnimation);. For non-blocking, do the same just without awaiting it: cEgo.AnimateAsync(jumpUpAnimation);. As for delay, repeat style and direction, those are configured as part of the animation ("jumpUpAnimation" in this scenario). It can be changed at run-time before animating, if you want. For example: jumpUpAnimation.Looping = LoopingStyle.BackwardsForwards; jumpUpAnimation.Loops = 15; jumpUpAnimation.DelayBetweenFrames = 3; Note that MonoAGS doesn't have the concepts of view and loop, just individual animations for manual animations, and directional animations for automatic animations like walk and idle.
    ChangeRoom ChangeRoomAsync cEgo.ChangeRoom(4, 50, 50); cEgo.ChangeRoomAsync(rLobby, 50, 50); Note that unlike AGS, you CAN wait for the change room to finish in your current script if you use await.
    ChangeRoomAutoPosition ? cEgo.ChangeRoomAutoPosition() ?
    ChangeView Outfit cEgo.ChangeView(5); cEgo.Outfit = outfitWithHat; Note that the concepts are not identical: ChangeView in AGS changes the walk animation, where Outfit in MonoAGS changes all animations in that outfit (which can be walk, idle, etc).
    FaceCharacter FaceDirectionAsync cEgo.FaceCharacter(cSomeGirl, eBlock); Non-blocking: cEgo.FaceDirectionAsync(cSomeGirl);, blocking: await cEgo.FaceDirectionAsync(cSomeGirl); Missing support for "turning" animation.
    FaceDirection FaceDirectionAsync cEgo.FaceDirection(eDirectionUpRight); await cEgo.FaceDirectionAsync(Direction.UpRight);
    FaceLocation FaceDirectionAsync cEgo.FaceLocation(50, 50, eBlock); Non-blocking: cEgo.FaceDirectionAsync(50, 50);, blocking: await cEgo.FaceDirectionAsync(50, 50); Missing support for "turning" animation.
    FaceObject FaceDirectionAsync cEgo.FaceObject(oFridge, eBlock); Non-blocking: cEgo.FaceDirectionAsync(oFridge);, blocking: await cEgo.FaceDirectionAsync(oFridge); Missing support for "turning" animation.
    FollowCharacter Follow cBadGuy.FollowCharacter(cEgo); cBadGuy.Follow(cEgo); Note that in MonoAGS you can follow more than just characters, including objects and even GUIs.
    GetAtScreenXY IHitTest.ObjectAtMousePosition or IHitTest.GetObjectAt if (Character.GetAtScreenXY(mouse.x, mouse.y) == cEgo){} if (hitTest.ObjectAtMousePosition == cEgo) {} or if (hitTest.GetObjectAt(200, 100)) {}
    GetProperty Properties.Ints.GetValue if (cEgo.GetProperty("Value") > 200) {} if (cEgo.Properties.Ints.GetValue("Value") > 200) {}
    GetTextProperty Properties.Strings.GetValue cEgo.GetTextProperty("Description"); cEgo.Properties.Strings.GetValue("Description");
    SetProperty Properties.Ints.SetValue cEgo.SetProperty("XPLevel", 10); cEgo.Properties.Ints.SetValue("XPLevel", 10);
    SetTextProperty Properties.Strings.SetValue cEgo.SetTextProperty("Description", "I am handsome!"); cEgo.Properties.Strings.SetValue("Description", "I am handsome!");
    HasExplicitLight ? if (cEgo.HasExplicitLight) {} ?
    HasInventory Inventory.Items.Contains if (cEgo.HasInventory(iKnife)) {} if (cEgo.Inventory.Items.Contains(iKnife)) {}
    IsCollidingWithChar CollidesWith if (cEgo.IsCollidingWithChar(cGuy) == 1) {} if (cEgo.CollidesWith(cGuy.X, cGuy.Y, state.Viewport)) {} Note that MonoAGS supports multiple viewports so we need to pass the viewport in which we'd like to test for collisions.
    IsCollidingWithObject (character) CollidesWith if (cEgo.IsCollidingWithChar(oBottle) == 1) {} if (cEgo.CollidesWith(oBottle.X, oBottle.Y, state.Viewport)) {} Note that MonoAGS supports multiple viewports so we need to pass the viewport in which we'd like to test for collisions.
    LightLevel Brightness cEgo.LightLevel cEgo.Brightness Note that unlike AGS, in MonoAGS the brightness does not override the tint, but is added on top of it.
    LockView Outfit cEgo.LockView(12); cEgo.Outfit = swimmingOutfit;
    LockViewAligned ? cEgo.LockViewAligned(12, 1, eAlignLeft); ?
    LockViewFrame To display a still frame, use Image, for actual locking set a different outfit cEgo.LockViewFrame(AGHAST, 2, 4) cEgo.Image = cEgo.Outfit[Animations.Aghast].Left.Frames[4].Sprite.Image;
    LockViewOffset ? cEgo.LockViewOffset(12, 1, -1); ? Note that while there's no direct equivalent, you can change offsets for individual animation frames, so you can do that manually (at run-time if you desire), for example: cEgo.Outfit[Animations.Walk].Left.Frames[0].Sprite.X = 5; //will offset the first left walking animation frame by 5 pixels to the right
    LoseInventory Inventory.Items.Remove cEgo.LoseInventory(iKnife); cEgo.Inventory.Items.Remove(iKnife);
    Move (character) set the outfit to an outfit without a walk animation cEgo.Move(155, 122, eBlock); Non-blocking: cEgo.Outfit = idleOnlyOutfit; cEgo.WalkAsync(155, 122);, blocking: cEgo.Outfit = idleOnlyOutfit; await cEgo.WalkAsync(155, 122); No support currently for "walk anywhere"
    PlaceOnWalkableArea PlaceOnWalkableArea cEgo.PlaceOnWalkableArea(); cEgo.PlaceOnWalkableArea();
    RemoveTint Tint cEgo.RemoveTint(); cEgo.Tint = Colors.White;
    IsInteractionAvailable checking subscriber count on the interaction event if (cEgo.IsInteractionAvailable(eModeLookat) == 0) {} if (cEgo.Interactions.OnInteract(Verbs.Look).SubscribersCount == 0) {}
    RunInteraction Interactions.OnInteract(Verb).InvokeAsync cEgo.RunInteraction(eModeTalk); cEgo.Interactions.OnInteract(Verbs.Talk).InvokeAsync();
    Say SayAsync cEgo.Say("Hello!"); await cEgo.SayAsync("Hello!");
    SayAt ? cEgo.SayAt("Hello!", 50, 50); await cEgo.SayAsync("Hello!", (50, 50));
    SayBackground SayAsync cEgo.SayBackground("Hello!"); cEgo.SayAsync("Hello!"); There's no way in AGS to know when SayBackground completes. MonoAGS gives you the task completion API for this: Task task = cEgo.SayAsync("Hello!"); ... while (!task.IsCompleted) {..}, or simply: Task task = cEgo.SayAsync("Hello!"); ... await task;
    SetAsPlayer IGameState.Player cEgo.SetAsPlayer(); state.Player = cEgo;
    SetLightLevel Brightness cEgo.SetLightLevel(100); cEgo.Brightness = new Vector4(2,2,2,2);
    SetIdleView Outfit cEgo.SetIdleView(5); cEgo.Outfit = outfitWithHat; Note that the concepts are not identical: SetIdleView in AGS changes the idle animation, where Outfit in MonoAGS changes all animations in that outfit (which can be walk, idle, etc).
    SetWalkSpeed WalkStep cEgo.SetWalkSpeed(5, 5); cEgo.WalkStep = new PointF(5, 5);
    StopMoving StopWalkingAsync cEgo.StopMoving(); cEgo.StopWalkingAsync();
    Think ? cEgo.Think("Hmmmm.."); ?
    Tint Tint cEgo.Tint(0, 250, 0, 30, 100); cEgo.Tint = Colors.Green; or cEgo.Tint = Color.FromRgba(0, 255, 0, 255); or cEgo.Tint = Color.FromHsla(200, 1, 1, 255); or cEgo.Tint = Color.FromHexa(59f442);
    TintBlue Tint.B cEgo.TintBlue cEgo.Tint.B
    TintGreen Tint.G cEgo.TintGreen cEgo.Tint.G
    TintRed Tint.R cEgo.TintRed cEgo.Tint.R
    TintSaturation Tint.GetSaturation cEgo.TintSaturation cEgo.Tint.GetSaturation()
    TintLuminance Tint.GetLightness cEgo.TintLuminance cEgo.Tint.GetLightness()
    UnlockView Outfit cEgo.UnlockView(); cEgo.Outfit = defaultOutfit;
    Walk WalkAsync cEgo.Walk(100, 100); For non blocking: cEgo.WalkAsync((100, 100));, for blocking: await cEgo.WalkAsync((100, 100));
    WalkStraight WalkStraight cEgo.WalkStraight(100, 100); await cEgo.WalkStraight((100, 100));
    ActiveInventory Inventory.ActiveItem cEgo.ActiveInventory cEgo.Inventory.ActiveItem
    Animating Animation.State.IsPaused if (cEgo.Animating) {} if (!cEgo.Animation.State.IsPaused) {}
    AnimationSpeed Animation.Configuration.DelayBetweenFrames cEgo.AnimationSpeed = 4; cEgo.Animation.Configuration.DelayBetweenFrames = 4;
    Baseline Z cEgo.Baseline = 40; cEgo.Z = 40;
    BlinkInterval ? cEgo.BlinkInterval = 10; ?
    BlinkView ? cEgo.BlinkView = 10; ?
    BlinkWhileThinking property ? cEgo.BlinkWhileThinking = false; ?
    BlockingHeight ? cEgo.BlockingHeight = 20; ?
    BlockingWidth ? cEgo.BlockingWidth = 20; ?
    Clickable Enabled cEgo.Clickable = false; cEgo.Enabled = false;
    DestinationX WalkDestination.X cEgo.DestinationX cEgo.WalkDestination.X
    DestinationY WalkDestination.Y cEgo.DestinationY cEgo.WalkDestination.Y
    DiagonalLoops Configure your directional animation either with or without diagonal directions cEgo.DiagonalLoops = true; Nothing special needed for this to work
    Frame Animation.State.CurrentFrame cEgo.Frame cEgo.Animation.State.CurrentFrame
    HasExplicitTint Tint if (cEgo.HasExplicitTint) {} if (cEgo.Tint != Colors.White) {}
    ID ID cEgo.ID cEgo.ID
    IdleView Outfit[Animations.Idle] cEgo.IdleView cEgo.Outfit[Animations.Idle]
    IgnoreLighting ? cEgo.IgnoreLighting = 1; ?
    IgnoreWalkbehinds ? cEgo.IgnoreWalkbehinds = true; ? Probably not really needed in MonoAGS- with the combination of render layers, Z and parent-child relationships you have the ability control rendering order more easily
    InventoryQuantity InventoryItem.Qty player.InventoryQuantity[iCash.ID] iCash.Qty
    Loop Animation.State.CurrentLoop cEgo.Loop cEgo.Animation.State.CurrentLoop
    ManualScaling IgnoreScalingArea cEgo.ManualScaling = true; cEgo.IgnoreScalingArea = true; This is not a 1-to-1 fit. In MonoAGS you can still set manual scaling to be applied onto the walkable area scaling, even if IgnoreScalingArea is false.
    MovementLinkedToAnimation MovementLinkedToAnimation cEgo.MovementLinkedToAnimation = false; cEgo.MovementLinkedToAnimation = false;
    Moving IsWalking if (cEgo.IsMoving) {} if (cEgo.IsWalking) {}
    Name DisplayName cEgo.Name = "Bernard"; cEgo.DisplayName = "Bernard";
    NormalView Outfit[Animations.Walk] cEgo.NormalView cEgo.Outfit[Animations.Walk];
    PreviousRoom PreviousRoom if (cEgo.PreviousRoom == 5) {} if (cEgo.PreviousRoom == elevator) {} In MonoAGS, PreviousRoom actually provides you with access to the entire room's API, not just its ID, so you can query the room's objects, for example.
    Room Room if (cEgo.Room == 5) {} if (cEgo.Room == elevator) {} In MonoAGS, Room actually provides you with access to the entire room's API, not just its ID, so you can query the room's objects, for example.
    ScaleMoveSpeed AdjustWalkSpeedToScaleArea cEgo.ScaleMoveSpeed = true; cEgo.AdjustWalkSpeedToScaleArea = true;
    ScaleVolume scalingArea.ScaleVolume cEgo.ScaleVolume = true; scalingArea.ScaleVolume = true; This is not a 1-to-1 match. In AGS, scale volume scales the volume according to the scaling of the character, and it doesn't matter if the scaling was set manually or in an area. In MonoAGS, this is specfically for areas, there is no equivalent configuration for manual scaling changes currently.
    Scaling ScaleX and ScaleY cEgo.ManualScaling = true; cEgo.Scaling = 200; cEgo.ScaleX = 2; cEgo.ScaleY = 2; In AGS the range is 5 to 200, where the value must be an integer and 100 is not scaled. In MonoAGS there's no "allowed" range, the value is a float (so you can do cEgo.ScaleX = 0.5f) and 1 is not scaled.
    Solid ? if (cEgo.Solid) {} ?
    Speaking Outfit[Animations.Speak].Animation.State.IsPaused if (cEgo.Speaking) {} if (!cEgo.Outfit[Animations.Speak].Animation.State.IsPaused) {}
    SpeakingFrame Outfit[Animations.Speak].Animation.State.CurrentFrame cEgo.SpeakingFrame cEgo.Outfit[Animations.Speak].Animation.State.CurrentFrame
    SpeechAnimationDelay Outfit[Animations.Speak].Animation.Configuration.DelayBetweenFrames cEgo.SpeechAnimationDelay cEgo.Outfit[Animations.Speak].Animation.Configuration.DelayBetweenFrames
    SpeechColor SpeechConfig.TextConfig.Brush cEgo.SpeechColor = 14; cEgo.SpeechConfig.TextConfig.Brush = blueSolidBrush;
    SpeechView Outfit[Animations.Speak] cEgo.SpeechView cEgo.Outfit[Animations.Speak]
    Thinking ? if (cEgo.Thinking) {} ? There's nothing particular about Think in MonoAGS currently, but using outfit you can assign and query specific animations, so you can create a "think" animation if it fits your game.
    ThinkingFrame Outfit[Animations.Think].Animation.State.CurrentFrame cEgo.ThinkingFrame cEgo.Outfit[Animations.Think].Animation.State.CurrentFrame There's nothing particular about Think in MonoAGS currently, but using outfit you can assign and query specific animations, so you can create a "think" animation if it fits your game.
    ThinkView Outfit[Animations.Think] cEgo.ThinkView cEgo.Outfit[Animations.Think] There's nothing particular about Think in MonoAGS currently, but using outfit you can assign and query specific animations, so you can create a "think" animation if it fits your game.
    Transparency Opacity cEgo.Transparency = 100; cEgo.Opacity = 0; The range for AGS transparency is 0-100, the range for MonoAGS opacity is 0-255
    TurnBeforeWalking ? cEgo.TurnBeforeWalking = 1; ?
    View Animation cEgo.View cEgo.Animation
    WalkSpeedX WalkStep.X cEgo.WalkSpeedX cEgo.WalkStep.X
    WalkSpeedY WalkStep.Y cEgo.WalkSpeedY cEgo.WalkStep.Y
    x X cEgo.x cEgo.X
    y Y cEgo.y cEgo.Y
    z JumpOffset.Y cEgo.Z = 100; cEgo.JumpOffset = new PointF(0, 100); This requires the jump component to be added to the character.

    Missing in AGS but exists in MonoAGS: asynchronous speech/walk, configuring speech background color/shadows + outlines/text brushes/borders/alignments/text skipping/portraits, hooking/customizing speech/walk/path finding, face direction based on where somebody else is looking, iterating/querying inventory items, subscribing/unsubscribing interaction events during the game, more configurations for following, follow objects which are not characters, query the current follow target, and as a character is an extension of object, see the list for object for more stuff.

    DateTime

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    Now Now DateTime.Now DateTime.Now
    DayOfMonth DayOfMonth now.DayOfMonth now.DayOfMonth
    Hour Hour now.Hour now.Hour
    Minute Minute now.Minute now.Minute
    Month Month now.Month now.Month
    RawTime Need to calculate DateTime.Now.RawTime (DateTime.UtcNow - new DateTime(1970,1,1)).TotalSeconds
    Second Second now.Second now.Second
    Year Year now.Year now.Year

    Missing in AGS but exists in MonoAGS: well, nothing here is MonoAGS specific, this is all c#. You can see all available functions here: https://msdn.microsoft.com/en-us/library/system.datetime(v=vs.110).aspx

    Also note, that if you need correct handling of time zones and DST, this a recommended library which you can add to your project: https://github.com/nodatime/nodatime

    Dialog

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    DisplayOptions ? dOldMan.DisplayOptions(); ?
    GetOptionState option.Label.UnderlyingVisible (and optionally combine with ShowOnce if you need to compare with "off forever") if (dJoeExcited.GetOptionState(2) == eOptionOffForever) {} dOption = dJoeExcited.Options[2]; if (!dOption.Label.UnderlyingVisible && dOption.ShowOnce) {}
    GetOptionText option.Label.Text dJoeExcited.GetOptionText(3) dJoeExcited.Options[3].Label.Text
    HasOptionBeenChosen option.HasOptionBeenChosen dJoeExcited.HasOptionBeenChosen(3) dJoeExcited.Options[3].HasOptionBeenChosen
    ID ? dJoeExcited.ID ? It doesn't seem there's any need for an id for the dialog, you can just compare with the dialog reference if you need equality checks
    OptionCount Options.Count dJoeExcited.OptionCount dJoeExcited.Options.Count
    SetHasOptionBeenChosen option.HasOptionBeenChosen dJoeExcited.SetHasOptionBeenChosen(3, false); dJoeExcited.Options[3].HasOptionBeenChosen = false;
    SetOptionState Either set option.Label.Visible or option.ShowOnce dJoeExcited.SetOptionState(2, eOptionOff) For option off/on: dJoeExcited.Options[2].Label.Visible = false;, for off forever, you can add: dJoeExcited.Options[2].ShowOnce = true;
    ShowTextParser ? if (cJoeExcited.ShowTextParser) {} ?
    Start RunAsync dJoeExcited.Start(); dJoeExcited.RunAsync();
    StopDialog ? dJoeExcited.StopDialog(); ?

    Missing in AGS but exists in MonoAGS: create and change dialogs at run-time, customize appearances of everything dialog related, asynchronously wait for a dialog to complete, automatic grey-out (or any desired rendering) for already selected options, show/hide dialog options when speaking, run a specific dialog option on demand, enable/disable specific dialog actions.

    DialogOptionsRenderingInfo

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    RunActiveOption option.RunAsync info.RunActiveOption(); await option.RunAsync(); There's no support in MonoAGS for having an "active option", you just select the option you want to run.
    Update Not Needed info.Update(); N/A No need for this in MonoAGS currently, dialog is continously rendered.
    ActiveOptionID Not Needed info.ActiveOptionID = 1 N/A This is required for custom dialog rendering in AGS, as the assumption is you get a drawing surface and natively drawing all the options, and then AGS can't do hit-tests itself so you need to worry about it. This is not required in MonoAGS, as you can provide individual rendering for the dialog options and they can still be used as hit-test targets.
    DialogToRender ? info.DialogToRender ? The way to do custom rendering is a bit different in MonoAGS. There's no one single hook to customize the dialogs, but you can choose on which layer you want to provide your own different implementation. So you can provide a different implementation for IDialogLayout (which gets the dialog graphics and options graphics and chooses how to place them), or you can provide a different implementation for each (or for specific) IDialogOption to change how they are rendered/behave, or you can provide a different implementation for IDialog to completely rewrite the dialog mechanism (but still be able to hook it up to existing dialog code). Each of those custom implementations can be either changed for all dialogs or for specific dialogs.
    HasAlphaChannel ? info.HasAlphaChannel = true; All graphics always have an alpha channel
    Height dialog.Graphics.Height info.Height dialog.Graphics.Height
    ParserTextBoxWidth ? info.ParserTextBoxWidth ?
    ParserTextBoxX ? info.ParserTextBoxX ?
    ParserTextBoxY ? info.ParserTextBoxY ?
    Surface Not needed info.Surface N/A See notes on "ActiveOptionID" and "DialogToRender" to see why this is not needed.
    Width dialog.Graphics.Width info.Width dialog.Graphics.Width
    X dialog.Graphics.X info.X dialog.Graphics.X
    Y dialog.Graphics.Y info.Y dialog.Graphics.Y

    Missing in AGS but exists in MonoAGS: The whole process for custom dialog rendering is completely different (see notes on DialogToRender).

    DrawingSurface

    Currently nothing built in that's equivalent for this, but one could directly implement IImageRenderer, assign it to its object with obj.CustomRenderer = myRenderer and use OpenGL in that renderer implementation to do everything desired.

    DynamicSprite

    The concept of dynamic sprite is not really needed in MonoAGS, as everything is dynamic by default, so you can create objects, characters, animations, etc, all in run-time. So in this section, equivalent behaviors might be found on one or more levels: bitmaps, images (container above bitmap which also adds texture information), sprites (container above image which adds abilities for run-time transforms) and objects (which contain sprites as individual animation frames or a single image).

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    Create new EmptyImage DynamicSprite.Create(50, 30); new EmptyImage(50, 30);
    CreateFromBackground LoadImage DynamicSprite.CreateFromBackground() graphicsFactory.LoadImage(state.Room.Image.OriginalBitmap)
    CreateFromDrawingSurface ? DynamicSprite.CreateFromDrawingSurface(surface, 0, 0, 10, 10); ? While there's nothing drawing area specific, one could implement a custom renderer for doing something like this.
    CreateFromExistingSprite LoadImage DynamicSprite.CreateFromExistingSprite(20); graphicsFactory.LoadImage(existingImage.OriginalBitmap)
    CreateFromFile LoadImage DynamicSprite.CreateFromFile("door.png") graphicsFactory.LoadImage("door.png")
    CreateFromSaveGame ? DynamicSprite.CreateFromSaveGame(1, 50, 50) ?
    CreateFromScreenShot ? DynamicSprite.CreateFromScreenShot(80, 50) ?
    ChangeCanvasSize ? DynamicSprite.ChangeCanvasSize(sprite.Width + 10, sprite.Height, 5, 0); ? While there's nothing specific for this, this could be implemented by manual bitmap manipulations (but it's tedious): you first create a bitmap with the new size, manually get pixels from the original bitmap and set them in the new bitmap, then load an image from the new bitmap.
    CopyTransparencyMask ? DynamicSprite.CopyTransparencyMask ? While there's nothing specific for this, this could be implemented by manual bitmap manipulations (but it's tedious): you first create a bitmap with the new size, manually get pixels from the original bitmap and set them in the new bitmap, then load an image from the new bitmap.
    Crop bitmap.Crop sprite.Crop(10, 10, sprite.Width - 10, sprite.Height - 10); graphicsFactory.LoadImage(sprite.OriginalBitmap.Crop(new Rectangle(10, 10, sprite.Width - 10, sprite.Height - 10))); Also, instead of cropping the bitmap, one could add an ICropSelfComponent to the object which will crop the rendered object at run-time (without touching the bitmap).
    Delete ? sprite.Delete(); ?
    Flip FlipHorizontally or FlipVertically sprite.Flip(eFlipUpsideDown); obj.FlipHorizontally();
    GetDrawingSurface ? sprite.GetDrawingSurface() ? While there's nothing drawing area specific, one could implement a custom renderer for doing something like this.
    Resize ScaleX and ScaleY sprite.Resize(100, 50); obj.ScaleX = 100; obj.ScaleY = 50;
    Rotate Angle sprite.Rotate(180); obj.Angle = 180;
    SaveToFile bitmap.SafeToFile sprite.SaveToFile("abc.png"); sprite.OriginalBitmap.SaveToFile("abc.png");
    Tint Tint sprite.Tint(0, 250, 0, 30, 100); sprite.Tint = Colors.Green; or sprite.Tint = Color.FromRgba(0, 255, 0, 255); or sprite.Tint = Color.FromHsla(200, 1, 1, 255); or sprite.Tint = Color.FromHexa(59f442);
    ColorDepth ? sprite.ColorDepth ?
    Graphic ID sprite.Graphic image.ID
    Height Height sprite.Height image.Height
    Width Width sprite.Width image.Width

    File

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    Open Open File *output = File.Open("temp.tmp", eFileWrite); var output = File.Open("temp.tmp", FileMode.Create);
    Close Close output.Close(); output.Close();
    Delete Delete File.Delete("temp.tmp"); File.Delete("temp.tmp");
    Exists Exists if (File.Exists("temp.tmp")) {} if (File.Exists("temp.tmp")) {}
    ReadInt BinaryReader.ReadInt32 int number; number = input.ReadInt(); using (var reader = new BinaryReader(File.OpenRead("file.txt")) ) { char c = reader.ReadInt32(); }
    ReadRawChar BinaryReader.ReadChar String buffer = String.Format("%c", input.ReadRawChar()); using (var reader = new BinaryReader(File.OpenRead("file.txt")) ) { char c = reader.ReadChar(); }
    ReadRawInt BinaryReader.ReadInt32 int number; number = input.ReadRawInt(); using (var reader = new BinaryReader(File.OpenRead("file.txt")) ) { char c = reader.ReadInt32(); }
    ReadRawLineBack StreamReader.ReadLine String line = input.ReadRawLineBack(); using (var reader = new StreamReader("file.txt")) { string line = reader.ReadLine();}
    ReadStringBack BinaryReader.ReadString String buffer = input.ReadStringBack(); using (var reader = new BinaryReader(File.OpenRead("file.txt")) ) { char c = reader.ReadInt32();
    Seek BaseStream.Seek input.Seek(256); using (var reader = new BinaryReader(File.OpenRead("file.txt")) ) { reader.BaseStream.Seek(256, SeekOrigin.Begin);
    WriteInt BinaryWriter.Write output.WriteInt(6); using (var writer = new BinaryWriter(File.Open("temp.tmp", FileMode.Create))) { writer.Write(6);
    WriteRawChar BinaryWriter.Write output.WriteRawChar('A'); using (var writer = new BinaryWriter(File.Open("temp.tmp", FileMode.Create))) { writer.Write('A');
    WriteRawLine StreamWriter.WriteLine output.WriteRawLine("My line"); using (var writer = new StreamWriter("file.txt")) { writer.WriteLine("My line"); }
    WriteString BinaryWriter.Write output.WriteString("test string"); using (var writer = new BinaryWriter(File.Open("temp.tmp", FileMode.Create))) { writer.Write("test string");
    EOF BaseStream.Position while (!output.EOF) {} while (reader.BaseStream.Position != reader.BaseStream.Length)
    Error try/catch output.WriteInt(51); if (output.Error) { Display("Error writing the data!"); } try { writer.Write(51); } catch (Exception e) { AGSMessageBox.DisplayAsync($"Error while writing the data. The error message is: {e.Message}"); }
    Position BaseStream.Position input.Position reader.BaseStream.Position

    Missing in AGS but exists in MonoAGS: well, nothing here is MonoAGS specific, this is all c#. You can see all available functions here: https://msdn.microsoft.com/en-us/library/system.io.file(v=vs.110).aspx https://msdn.microsoft.com/en-us/library/system.io.binaryreader(v=vs.110).aspx https://msdn.microsoft.com/en-us/library/system.io.binarywriter(v=vs.110).aspx https://msdn.microsoft.com/en-us/library/system.io.streamreader(v=vs.110).aspx https://msdn.microsoft.com/en-us/library/system.io.streamwriter(v=vs.110).aspx https://msdn.microsoft.com/en-us/library/system.io.filestream(v=vs.110).aspx

    Game / Global functions

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    AbortGame throw AbortGame("Error in game!"); throw new Exception("Error im game!");
    CallRoomScript Nothing specific, but you can create a shared interfaces between your rooms and call it. CallRoomScript(1); ... function on_call(int value) {...} public interface IOnCall { void on_call(int value); } .. public class MyRoom : IOnCall { public void on_call(int value) {...} } ... (state.Room as IOnCall)?.on_call(1);
    ChangeTranslation ? Game.ChangeTranslation("Spanish") ?
    ClaimEvent event.Claimed ClaimEvent(); someEvent.Subscribe(onMyEvent); ... void onMyEvent(ref ClaimEventToken token) { token.Claimed = true; }
    Debug ? Debug(0); ?
    DeleteSaveSlot N/A DeleteSaveSlot(130); MonoAGS doesn't have the concept of save slots, you can just delete the save file.
    DisableInterface ? DisableInterface(); There's nothing specific currently, but you can disable all GUI controls and change the cursor.
    DoOnceOnly Repeat.OnceOnly if (Game.DoOnceOnly("open cupboard")) {} if Repeat.OnceOnly("open cupboard") {}
    EnableInterface ? EnableInterface(); There's nothing specific currently, but you can disable all GUI controls and change the cursor.
    EndCutscene Cutscene.End EndCutscene(); state.Cutscene.End();
    GetColorFromRGB Color.FromRgba Game.GetColorFromRGB(0, 255, 0); Color.FromRgba(0, 255, 0, 255);
    GetFrameCountForLoop animation.Frames.Count Game.GetFrameCountForLoop(SWIMMING, 2); cEgo.Outfit[Animations.Swim].Left.Frames.Count
    GetGameOption ? GetGameOption(OPT_WALKONLOOK) ? There's a lot of unrelated very specific configurations for AGS here, some of them have equivalents in MonoAGS, see SetGameOption for more details.
    GetGameSpeed state.Speed GetGameSpeed(); game.State.Speed
    GetLocationName hitTest.ObjectAtMousePosition or hitTest.GetObjectAt if (GetLocationName(mouse.x, mouse.y) == "Hero") {} if (hitTest.ObjectAtMousePosition?.DisplayName == "Hero") {} or if (hitTest.GetObjectAt(200, 100)?.DisplayName == "Hero") {}
    GetLocationType hitTest.ObjectAtMousePosition or hitTest.GetObjectAt if (GetLocationType(mouse.x, mouse.y) == eLocationCharacter) {} if (hitTest.ObjectAtMousePosition is ICharacter) {} or if (hitTest.GetObjectAt(200, 100) is ICharacter) {}
    GetLoopCountForView GetAllDirections Game.GetLoopCountForView(SWIMMING) cEgo.Outfit[Animation.Swim].GetAllDirections().Count()
    GetRunNextSettingForLoop ? Game.GetRunNextSettingForLoop(SWIMMING, 5) ?
    GetSaveSlotDescription ? Game.GetSaveSlotDescription(10) ?
    GetTextHeight Font.MeasureString GetTextHeight("The message on the GUI!", Game.NormalFont, 100) AGSGameSettings.DefaultTextFont.MeasureString("The message on the GUI!", 100).Height
    GetTextWidth Font.MeasureString GetTextWidth("Hello!", Game.NormalFont) AGSGameSettings.DefaultTextFont.MeasureString("Hello!").Width
    GetTranslation ? GetTranslation("secret") ?
    GetViewFrame Frames[index] Game.GetViewFrame(SWIMMING, 2, 3) cEgo.Outfit[Animations.Swim].Left.Frames[3]
    GiveScore ? GiveScore(5) ? Nothing specific in MonoAGS for this, but this could be easily implemented in just a few lines: public static class Score { public static int Score { get; private set; } public static void GiveScore(int score) { Score += score; Sounds.Score.Play();}}
    GetFontHeight Font.SizeInPoints GetFontHeight(eFontSpeech) myFont.SizeInPoints
    GetFontLineSpacing ? GetFontLineSpacing(eFontSpeech) ? Note that you can use MeasureString to get accurate measurements of texts: myFont.MeasureString("Hello world");
    InputBox ? String name = Game.InputBox("!What is your name?"); ?
    IsGamePaused state.Paused if (IsGamePaused()) {} if (game.State.Paused) {}
    IsInterfaceEnabled ? if (IsInterfaceEnabled()) {} ? There's nothing specific for this in MonoAGS, but you can query (and set) enabled/disabled for individual GUI components.
    IsInteractionAvailable checking subscriber count on the interaction event if (IsInteractionAvailable(mouse.x,mouse.y, eModeLookat) == 0) {} if (hitTest.ObjectAtMousePosition != null && hitTest.ObjectAtMousePosition.Interactions.OnInteract(Verbs.Look).SubscribersCount == 0) {}
    IsKeyPressed input.IsKeyDown if (IsKeyPressed(eKeyUpArrow)) {} if (game.Input.IsKeyDown(Key.Up)) {}
    IsTimerExpired Stopwatch.Elapsed SetTimer(1, 3000); ... if (IsTimerExpired(1)) {} Stopwatch myTimer = new Stopwatch(); myTimer.Start(); ... if (myTimer.Elapsed.Seconds > 3) {}
    IsTranslationAvailable ? if (IsTranslationAvailable() == 1) {} ?
    PauseGame state.Paused PauseGame(); game.State.Paused = true;
    QuitGame game.Quit QuitGame(0); game.Quit(); No built-in support in MonoAGS for "ask first", though this could be easily coded by using a message box: if (await AGSMessageBox.YesNoAsync("Are you sure you want to quit?")) { game.Quit(); }
    Random MathUtils.Random().Next int ran = Random(2); int ran = MathUtils.Random().Next(0, 2);
    RestartGame SaveLoad.Restart() RestartGame(); game.SaveLoad.Restart();
    RestoreGameDialog AGSSelectFileDialog.SelectFile RestoreGameDialog(); await AGSSelectFileDialog.SelectFile("Select file to load", FileSelection.FileOnly);
    RestoreGameSlot SaveLoad.Load RestoreGameSlot(5); await game.SaveLoad.LoadAsync("save.bin");
    RunAGSGame Process.Start RunAGSGame ("MyGame.exe", 0, 51); Process.Start("MyGame.exe");
    SaveGameDialog AGSSelectFileDialog.SelectFile SaveGameDialog(); await AGSSelectFileDialog.SelectFile("Select file to save", FileSelection.FileOnly);
    SaveGameSlot SaveLoad.Save SaveGameSlot(30, "save game"); await game.SaveLoad.SaveAsync("save.bin");
    SaveScreenShot ? SaveScreenshot("pic.pcx"); ?
    SetAmbientLightLevel ? SetAmbientLightLevel(50); ?
    SetAmbientTint ? SetAmbientTint(0, 0, 250, 30, 100); ?
    SetGameOption ? SetGameOption(OPT_WALKONLOOK, 1); ? There's a lot of unrelated very specific configurations for AGS here, some of them have equivalents in MonoAGS: OPT_WALKONLOOK + OPT_NOWALKMODE -> Configure the "approach" component, for example: cEgo.ApproachStyle.ApproachWhenVerb[Verbs.Look] = ApproachHotspots.AlwaysWalk, OPT_PIXELPERFECT -> can be configured per entity: cEgo.PixelPerfect(false);, OPT_FIXEDINVCURSOR -> can be configured per inventory item: iKnife.CursoreGraphics = iKnife.Graphics;, OPT_CROSSFADEMUSIC -> you have several more configuration options here, for example: var crossFade = game.AudioSettings.RoomMusicCrossFading; crossFade.FadeIn = true; crossFade.FadeOut = false; crossFade.FadeInSeconds = 5f; crossFade.EaseFadeIn = Ease.QuadIn;, OPT_PORTRAITPOSITION => cEgo.SpeechConfig.PortraitConfig.Positioning = PortraitPositioning.Alternating;
    SetGameSpeed state.Speed SetGameSpeed(80); game.State.Speed = 80;
    SetMultitaskingMode ? SetMultitaskingMode(1); ?
    SetRestartPoint SaveLoad.SetRestartPoint SetRestartPoint(); game.SaveLoad.SetRestartPoint();
    SetSaveGameDirectory ? Game.SetSaveGameDirectory("My cool game saves"); ? MonoAGS does not have a "save game directory" because when you save a game you select the directory to save in.
    SetTextWindowGUI ? SetTextWindowGUI(4); ?
    SetTimer Stopwatch.Start SetTimer(1, 3000); ... if (IsTimerExpired(1)) {} Stopwatch myTimer = new Stopwatch(); myTimer.Start(); ... if (myTimer.Elapsed.Seconds > 3) {}
    SkipUntilCharacterStops ? SkipUntilCharacterStops(EGO); ?
    StartCutscene Cutscene.Start StartCutscene(); state.Cutscene.Start();
    UpdateInventory N/A UpdateInventory(); N/A Not needed
    UnPauseGame Paused UnPauseGame(); state.Paused = false;
    Wait Task.Delay or Thread.Sleep Wait(80); await Task.Delay(80); or Thread.Sleep(80); Note, that both methods are not perfect fit-ins, as it waits milliseconds and not game loops as in Wait, so we'll need to add another option.
    WaitKey ? WaitKey(200); ?
    WaitMouseKey ? WaitMouseKey(200); ?
    AudioClipCount AudioSystem.AudioClips.Count Game.AudioClipCount game.Audio.AudioClips.Count
    AudioClips AudioSystem.AudioClips Game.AudioClips game.Audio.AudioClips
    CharacterCount calculate yourself Game.CharacterCount state.Rooms.Select(r => r.Objects.Count(o => o is ICharacter)).Sum())
    DialogCount ? Game.DialogCount ?
    FileName use dotnet functions Game.FileName Process.GetCurrentProcess().MainModule.FileName or Path.GetFileName(Assembly.GetEntryAssembly().Location)
    FontCount ? Game.FontCount ?
    GlobalStrings GlobalVariables.Strings Game.GlobalStrings[15] = "Joe"; state.GlobalVariables.Strings.SetValue("ImportantCharacterName", "Joe");
    GUICount state.UI.Count Game.GUICount state.UI.Count
    IgnoreUserInputAfterTextTimeoutMs ? Game.IgnoreUserInputAfterTextTimeoutMs = 1000; ? This is currently hard-coded to 500 ms in MonoAGS (in FastFingerChecker class), and you can bypass it with a custom value like this (should be done at the very start of the game): FastFingerChecker checker = new FastFingerChecker { FastFingerSafeBuffer = 1000 }; Resolver.Override(resolver => resolver.Builder.RegisterInstance(checker));
    InSkippableCutscene Cutscene.IsRunning if (Game.InSkippableCutscene) {} if (state.Cutscene.IsRunning) {}
    InventoryItemCount ? Game.InventoryItemCount ?
    MinimumTextDisplayTimeMs ? Game.MinimumTextDisplayTimeMs = 1000; ? Currently hard-coded to 40 ms in MonoAGS.
    MouseCursorCount ? Game.MouseCursorCount ?
    Name Title Game.Name = "My game"; game.Title = "My game";
    NormalFont AGSGameSettings.DefaultTextFont Game.NormalFont = eFontSpecial; AGSGameSettings.DefaultTextFont = Fonts.Special;
    SkippingCutscene Cutscene.IsSkipping if (!Game.SkippingCutscene) {} if (!state.Cutscene.IsSkipping) {}
    SpeechFont AGSGameSettings.DefaultSpeechFont Game.SpeechFont = eFontStandard; AGSGameSettings.DefaultSpeechFont = Fonts.Standard;
    SpriteHeight sprite.Height Game.SpriteHeight[15] animation.Left.Frames[3].Sprite.Height
    SpriteWidth sprite.Width Game.SpriteWidth[15] animation.Left.Frames[3].Sprite.Width
    TextReadingSpeed SayConfig.TextDelay Game.TextReadingSpeed = 10; cEgo.SayConfig.TextDelay = 100; Note the difference in units: in AGS it stands for "number of characters to read in a second", where in MonoAGS it stands for "number of milliseconds to wait for each character".
    TranslationFilename ? if (Game.TranslationFilename == "German") {} ?
    UseNativeCoordinates N/A if (Game.UseNativeCoordinates) {} N/A Not needed in MonoAGS (there is no low resolution backwards-compatible mode)
    ViewCount ? Game.ViewCount ?

    GUI

    In AGS there's a separation between GUI and GUI controls, where GUI is a panel containing other controls. In MonoAGS there's no distinction like this, as every control can contain other controls, however there is a "Panel" in MonoAGS which is a naked UI control without any other components added to it, which is probably the closest equivalent for AGS "GUI".

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    Centre Position yourself gPanel.Centre(); gPanel.Pivot = new PointF(0.5f, 0.5f); gPanel.X = game.Settings.VirtualResolution.Width / 2; gPanel.Y = game.Settings.VirtualResolution.Height / 2; The example assumes that the panel has no parent and using the default game's resolution.
    GetAtScreenXY hitTest.ObjectAtMousePosition or hitTest.GetObjectAt GUI.GetAtScreenXY(mouse.x, mouse.y) hitTest.ObjectAtMousePosition or hitTest.GetObjectAt(200, 100)
    ProcessClick use hit testing and invoke the interaction event GUI.ProcessClick(100, 50, eModeLookAt); var myGui = hitTest.GetObjectAt(100, 50, obj => obj is IUIControl); myButton?.Interactions.OnInteract(Verbs.Look).InvokeAsync();
    SetPosition Position gPanel.SetPosition(50, 50); gPanel.Position = (50, 50);
    SetSize BaseSize gPanel.setSize(100, 100); gPanel.BaseSize = new SizeF(100, 100);
    BackgroundGraphic Image gPanel.BackgroundGraphic = 5; gPanel.Image = myBackgroundImage;
    Clickable Enabled or ClickThrough gPanel.Clickable = false; gPanel.Enabled = false; or gPanel.ClickThrough = false; Note the different between Enabled and ClickThrough in MonoAGS: Enabled disables the panel and all of the controls within, while ClickThrough disables the panel itself but still allows for inner children to respond.
    ControlCount TreeNode.ChildrenCount gPanel.ControlCount gPanel.TreeNode.ChildrenCount
    Controls TreeNode.Children gPanel.Controls gPanel.TreeNode.Children
    Height BaseSize.Height gPanel.Height = 100; gPanel.BaseSize = new SizeF(gPanel.BaseSize.Width, 100);
    ID ID gPanel.ID gPanel.ID
    Transparency Opacity gPanel.Transparency = 100; gPanel.Opacity = 0; The range for AGS transparency is 0-100, the range for MonoAGS opacity is 0-255
    Visible Visible gPanel.Visible = true; gPanel.Visible = true;
    Width BaseSize.Width gPanel.Width = 100; gPanel.BaseSize = new SizeF(100, gPanel.BaseSize.Height);
    X X gPanel.X = 5; gPanel.X = 5;
    Y Y gPanel.Y = 5; gPanel.Y = 5;
    ZOrder Z gPanel.ZOrder = 5; gPanel.Z = 5;

    Missing in AGS but exists in MonoAGS: scaling and rotating panels, scrolling panels, nesting panels (or any other object) within panels (or any other object), placing GUIs as part of the world (behind non-GUIs), different resolution from the game, custom rendering (including shaders), mouse events (enter, leave, move, click, double-click, down, up, lost focus), sub-pixel positioning, skinning, and also, as panels extend objects, see objects for more stuff.

    GUI Control

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    GetAtScreenXY hitTest.ObjectAtMousePosition or hitTest.GetObjectAt GUIControl.GetAtScreenXY(mouse.x, mouse.y) hitTest.ObjectAtMousePosition or hitTest.GetObjectAt(200, 100)
    AsType as gIconbar.Controls[2].AsButton gIconBar.TreeNode.Children[2] as IButton You can also use is: if (child is IButton button) { button.X = 500; }
    BringToFront Z btnBigButton.BringToFront() btnBigButton.Z = btnBigButton.TreeNode.Parent.TreeNode.Children.Max(c => c.Z) + 1;
    Clickable ClickThrough btnSaveGame.Clickable = false; btnSaveGame.ClickThrough = true;
    Enabled Enabled btnSaveGame.Enabled = false; btnSaveGame.Enabled = false;
    Height BaseSize.Height btnConfirm.Height = 20; btnConfirm.BaseSize = new SizeF(btnConfirm.BaseSize.Width, 20);;
    ID ID btnConfirm.ID btnConfirm.ID
    OwningGUI TreeNode.Parent btnConfirm.OwningGUI btnConfirm.TreeNode.Parent
    SendToBack Z btnBigButton.SendToBack() btnBigButton.Z = btnBigButton.TreeNode.Parent.TreeNode.Children.Min(c => c.Z) - 1;
    SetPosition Position btnConfirm.SetPosition(40, 10); btnConfirm.Position = (40, 10);
    SetSize BaseSize invMain.SetSize(160, 100); invMain.BaseSize = new SizeF(160, 100);
    Visible Visible btnSaveGame.Visible = false; btnSaveGame.Visible = false;
    Width BaseSize.Width btnConfirm.Width = 20; btnConfirm.BaseSize = new SizeF(20, btnConfirm.BaseSize.Height);;
    X X btnConfirm.X = 10; btnConfirm.X = 10;
    Y Y btnConfirm.Y = 20; btnConfirm.Y = 20;
    ZOrder Z btnConfirm.ZOrder = 20; btnConfirm.Z = 20;

    Missing in AGS but exists in MonoAGS: scaling and rotating controls, nesting controls (or any other object) within controls (or any other object), placing GUI controls as part of the world (behind non-GUIs), different resolution from the game, custom rendering (including shaders), mouse events (enter, leave, move, click, double-click, down, up, lost focus), sub-pixel positioning, skinning, and also, as the controls extend objects, see objects for more stuff.

    Button

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    Click MouseClicked.InvokeAsync button.Click() button.MouseClicked.InvokeAsync()
    Animate AnimateAsync btnDeathAnim.Animate(6, 2, 4, eRepeat); btnDeathAnim.AnimateAsync(deathAnimation); //The delay & repeat for the animation is configured in the animation configuration
    Animating Animation.State.IsPaused if (button.Animating) {} if (!button.Animation.State.IsPaused) {}
    Frame Animation.State.CurrentFrame button.Frame button.Animation.State.CurrentFrame
    Loop Animation.State.CurrentLoop button.Loop button.Animation.State.CurrentLoop
    View Animation button.View button.Animation
    ClipImage image is always clipped to the button size btnOK.ClipImage = true; N/A
    Font TextConfig.Font btnOK.Font = eFontMain; btnOK.TextConfig.Font = Fonts.Main;
    Graphic Image btnPlay.Graphic btnPlay.Image
    MouseOverGraphic HoverAnimation btnPlay.MouseOverGraphic = 5; btnPlay.HoverAnimation = buttonHoverAnimation;
    NormalGraphic IdleAnimation btnPlay.NormalGraphic = 5; btnPlay.IdleAnimation = buttonIdleAnimation;
    PushedGraphic PushedAnimation btnPlay.PushedGraphic = 5; btnPlay.PushedAnimation = buttonPushedAnimation;
    Text Text btnPlay.Text = "Play"; btnPlay.Text = "Play";
    TextColor TextConfig.Brush btnPlay.TextColor = 15; btnPlay.TextConfig.Brush = solidWhiteBrush;

    Missing in AGS but exists in MonoAGS: animations for button states, shadows + outlines/text brushes/alignments/auto-fitting, borders, see GUI controls for more.

    InvWindow

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    ScrollDown ScrollDown invMain.ScrollDown(); invMain.ScrollDown();
    ScrollUp ScrollUp invMain.ScrollUp(); invMain.ScrollUp();
    CharacterToUse Inventory invMain.CharacterToUse = cJack; invMain.Inventory = cJack.Inventory;
    ItemAtIndex Inventory.Items[] item = invMain.ItemAtIndex[0]; item = invMain.Inventory.Items[0];
    ItemCount Inventory.Items.Count invMain.ItemCount invMain.Inventory.Items.Count
    ItemHeight ItemSize.Height invMain.ItemHeight = 30; invMain.ItemSize = new SizeF(50, 30);
    ItemWidth ItemSize.Width invMain.ItemWidth = 50; invMain.ItemSize = new SizeF(50, 30);
    ItemsPerRow ItemsPerRow invMain.ItemsPerRow invMain.ItemsPerRow
    RowCount RowCount invMain.RowCount invMain.RowCount
    TopItem TopItem invMain.TopItem = 0; invMain.TopItem = 0;

    Missing in AGS but exists in MonoAGS: The ability to attach inventories (and show them in the inventory window) to non-characters, see GUI controls for more.

    Label

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    Font TextConfig.Font lblStatus.Font = eFontMain; lblStatus.TextConfig.Font = Fonts.Main;
    Text Text lblStatus.Text = "Play"; lblStatus.Text = "Play";
    TextColor TextConfig.Brush lblStatus.TextColor = 15; lblStatus.TextConfig.Brush = solidWhiteBrush;

    Missing in AGS but exists in MonoAGS: shadows + outlines/text brushes/alignments/auto-fitting, borders, see GUI controls for more.

    ListBox

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    AddItem Items.Add lstChoices.AddItem("Hello"); lstChoices.Items.Add(new AGSStringItem("Hello"));
    Clear Items.Clear lstChoices.Clear(); lstChoices.Items.Clear();
    FillDirList ? lstSaveGames.FillDirList("agssave.*"); ?
    FillSaveGameList ? lstSaveGames.FillSaveGameList(); ?
    GetItemAtLocation hitTest.ObjectAtMousePosition or hitTest.GetObjectAt lstOptions.GetItemAtLocation(mouse.x, mouse.y) hitTest.ObjectAtMousePosition or hitTest.GetObjectAt(200, 100)
    InsertItemAt Items.Insert lstChoices.InsertItemAt(1, "Third item"); lstChoices.Items.Insert(1, new AGSStringItem("Third item"));
    RemoveItem Items.RemoveAt lstChoices.RemoveItem(0); lstChoices.Items.RemoveAt(0);
    ScrollDown ? lstTest.ScrollDown();
    ScrollUp ? lstTest.ScrollUp();
    Font either set fonts on individual rows in the listbox, or set a default font in the factory lstSaveGames.Font = eFontSpeech; For individual rows: lstSaveGames.ItemButtons[3].TextConfig.Font = Fonts.MyFont;, a global font using a factory: var defaultFactory = lstSaveGames.ItemButtonFactory; lstSaveGames.ItemButtonFactory = text => { var button = defaultFactory(text); button.TextConfig.Font = Fonts.MyFont; }
    HideBorder Border lstSaveGames.HideBorder = true; lstSaveGames.Border = null;
    HideScrollArrows Scrolling component.Vertical/HorizontalScrollBar lstSaveGames.HideScrollArrows = true; var scrolling = lstSaveGames.GetComponent<IScrollingComponent>(); scrolling.VerticalScrollBar = null;
    ItemCount Items.Count lstChoices.ItemCount lstChoices.Items.Count
    Items Items lstOptions.Items[3] lstOptions.Items[3]
    RowCount ? lstOptions.RowCount ? Note, that the listbox in MonoAGS has a smooth scrollbar, meaning it might show part of a row if the scrollbar is set just in the middle of the row.
    SaveGameSlots ? lstSaveGames.SaveGameSlots[index] ?
    SelectedIndex SelectedIndex lstSaveGames.SelectedIndex lstSaveGames.SelectedIndex
    TopItem ? lstSaveGames.TopItem = 0; ?
    Translated ? if (lstOptions.Translated) {} ?

    Missing in AGS but exists in MonoAGS: smooth scrolling for the listbox, SelectedItem, control individual appearances of rows/scrollbars/panel, allow automatic resizing of the box with minimum and maximum height, change events, search filter, see GUI controls for more.

    Slider

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    BackgroundGraphic Graphics sldHealth.BackgroundGraphic = 5; sldHealth.Graphics = animatedSliderBackground;
    HandleGraphic HandleGraphics sldHealth.HandleGraphic = 6; sldHealth.HandleGraphics = animatedSliderHandle;
    HandleOffset Add the jump component to the handle graphics sldHealth.HandleOffset = 2; var jump = sldHealth.HandleGraphics.AddComponent<IJumpOffsetComponent>(); jump.JumpOffset = new PointF(2, 0);
    Max MaxValue sldHealth.Max = 200; sldHealth.MaxValue = 200;
    Min MinValue sldHealth.Min = 200; sldHealth.MinValue = 200;
    Value Value sldHealth.Value = 100; sldHealth.Value = 100;

    Missing in AGS but exists in MonoAGS: animations for slider background + handle, subscribing to slider events, non-integer values for the slider, see GUI controls for more.

    Text Box

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    Font TextConfig.Font txtUserInput.Font = eFontNormal; txtUserInput.TextConfig.Font = Fonts.MyFont;
    Text Text txtUserInput.Text = "Hello"; txtUserInput.Text = "Hello";
    TextColor TextConfig.Brush txtUserInput.TextColor = 5; txtUserInput.TextConfig.Brush = solidRedBrush;

    Missing in AGS but exists in MonoAGS: configuring background color/shadows + outlines/text brushes/borders/alignments/auto-fitting, configure caret flashing speed, query and set the caret position, set a watermark for the textbox, focus/unfocus, subscribe to text change events on the textbox with the option to undo entered text, see GUI controls for more.

    Hotspot

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    GetAtScreenXY IHitTest.ObjectAtMousePosition or IHitTest.GetObjectAt if (Hotspot.GetAtScreenXY(mouse.x, mouse.y) == hDoor){} if (hitTest.ObjectAtMousePosition == hDoor) {} or if (hitTest.GetObjectAt(200, 100) == hDoor) {}
    GetProperty Properties.Ints.GetValue if (hDoor.GetProperty("Value") > 200) {} if (hDoor.Properties.Ints.GetValue("Value") > 200) {}
    GetTextProperty Properties.Strings.GetValue hDoor.GetTextProperty("Description"); hDoor.Properties.Strings.GetValue("Description");
    SetProperty Properties.Ints.SetValue hDoor.SetProperty("Value", 200); hDoor.Properties.Ints.SetValue("Value", 200);
    SetTextProperty Properties.Strings.SetValue hDoor.SetTextProperty("Description", "Nice door"); hDoor.Properties.Strings.SetValue("Description", "Nice door");
    IsInteractionAvailable checking subscriber count on the interaction event if (hTable.IsInteractionAvailable(eModeLookat) == 0) {} if (hTable.Interactions.OnInteract(Verbs.Look).SubscribersCount == 0) {}
    RunInteraction Interactions.OnInteract(Verb).InvokeAsync hDoor.RunInteraction(eModeLookat); hDoor.Interactions.OnInteract(Verbs.Look).InvokeAsync();
    Enabled Enabled hDoor.Enabled = false; hDoor.Enabled = false;
    ID ID hDoor.ID hDoor.ID
    Name DisplayName hDoor.Name hDoor.DisplayName
    WalkToX WalkPoint.X hDoor.WalkToX hDoor.WalkPoint.X
    WalkToY WalkPoint.Y hDoor.WalkToY hDoor.WalkPoint.Y

    Missing in AGS but exists in MonoAGS: Change hotspot name at run-time, change hotspot walk-point at run-time, rotating/scaling hotspot area (at run-time), and as hotspot extends object, see Object for more.

    Inventory Item

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    GetAtScreenXY IHitTest.ObjectAtMousePosition or IHitTest.GetObjectAt if (InventoryItem.GetAtScreenXY(mouse.x, mouse.y) == iKnife){} if (hitTest.ObjectAtMousePosition == iKnife.Graphics) {} or if (hitTest.GetObjectAt(200, 100) == iKnife.Graphics) {}
    GetProperty Properties.Ints.GetValue if (iKnife.GetProperty("Value") > 200) {} if (iKnife.Graphics.Properties.Ints.GetValue("Value") > 200) {}
    GetTextProperty Properties.Strings.GetValue iKnife.GetTextProperty("Description"); iKnife.Graphics.Properties.Strings.GetValue("Description");
    SetProperty Properties.Ints.SetValue iKnife.SetProperty("Value", 200); hDoor.Properties.Ints.SetValue("Value", 200);
    SetTextProperty Properties.Strings.SetValue iKnife.SetTextProperty("Description", "Nice knife"); iKnife.Properties.Strings.SetValue("Description", "Nice knife");
    IsInteractionAvailable checking subscriber count on the interaction event if (iKeyring.IsInteractionAvailable(eModeLookat) == 0) {} if (iKeyring.Interactions.OnInteract(Verbs.Look).SubscribersCount == 0) {}
    RunInteraction Interactions.OnInteract(Verb).InvokeAsync iKeyring.RunInteraction(eModeLookat); iKeyring.Interactions.OnInteract(Verbs.Look).InvokeAsync();
    CursorGraphic CursorGraphics iKey.CursorGraphic = 5; iKey.CursorGraphics = animatedKeyCursor;
    Graphic Graphics iKey.Graphic = 5; iKey.Graphics = animatedKey;
    ID Graphics.ID iKey.ID iKey.Graphics.ID
    Name Graphics.DisplayName iKey.Name iKey.Graphics.DisplayName

    Missing in AGS but exists in MonoAGS: animated inventory items (and cursors), inventory items extend objects so you can do with them everything you can do with objects (rotate, scale, etc), see Object for more.

    Maths

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    FloatToInt Floor or Ceiling or Round followed by casting to int FloatToInt(10.7, eRoundNearest) (int)Math.Round(10.7f)
    IntToFloat cast to float IntToFloat(myIntValue) (float)myIntValue
    ArcCos Acos float angle = Maths.ArcCos(1.0); float angle = Math.Acos(1);
    ArcSin Asin float angle = Maths.ArcSin(0.5); float angle = Math.Asin(0.5f);
    ArcTan Atan float angle = Maths.ArcTan(0.5); float angle = Math.Atan(0.5f);
    ArcTan2 Atan2 float angle = Maths.ArcTan2(-862.42, 78.5149);
    Cos Cos float x = Maths.Cos(100); float x = Math.Cos(100);
    Cosh Cosh float x = Maths.Cosh(100); float x = Math.Cosh(100);
    DegreesToRadians MathUtils.DegreesToRadians float radians = Maths.DegreesToRadians(360.0); float radians = MathUtils.DegreesToRadians(360);
    Exp Exp float expValue = Maths.Exp(2.302585093); float expValue = Math.Exp(2.302585093f);
    Log Log float logVal = Maths.Log(9000.0); float logVal = Math.Log(9000);
    Log10 Log10 float logVal = Maths.Log10(9000.0); float logVal = Math.Log10(9000);
    RadiansToDegrees ? float val = Maths.RadiansToDegrees(angle); float val = angle * (180f / Math.PI);
    RaiseToPower Pow float value = Maths.RaiseToPower(4.5, 3.0); float value = Math.Pow(4.5f, 3);
    Sin Sin float value = Maths.Sin(50.0); float value = Math.Sin(50);
    Sinh Sinh float value = Maths.Sinh(50.0); float value = Math.Sinh(50);
    Sqrt Sqrt float value = Maths.Sqrt(9.0); float value = Math.Sqrt(9);
    Tan Tan float value = Maths.Tan(9.0); float value = Math.Tan(9);
    Tanh Tanh float value = Maths.Tanh(9.0); float value = Math.Tan(9);
    Pi PI Maths.Pi Math.PI

    Missing in AGS but exists in MonoAGS: well, almost nothing here is MonoAGS specific, this is all c# Math class, which you can view here: https://msdn.microsoft.com/en-us/library/system.math(v=vs.110).aspx Also, MonoAGS has some additional useful math methods in MathUtils like Lerp and Clamp which can be useful.

    Mouse

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    ChangeModeGraphic input.Cursor mouse.ChangeModeGraphic(eModeLookat, 120); game.Input.Cursor = myLookCursor; Note that the AGS "ChangeModeGraphic" function changes how the mouse cursor automatically changes, and the example shown here changes the cursor manually. For automatic changes, each control scheme might have different methods that you need to call as the logic might be completely different. For the rotating cursors scheme, for example, you'd call scheme.AddCursor(Verbs.Look, myLookCursor, true);
    ChangeModeHotspot change the pivot point on the cursor's object mouse.ChangeModeHotspot(eModeWalkTo, 10, 10); walkCursor.Pivot = new PointF(0.1f, 0.1f); Note that the pivot point is in relative co-ordinates to the graphics, so (0.5, 0.5) is the center of the image, for example.
    ChangeModeView input.Cursor mouse.ChangeModeView(eModeLookat, ROLLEYES); game.Input.Cursor = myLookCursor; See notes on ChangeModeGraphic
    Click input.MouseDown.InvokeAsync and input.MouseUp.InvokeAsync Mouse.Click(eMouseLeft); input.MouseDown.InvokeAsync(new MouseButtonEventArgs(null, MouseButton.Left, input.MousePosition));
    ControlEnabled ? if (Mouse.ControlEnabled) {} ?
    DisableMode ? mouse.DisableMode(eModeWalkto); ?
    EnableMode ? mouse.EnableMode(eModeWalkto); ?
    GetModeGraphic ? mouse.GetModeGraphic(eModeWalkto); ? There's nothing specific, but you can just query the specific mouse cursor that you're interested about
    IsButtonDown LeftMouseButtonDown or RightMouseButtonDown if (mouse.IsButtonDown(eMouseRight)) {} if (game.Input.RightMouseButtonDown)
    SaveCursorUntilItLeaves use the cursor component when hovering over "myHotspot": mouse.SaveCursorUntilItLeaves(); mouse.Mode = eModeTalk; var cursorComponent = myHotspot.AddComponent<IHasCursorComponent>(); cursorComponent.SpecialCursor = myAnimatedSpecialCursorForThisHotspot;
    SelectNextMode ? Mouse.SelectNextMode() In MonoAGS, by choosing the RotatingCursorsScheme as your control scheme, this is already handled (and you can look at the code if you want to handle it differently)
    SelectPreviousMode ? Mouse.SelectPreviousMode(); ?
    SetBounds Subscribe to mouse move event and change the position of the mouse accordingly mouse.SetBounds(160, 100, 320, 200); game.Input.MouseMove.Subscribe(args => if (args.MousePosition.XWindow > 160) OpenTK.Mouse.SetPosition(160, args.MousePosition.YWindow));
    SetPosition OpenTK.Mouse.SetPosition mouse.SetPosition(160, 100); OpenTK.Mouse.SetPosition(160, 100);
    Speed ? Mouse.Speed = 1.5; ?
    Update ? mouse.Update(); ?
    UseDefaultGraphic ? mouse.UseDefaultGraphic(); ?
    UseModeGraphic N/A mouse.UseModeGraphic(eModeWait) ? This can be different depending on the control scheme you chose for the game. For the RotatingCursorsScheme for example, you'd write: scheme.Mode = Verbs.Wait;
    Mode input.Cursor if (mouse.Mode == eModeWalkto) {} if (game.Input.Cursor == myWalkCursor) {} For individual control schemes, you might have the concept of "Mode", but it's not related to the mouse. In RotatingCursorsScheme, for example, you can query if (scheme.Mode == Verbs.Walk) {}.
    Visible Input.Cursor.Visible mouse.Visible = false; game.Input.Cursor.Visible = false;

    Missing in AGS but exists in MonoAGS: The cursors is just an extension of objects, so they can be manipulated in all ways an object can be manipulated (see Object for more).

    Multimedia

    Currently there are no equivalents to any of the multimedia functions in MonoAGS.

    Object

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    Animate AnimateAsync oRope.Animate(3, 1, 0, eBlock, eBackwards); For blocking: await oRope.AnimateAsync(jumpUpAnimation);. For non-blocking, do the same just without awaiting it: oRope.AnimateAsync(jumpUpAnimation);. As for delay, repeat style and direction, those are configured as part of the animation ("jumpUpAnimation" in this scenario). It can be changed at run-time before animating, if you want. For example: jumpUpAnimation.Looping = LoopingStyle.BackwardsForwards; jumpUpAnimation.Loops = 15; jumpUpAnimation.DelayBetweenFrames = 3; Note that MonoAGS doesn't have the concepts of view and loop, just individual animations for manual animations, and directional animations for automatic animations like walk and idle.
    GetAtScreenXY IHitTest.ObjectAtMousePosition or IHitTest.GetObjectAt if (Object.GetAtScreenXY(mouse.x, mouse.y) == oRope){} if (hitTest.ObjectAtMousePosition == oRope) {} or if (hitTest.GetObjectAt(200, 100) == oRope) {}
    GetProperty Properties.Ints.GetValue if (oRope.GetProperty("Value") > 200) {} if (oRope.Properties.Ints.GetValue("Value") > 200) {}
    GetTextProperty Properties.Strings.GetValue oRope.GetTextProperty("Description"); oRope.Properties.Strings.GetValue("Description");
    SetProperty Properties.Ints.SetValue oRope.SetProperty("Value", 200); oRope.Properties.Ints.SetValue("Value", 200);
    SetTextProperty Properties.Strings.SetValue oRope.SetTextProperty("Description", "Nice rope"); oRope.Properties.Strings.SetValue("Description", "Nice rope");
    IsCollidingWithObject (character) CollidesWith if (oRope.IsCollidingWithChar(oBottle) == 1) {} if (oRope.CollidesWith(oBottle.X, oBottle.Y, state.Viewport)) {} Note that MonoAGS supports multiple viewports so we need to pass the viewport in which we'd like to test for collisions.
    MergeIntoBackground ? object[3].MergeIntoBackground(); ?
    Move TweenX & TweenY object[2].Move(125, 40, 4, eBlock); For blocking: await oRope.TweenX(125, 3, Ease.Linear);, for non-blocking do the same just without awaiting it: oRope.TweenX(125, 3, Ease.Linear);
    RemoveTint Tint oRope.RemoveTint(); oRope.Tint = Colors.White;
    IsInteractionAvailable checking subscriber count on the interaction event if (oRope.IsInteractionAvailable(eModeLookat) == 0) {} if (oRope.Interactions.OnInteract(Verbs.Look).SubscribersCount == 0) {}
    RunInteraction Interactions.OnInteract(Verb).InvokeAsync oRope.RunInteraction(eModeTalk); oRope.Interactions.OnInteract(Verbs.Talk).InvokeAsync();
    SetLightLevel Brightness oRope.SetLightLevel(100); oRope.Brightness = new Vector4(2,2,2,2);
    SetPosition Position oRope.SetPosition(50, 50); oRope.Position = (50, 50);
    SetView N/A object[3].SetView(14); No need In AGS this is a command that must come before calling "Animate" so that AGS would know which animation to run. In MonoAGS you just pass the animation object to the "Animate" function, so SetView becomes redundant.
    StopAnimating Set an image oRope.StopAnimating(); oRope.Image = oRope.CurrentSprite.Image;
    StopMoving Stop the previous tween(s) oRope.StopMoving(); tween.Stop(TweenCompletion.Stay);
    Tint Tint oRope.Tint(0, 250, 0, 30, 100); oRope.Tint = Colors.Green; or cEoRopego.Tint = Color.FromRgba(0, 255, 0, 255); or oRope.Tint = Color.FromHsla(200, 1, 1, 255); or oRope.Tint = Color.FromHexa(59f442);
    Animating Animation.State.IsPaused if (oRope.Animating) {} if (!oRope.Animation.State.IsPaused) {}
    Baseline Z oRope.Baseline = 40; oRope.Z = 40;
    BlockingHeight ? oRope.BlockingHeight = 20; ?
    BlockingWidth ? oRope.BlockingWidth = 20; ?
    Clickable Enabled oRope.Clickable = false; oRope.Enabled = false;
    Frame Animation.State.CurrentFrame oRope.Frame oRope.Animation.State.CurrentFrame
    Graphic Image oRope.Graphic = 100; oRope.Image = ropeImage;
    HasExplicitLight compare Brightness if (oRope.HasExplicitLight) {} if (!oRope.Brightness.Equals(new Vector4(1,1,1,1))) {}
    HasExplicitTint compare Tint if (oRope.HasExplicitTint) {} if (oRope.Tint != Colors.White) {}
    ID ID oRope.ID oRope.ID
    IgnoreScaling IgnoreScalingArea oRope.IgnoreScaling = true; oRope.IgnoreScalingArea = true;
    IgnoreWalkbehinds ? oRope.IgnoreWalkbehinds = true; ? Probably not really needed in MonoAGS- with the combination of render layers, Z and parent-child relationships you have the ability control rendering order more easily
    LightLevel Brightness oRope.LightLevel oRope.Brightness
    Loop Animation.State.CurrentLoop oRope.Loop oRope.Animation.State.CurrentLoop
    Moving query the previous tween(s) if (oRope.Moving) {} if (myTween.State == TweenState.Playing) {}
    Name DisplayName oRope.Name oRope.DisplayName
    Solid ? oRope.Solid = true; ?
    TintBlue Tint.B oRope.TintBlue oRope.Tint.B
    TintGreen Tint.G oRope.TintGreen oRope.Tint.G
    TintRed Tint.R oRope.TintRed oRope.Tint.R
    TintSaturation Tint.GetSaturation oRope.TintSaturation oRope.Tint.GetSaturation()
    TintLuminance Tint.GetLightness oRope.TintLuminance oRope.Tint.GetLightness()
    Transparency Opacity oRope.Transparency = 100; oRope.Opacity = 0; The range for AGS transparency is 0-100, the range for MonoAGS opacity is 0-255
    View Animation oRope.View oRope.Animation
    Visible Visible oRope.Visible = true; oRope.Visible = true;
    X X oRope.X = 50; oRope.X = 50.5f;
    Y Y oRope.Y = 50; oRope.Y = 50.5f;

    Missing in AGS but exists in MonoAGS: scaling and rotating (with setting a pivot point), the ability to scale/rotate/translate individual animation frames, composition of objects (i.e nesting objects in other objects), mix & match with GUI, move between rooms, different resolution from the game, custom rendering (including shaders), sub-pixel positioning, rendering in multiple viewports, creation at run-time, selecting between pixel perfect or bounding box collision checks, objects are transitive with all other on-screen items (characters, GUIs), cropping objects, surround with borders, set hotspot text at runtime, controlling texture offset & scaling filter (per texture), subscribing to events (on pretty much anything that might change in any of the components), interactions with custom verbs, ability to extend objects with custom components, ability to replace engine implementation of components with your own (i.e implement your own collider component and provide custom collision checks, for example).

    Overlay

    The whole concept of overlays in AGS is for allowing to show graphics/text at run-time. In MonoAGS, all objects can be created at run-time so the whole concept of "overlay" is not really needed.

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    CreateGraphical Create an object Overlay* myOverlay = Overlay.CreateGraphical(100, 100, 300, true); IObject myObj = game.Factory.Object.GetObject("id for my object"); myObj.Image = game.Factory.Graphics.LoadImageAsync("overlay.png"); myObj.X = 100; myObj.Y = 100; game.State.Room.Objects.Add(myObj);
    CreateTextual Create a label Overlay* myOverlay = Overlay.CreateTextual(50,80,120, Game.SpeechFont, 15,"This is a text overlay"); ILabel myLabel = game.Factory.UI.GetLabel("id for my label", "This is a text overlay", 120, 0, 50, 80, addToUi: false); myLabel.TextConfig.AutoFit = AutoFit.TextShouldWrapAndLabelShouldFitHeight; myLabel.TextConfig.Font = AGSGameSettings.DefaultSpeechFont; game.State.Room.Objects.Add(myLabel); Note that when getting the label from the factory we passed "addToUi: false", this is to closely simulate the overlay behavior in AGS, where the overlay is local to the room and not global like a GUI (so instead of adding to UI, we add the label to the current room). This is still not identical behavior, as the AGS overlay gets removed when you switch to another room, and in MonoAGS the label will still be there if you return to the room (if you want the exact same behavior, subscribe to the room leave event and remove the label).
    Remove Remove the object from the room (or from the global GUI list) myOverlay.Remove(); If the object is in a specific room: myRoom.Objects.Remove(myObj);, and if the object is in the global GUI list: game.State.UI.Remove(myObj);
    SetText Set desired properties on the label myOverlay.SetText(120,Game.SpeechFont,15,"This is another text overlay"); myLabel.Text = "This is another text overlay"; myLabel.BaseSize = new SizeF(120, 0); myLabel.TextConfig.Font = AGSGameSettings.DefaultSpeechFont; myLabel.TextConfig.Brush = game.Factory.Graphics.Brushes.LoadSolidBrush(Colors.Red);
    Valid Check if the object is contained in room (or global GUI list) if (myOverlay.Valid) {} Checking in a specific room: if (room.Objects.Contains(myObj) {}, checking in global GUI list: if (game.State.UI.Contains(myObj)) {}
    X X myOverlay.X = 5; myObj.X = 5;
    Y Y myOverlay.Y = 5; myObj.Y = 5;

    Missing in AGS but exists in MonoAGS: no limits to the number of presented overlays, overlays are just objects so can be treated exactly the same as objects (like rotating/scaling), see the Object section for more details.

    Palette

    Currently there are no equivalents to the palette in MonoAGS (if you want to implement something like this, it would probably require writing a custom shader).

    Parser

    Currently there are no equivalents to the parser in MonoAGS, you'll have to program parsing logic yourself (but you can use a textbox and subscribe to key pressed events on the textbox).

    Region

    Currently there are no equivalents to regions in MonoAGS.

    Room

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    AreThingsOverlapping CollidesWith if (AreThingsOverlapping(1002, EGO)) {} if (cEgo.CollidesWith(oBullet.X, oBullet.Y, game.State.Viewport)) {} Note that in MonoAGS, if the colliding objects have the pixel-perfect component enabled, the collision checks will be accurate, and not using a bounding box like in AGS.
    DisableGroundLevelAreas manually disable areas & edges DisableGroundLevelAreas(0); foreach (var area in myRoom.Areas) { area.Enabled = false; } foreach (var edge in myRoom.Edges) { edge.Enabled = false; }
    EnableGroundLevelAreas manually enable areas & edges EnableGroundLevelAreas(); foreach (var area in myRoom.Areas) { area.Enabled = true; } foreach (var edge in myRoom.Edges) { edge.Enabled = true; }
    GetBackgroundFrame Background.Animation.State.CurrentFrame if (GetBackgroundFrame()==4) {} if (state.Room.Background.Animation.State.CurrentFrame == 4) {}
    GetDrawingSurfaceForBackground ? DrawingSurface *surface = Room.GetDrawingSurfaceForBackground(); ? No built-in way, but you can implement a custom renderer for the background and draw whatever you want.
    GetProperty Properties.Bools/Ints/etc if (Room.GetProperty("CanBeAttackedHere")) {} if (myRoom.Properties.Bools.GetValue("CanBeAttackedHere")) {}
    GetTextProperty Properties.Strings Room.GetTextProperty("Description"); myRoom.Properties.Strings.GetValue("Description");
    SetProperty Properties.Ints.SetValue Room.SetProperty("XPLevel", 10); myRoom.Properties.Ints.SetValue("XPLevel", 10);
    SetTextProperty Properties.Strings.SetValue Room.SetTextProperty("Description", "I am handsome!"); myRoom.Properties.Strings.SetValue("Description", "I am handsome!");
    GetScalingAt GetMatchingAreas and then calculate it yourself if (GetScalingAt(player.x, player.y) == 100) {} `float getAreaScalingWidth(IRoom room, IObject obj) { foreach (IArea are in room.GetMatchingAreas(obj.Position.XY, obj.ID)) { IScalingArea scaleArea = area.GetComponent(); is (scaleArea == null
    GetViewportX viewport.X if (GetViewportX() > 100) {} if (state.Viewport.X > 100) {} Note that in MonoAGS you can have multiple viewports, which you can access using the "SecondaryViewports" property: if (state.SecondaryViewports[0].X > 100) {}
    GetViewportY viewport.Y `if (GetViewportY() > 100) {} if (state.Viewport.Y > 100) {} Note that in MonoAGS you can have multiple viewports, which you can access using the "SecondaryViewports" property: if (state.SecondaryViewports[0].Y > 100) {}
    GetWalkableAreaAt GetMatchingAreas and then calculate it yourself if (GetWalkableAreaAt(mouse.x,mouse.y) == 0) {} private IArea getWalkableAreaAt(IRoom room, IObject obj) { return room.GetMatchingAreas(obj.Position.XY, obj.ID).FirstOrDefault(area => area.GetComponent<IWalkableArea>()?.IsWalkable ?? false); } ... if (getWalkableAreaAt(myRoom, myObj) == null) {} Note that it's not enough to just pass x,y to get the walkable area, we also need to pass the actual object- that's because in MonoAGS areas might be configured to include/exclude specific objects.
    HasPlayerBeenInRoom ? if (HasPlayerBeenInRoom(14)) {} ? Note that while this is not built-in, it can be programmed easily if needed: when entering the room you're interested in tracking, you can run Repeat.Do("playerInMySpecialRoom");, and then, for testing "HasPlayerBeenInRoom", you can run if (Repeat.Current("playerInMySpecialRoom") >= 1) {}
    ProcessClick Use hit testing and invoke the interaction event Room.ProcessClick(100, 50, eModeLookAt); var obj = hitTest.GetObjectAt(100, 50); obj?.Interactions.OnInteract(Verbs.Look).InvokeAsync(new ObjectEventArgs(oKnife));
    ReleaseViewport viewport.Camera.Enabled ReleaseViewport(); state.Viewport.Camera.Enabled = true; Note that in MonoAGS you can have multiple viewports, which you can access using the "SecondaryViewports" property: state.SecondaryViewports[0].Camera.Enabled = true;
    RemoveWalkableArea area.Enabled RemoveWalkableArea(5); myArea.Enabled = false; Note, that unlike AGS, the change is permanent, it does not reset when you switch rooms
    ResetRoom ? ResetRoom(0); ?
    RestoreWalkableArea area.Enabled RestoreWalkableArea(5); myArea.Enabled = true;
    SetAreaScaling scalingArea.MinScaling/MaxScaling SetAreaScaling(5, 120, 170); var scalingArea = area.GetComponent<IScalingArea>(); scalingArea.MinScaling = 1.2f; scalingArea.MaxScaling = 1.7f; Note that in MonoAGS the scaling value is the factor in which scaling is multiplied (so 100 scaling in AGS is 1 scaling in MonoAGS), and unlike AGS there are no limits to the scaling.
    SetBackgroundFrame Background.Image SetBackgroundFrame(4); and to get back to the animation: SetBackgroundFrame(-1); myRoom.Background.Image = myRoom.Background.Animation.Frames[4].Sprite.Image and to get back to the animation myRoom.Background.StartAnimation(myRoomAnimation); Note that there is no "4 animation frames" limit in MonoAGS like there is in AGS
    SetViewport Disable the camera and then set viewport x/y SetViewport(100, 100); state.Viewport.Camera.Enabled = false; state.Viewport.X = 100; state.Viewport.Y = 100;
    SetWalkBehindBase Baseline SetWalkBehindBase (3,0); var walkbehind = area.GetComponent<IWalkBehindArea>(); walkbehind.Baseline = 0;
    BottomEdge Edges.Bottom.Value Room.BottomEdge myRoom.Edges.Bottom.Value
    ColorDepth ? Room.ColorDepth ? This is probably not needed in MonoAGS, mix & match images with different color depths should work.
    Height Limits.Height Room.Height myRoom.Limits.Height
    LeftEdge Edges.Left.Value Room.LeftEdge myRoom.Edges.Left.Value
    Messages Properties.Strings String description = Room.Messages[1]; string dsescription = myRoom.Properties.Strings.GetValue("MyRoomDescription");
    MusicOnLoad MusicOnLoad Room.MusicOnLoad myRoom.MusicOnLoad
    ObjectCount Objects.Count Room.ObjectCount myRoom.Objects.Count Note that in MonoAGS this includes the characters in the room (as characters are also objects)
    RightEdge Edges.Right.Value Room.RightEdge myRoom.Edges.Right.Value
    TopEdge Edges.Top.Value Room.TopEdge myRoom.Edges.Top.Value
    Width Limits.Width Room.Width myRoom.Limits.Width

    Missing in AGS but exists in MonoAGS: no limits on the scaling areas, no limits on the number of animation frames for the background, multiple viewports, restriction lists to include/exclude specific entities from specific areas, separate horizontal/vertical scaling for scaling areas, set the scaling axis for scaling areas, can set custom properties at run-time, can create rooms at run-time, can subscribe/unsubcribe events at run-time, set custom limits for the room (including "endless" rooms), enable/disable specific areas & edges, volume scaling areas, camera zoom areas, zoom/scale the viewport.

    Screen

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    FadeIn ? FadeIn(10); ?
    FadeOut ? FadeOut(30); ?
    FlipScreen ? FlipScreen(1); ?
    SetFadeColor ? SetFadeColor(200, 0, 0); ?
    SetNextScreenTransition state.RoomTransitions.SetOneTimeNextTransition SetNextScreenTransition(eTransitionBoxout); state.RoomTransitions.SetOneTimeNextTransition(AGSRoomTransitions.BoxOut()); Note that you can give more options to the room transition in MonoAGS, for example: AGSRoomTransitions.BoxOut(timeInSeconds: 3, easeBoxOut: Ease.CubeIn, easeBoxIn: Ease.CubeOut)
    SetScreenTransition state.RoomTransitions.Transition SetScreenTransition(eTransitionFade); state.RoomTransitions.Transition = AGSRoomTransitions.Fade(); Note that you can give more options to the room transition in MonoAGS, for example: AGSRoomTransitions.Fade(timeInSeconds: 3.5f, easeFadeOut: Ease.CubeIn, easeFadeIn: Ease.CubeOut)
    ShakeScreen ShakeEffect ShakeScreen(5); ShakeEffect effect = new ShakeEffect (); await effect.RunAsync(TimeSpan.FromSeconds(5));
    ShakeScreenBackground ShakeEffect ShakeScreenBackground (4, 10, 80); ShakeEffect effect = new ShakeEffect(strength: 0.1f, decay: 0.9f); effect.RunAsync(TimeSpan.FromSeconds(5));
    TintScreen ? TintScreen (100, 50, 50); ?

    Missing in AGS but exists in MonoAGS: Customize time and easing for built in room transitions, code your own custom room transitions, shake can be applied to individual objects (not just the screen), custom shaders to generate all sorts of effects.

    Speech

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    AnimationStopTimeMargin ? Speech.AnimationStopTimeMargin = 40; ?
    CustomPortraitPlacement PortraitConfig.Positioning Speech.CustomPortraitPlacement = true; cEgo.SayConfig.PortraitConfig.Positioning = PortraitPositioning.Custom;
    DisplayPostTimeMs ? Speech.DisplayPostTimeMs = 40; ? This is currently hard-coded as 40 milliseconds
    GlobalSpeechAnimationDelay ? Speech.GlobalSpeechAnimationDelay = 5; ?
    PortraitXOffset PortraitConfig.PortraitOffset Speech.PortraitXOffset = 5; cEgo.SayConfig.PortraitConfig.PortraitOffset = (5, 0);
    PortraitY PortraitConfig.PortraitOffset Speech.PortraitY = 5; cEgo.SayConfig.PortraitConfig.PortraitOffset = (0, 5);
    SkipKey Use custom skipping and skip on key press Speech.SkipKey = eKeySpace; cEgo.OnBeforeSay.Subscribe(args => input.OnKeyDown.Subscribe(keyArgs => if (keyArgs.Key == Key.Space) { args.SkipText();}););
    SkipStyle SpeechConfig.SkipText Speech.SkipStyle = eSkipTime; player.SpeechConfig.SkipText = SkipText.ByTime; Note that the example given in MonoAGS is for setting the skip style for a specific character, not a global change like in AGS. Also you can do custom skipping by subscribing to OnBeforeSay, see the example on SkipKey.
    Style customize to your liking Speech.Style = eSpeechSierra; N/A For the "lucas arts" style (text over character's head), do nothing, that's the default. For the "sierra" style, set a portrait in the charater's speech config: cGraham.SpeechConfig.PortraitConfig.Portrait = grahamPortrait;. For the "sierra with background" style, set a portrait as before, and also set BackgroundColor in the character's speech config: cGraham.SpeechConfig.BackgroundColor = Colors.Pink;. For "QFG4-style full screen", set the portrait object to be a full-screen size object, and for customizing where the speech text and portrait will be located, you need to provide your custom implementation for ISayLocationProvider and then replace the default implementation. For example, this custom implementation will place both text and portrait in the bottom-left of the screen: public class Qfg4StyleSayLocationProvider : ISayLocationProvider { public ISayLocation GetLocation(string text, ISayConfig config) { var textLocation = new PointF(0f, 0f); var portraitLocation = new PointF(0f, 0f); return new AGSSayLocation(textLocation, portraitLocation); }}, then to use this implementation instead of the default engine's implementation, write (before the game loads): Resolver.Override(resolver => resolver.Builder.RegisterType<Qfg4StyleSayLocationProvider>().As<ISayLocationProvider>());.
    TextAlignment SayConfig.TextConfig.Alignment Speech.TextAlignment = eAlignRight; cEgo.SayConfig.TextConfig.Alignment = Alignment.MiddleRight;
    UseGlobalSpeechAnimationDelay ? Speech.UseGlobalSpeechAnimationDelay = true; ?
    VoiceMode ? Speech.VoiceMode = eSpeechVoiceAndText; ?

    Missing in AGS but exists in MonoAGS: Setting "skip text" styles for specific characters, more customizations to speech style, including creating custom say functions completely.

    String

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    Append + mytext = mytext.Append("World"); mytext = mytext + "World", or mytext += "World", or mytext = $"{mytext}World"
    AppendChar + mytext = mytext.AppendChar('o'); mytext = mytext + 'o', or mytext += 'o', or mytext = $"{mytext}o"
    CompareTo for direct equality, you can use "==", otherwise, CompareTo if (mytext.CompareTo("hello") == 0) {} if (mytext == "hello") {} or if (mytext.CompareTo("hello") == 0) {} Note, in c# both CompareTo and == are case sensitive, as opposed to AGS. If you want case insensitive equality check, you can do if (string.Equals(a, b, StringComparison.CurrentCultureIgnoreCase)) {}
    Copy Copy String newstring = mystring.Copy(); String newstring = mystring.Copy();
    EndsWith EndsWith if (myString.EndsWith("script!")) {} if (myString.EndsWith("script!", false)) {} In c# EndsWith is case sensitive by default, as opposed to AGS which is case insensitive by default (that's the reason for the added false parameter in the c# example, to match the AGS sample).
    Format Format, or string interpolation String text = String.Format("%d, %d", health, score); string text = string.Format("{0}, {1}", health, score); or string text = $"{health}, {score}";
    IndexOf IndexOf int result = haystack.IndexOf("a needle"); int result = haystack.IndexOf("a needle"); In c# IndexOf is case sensitive by default, if you want case insensitive, you can do: int result = haystack.IndexOf("a needle", StringComparison.InvariantCultureIgnoreCase);
    IsNullOrEmpty IsNullOrEmpty if (String.IsNullOrEmpty(myString)) {} if (string.IsNullOrEmpty(myString)) {}
    LowerCase ToLower String lowercased = mystring.LowerCase(); string lowercased = mystring.ToLower();
    Replace Replace String changed = original.Replace("hello", "goodbye"); string changed = original.Replace("hello", "goodbye"); In c# Replace is case sensitive, to do a case insensitive replace you can use a regular expression: string changed = Regex.Replace(original, "hello", "goodbye");
    ReplaceCharAt ToCharArray + index String changed = mystring.ReplaceCharAt(2, 'm'); char[] ch = mystring.ToCharArray(); ch[2] = 'm'; string changed = new string(ch);
    StartsWith StartsWith if (myString.StartsWith("script!")) {} if (myString.StartsWith("script!", false)) {} In c# StartsWith is case sensitive by default, as opposed to AGS which is case insensitive by default (that's the reason for the added false parameter in the c# example, to match the AGS sample).
    Substring Substring String substring = mystring.Substring(3, 5); String substring = mystring.Substring(3, 5);
    Truncate Substring String truncated = mystring.Truncate(4); string truncated = mystring.Length <= 4 ? mystring : mystring.Substring(0, 4);
    UpperCase ToUpper String uppercased = mystring.UpperCase(); string uppercased = mystring.ToUpper();
    AsFloat float.TryParse float number1; number1 = text1.AsFloat; float.TryParse(text1, out float number1);
    AsInt int.TryParse int number1; number1 = text1.AsInt; int.TryParse(text1, out int number1);
    Chars [] text.Chars[3] text[3]
    Length Length text.Length text.Length

    Missing in AGS but exists in MonoAGS: Everything here is not MonoAGS specific but c#: you can see c# string reference here: https://msdn.microsoft.com/en-us/library/system.string(v=vs.110).aspx

    System

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    AudioChannelCount AudioSystem.CurrentlyPlayingSounds.Count System.AudioChannelCount game.Audio.CurrentlyPlayingSounds.Count
    AudioChannels AudioSystem.CurrentlyPlayingSounds AudioChannel *channel = System.AudioChannels[2]; var sound = game.Audio.CurrentlyPlayingSounds[2];
    CapsLock Device.KeyboardState.CapslockOn if (System.CapsLock) {} if (AGSGame.Device.KeyboardState.CapslockOn) {}
    ColorDepth ? System.ColorDepth ?
    Gamma ? System.Gamma ?
    HardwareAcceleration Device.GrahpicsBackend.AreShadersSupported if (System.HardwareAcceleration) {} if (AGSGame.Device.GraphicsBackend.AreShadersSupported()) {}
    HasInputFocus ? if (!System.HasInputFocus) return; ?
    NumLock ? if (System.NunLock) {} ?
    OperatingSystem RuntimeInformation.IsOSPlatform if (System.OperatingSystem == eOSWindows) {} if (RuntimeInformation.IsOSPlatform(OSPlayform.Windows)) {} No current support for checking platforms other than windows, mac or linux
    RenderAtScreenResolution RenderLayer.IndependentResolution System.RenderAtScreenResolution = true; myObj.RenderLayer = new AGSRenderLayer(z, independentResolution: new Size(1200, 800));
    RuntimeInfo ? System.RuntimeInfo ?
    ScreenHeight Settings.WindowSize.Height System.ScreenHeight game.Settings.WindowSize.Height
    ScreenWidth Settings.WindowSize.Width System.ScreenWidth game.Settings.WindowSize.Width
    ScrollLock ? if (System.ScrollLock) {} ?
    SupportsGammaControl ? System.SupportsGammaControl ?
    Version ? System.Version ?
    ViewportHeight ? System.ViewportHeight ?
    ViewportWidth ? System.ViewportWidth ?
    Volume AudioSettings.MasterVolume System.Volume = 80; game.AudioSettings.MasterVolume = 0.8f; Range in AGS is 0-100, range in MonoAGS is 0-1
    VSync Settings.Vsync System.Vsync = true; game.Settings.Vsync = VsyncMode.On;
    Windowed Settings.WindowState if (Settings.Windowed) {} if (game.Settings.WindowState == WindowState.Normal) {}

    Missing in AGS but exists in MonoAGS: Change window size at runtime (including windowed or not, and bordered or not), adaptive vsync.

    Text Display / Speech

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    Display AGSMessageBox.DisplayAsync Display("Hello"); await AGSMessageBox.DisplayAsync("Hello");
    DisplayAt ? DisplayAt (50,50,100, "This is a message"); ?
    DisplayAtY ? DisplayAt (50, "This is a message"); ?
    DisplayMessage AGSMessageBox.DisplayAsync DisplayMessage(220); await AGSMessageBox.DisplayAsync(game.Properties.Strings.GetValue("MySpecialMessage"));
    DisplayMessageAtY ? DisplayMessageAtY(527, 200); ?
    DisplayTopBar ? DisplayTopBar(25, 8, 7, "Evil wizard", "Get out of my house and never return!"); ?

    Missing in AGS but exists in MonoAGS: show yes/no or ok/cancel dialogs (or any dialog with a custom number of buttons).

    ViewFrame

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    Flipped ? if (frame.Flipped) {} ? Note that you can currently flip a frame horizontally or vertically by doing frame.Sprite.FlipHorizontally(), but currently no way to query if a frame is flipped (other, perhaps, then checking if the scaling of the sprite is negative)
    Frame Frames.IndexOf frame.Frame animation.Frames.IndexOf(frame)
    Graphic Sprite.Image.ID frame.Graphic frame.Sprite.Image.ID
    LinkedAudio SoundEmitter.AudioClip frame.LinkedAudio frame.SoundEmitter.AudioClip
    Loop N/A frame.Loop N/A MonoAGS does not have the concept of loops in a view, so getting the loop of a frame is meaningless. You can check whether a frame is part of a particular animations by doing: animation.Frames.Contains(frame).
    Speed Delay frame.Speed frame.Delay
    View N/A frame.View N/A MonoAGS does not have the concept of a view. The most equivalent for a view is a directional animation. For a specific directional animation, you can check if the frame exists for one of its animations by doing: if (myDirectionalAnimation.GetAllDirections().Any(animation => animation.Frames.Contains(frame)) {}

    Missing in AGS but exists in MonoAGS: rotate/scale/translate individual animation frames (including at run-time), change the animation frame speed at run-time and allow for random animation frame delays within a range (very useful for speak animations), for the linked sound, allows to configure whether to automatically pan and adjust the volume of the sound based on the location of the animation relative to the center of the screen (for panning) and based on the location within a volume changing area.

    SCUMM_VERBCOIN_GUI

    Currently there are no equivalents to verb coin GUI in MonoAGS.

    Game variables

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    abort_key ? game.abort_key = 324 ?
    ambient_sounds_persist ? game.ambient_sounds_persist = 0 ?
    anim_background_speed room.Background.Animation.Configuration.DelayBetweenFrames game.anim_background_speed = 5; game.State.Room.Background.Animation.Configuration.DelayBetweenFrames = 5;
    auto_use_walkto_points ApproachStyle game.auto_use_walkto_points = 0; player.ApproachStyle.ApproachWhenVerb[Verbs.Look] = ApproachHotspots.NeverWalk;
    bgspeech_game_speed ? game.bgspeech_game_speed = 0; ?
    bgspeech_stay_on_display ? game.bgspeech_stay_on_display = 0; ?
    close_mouth_end_speech_time ? game.close_mouth_end_speech_time = 10; ?
    debug_mode #if DEBUG if (game.debug_mode == 1) {} #if DEBUG ... #endif
    dialog_options_x ? game.dialog_options_x = 4; ?
    dialog_options_y ? game.dialog_options_y = 4; ?
    disable_antialiasing you can select texture filter scaling per image game.disable_antialiasing = 1; image.Texture.Config = new AGSTextureConfig(scaleUp: ScaleUpFilters.Nearest);
    following_room_timer ? game.following_room_timer = 150; ?
    keep_screen_during_instant_transition ? game.keep_screen_during_instant_transition = 1; ?
    inv_activated Inventory.ActiveItem game.inv_activated player.Inventory.ActiveItem
    inventory_greys_out ? game.inventory_greys_out = 1; ?
    lipsync_speed ? game.lipsync_speed = 15; ?
    max_dialogoption_width ? game.max_dialogoption_width = 180; ?
    min_dialogoption_width ? game.min_dialogoption_width = 0; ?
    narrator_speech ? game.narrator_speech = 5; ?
    no_textbg_when_voice ? game.no_textbg_when_voice = 0; ?
    read_dialog_option_color ? game.read_dialog_option_color = 5; ?
    roomscript_finished N/A game.roomscript_finished N/A There's no need for on_call as there's no problem just executing functions between scripts
    score ? game.score ? There's no problem mimicking a score with a simple global variable
    score_sound ? game.score_sound ? There's no problem mimicking a score sound with a simple function that changes a global variable and plays a sound.
    screenshot_height ? game.screenshot_height = 200; ?
    screenshot_width ? game.screenshot_width = 320; ?
    show_single_dialog_option ? game.show_single_dialog_option = 1; ?
    sierra_inv_color set an empty image with a color on the inventory window game.sierra_inv_color = 5; invWindow.Image = new EmptyImage(300, 200); invWindow.Tint = Colors.Pink;
    skip_display ? game.skip_display = 3; ?
    skip_speech_specific_key Implement custom text skipping game.skip_speech_specific_key = 5; player.SpeechConfig.SkipText = SkipText.External; player.OnBeforeSay.Subscribe(args => { input.KeyDown.Subscribe(keyArgs => if (keyArgs.Key == Key.PageDown) args.Skip();) });
    speech_bubble_width ? game.speech_bubble_width = 100; ?
    speech_text_align SpeechConfig.TextConfig.Alignment game.speech_text_align = eAlignCentre; player.SpeechConfig.TextConfig.Alignment = Alignment.MiddleCenter;
    speech_text_gui Either set properties in SpeechConfig or subscribe to OnBeforeSay and manipulate the label game.speech_text_gui = 4; For basic changes: player.SpeechConfig.BackgroundColor = Colors.Pink; player.SpeechConfig.Border = factory.Graphics.Borders.Solid(Colors.Red, lineWidth: 5);, for complete control: player.OnBeforeSay.Subscribe(args => { args.Label.Opacity = 0; args.Label.TweenOpacity(255, 3f);});
    text_align SpeechConfig.TextConfig.Alignment game.speech_text_align = eAlignCentre; AGSMessageBox.Config.TextConfig.Alignment = Alignment.MiddleCenter;
    text_shadow_color SpeechConfig.TextConfig.ShadowBrush game.text_shadow_color = 16; player.SpeechConfig.TextConfig.ShadowBrush = Brushes.SolidBlue;
    top_bar_XXXX ? game.top_bar_bordercolor = 5; ?
    total_score ? game.total_score = 50; ? There's no problem mimicking a score sound with a simple function that changes a global variable and plays a sound.
    used_mode N/A game.used_mode N/A The "used mode" is dependent on your control scheme. For a "rotating cursors" scheme, you can get scheme.CurrentMode
    mouse.x input.MousePosition.XMainViewport mouse.x game.Input.MousePosition.XMainViewport
    mouse.y input.MousePosition.YMainViewport mouse.y game.Input.MousePosition.YMainViewport
    palette[SLOT] ? palette[0].r ?
    player state.Player player game.State.Player

    Predefined global script functions

    The predefined global script function in AGS are events. As there is no way of runtime event subscription in AGS, there are "magic" predefined functions in the script. In MonoAGS you can subscribe/unsubscribe events at will.

    AGS MonoAGS AGS Example MonoAGS Example Further notes
    dialog_request ? function dialog_request(int parameter) {} ?
    game_start game.Events.OnLoad function game_start() {} game.Events.OnLoad.Subscribe(onGameStart); ... void onGameStart() {}
    on_event:eEventEnterRoomBeforeFadein room.Events.OnBeforeFadeIn for specific room, or game.Events.OnRoomChanging function on_event (EventType event, int data) { if (event == eEventEnterRoomBeforeFadein) { int room = data; } } game.Events.OnRoomChanging.Subscribe(onRoomChanging); ... void onRoomChanging() { IRoom room = game.State.Room; }
    on_event:eEventLeaveRoom room.Events.OnAfterFadeOut for specific room, or game.Events.OnRoomChanging function on_event (EventType event, int data) { if (event == eEventLeaveRoom) { int room = data; } } game.Events.OnRoomChanging.Subscribe(onRoomChanging); ... void onRoomChanging() { IRoom room = player.PreviousRoom; } Missing state.PreviousRoom so OnRoomChanging for getting the previous room for the player will not work if that room is changed without moving the player to that room.
    on_event:eEventGotScore ? function on_event (EventType event, int data) { if (event == eEventGotScore) {} } ?
    on_event:eEventGUIMouseDown gui.MouseDown for specific gui, or subscribe to input.MouseDown and use hitTest for GUI checks function on_event (EventType event, int data) { if (event == eEventGUIMouseDown) { int gui = data; } } game.Input.MouseDown.Subscribe(onMouseDown); ... void onMouseDown(MouseButtonEventArgs args) { var clickedObject = hitTest.ObjectAtMousePosition; }
    on_event:eEventGUIMouseUp gui.MouseUp for specific gui, or subscribe to input.MouseUp and use hitTest for GUI checks function on_event (EventType event, int data) { if (event == eEventGUIMouseUp) { int gui = data; } } game.Input.MouseUp.Subscribe(onMouseUp); ... void onMouseUp(MouseButtonEventArgs args) { var clickedObject = hitTest.ObjectAtMousePosition; }
    on_event:eEventAddInventory ? function on_event (EventType event, int data) { if (event == eEventAddInventory) {} } ?
    on_event:eEventLoseInventory ? function on_event (EventType event, int data) { if (event == eEventLoseInventory) {} } ?
    on_event:eEventRestoreGame ? function on_event (EventType event, int data) { if (event == eEventRestoreGame) {} } ?
    on_key_press input.KeyDown function on_key_press (eKeyCode keycode) {} input.KeyDown.Subscribe(onKeyDown); ... void onKeyDown(KeyboardEventArgs args) {}
    on_mouse_click input.MouseDown function on_mouse_click (MouseButton button) {} input.MouseDown.Subscribe(onMouseDown); ... void onMouseDown(MouseButtonEventArgs args) {}
    repeatedly_execute Events.OnRepeatedlyExecute function repeatedly_execute() {} game.Events.OnRepeatedlyExecute.Subscribe(onRepeatedlyExecute); ... void onRepeatedlyExecute() {}
    repeatedly_execute_always Events.OnRepeatedlyExecuteAlways function repeatedly_execute_always() {} game.Events.OnRepeatedlyExecuteAlways.Subscribe(onRepeatedlyExecute); ... void onRepeatedlyExecute() { }
    unhandled_event Events.DefaultInteractions function unhandled_event (int what, int type) { if (what == 1 && type == 1) {}} game.Events.DefaultInteractions.OnInteract(Verbs.Look).Subscribe(args => {});

    Missing in AGS but exists in MonoAGS: Subscribe/unsubscribe to events at runtime, mouse move and key up generic events, mouse enter/leave/up/double click/lost focus per object events

    • Improve this Doc
    Back to top Generated by DocFX