Mode creation tips

You can talk about ManiaScript for ManiaPlanet here

Moderator: English Moderator

Post Reply
User avatar
Alinoa
Nadeo
Nadeo
Posts: 4112
Joined: 14 Jun 2010, 11:55
Location: France, Paris
Contact:

Mode creation tips

Post by Alinoa » 24 Jul 2012, 08:57

Slig wrote:
kapsubm wrote:seems not, i dont understand why nadeo just doesnt want to post examples, or really, just push out platform, stunt.
they do have it allready, just deleted it out of the game before releasing it. - the scripts should not be much different from the original tmnf .
You have some !...

Available examples : all those of title Storm in UserData/Scripts/ of the dedicated, and the few existing modes made by players. Only ones that we have not are Elite, Joust and Heroes ones (would probably be the more interesting ones for advanced work as they are the more complex, but protected mostly to avoid fake or modified ones in competitions in seems).


Basic maniascript syntax :
http://forum.maniaplanet.com/viewtopic.php?f=279&t=1672
http://forum.maniaplanet.com/viewtopic. ... 982#p91487
http://konte.org/trackmania/maniascript ... ml#General
http://destroflyer.mania-community.de/m ... t/page.php (german)
Several things are still missing, but most can be understood by studying examples... see also below for some replies about some of them (can't just give links as not in public part)


Classes description :
http://forum.maniaplanet.com/viewtopic. ... 05#p105879
http://tmrankings.com/maniascript/html/ ... ource.html
note that because of #RequireContext CSmMode at script beginning, most variables which seems gloable are in fact CSmMode members, that are listed in big.h


Examples :
You can start with the built-in examples ( Documents/Scripts/Modes/ShootMania/ ; some of them are not visible in the game but are in the dedicated files, in UserData/Scripts/Modes/ShootMania/ ; you can't see the scripts of gamemodes inculded in a title pack, like Elite, Heroes or Joust)
You can also look at custom scripts : http://forum.maniaplanet.com/viewtopic. ... 36&t=11556 and http://forum.maniaplanet.com/viewtopic. ... 36&t=12558


How to view script, edit it, test it ?
To test, create a server with your game, select the wanted screen, a map, start it : you can use F12 to see, edit, and test the script, ctrl+g to see the console (any 'log("xxx");' goes to the console).
Note that any error will stop the script ! then use ctrl+g (2 times) to see where is was stopped and the error message.


About built-in editor and debug
Gugli wrote:The Script editor is not exactly the same depending on the context. Some entry points are different when you're editing a plugin script, a game mode script or a maptype script.

When in the editor :
- you can use the plugin menu to edit or create a plugin script.
- you can press F12 to edit the maptype script

When you create a multiplayer server :
- you can press F12 to edit the game mode.

So, the simplest way to begin, is to create a private Melee server for example. Then press F12, then save the script as "MyNewMode.Script.txt" or something approaching. And start reading /editing.
Next time you want to edit again your script, start a game with MyNewMode instead of Melee.
Communication between server maniascript and client/manialink maniascript
Eole wrote:There's a way for Manialink to communicate with the CSmMode. If you take a look at the Elite mode script, you can see it in the Warmup Manialink.

When you declare a variable like that in the manialink script:

Code: Select all

declare netwrite MyVariable for UI = 0;
MyVariable = 10;
Then this variable is accessible in the UI that contains this Manialink.

Code: Select all

// If the Manialink is in a player UI
declare UI <=> UIManager.GetUI(PlayerWithManialink);
if (UI != Null) {
  declare netread MyVariable for UI = 0;
  // Now MyVariable = 10;
}

OR 

// If the Manialink is in the global UI
declare netread MyVariable for UIManager.UIAll = 0;
// Now MyVariable = 10;
But be aware that there's a delay between a change of value in the manialink and the change of this value in the mode script. The netread and netwrite keywords are there to speed up this process a little. But I think Gugli should be able to explain that way better than me.
Gugli wrote:Eole is perfectly right. The examples he gave are clear so I don't feel the need to continue. But don't hesitate to ask if you require more info on netread/netwrite.

Why there is such a difference :

In editor : the MapType script and the Manialink are run on the same computer. You can directly access the Manialink object. There is always one MapType for one Manialink.

In game : the Mode script is executed on the server, and the Manialink scripts are executed on the clients. And there's one server for many clients. That's why it's a bit more difficult to communicate. We have tried to make network communication as easy as possible for scripters, but it is still a bit more difficult than local variable access.

Text Compose : use game built-in word translations
Gugli wrote:Concerning the Text "Compose" function, it's a feature, allowing client-side translations :

When the server Mode script do something such as :

Code: Select all

UIManager.UIAll.BigMessage = "Hello !";
Basically, the text "Hello !" will be sent to every player. The client can then translate it. to "Salut !" for exemple.

When you use

Code: Select all

UIManager.UIAll.BigMessage = "Hello "^Player.Login^"!";
the text "Hello Gugli!" will be sent to every player : this text is unknown, and can not be translated T_T

To allow text translation, you can use compose :

Code: Select all

UIManager.UIAll.BigMessage = TextLib::Compose("Hello $<%1$>!", Player.Login);
The text "_Hello $<%1$> !_World" will be sent ( _ is in fact a weird unicode character ). The client will attempt to translate "Hello $<%1$> !", it will find "Salut $<%1$> !", and then replace the "%1". The client will then show : "Salut Gugli !".

Labels ( +++xxx+++ , ---xxx--- , ***xxx*** )
Gugli wrote:I call those "labels", and they are related to the #Extends directive.

In a script, you can add some labels, they indicate specific locations in your code, like "+++RoundBegin+++".

This way, if another person wants to add some features to your script, she/he will be only have to use #Extends "Name\Of\Your\Script", and add her/his code with the syntax :

Code: Select all

#Extends "Name\Of\Your\Script"

***RoundBegin***
***
// Some code I'd like to see executed when a new round begins
...
***
As you've seen, there are two syntaxes to create a label : +++Label+++ and ---Label---
The +++ one indicates that the label must be replaced by the sum of every code section with matching name.
The --- one in indicates that the label must be replaced only by the most derived matching section.

Examples :

Code: Select all

// File1

+++LabelPlus+++
---LabelMinus---

Code: Select all

// File2
#Extends "File1"
***LabelPlus***
***
ContentsPlus1
***

***LabelMinus***
***
ContentsMinus1
***

Code: Select all

// File3
#Extends "File2"
***LabelPlus***
***
ContentsPlus2
***

***LabelMinus***
***
ContentsMinus2
***
File3 will be an equivalent of :

Code: Select all

// File1

ContentsPlus1
ContentsPlus2

ContentsMinus2
So mostly, you can use the +++ labels, when you declare a special moment in your script, every derived script will add its own actions there.
And you can use --- when you declare a specific test or action like "TestCapture" : any script can override this test, but it would be pointless to make the test twice or more, since only one result is used, the most derived one.
Gugli wrote:The short answer is no. If you do not plan to extend a script, labels are useless.

But if you have to choose, it's better to write

Code: Select all

+++BeginRound+++
than to write

Code: Select all

// BeginRound


You never know... someone may want to extends your script ^_^

Another detail, if you have more that one ***BeginRound*** in the same file, they will either be concatenated (for +++ labels) or the last one will prevail (for --- labels).

About directive: declare xxx for yyy
about: declare xxx for yyy


MathLib and TextLib functions (from a drmaxkurt post) :

Code: Select all

#Include "MathLib" as MathLib
MathLib::AbsInteger();
MathLib::AbsReal();
MathLib::ToReal();
MathLib::Sin();
MathLib::Cos();
MathLib::Tan();
MathLib::Atan2();
MathLib::Exp();
MathLib::RandReal();
MathLib::RandInteger();
MathLib::NearestReal();
MathLib::NearestInteger();
MathLib::FloorInteger();
MathLib::CeilingInteger();
MathLib::DistanceVec3();  =>  MathLib::Distance()
MathLib::AngleVec3();

#Include "TextLib" as TextLib
TextLib::ToReal();
TextLib::ToInteger();
TextLib::Substring();
TextLib::SubText();
TextLib::Length();
TextLib::ToText();
TextLib::TimeToText();
TextLib::Compose();
TextLib::MLEncode();

About UI optimisation
Gugli wrote:
Slig wrote:I wonder how the underlying system is optimized against what does maniascripts about UIAll and players UI changes...
When the changed values are taken into account ? at next yield/wait/sleep ? or immediatly ?
for example, if i do such silly thing :

Code: Select all

foreach(Player in Players) {
  declare UI <=> UIManager.GetUI(Player);
  if (UI==Null) continue;
    // previous UI.BigMessage is "john"
    UI.BigMessage = "john"; // (1)
    UI.BigMessage = ""; // (2)
    UI.BigMessage = "james"; // (3)
    UI.BigMessage = "john"; // (4)
}
The UI changes are sent only every 500ms and if there is an actual change.

So in your 1st example : if the 500ms tick occurs between (2) an (3), the empty string "" will be sent, resulting in some time (500ms + ping variation) without message on the client.

The problem with the layers is not the network (the same 500ms check exists), but the time spent by the server to generate the contents of the layers. String handling and such likes can be long, so it is better to avoid doing that every 10ms. Especially when you know they won't be sent before 500ms.
The same goes for unnecessary UILayers.reset() and UILayers.add(). It does not cost much, but it can become a problem if there are many players.

Also, when you want to have very dynamic pages on the client, it is better to use a Manialink <script> markup.
Ubisoft Support
Your Player Page

More information about maniaplanet, support, contents, community activities: useful links

ManiaPlanet technical documentation portal (Dedicated server, Mediatracker, ManiaLink, ManiaScript, Titles...)

User avatar
w1lla
Posts: 2360
Joined: 15 Jun 2010, 11:09
Location: Netherlands
Contact:

Re: Mode creation guide

Post by w1lla » 24 Sep 2012, 15:06

What is missed is a KeyCharTable link:

http://destroflyer.mania-community.de/m ... _table.php
TM² Info
SM Info
QM Info

OS: Windows 10 x64 Professional
MB: MSI 970A-G46
Processor: AMD FX-6300 3500 mHz
RAM Memory: 16 GB DDR3
Video: SAPPHIRE DUAL-X R9 280X 3GB GDDR5
KB: Logitech G510s
Mouse: Logitech G300s
Mode Creation
ManiaScript Docs

User avatar
steeffeen
Translator
Translator
Posts: 2472
Joined: 14 Oct 2012, 16:22
Location: Germany

Re: Mode creation guide

Post by steeffeen » 23 May 2013, 16:50

i would like to ask for an explanation of the following methods:

Code: Select all

Ladder_EnableChallengeMode(Boolean Enable);
Ladder_SetResultsVersion(Integer Version);
how do they work exactly?

thanks in advance
    Game Mode and Title Pack Creator, Developer, ShootMania-Player & more

    ManiaControl, FancyManiaLinks

    User avatar
    Eole
    Nadeo
    Nadeo
    Posts: 1213
    Joined: 26 Apr 2011, 21:08

    Re: Mode creation guide

    Post by Eole » 27 May 2013, 10:41

    Code: Select all

    Ladder_EnableChallengeMode(Boolean Enable);
    Not used at the moment. The idea behind it is something like a "double or nothing" mode for the ladder.

    Code: Select all

    Ladder_SetResultsVersion(Integer Version);
    You can set it to 0 (default) or 1. It modify the way the ladder points awarded at the end of a match are calculated. The "1" version is used in mode like Elite, Combo or Joust.

    Code: Select all

    foreach (Player in Players) {
      if (Player.Score == Null) continue;
    
      Player.Score.LadderClan = Player.CurrentClan;
      Player.Score.LadderMatchScoreValue = Player.Score.Points;
      if (Player.CurrentClan == WinnerClan) {
        Player.Score.LadderRankSortValue = 2;
      } else {
        Player.Score.LadderRankSortValue = 1;
      }
    }
    
    With mode 0, only the LadderRankSortValue will be taken into account to sort player. So the player in the same team will share the same ranking.
    With mode 1, there's two new variables: LadderClan and LadderMatchScoreValue. The LP reward will take into account with who you played and how well you performed in your team.

    Exemple:

    Code: Select all

    Blue 6 - 4 Red
    Player1 3 - 1 Player4
    Player2 1 - 5 Player5
    Player3 0 - 3 Player6
    
    In mode 0:
    Player1, Player2, Player3 are ranked first and Player4, Player5, Player6 are ranked second. The LP are awarded based on the ladder ranking of the players. If the players from the red team have a better ladder rank then the blue players will earn a lot of LP. But if the red have a lower ranking, the blue will earn nearly no LP.
    In Mode 1:
    Here the ladder function know that the Blue team won the match. But it can also access the score of individual player and modulate the LP they'll be awarded depending on their performance during the match. So a good player in the loosing team will still earn some LP while a bad player in a winning team will earn less LP.
    Contribute to the ManiaPlanet documentation on GitHub
    A question about ManiaScript? Ask it here!

    User avatar
    steeffeen
    Translator
    Translator
    Posts: 2472
    Joined: 14 Oct 2012, 16:22
    Location: Germany

    Re: Mode creation guide

    Post by steeffeen » 27 May 2013, 12:16

    wow big thanks for the detailed explanation! :thumbsup:
      Game Mode and Title Pack Creator, Developer, ShootMania-Player & more

      ManiaControl, FancyManiaLinks

      User avatar
      steeffeen
      Translator
      Translator
      Posts: 2472
      Joined: 14 Oct 2012, 16:22
      Location: Germany

      Re: Mode creation guide

      Post by steeffeen » 26 Jun 2013, 11:35

      there are functions in the MapUnits library which are using call-by-reference parameters and i was wondering if it's possible to define such functions with ManiaScript, too
      if yes, how does the syntax look for this?
      if no, any chance that it will come some-when? :)
        Game Mode and Title Pack Creator, Developer, ShootMania-Player & more

        ManiaControl, FancyManiaLinks

        User avatar
        Gugli
        Nadeo
        Nadeo
        Posts: 510
        Joined: 14 Jun 2010, 17:35
        Location: Mon PC est à Paris, mais mon coeur rode dans les forêts de Lozère

        Re: Mode creation guide

        Post by Gugli » 26 Jun 2013, 19:07

        steeffeen wrote:there are functions in the MapUnits library which are using call-by-reference parameters and i was wondering if it's possible to define such functions with ManiaScript, too
        if yes, how does the syntax look for this?
        if no, any chance that it will come some-when? :)
        No way to do that at the moment. Maybe someday, but not in a near future.
        --
        (>~_~)> ═╦═ ╔╦╗ <(~_~<)

        Post Reply

        Return to “ManiaScript”

        Who is online

        Users browsing this forum: Google [Bot] and 2 guests