NML - a Newgrf Meta Language

Discussions about the technical aspects of graphics development, including NewGRF tools and utilities.

Moderator: Graphics Moderators

User avatar
andythenorth
Tycoon
Tycoon
Posts: 5649
Joined: 31 Mar 2007 14:23
Location: Lost in Music

Re: NML - a Newgrf Meta Language

Post by andythenorth »

McZapkie wrote:but it is not working (I can still hear sawmill sound in my logging camp)
Are you redefining any original industry / reusing any original industry tiles? Wondering if the sound might persist.
Could be a false guess though; redefining the property should clear it.
Wahazar
Tycoon
Tycoon
Posts: 1451
Joined: 18 Jan 2014 18:10

Re: NML - a Newgrf Meta Language

Post by Wahazar »

andythenorth wrote:Are you redefining any original industry / reusing any original industry tiles? Wondering if the sound might persist.
No, all industry tiles are new, industry definition begin as follows:

Code: Select all

item(FEAT_INDUSTRIES, industry_logging_camp, 0x3F) {
		property {
			substitute: 0x19; 
			override: 0x19;
			spec_flags: bitmask(IND_FLAG_CUT_TREES);
Maybe issue is related with lumber mill mechanism - these saw sounds can be hear when trees are replaced by brown soil.
Formerly known as: McZapkie
Projects: Reproducible Map Generation patch, NewGRFs: Manpower industries, PolTrams, Polroad, 600mm narrow gauge, wired, ECS industry extension, V4 CEE train set, HotHut.
Another favorite games: freeciv longturn, OHOL/2HOL.
User avatar
supermop
Tycoon
Tycoon
Posts: 1104
Joined: 21 Feb 2010 00:15
Location: Fitzroy North - 96

Re: NML - a Newgrf Meta Language

Post by supermop »

Hi All,

I got a weird internal error with the nrt build of nmlc:

Code: Select all


[Knmlc ERROR: nmlc: An internal error has occurred:
nmlc-version: unknown
Error:    (IndexError) "pop from empty list".
Command:  ['nmlc', 'moprv26.nml']
Location: File "nml\free_number_list.py", line 74, in pop

not sure if this is the best place to put it, I can share my nml code as well...

EDIT: seems to have been caused by using numerical IDs that were too big. Error message could be a bit more clear though...
User avatar
supermop
Tycoon
Tycoon
Posts: 1104
Joined: 21 Feb 2010 00:15
Location: Fitzroy North - 96

Re: NML - a Newgrf Meta Language

Post by supermop »

Sorry for another question...

Is it at all possible to access vehicle properties such as power and weight to use as variables for switches in NML? NMLC won't recognize 'power' when used this way, and I am not sure if there is a workaround at all. (I am making running costs variable based on power and weight, among other things..)

Code: Select all

switch (FEAT_ROADVEHS, SELF, switch_etram_powercost, current_year ) {
        0..1900:	(cargo_capacity/5)*((1/(num_vehs_in_consist))+1)+(power/20)+((param_runcost*30)/2)+(weight);
        1901..1940: (cargo_capacity/5)*((1/(num_vehs_in_consist))+1)+(power/20)+((param_runcost*34)/2)+(weight);
        1941..1980: (cargo_capacity/5)*((1/(num_vehs_in_consist))+1)+(power/20)+((param_runcost*32)/2)+(weight);
        1981..2020: (cargo_capacity/5)*((1/(num_vehs_in_consist))+1)+(power/20)+((param_runcost*35)/2)+(weight);
        default:	(cargo_capacity/5)*((1/(num_vehs_in_consist))+1)+(power/20)+((param_runcost*33)/2)+(weight);	

}
Best,
Cadde
Transport Coordinator
Transport Coordinator
Posts: 290
Joined: 07 Oct 2004 12:51

Re: NML - a Newgrf Meta Language

Post by Cadde »

https://newgrf-specs.tt-wiki.net/wiki/N ... _variables

The only variables with "power" in them are "vehicle_is_powered", "vehicle_is_not_powered" and "vehicle_is_potentially_powered".
I ran into this issue as well when making variable running costs for 2cc in NML. You have to provide those values hardcoded for the vehicle in question.

I.E:

Code: Select all

// Dynamic running cost for locomotive.
switch(FEAT_TRAINS, PARENT, switch_dmu_Germany_DB_VT_040_Flying_Hamburger_locomotive_running_cost_factor, [STORE_TEMP(25, 0)]) {
    switch_locomotive_running_cost_factor;
}
I am storing the value '25' in temporary storage zero.

Code: Select all

// Dynamic running cost for locomotive.
switch(FEAT_TRAINS, PARENT, switch_locomotive_running_cost_factor,
    [STORE_TEMP(param_locomotive_running_cost == 0 ? 0 : LOAD_TEMP(0) * 10000 / (10000 / param_locomotive_running_cost) / 100, 1),
    STORE_TEMP(param_running_cost_dynamic_idle_percentage == 0 ? 0 : LOAD_TEMP(1) * 10000 / (10000 / param_running_cost_dynamic_idle_percentage) / 100, 2),
    STORE_TEMP(
        param_locomotive_running_cost_dynamic == 2 ? 200 :
        param_locomotive_running_cost_dynamic == 3 ? 50 :
        param_locomotive_running_cost_dynamic == 4 ? 10 :
        param_locomotive_running_cost_dynamic == 5 ? 2 : 1
    , 3),
    param_locomotive_running_cost_dynamic]) {
    0: max(0, LOAD_TEMP(1));
    1: max(0, max(LOAD_TEMP(2), current_speed * 100 / max_speed * LOAD_TEMP(1) / 100));
    2..5: switch_running_costs_dynamic_curve;
    6: max(0, current_speed < 1 ? LOAD_TEMP(2) : current_speed < current_max_speed ? LOAD_TEMP(1) * 150 / 100 : LOAD_TEMP(1));
}
And i am loading that value in that switch and doing a "diminishing returns" (basically the same as 1 / n where 'n' is a setting in the grf as a running cost percentage) on it and store that calculation in temp register 1.
Then i figure out what the idle running cost will be, using temp 1's value, and store that in temp 2.
The actual "diminishing returns" formula is using temp 3's value for 'linearity factor' and is in another switch:

Code: Select all

switch(FEAT_TRAINS, PARENT, switch_running_costs_dynamic_curve, 0) {
    return max(0,
        max(LOAD_TEMP(2),
            min(LOAD_TEMP(1),
                (LOAD_TEMP(1) + 1) *
                ((1000000 - LOAD_TEMP(3) * 1000000 / (current_speed + LOAD_TEMP(3))) /
                (1000 - LOAD_TEMP(3) * 1000 / (max_speed + LOAD_TEMP(3)))) / 1000
        )));
}
Which produces a nice curve where running costs go up rapidly at low speeds and level off towards the vehicles designed max speed.

Either way, you have to provide those hardcoded values as they don't exist in variables unfortunately. You can ofc abuse the CCompiler for this using define statements. Or, you could do what i did and simply write a piece of software that fetches whatever value there currently is and writes the appropriate switches for each vehicle as in the first code block above.

You can find my application here: https://github.com/TheCadde/OTTD-2cc-in ... eplacement
Though obviously it's aimed at 2CC trainset in NML. But the general idea is there.
User avatar
supermop
Tycoon
Tycoon
Posts: 1104
Joined: 21 Feb 2010 00:15
Location: Fitzroy North - 96

Re: NML - a Newgrf Meta Language

Post by supermop »

My intent for this was more to have a single dynamic switch that would get a roughly balance running cost for any given tram at any given time, and avoid having separate switches for each tram or type of tram, hence all the various hooks in the switch that would vary by vehicle type. Partly this is out of laziness, partly out of some sort of conceptual idealism about parametrically generative vehicle stats, and partly because i want to subsequently introduce subtle variations in vehicle stats depending on when vehicle is purchased, so as to provide a bit more granularity without doubling or tripling the number of vehicle types. ( that is, buy a Tram A in 1940 and it has 300HP, but a 1950 model Tram A has 350, etc.. A 1960 Tram A is worse than a 1960 Tram B, but better than the 1940 Tram A). Having tram running costs vary with power and weight would allow a little more articulation, but seems not to be possible. Outside of my arcane concepts, I don't think there would be much appetite to add a power or weight variable.
Cadde
Transport Coordinator
Transport Coordinator
Posts: 290
Joined: 07 Oct 2004 12:51

Re: NML - a Newgrf Meta Language

Post by Cadde »

You have age related variables though. So you can still implement your aging ideas.
And a switch is actually a choice. Thus, if you have a hardcoded value of 300 for power at year 1950 then you can switch on the current year. (https://newgrf-specs.tt-wiki.net/wiki/N ... _variables)

Thus, your power callback could look something like:

Code: Select all

switch(FEAT_ROADVEHS, SELF, somePowerSwitch, current_year) {
    0..1960: 300;
    1961..1970: 350;
    1971..1980: 400;
    1981..1990: 450;
}
Disregarding the fact that the return from power callback isn't in units but some internal value. See NewGRF specs.
You can then do the same for running costs. You just call relevant switches from the vehicle in question with the values that does not exist as a variable at run time.

Sure, it's a switch for every vehicle but how different is that from having a property for every vehicle? You are still looking to have a callback and getting a constant value vs a real time variable is about the same computation wise.
You can look at FIRS industry set for an example of an automated NML generation process as well. You just assign the base values you want in code and then the code generates NML with all the necessary switches. Thus you only maintain the "database", rather than a whole set of NML files.
User avatar
planetmaker
OpenTTD Developer
OpenTTD Developer
Posts: 9432
Joined: 07 Nov 2007 22:44
Location: Sol d

Re: NML - a Newgrf Meta Language

Post by planetmaker »

supermop wrote:(...)Outside of my arcane concepts, I don't think there would be much appetite to add a power or weight variable.
I'm pretty sure you're not the first (nor last) person who would like it accessible as variable in the argument of a switch to adjust something else based on that... (yes, I had that desire before, too).
frosch
OpenTTD Developer
OpenTTD Developer
Posts: 988
Joined: 20 Dec 2006 13:31
Location: Aschaffenburg

Re: NML - a Newgrf Meta Language

Post by frosch »

Properties are generally not available as variables, and likely never will be.

The reason is that properties can be set via callbacks. So you would use callback results in other callbacks.
This leads to countless problems: In which order are the callbacks called? Can running cost depend on speed? Can Speed depend on running cost? Can you make them cross-reference cyclically? ...

This problem is fundamental to how NewGRFs work. NewGRF are no imperative programming language, where order is clearly defines, but rather functional.
⢇⡸⢸⠢⡇⡇⢎⡁⢎⡱⢸⡱⢸⣭⠀⢸⢜⢸⢸⣀⢸⣀⢸⣭⢸⡱⠀⢰⠭⡆⣫⠰⣉⢸⢸⠀⢰⠭⡆⡯⡆⢹⠁⠀⢐⠰⡁
User avatar
supermop
Tycoon
Tycoon
Posts: 1104
Joined: 21 Feb 2010 00:15
Location: Fitzroy North - 96

Re: NML - a Newgrf Meta Language

Post by supermop »

frosch wrote:Properties are generally not available as variables, and likely never will be.

The reason is that properties can be set via callbacks. So you would use callback results in other callbacks.
This leads to countless problems: In which order are the callbacks called? Can running cost depend on speed? Can Speed depend on running cost? Can you make them cross-reference cyclically? ...

This problem is fundamental to how NewGRFs work. NewGRF are no imperative programming language, where order is clearly defines, but rather functional.
Yeah I understand how it could cause circular problems. My problem is that there is not many other variables i can access that serve to effectively differentiate different types of trams. (A tram with 3 parts from 1890 of course is very different in many ways than a 3 part tram from 2010). So I may well have little choice but to make many more switches with more hardcoded values for different types.

Thanks for the help though!
Transportman
Tycoon
Tycoon
Posts: 2781
Joined: 22 Feb 2011 18:34

Re: NML - a Newgrf Meta Language

Post by Transportman »

supermop wrote:
frosch wrote:Properties are generally not available as variables, and likely never will be.

The reason is that properties can be set via callbacks. So you would use callback results in other callbacks.
This leads to countless problems: In which order are the callbacks called? Can running cost depend on speed? Can Speed depend on running cost? Can you make them cross-reference cyclically? ...

This problem is fundamental to how NewGRFs work. NewGRF are no imperative programming language, where order is clearly defines, but rather functional.
Yeah I understand how it could cause circular problems. My problem is that there is not many other variables i can access that serve to effectively differentiate different types of trams. (A tram with 3 parts from 1890 of course is very different in many ways than a 3 part tram from 2010). So I may well have little choice but to make many more switches with more hardcoded values for different types.

Thanks for the help though!
I used defines with the gcc/make-stuff in the 2cc TrainsInNML set to have a single point where I need to set a value. I can then define switches with those defined properties to create the switches I need. Maybe you can look at that.
Coder of the Dutch Trackset | Development support for the Dutch Trainset | Coder of the 2cc TrainsInNML
Cadde
Transport Coordinator
Transport Coordinator
Posts: 290
Joined: 07 Oct 2004 12:51

Re: NML - a Newgrf Meta Language

Post by Cadde »

Indeed, the end result is still the same. lots of switches in the final NML. So no matter how you approach it, hardcoded is the only way.
User avatar
Gwyd
Chief Executive
Chief Executive
Posts: 721
Joined: 17 Apr 2017 16:52
Location: Western Ile-de-France Region

Re: NML - a Newgrf Meta Language

Post by Gwyd »

Is it at all possible to add custom sound effects for a train in NML? I can find how to import sounds, but otherwise, nothing. Sound effects aren't a property for trains. If you can show an example, that would be amazing.
Alberth
OpenTTD Developer
OpenTTD Developer
Posts: 4763
Joined: 09 Sep 2007 05:03
Location: home

Re: NML - a Newgrf Meta Language

Post by Alberth »

A train is also a vehicle, and that has sound callback: https://newgrf-specs.tt-wiki.net/wiki/N ... _callbacks
No idea if that works, but it looks like it should. Near the bottom is the list event types.
Being a retired OpenTTD developer does not mean I know what I am doing.
User avatar
Gwyd
Chief Executive
Chief Executive
Posts: 721
Joined: 17 Apr 2017 16:52
Location: Western Ile-de-France Region

Re: NML - a Newgrf Meta Language

Post by Gwyd »

I still can't seem to get it: it doesn't help that "sound_effect" isn't a property.
Cadde
Transport Coordinator
Transport Coordinator
Posts: 290
Joined: 07 Oct 2004 12:51

Re: NML - a Newgrf Meta Language

Post by Cadde »

No, sound effect is a callback. And only a callback.
It goes into the graphics { } block.
The documentation seems rather clear on how it should work as long as you are versed in using callbacks.

It would go something like this (from memory, reading the sound effect specific documentation and guesstimating, not at all tested)

Code: Select all

switch(FEAT_TRAINS, SELF, switchSoundEffect, getbits(extra_callback_info1, 0, 8)) {
    SOUND_EVENT_START: sound("moo.wav");
    SOUND_EVENT_TUNNEL: sound("moo.wav");
    SOUND_EVENT_BREAKDOWN: sound("deadmoo.wav");
    ...
}

item(FEAT_TRAINS, someCowPoweredTrain) {
    ...
    graphics {
        sound_effect: switchSoundEffect;
    }
}
User avatar
Gwyd
Chief Executive
Chief Executive
Posts: 721
Joined: 17 Apr 2017 16:52
Location: Western Ile-de-France Region

Re: NML - a Newgrf Meta Language

Post by Gwyd »

Thank you very much! Now I can annoy people with my NewGRFs!
User avatar
Greyfur
Engineer
Engineer
Posts: 112
Joined: 31 Oct 2004 12:43
Location: Slovakia - Bratislava
Contact:

Re: NML - a Newgrf Meta Language

Post by Greyfur »

I raised from the dead... and I already got a question. Is it possible with NML to do these?

1) Have a bus transport both passengers and mail at once?
2) Have a vehicle, which, when you buy it gives you a random type (or decided based on percentual chances) from a pre-defined list? (wanted to simulate the distribution of buses after WWII / during socialism)
3) Is it possible to refit an articulated bus to a non-articulated one and vice versa?

Thank you!
My project: CS Bus Set viewtopic.php?f=26&t=87962

Škoda - Praga - Tatra - Karosa - Oasa - Prima TL - Zliner - TAM BUS - SOR - Novoplan - Granus - Slovbus - Tedom - Irisbus - Iveco

Woof !
Wahazar
Tycoon
Tycoon
Posts: 1451
Joined: 18 Jan 2014 18:10

Re: NML - a Newgrf Meta Language

Post by Wahazar »

Greyfur wrote: 1) Have a bus transport both passengers and mail at once?
2) Have a vehicle, which, when you buy it gives you a random type (or decided based on percentual chances) from a pre-defined list? (wanted to simulate the distribution of buses after WWII / during socialism)
3) Is it possible to refit an articulated bus to a non-articulated one and vice versa?
1) probably yes, take a look at PKP train set, there are goods/mail or mail/pax coaches - it was done by adding invisible articulated part.
2) no. But you can make universal vehicle, which can pickup passengers or freight, whatever is waiting (using autorefit orders), probably it is what you want. For example, refer to my Polroad set (GMC CCKW truck).
3) partially yes. You can toggle articulated part view and length between visible/long or invisible/short, but you cannot detach it. Refer to my Poltrams newgrf (options for purchase/sell additional tram trailers via refit).

Please note, that all these hacks with articulated vehicles have some unwanted side effects, for example it is impossible to automatic replace articulated vehicle with non-homogenous cargo refit. More reality -> less playability.
Formerly known as: McZapkie
Projects: Reproducible Map Generation patch, NewGRFs: Manpower industries, PolTrams, Polroad, 600mm narrow gauge, wired, ECS industry extension, V4 CEE train set, HotHut.
Another favorite games: freeciv longturn, OHOL/2HOL.
User avatar
andythenorth
Tycoon
Tycoon
Posts: 5649
Joined: 31 Mar 2007 14:23
Location: Lost in Music

Re: NML - a Newgrf Meta Language

Post by andythenorth »

Greyfur wrote:1) Have a bus transport both passengers and mail at once?
No, the vehicle can be built, but can't be given any station orders (vehicles fitted for pax can't route to truck stations and vice versa).

:)
Post Reply

Return to “NewGRF Technical Discussions”

Who is online

Users browsing this forum: No registered users and 2 guests