GRFCodec feature discussion thread

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

Moderator: Graphics Moderators

User avatar
Csaboka
Tycoon
Tycoon
Posts: 1202
Joined: 25 Nov 2002 16:30
Location: Tiszavasvári, Hungary
Contact:

Post by Csaboka »

Patchman wrote:I think left-to-right would be very counterintuitive though.
Maybe, but it would reflect how the action itself works - you always use the result of the previous calculation for the next one.
DaleStan wrote:So, all sequences that can be parsed as "varXX[(<param>)] [>> <shift>] [& <mask>] [(+|-) <add>] [(%|/) <divmod>]" have implicit parens, and everything else is explicit or left-to-right.
Now that would be counter-intuitive IMO.

Code: Select all

reg[0] & 0xFF - var80 & 0xFF +1
would get implicit parens like this:

Code: Select all

(reg[0] & 0xFF) - (var80 & 0xFF +1)
while

Code: Select all

reg[0] & 0xFF - var80 +1 & 0xFF
would become

Code: Select all

(reg[0] & 0xFF) - (var80 +1) & 0xFF
I think it should be consistent - either left-to-right with explicit parens or the usual precedence rules, but no implicit parens in any case.
Reality is that which, when you stop believing in it, doesn't go away.—Philip K. Dick
User avatar
Csaboka
Tycoon
Tycoon
Posts: 1202
Joined: 25 Nov 2002 16:30
Location: Tiszavasvári, Hungary
Contact:

Post by Csaboka »

DaleStan: Do you still plan to add this feature, or did you get bored with my nitpicking and gave up on it? :) I don't want to rush you, I just want to know if it's still considered. If it isn't, I think I'll try to write some "compiler" myself in C++, if I'll have enough time for it. It would be nice for a first "real" project (something that's larger than textbook examples).
Reality is that which, when you stop believing in it, doesn't go away.—Philip K. Dick
DaleStan
TTDPatch Developer
TTDPatch Developer
Posts: 10285
Joined: 18 Feb 2004 03:06
Contact:

Post by DaleStan »

Go ahead.

You have a point there, with the non-intuitiveness of some of those arrangements, but I don't particularly like the idea of enforcing parenthesis around simple adjustments. Maybe the var and var-shift forms could permit no-parens, and the other forms require them?

If you're interested, I've got a bison script that I believe generates a parser that does the implicit parenthesization of varadjusts, but I haven't written a lexer to test it, and does basically nothing productive with the input. It may be easier than starting from scratch, or at least give you some ideas if you do decide to go the flex/bison (GNU's lex/yacc) route.
To get a good answer, ask a Smart Question. Similarly, if you want a bug fixed, write a Useful Bug Report. No TTDPatch crashlog? Then follow directions.
Projects: NFORenum (download) | PlaneSet (Website) | grfcodec (download) | grfdebug.log parser
User avatar
Csaboka
Tycoon
Tycoon
Posts: 1202
Joined: 25 Nov 2002 16:30
Location: Tiszavasvári, Hungary
Contact:

Post by Csaboka »

DaleStan wrote:Maybe the var and var-shift forms could permit no-parens, and the other forms require them?
That's a good idea. Since right shift isn't a valid operator, it would be unambigouos (can only be a varadjust).
DaleStan wrote:If you're interested, I've got a bison script that I believe generates a parser that does the implicit parenthesization of varadjusts, but I haven't written a lexer to test it, and does basically nothing productive with the input. It may be easier than starting from scratch, or at least give you some ideas if you do decide to go the flex/bison (GNU's lex/yacc) route.
I think I'll try the boost::spirit parser. I'm not too experienced with these things, but it seems to be a nice idea to specify rules in the C++ source code itself. I'm a bit concerned about code bloat caused by the templating it uses, so I may end up with a more regular parser...

As a first step, I'd like to add a human-readable version for all actions. This would be mainly useful to reduce repetitive and error-prone parts like counting the number of properties in action 0 or counting the sprites to skip in action 7. The primitive version of action 2 would look like something like my first proposal, except maybe that functions could be used for (u)min and (u)max. With some symbolic constants, variable names in actions 0, 2, 7 and D could be made much easier to read.

The biggest problem I can see with this step is action 6. Using it requires intimate knowledge about where something lies inside the next action. How can you add higher-level support to self-modifying code?

Later, if the idea still seems to be worth doing, I would add a higher-level syntax to action2 chains. You could write some high-level snippet and it would automatically be compiled into an action2 chain. CASE could be directly compiled into a variational action2. IF (expr == const), IF (expr < const) and IF (expr > const) are still easy. IF (expr1 relation expr2) could be rewritten into IF (expr1 - expr2 relation 0). AND and OR would need one action2 for each expression that's connected. Function calls would be possible using var 7E. Loops wouldn't be possible, though, since you can't jump forward with an action2. The benefit of this solution would be that you no longer would need to read and write chains backwards - you could write the first check first, and the compiler would worry about placing them in the right order.

The second step would pose the problem of debugging, though. Debugging an action2 chain is hard enough already, and it would be even harder when you don't know what your code has been compiled into.

And, of course, it's possible that none of this will be implemented because I'll be too busy with my studies...
Reality is that which, when you stop believing in it, doesn't go away.—Philip K. Dick
DaleStan
TTDPatch Developer
TTDPatch Developer
Posts: 10285
Joined: 18 Feb 2004 03:06
Contact:

Post by DaleStan »

Csaboka wrote:The biggest problem I can see with this step is action 6. Using it requires intimate knowledge about where something lies inside the next action. How can you add higher-level support to self-modifying code?
In NFO, it does. For all its useful uses, though, you're replacing a specific named value, not a specific byte offset. With this in mind, literals could be replaced with the "library" functions "int GetParam(int);", "int GRM(char*);", and "int GRM(enum Feature, char*);".
All three would return a value of the appropriate width.

GRM(char*) would be a shortcut for the two-argument form, and only valid once the two argument form had been called with the char* in question.
GRM(enum Feature, char*) would generate a GRM reservation for one (more) ID from the requested feature, and associate the new ID with the char*. On future calls with the same char*, it would simply return the ID associated with the char*.
Csaboka wrote:The second step would pose the problem of debugging, though. Debugging an action2 chain is hard enough already, and it would be even harder when you don't know what your code has been compiled into.
grfdebug.log provides reams of very computer-readable information. Would it be possible to open that and use it to "run" the debugger?
To get a good answer, ask a Smart Question. Similarly, if you want a bug fixed, write a Useful Bug Report. No TTDPatch crashlog? Then follow directions.
Projects: NFORenum (download) | PlaneSet (Website) | grfcodec (download) | grfdebug.log parser
User avatar
Csaboka
Tycoon
Tycoon
Posts: 1202
Joined: 25 Nov 2002 16:30
Location: Tiszavasvári, Hungary
Contact:

Post by Csaboka »

DaleStan wrote:In NFO, it does. For all its useful uses, though, you're replacing a specific named value, not a specific byte offset. With this in mind, literals could be replaced with the "library" functions "int GetParam(int);", "int GRM(char*);", and "int GRM(enum Feature, char*);".
All three would return a value of the appropriate width.
GetParam would be OK, but I don't think GRF can be simplified that much. That would need the compiler to use a "difference" register behind the coder's back, something I wouldn't like. On the other hand, I had a scenario more complex than this in TTRS3: I have three blocks that need to be adjusted with GRM. The first is skipped after 1970, the second is skipped before 1970, and the third is processed always. Therefore, I needed three differences and three "last" values.

For the "add" variety of action 6, I think I'll have something like GetParamSum(const, param). Supporting GetParam and GetParamSum seems to be the trickiest part of the compiler, but I've never said it's impossible :)
DaleStan wrote:grfdebug.log provides reams of very computer-readable information. Would it be possible to open that and use it to "run" the debugger?
You're completely right. I was thinking about something like a run-time debugger, but the log file gives enough information to replay the chain after the fact. We "just" need a graphical debugger tool that makes the log file more manageable, by allowing to replay the chain step by step.
Reality is that which, when you stop believing in it, doesn't go away.—Philip K. Dick
User avatar
skidd13
OpenTTD Developer
OpenTTD Developer
Posts: 522
Joined: 03 Mar 2005 10:49
Location: Germany

Post by skidd13 »

DaleStan refered me to this topic.
I thought over a compiler/decompiler for NFO-files.
Basicly I like the clearness of C/C++ code (mostly ;) ).
For the implementation I prefer perl or php styled var's.
Calculation should be possible.
So you need only write a replacement once and call it with another parameter. The creation of my combined airport set would have been easier then.

Here an idea of such a code.

Code: Select all

nfo testfile {

 void replace_sprite runway( ) {
  $start_sprite = 2648;
  // position, movement, size,  compression
  add_sprite( ... );
  /* position is the only one that is needed
   * movement is defalut zero
   * size could be searched by an algorithm
   * compression clould be default 09
   */
 }

 void main( int @parameters ) {
  string $name = "name for the replacement";
  hex $grf_version = 0.1; // the version of this grf
  misc $grf_id = "TEST"; // 4 hex / 4 char / 1 string

  if (TT_TYPE == TTDPATCH && CLIMATE != TOYLAND) {
   runway();
  }
 }
}
What does that mean - the circumstances? I determine what circumstances prevail. -- Napoleon Bonaparte
---
If we cannot end now our differences, at least we can help make the world safe for diversity. -- John F. Kennedy
---
Our problems are man-made, therefore they may be solved by man. No problem of human destiny is beyond human beings. -- John F. Kennedy
DaleStan
TTDPatch Developer
TTDPatch Developer
Posts: 10285
Joined: 18 Feb 2004 03:06
Contact:

Post by DaleStan »

Eww. Just Eww.

By "proposal", I meant "thing with obvious corresponding NFO code".

Go away. And don't come back until you have something that could be encoded in NFO, along with the corresponding NFO. You have used at least one thing that does not exist, and glossed over lots of vital details -- like the algorithm that automagically generates the proper sizes and offsets for sprites, and entirety of action 0 and the 1/2/3 system.

You also failed to specify whether "if" is encoded as a 7 or a 9, and the appropriate incantations to acquire the other.
To get a good answer, ask a Smart Question. Similarly, if you want a bug fixed, write a Useful Bug Report. No TTDPatch crashlog? Then follow directions.
Projects: NFORenum (download) | PlaneSet (Website) | grfcodec (download) | grfdebug.log parser
User avatar
gkirilov
Chief Executive
Chief Executive
Posts: 696
Joined: 03 May 2005 09:32
Location: Othala

Post by gkirilov »

Why do you people (I mean DaleStan) oppose to NFO being made easier to use? If someone wants to create things like skidd13 described (compiler/translator) for NFO, let them. You have nothing to lose. You can still use the old-fashioned way but the new stuff will only bring more coders in. And this is only a benefit to the community.
OTTDCoop NewGRF Pack|Different sets of GRFs for TTDPatch (some of them work in OTTD) - 1|- 2|GRF sets for OTTD|OTTD nightly
Image
I hooked up my accelerator to my brake lights. I hit the gas, people behind me stop, and I'm gone.
Understeer is when you hit the wall with the front of the car. Oversteer is when you hit the wall with the rear of the car. Horsepower is how fast you hit the wall. Torque is how far you take the wall with you. Spoilers and bodykits are how much of the wall you take with you. Rollcages and windownets are how much of a mess you leave on the wall.
User avatar
PikkaBird
Graphics Moderator
Graphics Moderator
Posts: 5631
Joined: 13 Sep 2004 13:21
Location: The Moon

Post by PikkaBird »

gkirilov wrote:Why do you people (I mean DaleStan) oppose to NFO being made easier to use?
Because DaleStan is a reactionary who's afraid that if the common people can code NFO it will lessen his importance in the community.

Or possibly, his problem with skidd13's post (and I thought this was pretty clear from what he wrote) is that if you're going to write a translator for NFO, it has to actually translate NFO, rather than being some completely different code structure.
michael blunck
Tycoon
Tycoon
Posts: 5954
Joined: 27 Apr 2005 07:09
Contact:

Post by michael blunck »

>> Why do you people (I mean DaleStan) oppose to NFO being made easier to use?

> if you're going to write a translator for NFO, it has to actually translate NFO, rather than being some completely different code structure.

I.e., something like that for a typical .nfo action0 for trains:

Code: Select all

BR92 ::= defineTrain(
	intro=1920,
	rel_decr=9,
	v_life=28,
	m_life=28,
	track_type=RAIL,
	climate=TEMP|ARCTIC,
	AI_loco=FALSE,
	speed=50,
	power=500,
	Rcost_mul=96,
	Rcost_base=STEAM,
	sprite_ID=NEW,
	dual_head=FALSE,
	cargo_capacity=NIL,
	cargo_type=NIL,
	weight=57,
	price_factor=2,
	AI_rank=1,
	traction_type=STEAM,
	sort_purchaselist=TRUE,
	callbacks=COLOR|SOUND,
	trac_effort=80, 	// in kN
	shortage=1,
	retire=3)
regards
Michael
Image
dragonhorseboy
Engineer
Engineer
Posts: 66
Joined: 04 May 2006 15:24
Contact:

Post by dragonhorseboy »

michael I had to agree with that example you posted..I would have quite liked such translator for myself too :wink:
DaleStan
TTDPatch Developer
TTDPatch Developer
Posts: 10285
Joined: 18 Feb 2004 03:06
Contact:

Post by DaleStan »

Now that, as an action0 replacement, is not bad.
I don't see where the vehicle's ID is set, nor exactly how you intended to set prop 1A ("list_before=<name>", possibly?), and new properties would break this very quickly. The latter could possibly be solved by

Code: Select all

   shortage=1,
   retire=3,
   extra_props(<num>,"<literal nfo>") )
where extra_props could take either the property number and its value, or the count of additional properties and the all the required <prop>/<new-info> pairs. Or maybe ("<prop><newinfo>","<prop><newinfo>",...)

The complex properties (station prop 09, 0E, bridge prop 0D, general prop 10, industry prop 0A, 16) of course, require completely different rules. Industry prop 16 is not too difficult; "random_sounds(<num1>, <num2>, ...)", but the others require more thought.
PikkaBird wrote:Or possibly, his problem with skidd13's post (and I thought this was pretty clear from what he wrote) is that if you're going to write a translator for NFO, it has to actually translate NFO, rather than being some completely different code structure.
I don't actually have a problem with a C-styled language. But if what you design looks like it's trying to completely replace NFO, it actually has to do so. If all it's trying to replace is Action 0, then that's all it needs to replace.
To get a good answer, ask a Smart Question. Similarly, if you want a bug fixed, write a Useful Bug Report. No TTDPatch crashlog? Then follow directions.
Projects: NFORenum (download) | PlaneSet (Website) | grfcodec (download) | grfdebug.log parser
User avatar
Csaboka
Tycoon
Tycoon
Posts: 1202
Joined: 25 Nov 2002 16:30
Location: Tiszavasvári, Hungary
Contact:

Post by Csaboka »

Meanwhile, I've read the documentation of Spirit, and it seems to be feasible for the job. (And I don't know anything else anyway...) I didn't yet have time to create a grammar, but I think action0 could look like this:

Code: Select all

set_property for industry ID 10 {
   substitute = 10;   // default base is decimal
   produced_cargoes = 0xFF08;   // hex can be used anywhere if needed
   prop_17 = (byte) 0;   // properties can be specified manually via hex number, but then you need to say the size explicitly
   sounds = [03 22 23 24];   // you can specify properties via a byte stream as well, just like regular NFO
}
The "byte stream" would mainly be a fallback mechanism for properties not supported properly yet. You could use a two-byte stream (almost) anywhere a word is needed, and the same would be true for two-byte streams and dwords. (Technically, it would work for bytes too, but it's rather pointless to do that.)

For similar reasons, the feature names could be substituted with feat_XX, and property names with prop_XX. For the ultimate fallback, there would be a "manual" keyword that requires a byte stream only, and spits the given stream into the output as a new pseudo-sprite. This way, it would be possible to use new features of TTDPatch even before proper support is added to the compiler itself.

If you need to modify more IDs in a single action0, you could replace the "ID 10" part with "IDs 10..12" for example. Then the right hand side values would need to be comma-separated lists, one value for each ID.

I know this isn't a full specification, but I hope it's enough to start a debate. I'm sure I've forgotten about some special case or something like that.

Edit: That "for" word in the beginning has no semantic meaning, so I guess it could be optional. In general, should that language look like C (i.e. striving for minimalizing keypresses) or COBOL (i.e. striving to look more like English)?
Reality is that which, when you stop believing in it, doesn't go away.—Philip K. Dick
DaleStan
TTDPatch Developer
TTDPatch Developer
Posts: 10285
Joined: 18 Feb 2004 03:06
Contact:

Post by DaleStan »

Personally, I'd go for a C-style language, but action 0 is (with the exception of the six "complex" properties) not really an issue; there's nothing particularly interesting, complicated, or powerful about action 0. It's just big. As much as it's nice to have a decent spec for action 0, I'd be more worried about getting 1/2/3 and 7/9/D/10 functional, and then generating formats for the remainder that correspond to those.

Action 0 could reasonably be written in <ebg13>KZY</ebg13>, but making part of the language look like that, and other parts look like C is probably not the best idea in the world. And the rest of NFO really doesn't lend itself to that particular format.
To get a good answer, ask a Smart Question. Similarly, if you want a bug fixed, write a Useful Bug Report. No TTDPatch crashlog? Then follow directions.
Projects: NFORenum (download) | PlaneSet (Website) | grfcodec (download) | grfdebug.log parser
User avatar
skidd13
OpenTTD Developer
OpenTTD Developer
Posts: 522
Joined: 03 Mar 2005 10:49
Location: Germany

Post by skidd13 »

Csaboka wrote:... but I think action0 could look like this:

Code: Select all

set_property for industry ID 10 {
   substitute = 10;   // default base is decimal
   produced_cargoes = 0xFF08;   // hex can be used anywhere if needed
   prop_17 = (byte) 0;   // properties can be specified manually via hex number, but then you need to say the size explicitly
   sounds = [03 22 23 24];   // you can specify properties via a byte stream as well, just like regular NFO
}
...
Looks clean and easy ... fantastic!
DaleStan wrote:Eww. Just Eww.
By "proposal", I meant "thing with obvious corresponding NFO code".
Go away. And don't come back until you have something that could be ...
Just want to bring some movement into this. :(
What does that mean - the circumstances? I determine what circumstances prevail. -- Napoleon Bonaparte
---
If we cannot end now our differences, at least we can help make the world safe for diversity. -- John F. Kennedy
---
Our problems are man-made, therefore they may be solved by man. No problem of human destiny is beyond human beings. -- John F. Kennedy
User avatar
eis_os
TTDPatch Developer
TTDPatch Developer
Posts: 3603
Joined: 07 Mar 2003 13:10
Location: Germany
Contact:

Post by eis_os »

Hmm, that looks a bit like css, so I guess you could reuse a css gramer description:

http://www.w3.org/TR/CSS21/grammar.html

(Sometimes it's good that they need decades for specs)

Btw. It would be nice to have a plain text file as rules, so you can add new properties easy without changeing grfcodec/nforenum/grfcompiler
User avatar
Csaboka
Tycoon
Tycoon
Posts: 1202
Joined: 25 Nov 2002 16:30
Location: Tiszavasvári, Hungary
Contact:

Post by Csaboka »

To be honest, I don't know CSS very well, but I don't see which parts could be reused from it. Action0 might be similar to CSS definitions, but the grammar for that doesn't seem to be hard anyway.

DaleStan is right: I should start with the most difficult part, probably with the action2 family (final action2, random action2, simple variational action2 and advanced variational action2, maybe not in this order). If I fail at the most difficult part, at least I haven't wasted time on the other parts. If, on the other hand, I succeed with the difficult parts, the rest will seem very easy :)
Btw. It would be nice to have a plain text file as rules, so you can add new properties easy without changeing grfcodec/nforenum/grfcompiler
Yes, I was thinking about some config files that would allow adding simple properties (bytes, words, dwords and textIDs at least) to action0 without recompiling the main program. A similar file could be added for action2 and action7/9/D variables.
Reality is that which, when you stop believing in it, doesn't go away.—Philip K. Dick
michael blunck
Tycoon
Tycoon
Posts: 5954
Joined: 27 Apr 2005 07:09
Contact:

Post by michael blunck »

Just my 2cc.

For a good project start, we should address three domains:

1. generate a grammatic specification of current ".nfo", preferably in BNF notation,
2. specify a "target language", generate a grammatic specification for it and build a parser,
3. build the "code generation" part for the compiler.


I´d like to address item 2 from a user´s POV and present some ideas for the target language. My approach being simply to "re-implement" existing (train) .nfo code into a "mock-C" language.

Some thoughts before on the subject.

I don´t think the main benefit of a "compiler" and a new "language" would be the move to more "human-readable" vars and operations in the first place. Instead, the real benefit would be the hiding of those many interdependencies in current .nfo and releasing the programmer from the burden of today´s superfluous work. (Therefore, we need to work on item 1.)

A neat side effect would be that we don´t have to implement each and every .nfo feature or var in a 1:1 fashion, but instead we could encapsulate the underlying mechanism into the "language" itself (either in special data types or in special functions). E.g., see "var 7F" versus the data type "nfo_colormap" which should define a new colourmap and have GRM provide the necessary new sprite for it, including all the needed overhead.

Now, let´s see how the first (very simple) engine, the BR92 of DBXL would look like.


1.

The current "action0 " for a certain engine could be simply replaced by a var of type "nfo_trainveh", a structure using "tags", simply filled with the needed constants:

Code: Select all

nfo_trainveh br92 :=  { 
   id = 0;		// engine ID
   intro = 1920;	// introduction year
   rel_decr = 9; 	// rate of reliability decreas
   v_life = 28; 	// vehicle life in years
   m_life = 28; 	// model life in years
   track_type = RAIL; 	// track type
   climate = TEMP | ARCTIC; 	// climates this engine will work in
   AI_loco = FALSE; 	// AI uses this one for passenger transport exclusively
   speed = 50; 	// speed in km/h
   power = 500; 	// power in hp, PS, whatever. We should move to kW
   Rcost_mul = 96; 	// running cost multiplier
   Rcost_base = _STEAM; 	// running cost base 
   sprite_ID = NEW; 	// this needs new graphics
   dual_head = FALSE; 	// single head engine
   cargo_capacity = NIL; 	// w/o any cargo capacity
   cargo_type = NIL;		// sic! 
   weight = 57; 	// weight in tons
   price_facto r= 2;	// purchase price multiplier 	
   AI_rank = 1; 	// AI rank of this engine
   traction_type = STEAM; 	// for effects: steam plumes, diesel soot or elctric sparks
   sort_purchaselist = 0; 	// sort in purchase list ???
   callbacks = cb_COLOR | cb_SOUND; 	// callbacks used
   trac_effort = 80;	// tractive effort in kN
   shortage = 1; 	// short engine, level 1
   retire = 3	// early retirement, 3 years
}
2.

Vars should be strongly typed. However, we would gain some more flexibility if there´d be distinct classes for vars which could be accessed in a "hierarchical" way. E.g., a var of type "nfo_spriteblock" could be referenced by one of type "nfo_cid" (which would be the standard var type, BTW) as well. Other types could include "nfo_text" for C000/D000 texts, "nfo_sound" for sounds, "nfo_colormap" for colour translation tables, etc. pp.

Code: Select all

nfo_cid  f1, f2, f3, f4; // some vars

nfo_spriteblock br92_display {
<sprite info>
}	// special graphics for purchasing list

nfo_spriteblock br92_frame1 {
<sprite info>
}	// animation frame 1

nfo_spriteblock br92_frame2 {
<sprite info>
}	// animation frame 2

nfo_spriteblock br92_frame3 {
<sprite info>
}	// animation frame 3

nfo_spriteblock br92_frame4 {
<sprite info>
}	// animation frame 4

f1 := br92_frame1; // just to demonstrate var assignment. In fact, we wouldn´t need vars here
f2 := br92_frame2;
f3 := br92_frame3;
f4 := br92_frame4;

// assemble animation frames
nfo_cid br92_animated := switch (nfo_animcounter >>8 &03) {
	case 0: f1;	// respectively,  "case 0:  br92_frame1;" etc ... s.a.
	case 1: f2;
	case 2: f3;
	default: f4; 
}
I´d propose "action2s" to rely heavily on the "switch statement" when checking that large number of .nfo vars available. In addition, we could easily allow for the complete C set of bit operators.


3.

Text should be handled transparently, regardless if it´s a class C000 or D000 text:

Code: Select all

nfo_text br92text { txt_ALL; "BR92 (ex wü T5)";} // text to use in action4 for all languages

nfo_text br92addtext { 
	txt_ENG; "axle scheme: E \n builder: Union \n tank engine for basic passenger and freight services.\n";
	txt_GER; "Achsfolge: E \n Hersteller: Union \n Universelle Tenderlok für einfachen Personen-  und Güterverkehr";
}	// additional text for callback 23

nfo_sound br92sound { 
<filename>
}	// define engine sounds

nfo_colormap KPEV { ..... } // define new colourmap and have GRM provide a new sprite for it 

nfo_colormap ttd_GREEN; // use original TTD colormap #30E

nfo_cid n1, n2, br92, br92display;	// more vars

n1 := switch (nfo_date_year) {
	1920 ... 1927: KPEV; // to have ranges too would be very convenient!
	default: ttd_GREEN;
}	// check global nfo var "date_year" and branch accordingly

n2 := switch (nfo_soundevent) {
	snd_START ... snd_TUNNEL: br92_sound;
	default: void;
} 	// check global nfo var "soundevent", use sound when engine starts and/or in tunnel

br92 := switch (nfo_callback) {
	case cb_COLOR: n1;	// recolouring
	case cb_SOUND: n2;	// sound
	default: br92_animated; // graphics
}	// check global nfo var "callback", branch according to callback type

br92display := switch (nfo_callback) {
	case cb_COLOR: n1;	// recolouring
	case cb_TEXT: br92addtext;	// additional text in purchase menu
	default: br92_display; 	//  graphics for purchase menu
}

// make_engine (nfo_trainveh, nfo_cid, nfo_cid, nfo_text);
make_engine (br92, br92, br92display, br92text);
regards
Michael
Image
User avatar
AndersI
Tycoon
Tycoon
Posts: 1732
Joined: 19 Apr 2004 20:09
Location: Sweden
Contact:

Post by AndersI »

Sorry if I'm saying something already turned down (or stupid), but wouldn't a plain old macro preprocessor help increasing the ease of creating, and readability of, NFO?

This could be as simple as just a way to get the NFO to look like the wording in the Wiki instead of the code numbers (for those that read words faster than numbers). No extra syntax checks etc. just a means to get the code a bit more symbolic.

In this way it is easier to show the intent of the code, and to slowly build up a library of helpful macros, while keeping the NFO++ files fully compilable all the time. This might increase acceptance of the system - run a plain NFO through the preprocessor, and the same plain NFO comes out in the other end. Use a DWORD(...) here and a BYTE_ARRAY(...) there, a SET_PROP(...,...) anywhere, and they will get processed to the right thing (still assuming I put them at the right place). The tool chain can be the same for both plain NFO and NFO++

Now add definitions for the actions, expression evaluators, anchor points for the selfmodifying parts, and so on.
Locked

Return to “NewGRF Technical Discussions”

Who is online

Users browsing this forum: Ahrefs [Bot] and 16 guests