NML - a Newgrf Meta Language

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

Moderator: Graphics Moderators

Transportman
Tycoon
Tycoon
Posts: 2781
Joined: 22 Feb 2011 18:34

Re: NML - a Newgrf Meta Language

Post by Transportman »

I need some help with a piece of code I'm working on. I want to know the Vehicle ID of a wagon in front of the current wagon, for use in a chain that determines if the vehicle can be attached, but I have a problem with it not working. The first evaluated switch (switch_can_attach_vehicle) works fine, but the other switches don't work. I guess I made an error with accessing the NFO-equivalent variables, which I based on this post.

Code: Select all

/*	This file is used to determine which vehicles can be attached to which vehicles.
 *  First the ID of the attaching vehicle is detected:
 *  Engines will always be allowed to attach
 *  Regular wagons and coaches will only be attached to regular engines
 *	Unit wagons are only allowed behind other Unit wagons and the front heads of MUs
*/

/*
* Regular wagons/coaches
*/

//Check vehicle ID of the vehicle in front 
//Wagons and coaches can only be attached to normal engines and other wagons and coaches, but not to Multiple Unit vehicles
switch(FEAT_TRAINS, SELF, switch_can_attach_wagon, [STORE_TEMP(-1, 0x10F), var[0x61, 0, 0x0000FFFF, 0xC6]]) {
	  1000..1999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Steam Railbus, allow
	  2000..2999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Diesel Railbus, allow
	  3000..3999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Electric Railbus, allow
	  4000..4999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Steam, allow
	  5000..5999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Diesel, allow
	  6000..6999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Electric, allow
	  7000..7999: string(str_cannot_attach_wagon_to_MU); //DMU, disallow
	  8000..8999: string(str_cannot_attach_wagon_to_MU); //EMU, disallow
	  9000..9999: string(str_cannot_attach_wagon_to_MU); //Multi Unit Metro, disallow
	10000..10999: string(str_cannot_attach_wagon_to_MU); //Multi Unit Maglev, disallow
	11000..11999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Coaches, allow
	12000..12999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Wagons, allow
	13000..13999: string(str_cannot_attach_wagon_to_Unit_Wagon); //Unit Wagons, disallow
	14000..14999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Single Unit Metro, allow
	15000..15999: string(str_cannot_attach_wagon_to_MU); //SMU, disallow
	16000..16999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Single Unit Maglev, allow
}

/*
* Unit Wagon
*/

//Check if the Unit wagon follows the front head
switch(FEAT_TRAINS, SELF, switch_can_attach_Unit_to_MU_head, [STORE_TEMP(-1, 0x10F), var[0x61, 0xC8]]) {
	0xFE: string(str_cannot_attach_Unit_wagon_to_back); //Back head, disallow
    0xFF: string(str_cannot_attach_Unit_wagon_to_back); //Back head, disallow
    CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Front head, allow
}
	
//Check vehicle ID of the vehicle in front in case this is a unit wagon
//Unit wagons can be attached to Multiple Unit vehicles, but not to engines and other wagons/coaches
switch(FEAT_TRAINS, SELF, switch_can_attach_unit, [STORE_TEMP(-1, 0x10E), var[0x61, 0, 0x0000FFFF, 0xC6]]) {
	  1000..1999: string(str_cannot_attach_Unit_wagon_to_engine); //Steam Railbus, disallow
	  2000..2999: string(str_cannot_attach_Unit_wagon_to_engine); //Diesel Railbus, disallow
	  3000..3999: string(str_cannot_attach_Unit_wagon_to_engine); //Electric Railbus, disallow
	  4000..4999: string(str_cannot_attach_Unit_wagon_to_engine); //Steam, disallow
	  5000..5999: string(str_cannot_attach_Unit_wagon_to_engine); //Diesel, disallow
	  6000..6999: string(str_cannot_attach_Unit_wagon_to_engine); //Electric, disallow
	  7000..7999: switch_can_attach_Unit_to_MU_head; //DMU, go to Head-switch
	  8000..8999: switch_can_attach_Unit_to_MU_head; //EMU, go to Head-switch
	  9000..9999: switch_can_attach_Unit_to_MU_head; //Multi Unit Metro, go to Head-switch
	10000..10999: switch_can_attach_Unit_to_MU_head; //Multi Unit Maglev, go to Head-switch
	11000..11999: string(str_cannot_attach_Unit_wagon_to_wagon); //Coaches, allow
	12000..12999: string(str_cannot_attach_Unit_wagon_to_wagon); //Wagons, allow
	13000..13999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Unit Wagons, disallow
	14000..14999: string(str_cannot_attach_Unit_wagon_to_engine); //Single Unit Metro, allow
	15000..15999: switch_can_attach_Unit_to_MU_head; //SMU, go to Head-switch
	16000..16999: string(str_cannot_attach_Unit_wagon_to_engine); //Single Unit Maglev, allow
}
	
/*	Check vehicle ID to determine which case we have. 
 *	Engines are always allowed to be attached
 *	Wagons depend on vehicle in front of it
*/
switch(FEAT_TRAINS, SELF, switch_can_attach_vehicle, vehicle_type_id) {
	  1000..1999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Steam Railbus, always allow
	  2000..2999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Diesel Railbus, always allow
	  3000..3999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Electric Railbus, always allow
	  4000..4999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Steam, always allow
	  5000..5999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Diesel, always allow
	  6000..6999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Electric, always allow
	  7000..7999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //DMU, always allow
	  8000..8999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //EMU, always allow
	  9000..9999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Multi Unit Metro, always allow
	10000..10999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Multi Unit Maglev, always allow
	11000..11999: switch_can_attach_wagon; //Coaches, go to Regular-switch
	12000..12999: switch_can_attach_wagon; //Wagons, go to Regular-switch
	13000..13999: switch_can_attach_unit; //Unit Wagons, go to Unit-switch
	14000..14999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Single Unit Metro, always allow
	15000..15999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //SMU, always allow
	16000..16999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Single Unit Maglev, always allow
}
}
Coder of the Dutch Trackset | Development support for the Dutch Trainset | Coder of the 2cc TrainsInNML
michael blunck
Tycoon
Tycoon
Posts: 5948
Joined: 27 Apr 2005 07:09
Contact:

Re: NML - a Newgrf Meta Language

Post by michael blunck »

Transportman wrote: I have a problem with it not working.
Because of var61: "The resulting value will have the size of whatever variable is queried".

regards
Michael
Image
Eddi
Tycoon
Tycoon
Posts: 8272
Joined: 17 Jan 2007 00:14

Re: NML - a Newgrf Meta Language

Post by Eddi »

Transportman wrote:

Code: Select all

var[0x61, 0xC8]
you cannot leave out stuff in the middle. if you only give two parameters to var[<var>,<shift>,<mask>,<param>], they will be interpreted as <var> and <shift>, not as <var> and <param> like you intended.
Transportman
Tycoon
Tycoon
Posts: 2781
Joined: 22 Feb 2011 18:34

Re: NML - a Newgrf Meta Language

Post by Transportman »

Eddi wrote:
Transportman wrote:

Code: Select all

var[0x61, 0xC8]
you cannot leave out stuff in the middle. if you only give two parameters to var[<var>,<shift>,<mask>,<param>], they will be interpreted as <var> and <shift>, not as <var> and <param> like you intended.
Aha, that might have slipped in because I use 0xC8 elsewhere in the code, but there the whole shift, mask and param parts are left out as they are not needed, which I assumed would also hold for this case. Do you know which shifts and masks I need to make both switch-blocks work properly?
Coder of the Dutch Trackset | Development support for the Dutch Trainset | Coder of the 2cc TrainsInNML
michael blunck
Tycoon
Tycoon
Posts: 5948
Joined: 27 Apr 2005 07:09
Contact:

Re: NML - a Newgrf Meta Language

Post by michael blunck »

Well, var "C8" is a byte, so var[0x61, 0, 0x000000FF, 0xC8] should do the trick.

regards
Michael
Image
Transportman
Tycoon
Tycoon
Posts: 2781
Joined: 22 Feb 2011 18:34

Re: NML - a Newgrf Meta Language

Post by Transportman »

michael blunck wrote:
Transportman wrote: I have a problem with it not working.
Because of var61: "The resulting value will have the size of whatever variable is queried".

regards
Michael
It took some time, but I think I now understand this statement. VarC6 has the size of a W, which is a 2 byte word in little-endian order, while I used the values vehicle_type_id would have in NML switch blocks. So I would need to convert the values I used to that 2 byte word in little-endian order, correct?
Coder of the Dutch Trackset | Development support for the Dutch Trainset | Coder of the 2cc TrainsInNML
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 »

you simply have to mask out all those bits which are meaningless. Thus for var 0xC8 is byte-sized and you keep only the last byte, masking with 0x000000FF while the vehicleID is a word variable and you keep the last 16 bit, masking with 0x0000FFFF. The masking is required as the masked-out bits are not guaranteed to contain anything useful and could have any arbitrary value - which would make your switch fail.
Transportman
Tycoon
Tycoon
Posts: 2781
Joined: 22 Feb 2011 18:34

Re: NML - a Newgrf Meta Language

Post by Transportman »

planetmaker wrote:you simply have to mask out all those bits which are meaningless. Thus for var 0xC8 is byte-sized and you keep only the last byte, masking with 0x000000FF while the vehicleID is a word variable and you keep the last 16 bit, masking with 0x0000FFFF. The masking is required as the masked-out bits are not guaranteed to contain anything useful and could have any arbitrary value - which would make your switch fail.
Thanks for the explanation, I think I understand now.

But I'm still clueless as to why it is not working. I have the following NML code:

Code: Select all

/*
* Regular wagons/coaches
*/

//Check vehicle ID of the vehicle in front 
switch(FEAT_TRAINS, SELF, switch_can_attach_wagon, [STORE_TEMP(-1, 0x10F), var[0x61, 0, 0x0000FFFF, 0xC6]]) {
	0x03E8..0x07CF: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Steam Railbus, allow
	0x07D0..0x0BB7: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Diesel Railbus, allow
	0x0BB8..0x0F9F: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Electric Railbus, allow
	0x0FA0..0x1387: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Steam, allow
	0x1388..0x176F: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Diesel, allow
	0x1770..0x1B57: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Electric, allow
	0x1B58..0x1F3F: string(str_cannot_attach_wagon_to_MU); //DMU, disallow
	0x1F40..0x2327: string(str_cannot_attach_wagon_to_MU); //EMU, disallow
	0x2328..0x270F: string(str_cannot_attach_wagon_to_MU); //Multi Unit Metro, disallow
	0x2710..0x2AF7: string(str_cannot_attach_wagon_to_MU); //Multi Unit Maglev, disallow
	0x2AF8..0x2EDF: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Coaches, allow
	0x2EE0..0x32C7: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Wagons, allow
	0x32C8..0x36AF: string(str_cannot_attach_wagon_to_Unit_Wagon); //Unit Wagons, disallow
	0x36B0..0x3A97: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Single Unit Metro, allow
	0x3A98..0x3E7F: string(str_cannot_attach_wagon_to_MU); //SMU, disallow
	0x3E80..0x4267: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Single Unit Maglev, allow
	string(str_cannot_attach_A);
}

/*
* Unit Wagon
*/

//Check vehicle ID of the vehicle in front in case this is a unit wagon
switch(FEAT_TRAINS, SELF, switch_can_attach_unit, [STORE_TEMP(-1, 0x10F), var[0x61, 0, 0x0000FFFF, 0xC6]]) {
	0x03E8..0x07CF: string(str_cannot_attach_Unit_wagon_to_engine); //Steam Railbus, disallow
	0x07D0..0x0BB7: string(str_cannot_attach_Unit_wagon_to_engine); //Diesel Railbus, disallow
	0x0BB8..0x0F9F: string(str_cannot_attach_Unit_wagon_to_engine); //Electric Railbus, disallow
	0x0FA0..0x1387: string(str_cannot_attach_Unit_wagon_to_engine); //Steam, disallow
	0x1388..0x176F: string(str_cannot_attach_Unit_wagon_to_engine); //Diesel, disallow
	0x1770..0x1B57: string(str_cannot_attach_Unit_wagon_to_engine); //Electric, disallow
	0x1B58..0x1F3F: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //DMU, allow
	0x1F40..0x2327: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //EMU, allow
	0x2328..0x270F: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Multi Unit Metro, allow
	0x2710..0x2AF7: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Multi Unit Maglev, allow
	0x2AF8..0x2EDF: string(str_cannot_attach_Unit_wagon_to_wagon); //Coaches, disallow
	0x2EE0..0x32C7: string(str_cannot_attach_Unit_wagon_to_wagon); //Wagons, disallow
	0x32C8..0x36AF: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Unit Wagons, allow
	0x36B0..0x3A97: string(str_cannot_attach_Unit_wagon_to_engine); //Single Unit Metro, disallow
	0x3A98..0x3E7F: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //SMU, go to Head-switch
	0x3E80..0x4267: string(str_cannot_attach_Unit_wagon_to_engine); //Single Unit Maglev, dissallow
	string(str_cannot_attach_B);
}
	
/*	Check vehicle ID to determine which case we have. 
 *	Engines are always allowed
 *	Wagons depend on vehicle in front of it
*/
switch(FEAT_TRAINS, SELF, switch_can_attach_vehicle, vehicle_type_id) {
	  1000..1999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Steam Railbus, always allow
	  2000..2999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Diesel Railbus, always allow
	  3000..3999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Electric Railbus, always allow
	  4000..4999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Steam, always allow
	  5000..5999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Diesel, always allow
	  6000..6999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Electric, always allow
	  7000..7999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //DMU, always allow
	  8000..8999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //EMU, always allow
	  9000..9999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Multi Unit Metro, always allow
	10000..10999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Multi Unit Maglev, always allow
	11000..11999: switch_can_attach_wagon; //Coaches, go to Regular-switch
	12000..12999: switch_can_attach_wagon; //Wagons, go to Regular-switch
	13000..13999: switch_can_attach_unit; //Unit Wagons, go to Unit-switch
	14000..14999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Single Unit Metro, always allow
	15000..15999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //SMU, always allow
	16000..16999: CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES; //Single Unit Maglev, always allow
	string(str_cannot_attach_C);
}
switch_can_attach_vehicle works, but the other switches give a 0 (and since that is not in one of the ranges it goes to the default return). What did I do wrong?

Which results in the following NFO:

Code: Select all

// Name: switch_can_attach_wagon
53 * 188 02 00 FF 89 
1A 20 \dxFFFFFFFF 
\2sto 1A 20 \dx0000010F 
\2r 61 C6 00 \dx0000FFFF 
\b16 
\wx8400 \dx000003E8 \dx000007CF 	// 1000 .. 1999: return 1024;
\wx8400 \dx000007D0 \dx00000BB7 	// 2000 .. 2999: return 1024;
\wx8400 \dx00000BB8 \dx00000F9F 	// 3000 .. 3999: return 1024;
\wx8400 \dx00000FA0 \dx00001387 	// 4000 .. 4999: return 1024;
\wx8400 \dx00001388 \dx0000176F 	// 5000 .. 5999: return 1024;
\wx8400 \dx00001770 \dx00001B57 	// 6000 .. 6999: return 1024;
\wx8000 \dx00001B58 \dx00001F3F 	// 7000 .. 7999: return string(str_cannot_attach_wagon_to_MU);
\wx8000 \dx00001F40 \dx00002327 	// 8000 .. 8999: return string(str_cannot_attach_wagon_to_MU);
\wx8000 \dx00002328 \dx0000270F 	// 9000 .. 9999: return string(str_cannot_attach_wagon_to_MU);
\wx8000 \dx00002710 \dx00002AF7 	// 10000 .. 10999: return string(str_cannot_attach_wagon_to_MU);
\wx8400 \dx00002AF8 \dx00002EDF 	// 11000 .. 11999: return 1024;
\wx8400 \dx00002EE0 \dx000032C7 	// 12000 .. 12999: return 1024;
\wx8001 \dx000032C8 \dx000036AF 	// 13000 .. 13999: return string(str_cannot_attach_wagon_to_Unit_Wagon);
\wx8400 \dx000036B0 \dx00003A97 	// 14000 .. 14999: return 1024;
\wx8000 \dx00003A98 \dx00003E7F 	// 15000 .. 15999: return string(str_cannot_attach_wagon_to_MU);
\wx8400 \dx00003E80 \dx00004267 	// 16000 .. 16999: return 1024;
\wx8002 // default: return string(str_cannot_attach_A);

// Name: switch_can_attach_unit
54 * 188 02 00 FE 89 
1A 20 \dxFFFFFFFF 
\2sto 1A 20 \dx0000010F 
\2r 61 C6 00 \dx0000FFFF 
\b16 
\wx8003 \dx000003E8 \dx000007CF 	// 1000 .. 1999: return string(str_cannot_attach_Unit_wagon_to_engine);
\wx8003 \dx000007D0 \dx00000BB7 	// 2000 .. 2999: return string(str_cannot_attach_Unit_wagon_to_engine);
\wx8003 \dx00000BB8 \dx00000F9F 	// 3000 .. 3999: return string(str_cannot_attach_Unit_wagon_to_engine);
\wx8003 \dx00000FA0 \dx00001387 	// 4000 .. 4999: return string(str_cannot_attach_Unit_wagon_to_engine);
\wx8003 \dx00001388 \dx0000176F 	// 5000 .. 5999: return string(str_cannot_attach_Unit_wagon_to_engine);
\wx8003 \dx00001770 \dx00001B57 	// 6000 .. 6999: return string(str_cannot_attach_Unit_wagon_to_engine);
\wx8400 \dx00001B58 \dx00001F3F 	// 7000 .. 7999: return 1024;
\wx8400 \dx00001F40 \dx00002327 	// 8000 .. 8999: return 1024;
\wx8400 \dx00002328 \dx0000270F 	// 9000 .. 9999: return 1024;
\wx8400 \dx00002710 \dx00002AF7 	// 10000 .. 10999: return 1024;
\wx8004 \dx00002AF8 \dx00002EDF 	// 11000 .. 11999: return string(str_cannot_attach_Unit_wagon_to_wagon);
\wx8004 \dx00002EE0 \dx000032C7 	// 12000 .. 12999: return string(str_cannot_attach_Unit_wagon_to_wagon);
\wx8400 \dx000032C8 \dx000036AF 	// 13000 .. 13999: return 1024;
\wx8003 \dx000036B0 \dx00003A97 	// 14000 .. 14999: return string(str_cannot_attach_Unit_wagon_to_engine);
\wx8400 \dx00003A98 \dx00003E7F 	// 15000 .. 15999: return 1024;
\wx8003 \dx00003E80 \dx00004267 	// 16000 .. 16999: return string(str_cannot_attach_Unit_wagon_to_engine);
\wx8005 // default: return string(str_cannot_attach_B);

// Name: switch_can_attach_vehicle
55 * 173 02 00 FE 89 
C6 00 \dx0000FFFF 
\b16 
\wx8400 \dx000003E8 \dx000007CF 	// 1000 .. 1999: return 1024;
\wx8400 \dx000007D0 \dx00000BB7 	// 2000 .. 2999: return 1024;
\wx8400 \dx00000BB8 \dx00000F9F 	// 3000 .. 3999: return 1024;
\wx8400 \dx00000FA0 \dx00001387 	// 4000 .. 4999: return 1024;
\wx8400 \dx00001388 \dx0000176F 	// 5000 .. 5999: return 1024;
\wx8400 \dx00001770 \dx00001B57 	// 6000 .. 6999: return 1024;
\wx8400 \dx00001B58 \dx00001F3F 	// 7000 .. 7999: return 1024;
\wx8400 \dx00001F40 \dx00002327 	// 8000 .. 8999: return 1024;
\wx8400 \dx00002328 \dx0000270F 	// 9000 .. 9999: return 1024;
\wx8400 \dx00002710 \dx00002AF7 	// 10000 .. 10999: return 1024;
\wx00FF \dx00002AF8 \dx00002EDF 	// 11000 .. 11999: switch_can_attach_wagon;
\wx00FF \dx00002EE0 \dx000032C7 	// 12000 .. 12999: switch_can_attach_wagon;
\wx00FE \dx000032C8 \dx000036AF 	// 13000 .. 13999: switch_can_attach_unit;
\wx8400 \dx000036B0 \dx00003A97 	// 14000 .. 14999: return 1024;
\wx8400 \dx00003A98 \dx00003E7F 	// 15000 .. 15999: return 1024;
\wx8400 \dx00003E80 \dx00004267 	// 16000 .. 16999: return 1024;
\wx8006 // default: return string(str_cannot_attach_C);
Coder of the Dutch Trackset | Development support for the Dutch Trainset | Coder of the 2cc TrainsInNML
frosch
OpenTTD Developer
OpenTTD Developer
Posts: 988
Joined: 20 Dec 2006 13:31
Location: Aschaffenburg

Re: NML - a Newgrf Meta Language

Post by frosch »

"can_attach_wagon" is evaluated with
* SELF refering to the vehicle being attached.
* PARENT refering to the consist of the engine and the wagons in front, but with SELF not yet attached.
(for completeness: inserting a vehicle in the middle is evaluated by detaching all vehicles in the back, and then reattaching them one by one)

You try to access the vehicle in front of SELF, but there is none. Instead you need to access the last vehicle of the PARENT consist.
Try:

Code: Select all

switch(FEAT_TRAINS, PARENT, switch_can_attach_wagon, [STORE_TEMP(position_in_consist_from_end , 0x10F), ...
⢇⡸⢸⠢⡇⡇⢎⡁⢎⡱⢸⡱⢸⣭⠀⢸⢜⢸⢸⣀⢸⣀⢸⣭⢸⡱⠀⢰⠭⡆⣫⠰⣉⢸⢸⠀⢰⠭⡆⡯⡆⢹⠁⠀⢐⠰⡁
Transportman
Tycoon
Tycoon
Posts: 2781
Joined: 22 Feb 2011 18:34

Re: NML - a Newgrf Meta Language

Post by Transportman »

frosch wrote:"can_attach_wagon" is evaluated with
* SELF refering to the vehicle being attached.
* PARENT refering to the consist of the engine and the wagons in front, but with SELF not yet attached.
(for completeness: inserting a vehicle in the middle is evaluated by detaching all vehicles in the back, and then reattaching them one by one)

You try to access the vehicle in front of SELF, but there is none. Instead you need to access the last vehicle of the PARENT consist.
Try:

Code: Select all

switch(FEAT_TRAINS, PARENT, switch_can_attach_wagon, [STORE_TEMP(position_in_consist_from_end , 0x10F), ...
Thanks, that does it. It also makes sense like that, but the NML specs are not very clear about that, as NML has no own variable for accessing properties of other vehicles it is also not mentioned that PARENT combined with var 61 can refer to other parts of the consist.
Coder of the Dutch Trackset | Development support for the Dutch Trainset | Coder of the 2cc TrainsInNML
Eddi
Tycoon
Tycoon
Posts: 8272
Joined: 17 Jan 2007 00:14

Re: NML - a Newgrf Meta Language

Post by Eddi »

once upon a time the idea was that "vehicle_type_id(offset)" (or something similar) would invoke var61, but nobody implemented that yet.
Transportman
Tycoon
Tycoon
Posts: 2781
Joined: 22 Feb 2011 18:34

Re: NML - a Newgrf Meta Language

Post by Transportman »

Eddi wrote:once upon a time the idea was that "vehicle_type_id(offset)" (or something similar) would invoke var61, but nobody implemented that yet.
If it is ever implemented, I would prefer to have it the same way as the random switch types.

And I have another question: How long is something in temporary storage accessible? Is it only accessible in the switch-chain that stores something there in the first place?

The reason I ask is because I have a bunch of vehicles that all have 2 sets of switch blocks that basically do the same calculations, but one set is part of the visual_effect_and_powered-callback (for the visual effect, wagon power is disabled) the other set returns a matching spriteset (panto up or down). I want to store the result of the visual_effect_and_powered-callback to simplify my spriteset switches, but if temporary storage is limited to the switch-chain that stored it that is not going to work.
Coder of the Dutch Trackset | Development support for the Dutch Trainset | Coder of the 2cc TrainsInNML
User avatar
PikkaBird
Graphics Moderator
Graphics Moderator
Posts: 5602
Joined: 13 Sep 2004 13:21
Location: The Moon

Re: NML - a Newgrf Meta Language

Post by PikkaBird »

Transportman wrote:The reason I ask is because I have a bunch of vehicles that all have 2 sets of switch blocks that basically do the same calculations, but one set is part of the visual_effect_and_powered-callback (for the visual effect, wagon power is disabled) the other set returns a matching spriteset (panto up or down). I want to store the result of the visual_effect_and_powered-callback to simplify my spriteset switches, but if temporary storage is limited to the switch-chain that stored it that is not going to work.
The wrong answer: use callback 36 to modify the vehicle's property 25, then read it back with var 42.

The right answer: do the calculations first, then split the tree into spritesets and cb results. Congratulations, your action 2 chains have gotten complex enough that you have to start thinking about what order you do things in. :)
Transportman
Tycoon
Tycoon
Posts: 2781
Joined: 22 Feb 2011 18:34

Re: NML - a Newgrf Meta Language

Post by Transportman »

PikkaBird wrote:The wrong answer: use callback 36 to modify the vehicle's property 25, then read it back with var 42.
That is indeed the wrong answer, I want to simplify stuff, not make things more complicated.
The right answer: do the calculations first, then split the tree into spritesets and cb results. Congratulations, your action 2 chains have gotten complex enough that you have to start thinking about what order you do things in. :)
Is that possible? I can't find anything about it in the NML specs. Also, the result I get depends on the place in a chain of vehicles, there is randomization, and I want to merge the visual_effect_and_powered-cbs of the various vehicles to one switch-block that I call for all those vehicles while the spritesets are kept unique to each vehicle. Is it then still possible to do the calculations first?
Coder of the Dutch Trackset | Development support for the Dutch Trainset | Coder of the 2cc TrainsInNML
User avatar
PikkaBird
Graphics Moderator
Graphics Moderator
Posts: 5602
Joined: 13 Sep 2004 13:21
Location: The Moon

Re: NML - a Newgrf Meta Language

Post by PikkaBird »

Transportman wrote:I want to merge the visual_effect_and_powered-cbs of the various vehicles to one switch-block that I call for all those vehicles while the spritesets are kept unique to each vehicle
Any particular reason? You can do procedure calls for vehicle callbacks in NFO, but I don't think that's been implemented in NML.

The callback result is always the same for any given spriteset, yes? eg, pantograph up = sparks, pantograph down = no sparks? So why not do the calculations for the spriteset, and then simply return the appropriate callback result in each case?
Transportman
Tycoon
Tycoon
Posts: 2781
Joined: 22 Feb 2011 18:34

Re: NML - a Newgrf Meta Language

Post by Transportman »

PikkaBird wrote:
Transportman wrote:I want to merge the visual_effect_and_powered-cbs of the various vehicles to one switch-block that I call for all those vehicles while the spritesets are kept unique to each vehicle
Any particular reason? You can do procedure calls for vehicle callbacks in NFO, but I don't think that's been implemented in NML.
No particular reason, it is just some code cleanup I am considering, because I have a bunch of vehicles that have the following code, with only identifiers different:

Code: Select all

//Visual effect, for EMU this is done on the part with the pantograph
random_switch(FEAT_TRAINS, SELF, switch_emu_<Vehicle_Name>_visual_effect_and_powered) {
	9: visual_effect_and_powered(VISUAL_EFFECT_DISABLE, 0, DISABLE_WAGON_POWER);
	1: visual_effect_and_powered(VISUAL_EFFECT_ELECTRIC, -3, DISABLE_WAGON_POWER);
}

switch(FEAT_TRAINS, SELF, switch_emu_<Vehicle_Name>_visual_effect_and_powered_position, position_in_vehid_chain) {
	0: visual_effect_and_powered(VISUAL_EFFECT_ELECTRIC, -3, DISABLE_WAGON_POWER);
	switch_emu_<Vehicle_Name>_visual_effect_and_powered;
}

random_switch(FEAT_TRAINS, SELF, switch_emu_<Vehicle_Name>_middlepass_livery) {
	dependent: switch_emu_<Vehicle_Name>_visual_effect_and_powered;
	9: spriteset_emu_<Vehicle_Name>_middlepass_L1;
	1: spriteset_emu_<Vehicle_Name>_middlepass_L2;
}

//First unit wagon always has a pantograph
switch(FEAT_TRAINS, SELF, switch_emu_<Vehicle_Name>_middlepass_position, position_in_vehid_chain) {
	0: spriteset_emu_<Vehicle_Name>_middlepass_L2;
	switch_emu_<Vehicle_Name>_middlepass_livery;
}
That's why I started my question, I want to simplify the spriteset switches as the calculations are the same.
The callback result is always the same for any given spriteset, yes? eg, pantograph up = sparks, pantograph down = no sparks? So why not do the calculations for the spriteset, and then simply return the appropriate callback result in each case?
Yes, the result is always the same, panto up = sparks, panto down = no sparks. Problem with doing the spriteset calculations first is that there is also a cargo class switch in those calculations and different spritesets depending on the cargo class (not shown in the code above), making that route less simple than the cb-first route. With the cb-first route I would only need the cargo class switch and a livery switch for each cargo class at the price of two cb-switches, while with spriteset-first I would have one cb-switch but two livery switches for each cargo class (one for the position in the chain and one for the random part). Or am I now misunderstanding you?
Coder of the Dutch Trackset | Development support for the Dutch Trainset | Coder of the 2cc TrainsInNML
User avatar
PikkaBird
Graphics Moderator
Graphics Moderator
Posts: 5602
Joined: 13 Sep 2004 13:21
Location: The Moon

Re: NML - a Newgrf Meta Language

Post by PikkaBird »

Perhaps a picture is worth a thousand words. :)

This is one way of structuring your switches:
action2_flow_1.png
action2_flow_1.png (28.97 KiB) Viewed 2910 times
This is how I'd do it:
action2_flow_2.png
action2_flow_2.png (17.04 KiB) Viewed 2910 times
Now, there are still the same number of switches there, and there's still duplication; that's unavoidable. However, imo the second structure has the following advantages:

1) Less work for OpenTTD. Because the game has to calculate both the FX and the sprites, the first one is evaluating 6 switches per vehicle; the second is only doing 4.
2) The second one duplicates less "creative" code. When copying the code for a new vehicle, you might want to change how the vehicle picks wagon sprites, but you're not going to want to change "is this the FX callback?". By duplicating less creative code, you reduce the chance of introducing bugs by making inconsistent changes.
3) the callback result and the spriteset come out of the same switch. This makes spotting inconsistencies (ie a wrong fx/sprite combination) much easier.
Transportman
Tycoon
Tycoon
Posts: 2781
Joined: 22 Feb 2011 18:34

Re: NML - a Newgrf Meta Language

Post by Transportman »

PikkaBird wrote:Perhaps a picture is worth a thousand words. :)

This is one way of structuring your switches:
That is how my code looks currently.
This is how I'd do it:

Now, there are still the same number of switches there, and there's still duplication; that's unavoidable. However, imo the second structure has the following advantages:

1) Less work for OpenTTD. Because the game has to calculate both the FX and the sprites, the first one is evaluating 6 switches per vehicle; the second is only doing 4.
2) The second one duplicates less "creative" code. When copying the code for a new vehicle, you might want to change how the vehicle picks wagon sprites, but you're not going to want to change "is this the FX callback?". By duplicating less creative code, you reduce the chance of introducing bugs by making inconsistent changes.
3) the callback result and the spriteset come out of the same switch. This makes spotting inconsistencies (ie a wrong fx/sprite combination) much easier.
Looks good, but I'm not sure if it can be coded that simple that in NML, especially the 3rd point I have some doubts about with getting the callback result and spriteset out of the same switch.
Coder of the Dutch Trackset | Development support for the Dutch Trainset | Coder of the 2cc TrainsInNML
Eddi
Tycoon
Tycoon
Posts: 8272
Joined: 17 Jan 2007 00:14

Re: NML - a Newgrf Meta Language

Post by Eddi »

i'm not aware of procedures ever being implemented in NML, but you can try invoking "var[0x7E, 0, 0x7FFF, switch_to_call]" in a switch, and then comparing this value with your results.

so something like:

Code: Select all

random_switch(is_panto_up) {
    1: return panto_up;
    1: return panto_down;
}

switch(get_sprite, var[0x7E, 0, 0x7FFF, is_panto_up]) {
    panto_up: sprite_panto_up;
    panto_down: sprite_panto_down;
}

switch(get_cb_result, var[0x7E, 0, 0x7FFF, is_panto_up]) {
    panto_up: return spark;
    panto_down: return no_spark;
}

graphics {
    default: get_sprite;
    visual_effect: get_cb_result;
}
no guarantee whether that works.

other than that, the way pikka describes can be implemented in NML, by checking var 0C in the default callback, instead of giving a switch for the visual effect callback. this, however is "deprecated syntax".
Transportman
Tycoon
Tycoon
Posts: 2781
Joined: 22 Feb 2011 18:34

Re: NML - a Newgrf Meta Language

Post by Transportman »

Eddi wrote:i'm not aware of procedures ever being implemented in NML, but you can try invoking "var[0x7E, 0, 0x7FFF, switch_to_call]" in a switch, and then comparing this value with your results.
no guarantee whether that works.
That doesn't work, as "All parts of a variable access must be integers" and "Switch block parameter 3 'name' must be an identifier" basically exclude each other.

I think I just stick with the code I already have and wait for NML to support things like that natively.
Eddi wrote:"deprecated syntax".
As long as NML doesn't have own variable names for some things, that "deprecated syntax" keeps being necessary.
Coder of the Dutch Trackset | Development support for the Dutch Trainset | Coder of the 2cc TrainsInNML
Post Reply

Return to “NewGRF Technical Discussions”

Who is online

Users browsing this forum: No registered users and 19 guests