Houses in NML

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

Moderator: Graphics Moderators

Post Reply
Yoshi
Transport Coordinator
Transport Coordinator
Posts: 278
Joined: 21 Dec 2010 17:24

Houses in NML

Post by Yoshi »

Today i continued with coding houses in NML (for TARS-Towns).

My old attempt:
-For every single sprite an own file.
-7 spritesets (no snow, 1/4, 2/4, 3/4, and 4/4 + ground 0/4 and ground 4/4 snow)
-5 spritelayouts for all snow-stages (0/4 - 4/4)

I think, this is much coding for little output.
house_old.nml
(2.41 KiB) Downloaded 149 times

So i revamped the code and made one single file for all sprites of one building.

-one file
-5 spritesets (no snow (3 sprites: 2 buildingstages, 1 finished building), one for all snow stages (without buildingstages), one for full snow (3 sprites: 2 buildingstages, 1 finished building))
-5 spritelayouts for all snow-stages (0/4 - 4/4)

This is better.... but it needs much code as well...
house_new.nml
(3.41 KiB) Downloaded 131 times

I think, something like an extended spritelayout wouldn't be bad:

Code: Select all

spritelayout gfx_house {
			ground {
				view	        :bitmap(HOUSE_NORMAL,HOUSE_1_4_SNOW,...);
				sprite	:[spriteset_house(15),spriteset_house(16),spriteset_house(17),spriteset_house(18),spriteset_house(19)];
			}
			building {
				view	:bitmap(HOUSE_NORMAL,HOUSE_1_4_SNOW,HOUSE_2_4_SNOW,HOUSE_3_4_SNOW,HOUSE_4_4_SNOW,);
				sprite	:[spriteset_house(0),spriteset_house(1),spriteset_house(2),spriteset_house(3),spriteset_house(4)];
			}
		}
view: contains a bitmap with the sprites which are available for this house.
sprite: contains an array of spriteset-references

Here is a fictive code
house_wish.nml
(4 KiB) Downloaded 129 times


Could something like this be realised?
Are there existing alternatives?
User avatar
planetmaker
OpenTTD Developer
OpenTTD Developer
Posts: 9432
Joined: 07 Nov 2007 22:44
Location: Sol d

Re: Houses in NML

Post by planetmaker »

Yoshi wrote:Today i continued with coding houses in NML (for TARS-Towns).

My old attempt:
-For every single sprite an own file.
-7 spritesets (no snow, 1/4, 2/4, 3/4, and 4/4 + ground 0/4 and ground 4/4 snow)
-5 spritelayouts for all snow-stages (0/4 - 4/4)

I think, this is much coding for little output.
house_old.nml

So i revamped the code and made one single file for all sprites of one building.

-one file
-5 spritesets (no snow (3 sprites: 2 buildingstages, 1 finished building), one for all snow stages (without buildingstages), one for full snow (3 sprites: 2 buildingstages, 1 finished building))
-5 spritelayouts for all snow-stages (0/4 - 4/4)

This is better.... but it needs much code as well...
house_new.nml

I think, something like an extended spritelayout wouldn't be bad:

Code: Select all

spritelayout gfx_house {
			ground {
				view	        :bitmap(HOUSE_NORMAL,HOUSE_1_4_SNOW,...);
				sprite	:[spriteset_house(15),spriteset_house(16),spriteset_house(17),spriteset_house(18),spriteset_house(19)];
			}
			building {
				view	:bitmap(HOUSE_NORMAL,HOUSE_1_4_SNOW,HOUSE_2_4_SNOW,HOUSE_3_4_SNOW,HOUSE_4_4_SNOW,);
				sprite	:[spriteset_house(0),spriteset_house(1),spriteset_house(2),spriteset_house(3),spriteset_house(4)];
			}
		}
view: contains a bitmap with the sprites which are available for this house.
sprite: contains an array of spriteset-references

Here is a fictive code
house_wish.nml


Could something like this be realised?
Are there existing alternatives?
Using the advanced spritesets as available in NewGRF v8 (and NML 0.3+) you can give offsets into a spriteset (see also the example at the end of the page). These offsets can be calculated in advance and stored in temporary registers.
Other examples can be found in ogfx-industries or here (search for oil_well_tile). You can in the same way also access for example the default ground tiles (see there e.g. ogfx+landscape which uses it to easily decide on slopes).

An example could look like below. The spritelayout can be defined with parameters (untested code, you might want to add climate sensitivity, too):

Code: Select all

spriteset (myhouse_sprites) {
// we define the first entries of building and ground as spr_myhouse and spr_myground respectively for future reference in the layout:
spr_myhouse:  [sprite construction0, snowyness 0]
  [sprite construction0, snowyness 1]
  [sprite construction0, snowyness 2]
  [sprite construction0, snowyness 3]
  [sprite construction0, snowyness 4]
  [sprite construction1, snowyness 0]
  [sprite construction1, snowyness 1]
  [sprite construction1, snowyness 2]
  [sprite construction1, snowyness 3]
  (...)
  [sprite construction3, snowyness 4]
spr_myground:   [sprite construction0, snowyness 0]
  [sprite construction0, snowyness 1]
  [sprite construction0, snowyness 2]
  [sprite construction0, snowyness 3]
  [sprite construction0, snowyness 4]
  [sprite construction1, snowyness 0]
  [sprite construction1, snowyness 1]
  [sprite construction1, snowyness 2]
  [sprite construction1, snowyness 3]
  (...)
  [sprite construction3, snowyness 4]
}

// this will possibly be more elaborate, using offsets or so
spritelayout  myhouse_tile(construction_stage, snowyness) {
  ground {
    sprite: myhouse_ground_sprites(spr_myground + construction_stage * 5 + snowyness);
  }
  building {
    sprite: myhouse_sprites(spr_myhouse + construction_stage * 5 + snowyness);
    // usual stuff for sprite layouts - adjust as needed:
    hide_sprite: 0;
    xoffset: 16;
    yoffset:  0;
    zoffset: 0
    xextent: 0;
    yextent: 16;
    zextent: 6;
    recolour_mode: RECOLOUR_REMAP;
    palette:       PALETTE_USE_DEFAULT;
  }
}

switch (FEAT_HOUSES, SELF, myhouse, [
   // store construction state in temp. variable 0
  STORE_TEMP(0, construction_stage),
  // calculate the height above the snowline
  STORE_TEMP( (nearby_tile_height(0, 0) < (snowline_height - 1)), 1),
  STORE_TEMP( LOAD_TEMP(1) + (LOAD_TEMP(1) == 0) * (nearby_tile_height(0, 0) <  (snowline_height     )), 1),
  STORE_TEMP( LOAD_TEMP(1) + (LOAD_TEMP(1) == 0) * (nearby_tile_height(0, 0) <  (snowline_height +  1)), 1),
  STORE_TEMP( LOAD_TEMP(1) + (LOAD_TEMP(1) == 0) * (nearby_tile_height(0, 0) <  (snowline_height + 2)), 1),
  STORE_TEMP( LOAD_TEMP(1) + (LOAD_TEMP(1) == 0) * (nearby_tile_height(0, 0) >= (snowline_height + 2)), 1),
  1 ]
  ) {
  myhouse_tile(LOAD_TEMP(0), LOAD_TEMP(1));
}
EDIT: Looking at it... one could probably skip giving the construction_state as parameter to the layout and query that variable directly there.

In order to accomodate for different climates, you could use the hide_sprite: CLIMATE == CLIMATE_ARCTIC ? 0 : 1 for the sprites. And define a separate sprite in the layout with a similar rule for the other climates.

EDIT2: corrected nasty omission in code
User avatar
planetmaker
OpenTTD Developer
OpenTTD Developer
Posts: 9432
Joined: 07 Nov 2007 22:44
Location: Sol d

Re: Houses in NML

Post by planetmaker »

Another addendum: I just re-wrote the code for the wind turbine in ogfx+landscape. It should now be relatively short and do a similar thing (albeit with animation stages instead of construction and no snowyness): http://dev.openttdcoop.org/projects/ogf ... plant.pnml
Yoshi
Transport Coordinator
Transport Coordinator
Posts: 278
Joined: 21 Dec 2010 17:24

Re: Houses in NML

Post by Yoshi »

Code: Select all

 sprite: myhouse_ground_sprites(spr_myground + construction_stage * 5 + snowyness);
I tried to find out, what the function of this line is, but it did'nt made much sense for me.

Code: Select all

 sprite: spr_myground(construction_stage * 5 + snowyness);
I think, this line makes more sense for me ;) .
Yoshi
Transport Coordinator
Transport Coordinator
Posts: 278
Joined: 21 Dec 2010 17:24

Re: Houses in NML

Post by Yoshi »

Now it works... but not everything :(

Code: Select all

(c) Matthias Gürtler 2012

spriteset (spriteset_old_cabin)
	{
		template_houses_70(0,0,"gfx/old_cabin.png")		
	}
	
spriteset (spriteset_old_cabin_ground)
	{
		template_grounds_70(0,0,"gfx/old_cabin.png")		
	}
		
spritelayout  old_cabin_tile (construction_stage, snowyness) {
  ground {
    sprite: (4493 + snowyness * 19);
  }
  building {
    sprite: spriteset_old_cabin_ground(construction_stage * 5 + snowyness);
	always_draw: 1;
  }
  building {
    sprite: spriteset_old_cabin(construction_stage * 5 + snowyness);
  }
}

switch (FEAT_HOUSES, SELF, old_cabin, [
   // store construction state in temp. variable 0
  STORE_TEMP(0, construction_state),
  // calculate the height above the snowline
  STORE_TEMP( (nearby_tile_height(0, 0) < (snowline_height - 1)), 1),
  STORE_TEMP( LOAD_TEMP(1) + (LOAD_TEMP(1) == 0) * (nearby_tile_height(0, 0) <  (snowline_height     )), 1),
  STORE_TEMP( LOAD_TEMP(1) + (LOAD_TEMP(1) == 0) * (nearby_tile_height(0, 0) <  (snowline_height +  1)), 1),
  STORE_TEMP( LOAD_TEMP(1) + (LOAD_TEMP(1) == 0) * (nearby_tile_height(0, 0) <  (snowline_height + 2)), 1),
  STORE_TEMP( LOAD_TEMP(1) + (LOAD_TEMP(1) == 0) * (nearby_tile_height(0, 0) >= (snowline_height + 2)), 1),
  1 ]) {
  old_cabin_tile(LOAD_TEMP(0), LOAD_TEMP(1));
}
The output is something like this:
house_bug1.png
house_bug1.png (99.36 KiB) Viewed 345 times
The ground is always the same :(
And the building as well ;)
User avatar
planetmaker
OpenTTD Developer
OpenTTD Developer
Posts: 9432
Joined: 07 Nov 2007 22:44
Location: Sol d

Re: Houses in NML

Post by planetmaker »

I do not believe that this issue can be addressed without knowledge of your spriteset (including its templates) definitions (code + graphis). EDIT: Excellent would be a minimally buildable NewGRF which exhibits this issue. You unfortunately mostly quote what I gave you as untested quick example a bit further above.

I also believe that you use construction stages the wrong way around (stage0...2 = increasingly finished building; stage3 = finished building).
Yoshi
Transport Coordinator
Transport Coordinator
Posts: 278
Joined: 21 Dec 2010 17:24

Re: Houses in NML

Post by Yoshi »

planetmaker wrote: I also believe that you use construction stages the wrong way around (stage0...2 = increasingly finished building; stage3 = finished building).
Yes, i noticed that a few minutes ago :)

I'll change the sprites ;)
Yoshi
Transport Coordinator
Transport Coordinator
Posts: 278
Joined: 21 Dec 2010 17:24

Re: Houses in NML

Post by Yoshi »

House.zip
ZIP with sources AND GRF
(135.28 KiB) Downloaded 107 times

Here is a mini-grf with this house ...
Yexo
Tycoon
Tycoon
Posts: 3663
Joined: 20 Dec 2007 12:49

Re: Houses in NML

Post by Yexo »

Yoshi wrote:

Code: Select all

   // store construction state in temp. variable 0
  STORE_TEMP(0, construction_state),
Actually you're storing 0 in a variable with number depending on the construction state.

Code: Select all

  // calculate the height above the snowline
  STORE_TEMP( (nearby_tile_height(0, 0) < (snowline_height - 1)), 1),
  STORE_TEMP( LOAD_TEMP(1) + (LOAD_TEMP(1) == 0) * (nearby_tile_height(0, 0) <  (snowline_height     )), 1),
  STORE_TEMP( LOAD_TEMP(1) + (LOAD_TEMP(1) == 0) * (nearby_tile_height(0, 0) <  (snowline_height +  1)), 1),
  STORE_TEMP( LOAD_TEMP(1) + (LOAD_TEMP(1) == 0) * (nearby_tile_height(0, 0) <  (snowline_height + 2)), 1),
  STORE_TEMP( LOAD_TEMP(1) + (LOAD_TEMP(1) == 0) * (nearby_tile_height(0, 0) >= (snowline_height + 2)), 1),
You need to rethink your logic. What you're doing is this:
- Store either 0 or 1 in temp(1).
- If temp(1) is 1, store 1 in temp(1), otherwise store 0 or 1.
- If temp(1) is 1, store 1 in temp(1), otherwise store 0 or 1.
- If temp(1) is 1, store 1 in temp(1), otherwise store 0 or 1.
- Store 1 in temp(1).
I'm not surprised at all you get the same ground sprite every time ;).

Can you try to get an even smaller example to work first? I mean no construction stages at all, just different graphics below and above the snowline (not multiple stages like you have now). If you can't get that to work, please post again and I'll have another look.
User avatar
planetmaker
OpenTTD Developer
OpenTTD Developer
Posts: 9432
Joined: 07 Nov 2007 22:44
Location: Sol d

Re: Houses in NML

Post by planetmaker »

I somehow forgot about this topic...

Yexo is right of course that the logic is a bit awkward. If I wrote that, must have been a bad day without much tea. Anyhow,

Code: Select all

spritelayout  old_cabin_tile (construction_stage, snowyness) {
  ground {
	  sprite: GROUNDSPRITE_NORMAL;
  }
  childsprite {
    sprite: GROUNDSPRITE_SNOW_1_4 + (snowyness - 1) * 19;
    hide_sprite: snowyness == 0;
  }
  building {
    sprite: spriteset_old_cabin_ground(snowyness + construction_stage * 5);
	always_draw: 1;
  }
  building {
	  sprite: spriteset_old_cabin(snowyness + construction_stage * 5);
  }
}

switch (FEAT_HOUSES, SELF, old_cabin, [
   // store construction state in temp. variable 0
  STORE_TEMP(construction_state, 0),
  // calculate the height above the snowline
  STORE_TEMP( (nearby_tile_height(0, 0) > (snowline_height - 1)), 1),
  STORE_TEMP( LOAD_TEMP(1) + (nearby_tile_height(0, 0) >  (snowline_height    )), 1),
  STORE_TEMP( LOAD_TEMP(1) + (nearby_tile_height(0, 0) >  (snowline_height + 1)), 1),
  STORE_TEMP( LOAD_TEMP(1) + (nearby_tile_height(0, 0) >  (snowline_height + 2)), 1),
  LOAD_TEMP(1)] ) {
	0: old_cabin_tile(LOAD_TEMP(0), 0);
	1: old_cabin_tile(LOAD_TEMP(0), 1);
	2: old_cabin_tile(LOAD_TEMP(0), 2);
	3: old_cabin_tile(LOAD_TEMP(0), 3);
	old_cabin_tile(LOAD_TEMP(0), LOAD_TEMP(1));
}
results for me in (maybe it's off by one height level, didn't properly check). Generally, setup your variables step by step and go back to the last simpler case which worked for you :-)
Attachments
screenshot#1.png
screenshot#1.png (667.96 KiB) Viewed 344 times
Yexo
Tycoon
Tycoon
Posts: 3663
Joined: 20 Dec 2007 12:49

Re: Houses in NML

Post by Yexo »

Code: Select all

  LOAD_TEMP(1)] ) {
   0: old_cabin_tile(LOAD_TEMP(0), 0);
   1: old_cabin_tile(LOAD_TEMP(0), 1);
   2: old_cabin_tile(LOAD_TEMP(0), 2);
   3: old_cabin_tile(LOAD_TEMP(0), 3);
All these lines from planetmaker's post could be removed without changing the end result (You only need to keep ") {"). This of course also applies to the original code.
Last edited by Yexo on 22 Oct 2012 11:00, edited 1 time in total.
User avatar
wallyweb
Tycoon
Tycoon
Posts: 6102
Joined: 27 Nov 2004 15:05
Location: Canada

Re: Houses in NML

Post by wallyweb »

When I started coding TARS Pistes as newobjects, I needed a simple way to test my code with respect to variable snowlines. Because it was graphically obvious, SwissFan91 was kind enough to allow me to use one of his houses from his house set.

The code is NFO but it is well commented and should be easily redone in NML or m4nfo. I post it here in the hopes that it will help.

Snowline transitions are handled differently in base TTDP (or OTTD?) than it is under OpenGFX where there is a difference between flat tiles and sloped tiles. This code sorts it out.

Note that it has to be repeated for each object but perhaps someone has a way to do it only once?

I hope this helps.

Code: Select all

// House -----------------------------------------------------------------------------------------------
// Action 1 - Define a set of real sprites ------------------------------------------------------------------
 1960 * 4	 01 0F 05 01
// Format: spritenum pcxfile xpos ypos compression ysize xsize xrel yrel
 1961 C:\MPS\_tools\grfcodec\sprites\4_Swissfan91\town\TARSHouse8bpp.png 16 16 09 44 64 -31 -13 // no snow
 1962 C:\MPS\_tools\grfcodec\sprites\4_Swissfan91\town\TARSHouse8bpp.png 336 16 09 44 64 -31 -13 // snow
 1963 C:\MPS\_tools\grfcodec\sprites\4_Swissfan91\town\TARSHouse8bpp.png 256 16 09 44 64 -31 -13 // 3/4 snow
 1964 C:\MPS\_tools\grfcodec\sprites\4_Swissfan91\town\TARSHouse8bpp.png 176 16 09 44 64 -31 -13 // 1/2 snow
 1965 C:\MPS\_tools\grfcodec\sprites\4_Swissfan91\town\TARSHouse8bpp.png 96 16 09 44 64 -31 -13 // 1/4 snow
// Action 2 - Flat Tiles ---------------------------------------------------------------------------------------
 1966 * 17	 02 0F 00 00  8D 0F 00 00  00 80 00 80   00 00   0F 0F 28 // no snow 3981 8D 0F
 1967 * 17	 02 0F 01 00  C6 11 00 00  01 80 00 80   00 00   0F 0F 28 // snow 4550 C6 11
// varAction 2 - Autoslope Control - CB 15D - 00 allow - 01 disallow -----------------------------------
 1968 * 17	 02 0F 02 85 0C 00 FF FF 01  00 80  5D 01 5D 01  00 00 // no snow Flat
 1969 * 17	 02 0F 03 85 0C 00 FF FF 01  00 80  5D 01 5D 01  01 00 // snow Flat
// varAction 2 - Terrain Type check - 00 Temperate - 04 Arctic ---------------------------------------
 1970 * 14	 02 0F 04 81 41 00 FF 01  03 00 04 04  02 00
// Action 2 - Snow Transitions Flat Tiles ------------------------------------------------------------------
 1971 * 17	 02 0F 05 00  B3 11 00 00  02 80 00 80   00 00   0F 0F E5 // 3/4 snow 4531 B3 11
 1972 * 17	 02 0F 06 00  A0 11 00 00  03 80 00 80   00 00   0F 0F E5 // 1/2 snow 4512 A0 11
 1973 * 17	 02 0F 07 00  8D 11 00 00  04 80 00 80   00 00   0F 0F E5 // 1/4 snow 4493 8D 11
// varAction 2 - OTTD Solution -----------------------------------------------------------------------------
 1974 * 31	 02 0F 08 81  20 20 FF  
				00  1A 20 10
				01  62 00 10 FF
				03	
					05 00 00 00	// 3/4 snow
					06 00 08 08	// 1/2 snow
					07 00 10 10	// 1/4 snow
					04 00
// varAction 2 - TTDP Solution -----------------------------------------------------------------------------
 1975 * 31	 02 0F 09 81  20 20 FF
				00  1A 20 08
				01  62 00 10 FF  03
					05 00 00 00	// 3/4 snow
					06 00 08 08	// 1/2 snow
					07 00 10 10	// 1/4 snow
					04 00
// varAction 2 - OTTD/TTDP selector ---------------------------------------------------------------------
 1976 * 14	 02 0F 0A 81 1D 00 FF 01 // 00 TTDPatch - 01 OpenTTD
				08 00   01 01			 
				09 00
// Snow Transitions Sloped Tiles --------------------------------------------------------------------------
// varAction 2 - OTTD Solution ----------------------------------------------------------------------------
 1977 * 31	 02 0F 0B 81  20 20 FF
				00  1A 20 08
				01  62 00 10 FF
				03
					05 00 00 00	// 3/4 snow
					06 00 08 08	// 1/2 snow
					07 00 10 10	// 1/4 snow
					04 00
// varAction 2 - TTDP Solution ----------------------------------------------------------------------------
 1978 * 27	 02 0F 0C 81  20 20 FF
				01  62 00 10 FF  03
					05 00 00 00	// 3/4 snow
					06 00 08 08	// 1/2 snow
					07 00 10 10	// 1/4 snow
					04 00
// varAction 2 - OTTD/TTDP selector --------------------------------------------------------------------
 1979 * 14	 02 0F 0D 81 1D 00 FF 01 // 00 TTDPatch - 01 OpenTTD
				0B 00   01 01
				0C 00
// Menu =========================================================================
// Action 1 - Define a set of real sprites -----------------------------------------------------------------
 1980 * 4	 01 0F 01 01
 1981 C:\MPS\_tools\grfcodec\sprites\4_Swissfan91\town\TARSHouse8bpp.png 16 16 09 44 64 -31 -13 // no snow
// Action 2 for menu ----------------------------------------------------------------------------------------
 1982 * 17	 02 0F 0E 00   00 80 00 80   00 00 00 00   00 00   00 00 00
// varAction 2 - Slope check for CB157 var 10 -----------------------------------------------------------
 1983 * 14	 02 0F 0F 81 10 00 FF  01  00 80 00 00  0E 80 // flat tile
 1984 * 14	 02 0F 10 81 10 00 FF  01  00 80 01 0E  0E 80 // sloped tile
// varAction 2 - Return to graphics - Callback checks ---------------------------------------------------
 1985 * 23	 02 0F 11 85 0C 00 FF FF 02
				5C 80  5C 01 5C 01 // Additional text
				0F 00  57 01 57 01 // slope
				0E 00 // Default
 1986 * 23	 02 0F 12 85 0C 00 FF FF 02
				5C 80  5C 01 5C 01 // Additional text
				10 00  57 01 57 01 // slope
				0E 00 // Default
// varAction 2 - Slope Picker -------------------------------------------------------------------------------
 1987 * 15	 02 0F 13 81 62 00 00 FF 01
				12 00 01 0E
				11 00
 1988 * 15	 02 0F 14 81 62 00 00 FF 01
				0D 00 01 0E
				0A 00
//===============================================================================
// Action 3 Associate with graphics set IDs --------------------------------------------------------------
 1989 * 10	 03 0F 01 12 01 FF 13 00 14 00
Post Reply

Return to “NewGRF Technical Discussions”

Who is online

Users browsing this forum: No registered users and 24 guests