NMLTutorial/Object slopes

From TTWiki
< NMLTutorial
Revision as of 21:49, 27 August 2011 by FooBar (talk | contribs) (intermediate save)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

The example used here is from the Dutch Road Furniture. The original graphics for this are by FooBar. The code is by FooBar, based on code for the object example from the NML source by planetmaker and Hirundu. Code and graphics are both licensed according to the GPL v2 or later. The code has been modified for the purpose of this tutorial.


This continues and concludes the second part of the object example. In this last part we'll make the object compatible with sloped terrain as well as snow and desert terrain. For this some recent features of OpenTTD will be used, which makes this last part of the example incompatible with anything other than OpenTTD 1.2.0 (r22723) or higher.

Notepad.png
Note
This page is incomplete. It will be completed very soon.


Version check

if (version_openttd(1,2,0,22723) > openttd_version) {
	error(FATAL, REQUIRES_OPENTTD, string(STR_OPENTTD_VERSION));
}
STR_OPENTTD_VERSION :1.2.0 (r22723)


Sloped ground sprites

        default:            switch_fingerpost_3_object;
        purchase:           switch_fingerpost_3_purchase;
        autoslope:          return(CB_RESULT_AUTOSLOPE);


switch (FEAT_OBJECTS, SELF, switch_fingerpost_3_object, [
        //tile slope offset in storage register 0
        STORE_TEMP(slope_to_sprite_offset(tile_slope), 0),
        //terrain type in storage register 1
        STORE_TEMP(GROUNDSPRITE_NORMAL, 1),
        STORE_TEMP(terrain_type == TILETYPE_DESERT ? GROUNDSPRITE_DESERT : LOAD_TEMP(1), 1),
        STORE_TEMP(terrain_type == TILETYPE_SNOW   ? GROUNDSPRITE_SNOW   : LOAD_TEMP(1), 1)
        ]) {
	switch_fingerpost_3_build_date;
}


//calculate ground sprite for purchase menu
switch (FEAT_OBJECTS, SELF, switch_fingerpost_3_purchase, [
        //use flat gound sprite for purchase menu
        STORE_TEMP(0, 0),
        //use normal terrain for purchase menu
        STORE_TEMP(GROUNDSPRITE_NORMAL, 1),
        ]) {
	switch_fingerpost_3_build_date;
}


With this the end of the object example is reached. You can now encode this as a NewGRF.


The complete code

If you put everything in the correct order, this will be the complete NML file:

// define the newgrf
grf {
    grfid:                  "\FB\FB\05\01";
    name:                   string(STR_GRF_NAME);
    desc:                   string(STR_GRF_DESCRIPTION);
    version:                0;
    min_compatible_version: 0;
}

//check OpenTTD version
//parameterized spritelayout is only supported since OpenTTD 1.2.0 r22723
if (version_openttd(1,2,0,22723) > openttd_version) {
	error(FATAL, REQUIRES_OPENTTD, string(STR_OPENTTD_VERSION));
}

//templates
template template_fingerpost(x,y,filename) {
    [x,     y,      20,     32,     -10,    -28,    filename]
    [x+30,  y,      20,     32,     -10,    -28,    filename]
    [x+60,  y,      20,     32,     -10,    -28,    filename]
    [x+90,  y,      20,     32,     -10,    -28,    filename]
}

//spriteset with four directions
spriteset (spriteset_fingerpost_3) {
    template_fingerpost(0,0,"gfx/dutch_fingerpost.png")
}

/* spritelayouts */

//south east
spritelayout spritelayout_fingerpost_3_SE {
    ground {
        sprite: LOAD_TEMP(0) + LOAD_TEMP(1);
    }
    building {
        sprite: spriteset_fingerpost_3(0);
        xextent: 4;
        yextent: 4;
        zextent: 24;
        xoffset: 6; //from NE edge
        yoffset: 12; //from NW edge
        zoffset: 0;
    }
}

//south west
spritelayout spritelayout_fingerpost_3_SW {
    ground {
        sprite: LOAD_TEMP(0) + LOAD_TEMP(1);
    }
    building {
        sprite: spriteset_fingerpost_3(1);
        xextent: 4;
        yextent: 4;
        zextent: 24;
        xoffset: 12; //from NE edge
        yoffset: 6; //from NW edge
        zoffset: 0;
    }
}

//north west
spritelayout spritelayout_fingerpost_3_NW {
    ground {
        sprite: LOAD_TEMP(0) + LOAD_TEMP(1);
    }
    building {
        sprite: spriteset_fingerpost_3(2);
        xextent: 4;
        yextent: 4;
        zextent: 24;
        xoffset: 6; //from NE edge
        yoffset: 0; //from NW edge
        zoffset: 0;
    }
}

//north east
spritelayout spritelayout_fingerpost_3_NE {
    ground {
        sprite: LOAD_TEMP(0) + LOAD_TEMP(1);
    }
    building {
        sprite: spriteset_fingerpost_3(3);
        xextent: 4;
        yextent: 4;
        zextent: 24;
        xoffset: 0; //from NE edge
        yoffset: 6; //from NW edge
        zoffset: 0;
    }
}

//decide spritelayout for each of the 4 views
switch (FEAT_OBJECTS, SELF, switch_fingerpost_3_view, view) {
    1:  spritelayout_fingerpost_3_SW;
    2:  spritelayout_fingerpost_3_NW;
    3:  spritelayout_fingerpost_3_NE;
    spritelayout_fingerpost_3_SE;
}

//calculate ground sprite for object
switch (FEAT_OBJECTS, SELF, switch_fingerpost_3_object, [
        //tile slope offset in storage register 0
        STORE_TEMP(slope_to_sprite_offset(tile_slope), 0),
        //terrain type in storage register 1
        STORE_TEMP(GROUNDSPRITE_NORMAL, 1),
        STORE_TEMP(terrain_type == TILETYPE_DESERT ? GROUNDSPRITE_DESERT : LOAD_TEMP(1), 1),
        STORE_TEMP(terrain_type == TILETYPE_SNOW   ? GROUNDSPRITE_SNOW   : LOAD_TEMP(1), 1)
        ]) {
	switch_fingerpost_3_build_date;
}

//calculate ground sprite for purchase menu
switch (FEAT_OBJECTS, SELF, switch_fingerpost_3_purchase, [
        //use flat gound sprite for purchase menu
        STORE_TEMP(0, 0),
        //use normal terrain for purchase menu
        STORE_TEMP(GROUNDSPRITE_NORMAL, 1),
        ]) {
	switch_fingerpost_3_build_date;
}

item (FEAT_OBJECTS, fingerpost_3) {
    property {
        class:                  "NLRF";
        classname:              string(STR_NLRF);
        name:                   string(STR_HANDWIJZER_3);
        climates_available:     ALL_CLIMATES;
        size:                   [1,1];
        build_cost_multiplier:  2;
        remove_cost_multiplier: 8;
        introduction_date:      date(1961,1,1);
        end_of_life_date:       0xFFFFFFFF;
        object_flags:           bitmask(OBJ_FLAG_REMOVE_IS_INCOME, OBJ_FLAG_NO_FOUNDATIONS, OBJ_FLAG_ALLOW_BRIDGE);
        height:                 2;
        num_views:              4;
    }
    graphics {
        default:            switch_fingerpost_3_object;
        purchase:           switch_fingerpost_3_purchase;
        autoslope:          return(CB_RESULT_AUTOSLOPE);
        additional_text:    string(STR_FINGERPOST_3_PURCHASE);
    }
}

The language file will now contain:

##grflangid 0x01

#Main grf title and description
STR_GRF_NAME        :{TITLE}
STR_GRF_DESCRIPTION :Description: {SILVER}Dutch Road Furniture is an eyecandy object NewGRF that features road furniture that can be found alongside Dutch roads. {}(c)2011 FooBar. {}{BLACK}License: {SILVER}GPLv2 or higher.

#error messages
STR_OPENTTD_VERSION :1.2.0 (r22723)

#object classes
STR_NLRF            :Dutch Road Furniture

#object name and description
STR_FINGERPOST_3            :Dutch Fingerpost three-way
STR_FINGERPOST_3_PURCHASE   :The three-way fingerpost is centered at one side of the tile and facing outward. Intended to be placed directly opposite of the secondary road at a three-way junction.

This is the end of this example and the end of the series. Only thing left for you to skip is a useless conclusion


NML Tutorial: Object slopes